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