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