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:   On rank 0 of `PETSC_COMM_WORLD` prints the values

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

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

338:   Level: advanced

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
422: - classname - the name of the class

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:   PetscAssertPointer(obj, 2);
437:   *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:         *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 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 context if provided
514: - ctx     - optional context for check function

516:   Level: developer

518: .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectProcessOptionsHandlers()`, `PetscObjectDestroyOptionsHandlers()`,
519:           `PetscObject`
520: @*/
521: PetscErrorCode PetscObjectAddOptionsHandler(PetscObject obj, PetscErrorCode (*handle)(PetscObject, PetscOptionItems *, void *), PetscErrorCode (*destroy)(PetscObject, void *), void *ctx)
522: {
523:   PetscFunctionBegin;
525:   PetscCheck(obj->noptionhandler < PETSC_MAX_OPTIONS_HANDLER, obj->comm, PETSC_ERR_ARG_OUTOFRANGE, "To many options handlers added");
526:   obj->optionhandler[obj->noptionhandler] = handle;
527:   obj->optiondestroy[obj->noptionhandler] = destroy;
528:   obj->optionctx[obj->noptionhandler++]   = ctx;
529:   PetscFunctionReturn(PETSC_SUCCESS);
530: }

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

535:   Not Collective

537:   Input Parameters:
538: + obj                - the PETSc object
539: - PetscOptionsObject - the options context

541:   Level: developer

543: .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectAddOptionsHandler()`, `PetscObjectDestroyOptionsHandlers()`,
544:           `PetscObject`
545: @*/
546: PetscErrorCode PetscObjectProcessOptionsHandlers(PetscObject obj, PetscOptionItems *PetscOptionsObject)
547: {
548:   PetscFunctionBegin;
550:   for (PetscInt i = 0; i < obj->noptionhandler; i++) PetscCall((*obj->optionhandler[i])(obj, PetscOptionsObject, obj->optionctx[i]));
551:   PetscFunctionReturn(PETSC_SUCCESS);
552: }

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

557:   Not Collective

559:   Input Parameter:
560: . obj - the PETSc object

562:   Level: developer

564: .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectAddOptionsHandler()`, `PetscObjectProcessOptionsHandlers()`,
565:           `PetscObject`
566: @*/
567: PetscErrorCode PetscObjectDestroyOptionsHandlers(PetscObject obj)
568: {
569:   PetscFunctionBegin;
571:   for (PetscInt i = 0; i < obj->noptionhandler; i++) {
572:     if (obj->optiondestroy[i]) PetscCall((*obj->optiondestroy[i])(obj, obj->optionctx[i]));
573:   }
574:   obj->noptionhandler = 0;
575:   PetscFunctionReturn(PETSC_SUCCESS);
576: }

578: /*@C
579:   PetscObjectReference - Indicates to any `PetscObject` that it is being
580:   referenced by another `PetscObject`. This increases the reference
581:   count for that object by one.

583:   Logically Collective

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

589:   Level: advanced

591: .seealso: `PetscObjectCompose()`, `PetscObjectDereference()`, `PetscObject`
592: @*/
593: PetscErrorCode PetscObjectReference(PetscObject obj)
594: {
595:   PetscFunctionBegin;
596:   if (!obj) PetscFunctionReturn(PETSC_SUCCESS);
598:   obj->refct++;
599:   PetscFunctionReturn(PETSC_SUCCESS);
600: }

602: /*@C
603:   PetscObjectGetReference - Gets the current reference count for
604:   any PETSc object.

606:   Not Collective

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

612:   Output Parameter:
613: . cnt - the reference count

615:   Level: advanced

617: .seealso: `PetscObjectCompose()`, `PetscObjectDereference()`, `PetscObjectReference()`, `PetscObject`
618: @*/
619: PetscErrorCode PetscObjectGetReference(PetscObject obj, PetscInt *cnt)
620: {
621:   PetscFunctionBegin;
623:   PetscAssertPointer(cnt, 2);
624:   *cnt = obj->refct;
625:   PetscFunctionReturn(PETSC_SUCCESS);
626: }

628: /*@C
629:   PetscObjectDereference - Indicates to any `PetscObject` that it is being
630:   referenced by one less `PetscObject`. This decreases the reference
631:   count for that object by one.

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

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

639:   Level: advanced

641:   Note:
642:   `PetscObjectDestroy()` sets the obj pointer to null after the call, this routine does not.

644: .seealso: `PetscObjectCompose()`, `PetscObjectReference()`, `PetscObjectDestroy()`, `PetscObject`
645: @*/
646: PetscErrorCode PetscObjectDereference(PetscObject obj)
647: {
648:   PetscFunctionBegin;
649:   if (!obj) PetscFunctionReturn(PETSC_SUCCESS);
651:   if (obj->bops->destroy) PetscCall((*obj->bops->destroy)(&obj));
652:   else PetscCheck(--(obj->refct), PETSC_COMM_SELF, PETSC_ERR_SUP, "This PETSc object does not have a generic destroy routine");
653:   PetscFunctionReturn(PETSC_SUCCESS);
654: }

656: /*
657:      The following routines are the versions private to the PETSc object
658:      data structures.
659: */
660: PetscErrorCode PetscObjectRemoveReference(PetscObject obj, const char name[])
661: {
662:   PetscFunctionBegin;
664:   PetscCall(PetscObjectListRemoveReference(&obj->olist, name));
665:   PetscFunctionReturn(PETSC_SUCCESS);
666: }

668: /*@C
669:   PetscObjectCompose - Associates another PETSc object with a given PETSc object.

671:   Not Collective

673:   Input Parameters:
674: + obj  - the PETSc object; this must be cast with (`PetscObject`), for example,
675:          `PetscObjectCompose`((`PetscObject`)mat,...);
676: . name - name associated with the child object
677: - ptr  - the other PETSc object to associate with the PETSc object; this must also be
678:          cast with (`PetscObject`)

680:   Level: advanced

682:   Notes:
683:   The second objects reference count is automatically increased by one when it is
684:   composed.

686:   Replaces any previous object that had the same name.

688:   If ptr is null and name has previously been composed using an object, then that
689:   entry is removed from the obj.

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

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

697: .seealso: `PetscObjectQuery()`, `PetscContainerCreate()`, `PetscObjectComposeFunction()`, `PetscObjectQueryFunction()`, `PetscContainer`,
698:           `PetscContainerSetPointer()`, `PetscObject`
699: @*/
700: PetscErrorCode PetscObjectCompose(PetscObject obj, const char name[], PetscObject ptr)
701: {
702:   PetscFunctionBegin;
704:   PetscAssertPointer(name, 2);
706:   PetscCheck(obj != ptr, PetscObjectComm((PetscObject)obj), PETSC_ERR_SUP, "Cannot compose object with itself");
707:   if (ptr) {
708:     char     *tname;
709:     PetscBool skipreference;

711:     PetscCall(PetscObjectListReverseFind(ptr->olist, obj, &tname, &skipreference));
712:     if (tname) PetscCheck(skipreference, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "An object cannot be composed with an object that was composed with it");
713:   }
714:   PetscCall(PetscObjectListAdd(&obj->olist, name, ptr));
715:   PetscFunctionReturn(PETSC_SUCCESS);
716: }

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

721:   Not Collective

723:   Input Parameters:
724: + obj  - the PETSc object
725:          Thus must be cast with a (`PetscObject`), for example,
726:          `PetscObjectCompose`((`PetscObject`)mat,...);
727: . name - name associated with child object
728: - ptr  - the other PETSc object associated with the PETSc object, this must be
729:          cast with (`PetscObject`*)

731:   Level: advanced

733:   Note:
734:   The reference count of neither object is increased in this call

736: .seealso: `PetscObjectCompose()`, `PetscObjectComposeFunction()`, `PetscObjectQueryFunction()`, `PetscContainer`
737:           `PetscContainerGetPointer()`, `PetscObject`
738: @*/
739: PetscErrorCode PetscObjectQuery(PetscObject obj, const char name[], PetscObject *ptr)
740: {
741:   PetscFunctionBegin;
743:   PetscAssertPointer(name, 2);
744:   PetscAssertPointer(ptr, 3);
745:   PetscCall(PetscObjectListFind(obj->olist, name, ptr));
746:   PetscFunctionReturn(PETSC_SUCCESS);
747: }

749: /*MC
750:   PetscObjectComposeFunction - Associates a function with a given PETSc object.

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

756:   Logically Collective

758:   Input Parameters:
759: + obj  - the PETSc object; this must be cast with a (`PetscObject`), for example,
760:          `PetscObjectCompose`((`PetscObject`)mat,...);
761: . name - name associated with the child function
762: - fptr - function pointer

764:   Level: advanced

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

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

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

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

777: .seealso: `PetscObjectQueryFunction()`, `PetscContainerCreate()` `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscTryMethod()`, `PetscUseMethod()`,
778:           `PetscUseTypeMethod()`, `PetscTryTypeMethod()`, `PetscObject`
779: M*/
780: PetscErrorCode PetscObjectComposeFunction_Private(PetscObject obj, const char name[], void (*fptr)(void))
781: {
782:   PetscFunctionBegin;
784:   PetscAssertPointer(name, 2);
785:   PetscCall(PetscFunctionListAdd(&obj->qlist, name, fptr));
786:   PetscFunctionReturn(PETSC_SUCCESS);
787: }

789: /*MC
790:   PetscObjectQueryFunction - Gets a function associated with a given object.

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

796:   Logically Collective

798:   Input Parameters:
799: + obj  - the PETSc object; this must be cast with (`PetscObject`), for example,
800:          `PetscObjectQueryFunction`((`PetscObject`)ksp,...);
801: - name - name associated with the child function

803:   Output Parameter:
804: . fptr - function pointer

806:   Level: advanced

808: .seealso: `PetscObjectComposeFunction()`, `PetscFunctionListFind()`, `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscObject`
809: M*/
810: PETSC_EXTERN PetscErrorCode PetscObjectQueryFunction_Private(PetscObject obj, const char name[], void (**fptr)(void))
811: {
812:   PetscFunctionBegin;
814:   PetscAssertPointer(name, 2);
815:   PetscCall(PetscFunctionListFind(obj->qlist, name, fptr));
816:   PetscFunctionReturn(PETSC_SUCCESS);
817: }

819: struct _p_PetscContainer {
820:   PETSCHEADER(int);
821:   void *ptr;
822:   PetscErrorCode (*userdestroy)(void *);
823: };

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

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

831:   Input Parameter:
832: . ctx - pointer to user-provided data

834:   Level: advanced

836: .seealso: `PetscContainerDestroy()`, `PetscContainerSetUserDestroy()`, `PetscObject`
837: @*/
838: PetscErrorCode PetscContainerUserDestroyDefault(void *ctx)
839: {
840:   PetscFunctionBegin;
841:   PetscCall(PetscFree(ctx));
842:   PetscFunctionReturn(PETSC_SUCCESS);
843: }

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

848:   Not Collective

850:   Input Parameter:
851: . obj - the object created with `PetscContainerCreate()`

853:   Output Parameter:
854: . ptr - the pointer value

856:   Level: advanced

858: .seealso: `PetscContainerCreate()`, `PetscContainerDestroy()`, `PetscObject`,
859:           `PetscContainerSetPointer()`
860: @*/
861: PetscErrorCode PetscContainerGetPointer(PetscContainer obj, void **ptr)
862: {
863:   PetscFunctionBegin;
865:   PetscAssertPointer(ptr, 2);
866:   *ptr = obj->ptr;
867:   PetscFunctionReturn(PETSC_SUCCESS);
868: }

870: /*@C
871:   PetscContainerSetPointer - Sets the pointer value contained in the container.

873:   Logically Collective

875:   Input Parameters:
876: + obj - the object created with `PetscContainerCreate()`
877: - ptr - the pointer value

879:   Level: advanced

881: .seealso: `PetscContainerCreate()`, `PetscContainerDestroy()`, `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscObject`,
882:           `PetscContainerGetPointer()`
883: @*/
884: PetscErrorCode PetscContainerSetPointer(PetscContainer obj, void *ptr)
885: {
886:   PetscFunctionBegin;
888:   if (ptr) PetscAssertPointer(ptr, 2);
889:   obj->ptr = ptr;
890:   PetscFunctionReturn(PETSC_SUCCESS);
891: }

893: /*@C
894:   PetscContainerDestroy - Destroys a PETSc container object.

896:   Collective

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

901:   Level: advanced

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

907: .seealso: `PetscContainerCreate()`, `PetscContainerSetUserDestroy()`, `PetscObject`
908: @*/
909: PetscErrorCode PetscContainerDestroy(PetscContainer *obj)
910: {
911:   PetscFunctionBegin;
912:   if (!*obj) PetscFunctionReturn(PETSC_SUCCESS);
914:   if (--((PetscObject)(*obj))->refct > 0) {
915:     *obj = NULL;
916:     PetscFunctionReturn(PETSC_SUCCESS);
917:   }
918:   if ((*obj)->userdestroy) PetscCall((*(*obj)->userdestroy)((*obj)->ptr));
919:   PetscCall(PetscHeaderDestroy(obj));
920:   PetscFunctionReturn(PETSC_SUCCESS);
921: }

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

926:   Logically Collective

928:   Input Parameters:
929: + obj - an object that was created with `PetscContainerCreate()`
930: - des - name of the user destroy function

932:   Level: advanced

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

937: .seealso: `PetscContainerDestroy()`, `PetscContainerUserDestroyDefault()`, `PetscMalloc()`, `PetscMalloc1()`, `PetscCalloc()`, `PetscCalloc1()`, `PetscObject`
938: @*/
939: PetscErrorCode PetscContainerSetUserDestroy(PetscContainer obj, PetscErrorCode (*des)(void *))
940: {
941:   PetscFunctionBegin;
943:   obj->userdestroy = des;
944:   PetscFunctionReturn(PETSC_SUCCESS);
945: }

947: PetscClassId PETSC_CONTAINER_CLASSID;

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

952:   Collective

954:   Input Parameter:
955: . comm - MPI communicator that shares the object

957:   Output Parameter:
958: . container - the container created

960:   Level: advanced

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

967: .seealso: `PetscContainerDestroy()`, `PetscContainerSetPointer()`, `PetscContainerGetPointer()`, `PetscObjectCompose()`, `PetscObjectQuery()`,
968:           `PetscContainerSetUserDestroy()`, `PetscObject`
969: @*/
970: PetscErrorCode PetscContainerCreate(MPI_Comm comm, PetscContainer *container)
971: {
972:   PetscFunctionBegin;
973:   PetscAssertPointer(container, 2);
974:   PetscCall(PetscSysInitializePackage());
975:   PetscCall(PetscHeaderCreate(*container, PETSC_CONTAINER_CLASSID, "PetscContainer", "Container", "Sys", comm, PetscContainerDestroy, NULL));
976:   PetscFunctionReturn(PETSC_SUCCESS);
977: }

979: /*@
980:   PetscObjectSetFromOptions - Sets generic parameters from user options.

982:   Collective

984:   Input Parameter:
985: . obj - the `PetscObject`

987:   Level: beginner

989:   Note:
990:   We have no generic options at present, so this does nothing

992: .seealso: `PetscObjectSetOptionsPrefix()`, `PetscObjectGetOptionsPrefix()`, `PetscObject`
993: @*/
994: PetscErrorCode PetscObjectSetFromOptions(PetscObject obj)
995: {
996:   PetscFunctionBegin;
998:   PetscFunctionReturn(PETSC_SUCCESS);
999: }

1001: /*@
1002:   PetscObjectSetUp - Sets up the internal data structures for the later use.

1004:   Collective

1006:   Input Parameter:
1007: . obj - the `PetscObject`

1009:   Level: advanced

1011:   Note:
1012:   This does nothing at present.

1014: .seealso: `PetscObjectDestroy()`, `PetscObject`
1015: @*/
1016: PetscErrorCode PetscObjectSetUp(PetscObject obj)
1017: {
1018:   PetscFunctionBegin;
1020:   PetscFunctionReturn(PETSC_SUCCESS);
1021: }