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