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