xref: /petsc/src/sys/objects/destroy.c (revision 66af8762ec03dbef0e079729eb2a1734a35ed7ff)
1 /*
2      Provides utility routines for manulating any type of PETSc object.
3 */
4 #include <petsc/private/petscimpl.h> /*I   "petscsys.h"    I*/
5 #include <petscviewer.h>
6 
7 static PetscErrorCode DestroyComposedData(void ***composed_star, PetscObjectState **state_star, PetscInt *count_star, void **composed, PetscObjectState **state)
8 {
9   void **tmp_star = *composed_star;
10 
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 }
18 
19 PetscErrorCode PetscComposedQuantitiesDestroy(PetscObject obj)
20 {
21   PetscFunctionBegin;
22   PetscValidHeader(obj, 1);
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 }
30 
31 /*@
32   PetscObjectDestroy - Destroys any `PetscObject`, regardless of the type.
33 
34   Collective
35 
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);
40 
41   Level: beginner
42 
43 .seealso: `PetscObject`
44 @*/
45 PetscErrorCode PetscObjectDestroy(PetscObject *obj)
46 {
47   PetscFunctionBegin;
48   if (!obj || !*obj) PetscFunctionReturn(PETSC_SUCCESS);
49   PetscValidHeader(*obj, 1);
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 }
54 
55 /*@C
56   PetscObjectView - Views any `PetscObject`, regardless of the type.
57 
58   Collective
59 
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
65 
66   Level: intermediate
67 
68 .seealso: `PetscObject`, `PetscObjectViewFromOptions()`
69 @*/
70 PetscErrorCode PetscObjectView(PetscObject obj, PetscViewer viewer)
71 {
72   PetscFunctionBegin;
73   PetscValidHeader(obj, 1);
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));
76   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
77 
78   PetscCall((*obj->bops->view)(obj, viewer));
79   PetscFunctionReturn(PETSC_SUCCESS);
80 }
81 
82 /*@C
83   PetscObjectViewFromOptions - Processes command line options to determine if/how a `PetscObject` is to be viewed.
84 
85   Collective
86 
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
91 
92   Options Database Key:
93 . -optionname_view [viewertype]:... - option name and values. In actual usage this would be something like `-mat_coarse_view`
94 
95   Level: developer
96 
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
108 
109   This is not called directly but is called by, for example, `MatViewFromOptions()`
110 
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;
120 
121   PetscFunctionBegin;
122   PetscValidHeader(obj, 1);
123   if (bobj) PetscValidHeader(bobj, 2);
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 }
138 
139 /*@C
140   PetscObjectTypeCompare - Determines whether a PETSc object is of a particular type.
141 
142   Not Collective
143 
144   Input Parameters:
145 + obj       - any 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
149 
150   Output Parameter:
151 . same - `PETSC_TRUE` if the type of `obj` and `type_name` are the same or both `NULL`, else `PETSC_FALSE`
152 
153   Level: intermediate
154 
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 {
163     PetscValidHeader(obj, 1);
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 }
172 
173 /*@C
174   PetscObjectObjectTypeCompare - Determines whether two PETSc objects are of the same type
175 
176   Logically Collective
177 
178   Input Parameters:
179 + obj1 - any PETSc object, for example a `Vec`, `Mat` or `KSP`.
180 - obj2 - another PETSc object
181 
182   Output Parameter:
183 . same - `PETSC_TRUE` if they are the same or both unset, else `PETSC_FALSE`
184 
185   Level: intermediate
186 
187 .seealso: `PetscObjectTypeCompare()`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`
188 
189 @*/
190 PetscErrorCode PetscObjectObjectTypeCompare(PetscObject obj1, PetscObject obj2, PetscBool *same)
191 {
192   PetscFunctionBegin;
193   PetscValidHeader(obj1, 1);
194   PetscValidHeader(obj2, 2);
195   PetscAssertPointer(same, 3);
196   PetscCall(PetscStrcmp(obj1->type_name, obj2->type_name, same));
197   PetscFunctionReturn(PETSC_SUCCESS);
198 }
199 
200 /*@C
201   PetscObjectBaseTypeCompare - Determines whether a `PetscObject` is of a given base type. For example the base type of `MATSEQAIJPERM` is `MATSEQAIJ`
202 
203   Not Collective
204 
205   Input Parameters:
206 + obj       - the matrix
207 - type_name - string containing a type name
208 
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
211 
212   Level: intermediate
213 
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 {
222     PetscValidHeader(obj, 1);
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 }
231 
232 /*@C
233   PetscObjectTypeCompareAny - Determines whether a PETSc object is of any of a list of types.
234 
235   Not Collective
236 
237   Input Parameters:
238 + obj       - any 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
241 
242   Output Parameter:
243 . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE`
244 
245   Level: intermediate
246 
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;
252 
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 }
270 
271 /*@C
272   PetscObjectBaseTypeCompareAny - Determines whether a PETSc object has the base type of any of a list of types.
273 
274   Not Collective
275 
276   Input Parameters:
277 + obj       - any 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
280 
281   Output Parameter:
282 . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE`
283 
284   Level: intermediate
285 
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;
291 
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 }
308 
309 typedef struct {
310   PetscErrorCode (*func)(void);
311 } PetscFinalizeFunction;
312 
313 typedef struct {
314   PetscErrorCode (*func)(void *);
315   void *ctx;
316 } PetscFinalizeFunctionWithCtx;
317 
318 typedef enum {
319   PETSC_FINALIZE_EMPTY,
320   PETSC_FINALIZE_OBJECT,
321   PETSC_FINALIZE_FUNC,
322   PETSC_FINALIZE_FUNC_WITH_CTX
323 } PetscFinalizeType;
324 
325 static const char *const PetscFinalizeTypes[] = {"PETSC_FINALIZE_EMPTY", "PETSC_FINALIZE_OBJECT", "PETSC_FINALIZE_FUNC", "PETSC_FINALIZE_FUNC_WITH_CTX", PETSC_NULLPTR};
326 
327 typedef struct {
328   union ThunkUnion
329   {
330     PetscObject                  obj;
331     PetscFinalizeFunction        fn;
332     PetscFinalizeFunctionWithCtx fnctx;
333   } thunk;
334   PetscFinalizeType type;
335 } PetscFinalizerContainer;
336 
337 #define PETSC_MAX_REGISTERED_FINALIZERS 256
338 static int                     reg_count = 0;
339 static PetscFinalizerContainer regfin[PETSC_MAX_REGISTERED_FINALIZERS];
340 
341 static PetscErrorCode PetscRunRegisteredFinalizers(void)
342 {
343   PetscFunctionBegin;
344   while (reg_count) {
345     PetscFinalizerContainer top = regfin[--reg_count];
346 
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 }
367 
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 }
383 
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 }
395 
396 /*@C
397   PetscObjectRegisterDestroy - Registers a PETSc object to be destroyed when
398   `PetscFinalize()` is called.
399 
400   Logically Collective
401 
402   Input Parameter:
403 . obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`.
404          This must be cast with a (`PetscObject`), for example,
405          `PetscObjectRegisterDestroy`((`PetscObject`)mat);
406 
407   Level: developer
408 
409   Note:
410   This is used by, for example, `PETSC_VIEWER_XXX_()` routines to free the viewer
411   when PETSc ends.
412 
413 .seealso: `PetscObjectRegisterDestroyAll()`
414 @*/
415 PetscErrorCode PetscObjectRegisterDestroy(PetscObject obj)
416 {
417   PetscFinalizerContainer container;
418 
419   PetscFunctionBegin;
420   PetscValidHeader(obj, 1);
421   container.thunk.obj = obj;
422   container.type      = PETSC_FINALIZE_OBJECT;
423   PetscCall(RegisterFinalizer(container));
424   PetscFunctionReturn(PETSC_SUCCESS);
425 }
426 
427 /*@C
428   PetscObjectRegisterDestroyAll - Frees all the PETSc objects that have been registered
429   with `PetscObjectRegisterDestroy()`. Called by `PetscFinalize()`
430 
431   Logically Collective on the individual `PetscObject`s that are being processed
432 
433   Level: developer
434 
435 .seealso: `PetscObjectRegisterDestroy()`
436 @*/
437 PetscErrorCode PetscObjectRegisterDestroyAll(void)
438 {
439   PetscFunctionBegin;
440   PetscCall(PetscRunRegisteredFinalizers());
441   PetscFunctionReturn(PETSC_SUCCESS);
442 }
443 
444 /*@C
445   PetscRegisterFinalize - Registers a function that is to be called in `PetscFinalize()`
446 
447   Not Collective
448 
449   Input Parameter:
450 . f - function to be called
451 
452   Level: developer
453 
454   Notes:
455   This is used by, for example, `DMInitializePackage()` to have `DMFinalizePackage()` called
456 
457   Use `PetscObjectRegisterDestroy()` to register the destruction of an object in `PetscFinalize()`
458 
459 .seealso: `PetscRegisterFinalizeAll()`, `PetscObjectRegisterDestroy()`
460 @*/
461 PetscErrorCode PetscRegisterFinalize(PetscErrorCode (*f)(void))
462 {
463   PetscFinalizerContainer container;
464 
465   PetscFunctionBegin;
466   PetscValidFunction(f, 1);
467   container.thunk.fn.func = f;
468   container.type          = PETSC_FINALIZE_FUNC;
469   PetscCall(RegisterFinalizer(container));
470   PetscFunctionReturn(PETSC_SUCCESS);
471 }
472 
473 /*@C
474   PetscRegisterFinalizeAll - Runs all the finalize functions set with `PetscRegisterFinalize()`
475 
476   Not Collective unless registered functions are collective
477 
478   Level: developer
479 
480 .seealso: `PetscRegisterFinalize()`, `PetscObjectRegisterDestroyAll()`
481 @*/
482 PetscErrorCode PetscRegisterFinalizeAll(void)
483 {
484   PetscFunctionBegin;
485   PetscCall(PetscRunRegisteredFinalizers());
486   PetscFunctionReturn(PETSC_SUCCESS);
487 }
488