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