xref: /petsc/src/sys/objects/inherit.c (revision 10450e9e44b354a0a3da7bbd573407bdf051df10)
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 Notes:
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 PetscErrorCode PetscObjectComposeFunction_Private(PetscObject obj, const char name[], void (*fptr)(void))
772 {
773   PetscFunctionBegin;
774   PetscValidHeader(obj, 1);
775   PetscValidCharPointer(name, 2);
776   PetscCall(PetscFunctionListAdd(&obj->qlist, name, fptr));
777   PetscFunctionReturn(PETSC_SUCCESS);
778 }
779 
780 /*MC
781   PetscObjectQueryFunction - Gets a function associated with a given object.
782 
783   Synopsis:
784   #include <petscsys.h>
785   PetscErrorCode PetscObjectQueryFunction(PetscObject obj, const char name[], void (**fptr)(void))
786 
787   Logically Collective
788 
789   Input Parameters:
790 + obj  - the PETSc object; this must be cast with (`PetscObject`), for example,
791          `PetscObjectQueryFunction`((`PetscObject`)ksp,...);
792 - name - name associated with the child function
793 
794   Output Parameter:
795 . fptr - function pointer
796 
797   Level: advanced
798 
799 .seealso: `PetscObjectComposeFunction()`, `PetscFunctionListFind()`, `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscObject`
800 M*/
801 PETSC_EXTERN PetscErrorCode PetscObjectQueryFunction_Private(PetscObject obj, const char name[], void (**fptr)(void))
802 {
803   PetscFunctionBegin;
804   PetscValidHeader(obj, 1);
805   PetscValidCharPointer(name, 2);
806   PetscCall(PetscFunctionListFind(obj->qlist, name, fptr));
807   PetscFunctionReturn(PETSC_SUCCESS);
808 }
809 
810 struct _p_PetscContainer {
811   PETSCHEADER(int);
812   void *ptr;
813   PetscErrorCode (*userdestroy)(void *);
814 };
815 
816 /*@C
817   PetscContainerUserDestroyDefault - Default destroy routine for user-provided data that simply calls `PetscFree()` in the data
818   provided with `PetscContainerSetPointer()`
819 
820   Logically Collective on the `PetscContainer` containing the user data
821 
822   Input Parameter:
823 . ctx - pointer to user-provided data
824 
825   Level: advanced
826 
827 .seealso: `PetscContainerDestroy()`, `PetscContainerSetUserDestroy()`, `PetscObject`
828 @*/
829 PetscErrorCode PetscContainerUserDestroyDefault(void *ctx)
830 {
831   PetscFunctionBegin;
832   PetscCall(PetscFree(ctx));
833   PetscFunctionReturn(PETSC_SUCCESS);
834 }
835 
836 /*@C
837   PetscContainerGetPointer - Gets the pointer value contained in the container that was provided with `PetscContainerSetPointer()`
838 
839   Not Collective
840 
841   Input Parameter:
842 . obj - the object created with `PetscContainerCreate()`
843 
844   Output Parameter:
845 . ptr - the pointer value
846 
847   Level: advanced
848 
849 .seealso: `PetscContainerCreate()`, `PetscContainerDestroy()`, `PetscObject`,
850           `PetscContainerSetPointer()`
851 @*/
852 PetscErrorCode PetscContainerGetPointer(PetscContainer obj, void **ptr)
853 {
854   PetscFunctionBegin;
855   PetscValidHeaderSpecific(obj, PETSC_CONTAINER_CLASSID, 1);
856   PetscValidPointer(ptr, 2);
857   *ptr = obj->ptr;
858   PetscFunctionReturn(PETSC_SUCCESS);
859 }
860 
861 /*@C
862   PetscContainerSetPointer - Sets the pointer value contained in the container.
863 
864   Logically Collective
865 
866   Input Parameters:
867 + obj - the object created with `PetscContainerCreate()`
868 - ptr - the pointer value
869 
870   Level: advanced
871 
872 .seealso: `PetscContainerCreate()`, `PetscContainerDestroy()`, `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscObject`,
873           `PetscContainerGetPointer()`
874 @*/
875 PetscErrorCode PetscContainerSetPointer(PetscContainer obj, void *ptr)
876 {
877   PetscFunctionBegin;
878   PetscValidHeaderSpecific(obj, PETSC_CONTAINER_CLASSID, 1);
879   if (ptr) PetscValidPointer(ptr, 2);
880   obj->ptr = ptr;
881   PetscFunctionReturn(PETSC_SUCCESS);
882 }
883 
884 /*@C
885   PetscContainerDestroy - Destroys a PETSc container object.
886 
887   Collective
888 
889   Input Parameter:
890 . obj - an object that was created with `PetscContainerCreate()`
891 
892   Level: advanced
893 
894   Note:
895   If `PetscContainerSetUserDestroy()` was used to provide a user destroy object for the data provided with `PetscContainerSetPointer()`
896   then that function is called to destroy the data.
897 
898 .seealso: `PetscContainerCreate()`, `PetscContainerSetUserDestroy()`, `PetscObject`
899 @*/
900 PetscErrorCode PetscContainerDestroy(PetscContainer *obj)
901 {
902   PetscFunctionBegin;
903   if (!*obj) PetscFunctionReturn(PETSC_SUCCESS);
904   PetscValidHeaderSpecific(*obj, PETSC_CONTAINER_CLASSID, 1);
905   if (--((PetscObject)(*obj))->refct > 0) {
906     *obj = NULL;
907     PetscFunctionReturn(PETSC_SUCCESS);
908   }
909   if ((*obj)->userdestroy) PetscCall((*(*obj)->userdestroy)((*obj)->ptr));
910   PetscCall(PetscHeaderDestroy(obj));
911   PetscFunctionReturn(PETSC_SUCCESS);
912 }
913 
914 /*@C
915   PetscContainerSetUserDestroy - Sets name of the user destroy function for the data provided to the `PetscContainer` with `PetscContainerSetPointer()`
916 
917   Logically Collective
918 
919   Input Parameters:
920 + obj - an object that was created with `PetscContainerCreate()`
921 - des - name of the user destroy function
922 
923   Level: advanced
924 
925   Note:
926   Use `PetscContainerUserDestroyDefault()` if the memory was obtained by calling `PetscMalloc()` or one of its variants for single memory allocation.
927 
928 .seealso: `PetscContainerDestroy()`, `PetscContainerUserDestroyDefault()`, `PetscMalloc()`, `PetscMalloc1()`, `PetscCalloc()`, `PetscCalloc1()`, `PetscObject`
929 @*/
930 PetscErrorCode PetscContainerSetUserDestroy(PetscContainer obj, PetscErrorCode (*des)(void *))
931 {
932   PetscFunctionBegin;
933   PetscValidHeaderSpecific(obj, PETSC_CONTAINER_CLASSID, 1);
934   obj->userdestroy = des;
935   PetscFunctionReturn(PETSC_SUCCESS);
936 }
937 
938 PetscClassId PETSC_CONTAINER_CLASSID;
939 
940 /*@C
941   PetscContainerCreate - Creates a PETSc object that has room to hold a single pointer.
942 
943   Collective
944 
945   Input Parameter:
946 . comm - MPI communicator that shares the object
947 
948   Output Parameter:
949 . container - the container created
950 
951   Level: advanced
952 
953   Notes:
954   This allows one to attach any type of data (accessible through a pointer) with the
955   `PetscObjectCompose()` function to a `PetscObject`. The data item itself is attached by a
956   call to `PetscContainerSetPointer()`.
957 
958 .seealso: `PetscContainerDestroy()`, `PetscContainerSetPointer()`, `PetscContainerGetPointer()`, `PetscObjectCompose()`, `PetscObjectQuery()`,
959           `PetscContainerSetUserDestroy()`, `PetscObject`
960 @*/
961 PetscErrorCode PetscContainerCreate(MPI_Comm comm, PetscContainer *container)
962 {
963   PetscFunctionBegin;
964   PetscValidPointer(container, 2);
965   PetscCall(PetscSysInitializePackage());
966   PetscCall(PetscHeaderCreate(*container, PETSC_CONTAINER_CLASSID, "PetscContainer", "Container", "Sys", comm, PetscContainerDestroy, NULL));
967   PetscFunctionReturn(PETSC_SUCCESS);
968 }
969 
970 /*@
971   PetscObjectSetFromOptions - Sets generic parameters from user options.
972 
973   Collective
974 
975   Input Parameter:
976 . obj - the `PetscObject`
977 
978   Level: beginner
979 
980   Note:
981   We have no generic options at present, so this does nothing
982 
983 .seealso: `PetscObjectSetOptionsPrefix()`, `PetscObjectGetOptionsPrefix()`, `PetscObject`
984 @*/
985 PetscErrorCode PetscObjectSetFromOptions(PetscObject obj)
986 {
987   PetscFunctionBegin;
988   PetscValidHeader(obj, 1);
989   PetscFunctionReturn(PETSC_SUCCESS);
990 }
991 
992 /*@
993   PetscObjectSetUp - Sets up the internal data structures for the later use.
994 
995   Collective
996 
997   Input Parameter:
998 . obj - the `PetscObject`
999 
1000   Level: advanced
1001 
1002   Note:
1003   This does nothing at present.
1004 
1005 .seealso: `PetscObjectDestroy()`, `PetscObject`
1006 @*/
1007 PetscErrorCode PetscObjectSetUp(PetscObject obj)
1008 {
1009   PetscFunctionBegin;
1010   PetscValidHeader(obj, 1);
1011   PetscFunctionReturn(PETSC_SUCCESS);
1012 }
1013