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, PetscObjectDestroyFunction destroy, PetscObjectViewFunction view)
 23: {
 24:   if (ierr) return ierr;
 25:   PetscFunctionBegin;
 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, PetscObjectDestroyFunction destroy, PetscObjectViewFunction 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)++;
 58:   PetscCallMPI(MPI_Comm_set_attr(h->comm, Petsc_CreationIdx_keyval, cidx));

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

 65:     PetscObjectsCounts++;
 66:     for (PetscInt i = 0; i < PetscObjectsMaxCounts; ++i) {
 67:       if (!PetscObjects[i]) {
 68:         PetscObjects[i] = h;
 69:         PetscFunctionReturn(PETSC_SUCCESS);
 70:       }
 71:     }
 72:     /* Need to increase the space for storing PETSc objects */
 73:     if (!PetscObjectsMaxCounts) newPetscObjectsMaxCounts = 100;
 74:     else newPetscObjectsMaxCounts = 2 * PetscObjectsMaxCounts;
 75:     PetscCall(PetscCalloc1(newPetscObjectsMaxCounts, &newPetscObjects));
 76:     PetscCall(PetscArraycpy(newPetscObjects, PetscObjects, PetscObjectsMaxCounts));
 77:     PetscCall(PetscFree(PetscObjects));

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

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

 89: PetscErrorCode PetscHeaderDestroy_Function(PetscObject *h)
 90: {
 91:   PetscFunctionBegin;
 92:   PetscCall(PetscLogObjectDestroy(*h));
 93:   PetscCall(PetscHeaderDestroy_Private(*h, PETSC_FALSE));
 94:   PetscCall(PetscFree(*h));
 95:   PetscFunctionReturn(PETSC_SUCCESS);
 96: }

 98: /*
 99:     PetscHeaderDestroy_Private - Destroys a base PETSc object header. Called by
100:     the macro PetscHeaderDestroy().
101: */
102: PetscErrorCode PetscHeaderDestroy_Private(PetscObject obj, PetscBool clear_for_reuse)
103: {
104:   PetscFunctionBegin;
106:   PetscCheck(!obj->persistent, PetscObjectComm((PetscObject)obj), PETSC_ERR_ARG_WRONGSTATE, "Cannot destroy this object, it is destroyed automatically in PetscFinalize()");
107:   PetscCall(PetscComposedQuantitiesDestroy(obj));
108:   if (PetscMemoryCollectMaximumUsage) {
109:     PetscLogDouble usage;

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

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

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

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

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

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

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

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

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

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

207:   Logically Collective

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

213:   Level: developer

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

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

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

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

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

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

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

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

250:   Logically Collective

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

259:   Level: developer

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

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

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

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

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

293:   Logically Collective

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

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

304:   Level: developer

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

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

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

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

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

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

336:   Level: advanced

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

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

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

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

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

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

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

390:   Logically Collective

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

395:   Level: advanced

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

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

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

416:   Not Collective

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

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

425:   Level: advanced

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

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

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

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

459:   Level: developer

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

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

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

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

482:   Level: developer

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

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

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

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

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

508:   Not Collective

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

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

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

525:   Level: developer

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

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

544:   Not Collective

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

550:   Level: developer

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

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

566:   Not Collective

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

571:   Level: developer

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

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

592:   Logically Collective

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

598:   Level: advanced

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

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

614:   Not Collective

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

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

623:   Level: advanced

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

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

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

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

647:   Level: advanced

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

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

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

676: /*@C
677:   PetscObjectCompose - Associates another PETSc object with a given PETSc object.

679:   Not Collective

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

688:   Level: advanced

690:   Notes:
691:   The second objects reference count is automatically increased by one when it is
692:   composed.

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

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

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

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

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

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

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

729:   Not Collective

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

738:   Level: advanced

740:   Note:
741:   The reference count of neither object is increased in this call

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

756: /*MC
757:   PetscObjectComposeFunction - Associates a function with a given PETSc object.

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

763:   Logically Collective

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

771:   Level: advanced

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

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

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

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

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

796: /*MC
797:   PetscObjectQueryFunction - Gets a function associated with a given object.

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

803:   Logically Collective

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

810:   Output Parameter:
811: . fptr - function pointer

813:   Level: advanced

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

826: struct _p_PetscContainer {
827:   PETSCHEADER(int);
828:   void *ptr;
829:   PetscErrorCode (*userdestroy)(void *);
830: };

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

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

838:   Input Parameter:
839: . ctx - pointer to user-provided data

841:   Level: advanced

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

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

855:   Not Collective

857:   Input Parameter:
858: . obj - the object created with `PetscContainerCreate()`

860:   Output Parameter:
861: . ptr - the pointer value

863:   Level: advanced

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

877: /*@C
878:   PetscContainerSetPointer - Sets the pointer value contained in the container.

880:   Logically Collective

882:   Input Parameters:
883: + obj - the object created with `PetscContainerCreate()`
884: - ptr - the pointer value

886:   Level: advanced

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

900: /*@C
901:   PetscContainerDestroy - Destroys a PETSc container object.

903:   Collective

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

908:   Level: advanced

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

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

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

933:   Logically Collective

935:   Input Parameters:
936: + obj - an object that was created with `PetscContainerCreate()`
937: - des - name of the user destroy function

939:   Level: advanced

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

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

954: PetscClassId PETSC_CONTAINER_CLASSID;

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

959:   Collective

961:   Input Parameter:
962: . comm - MPI communicator that shares the object

964:   Output Parameter:
965: . container - the container created

967:   Level: advanced

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

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

986: /*@
987:   PetscObjectSetFromOptions - Sets generic parameters from user options.

989:   Collective

991:   Input Parameter:
992: . obj - the `PetscObject`

994:   Level: beginner

996:   Note:
997:   We have no generic options at present, so this does nothing

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

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

1011:   Collective

1013:   Input Parameter:
1014: . obj - the `PetscObject`

1016:   Level: advanced

1018:   Note:
1019:   This does nothing at present.

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