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