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