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