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(®fin[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: }