Actual source code: destroy.c

  1: /*
  2:      Provides utility routines for manulating any type of PETSc object.
  3: */
  4: #include <petsc/private/petscimpl.h>
  5: #include <petscviewer.h>

  7: static PetscErrorCode DestroyComposedData(void ***composed_star, PetscObjectState **state_star, PetscInt *count_star, void **composed, PetscObjectState **state)
  8: {
  9:   void **tmp_star = *composed_star;

 11:   PetscFunctionBegin;
 12:   for (PetscInt i = 0, imax = *count_star; i < imax; ++i) PetscCall(PetscFree(tmp_star[i]));
 13:   PetscCall(PetscFree2(*composed_star, *state_star));
 14:   PetscCall(PetscFree2(*composed, *state));
 15:   *count_star = 0;
 16:   PetscFunctionReturn(PETSC_SUCCESS);
 17: }

 19: PetscErrorCode PetscComposedQuantitiesDestroy(PetscObject obj)
 20: {
 21:   PetscFunctionBegin;
 23:   PetscCall(DestroyComposedData((void ***)&obj->intstarcomposeddata, &obj->intstarcomposedstate, &obj->intstar_idmax, (void **)&obj->intcomposeddata, &obj->intcomposedstate));
 24:   PetscCall(DestroyComposedData((void ***)&obj->realstarcomposeddata, &obj->realstarcomposedstate, &obj->realstar_idmax, (void **)&obj->realcomposeddata, &obj->realcomposedstate));
 25: #if PetscDefined(USE_COMPLEX)
 26:   PetscCall(DestroyComposedData((void ***)&obj->scalarstarcomposeddata, &obj->scalarstarcomposedstate, &obj->scalarstar_idmax, (void **)&obj->scalarcomposeddata, &obj->scalarcomposedstate));
 27: #endif
 28:   PetscFunctionReturn(PETSC_SUCCESS);
 29: }

 31: /*@
 32:   PetscObjectDestroy - Destroys a `PetscObject`, regardless of the class.

 34:   Collective

 36:   Input Parameter:
 37: . obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`\*), for example,
 38:         `PetscObjectDestroy`((`PetscObject`\*)&mat);

 40:   Level: beginner

 42: .seealso: `PetscObject`
 43: @*/
 44: PetscErrorCode PetscObjectDestroy(PetscObject *obj)
 45: {
 46:   PetscFunctionBegin;
 47:   if (!obj || !*obj) PetscFunctionReturn(PETSC_SUCCESS);
 49:   PetscCheck((*obj)->bops->destroy, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This PETSc object of class %s does not have a generic destroy routine", (*obj)->class_name);
 50:   PetscCall((*(*obj)->bops->destroy)(obj));
 51:   PetscFunctionReturn(PETSC_SUCCESS);
 52: }

 54: /*@
 55:   PetscObjectView - Views, that is displays or stores information about a `PetscObject`.

 57:   Collective

 59:   Input Parameters:
 60: + obj    - any PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
 61:            `PetscObjectView`((`PetscObject`)mat,`viewer`);
 62: - viewer - any PETSc viewer

 64:   Level: intermediate

 66: .seealso: `PetscObject`, `PetscObjectViewFromOptions()`, `PetscViewer`
 67: @*/
 68: PetscErrorCode PetscObjectView(PetscObject obj, PetscViewer viewer)
 69: {
 70:   PetscFunctionBegin;
 72:   PetscCheck(obj->bops->view, PETSC_COMM_SELF, PETSC_ERR_SUP, "This PETSc object does not have a generic viewer routine");
 73:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(obj->comm, &viewer));

 76:   PetscCall((*obj->bops->view)(obj, viewer));
 77:   PetscFunctionReturn(PETSC_SUCCESS);
 78: }

 80: /*@
 81:   PetscObjectViewFromOptions - Processes command line options to determine if/how a `PetscObject` is to be viewed.

 83:   Collective

 85:   Input Parameters:
 86: + obj  - the object
 87: . bobj - optional other object that provides prefix (if `NULL` then the prefix in `obj` is used)
 88: - name - option string that is used to activate viewing. It typically ends with `_view`.

 90:   Options Database Key:
 91: . -name viewer_specification - See `PetscOptionsCreateViewer()` for the values of `viewer_specification`

 93:   Level: developer

 95:   Notes:
 96:   This function is usually not called directly but is called by, for example, `MatViewFromOptions()`.

 98:   This checks the options database, creates the viewer on-the-fly, uses it and then destroys it. Hence it should not be called in heavily used routines,
 99:   rather `PetscOptionsCreateViewer()` should be used to construct the viewer once which can then be utilized in the heavily used routine.

101: .seealso: `PetscObject`, `PetscObjectViewSynchronizedFromOptions()`, `PetscObjectView()`, `PetscOptionsCreateViewer()`
102: @*/
103: PetscErrorCode PetscObjectViewFromOptions(PetscObject obj, PetscObject bobj, const char name[])
104: {
105:   PetscViewer       viewer;
106:   PetscBool         flg;
107:   static PetscBool  incall = PETSC_FALSE;
108:   PetscViewerFormat format;
109:   const char       *prefix;

111:   PetscFunctionBegin;
114:   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
115:   incall = PETSC_TRUE;
116:   prefix = bobj ? bobj->prefix : obj->prefix;
117:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm(obj), obj->options, prefix, name, &viewer, &format, &flg));
118:   if (flg) {
119:     PetscCall(PetscViewerPushFormat(viewer, format));
120:     PetscCall(PetscObjectView(obj, viewer));
121:     PetscCall(PetscViewerFlush(viewer));
122:     PetscCall(PetscViewerPopFormat(viewer));
123:     PetscCall(PetscViewerDestroy(&viewer));
124:   }
125:   incall = PETSC_FALSE;
126:   PetscFunctionReturn(PETSC_SUCCESS);
127: }

129: /*@
130:   PetscObjectViewSynchronizedFromOptions - Processes command line options to determine if/how a serial `PetscObject` is to be collectively viewed.

132:   Collective

134:   Input Parameters:
135: + obj  - the serial object
136: . sobj - synchronization object that provides the synchronizing communicator
137: - name - option string that is used to activate viewing. It typically ends with `_view`.

139:   Options Database Key:
140: . -name viewer_specification - See `PetscOptionsCreateViewer()` for the values of `viewer_specification`

142:   Level: developer

144:   Notes:
145:   The objects will be viewed in sequence, following the MPI rank order.

147:   The prefix of `obj` is used to search the options database key

149: .seealso: `PetscObject`, `PetscObjectViewFromOptions()`, `PetscObjectView()`, `PetscOptionsCreateViewer()`
150: @*/
151: PetscErrorCode PetscObjectViewSynchronizedFromOptions(PetscObject obj, PetscObject sobj, const char name[])
152: {
153:   PetscViewer       viewer;
154:   PetscBool         flg;
155:   static PetscBool  incall = PETSC_FALSE;
156:   PetscViewerFormat format;

158:   PetscFunctionBegin;
161:   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
162:   incall = PETSC_TRUE;
163:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm(sobj), obj->options, obj->prefix, name, &viewer, &format, &flg));
164:   if (flg) {
165:     PetscViewer selfviewer;

167:     PetscCall(PetscViewerPushFormat(viewer, format));
168:     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
169:     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
170:     PetscCall(PetscObjectView(obj, selfviewer));
171:     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
172:     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
173:     PetscCall(PetscViewerFlush(viewer));
174:     PetscCall(PetscViewerPopFormat(viewer));
175:     PetscCall(PetscViewerDestroy(&viewer));
176:   }
177:   incall = PETSC_FALSE;
178:   PetscFunctionReturn(PETSC_SUCCESS);
179: }

181: /*@
182:   PetscObjectTypeCompare - Determines whether a PETSc object is of a particular type.

184:   Not Collective

186:   Input Parameters:
187: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
188:               `PetscObjectTypeCompare`((`PetscObject`)mat);
189: - type_name - string containing a type name

191:   Output Parameter:
192: . same - `PETSC_TRUE` if the type of `obj` and `type_name` are the same or both `NULL`, else `PETSC_FALSE`

194:   Level: intermediate

196: .seealso: `PetscObject`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`, `PetscObjectObjectTypeCompare()`
197: @*/
198: PetscErrorCode PetscObjectTypeCompare(PetscObject obj, const char type_name[], PetscBool *same)
199: {
200:   PetscFunctionBegin;
201:   PetscAssertPointer(same, 3);
202:   if (!obj) *same = (PetscBool)!type_name;
203:   else {
205:     if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name);
206:     else {
207:       PetscAssertPointer(type_name, 2);
208:       PetscCall(PetscStrcmp(obj->type_name, type_name, same));
209:     }
210:   }
211:   PetscFunctionReturn(PETSC_SUCCESS);
212: }

214: /*@
215:   PetscObjectObjectTypeCompare - Determines whether two PETSc objects are of the same type

217:   Logically Collective

219:   Input Parameters:
220: + obj1 - any PETSc object, for example a `Vec`, `Mat` or `KSP`.
221: - obj2 - another PETSc object

223:   Output Parameter:
224: . same - `PETSC_TRUE` if they are the same or both unset, else `PETSC_FALSE`

226:   Level: intermediate

228:   Note:
229:   Both objects must be of the same class, for example both `Vec` objects.

231: .seealso: `PetscObjectTypeCompare()`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`
232: @*/
233: PetscErrorCode PetscObjectObjectTypeCompare(PetscObject obj1, PetscObject obj2, PetscBool *same)
234: {
235:   PetscFunctionBegin;
238:   PetscAssertPointer(same, 3);
239:   PetscCall(PetscStrcmp(obj1->type_name, obj2->type_name, same));
240:   PetscFunctionReturn(PETSC_SUCCESS);
241: }

243: /*@
244:   PetscObjectBaseTypeCompare - Determines whether a `PetscObject` is of a given base type. For example the base type of `MATSEQAIJPERM` is `MATSEQAIJ`

246:   Not Collective

248:   Input Parameters:
249: + obj       - the object
250: - type_name - string containing a type name

252:   Output Parameter:
253: . same - `PETSC_TRUE` if the object is of the same base type identified by `type_name` or both `NULL`, `PETSC_FALSE` otherwise

255:   Level: intermediate

257: .seealso: `PetscObject`, `PetscObjectTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`
258: @*/
259: PetscErrorCode PetscObjectBaseTypeCompare(PetscObject obj, const char type_name[], PetscBool *same)
260: {
261:   PetscFunctionBegin;
262:   PetscAssertPointer(same, 3);
263:   if (!obj) *same = (PetscBool)!type_name;
264:   else {
266:     if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name);
267:     else {
268:       PetscAssertPointer(type_name, 2);
269:       PetscCall(PetscStrbeginswith(obj->type_name, type_name, same));
270:     }
271:   }
272:   PetscFunctionReturn(PETSC_SUCCESS);
273: }

275: /*@
276:   PetscObjectTypeCompareAny - Determines whether a PETSc object is of any of a list of types.

278:   Not Collective

280:   Input Parameters:
281: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`),
282:               for example, `PetscObjectTypeCompareAny`((`PetscObject`)mat,...);
283: - type_name - one or more string arguments containing type names, pass the empty string `""` as the last argument

285:   Output Parameter:
286: . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE`

288:   Level: intermediate

290: .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()`
291: @*/
292: PetscErrorCode PetscObjectTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...)
293: {
294:   va_list Argp;

296:   PetscFunctionBegin;
297:   PetscAssertPointer(match, 2);
298:   *match = PETSC_FALSE;
299:   if (!obj) PetscFunctionReturn(PETSC_SUCCESS);
300:   va_start(Argp, type_name);
301:   while (type_name && type_name[0]) {
302:     PetscBool found;
303:     PetscCall(PetscObjectTypeCompare(obj, type_name, &found));
304:     if (found) {
305:       *match = PETSC_TRUE;
306:       break;
307:     }
308:     type_name = va_arg(Argp, const char *);
309:   }
310:   va_end(Argp);
311:   PetscFunctionReturn(PETSC_SUCCESS);
312: }

314: /*@
315:   PetscObjectBaseTypeCompareAny - Determines whether a PETSc object has the base type of any of a list of types.

317:   Not Collective

319:   Input Parameters:
320: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`),
321:               for example, `PetscObjectBaseTypeCompareAny`((`PetscObject`)mat,...);
322: - type_name - one or more string arguments containing type names, pass the empty string `""` as the last argument

324:   Output Parameter:
325: . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE`

327:   Level: intermediate

329: .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`
330: @*/
331: PetscErrorCode PetscObjectBaseTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...)
332: {
333:   va_list Argp;

335:   PetscFunctionBegin;
336:   PetscAssertPointer(match, 2);
337:   *match = PETSC_FALSE;
338:   va_start(Argp, type_name);
339:   while (type_name && type_name[0]) {
340:     PetscBool found;
341:     PetscCall(PetscObjectBaseTypeCompare(obj, type_name, &found));
342:     if (found) {
343:       *match = PETSC_TRUE;
344:       break;
345:     }
346:     type_name = va_arg(Argp, const char *);
347:   }
348:   va_end(Argp);
349:   PetscFunctionReturn(PETSC_SUCCESS);
350: }

352: typedef struct {
353:   PetscErrorCode (*func)(void);
354: } PetscFinalizeFunction;

356: typedef struct {
357:   PetscErrorCode (*func)(void *);
358:   PetscCtx ctx;
359: } PetscFinalizeFunctionWithCtx;

361: typedef enum {
362:   PETSC_FINALIZE_EMPTY,
363:   PETSC_FINALIZE_OBJECT,
364:   PETSC_FINALIZE_FUNC,
365:   PETSC_FINALIZE_FUNC_WITH_CTX
366: } PetscFinalizeType;

368: static const char *const PetscFinalizeTypes[] = {"PETSC_FINALIZE_EMPTY", "PETSC_FINALIZE_OBJECT", "PETSC_FINALIZE_FUNC", "PETSC_FINALIZE_FUNC_WITH_CTX", PETSC_NULLPTR};

370: typedef struct {
371:   union ThunkUnion
372:   {
373:     PetscObject                  obj;
374:     PetscFinalizeFunction        fn;
375:     PetscFinalizeFunctionWithCtx fnctx;
376:   } thunk;
377:   PetscFinalizeType type;
378: } PetscFinalizerContainer;

380: #define PETSC_MAX_REGISTERED_FINALIZERS 256
381: static int                     reg_count = 0;
382: static PetscFinalizerContainer regfin[PETSC_MAX_REGISTERED_FINALIZERS];

384: static PetscErrorCode PetscRunRegisteredFinalizers(void)
385: {
386:   PetscFunctionBegin;
387:   while (reg_count) {
388:     PetscFinalizerContainer top = regfin[--reg_count];

390:     regfin[reg_count].type = PETSC_FINALIZE_EMPTY;
391:     PetscCall(PetscArrayzero(&regfin[reg_count].thunk, 1));
392:     switch (top.type) {
393:     case PETSC_FINALIZE_OBJECT:
394:       PetscCall(PetscObjectDestroy(&top.thunk.obj));
395:       break;
396:     case PETSC_FINALIZE_FUNC:
397:       PetscCall((*top.thunk.fn.func)());
398:       break;
399:     case PETSC_FINALIZE_FUNC_WITH_CTX:
400:       PetscCall((*top.thunk.fnctx.func)(top.thunk.fnctx.ctx));
401:       break;
402:     case PETSC_FINALIZE_EMPTY:
403:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Finalizer at position %d is empty, yet registration count %d != 0", reg_count, reg_count);
404:       break;
405:     }
406:   }
407:   PetscFunctionReturn(PETSC_SUCCESS);
408: }

410: static int PetscFinalizerContainerEqual(const PetscFinalizerContainer *a, const PetscFinalizerContainer *b)
411: {
412:   if (a->type != b->type) return 0;
413:   switch (a->type) {
414:   case PETSC_FINALIZE_EMPTY:
415:     break;
416:   case PETSC_FINALIZE_OBJECT:
417:     return a->thunk.obj == b->thunk.obj;
418:   case PETSC_FINALIZE_FUNC:
419:     return a->thunk.fn.func == b->thunk.fn.func;
420:   case PETSC_FINALIZE_FUNC_WITH_CTX:
421:     return a->thunk.fnctx.func == b->thunk.fnctx.func && a->thunk.fnctx.ctx == b->thunk.fnctx.ctx;
422:   }
423:   return 1;
424: }

426: static PetscErrorCode RegisterFinalizer(PetscFinalizerContainer container)
427: {
428:   PetscFunctionBegin;
429:   PetscAssert(reg_count < (int)PETSC_STATIC_ARRAY_LENGTH(regfin), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "No more room in array, limit %zu, recompile %s with larger value for " PetscStringize(regfin), PETSC_STATIC_ARRAY_LENGTH(regfin), __FILE__);
430:   PetscAssert(regfin[reg_count].type == PETSC_FINALIZE_EMPTY, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Finalizer type (%s) at position %d is not PETSC_FINALIZE_EMPTY!", PetscFinalizeTypes[regfin[reg_count].type], reg_count);
431:   if (PetscDefined(USE_DEBUG)) {
432:     for (int i = 0; i < reg_count; ++i) PetscCheck(!PetscFinalizerContainerEqual(regfin + i, &container), PETSC_COMM_SELF, PETSC_ERR_ORDER, "Finalizer (of type %s) already registered!", PetscFinalizeTypes[container.type]);
433:   }
434:   regfin[reg_count++] = container;
435:   PetscFunctionReturn(PETSC_SUCCESS);
436: }

438: /*@
439:   PetscObjectRegisterDestroy - Registers a PETSc object to be destroyed when
440:   `PetscFinalize()` is called.

442:   Logically Collective

444:   Input Parameter:
445: . obj - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
446:         `PetscObjectRegisterDestroy`((`PetscObject`)mat);

448:   Level: developer

450:   Notes:
451:   This is used by, for example, `PETSC_VIEWER_XXX_()` routines to free the viewer
452:   when PETSc ends.

454:   This should be used only where there is no natural location in the code to put a call to the destructor of the object.

456: .seealso: `PetscObjectRegisterDestroyAll()`
457: @*/
458: PetscErrorCode PetscObjectRegisterDestroy(PetscObject obj)
459: {
460:   PetscFinalizerContainer container;

462:   PetscFunctionBegin;
464:   container.thunk.obj = obj;
465:   container.type      = PETSC_FINALIZE_OBJECT;
466:   PetscCall(RegisterFinalizer(container));
467:   PetscFunctionReturn(PETSC_SUCCESS);
468: }

470: /*@
471:   PetscObjectRegisterDestroyAll - Frees all the PETSc objects that have been registered
472:   with `PetscObjectRegisterDestroy()`. Called by `PetscFinalize()`

474:   Logically Collective on the individual `PetscObject`s that are being processed

476:   Level: developer

478: .seealso: `PetscObjectRegisterDestroy()`
479: @*/
480: PetscErrorCode PetscObjectRegisterDestroyAll(void)
481: {
482:   PetscFunctionBegin;
483:   PetscCall(PetscRunRegisteredFinalizers());
484:   PetscFunctionReturn(PETSC_SUCCESS);
485: }

487: /*@
488:   PetscRegisterFinalize - Registers a function that is to be called in `PetscFinalize()`

490:   Not Collective

492:   Input Parameter:
493: . f - function to be called

495:   Level: developer

497:   Notes:
498:   This is used by, for example, `DMInitializePackage()` to have `DMFinalizePackage()` called

500:   Use `PetscObjectRegisterDestroy()` to register the destruction of an object in `PetscFinalize()`

502: .seealso: `PetscRegisterFinalizeAll()`, `PetscObjectRegisterDestroy()`
503: @*/
504: PetscErrorCode PetscRegisterFinalize(PetscErrorCode (*f)(void))
505: {
506:   PetscFinalizerContainer container;

508:   PetscFunctionBegin;
510:   container.thunk.fn.func = f;
511:   container.type          = PETSC_FINALIZE_FUNC;
512:   PetscCall(RegisterFinalizer(container));
513:   PetscFunctionReturn(PETSC_SUCCESS);
514: }

516: /*@
517:   PetscRegisterFinalizeAll - Runs all the finalize functions set with `PetscRegisterFinalize()`

519:   Not Collective except for registered functions that are collective

521:   Level: developer

523: .seealso: `PetscRegisterFinalize()`, `PetscObjectRegisterDestroyAll()`
524: @*/
525: PetscErrorCode PetscRegisterFinalizeAll(void)
526: {
527:   PetscFunctionBegin;
528:   PetscCall(PetscRunRegisteredFinalizers());
529:   PetscFunctionReturn(PETSC_SUCCESS);
530: }