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