xref: /petsc/src/sys/objects/destroy.c (revision 98d129c30f3ee9fdddc40fdbc5a989b7be64f888)
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   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()`, `PetscOptionsGetViewer()`
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(PetscOptionsGetViewer(PetscObjectComm((PetscObject)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(PetscOptionsRestoreViewer(&viewer));
141   }
142   incall = PETSC_FALSE;
143   PetscFunctionReturn(PETSC_SUCCESS);
144 }
145 
146 /*@C
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 /*@C
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 /*@C
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   void *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       top.thunk.obj->persistent = PETSC_FALSE;
358       PetscCall(PetscObjectDestroy(&top.thunk.obj));
359       break;
360     case PETSC_FINALIZE_FUNC:
361       PetscCall((*top.thunk.fn.func)());
362       break;
363     case PETSC_FINALIZE_FUNC_WITH_CTX:
364       PetscCall((*top.thunk.fnctx.func)(top.thunk.fnctx.ctx));
365       break;
366     case PETSC_FINALIZE_EMPTY:
367       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Finalizer at position %d is empty, yet registration count %d != 0", reg_count, reg_count);
368       break;
369     }
370   }
371   PetscFunctionReturn(PETSC_SUCCESS);
372 }
373 
374 static int PetscFinalizerContainerEqual(const PetscFinalizerContainer *a, const PetscFinalizerContainer *b)
375 {
376   if (a->type != b->type) return 0;
377   switch (a->type) {
378   case PETSC_FINALIZE_EMPTY:
379     break;
380   case PETSC_FINALIZE_OBJECT:
381     return a->thunk.obj == b->thunk.obj;
382   case PETSC_FINALIZE_FUNC:
383     return a->thunk.fn.func == b->thunk.fn.func;
384   case PETSC_FINALIZE_FUNC_WITH_CTX:
385     return a->thunk.fnctx.func == b->thunk.fnctx.func && a->thunk.fnctx.ctx == b->thunk.fnctx.ctx;
386   }
387   return 1;
388 }
389 
390 static PetscErrorCode RegisterFinalizer(PetscFinalizerContainer container)
391 {
392   PetscFunctionBegin;
393   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__);
394   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);
395   if (PetscDefined(USE_DEBUG)) {
396     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]);
397   }
398   regfin[reg_count++] = container;
399   PetscFunctionReturn(PETSC_SUCCESS);
400 }
401 
402 /*@C
403   PetscObjectRegisterDestroy - Registers a PETSc object to be destroyed when
404   `PetscFinalize()` is called.
405 
406   Logically Collective
407 
408   Input Parameter:
409 . obj - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
410         `PetscObjectRegisterDestroy`((`PetscObject`)mat);
411 
412   Level: developer
413 
414   Note:
415   This is used by, for example, `PETSC_VIEWER_XXX_()` routines to free the viewer
416   when PETSc ends.
417 
418 .seealso: `PetscObjectRegisterDestroyAll()`
419 @*/
420 PetscErrorCode PetscObjectRegisterDestroy(PetscObject obj)
421 {
422   PetscFinalizerContainer container;
423 
424   PetscFunctionBegin;
425   PetscValidHeader(obj, 1);
426   container.thunk.obj = obj;
427   container.type      = PETSC_FINALIZE_OBJECT;
428   PetscCall(RegisterFinalizer(container));
429   PetscFunctionReturn(PETSC_SUCCESS);
430 }
431 
432 /*@C
433   PetscObjectRegisterDestroyAll - Frees all the PETSc objects that have been registered
434   with `PetscObjectRegisterDestroy()`. Called by `PetscFinalize()`
435 
436   Logically Collective on the individual `PetscObject`s that are being processed
437 
438   Level: developer
439 
440 .seealso: `PetscObjectRegisterDestroy()`
441 @*/
442 PetscErrorCode PetscObjectRegisterDestroyAll(void)
443 {
444   PetscFunctionBegin;
445   PetscCall(PetscRunRegisteredFinalizers());
446   PetscFunctionReturn(PETSC_SUCCESS);
447 }
448 
449 /*@C
450   PetscRegisterFinalize - Registers a function that is to be called in `PetscFinalize()`
451 
452   Not Collective
453 
454   Input Parameter:
455 . f - function to be called
456 
457   Level: developer
458 
459   Notes:
460   This is used by, for example, `DMInitializePackage()` to have `DMFinalizePackage()` called
461 
462   Use `PetscObjectRegisterDestroy()` to register the destruction of an object in `PetscFinalize()`
463 
464 .seealso: `PetscRegisterFinalizeAll()`, `PetscObjectRegisterDestroy()`
465 @*/
466 PetscErrorCode PetscRegisterFinalize(PetscErrorCode (*f)(void))
467 {
468   PetscFinalizerContainer container;
469 
470   PetscFunctionBegin;
471   PetscValidFunction(f, 1);
472   container.thunk.fn.func = f;
473   container.type          = PETSC_FINALIZE_FUNC;
474   PetscCall(RegisterFinalizer(container));
475   PetscFunctionReturn(PETSC_SUCCESS);
476 }
477 
478 /*@C
479   PetscRegisterFinalizeAll - Runs all the finalize functions set with `PetscRegisterFinalize()`
480 
481   Not Collective unless registered functions are collective
482 
483   Level: developer
484 
485 .seealso: `PetscRegisterFinalize()`, `PetscObjectRegisterDestroyAll()`
486 @*/
487 PetscErrorCode PetscRegisterFinalizeAll(void)
488 {
489   PetscFunctionBegin;
490   PetscCall(PetscRunRegisteredFinalizers());
491   PetscFunctionReturn(PETSC_SUCCESS);
492 }
493