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