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 type.

 34:   Collective

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

 41:   Level: beginner

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

 55: /*@C
 56:   PetscObjectView - Views a `PetscObject`, regardless of the type.

 58:   Collective

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

 66:   Level: intermediate

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

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

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

 85:   Collective

 87:   Input Parameters:
 88: + obj        - the object
 89: . bobj       - optional other object that provides prefix (if `NULL` then the prefix in `obj` is used)
 90: - optionname - option string that is used to activate viewing

 92:   Options Database Key:
 93: . -optionname_view [viewertype]:... - option name and values. In actual usage this would be something like `-mat_coarse_view`

 95:   Level: developer

 97:   Notes:
 98: .vb
 99:     If no value is provided ascii:stdout is used
100:        ascii[:[filename][:[format][:append]]]    defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
101:                                                   for example ascii::ascii_info prints just the information about the object not all details
102:                                                   unless :append is given filename opens in write mode, overwriting what was already there
103:        binary[:[filename][:[format][:append]]]   defaults to the file binaryoutput
104:        draw[:drawtype[:filename]]                for example, draw:tikz, draw:tikz:figure.tex  or draw:x
105:        socket[:port]                             defaults to the standard output port
106:        saws[:communicatorname]                    publishes object to the Scientific Application Webserver (SAWs)
107: .ve

109:   This is not called directly but is called by, for example, `MatViewFromOptions()`

111: .seealso: `PetscObject`, `PetscObjectView()`, `PetscOptionsGetViewer()`
112: @*/
113: PetscErrorCode PetscObjectViewFromOptions(PetscObject obj, PetscObject bobj, const char optionname[])
114: {
115:   PetscViewer       viewer;
116:   PetscBool         flg;
117:   static PetscBool  incall = PETSC_FALSE;
118:   PetscViewerFormat format;
119:   const char       *prefix;

121:   PetscFunctionBegin;
124:   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
125:   incall = PETSC_TRUE;
126:   prefix = bobj ? bobj->prefix : obj->prefix;
127:   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)obj), obj->options, prefix, optionname, &viewer, &format, &flg));
128:   if (flg) {
129:     PetscCall(PetscViewerPushFormat(viewer, format));
130:     PetscCall(PetscObjectView(obj, viewer));
131:     PetscCall(PetscViewerFlush(viewer));
132:     PetscCall(PetscViewerPopFormat(viewer));
133:     PetscCall(PetscViewerDestroy(&viewer));
134:   }
135:   incall = PETSC_FALSE;
136:   PetscFunctionReturn(PETSC_SUCCESS);
137: }

139: /*@C
140:   PetscObjectTypeCompare - Determines whether a PETSc object is of a particular type.

142:   Not Collective

144:   Input Parameters:
145: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`.
146:          This must be cast with a (`PetscObject`), for example,
147:          `PetscObjectTypeCompare`((`PetscObject`)mat);
148: - type_name - string containing a type name

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

153:   Level: intermediate

155: .seealso: `PetscObject`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`, `PetscObjectObjectTypeCompare()`
156: @*/
157: PetscErrorCode PetscObjectTypeCompare(PetscObject obj, const char type_name[], PetscBool *same)
158: {
159:   PetscFunctionBegin;
160:   PetscAssertPointer(same, 3);
161:   if (!obj) *same = (PetscBool)!type_name;
162:   else {
164:     if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name);
165:     else {
166:       PetscAssertPointer(type_name, 2);
167:       PetscCall(PetscStrcmp(obj->type_name, type_name, same));
168:     }
169:   }
170:   PetscFunctionReturn(PETSC_SUCCESS);
171: }

173: /*@C
174:   PetscObjectObjectTypeCompare - Determines whether two PETSc objects are of the same type

176:   Logically Collective

178:   Input Parameters:
179: + obj1 - any PETSc object, for example a `Vec`, `Mat` or `KSP`.
180: - obj2 - another PETSc object

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

185:   Level: intermediate

187: .seealso: `PetscObjectTypeCompare()`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`

189: @*/
190: PetscErrorCode PetscObjectObjectTypeCompare(PetscObject obj1, PetscObject obj2, PetscBool *same)
191: {
192:   PetscFunctionBegin;
195:   PetscAssertPointer(same, 3);
196:   PetscCall(PetscStrcmp(obj1->type_name, obj2->type_name, same));
197:   PetscFunctionReturn(PETSC_SUCCESS);
198: }

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

203:   Not Collective

205:   Input Parameters:
206: + obj       - the matrix
207: - type_name - string containing a type name

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

212:   Level: intermediate

214: .seealso: `PetscObject`, `PetscObjectTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`
215: @*/
216: PetscErrorCode PetscObjectBaseTypeCompare(PetscObject obj, const char type_name[], PetscBool *same)
217: {
218:   PetscFunctionBegin;
219:   PetscAssertPointer(same, 3);
220:   if (!obj) *same = (PetscBool)!type_name;
221:   else {
223:     if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name);
224:     else {
225:       PetscAssertPointer(type_name, 2);
226:       PetscCall(PetscStrbeginswith(obj->type_name, type_name, same));
227:     }
228:   }
229:   PetscFunctionReturn(PETSC_SUCCESS);
230: }

232: /*@C
233:   PetscObjectTypeCompareAny - Determines whether a PETSc object is of any of a list of types.

235:   Not Collective

237:   Input Parameters:
238: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`.
239:          This must be cast with a (`PetscObject`), for example, `PetscObjectTypeCompareAny`((`PetscObject`)mat,...);
240: - type_name - array of strings containing type names, pass the empty string "" to terminate the list

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

245:   Level: intermediate

247: .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()`
248: @*/
249: PetscErrorCode PetscObjectTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...)
250: {
251:   va_list Argp;

253:   PetscFunctionBegin;
254:   PetscAssertPointer(match, 2);
255:   *match = PETSC_FALSE;
256:   if (!obj) PetscFunctionReturn(PETSC_SUCCESS);
257:   va_start(Argp, type_name);
258:   while (type_name && type_name[0]) {
259:     PetscBool found;
260:     PetscCall(PetscObjectTypeCompare(obj, type_name, &found));
261:     if (found) {
262:       *match = PETSC_TRUE;
263:       break;
264:     }
265:     type_name = va_arg(Argp, const char *);
266:   }
267:   va_end(Argp);
268:   PetscFunctionReturn(PETSC_SUCCESS);
269: }

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

274:   Not Collective

276:   Input Parameters:
277: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`.
278:          This must be cast with a (`PetscObject`), for example, `PetscObjectBaseTypeCompareAny`((`PetscObject`)mat,...);
279: - type_name - array of strings containing type names, pass the empty string "" to terminate the list

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

284:   Level: intermediate

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

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

309: typedef struct {
310:   PetscErrorCode (*func)(void);
311: } PetscFinalizeFunction;

313: typedef struct {
314:   PetscErrorCode (*func)(void *);
315:   void *ctx;
316: } PetscFinalizeFunctionWithCtx;

318: typedef enum {
319:   PETSC_FINALIZE_EMPTY,
320:   PETSC_FINALIZE_OBJECT,
321:   PETSC_FINALIZE_FUNC,
322:   PETSC_FINALIZE_FUNC_WITH_CTX
323: } PetscFinalizeType;

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

327: typedef struct {
328:   union ThunkUnion
329:   {
330:     PetscObject                  obj;
331:     PetscFinalizeFunction        fn;
332:     PetscFinalizeFunctionWithCtx fnctx;
333:   } thunk;
334:   PetscFinalizeType type;
335: } PetscFinalizerContainer;

337: #define PETSC_MAX_REGISTERED_FINALIZERS 256
338: static int                     reg_count = 0;
339: static PetscFinalizerContainer regfin[PETSC_MAX_REGISTERED_FINALIZERS];

341: static PetscErrorCode PetscRunRegisteredFinalizers(void)
342: {
343:   PetscFunctionBegin;
344:   while (reg_count) {
345:     PetscFinalizerContainer top = regfin[--reg_count];

347:     regfin[reg_count].type = PETSC_FINALIZE_EMPTY;
348:     PetscCall(PetscArrayzero(&regfin[reg_count].thunk, 1));
349:     switch (top.type) {
350:     case PETSC_FINALIZE_OBJECT:
351:       top.thunk.obj->persistent = PETSC_FALSE;
352:       PetscCall(PetscObjectDestroy(&top.thunk.obj));
353:       break;
354:     case PETSC_FINALIZE_FUNC:
355:       PetscCall((*top.thunk.fn.func)());
356:       break;
357:     case PETSC_FINALIZE_FUNC_WITH_CTX:
358:       PetscCall((*top.thunk.fnctx.func)(top.thunk.fnctx.ctx));
359:       break;
360:     case PETSC_FINALIZE_EMPTY:
361:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Finalizer at position %d is empty, yet registration count %d != 0", reg_count, reg_count);
362:       break;
363:     }
364:   }
365:   PetscFunctionReturn(PETSC_SUCCESS);
366: }

368: static int PetscFinalizerContainerEqual(const PetscFinalizerContainer *a, const PetscFinalizerContainer *b)
369: {
370:   if (a->type != b->type) return 0;
371:   switch (a->type) {
372:   case PETSC_FINALIZE_EMPTY:
373:     break;
374:   case PETSC_FINALIZE_OBJECT:
375:     return a->thunk.obj == b->thunk.obj;
376:   case PETSC_FINALIZE_FUNC:
377:     return a->thunk.fn.func == b->thunk.fn.func;
378:   case PETSC_FINALIZE_FUNC_WITH_CTX:
379:     return a->thunk.fnctx.func == b->thunk.fnctx.func && a->thunk.fnctx.ctx == b->thunk.fnctx.ctx;
380:   }
381:   return 1;
382: }

384: static PetscErrorCode RegisterFinalizer(PetscFinalizerContainer container)
385: {
386:   PetscFunctionBegin;
387:   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__);
388:   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);
389:   if (PetscDefined(USE_DEBUG)) {
390:     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]);
391:   }
392:   regfin[reg_count++] = container;
393:   PetscFunctionReturn(PETSC_SUCCESS);
394: }

396: /*@C
397:   PetscObjectRegisterDestroy - Registers a PETSc object to be destroyed when
398:   `PetscFinalize()` is called.

400:   Logically Collective

402:   Input Parameter:
403: . obj - a PETSc object, for example a `Vec`, `Mat` or `KSP`.
404:          This must be cast with a (`PetscObject`), for example,
405:          `PetscObjectRegisterDestroy`((`PetscObject`)mat);

407:   Level: developer

409:   Note:
410:   This is used by, for example, `PETSC_VIEWER_XXX_()` routines to free the viewer
411:   when PETSc ends.

413: .seealso: `PetscObjectRegisterDestroyAll()`
414: @*/
415: PetscErrorCode PetscObjectRegisterDestroy(PetscObject obj)
416: {
417:   PetscFinalizerContainer container;

419:   PetscFunctionBegin;
421:   container.thunk.obj = obj;
422:   container.type      = PETSC_FINALIZE_OBJECT;
423:   PetscCall(RegisterFinalizer(container));
424:   PetscFunctionReturn(PETSC_SUCCESS);
425: }

427: /*@C
428:   PetscObjectRegisterDestroyAll - Frees all the PETSc objects that have been registered
429:   with `PetscObjectRegisterDestroy()`. Called by `PetscFinalize()`

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

433:   Level: developer

435: .seealso: `PetscObjectRegisterDestroy()`
436: @*/
437: PetscErrorCode PetscObjectRegisterDestroyAll(void)
438: {
439:   PetscFunctionBegin;
440:   PetscCall(PetscRunRegisteredFinalizers());
441:   PetscFunctionReturn(PETSC_SUCCESS);
442: }

444: /*@C
445:   PetscRegisterFinalize - Registers a function that is to be called in `PetscFinalize()`

447:   Not Collective

449:   Input Parameter:
450: . f - function to be called

452:   Level: developer

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

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

459: .seealso: `PetscRegisterFinalizeAll()`, `PetscObjectRegisterDestroy()`
460: @*/
461: PetscErrorCode PetscRegisterFinalize(PetscErrorCode (*f)(void))
462: {
463:   PetscFinalizerContainer container;

465:   PetscFunctionBegin;
467:   container.thunk.fn.func = f;
468:   container.type          = PETSC_FINALIZE_FUNC;
469:   PetscCall(RegisterFinalizer(container));
470:   PetscFunctionReturn(PETSC_SUCCESS);
471: }

473: /*@C
474:   PetscRegisterFinalizeAll - Runs all the finalize functions set with `PetscRegisterFinalize()`

476:   Not Collective unless registered functions are collective

478:   Level: developer

480: .seealso: `PetscRegisterFinalize()`, `PetscObjectRegisterDestroyAll()`
481: @*/
482: PetscErrorCode PetscRegisterFinalizeAll(void)
483: {
484:   PetscFunctionBegin;
485:   PetscCall(PetscRunRegisteredFinalizers());
486:   PetscFunctionReturn(PETSC_SUCCESS);
487: }