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