Actual source code: destroy.c

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

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

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

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

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

 33:   Collective

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

 39:   Level: beginner

 41: .seealso: `PetscObject`
 42: @*/
 43: PetscErrorCode PetscObjectDestroy(PetscObject *obj)
 44: {
 45:   PetscFunctionBegin;
 46:   if (!obj || !*obj) PetscFunctionReturn(PETSC_SUCCESS);
 48:   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);
 49:   PetscCall((*(*obj)->bops->destroy)(obj));
 50:   PetscFunctionReturn(PETSC_SUCCESS);
 51: }

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

 56:   Collective

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

 63:   Level: intermediate

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

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

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

 82:   Collective

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

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

 92:   Level: developer

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

 97:   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,
 98:   rather `PetscOptionsCreateViewer()` should be used to construct the viewer once which can then be utilized in the heavily used routine.

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

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

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

131:   Collective

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

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

141:   Level: developer

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

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

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

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

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

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

183:   Not Collective

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

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

193:   Level: intermediate

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

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

216:   Logically Collective

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

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

225:   Level: intermediate

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

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

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

245:   Not Collective

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

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

254:   Level: intermediate

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

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

277:   Not Collective

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

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

287:   Level: intermediate

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

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

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

316:   Not Collective

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

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

326:   Level: intermediate

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

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

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

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

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

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

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

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

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

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

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

425: static PetscErrorCode RegisterFinalizer(PetscFinalizerContainer container)
426: {
427:   PetscFunctionBegin;
428:   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__);
429:   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);
430:   if (PetscDefined(USE_DEBUG)) {
431:     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]);
432:   }
433:   regfin[reg_count++] = container;
434:   PetscFunctionReturn(PETSC_SUCCESS);
435: }

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

441:   Logically Collective

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

447:   Level: developer

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

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

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

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

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

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

475:   Level: developer

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

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

489:   Not Collective

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

494:   Level: developer

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

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

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

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

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

518:   Not Collective except for registered functions that are collective

520:   Level: developer

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