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