xref: /petsc/src/sys/objects/inherit.c (revision 0970d93f389b89d61186faed376e9cc5531f567f)
1 /*
2      Provides utility routines for manipulating any type of PETSc object.
3 */
4 #include <petsc/private/petscimpl.h> /*I   "petscsys.h"    I*/
5 #include <petscviewer.h>
6 
7 #if defined(PETSC_USE_LOG)
8 PETSC_INTERN PetscObject *PetscObjects;
9 PETSC_INTERN PetscInt     PetscObjectsCounts;
10 PETSC_INTERN PetscInt     PetscObjectsMaxCounts;
11 PETSC_INTERN PetscBool    PetscObjectsLog;
12 #endif
13 
14 #if defined(PETSC_USE_LOG)
15 PetscObject *PetscObjects       = NULL;
16 PetscInt     PetscObjectsCounts = 0, PetscObjectsMaxCounts = 0;
17 PetscBool    PetscObjectsLog = PETSC_FALSE;
18 #endif
19 
20 PetscObjectId PetscObjectNewId_Internal(void)
21 {
22   static PetscObjectId idcnt = 1;
23   return idcnt++;
24 }
25 
26 /*
27    PetscHeaderCreate_Private - Creates a base PETSc object header and fills
28    in the default values.  Called by the macro PetscHeaderCreate().
29 */
30 PetscErrorCode PetscHeaderCreate_Private(PetscObject h, PetscClassId classid, const char class_name[], const char descr[], const char mansec[], MPI_Comm comm, PetscObjectDestroyFunction destroy, PetscObjectViewFunction view)
31 {
32   void       *get_tmp;
33   PetscInt64 *cidx;
34   PetscMPIInt flg;
35 
36   PetscFunctionBegin;
37   h->classid               = classid;
38   h->class_name            = (char *)class_name;
39   h->description           = (char *)descr;
40   h->mansec                = (char *)mansec;
41   h->refct                 = 1;
42   h->non_cyclic_references = NULL;
43   h->id                    = PetscObjectNewId_Internal();
44   h->bops->destroy         = destroy;
45   h->bops->view            = view;
46 
47   PetscCall(PetscCommDuplicate(comm, &h->comm, &h->tag));
48 
49   /* Increment and store current object creation index */
50   PetscCallMPI(MPI_Comm_get_attr(h->comm, Petsc_CreationIdx_keyval, &get_tmp, &flg));
51   PetscCheck(flg, h->comm, PETSC_ERR_ARG_CORRUPT, "MPI_Comm does not have an object creation index");
52   cidx    = (PetscInt64 *)get_tmp;
53   h->cidx = (*cidx)++;
54   PetscCallMPI(MPI_Comm_set_attr(h->comm, Petsc_CreationIdx_keyval, cidx));
55 
56 #if defined(PETSC_USE_LOG)
57   /* Keep a record of object created */
58   if (PetscObjectsLog) {
59     PetscObject *newPetscObjects;
60     PetscInt     newPetscObjectsMaxCounts;
61 
62     PetscObjectsCounts++;
63     for (PetscInt i = 0; i < PetscObjectsMaxCounts; ++i) {
64       if (!PetscObjects[i]) {
65         PetscObjects[i] = h;
66         PetscFunctionReturn(PETSC_SUCCESS);
67       }
68     }
69     /* Need to increase the space for storing PETSc objects */
70     if (!PetscObjectsMaxCounts) newPetscObjectsMaxCounts = 100;
71     else newPetscObjectsMaxCounts = 2 * PetscObjectsMaxCounts;
72     PetscCall(PetscCalloc1(newPetscObjectsMaxCounts, &newPetscObjects));
73     PetscCall(PetscArraycpy(newPetscObjects, PetscObjects, PetscObjectsMaxCounts));
74     PetscCall(PetscFree(PetscObjects));
75 
76     PetscObjects                        = newPetscObjects;
77     PetscObjects[PetscObjectsMaxCounts] = h;
78     PetscObjectsMaxCounts               = newPetscObjectsMaxCounts;
79   }
80 #endif
81   PetscFunctionReturn(PETSC_SUCCESS);
82 }
83 
84 PETSC_INTERN PetscBool      PetscMemoryCollectMaximumUsage;
85 PETSC_INTERN PetscLogDouble PetscMemoryMaximumUsage;
86 
87 /*
88     PetscHeaderDestroy_Private - Destroys a base PETSc object header. Called by
89     the macro PetscHeaderDestroy().
90 */
91 PetscErrorCode PetscHeaderDestroy_Private(PetscObject obj, PetscBool clear_for_reuse)
92 {
93   PetscFunctionBegin;
94   PetscValidHeader(obj, 1);
95   PetscCall(PetscComposedQuantitiesDestroy(obj));
96   if (PetscMemoryCollectMaximumUsage) {
97     PetscLogDouble usage;
98 
99     PetscCall(PetscMemoryGetCurrentUsage(&usage));
100     if (usage > PetscMemoryMaximumUsage) PetscMemoryMaximumUsage = usage;
101   }
102   /* first destroy things that could execute arbitrary code */
103   if (obj->python_destroy) {
104     void *python_context                     = obj->python_context;
105     PetscErrorCode (*python_destroy)(void *) = obj->python_destroy;
106 
107     obj->python_context = NULL;
108     obj->python_destroy = NULL;
109     PetscCall((*python_destroy)(python_context));
110   }
111   PetscCall(PetscObjectDestroyOptionsHandlers(obj));
112   PetscCall(PetscObjectListDestroy(&obj->olist));
113 
114   /* destroy allocated quantities */
115   if (PetscPrintFunctionList) PetscCall(PetscFunctionListPrintNonEmpty(obj->qlist));
116   PetscCheck(--(obj->refct) <= 0, obj->comm, PETSC_ERR_PLIB, "Destroying a PetscObject (%s) with reference count %" PetscInt_FMT " >= 1", obj->name ? obj->name : "unnamed", obj->refct);
117   PetscCall(PetscFree(obj->name));
118   PetscCall(PetscFree(obj->prefix));
119   PetscCall(PetscFree(obj->type_name));
120 
121   if (clear_for_reuse) {
122     /* we will assume that obj->bops->view and destroy are safe to leave as-is */
123 
124     /* reset quantities, in order of appearance in _p_PetscObject */
125     obj->id       = PetscObjectNewId_Internal();
126     obj->refct    = 1;
127     obj->tablevel = 0;
128     obj->state    = 0;
129     /* don't deallocate, zero these out instead */
130     PetscCall(PetscFunctionListClear(obj->qlist));
131     PetscCall(PetscArrayzero(obj->fortran_func_pointers, obj->num_fortran_func_pointers));
132     PetscCall(PetscArrayzero(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_CLASS], obj->num_fortrancallback[PETSC_FORTRAN_CALLBACK_CLASS]));
133     PetscCall(PetscArrayzero(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_SUBTYPE], obj->num_fortrancallback[PETSC_FORTRAN_CALLBACK_SUBTYPE]));
134     obj->optionsprinted = PETSC_FALSE;
135 #if PetscDefined(HAVE_SAWS)
136     obj->amsmem          = PETSC_FALSE;
137     obj->amspublishblock = PETSC_FALSE;
138 #endif
139     obj->options                                  = NULL;
140     obj->donotPetscObjectPrintClassNamePrefixType = PETSC_FALSE;
141   } else {
142     PetscCall(PetscFunctionListDestroy(&obj->qlist));
143     PetscCall(PetscFree(obj->fortran_func_pointers));
144     PetscCall(PetscFree(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_CLASS]));
145     PetscCall(PetscFree(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_SUBTYPE]));
146     PetscCall(PetscCommDestroy(&obj->comm));
147     obj->classid = PETSCFREEDHEADER;
148 
149 #if PetscDefined(USE_LOG)
150     if (PetscObjectsLog) {
151       /* Record object removal from list of all objects */
152       for (PetscInt i = 0; i < PetscObjectsMaxCounts; ++i) {
153         if (PetscObjects[i] == obj) {
154           PetscObjects[i] = NULL;
155           --PetscObjectsCounts;
156           break;
157         }
158       }
159       if (!PetscObjectsCounts) {
160         PetscCall(PetscFree(PetscObjects));
161         PetscObjectsMaxCounts = 0;
162       }
163     }
164 #endif
165   }
166   PetscFunctionReturn(PETSC_SUCCESS);
167 }
168 
169 /*
170   PetscHeaderReset_Internal - "Reset" a PetscObject header. This is tantamount to destroying
171   the object but does not free all resources. The object retains its:
172 
173   - classid
174   - bops->view
175   - bops->destroy
176   - comm
177   - tag
178   - class_name
179   - description
180   - mansec
181   - cpp
182 
183   Note that while subclass information is lost, superclass info remains. Thus this function is
184   intended to be used to reuse a PetscObject within the same class to avoid reallocating its
185   resources.
186 */
187 PetscErrorCode PetscHeaderReset_Internal(PetscObject obj)
188 {
189   PetscFunctionBegin;
190   PetscCall(PetscHeaderDestroy_Private(obj, PETSC_TRUE));
191   PetscFunctionReturn(PETSC_SUCCESS);
192 }
193 
194 /*@C
195   PetscObjectCopyFortranFunctionPointers - Copy function pointers to another object
196 
197   Logically Collective
198 
199   Input Parameters:
200 + src  - source object
201 - dest - destination object
202 
203   Level: developer
204 
205   Note:
206   Both objects must have the same class.
207 
208   This is used to help manage user callback functions that were provided in Fortran
209 
210 .seealso: `PetscFortranCallbackRegister()`, `PetscFortranCallbackGetSizes()`
211 @*/
212 PetscErrorCode PetscObjectCopyFortranFunctionPointers(PetscObject src, PetscObject dest)
213 {
214   PetscFortranCallbackId cbtype, numcb[PETSC_FORTRAN_CALLBACK_MAXTYPE];
215 
216   PetscFunctionBegin;
217   PetscValidHeader(src, 1);
218   PetscValidHeader(dest, 2);
219   PetscCheck(src->classid == dest->classid, src->comm, PETSC_ERR_ARG_INCOMP, "Objects must be of the same class");
220 
221   PetscCall(PetscFree(dest->fortran_func_pointers));
222   PetscCall(PetscMalloc(src->num_fortran_func_pointers * sizeof(void (*)(void)), &dest->fortran_func_pointers));
223   PetscCall(PetscMemcpy(dest->fortran_func_pointers, src->fortran_func_pointers, src->num_fortran_func_pointers * sizeof(void (*)(void))));
224 
225   dest->num_fortran_func_pointers = src->num_fortran_func_pointers;
226 
227   PetscCall(PetscFortranCallbackGetSizes(src->classid, &numcb[PETSC_FORTRAN_CALLBACK_CLASS], &numcb[PETSC_FORTRAN_CALLBACK_SUBTYPE]));
228   for (cbtype = PETSC_FORTRAN_CALLBACK_CLASS; cbtype < PETSC_FORTRAN_CALLBACK_MAXTYPE; cbtype++) {
229     PetscCall(PetscFree(dest->fortrancallback[cbtype]));
230     PetscCall(PetscCalloc1(numcb[cbtype], &dest->fortrancallback[cbtype]));
231     PetscCall(PetscMemcpy(dest->fortrancallback[cbtype], src->fortrancallback[cbtype], src->num_fortrancallback[cbtype] * sizeof(PetscFortranCallback)));
232     dest->num_fortrancallback[cbtype] = src->num_fortrancallback[cbtype];
233   }
234   PetscFunctionReturn(PETSC_SUCCESS);
235 }
236 
237 /*@C
238   PetscObjectSetFortranCallback - set fortran callback function pointer and context
239 
240   Logically Collective
241 
242   Input Parameters:
243 + obj    - object on which to set callback
244 . cbtype - callback type (class or subtype)
245 . cid    - address of callback Id, updated if not yet initialized (zero)
246 . func   - Fortran function
247 - ctx    - Fortran context
248 
249   Level: developer
250 
251   Note:
252   This is used to help manage user callback functions that were provided in Fortran
253 
254 .seealso: `PetscObjectGetFortranCallback()`, `PetscFortranCallbackRegister()`, `PetscFortranCallbackGetSizes()`
255 @*/
256 PetscErrorCode PetscObjectSetFortranCallback(PetscObject obj, PetscFortranCallbackType cbtype, PetscFortranCallbackId *cid, void (*func)(void), void *ctx)
257 {
258   const char *subtype = NULL;
259 
260   PetscFunctionBegin;
261   PetscValidHeader(obj, 1);
262   if (cbtype == PETSC_FORTRAN_CALLBACK_SUBTYPE) subtype = obj->type_name;
263   if (!*cid) PetscCall(PetscFortranCallbackRegister(obj->classid, subtype, cid));
264   if (*cid >= PETSC_SMALLEST_FORTRAN_CALLBACK + obj->num_fortrancallback[cbtype]) {
265     PetscFortranCallbackId oldnum = obj->num_fortrancallback[cbtype];
266     PetscFortranCallbackId newnum = PetscMax(*cid - PETSC_SMALLEST_FORTRAN_CALLBACK + 1, 2 * oldnum);
267     PetscFortranCallback  *callback;
268     PetscCall(PetscMalloc1(newnum, &callback));
269     PetscCall(PetscMemcpy(callback, obj->fortrancallback[cbtype], oldnum * sizeof(*obj->fortrancallback[cbtype])));
270     PetscCall(PetscFree(obj->fortrancallback[cbtype]));
271 
272     obj->fortrancallback[cbtype]     = callback;
273     obj->num_fortrancallback[cbtype] = newnum;
274   }
275   obj->fortrancallback[cbtype][*cid - PETSC_SMALLEST_FORTRAN_CALLBACK].func = func;
276   obj->fortrancallback[cbtype][*cid - PETSC_SMALLEST_FORTRAN_CALLBACK].ctx  = ctx;
277   PetscFunctionReturn(PETSC_SUCCESS);
278 }
279 
280 /*@C
281   PetscObjectGetFortranCallback - get fortran callback function pointer and context
282 
283   Logically Collective
284 
285   Input Parameters:
286 + obj    - object on which to get callback
287 . cbtype - callback type
288 - cid    - address of callback Id
289 
290   Output Parameters:
291 + func - Fortran function (or `NULL` if not needed)
292 - ctx  - Fortran context (or `NULL` if not needed)
293 
294   Level: developer
295 
296   Note:
297   This is used to help manage user callback functions that were provided in Fortran
298 
299 .seealso: `PetscObjectSetFortranCallback()`, `PetscFortranCallbackRegister()`, `PetscFortranCallbackGetSizes()`
300 @*/
301 PetscErrorCode PetscObjectGetFortranCallback(PetscObject obj, PetscFortranCallbackType cbtype, PetscFortranCallbackId cid, void (**func)(void), void **ctx)
302 {
303   PetscFortranCallback *cb;
304 
305   PetscFunctionBegin;
306   PetscValidHeader(obj, 1);
307   PetscCheck(cid >= PETSC_SMALLEST_FORTRAN_CALLBACK, obj->comm, PETSC_ERR_ARG_CORRUPT, "Fortran callback Id invalid");
308   PetscCheck(cid < PETSC_SMALLEST_FORTRAN_CALLBACK + obj->num_fortrancallback[cbtype], obj->comm, PETSC_ERR_ARG_CORRUPT, "Fortran callback not set on this object");
309   cb = &obj->fortrancallback[cbtype][cid - PETSC_SMALLEST_FORTRAN_CALLBACK];
310   if (func) *func = cb->func;
311   if (ctx) *ctx = cb->ctx;
312   PetscFunctionReturn(PETSC_SUCCESS);
313 }
314 
315 #if defined(PETSC_USE_LOG)
316 /*@C
317   PetscObjectsDump - Prints all the currently existing objects.
318 
319   On rank 0 of `PETSC_COMM_WORLD` prints the values
320 
321   Input Parameters:
322 + fd  - file pointer
323 - all - by default only tries to display objects created explicitly by the user, if all is `PETSC_TRUE` then lists all outstanding objects
324 
325   Options Database Key:
326 . -objects_dump <all> - print information about all the objects that exist at the end of the programs run
327 
328   Level: advanced
329 
330 .seealso: `PetscObject`
331 @*/
332 PetscErrorCode PetscObjectsDump(FILE *fd, PetscBool all)
333 {
334   PetscInt    i, j, k = 0;
335   PetscObject h;
336 
337   PetscFunctionBegin;
338   if (PetscObjectsCounts) {
339     PetscCall(PetscFPrintf(PETSC_COMM_WORLD, fd, "The following objects were never freed\n"));
340     PetscCall(PetscFPrintf(PETSC_COMM_WORLD, fd, "-----------------------------------------\n"));
341     for (i = 0; i < PetscObjectsMaxCounts; i++) {
342       if ((h = PetscObjects[i])) {
343         PetscCall(PetscObjectName(h));
344         {
345           PetscStack *stack  = NULL;
346           char       *create = NULL, *rclass = NULL;
347 
348           /* if the PETSc function the user calls is not a create then this object was NOT directly created by them */
349           PetscCall(PetscMallocGetStack(h, &stack));
350           if (stack) {
351             k = stack->currentsize - 2;
352             if (!all) {
353               k = 0;
354               while (!stack->petscroutine[k]) k++;
355               PetscCall(PetscStrstr(stack->function[k], "Create", &create));
356               if (!create) PetscCall(PetscStrstr(stack->function[k], "Get", &create));
357               PetscCall(PetscStrstr(stack->function[k], h->class_name, &rclass));
358               if (!create) continue;
359               if (!rclass) continue;
360             }
361           }
362 
363           PetscCall(PetscFPrintf(PETSC_COMM_WORLD, fd, "[%d] %s %s %s\n", PetscGlobalRank, h->class_name, h->type_name, h->name));
364 
365           PetscCall(PetscMallocGetStack(h, &stack));
366           if (stack) {
367             for (j = k; j >= 0; j--) fprintf(fd, "      [%d]  %s() in %s\n", PetscGlobalRank, stack->function[j], stack->file[j]);
368           }
369         }
370       }
371     }
372   }
373   PetscFunctionReturn(PETSC_SUCCESS);
374 }
375 
376 /*@C
377   PetscObjectsView - Prints the currently existing objects.
378 
379   Logically Collective
380 
381   Input Parameter:
382 . viewer - must be an `PETSCVIEWERASCII` viewer
383 
384   Level: advanced
385 
386 .seealso: `PetscObject`
387 @*/
388 PetscErrorCode PetscObjectsView(PetscViewer viewer)
389 {
390   PetscBool isascii;
391   FILE     *fd;
392 
393   PetscFunctionBegin;
394   if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD;
395   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
396   PetscCheck(isascii, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Only supports ASCII viewer");
397   PetscCall(PetscViewerASCIIGetPointer(viewer, &fd));
398   PetscCall(PetscObjectsDump(fd, PETSC_TRUE));
399   PetscFunctionReturn(PETSC_SUCCESS);
400 }
401 
402 /*@C
403   PetscObjectsGetObject - Get a pointer to a named object
404 
405   Not Collective
406 
407   Input Parameter:
408 . name - the name of an object
409 
410   Output Parameters:
411 + obj       - the object or `NULL` if there is no object
412 - classname - the name of the class
413 
414   Level: advanced
415 
416 .seealso: `PetscObject`
417 @*/
418 PetscErrorCode PetscObjectsGetObject(const char *name, PetscObject *obj, char **classname)
419 {
420   PetscInt    i;
421   PetscObject h;
422   PetscBool   flg;
423 
424   PetscFunctionBegin;
425   PetscAssertPointer(name, 1);
426   PetscAssertPointer(obj, 2);
427   *obj = NULL;
428   for (i = 0; i < PetscObjectsMaxCounts; i++) {
429     if ((h = PetscObjects[i])) {
430       PetscCall(PetscObjectName(h));
431       PetscCall(PetscStrcmp(h->name, name, &flg));
432       if (flg) {
433         *obj = h;
434         if (classname) *classname = h->class_name;
435         PetscFunctionReturn(PETSC_SUCCESS);
436       }
437     }
438   }
439   PetscFunctionReturn(PETSC_SUCCESS);
440 }
441 #endif
442 
443 /*@
444   PetscObjectSetPrintedOptions - indicate to an object that it should behave as if it has already printed the help for its options so it will not display the help message
445 
446   Input Parameter:
447 . obj - the `PetscObject`
448 
449   Level: developer
450 
451   Developer Notes:
452   This is used, for example to prevent sequential objects that are created from a parallel object; such as the `KSP` created by
453   `PCBJACOBI` from all printing the same help messages to the screen
454 
455 .seealso: `PetscOptionsInsert()`, `PetscObject`
456 @*/
457 PetscErrorCode PetscObjectSetPrintedOptions(PetscObject obj)
458 {
459   PetscFunctionBegin;
460   PetscAssertPointer(obj, 1);
461   obj->optionsprinted = PETSC_TRUE;
462   PetscFunctionReturn(PETSC_SUCCESS);
463 }
464 
465 /*@
466   PetscObjectInheritPrintedOptions - If the child object is not on the rank 0 process of the parent object and the child is sequential then the child gets it set.
467 
468   Input Parameters:
469 + pobj - the parent object
470 - obj  - the `PetscObject`
471 
472   Level: developer
473 
474   Developer Notes:
475   This is used, for example to prevent sequential objects that are created from a parallel object; such as the `KSP` created by
476   `PCBJACOBI` from all printing the same help messages to the screen
477 
478   This will not handle more complicated situations like with `PCGASM` where children may live on any subset of the parent's processes and overlap
479 
480 .seealso: `PetscOptionsInsert()`, `PetscObjectSetPrintedOptions()`, `PetscObject`
481 @*/
482 PetscErrorCode PetscObjectInheritPrintedOptions(PetscObject pobj, PetscObject obj)
483 {
484   PetscMPIInt prank, size;
485 
486   PetscFunctionBegin;
487   PetscValidHeader(pobj, 1);
488   PetscValidHeader(obj, 2);
489   PetscCallMPI(MPI_Comm_rank(pobj->comm, &prank));
490   PetscCallMPI(MPI_Comm_size(obj->comm, &size));
491   if (size == 1 && prank > 0) obj->optionsprinted = PETSC_TRUE;
492   PetscFunctionReturn(PETSC_SUCCESS);
493 }
494 
495 /*@C
496   PetscObjectAddOptionsHandler - Adds an additional function to check for options when `XXXSetFromOptions()` is called.
497 
498   Not Collective
499 
500   Input Parameters:
501 + obj     - the PETSc object
502 . handle  - function that checks for options
503 . destroy - function to destroy context if provided
504 - ctx     - optional context for check function
505 
506   Level: developer
507 
508 .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectProcessOptionsHandlers()`, `PetscObjectDestroyOptionsHandlers()`,
509           `PetscObject`
510 @*/
511 PetscErrorCode PetscObjectAddOptionsHandler(PetscObject obj, PetscErrorCode (*handle)(PetscObject, PetscOptionItems *, void *), PetscErrorCode (*destroy)(PetscObject, void *), void *ctx)
512 {
513   PetscFunctionBegin;
514   PetscValidHeader(obj, 1);
515   PetscCheck(obj->noptionhandler < PETSC_MAX_OPTIONS_HANDLER, obj->comm, PETSC_ERR_ARG_OUTOFRANGE, "To many options handlers added");
516   obj->optionhandler[obj->noptionhandler] = handle;
517   obj->optiondestroy[obj->noptionhandler] = destroy;
518   obj->optionctx[obj->noptionhandler++]   = ctx;
519   PetscFunctionReturn(PETSC_SUCCESS);
520 }
521 
522 /*@C
523   PetscObjectProcessOptionsHandlers - Calls all the options handlers attached to an object
524 
525   Not Collective
526 
527   Input Parameters:
528 + obj                - the PETSc object
529 - PetscOptionsObject - the options context
530 
531   Level: developer
532 
533 .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectAddOptionsHandler()`, `PetscObjectDestroyOptionsHandlers()`,
534           `PetscObject`
535 @*/
536 PetscErrorCode PetscObjectProcessOptionsHandlers(PetscObject obj, PetscOptionItems *PetscOptionsObject)
537 {
538   PetscFunctionBegin;
539   PetscValidHeader(obj, 1);
540   for (PetscInt i = 0; i < obj->noptionhandler; i++) PetscCall((*obj->optionhandler[i])(obj, PetscOptionsObject, obj->optionctx[i]));
541   PetscFunctionReturn(PETSC_SUCCESS);
542 }
543 
544 /*@C
545   PetscObjectDestroyOptionsHandlers - Destroys all the option handlers attached to an object
546 
547   Not Collective
548 
549   Input Parameter:
550 . obj - the PETSc object
551 
552   Level: developer
553 
554 .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectAddOptionsHandler()`, `PetscObjectProcessOptionsHandlers()`,
555           `PetscObject`
556 @*/
557 PetscErrorCode PetscObjectDestroyOptionsHandlers(PetscObject obj)
558 {
559   PetscFunctionBegin;
560   PetscValidHeader(obj, 1);
561   for (PetscInt i = 0; i < obj->noptionhandler; i++) {
562     if (obj->optiondestroy[i]) PetscCall((*obj->optiondestroy[i])(obj, obj->optionctx[i]));
563   }
564   obj->noptionhandler = 0;
565   PetscFunctionReturn(PETSC_SUCCESS);
566 }
567 
568 /*@C
569   PetscObjectReference - Indicates to any `PetscObject` that it is being
570   referenced by another `PetscObject`. This increases the reference
571   count for that object by one.
572 
573   Logically Collective
574 
575   Input Parameter:
576 . obj - the PETSc object. This must be cast with (`PetscObject`), for example,
577          `PetscObjectReference`((`PetscObject`)mat);
578 
579   Level: advanced
580 
581 .seealso: `PetscObjectCompose()`, `PetscObjectDereference()`, `PetscObject`
582 @*/
583 PetscErrorCode PetscObjectReference(PetscObject obj)
584 {
585   PetscFunctionBegin;
586   if (!obj) PetscFunctionReturn(PETSC_SUCCESS);
587   PetscValidHeader(obj, 1);
588   obj->refct++;
589   PetscFunctionReturn(PETSC_SUCCESS);
590 }
591 
592 /*@C
593   PetscObjectGetReference - Gets the current reference count for
594   any PETSc object.
595 
596   Not Collective
597 
598   Input Parameter:
599 . obj - the PETSc object; this must be cast with (`PetscObject`), for example,
600          `PetscObjectGetReference`((`PetscObject`)mat,&cnt);
601 
602   Output Parameter:
603 . cnt - the reference count
604 
605   Level: advanced
606 
607 .seealso: `PetscObjectCompose()`, `PetscObjectDereference()`, `PetscObjectReference()`, `PetscObject`
608 @*/
609 PetscErrorCode PetscObjectGetReference(PetscObject obj, PetscInt *cnt)
610 {
611   PetscFunctionBegin;
612   PetscValidHeader(obj, 1);
613   PetscAssertPointer(cnt, 2);
614   *cnt = obj->refct;
615   PetscFunctionReturn(PETSC_SUCCESS);
616 }
617 
618 /*@C
619   PetscObjectDereference - Indicates to any `PetscObject` that it is being
620   referenced by one less `PetscObject`. This decreases the reference
621   count for that object by one.
622 
623   Collective on obj if reference reaches 0 otherwise Logically Collective
624 
625   Input Parameter:
626 . obj - the PETSc object; this must be cast with (`PetscObject`), for example,
627          `PetscObjectDereference`((`PetscObject`)mat);
628 
629   Level: advanced
630 
631   Note:
632   `PetscObjectDestroy()` sets the obj pointer to null after the call, this routine does not.
633 
634 .seealso: `PetscObjectCompose()`, `PetscObjectReference()`, `PetscObjectDestroy()`, `PetscObject`
635 @*/
636 PetscErrorCode PetscObjectDereference(PetscObject obj)
637 {
638   PetscFunctionBegin;
639   if (!obj) PetscFunctionReturn(PETSC_SUCCESS);
640   PetscValidHeader(obj, 1);
641   if (obj->bops->destroy) PetscCall((*obj->bops->destroy)(&obj));
642   else PetscCheck(--(obj->refct), PETSC_COMM_SELF, PETSC_ERR_SUP, "This PETSc object does not have a generic destroy routine");
643   PetscFunctionReturn(PETSC_SUCCESS);
644 }
645 
646 /*
647      The following routines are the versions private to the PETSc object
648      data structures.
649 */
650 PetscErrorCode PetscObjectRemoveReference(PetscObject obj, const char name[])
651 {
652   PetscFunctionBegin;
653   PetscValidHeader(obj, 1);
654   PetscCall(PetscObjectListRemoveReference(&obj->olist, name));
655   PetscFunctionReturn(PETSC_SUCCESS);
656 }
657 
658 /*@C
659   PetscObjectCompose - Associates another PETSc object with a given PETSc object.
660 
661   Not Collective
662 
663   Input Parameters:
664 + obj  - the PETSc object; this must be cast with (`PetscObject`), for example,
665          `PetscObjectCompose`((`PetscObject`)mat,...);
666 . name - name associated with the child object
667 - ptr  - the other PETSc object to associate with the PETSc object; this must also be
668          cast with (`PetscObject`)
669 
670   Level: advanced
671 
672   Notes:
673   The second objects reference count is automatically increased by one when it is
674   composed.
675 
676   Replaces any previous object that had the same name.
677 
678   If ptr is null and name has previously been composed using an object, then that
679   entry is removed from the obj.
680 
681   `PetscObjectCompose()` can be used with any PETSc object (such as
682   `Mat`, `Vec`, `KSP`, `SNES`, etc.) or any user-provided object.
683 
684   `PetscContainerCreate()` can be used to create an object from a
685   user-provided pointer that may then be composed with PETSc objects using `PetscObjectCompose()`
686 
687 .seealso: `PetscObjectQuery()`, `PetscContainerCreate()`, `PetscObjectComposeFunction()`, `PetscObjectQueryFunction()`, `PetscContainer`,
688           `PetscContainerSetPointer()`, `PetscObject`
689 @*/
690 PetscErrorCode PetscObjectCompose(PetscObject obj, const char name[], PetscObject ptr)
691 {
692   PetscFunctionBegin;
693   PetscValidHeader(obj, 1);
694   PetscAssertPointer(name, 2);
695   if (ptr) PetscValidHeader(ptr, 3);
696   PetscCheck(obj != ptr, PetscObjectComm((PetscObject)obj), PETSC_ERR_SUP, "Cannot compose object with itself");
697   if (ptr) {
698     char     *tname;
699     PetscBool skipreference;
700 
701     PetscCall(PetscObjectListReverseFind(ptr->olist, obj, &tname, &skipreference));
702     if (tname) PetscCheck(skipreference, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "An object cannot be composed with an object that was composed with it");
703   }
704   PetscCall(PetscObjectListAdd(&obj->olist, name, ptr));
705   PetscFunctionReturn(PETSC_SUCCESS);
706 }
707 
708 /*@C
709   PetscObjectQuery  - Gets a PETSc object associated with a given object that was composed with `PetscObjectCompose()`
710 
711   Not Collective
712 
713   Input Parameters:
714 + obj  - the PETSc object
715          Thus must be cast with a (`PetscObject`), for example,
716          `PetscObjectCompose`((`PetscObject`)mat,...);
717 . name - name associated with child object
718 - ptr  - the other PETSc object associated with the PETSc object, this must be
719          cast with (`PetscObject`*)
720 
721   Level: advanced
722 
723   Note:
724   The reference count of neither object is increased in this call
725 
726 .seealso: `PetscObjectCompose()`, `PetscObjectComposeFunction()`, `PetscObjectQueryFunction()`, `PetscContainer`
727           `PetscContainerGetPointer()`, `PetscObject`
728 @*/
729 PetscErrorCode PetscObjectQuery(PetscObject obj, const char name[], PetscObject *ptr)
730 {
731   PetscFunctionBegin;
732   PetscValidHeader(obj, 1);
733   PetscAssertPointer(name, 2);
734   PetscAssertPointer(ptr, 3);
735   PetscCall(PetscObjectListFind(obj->olist, name, ptr));
736   PetscFunctionReturn(PETSC_SUCCESS);
737 }
738 
739 /*MC
740   PetscObjectComposeFunction - Associates a function with a given PETSc object.
741 
742   Synopsis:
743   #include <petscsys.h>
744   PetscErrorCode PetscObjectComposeFunction(PetscObject obj, const char name[], void (*fptr)(void))
745 
746   Logically Collective
747 
748   Input Parameters:
749 + obj  - the PETSc object; this must be cast with a (`PetscObject`), for example,
750          `PetscObjectCompose`((`PetscObject`)mat,...);
751 . name - name associated with the child function
752 - fptr - function pointer
753 
754   Level: advanced
755 
756   Notes:
757   When the first argument of `fptr` is (or is derived from) a `PetscObject` then `PetscTryMethod()` and `PetscUseMethod()`
758   can be used to call the function directly with error checking.
759 
760   To remove a registered routine, pass in `NULL` for `fptr`.
761 
762   `PetscObjectComposeFunction()` can be used with any PETSc object (such as
763   `Mat`, `Vec`, `KSP`, `SNES`, etc.) or any user-provided object.
764 
765   `PetscUseTypeMethod()` and `PetscTryTypeMethod()` are used to call a function that is stored in the objects `obj->ops` table.
766 
767 .seealso: `PetscObjectQueryFunction()`, `PetscContainerCreate()` `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscTryMethod()`, `PetscUseMethod()`,
768           `PetscUseTypeMethod()`, `PetscTryTypeMethod()`, `PetscObject`
769 M*/
770 PetscErrorCode PetscObjectComposeFunction_Private(PetscObject obj, const char name[], void (*fptr)(void))
771 {
772   PetscFunctionBegin;
773   PetscValidHeader(obj, 1);
774   PetscAssertPointer(name, 2);
775   PetscCall(PetscFunctionListAdd(&obj->qlist, name, fptr));
776   PetscFunctionReturn(PETSC_SUCCESS);
777 }
778 
779 /*MC
780   PetscObjectQueryFunction - Gets a function associated with a given object.
781 
782   Synopsis:
783   #include <petscsys.h>
784   PetscErrorCode PetscObjectQueryFunction(PetscObject obj, const char name[], void (**fptr)(void))
785 
786   Logically Collective
787 
788   Input Parameters:
789 + obj  - the PETSc object; this must be cast with (`PetscObject`), for example,
790          `PetscObjectQueryFunction`((`PetscObject`)ksp,...);
791 - name - name associated with the child function
792 
793   Output Parameter:
794 . fptr - function pointer
795 
796   Level: advanced
797 
798 .seealso: `PetscObjectComposeFunction()`, `PetscFunctionListFind()`, `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscObject`
799 M*/
800 PETSC_EXTERN PetscErrorCode PetscObjectQueryFunction_Private(PetscObject obj, const char name[], void (**fptr)(void))
801 {
802   PetscFunctionBegin;
803   PetscValidHeader(obj, 1);
804   PetscAssertPointer(name, 2);
805   PetscCall(PetscFunctionListFind(obj->qlist, name, fptr));
806   PetscFunctionReturn(PETSC_SUCCESS);
807 }
808 
809 struct _p_PetscContainer {
810   PETSCHEADER(int);
811   void *ptr;
812   PetscErrorCode (*userdestroy)(void *);
813 };
814 
815 /*@C
816   PetscContainerUserDestroyDefault - Default destroy routine for user-provided data that simply calls `PetscFree()` in the data
817   provided with `PetscContainerSetPointer()`
818 
819   Logically Collective on the `PetscContainer` containing the user data
820 
821   Input Parameter:
822 . ctx - pointer to user-provided data
823 
824   Level: advanced
825 
826 .seealso: `PetscContainerDestroy()`, `PetscContainerSetUserDestroy()`, `PetscObject`
827 @*/
828 PetscErrorCode PetscContainerUserDestroyDefault(void *ctx)
829 {
830   PetscFunctionBegin;
831   PetscCall(PetscFree(ctx));
832   PetscFunctionReturn(PETSC_SUCCESS);
833 }
834 
835 /*@C
836   PetscContainerGetPointer - Gets the pointer value contained in the container that was provided with `PetscContainerSetPointer()`
837 
838   Not Collective
839 
840   Input Parameter:
841 . obj - the object created with `PetscContainerCreate()`
842 
843   Output Parameter:
844 . ptr - the pointer value
845 
846   Level: advanced
847 
848 .seealso: `PetscContainerCreate()`, `PetscContainerDestroy()`, `PetscObject`,
849           `PetscContainerSetPointer()`
850 @*/
851 PetscErrorCode PetscContainerGetPointer(PetscContainer obj, void **ptr)
852 {
853   PetscFunctionBegin;
854   PetscValidHeaderSpecific(obj, PETSC_CONTAINER_CLASSID, 1);
855   PetscAssertPointer(ptr, 2);
856   *ptr = obj->ptr;
857   PetscFunctionReturn(PETSC_SUCCESS);
858 }
859 
860 /*@C
861   PetscContainerSetPointer - Sets the pointer value contained in the container.
862 
863   Logically Collective
864 
865   Input Parameters:
866 + obj - the object created with `PetscContainerCreate()`
867 - ptr - the pointer value
868 
869   Level: advanced
870 
871 .seealso: `PetscContainerCreate()`, `PetscContainerDestroy()`, `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscObject`,
872           `PetscContainerGetPointer()`
873 @*/
874 PetscErrorCode PetscContainerSetPointer(PetscContainer obj, void *ptr)
875 {
876   PetscFunctionBegin;
877   PetscValidHeaderSpecific(obj, PETSC_CONTAINER_CLASSID, 1);
878   if (ptr) PetscAssertPointer(ptr, 2);
879   obj->ptr = ptr;
880   PetscFunctionReturn(PETSC_SUCCESS);
881 }
882 
883 /*@C
884   PetscContainerDestroy - Destroys a PETSc container object.
885 
886   Collective
887 
888   Input Parameter:
889 . obj - an object that was created with `PetscContainerCreate()`
890 
891   Level: advanced
892 
893   Note:
894   If `PetscContainerSetUserDestroy()` was used to provide a user destroy object for the data provided with `PetscContainerSetPointer()`
895   then that function is called to destroy the data.
896 
897 .seealso: `PetscContainerCreate()`, `PetscContainerSetUserDestroy()`, `PetscObject`
898 @*/
899 PetscErrorCode PetscContainerDestroy(PetscContainer *obj)
900 {
901   PetscFunctionBegin;
902   if (!*obj) PetscFunctionReturn(PETSC_SUCCESS);
903   PetscValidHeaderSpecific(*obj, PETSC_CONTAINER_CLASSID, 1);
904   if (--((PetscObject)(*obj))->refct > 0) {
905     *obj = NULL;
906     PetscFunctionReturn(PETSC_SUCCESS);
907   }
908   if ((*obj)->userdestroy) PetscCall((*(*obj)->userdestroy)((*obj)->ptr));
909   PetscCall(PetscHeaderDestroy(obj));
910   PetscFunctionReturn(PETSC_SUCCESS);
911 }
912 
913 /*@C
914   PetscContainerSetUserDestroy - Sets name of the user destroy function for the data provided to the `PetscContainer` with `PetscContainerSetPointer()`
915 
916   Logically Collective
917 
918   Input Parameters:
919 + obj - an object that was created with `PetscContainerCreate()`
920 - des - name of the user destroy function
921 
922   Level: advanced
923 
924   Note:
925   Use `PetscContainerUserDestroyDefault()` if the memory was obtained by calling `PetscMalloc()` or one of its variants for single memory allocation.
926 
927 .seealso: `PetscContainerDestroy()`, `PetscContainerUserDestroyDefault()`, `PetscMalloc()`, `PetscMalloc1()`, `PetscCalloc()`, `PetscCalloc1()`, `PetscObject`
928 @*/
929 PetscErrorCode PetscContainerSetUserDestroy(PetscContainer obj, PetscErrorCode (*des)(void *))
930 {
931   PetscFunctionBegin;
932   PetscValidHeaderSpecific(obj, PETSC_CONTAINER_CLASSID, 1);
933   obj->userdestroy = des;
934   PetscFunctionReturn(PETSC_SUCCESS);
935 }
936 
937 PetscClassId PETSC_CONTAINER_CLASSID;
938 
939 /*@C
940   PetscContainerCreate - Creates a PETSc object that has room to hold a single pointer.
941 
942   Collective
943 
944   Input Parameter:
945 . comm - MPI communicator that shares the object
946 
947   Output Parameter:
948 . container - the container created
949 
950   Level: advanced
951 
952   Notes:
953   This allows one to attach any type of data (accessible through a pointer) with the
954   `PetscObjectCompose()` function to a `PetscObject`. The data item itself is attached by a
955   call to `PetscContainerSetPointer()`.
956 
957 .seealso: `PetscContainerDestroy()`, `PetscContainerSetPointer()`, `PetscContainerGetPointer()`, `PetscObjectCompose()`, `PetscObjectQuery()`,
958           `PetscContainerSetUserDestroy()`, `PetscObject`
959 @*/
960 PetscErrorCode PetscContainerCreate(MPI_Comm comm, PetscContainer *container)
961 {
962   PetscFunctionBegin;
963   PetscAssertPointer(container, 2);
964   PetscCall(PetscSysInitializePackage());
965   PetscCall(PetscHeaderCreate(*container, PETSC_CONTAINER_CLASSID, "PetscContainer", "Container", "Sys", comm, PetscContainerDestroy, NULL));
966   PetscFunctionReturn(PETSC_SUCCESS);
967 }
968 
969 /*@
970   PetscObjectSetFromOptions - Sets generic parameters from user options.
971 
972   Collective
973 
974   Input Parameter:
975 . obj - the `PetscObject`
976 
977   Level: beginner
978 
979   Note:
980   We have no generic options at present, so this does nothing
981 
982 .seealso: `PetscObjectSetOptionsPrefix()`, `PetscObjectGetOptionsPrefix()`, `PetscObject`
983 @*/
984 PetscErrorCode PetscObjectSetFromOptions(PetscObject obj)
985 {
986   PetscFunctionBegin;
987   PetscValidHeader(obj, 1);
988   PetscFunctionReturn(PETSC_SUCCESS);
989 }
990 
991 /*@
992   PetscObjectSetUp - Sets up the internal data structures for the later use.
993 
994   Collective
995 
996   Input Parameter:
997 . obj - the `PetscObject`
998 
999   Level: advanced
1000 
1001   Note:
1002   This does nothing at present.
1003 
1004 .seealso: `PetscObjectDestroy()`, `PetscObject`
1005 @*/
1006 PetscErrorCode PetscObjectSetUp(PetscObject obj)
1007 {
1008   PetscFunctionBegin;
1009   PetscValidHeader(obj, 1);
1010   PetscFunctionReturn(PETSC_SUCCESS);
1011 }
1012