Actual source code: inherit.c

  1: /*
  2:      Provides utility routines for manipulating any type of PETSc object.
  3: */
  4: #include <petsc/private/petscimpl.h>
  5: #include <petscviewer.h>

  7: PETSC_INTERN PetscObject *PetscObjects;
  8: PETSC_INTERN PetscInt     PetscObjectsCounts;
  9: PETSC_INTERN PetscInt     PetscObjectsMaxCounts;
 10: PETSC_INTERN PetscBool    PetscObjectsLog;

 12: PetscObject *PetscObjects       = NULL;
 13: PetscInt     PetscObjectsCounts = 0, PetscObjectsMaxCounts = 0;
 14: PetscBool    PetscObjectsLog = PETSC_FALSE;

 16: PetscObjectId PetscObjectNewId_Internal(void)
 17: {
 18:   static PetscObjectId idcnt = 1;
 19:   return idcnt++;
 20: }

 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: }

 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;

 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;

 51:   PetscCall(PetscCommDuplicate(comm, &h->comm, &h->tag));

 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)++;

 59:   /* Keep a record of object created */
 60:   if (PetscDefined(USE_LOG) && PetscObjectsLog) {
 61:     PetscObject *newPetscObjects;
 62:     PetscInt     newPetscObjectsMaxCounts;

 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));

 78:     PetscObjects                        = newPetscObjects;
 79:     PetscObjects[PetscObjectsMaxCounts] = h;
 80:     PetscObjectsMaxCounts               = newPetscObjectsMaxCounts;
 81:   }
 82:   PetscFunctionReturn(PETSC_SUCCESS);
 83: }

 85: PETSC_INTERN PetscBool      PetscMemoryCollectMaximumUsage;
 86: PETSC_INTERN PetscLogDouble PetscMemoryMaximumUsage;

 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: }

 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;
105:   PetscCheck(!obj->persistent, PetscObjectComm((PetscObject)obj), PETSC_ERR_ARG_WRONGSTATE, "Cannot destroy this object, it is destroyed automatically in PetscFinalize()");
106:   PetscCall(PetscComposedQuantitiesDestroy(obj));
107:   if (PetscMemoryCollectMaximumUsage) {
108:     PetscLogDouble usage;

110:     PetscCall(PetscMemoryGetCurrentUsage(&usage));
111:     if (usage > PetscMemoryMaximumUsage) PetscMemoryMaximumUsage = usage;
112:   }
113:   /* first destroy things that could execute arbitrary code */
114:   if (obj->python_destroy) {
115:     void *python_context                     = obj->python_context;
116:     PetscErrorCode (*python_destroy)(void *) = obj->python_destroy;

118:     obj->python_context = NULL;
119:     obj->python_destroy = NULL;
120:     PetscCall((*python_destroy)(python_context));
121:   }
122:   PetscCall(PetscObjectDestroyOptionsHandlers(obj));
123:   PetscCall(PetscObjectListDestroy(&obj->olist));

125:   /* destroy allocated quantities */
126:   if (PetscPrintFunctionList) PetscCall(PetscFunctionListPrintNonEmpty(obj->qlist));
127:   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);
128:   PetscCall(PetscFree(obj->name));
129:   PetscCall(PetscFree(obj->prefix));
130:   PetscCall(PetscFree(obj->type_name));

132:   if (clear_for_reuse) {
133:     /* we will assume that obj->bops->view and destroy are safe to leave as-is */

135:     /* reset quantities, in order of appearance in _p_PetscObject */
136:     obj->id       = PetscObjectNewId_Internal();
137:     obj->refct    = 1;
138:     obj->tablevel = 0;
139:     obj->state    = 0;
140:     /* don't deallocate, zero these out instead */
141:     PetscCall(PetscFunctionListClear(obj->qlist));
142:     PetscCall(PetscArrayzero(obj->fortran_func_pointers, obj->num_fortran_func_pointers));
143:     PetscCall(PetscArrayzero(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_CLASS], obj->num_fortrancallback[PETSC_FORTRAN_CALLBACK_CLASS]));
144:     PetscCall(PetscArrayzero(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_SUBTYPE], obj->num_fortrancallback[PETSC_FORTRAN_CALLBACK_SUBTYPE]));
145:     obj->optionsprinted = PETSC_FALSE;
146: #if PetscDefined(HAVE_SAWS)
147:     obj->amsmem          = PETSC_FALSE;
148:     obj->amspublishblock = PETSC_FALSE;
149: #endif
150:     obj->options                                  = NULL;
151:     obj->donotPetscObjectPrintClassNamePrefixType = PETSC_FALSE;
152:   } else {
153:     PetscCall(PetscFunctionListDestroy(&obj->qlist));
154:     PetscCall(PetscFree(obj->fortran_func_pointers));
155:     PetscCall(PetscFree(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_CLASS]));
156:     PetscCall(PetscFree(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_SUBTYPE]));
157:     PetscCall(PetscCommDestroy(&obj->comm));
158:     obj->classid = PETSCFREEDHEADER;

160:     if (PetscDefined(USE_LOG) && PetscObjectsLog) {
161:       /* Record object removal from list of all objects */
162:       for (PetscInt i = 0; i < PetscObjectsMaxCounts; ++i) {
163:         if (PetscObjects[i] == obj) {
164:           PetscObjects[i] = NULL;
165:           --PetscObjectsCounts;
166:           break;
167:         }
168:       }
169:       if (!PetscObjectsCounts) {
170:         PetscCall(PetscFree(PetscObjects));
171:         PetscObjectsMaxCounts = 0;
172:       }
173:     }
174:   }
175:   PetscFunctionReturn(PETSC_SUCCESS);
176: }

178: /*
179:   PetscHeaderReset_Internal - "Reset" a PetscObject header. This is tantamount to destroying
180:   the object but does not free all resources. The object retains its:

182:   - classid
183:   - bops->view
184:   - bops->destroy
185:   - comm
186:   - tag
187:   - class_name
188:   - description
189:   - mansec
190:   - cpp

192:   Note that while subclass information is lost, superclass info remains. Thus this function is
193:   intended to be used to reuse a PetscObject within the same class to avoid reallocating its
194:   resources.
195: */
196: PetscErrorCode PetscHeaderReset_Internal(PetscObject obj)
197: {
198:   PetscFunctionBegin;
199:   PetscCall(PetscHeaderDestroy_Private(obj, PETSC_TRUE));
200:   PetscFunctionReturn(PETSC_SUCCESS);
201: }

203: /*@C
204:   PetscObjectCopyFortranFunctionPointers - Copy function pointers to another object

206:   Logically Collective

208:   Input Parameters:
209: + src  - source object
210: - dest - destination object

212:   Level: developer

214:   Note:
215:   Both objects must have the same class.

217:   This is used to help manage user callback functions that were provided in Fortran

219: .seealso: `PetscFortranCallbackRegister()`, `PetscFortranCallbackGetSizes()`
220: @*/
221: PetscErrorCode PetscObjectCopyFortranFunctionPointers(PetscObject src, PetscObject dest)
222: {
223:   PetscFortranCallbackId cbtype, numcb[PETSC_FORTRAN_CALLBACK_MAXTYPE];

225:   PetscFunctionBegin;
228:   PetscCheck(src->classid == dest->classid, src->comm, PETSC_ERR_ARG_INCOMP, "Objects must be of the same class");

230:   PetscCall(PetscFree(dest->fortran_func_pointers));
231:   PetscCall(PetscMalloc(src->num_fortran_func_pointers * sizeof(void (*)(void)), &dest->fortran_func_pointers));
232:   PetscCall(PetscMemcpy(dest->fortran_func_pointers, src->fortran_func_pointers, src->num_fortran_func_pointers * sizeof(void (*)(void))));

234:   dest->num_fortran_func_pointers = src->num_fortran_func_pointers;

236:   PetscCall(PetscFortranCallbackGetSizes(src->classid, &numcb[PETSC_FORTRAN_CALLBACK_CLASS], &numcb[PETSC_FORTRAN_CALLBACK_SUBTYPE]));
237:   for (cbtype = PETSC_FORTRAN_CALLBACK_CLASS; cbtype < PETSC_FORTRAN_CALLBACK_MAXTYPE; cbtype++) {
238:     PetscCall(PetscFree(dest->fortrancallback[cbtype]));
239:     PetscCall(PetscCalloc1(numcb[cbtype], &dest->fortrancallback[cbtype]));
240:     PetscCall(PetscMemcpy(dest->fortrancallback[cbtype], src->fortrancallback[cbtype], src->num_fortrancallback[cbtype] * sizeof(PetscFortranCallback)));
241:     dest->num_fortrancallback[cbtype] = src->num_fortrancallback[cbtype];
242:   }
243:   PetscFunctionReturn(PETSC_SUCCESS);
244: }

246: /*@C
247:   PetscObjectSetFortranCallback - set Fortran callback function pointer and context

249:   Logically Collective

251:   Input Parameters:
252: + obj    - object on which to set callback
253: . cbtype - callback type (class or subtype)
254: . cid    - address of callback Id, updated if not yet initialized (zero)
255: . func   - Fortran function
256: - ctx    - Fortran context

258:   Level: developer

260:   Note:
261:   This is used to help manage user callback functions that were provided in Fortran

263: .seealso: `PetscObjectGetFortranCallback()`, `PetscFortranCallbackRegister()`, `PetscFortranCallbackGetSizes()`
264: @*/
265: PetscErrorCode PetscObjectSetFortranCallback(PetscObject obj, PetscFortranCallbackType cbtype, PetscFortranCallbackId *cid, void (*func)(void), void *ctx)
266: {
267:   const char *subtype = NULL;

269:   PetscFunctionBegin;
271:   if (cbtype == PETSC_FORTRAN_CALLBACK_SUBTYPE) subtype = obj->type_name;
272:   if (!*cid) PetscCall(PetscFortranCallbackRegister(obj->classid, subtype, cid));
273:   if (*cid >= PETSC_SMALLEST_FORTRAN_CALLBACK + obj->num_fortrancallback[cbtype]) {
274:     PetscFortranCallbackId oldnum = obj->num_fortrancallback[cbtype];
275:     PetscFortranCallbackId newnum = PetscMax(*cid - PETSC_SMALLEST_FORTRAN_CALLBACK + 1, 2 * oldnum);
276:     PetscFortranCallback  *callback;
277:     PetscCall(PetscMalloc1(newnum, &callback));
278:     PetscCall(PetscMemcpy(callback, obj->fortrancallback[cbtype], oldnum * sizeof(*obj->fortrancallback[cbtype])));
279:     PetscCall(PetscFree(obj->fortrancallback[cbtype]));

281:     obj->fortrancallback[cbtype]     = callback;
282:     obj->num_fortrancallback[cbtype] = newnum;
283:   }
284:   obj->fortrancallback[cbtype][*cid - PETSC_SMALLEST_FORTRAN_CALLBACK].func = func;
285:   obj->fortrancallback[cbtype][*cid - PETSC_SMALLEST_FORTRAN_CALLBACK].ctx  = ctx;
286:   PetscFunctionReturn(PETSC_SUCCESS);
287: }

289: /*@C
290:   PetscObjectGetFortranCallback - get Fortran callback function pointer and context

292:   Logically Collective

294:   Input Parameters:
295: + obj    - object on which to get callback
296: . cbtype - callback type
297: - cid    - address of callback Id

299:   Output Parameters:
300: + func - Fortran function (or `NULL` if not needed)
301: - ctx  - Fortran context (or `NULL` if not needed)

303:   Level: developer

305:   Note:
306:   This is used to help manage user callback functions that were provided in Fortran

308: .seealso: `PetscObjectSetFortranCallback()`, `PetscFortranCallbackRegister()`, `PetscFortranCallbackGetSizes()`
309: @*/
310: PetscErrorCode PetscObjectGetFortranCallback(PetscObject obj, PetscFortranCallbackType cbtype, PetscFortranCallbackId cid, void (**func)(void), void **ctx)
311: {
312:   PetscFortranCallback *cb;

314:   PetscFunctionBegin;
316:   PetscCheck(cid >= PETSC_SMALLEST_FORTRAN_CALLBACK, obj->comm, PETSC_ERR_ARG_CORRUPT, "Fortran callback Id invalid");
317:   PetscCheck(cid < PETSC_SMALLEST_FORTRAN_CALLBACK + obj->num_fortrancallback[cbtype], obj->comm, PETSC_ERR_ARG_CORRUPT, "Fortran callback not set on this object");
318:   cb = &obj->fortrancallback[cbtype][cid - PETSC_SMALLEST_FORTRAN_CALLBACK];
319:   if (func) *func = cb->func;
320:   if (ctx) *ctx = cb->ctx;
321:   PetscFunctionReturn(PETSC_SUCCESS);
322: }

324: #if defined(PETSC_USE_LOG)
325: /*@C
326:   PetscObjectsDump - Prints all the currently existing objects.

328:   Input Parameters:
329: + fd  - file pointer
330: - all - by default only tries to display objects created explicitly by the user, if all is `PETSC_TRUE` then lists all outstanding objects

332:   Options Database Key:
333: . -objects_dump <all> - print information about all the objects that exist at the end of the programs run

335:   Level: advanced

337:   Note:
338:   Only MPI rank 0 of `PETSC_COMM_WORLD` prints the values

340: .seealso: `PetscObject`
341: @*/
342: PetscErrorCode PetscObjectsDump(FILE *fd, PetscBool all)
343: {
344:   PetscInt    i, j, k = 0;
345:   PetscObject h;

347:   PetscFunctionBegin;
348:   if (PetscObjectsCounts) {
349:     PetscCall(PetscFPrintf(PETSC_COMM_WORLD, fd, "The following objects were never freed\n"));
350:     PetscCall(PetscFPrintf(PETSC_COMM_WORLD, fd, "-----------------------------------------\n"));
351:     for (i = 0; i < PetscObjectsMaxCounts; i++) {
352:       if ((h = PetscObjects[i])) {
353:         PetscCall(PetscObjectName(h));
354:         {
355:           PetscStack *stack  = NULL;
356:           char       *create = NULL, *rclass = NULL;

358:           /* if the PETSc function the user calls is not a create then this object was NOT directly created by them */
359:           PetscCall(PetscMallocGetStack(h, &stack));
360:           if (stack) {
361:             k = stack->currentsize - 2;
362:             if (!all) {
363:               k = 0;
364:               while (!stack->petscroutine[k]) k++;
365:               PetscCall(PetscStrstr(stack->function[k], "Create", &create));
366:               if (!create) PetscCall(PetscStrstr(stack->function[k], "Get", &create));
367:               PetscCall(PetscStrstr(stack->function[k], h->class_name, &rclass));
368:               if (!create) continue;
369:               if (!rclass) continue;
370:             }
371:           }

373:           PetscCall(PetscFPrintf(PETSC_COMM_WORLD, fd, "[%d] %s %s %s\n", PetscGlobalRank, h->class_name, h->type_name, h->name));

375:           PetscCall(PetscMallocGetStack(h, &stack));
376:           if (stack) {
377:             for (j = k; j >= 0; j--) fprintf(fd, "      [%d]  %s() in %s\n", PetscGlobalRank, stack->function[j], stack->file[j]);
378:           }
379:         }
380:       }
381:     }
382:   }
383:   PetscFunctionReturn(PETSC_SUCCESS);
384: }

386: /*@C
387:   PetscObjectsView - Prints the currently existing objects.

389:   Logically Collective

391:   Input Parameter:
392: . viewer - must be an `PETSCVIEWERASCII` viewer

394:   Level: advanced

396: .seealso: `PetscObject`
397: @*/
398: PetscErrorCode PetscObjectsView(PetscViewer viewer)
399: {
400:   PetscBool isascii;
401:   FILE     *fd;

403:   PetscFunctionBegin;
404:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD;
405:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
406:   PetscCheck(isascii, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Only supports ASCII viewer");
407:   PetscCall(PetscViewerASCIIGetPointer(viewer, &fd));
408:   PetscCall(PetscObjectsDump(fd, PETSC_TRUE));
409:   PetscFunctionReturn(PETSC_SUCCESS);
410: }

412: /*@C
413:   PetscObjectsGetObject - Get a pointer to a named object

415:   Not Collective

417:   Input Parameter:
418: . name - the name of an object

420:   Output Parameters:
421: + obj       - the object or `NULL` if there is no object, optional, pass in `NULL` if not needed
422: - classname - the name of the class of the object, optional, pass in `NULL` if not needed

424:   Level: advanced

426: .seealso: `PetscObject`
427: @*/
428: PetscErrorCode PetscObjectsGetObject(const char *name, PetscObject *obj, char **classname)
429: {
430:   PetscInt    i;
431:   PetscObject h;
432:   PetscBool   flg;

434:   PetscFunctionBegin;
435:   PetscAssertPointer(name, 1);
436:   if (obj) *obj = NULL;
437:   for (i = 0; i < PetscObjectsMaxCounts; i++) {
438:     if ((h = PetscObjects[i])) {
439:       PetscCall(PetscObjectName(h));
440:       PetscCall(PetscStrcmp(h->name, name, &flg));
441:       if (flg) {
442:         if (obj) *obj = h;
443:         if (classname) *classname = h->class_name;
444:         PetscFunctionReturn(PETSC_SUCCESS);
445:       }
446:     }
447:   }
448:   PetscFunctionReturn(PETSC_SUCCESS);
449: }
450: #endif

452: /*@
453:   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

455:   Input Parameter:
456: . obj - the `PetscObject`

458:   Level: developer

460:   Developer Notes:
461:   This is used, for example to prevent sequential objects that are created from a parallel object; such as the `KSP` created by
462:   `PCBJACOBI` from all printing the same help messages to the screen

464: .seealso: `PetscOptionsInsert()`, `PetscObject`
465: @*/
466: PetscErrorCode PetscObjectSetPrintedOptions(PetscObject obj)
467: {
468:   PetscFunctionBegin;
469:   PetscAssertPointer(obj, 1);
470:   obj->optionsprinted = PETSC_TRUE;
471:   PetscFunctionReturn(PETSC_SUCCESS);
472: }

474: /*@
475:   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.

477:   Input Parameters:
478: + pobj - the parent object
479: - obj  - the `PetscObject`

481:   Level: developer

483:   Developer Notes:
484:   This is used, for example to prevent sequential objects that are created from a parallel object; such as the `KSP` created by
485:   `PCBJACOBI` from all printing the same help messages to the screen

487:   This will not handle more complicated situations like with `PCGASM` where children may live on any subset of the parent's processes and overlap

489: .seealso: `PetscOptionsInsert()`, `PetscObjectSetPrintedOptions()`, `PetscObject`
490: @*/
491: PetscErrorCode PetscObjectInheritPrintedOptions(PetscObject pobj, PetscObject obj)
492: {
493:   PetscMPIInt prank, size;

495:   PetscFunctionBegin;
498:   PetscCallMPI(MPI_Comm_rank(pobj->comm, &prank));
499:   PetscCallMPI(MPI_Comm_size(obj->comm, &size));
500:   if (size == 1 && prank > 0) obj->optionsprinted = PETSC_TRUE;
501:   PetscFunctionReturn(PETSC_SUCCESS);
502: }

504: /*@C
505:   PetscObjectAddOptionsHandler - Adds an additional function to check for options when `XXXSetFromOptions()` is called.

507:   Not Collective

509:   Input Parameters:
510: + obj     - the PETSc object
511: . handle  - function that checks for options
512: . destroy - function to destroy `ctx` if provided
513: - ctx     - optional context for check function

515:   Calling sequence of `handle`:
516: + obj                - the PETSc object
517: . PetscOptionsObject - the `PetscOptionItems` object
518: - ctx                - optional context for `handle`

520:   Calling sequence of `destroy`:
521: + obj - the PETSc object
522: - ctx - optional context for `handle`

524:   Level: developer

526: .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectProcessOptionsHandlers()`, `PetscObjectDestroyOptionsHandlers()`,
527:           `PetscObject`
528: @*/
529: PetscErrorCode PetscObjectAddOptionsHandler(PetscObject obj, PetscErrorCode (*handle)(PetscObject obj, PetscOptionItems *PetscOptionsObject, void *ctx), PetscErrorCode (*destroy)(PetscObject obj, void *ctx), void *ctx)
530: {
531:   PetscFunctionBegin;
533:   PetscCheck(obj->noptionhandler < PETSC_MAX_OPTIONS_HANDLER, obj->comm, PETSC_ERR_ARG_OUTOFRANGE, "To many options handlers added");
534:   obj->optionhandler[obj->noptionhandler] = handle;
535:   obj->optiondestroy[obj->noptionhandler] = destroy;
536:   obj->optionctx[obj->noptionhandler++]   = ctx;
537:   PetscFunctionReturn(PETSC_SUCCESS);
538: }

540: /*@C
541:   PetscObjectProcessOptionsHandlers - Calls all the options handlers attached to an object

543:   Not Collective

545:   Input Parameters:
546: + obj                - the PETSc object
547: - PetscOptionsObject - the options context

549:   Level: developer

551: .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectAddOptionsHandler()`, `PetscObjectDestroyOptionsHandlers()`,
552:           `PetscObject`
553: @*/
554: PetscErrorCode PetscObjectProcessOptionsHandlers(PetscObject obj, PetscOptionItems *PetscOptionsObject)
555: {
556:   PetscFunctionBegin;
558:   for (PetscInt i = 0; i < obj->noptionhandler; i++) PetscCall((*obj->optionhandler[i])(obj, PetscOptionsObject, obj->optionctx[i]));
559:   PetscFunctionReturn(PETSC_SUCCESS);
560: }

562: /*@C
563:   PetscObjectDestroyOptionsHandlers - Destroys all the option handlers attached to an object

565:   Not Collective

567:   Input Parameter:
568: . obj - the PETSc object

570:   Level: developer

572: .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectAddOptionsHandler()`, `PetscObjectProcessOptionsHandlers()`,
573:           `PetscObject`
574: @*/
575: PetscErrorCode PetscObjectDestroyOptionsHandlers(PetscObject obj)
576: {
577:   PetscFunctionBegin;
579:   for (PetscInt i = 0; i < obj->noptionhandler; i++) {
580:     if (obj->optiondestroy[i]) PetscCall((*obj->optiondestroy[i])(obj, obj->optionctx[i]));
581:   }
582:   obj->noptionhandler = 0;
583:   PetscFunctionReturn(PETSC_SUCCESS);
584: }

586: /*@C
587:   PetscObjectReference - Indicates to a `PetscObject` that it is being
588:   referenced by another `PetscObject`. This increases the reference
589:   count for that object by one.

591:   Logically Collective

593:   Input Parameter:
594: . obj - the PETSc object. This must be cast with (`PetscObject`), for example, `PetscObjectReference`((`PetscObject`)mat);

596:   Level: advanced

598:   Note:
599:   If `obj` is `NULL` this function returns without doing anything.

601: .seealso: `PetscObjectCompose()`, `PetscObjectDereference()`, `PetscObject`
602: @*/
603: PetscErrorCode PetscObjectReference(PetscObject obj)
604: {
605:   PetscFunctionBegin;
606:   if (!obj) PetscFunctionReturn(PETSC_SUCCESS);
608:   obj->refct++;
609:   PetscFunctionReturn(PETSC_SUCCESS);
610: }

612: /*@C
613:   PetscObjectGetReference - Gets the current reference count for a PETSc object.

615:   Not Collective

617:   Input Parameter:
618: . obj - the PETSc object; this must be cast with (`PetscObject`), for example,
619:         `PetscObjectGetReference`((`PetscObject`)mat,&cnt); `obj` cannot be `NULL`

621:   Output Parameter:
622: . cnt - the reference count

624:   Level: advanced

626: .seealso: `PetscObjectCompose()`, `PetscObjectDereference()`, `PetscObjectReference()`, `PetscObject`
627: @*/
628: PetscErrorCode PetscObjectGetReference(PetscObject obj, PetscInt *cnt)
629: {
630:   PetscFunctionBegin;
632:   PetscAssertPointer(cnt, 2);
633:   *cnt = obj->refct;
634:   PetscFunctionReturn(PETSC_SUCCESS);
635: }

637: /*@C
638:   PetscObjectDereference - Indicates to any `PetscObject` that it is being
639:   referenced by one less `PetscObject`. This decreases the reference
640:   count for that object by one.

642:   Collective on `obj` if reference reaches 0 otherwise Logically Collective

644:   Input Parameter:
645: . obj - the PETSc object; this must be cast with (`PetscObject`), for example,
646:         `PetscObjectDereference`((`PetscObject`)mat);

648:   Level: advanced

650:   Notes:
651:   `PetscObjectDestroy()` sets the `obj` pointer to `NULL` after the call, this routine does not.

653:   If `obj` is `NULL` this function returns without doing anything.

655: .seealso: `PetscObjectCompose()`, `PetscObjectReference()`, `PetscObjectDestroy()`, `PetscObject`
656: @*/
657: PetscErrorCode PetscObjectDereference(PetscObject obj)
658: {
659:   PetscFunctionBegin;
660:   if (!obj) PetscFunctionReturn(PETSC_SUCCESS);
662:   if (obj->bops->destroy) PetscCall((*obj->bops->destroy)(&obj));
663:   else PetscCheck(--(obj->refct), PETSC_COMM_SELF, PETSC_ERR_SUP, "This PETSc object does not have a generic destroy routine");
664:   PetscFunctionReturn(PETSC_SUCCESS);
665: }

667: /*
668:      The following routines are the versions private to the PETSc object
669:      data structures.
670: */
671: PetscErrorCode PetscObjectRemoveReference(PetscObject obj, const char name[])
672: {
673:   PetscFunctionBegin;
675:   PetscCall(PetscObjectListRemoveReference(&obj->olist, name));
676:   PetscFunctionReturn(PETSC_SUCCESS);
677: }

679: /*@C
680:   PetscObjectCompose - Associates another PETSc object with a given PETSc object.

682:   Not Collective

684:   Input Parameters:
685: + obj  - the PETSc object; this must be cast with (`PetscObject`), for example,
686:          `PetscObjectCompose`((`PetscObject`)mat,...);
687: . name - name associated with the child object
688: - ptr  - the other PETSc object to associate with the PETSc object; this must also be
689:          cast with (`PetscObject`)

691:   Level: advanced

693:   Notes:
694:   The second objects reference count is automatically increased by one when it is
695:   composed.

697:   Replaces any previous object that had been composed with the same name.

699:   If `ptr` is `NULL` and `name` has previously been composed using an object, then that
700:   entry is removed from `obj`.

702:   `PetscObjectCompose()` can be used with any PETSc object (such as
703:   `Mat`, `Vec`, `KSP`, `SNES`, etc.) or any user-provided object.

705:   `PetscContainerCreate()` can be used to create an object from a
706:   user-provided pointer that may then be composed with PETSc objects using `PetscObjectCompose()`

708: .seealso: `PetscObjectQuery()`, `PetscContainerCreate()`, `PetscObjectComposeFunction()`, `PetscObjectQueryFunction()`, `PetscContainer`,
709:           `PetscContainerSetPointer()`, `PetscObject`
710: @*/
711: PetscErrorCode PetscObjectCompose(PetscObject obj, const char name[], PetscObject ptr)
712: {
713:   PetscFunctionBegin;
715:   PetscAssertPointer(name, 2);
717:   PetscCheck(obj != ptr, PetscObjectComm((PetscObject)obj), PETSC_ERR_SUP, "Cannot compose object with itself");
718:   if (ptr) {
719:     char     *tname;
720:     PetscBool skipreference;

722:     PetscCall(PetscObjectListReverseFind(ptr->olist, obj, &tname, &skipreference));
723:     if (tname) PetscCheck(skipreference, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "An object cannot be composed with an object that was composed with it");
724:   }
725:   PetscCall(PetscObjectListAdd(&obj->olist, name, ptr));
726:   PetscFunctionReturn(PETSC_SUCCESS);
727: }

729: /*@C
730:   PetscObjectQuery  - Gets a PETSc object associated with a given object that was composed with `PetscObjectCompose()`

732:   Not Collective

734:   Input Parameters:
735: + obj  - the PETSc object. It must be cast with a (`PetscObject`), for example,
736:          `PetscObjectCompose`((`PetscObject`)mat,...);
737: . name - name associated with child object
738: - ptr  - the other PETSc object associated with the PETSc object, this must be
739:          cast with (`PetscObject`*)

741:   Level: advanced

743:   Note:
744:   The reference count of neither object is increased in this call

746: .seealso: `PetscObjectCompose()`, `PetscObjectComposeFunction()`, `PetscObjectQueryFunction()`, `PetscContainer`
747:           `PetscContainerGetPointer()`, `PetscObject`
748: @*/
749: PetscErrorCode PetscObjectQuery(PetscObject obj, const char name[], PetscObject *ptr)
750: {
751:   PetscFunctionBegin;
753:   PetscAssertPointer(name, 2);
754:   PetscAssertPointer(ptr, 3);
755:   PetscCall(PetscObjectListFind(obj->olist, name, ptr));
756:   PetscFunctionReturn(PETSC_SUCCESS);
757: }

759: /*MC
760:   PetscObjectComposeFunction - Associates a function with a given PETSc object.

762:   Synopsis:
763: #include <petscsys.h>
764:   PetscErrorCode PetscObjectComposeFunction(PetscObject obj, const char name[], void (*fptr)(void))

766:   Logically Collective

768:   Input Parameters:
769: + obj  - the PETSc object; this must be cast with a (`PetscObject`), for example,
770:          `PetscObjectCompose`((`PetscObject`)mat,...);
771: . name - name associated with the child function
772: - fptr - function pointer

774:   Level: advanced

776:   Notes:
777:   When the first argument of `fptr` is (or is derived from) a `PetscObject` then `PetscTryMethod()` and `PetscUseMethod()`
778:   can be used to call the function directly with error checking.

780:   To remove a registered routine, pass in `NULL` for `fptr`.

782:   `PetscObjectComposeFunction()` can be used with any PETSc object (such as
783:   `Mat`, `Vec`, `KSP`, `SNES`, etc.) or any user-provided object.

785:   `PetscUseTypeMethod()` and `PetscTryTypeMethod()` are used to call a function that is stored in the objects `obj->ops` table.

787: .seealso: `PetscObjectQueryFunction()`, `PetscContainerCreate()` `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscTryMethod()`, `PetscUseMethod()`,
788:           `PetscUseTypeMethod()`, `PetscTryTypeMethod()`, `PetscObject`
789: M*/
790: PetscErrorCode PetscObjectComposeFunction_Private(PetscObject obj, const char name[], void (*fptr)(void))
791: {
792:   PetscFunctionBegin;
794:   PetscAssertPointer(name, 2);
795:   PetscCall(PetscFunctionListAdd(&obj->qlist, name, fptr));
796:   PetscFunctionReturn(PETSC_SUCCESS);
797: }

799: /*MC
800:   PetscObjectQueryFunction - Gets a function associated with a given object.

802:   Synopsis:
803: #include <petscsys.h>
804:   PetscErrorCode PetscObjectQueryFunction(PetscObject obj, const char name[], void (**fptr)(void))

806:   Logically Collective

808:   Input Parameters:
809: + obj  - the PETSc object; this must be cast with (`PetscObject`), for example,
810:          `PetscObjectQueryFunction`((`PetscObject`)ksp,...);
811: - name - name associated with the child function

813:   Output Parameter:
814: . fptr - function pointer

816:   Level: advanced

818: .seealso: `PetscObjectComposeFunction()`, `PetscFunctionListFind()`, `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscObject`
819: M*/
820: PETSC_EXTERN PetscErrorCode PetscObjectQueryFunction_Private(PetscObject obj, const char name[], void (**fptr)(void))
821: {
822:   PetscFunctionBegin;
824:   PetscAssertPointer(name, 2);
825:   PetscCall(PetscFunctionListFind(obj->qlist, name, fptr));
826:   PetscFunctionReturn(PETSC_SUCCESS);
827: }

829: struct _p_PetscContainer {
830:   PETSCHEADER(int);
831:   void *ptr;
832:   PetscErrorCode (*userdestroy)(void *);
833: };

835: /*@C
836:   PetscContainerUserDestroyDefault - Default destroy routine for user-provided data that simply calls `PetscFree()` in the data
837:   provided with `PetscContainerSetPointer()`

839:   Logically Collective on the `PetscContainer` containing the user data

841:   Input Parameter:
842: . ctx - pointer to user-provided data

844:   Level: advanced

846: .seealso: `PetscContainerDestroy()`, `PetscContainerSetUserDestroy()`, `PetscObject`
847: @*/
848: PetscErrorCode PetscContainerUserDestroyDefault(void *ctx)
849: {
850:   PetscFunctionBegin;
851:   PetscCall(PetscFree(ctx));
852:   PetscFunctionReturn(PETSC_SUCCESS);
853: }

855: /*@C
856:   PetscContainerGetPointer - Gets the pointer value contained in the container that was provided with `PetscContainerSetPointer()`

858:   Not Collective

860:   Input Parameter:
861: . obj - the object created with `PetscContainerCreate()`

863:   Output Parameter:
864: . ptr - the pointer value

866:   Level: advanced

868: .seealso: `PetscContainerCreate()`, `PetscContainerDestroy()`, `PetscObject`,
869:           `PetscContainerSetPointer()`
870: @*/
871: PetscErrorCode PetscContainerGetPointer(PetscContainer obj, void **ptr)
872: {
873:   PetscFunctionBegin;
875:   PetscAssertPointer(ptr, 2);
876:   *ptr = obj->ptr;
877:   PetscFunctionReturn(PETSC_SUCCESS);
878: }

880: /*@C
881:   PetscContainerSetPointer - Sets the pointer value contained in the container.

883:   Logically Collective

885:   Input Parameters:
886: + obj - the object created with `PetscContainerCreate()`
887: - ptr - the pointer value

889:   Level: advanced

891: .seealso: `PetscContainerCreate()`, `PetscContainerDestroy()`, `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscObject`,
892:           `PetscContainerGetPointer()`
893: @*/
894: PetscErrorCode PetscContainerSetPointer(PetscContainer obj, void *ptr)
895: {
896:   PetscFunctionBegin;
898:   if (ptr) PetscAssertPointer(ptr, 2);
899:   obj->ptr = ptr;
900:   PetscFunctionReturn(PETSC_SUCCESS);
901: }

903: /*@C
904:   PetscContainerDestroy - Destroys a PETSc container object.

906:   Collective

908:   Input Parameter:
909: . obj - an object that was created with `PetscContainerCreate()`

911:   Level: advanced

913:   Note:
914:   If `PetscContainerSetUserDestroy()` was used to provide a user destroy object for the data provided with `PetscContainerSetPointer()`
915:   then that function is called to destroy the data.

917: .seealso: `PetscContainerCreate()`, `PetscContainerSetUserDestroy()`, `PetscObject`
918: @*/
919: PetscErrorCode PetscContainerDestroy(PetscContainer *obj)
920: {
921:   PetscFunctionBegin;
922:   if (!*obj) PetscFunctionReturn(PETSC_SUCCESS);
924:   if (--((PetscObject)*obj)->refct > 0) {
925:     *obj = NULL;
926:     PetscFunctionReturn(PETSC_SUCCESS);
927:   }
928:   if ((*obj)->userdestroy) PetscCall((*(*obj)->userdestroy)((*obj)->ptr));
929:   PetscCall(PetscHeaderDestroy(obj));
930:   PetscFunctionReturn(PETSC_SUCCESS);
931: }

933: /*@C
934:   PetscContainerSetUserDestroy - Sets name of the user destroy function for the data provided to the `PetscContainer` with `PetscContainerSetPointer()`

936:   Logically Collective

938:   Input Parameters:
939: + obj - an object that was created with `PetscContainerCreate()`
940: - des - name of the user destroy function

942:   Level: advanced

944:   Note:
945:   Use `PetscContainerUserDestroyDefault()` if the memory was obtained by calling `PetscMalloc()` or one of its variants for single memory allocation.

947: .seealso: `PetscContainerDestroy()`, `PetscContainerUserDestroyDefault()`, `PetscMalloc()`, `PetscMalloc1()`, `PetscCalloc()`, `PetscCalloc1()`, `PetscObject`
948: @*/
949: PetscErrorCode PetscContainerSetUserDestroy(PetscContainer obj, PetscErrorCode (*des)(void *))
950: {
951:   PetscFunctionBegin;
953:   obj->userdestroy = des;
954:   PetscFunctionReturn(PETSC_SUCCESS);
955: }

957: PetscClassId PETSC_CONTAINER_CLASSID;

959: /*@C
960:   PetscContainerCreate - Creates a PETSc object that has room to hold a single pointer.

962:   Collective

964:   Input Parameter:
965: . comm - MPI communicator that shares the object

967:   Output Parameter:
968: . container - the container created

970:   Level: advanced

972:   Notes:
973:   This allows one to attach any type of data (accessible through a pointer) with the
974:   `PetscObjectCompose()` function to a `PetscObject`. The data item itself is attached by a
975:   call to `PetscContainerSetPointer()`.

977: .seealso: `PetscContainerDestroy()`, `PetscContainerSetPointer()`, `PetscContainerGetPointer()`, `PetscObjectCompose()`, `PetscObjectQuery()`,
978:           `PetscContainerSetUserDestroy()`, `PetscObject`
979: @*/
980: PetscErrorCode PetscContainerCreate(MPI_Comm comm, PetscContainer *container)
981: {
982:   PetscFunctionBegin;
983:   PetscAssertPointer(container, 2);
984:   PetscCall(PetscSysInitializePackage());
985:   PetscCall(PetscHeaderCreate(*container, PETSC_CONTAINER_CLASSID, "PetscContainer", "Container", "Sys", comm, PetscContainerDestroy, NULL));
986:   PetscFunctionReturn(PETSC_SUCCESS);
987: }

989: /*@
990:   PetscObjectSetFromOptions - Sets generic parameters from user options.

992:   Collective

994:   Input Parameter:
995: . obj - the `PetscObject`

997:   Level: beginner

999:   Note:
1000:   We have no generic options at present, so this does nothing

1002: .seealso: `PetscObjectSetOptionsPrefix()`, `PetscObjectGetOptionsPrefix()`, `PetscObject`
1003: @*/
1004: PetscErrorCode PetscObjectSetFromOptions(PetscObject obj)
1005: {
1006:   PetscFunctionBegin;
1008:   PetscFunctionReturn(PETSC_SUCCESS);
1009: }

1011: /*@
1012:   PetscObjectSetUp - Sets up the internal data structures for later use of the object

1014:   Collective

1016:   Input Parameter:
1017: . obj - the `PetscObject`

1019:   Level: advanced

1021:   Note:
1022:   This does nothing at present.

1024: .seealso: `PetscObjectDestroy()`, `PetscObject`
1025: @*/
1026: PetscErrorCode PetscObjectSetUp(PetscObject obj)
1027: {
1028:   PetscFunctionBegin;
1030:   PetscFunctionReturn(PETSC_SUCCESS);
1031: }