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