Actual source code: destroy.c

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

      7: static PetscErrorCode DestroyComposedData(void ***composed_star, PetscObjectState **state_star, PetscInt *count_star, void **composed, PetscObjectState **state)
      8: {
      9:   void **tmp_star = *composed_star;

     11:   PetscFunctionBegin;
     12:   for (PetscInt i = 0, imax = *count_star; i < imax; ++i) PetscCall(PetscFree(tmp_star[i]));
     13:   PetscCall(PetscFree2(*composed_star, *state_star));
     14:   PetscCall(PetscFree2(*composed, *state));
     15:   *count_star = 0;
     16:   PetscFunctionReturn(PETSC_SUCCESS);
     17: }

     19: PetscErrorCode PetscComposedQuantitiesDestroy(PetscObject obj)
     20: {
     21:   PetscFunctionBegin;
     23:   PetscCall(DestroyComposedData((void ***)&obj->intstarcomposeddata, &obj->intstarcomposedstate, &obj->intstar_idmax, (void **)&obj->intcomposeddata, &obj->intcomposedstate));
     24:   PetscCall(DestroyComposedData((void ***)&obj->realstarcomposeddata, &obj->realstarcomposedstate, &obj->realstar_idmax, (void **)&obj->realcomposeddata, &obj->realcomposedstate));
     25: #if PetscDefined(USE_COMPLEX)
     26:   PetscCall(DestroyComposedData((void ***)&obj->scalarstarcomposeddata, &obj->scalarstarcomposedstate, &obj->scalarstar_idmax, (void **)&obj->scalarcomposeddata, &obj->scalarcomposedstate));
     27: #endif
     28:   PetscFunctionReturn(PETSC_SUCCESS);
     29: }

     31: /*@
     32:   PetscObjectDestroy - Destroys a `PetscObject`, regardless of the type.

     34:   Collective

     36:   Input Parameter:
     37: . obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`\*), for example,
     38:         `PetscObjectDestroy`((`PetscObject`\*)&mat);

     40:   Level: beginner

     42: .seealso: `PetscObject`
     43: @*/
     44: PetscErrorCode PetscObjectDestroy(PetscObject *obj)
     45: {
     46:   PetscFunctionBegin;
     47:   if (!obj || !*obj) PetscFunctionReturn(PETSC_SUCCESS);
     49:   PetscCheck((*obj)->bops->destroy, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This PETSc object of class %s does not have a generic destroy routine", (*obj)->class_name);
     50:   PetscCall((*(*obj)->bops->destroy)(obj));
     51:   PetscFunctionReturn(PETSC_SUCCESS);
     52: }

     54: /*@
     55:   PetscObjectView - Views a `PetscObject` regardless of the type.

     57:   Collective

     59:   Input Parameters:
     60: + obj    - any PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
     61:            `PetscObjectView`((`PetscObject`)mat,`viewer`);
     62: - viewer - any PETSc viewer

     64:   Level: intermediate

     66: .seealso: `PetscObject`, `PetscObjectViewFromOptions()`, `PetscViewer`
     67: @*/
     68: PetscErrorCode PetscObjectView(PetscObject obj, PetscViewer viewer)
     69: {
     70:   PetscFunctionBegin;
     72:   PetscCheck(obj->bops->view, PETSC_COMM_SELF, PETSC_ERR_SUP, "This PETSc object does not have a generic viewer routine");
     73:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(obj->comm, &viewer));

     76:   PetscCall((*obj->bops->view)(obj, viewer));
     77:   PetscFunctionReturn(PETSC_SUCCESS);
     78: }

     80: /*@
     81:   PetscObjectViewFromOptions - Processes command line options to determine if/how a `PetscObject` is to be viewed.

     83:   Collective

     85:   Input Parameters:
     86: + obj        - the object
     87: . bobj       - optional other object that provides prefix (if `NULL` then the prefix in `obj` is used)
     88: - optionname - option string that is used to activate viewing

     90:   Options Database Key:
     91: . -optionname_view [viewertype]:... - option name and values. In actual usage this would be something like `-mat_coarse_view`

     93:   Level: developer

     95:   Notes:
     96:   The argument has the following form
     97: .vb
     98:     type:filename:format:filemode
     99: .ve
    100:   where all parts are optional, but you need to include the colon to access the next part. For example, to read from an HDF5 file, use
    101: .vb
    102:     hdf5:sol.h5::read
    103: .ve

    105: .vb
    106:     If no value is provided ascii:stdout is used
    107:        ascii[:[filename][:[format][:append]]]    defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
    108:                                                   for example ascii::ascii_info prints just the information about the object not all details
    109:                                                   unless :append is given filename opens in write mode, overwriting what was already there
    110:        binary[:[filename][:[format][:append]]]   defaults to the file binaryoutput
    111:        draw[:drawtype[:filename]]                for example, draw:tikz, draw:tikz:figure.tex  or draw:x
    112:        socket[:port]                             defaults to the standard output port
    113:        saws[:communicatorname]                    publishes object to the Scientific Application Webserver (SAWs)
    114: .ve

    116:   This is not called directly but is called by, for example, `MatViewFromOptions()`

    118: .seealso: `PetscObject`, `PetscObjectView()`, `PetscOptionsCreateViewer()`
    119: @*/
    120: PetscErrorCode PetscObjectViewFromOptions(PetscObject obj, PetscObject bobj, const char optionname[])
    121: {
    122:   PetscViewer       viewer;
    123:   PetscBool         flg;
    124:   static PetscBool  incall = PETSC_FALSE;
    125:   PetscViewerFormat format;
    126:   const char       *prefix;

    128:   PetscFunctionBegin;
    131:   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
    132:   incall = PETSC_TRUE;
    133:   prefix = bobj ? bobj->prefix : obj->prefix;
    134:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)obj), obj->options, prefix, optionname, &viewer, &format, &flg));
    135:   if (flg) {
    136:     PetscCall(PetscViewerPushFormat(viewer, format));
    137:     PetscCall(PetscObjectView(obj, viewer));
    138:     PetscCall(PetscViewerFlush(viewer));
    139:     PetscCall(PetscViewerPopFormat(viewer));
    140:     PetscCall(PetscViewerDestroy(&viewer));
    141:   }
    142:   incall = PETSC_FALSE;
    143:   PetscFunctionReturn(PETSC_SUCCESS);
    144: }

    146: /*@
    147:   PetscObjectTypeCompare - Determines whether a PETSc object is of a particular type.

    149:   Not Collective

    151:   Input Parameters:
    152: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
    153:               `PetscObjectTypeCompare`((`PetscObject`)mat);
    154: - type_name - string containing a type name

    156:   Output Parameter:
    157: . same - `PETSC_TRUE` if the type of `obj` and `type_name` are the same or both `NULL`, else `PETSC_FALSE`

    159:   Level: intermediate

    161: .seealso: `PetscObject`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`, `PetscObjectObjectTypeCompare()`
    162: @*/
    163: PetscErrorCode PetscObjectTypeCompare(PetscObject obj, const char type_name[], PetscBool *same)
    164: {
    165:   PetscFunctionBegin;
    166:   PetscAssertPointer(same, 3);
    167:   if (!obj) *same = (PetscBool)!type_name;
    168:   else {
    170:     if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name);
    171:     else {
    172:       PetscAssertPointer(type_name, 2);
    173:       PetscCall(PetscStrcmp(obj->type_name, type_name, same));
    174:     }
    175:   }
    176:   PetscFunctionReturn(PETSC_SUCCESS);
    177: }

    179: /*@
    180:   PetscObjectObjectTypeCompare - Determines whether two PETSc objects are of the same type

    182:   Logically Collective

    184:   Input Parameters:
    185: + obj1 - any PETSc object, for example a `Vec`, `Mat` or `KSP`.
    186: - obj2 - another PETSc object

    188:   Output Parameter:
    189: . same - `PETSC_TRUE` if they are the same or both unset, else `PETSC_FALSE`

    191:   Level: intermediate

    193: .seealso: `PetscObjectTypeCompare()`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`

    195: @*/
    196: PetscErrorCode PetscObjectObjectTypeCompare(PetscObject obj1, PetscObject obj2, PetscBool *same)
    197: {
    198:   PetscFunctionBegin;
    201:   PetscAssertPointer(same, 3);
    202:   PetscCall(PetscStrcmp(obj1->type_name, obj2->type_name, same));
    203:   PetscFunctionReturn(PETSC_SUCCESS);
    204: }

    206: /*@
    207:   PetscObjectBaseTypeCompare - Determines whether a `PetscObject` is of a given base type. For example the base type of `MATSEQAIJPERM` is `MATSEQAIJ`

    209:   Not Collective

    211:   Input Parameters:
    212: + obj       - the object
    213: - type_name - string containing a type name

    215:   Output Parameter:
    216: . same - `PETSC_TRUE` if the object is of the same base type identified by `type_name` or both `NULL`, `PETSC_FALSE` otherwise

    218:   Level: intermediate

    220: .seealso: `PetscObject`, `PetscObjectTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`
    221: @*/
    222: PetscErrorCode PetscObjectBaseTypeCompare(PetscObject obj, const char type_name[], PetscBool *same)
    223: {
    224:   PetscFunctionBegin;
    225:   PetscAssertPointer(same, 3);
    226:   if (!obj) *same = (PetscBool)!type_name;
    227:   else {
    229:     if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name);
    230:     else {
    231:       PetscAssertPointer(type_name, 2);
    232:       PetscCall(PetscStrbeginswith(obj->type_name, type_name, same));
    233:     }
    234:   }
    235:   PetscFunctionReturn(PETSC_SUCCESS);
    236: }

    238: /*@C
    239:   PetscObjectTypeCompareAny - Determines whether a PETSc object is of any of a list of types.

    241:   Not Collective

    243:   Input Parameters:
    244: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`),
    245:               for example, `PetscObjectTypeCompareAny`((`PetscObject`)mat,...);
    246: - type_name - one or more string arguments containing type names, pass the empty string "" as the last argument

    248:   Output Parameter:
    249: . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE`

    251:   Level: intermediate

    253: .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()`
    254: @*/
    255: PetscErrorCode PetscObjectTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...)
    256: {
    257:   va_list Argp;

    259:   PetscFunctionBegin;
    260:   PetscAssertPointer(match, 2);
    261:   *match = PETSC_FALSE;
    262:   if (!obj) PetscFunctionReturn(PETSC_SUCCESS);
    263:   va_start(Argp, type_name);
    264:   while (type_name && type_name[0]) {
    265:     PetscBool found;
    266:     PetscCall(PetscObjectTypeCompare(obj, type_name, &found));
    267:     if (found) {
    268:       *match = PETSC_TRUE;
    269:       break;
    270:     }
    271:     type_name = va_arg(Argp, const char *);
    272:   }
    273:   va_end(Argp);
    274:   PetscFunctionReturn(PETSC_SUCCESS);
    275: }

    277: /*@C
    278:   PetscObjectBaseTypeCompareAny - Determines whether a PETSc object has the base type of any of a list of types.

    280:   Not Collective

    282:   Input Parameters:
    283: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`),
    284:               for example, `PetscObjectBaseTypeCompareAny`((`PetscObject`)mat,...);
    285: - type_name - one or more string arguments containing type names, pass the empty string "" as the last argument

    287:   Output Parameter:
    288: . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE`

    290:   Level: intermediate

    292: .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`
    293: @*/
    294: PetscErrorCode PetscObjectBaseTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...)
    295: {
    296:   va_list Argp;

    298:   PetscFunctionBegin;
    299:   PetscAssertPointer(match, 2);
    300:   *match = PETSC_FALSE;
    301:   va_start(Argp, type_name);
    302:   while (type_name && type_name[0]) {
    303:     PetscBool found;
    304:     PetscCall(PetscObjectBaseTypeCompare(obj, type_name, &found));
    305:     if (found) {
    306:       *match = PETSC_TRUE;
    307:       break;
    308:     }
    309:     type_name = va_arg(Argp, const char *);
    310:   }
    311:   va_end(Argp);
    312:   PetscFunctionReturn(PETSC_SUCCESS);
    313: }

    315: typedef struct {
    316:   PetscErrorCode (*func)(void);
    317: } PetscFinalizeFunction;

    319: typedef struct {
    320:   PetscErrorCode (*func)(void *);
    321:   void *ctx;
    322: } PetscFinalizeFunctionWithCtx;

    324: typedef enum {
    325:   PETSC_FINALIZE_EMPTY,
    326:   PETSC_FINALIZE_OBJECT,
    327:   PETSC_FINALIZE_FUNC,
    328:   PETSC_FINALIZE_FUNC_WITH_CTX
    329: } PetscFinalizeType;

    331: static const char *const PetscFinalizeTypes[] = {"PETSC_FINALIZE_EMPTY", "PETSC_FINALIZE_OBJECT", "PETSC_FINALIZE_FUNC", "PETSC_FINALIZE_FUNC_WITH_CTX", PETSC_NULLPTR};

    333: typedef struct {
    334:   union ThunkUnion
    335:   {
    336:     PetscObject                  obj;
    337:     PetscFinalizeFunction        fn;
    338:     PetscFinalizeFunctionWithCtx fnctx;
    339:   } thunk;
    340:   PetscFinalizeType type;
    341: } PetscFinalizerContainer;

    343: #define PETSC_MAX_REGISTERED_FINALIZERS 256
    344: static int                     reg_count = 0;
    345: static PetscFinalizerContainer regfin[PETSC_MAX_REGISTERED_FINALIZERS];

    347: static PetscErrorCode PetscRunRegisteredFinalizers(void)
    348: {
    349:   PetscFunctionBegin;
    350:   while (reg_count) {
    351:     PetscFinalizerContainer top = regfin[--reg_count];

    353:     regfin[reg_count].type = PETSC_FINALIZE_EMPTY;
    354:     PetscCall(PetscArrayzero(&regfin[reg_count].thunk, 1));
    355:     switch (top.type) {
    356:     case PETSC_FINALIZE_OBJECT:
    357:       PetscCall(PetscObjectDestroy(&top.thunk.obj));
    358:       break;
    359:     case PETSC_FINALIZE_FUNC:
    360:       PetscCall((*top.thunk.fn.func)());
    361:       break;
    362:     case PETSC_FINALIZE_FUNC_WITH_CTX:
    363:       PetscCall((*top.thunk.fnctx.func)(top.thunk.fnctx.ctx));
    364:       break;
    365:     case PETSC_FINALIZE_EMPTY:
    366:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Finalizer at position %d is empty, yet registration count %d != 0", reg_count, reg_count);
    367:       break;
    368:     }
    369:   }
    370:   PetscFunctionReturn(PETSC_SUCCESS);
    371: }

    373: static int PetscFinalizerContainerEqual(const PetscFinalizerContainer *a, const PetscFinalizerContainer *b)
    374: {
    375:   if (a->type != b->type) return 0;
    376:   switch (a->type) {
    377:   case PETSC_FINALIZE_EMPTY:
    378:     break;
    379:   case PETSC_FINALIZE_OBJECT:
    380:     return a->thunk.obj == b->thunk.obj;
    381:   case PETSC_FINALIZE_FUNC:
    382:     return a->thunk.fn.func == b->thunk.fn.func;
    383:   case PETSC_FINALIZE_FUNC_WITH_CTX:
    384:     return a->thunk.fnctx.func == b->thunk.fnctx.func && a->thunk.fnctx.ctx == b->thunk.fnctx.ctx;
    385:   }
    386:   return 1;
    387: }

    389: static PetscErrorCode RegisterFinalizer(PetscFinalizerContainer container)
    390: {
    391:   PetscFunctionBegin;
    392:   PetscAssert(reg_count < (int)PETSC_STATIC_ARRAY_LENGTH(regfin), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "No more room in array, limit %zu, recompile %s with larger value for " PetscStringize(regfin), PETSC_STATIC_ARRAY_LENGTH(regfin), __FILE__);
    393:   PetscAssert(regfin[reg_count].type == PETSC_FINALIZE_EMPTY, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Finalizer type (%s) at position %d is not PETSC_FINALIZE_EMPTY!", PetscFinalizeTypes[regfin[reg_count].type], reg_count);
    394:   if (PetscDefined(USE_DEBUG)) {
    395:     for (int i = 0; i < reg_count; ++i) PetscCheck(!PetscFinalizerContainerEqual(regfin + i, &container), PETSC_COMM_SELF, PETSC_ERR_ORDER, "Finalizer (of type %s) already registered!", PetscFinalizeTypes[container.type]);
    396:   }
    397:   regfin[reg_count++] = container;
    398:   PetscFunctionReturn(PETSC_SUCCESS);
    399: }

    401: /*@
    402:   PetscObjectRegisterDestroy - Registers a PETSc object to be destroyed when
    403:   `PetscFinalize()` is called.

    405:   Logically Collective

    407:   Input Parameter:
    408: . obj - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
    409:         `PetscObjectRegisterDestroy`((`PetscObject`)mat);

    411:   Level: developer

    413:   Note:
    414:   This is used by, for example, `PETSC_VIEWER_XXX_()` routines to free the viewer
    415:   when PETSc ends.

    417: .seealso: `PetscObjectRegisterDestroyAll()`
    418: @*/
    419: PetscErrorCode PetscObjectRegisterDestroy(PetscObject obj)
    420: {
    421:   PetscFinalizerContainer container;

    423:   PetscFunctionBegin;
    425:   container.thunk.obj = obj;
    426:   container.type      = PETSC_FINALIZE_OBJECT;
    427:   PetscCall(RegisterFinalizer(container));
    428:   PetscFunctionReturn(PETSC_SUCCESS);
    429: }

    431: /*@C
    432:   PetscObjectRegisterDestroyAll - Frees all the PETSc objects that have been registered
    433:   with `PetscObjectRegisterDestroy()`. Called by `PetscFinalize()`

    435:   Logically Collective on the individual `PetscObject`s that are being processed

    437:   Level: developer

    439: .seealso: `PetscObjectRegisterDestroy()`
    440: @*/
    441: PetscErrorCode PetscObjectRegisterDestroyAll(void)
    442: {
    443:   PetscFunctionBegin;
    444:   PetscCall(PetscRunRegisteredFinalizers());
    445:   PetscFunctionReturn(PETSC_SUCCESS);
    446: }

    448: /*@C
    449:   PetscRegisterFinalize - Registers a function that is to be called in `PetscFinalize()`

    451:   Not Collective

    453:   Input Parameter:
    454: . f - function to be called

    456:   Level: developer

    458:   Notes:
    459:   This is used by, for example, `DMInitializePackage()` to have `DMFinalizePackage()` called

    461:   Use `PetscObjectRegisterDestroy()` to register the destruction of an object in `PetscFinalize()`

    463: .seealso: `PetscRegisterFinalizeAll()`, `PetscObjectRegisterDestroy()`
    464: @*/
    465: PetscErrorCode PetscRegisterFinalize(PetscErrorCode (*f)(void))
    466: {
    467:   PetscFinalizerContainer container;

    469:   PetscFunctionBegin;
    471:   container.thunk.fn.func = f;
    472:   container.type          = PETSC_FINALIZE_FUNC;
    473:   PetscCall(RegisterFinalizer(container));
    474:   PetscFunctionReturn(PETSC_SUCCESS);
    475: }

    477: /*@C
    478:   PetscRegisterFinalizeAll - Runs all the finalize functions set with `PetscRegisterFinalize()`

    480:   Not Collective unless registered functions are collective

    482:   Level: developer

    484: .seealso: `PetscRegisterFinalize()`, `PetscObjectRegisterDestroyAll()`
    485: @*/
    486: PetscErrorCode PetscRegisterFinalizeAll(void)
    487: {
    488:   PetscFunctionBegin;
    489:   PetscCall(PetscRunRegisteredFinalizers());
    490:   PetscFunctionReturn(PETSC_SUCCESS);
    491: }