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