xref: /petsc/src/sys/objects/destroy.c (revision 34c645fd3b0199e05bec2fcc32d3597bfeb7f4f2)
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 a `PetscObject`, regardless of the type.
33 
34   Collective
35 
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);
39 
40   Level: beginner
41 
42 .seealso: `PetscObject`
43 @*/
44 PetscErrorCode PetscObjectDestroy(PetscObject *obj)
45 {
46   PetscFunctionBegin;
47   if (!obj || !*obj) PetscFunctionReturn(PETSC_SUCCESS);
48   PetscValidHeader(*obj, 1);
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 }
53 
54 /*@C
55   PetscObjectView - Views a `PetscObject` regardless of the type.
56 
57   Collective
58 
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
63 
64   Level: intermediate
65 
66 .seealso: `PetscObject`, `PetscObjectViewFromOptions()`, `PetscViewer`
67 @*/
68 PetscErrorCode PetscObjectView(PetscObject obj, PetscViewer viewer)
69 {
70   PetscFunctionBegin;
71   PetscValidHeader(obj, 1);
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));
74   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
75 
76   PetscCall((*obj->bops->view)(obj, viewer));
77   PetscFunctionReturn(PETSC_SUCCESS);
78 }
79 
80 /*@C
81   PetscObjectViewFromOptions - Processes command line options to determine if/how a `PetscObject` is to be viewed.
82 
83   Collective
84 
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 - optionname - option string that is used to activate viewing
89 
90   Options Database Key:
91 . -optionname_view [viewertype]:... - option name and values. In actual usage this would be something like `-mat_coarse_view`
92 
93   Level: developer
94 
95   Notes:
96 .vb
97     If no value is provided ascii:stdout is used
98        ascii[:[filename][:[format][:append]]]    defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
99                                                   for example ascii::ascii_info prints just the information about the object not all details
100                                                   unless :append is given filename opens in write mode, overwriting what was already there
101        binary[:[filename][:[format][:append]]]   defaults to the file binaryoutput
102        draw[:drawtype[:filename]]                for example, draw:tikz, draw:tikz:figure.tex  or draw:x
103        socket[:port]                             defaults to the standard output port
104        saws[:communicatorname]                    publishes object to the Scientific Application Webserver (SAWs)
105 .ve
106 
107   This is not called directly but is called by, for example, `MatViewFromOptions()`
108 
109 .seealso: `PetscObject`, `PetscObjectView()`, `PetscOptionsGetViewer()`
110 @*/
111 PetscErrorCode PetscObjectViewFromOptions(PetscObject obj, PetscObject bobj, const char optionname[])
112 {
113   PetscViewer       viewer;
114   PetscBool         flg;
115   static PetscBool  incall = PETSC_FALSE;
116   PetscViewerFormat format;
117   const char       *prefix;
118 
119   PetscFunctionBegin;
120   PetscValidHeader(obj, 1);
121   if (bobj) PetscValidHeader(bobj, 2);
122   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
123   incall = PETSC_TRUE;
124   prefix = bobj ? bobj->prefix : obj->prefix;
125   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)obj), obj->options, prefix, optionname, &viewer, &format, &flg));
126   if (flg) {
127     PetscCall(PetscViewerPushFormat(viewer, format));
128     PetscCall(PetscObjectView(obj, viewer));
129     PetscCall(PetscViewerFlush(viewer));
130     PetscCall(PetscViewerPopFormat(viewer));
131     PetscCall(PetscOptionsRestoreViewer(&viewer));
132   }
133   incall = PETSC_FALSE;
134   PetscFunctionReturn(PETSC_SUCCESS);
135 }
136 
137 /*@C
138   PetscObjectTypeCompare - Determines whether a PETSc object is of a particular type.
139 
140   Not Collective
141 
142   Input Parameters:
143 + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
144               `PetscObjectTypeCompare`((`PetscObject`)mat);
145 - type_name - string containing a type name
146 
147   Output Parameter:
148 . same - `PETSC_TRUE` if the type of `obj` and `type_name` are the same or both `NULL`, else `PETSC_FALSE`
149 
150   Level: intermediate
151 
152 .seealso: `PetscObject`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`, `PetscObjectObjectTypeCompare()`
153 @*/
154 PetscErrorCode PetscObjectTypeCompare(PetscObject obj, const char type_name[], PetscBool *same)
155 {
156   PetscFunctionBegin;
157   PetscAssertPointer(same, 3);
158   if (!obj) *same = (PetscBool)!type_name;
159   else {
160     PetscValidHeader(obj, 1);
161     if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name);
162     else {
163       PetscAssertPointer(type_name, 2);
164       PetscCall(PetscStrcmp(obj->type_name, type_name, same));
165     }
166   }
167   PetscFunctionReturn(PETSC_SUCCESS);
168 }
169 
170 /*@C
171   PetscObjectObjectTypeCompare - Determines whether two PETSc objects are of the same type
172 
173   Logically Collective
174 
175   Input Parameters:
176 + obj1 - any PETSc object, for example a `Vec`, `Mat` or `KSP`.
177 - obj2 - another PETSc object
178 
179   Output Parameter:
180 . same - `PETSC_TRUE` if they are the same or both unset, else `PETSC_FALSE`
181 
182   Level: intermediate
183 
184 .seealso: `PetscObjectTypeCompare()`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`
185 
186 @*/
187 PetscErrorCode PetscObjectObjectTypeCompare(PetscObject obj1, PetscObject obj2, PetscBool *same)
188 {
189   PetscFunctionBegin;
190   PetscValidHeader(obj1, 1);
191   PetscValidHeader(obj2, 2);
192   PetscAssertPointer(same, 3);
193   PetscCall(PetscStrcmp(obj1->type_name, obj2->type_name, same));
194   PetscFunctionReturn(PETSC_SUCCESS);
195 }
196 
197 /*@C
198   PetscObjectBaseTypeCompare - Determines whether a `PetscObject` is of a given base type. For example the base type of `MATSEQAIJPERM` is `MATSEQAIJ`
199 
200   Not Collective
201 
202   Input Parameters:
203 + obj       - the object
204 - type_name - string containing a type name
205 
206   Output Parameter:
207 . same - `PETSC_TRUE` if the object is of the same base type identified by `type_name` or both `NULL`, `PETSC_FALSE` otherwise
208 
209   Level: intermediate
210 
211 .seealso: `PetscObject`, `PetscObjectTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`
212 @*/
213 PetscErrorCode PetscObjectBaseTypeCompare(PetscObject obj, const char type_name[], PetscBool *same)
214 {
215   PetscFunctionBegin;
216   PetscAssertPointer(same, 3);
217   if (!obj) *same = (PetscBool)!type_name;
218   else {
219     PetscValidHeader(obj, 1);
220     if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name);
221     else {
222       PetscAssertPointer(type_name, 2);
223       PetscCall(PetscStrbeginswith(obj->type_name, type_name, same));
224     }
225   }
226   PetscFunctionReturn(PETSC_SUCCESS);
227 }
228 
229 /*@C
230   PetscObjectTypeCompareAny - Determines whether a PETSc object is of any of a list of types.
231 
232   Not Collective
233 
234   Input Parameters:
235 + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`),
236               for example, `PetscObjectTypeCompareAny`((`PetscObject`)mat,...);
237 - type_name - one or more string arguments containing type names, pass the empty string "" as the last argument
238 
239   Output Parameter:
240 . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE`
241 
242   Level: intermediate
243 
244 .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()`
245 @*/
246 PetscErrorCode PetscObjectTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...)
247 {
248   va_list Argp;
249 
250   PetscFunctionBegin;
251   PetscAssertPointer(match, 2);
252   *match = PETSC_FALSE;
253   if (!obj) PetscFunctionReturn(PETSC_SUCCESS);
254   va_start(Argp, type_name);
255   while (type_name && type_name[0]) {
256     PetscBool found;
257     PetscCall(PetscObjectTypeCompare(obj, type_name, &found));
258     if (found) {
259       *match = PETSC_TRUE;
260       break;
261     }
262     type_name = va_arg(Argp, const char *);
263   }
264   va_end(Argp);
265   PetscFunctionReturn(PETSC_SUCCESS);
266 }
267 
268 /*@C
269   PetscObjectBaseTypeCompareAny - Determines whether a PETSc object has the base type of any of a list of types.
270 
271   Not Collective
272 
273   Input Parameters:
274 + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`),
275               for example, `PetscObjectBaseTypeCompareAny`((`PetscObject`)mat,...);
276 - type_name - one or more string arguments containing type names, pass the empty string "" as the last argument
277 
278   Output Parameter:
279 . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE`
280 
281   Level: intermediate
282 
283 .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`
284 @*/
285 PetscErrorCode PetscObjectBaseTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...)
286 {
287   va_list Argp;
288 
289   PetscFunctionBegin;
290   PetscAssertPointer(match, 2);
291   *match = PETSC_FALSE;
292   va_start(Argp, type_name);
293   while (type_name && type_name[0]) {
294     PetscBool found;
295     PetscCall(PetscObjectBaseTypeCompare(obj, type_name, &found));
296     if (found) {
297       *match = PETSC_TRUE;
298       break;
299     }
300     type_name = va_arg(Argp, const char *);
301   }
302   va_end(Argp);
303   PetscFunctionReturn(PETSC_SUCCESS);
304 }
305 
306 typedef struct {
307   PetscErrorCode (*func)(void);
308 } PetscFinalizeFunction;
309 
310 typedef struct {
311   PetscErrorCode (*func)(void *);
312   void *ctx;
313 } PetscFinalizeFunctionWithCtx;
314 
315 typedef enum {
316   PETSC_FINALIZE_EMPTY,
317   PETSC_FINALIZE_OBJECT,
318   PETSC_FINALIZE_FUNC,
319   PETSC_FINALIZE_FUNC_WITH_CTX
320 } PetscFinalizeType;
321 
322 static const char *const PetscFinalizeTypes[] = {"PETSC_FINALIZE_EMPTY", "PETSC_FINALIZE_OBJECT", "PETSC_FINALIZE_FUNC", "PETSC_FINALIZE_FUNC_WITH_CTX", PETSC_NULLPTR};
323 
324 typedef struct {
325   union ThunkUnion
326   {
327     PetscObject                  obj;
328     PetscFinalizeFunction        fn;
329     PetscFinalizeFunctionWithCtx fnctx;
330   } thunk;
331   PetscFinalizeType type;
332 } PetscFinalizerContainer;
333 
334 #define PETSC_MAX_REGISTERED_FINALIZERS 256
335 static int                     reg_count = 0;
336 static PetscFinalizerContainer regfin[PETSC_MAX_REGISTERED_FINALIZERS];
337 
338 static PetscErrorCode PetscRunRegisteredFinalizers(void)
339 {
340   PetscFunctionBegin;
341   while (reg_count) {
342     PetscFinalizerContainer top = regfin[--reg_count];
343 
344     regfin[reg_count].type = PETSC_FINALIZE_EMPTY;
345     PetscCall(PetscArrayzero(&regfin[reg_count].thunk, 1));
346     switch (top.type) {
347     case PETSC_FINALIZE_OBJECT:
348       top.thunk.obj->persistent = PETSC_FALSE;
349       PetscCall(PetscObjectDestroy(&top.thunk.obj));
350       break;
351     case PETSC_FINALIZE_FUNC:
352       PetscCall((*top.thunk.fn.func)());
353       break;
354     case PETSC_FINALIZE_FUNC_WITH_CTX:
355       PetscCall((*top.thunk.fnctx.func)(top.thunk.fnctx.ctx));
356       break;
357     case PETSC_FINALIZE_EMPTY:
358       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Finalizer at position %d is empty, yet registration count %d != 0", reg_count, reg_count);
359       break;
360     }
361   }
362   PetscFunctionReturn(PETSC_SUCCESS);
363 }
364 
365 static int PetscFinalizerContainerEqual(const PetscFinalizerContainer *a, const PetscFinalizerContainer *b)
366 {
367   if (a->type != b->type) return 0;
368   switch (a->type) {
369   case PETSC_FINALIZE_EMPTY:
370     break;
371   case PETSC_FINALIZE_OBJECT:
372     return a->thunk.obj == b->thunk.obj;
373   case PETSC_FINALIZE_FUNC:
374     return a->thunk.fn.func == b->thunk.fn.func;
375   case PETSC_FINALIZE_FUNC_WITH_CTX:
376     return a->thunk.fnctx.func == b->thunk.fnctx.func && a->thunk.fnctx.ctx == b->thunk.fnctx.ctx;
377   }
378   return 1;
379 }
380 
381 static PetscErrorCode RegisterFinalizer(PetscFinalizerContainer container)
382 {
383   PetscFunctionBegin;
384   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__);
385   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);
386   if (PetscDefined(USE_DEBUG)) {
387     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]);
388   }
389   regfin[reg_count++] = container;
390   PetscFunctionReturn(PETSC_SUCCESS);
391 }
392 
393 /*@C
394   PetscObjectRegisterDestroy - Registers a PETSc object to be destroyed when
395   `PetscFinalize()` is called.
396 
397   Logically Collective
398 
399   Input Parameter:
400 . obj - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
401         `PetscObjectRegisterDestroy`((`PetscObject`)mat);
402 
403   Level: developer
404 
405   Note:
406   This is used by, for example, `PETSC_VIEWER_XXX_()` routines to free the viewer
407   when PETSc ends.
408 
409 .seealso: `PetscObjectRegisterDestroyAll()`
410 @*/
411 PetscErrorCode PetscObjectRegisterDestroy(PetscObject obj)
412 {
413   PetscFinalizerContainer container;
414 
415   PetscFunctionBegin;
416   PetscValidHeader(obj, 1);
417   container.thunk.obj = obj;
418   container.type      = PETSC_FINALIZE_OBJECT;
419   PetscCall(RegisterFinalizer(container));
420   PetscFunctionReturn(PETSC_SUCCESS);
421 }
422 
423 /*@C
424   PetscObjectRegisterDestroyAll - Frees all the PETSc objects that have been registered
425   with `PetscObjectRegisterDestroy()`. Called by `PetscFinalize()`
426 
427   Logically Collective on the individual `PetscObject`s that are being processed
428 
429   Level: developer
430 
431 .seealso: `PetscObjectRegisterDestroy()`
432 @*/
433 PetscErrorCode PetscObjectRegisterDestroyAll(void)
434 {
435   PetscFunctionBegin;
436   PetscCall(PetscRunRegisteredFinalizers());
437   PetscFunctionReturn(PETSC_SUCCESS);
438 }
439 
440 /*@C
441   PetscRegisterFinalize - Registers a function that is to be called in `PetscFinalize()`
442 
443   Not Collective
444 
445   Input Parameter:
446 . f - function to be called
447 
448   Level: developer
449 
450   Notes:
451   This is used by, for example, `DMInitializePackage()` to have `DMFinalizePackage()` called
452 
453   Use `PetscObjectRegisterDestroy()` to register the destruction of an object in `PetscFinalize()`
454 
455 .seealso: `PetscRegisterFinalizeAll()`, `PetscObjectRegisterDestroy()`
456 @*/
457 PetscErrorCode PetscRegisterFinalize(PetscErrorCode (*f)(void))
458 {
459   PetscFinalizerContainer container;
460 
461   PetscFunctionBegin;
462   PetscValidFunction(f, 1);
463   container.thunk.fn.func = f;
464   container.type          = PETSC_FINALIZE_FUNC;
465   PetscCall(RegisterFinalizer(container));
466   PetscFunctionReturn(PETSC_SUCCESS);
467 }
468 
469 /*@C
470   PetscRegisterFinalizeAll - Runs all the finalize functions set with `PetscRegisterFinalize()`
471 
472   Not Collective unless registered functions are collective
473 
474   Level: developer
475 
476 .seealso: `PetscRegisterFinalize()`, `PetscObjectRegisterDestroyAll()`
477 @*/
478 PetscErrorCode PetscRegisterFinalizeAll(void)
479 {
480   PetscFunctionBegin;
481   PetscCall(PetscRunRegisteredFinalizers());
482   PetscFunctionReturn(PETSC_SUCCESS);
483 }
484