Actual source code: dmgenerate.c

      1: #include <petsc/private/dmimpl.h>

      3: PETSC_EXTERN PetscErrorCode DMIsForest(DM, PetscBool *);

      5: DMGeneratorFunctionList DMGenerateList              = NULL;
      6: PetscBool               DMGenerateRegisterAllCalled = PETSC_FALSE;

      8: #if defined(PETSC_HAVE_TRIANGLE)
      9: PETSC_EXTERN PetscErrorCode DMPlexGenerate_Triangle(DM, PetscBool, DM *);
     10: PETSC_EXTERN PetscErrorCode DMPlexRefine_Triangle(DM, PetscReal *, DM *);
     11: #endif
     12: #if defined(PETSC_HAVE_TETGEN)
     13: PETSC_EXTERN PetscErrorCode DMPlexGenerate_Tetgen(DM, PetscBool, DM *);
     14: PETSC_EXTERN PetscErrorCode DMPlexRefine_Tetgen(DM, double *, DM *);
     15: #endif
     16: #if defined(PETSC_HAVE_CTETGEN)
     17: PETSC_EXTERN PetscErrorCode DMPlexGenerate_CTetgen(DM, PetscBool, DM *);
     18: PETSC_EXTERN PetscErrorCode DMPlexRefine_CTetgen(DM, double *, DM *);
     19: #endif
     20: #if defined(PETSC_HAVE_PRAGMATIC)
     21: PETSC_EXTERN PetscErrorCode DMAdaptMetric_Pragmatic_Plex(DM, Vec, DMLabel, DMLabel, DM *);
     22: #endif
     23: #if defined(PETSC_HAVE_MMG)
     24: PETSC_EXTERN PetscErrorCode DMAdaptMetric_Mmg_Plex(DM, Vec, DMLabel, DMLabel, DM *);
     25: #endif
     26: #if defined(PETSC_HAVE_PARMMG)
     27: PETSC_EXTERN PetscErrorCode DMAdaptMetric_ParMmg_Plex(DM, Vec, DMLabel, DMLabel, DM *);
     28: #endif
     29: PETSC_EXTERN PetscErrorCode DMPlexTransformAdaptLabel(DM, Vec, DMLabel, DMLabel, DM *);
     30: PETSC_EXTERN PetscErrorCode DMAdaptLabel_Forest(DM, Vec, DMLabel, DMLabel, DM *);

     32: /*@C
     33:   DMGenerateRegisterAll - Registers all of the mesh generation methods in the `DM` package.

     35:   Not Collective

     37:   Level: advanced

     39: .seealso: `DM`, `DMGenerateRegisterDestroy()`
     40: @*/
     41: PetscErrorCode DMGenerateRegisterAll(void)
     42: {
     43:   PetscFunctionBegin;
     44:   if (DMGenerateRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
     45:   DMGenerateRegisterAllCalled = PETSC_TRUE;
     46: #if defined(PETSC_HAVE_TRIANGLE)
     47:   PetscCall(DMGenerateRegister("triangle", DMPlexGenerate_Triangle, DMPlexRefine_Triangle, NULL, 1));
     48: #endif
     49: #if defined(PETSC_HAVE_CTETGEN)
     50:   PetscCall(DMGenerateRegister("ctetgen", DMPlexGenerate_CTetgen, DMPlexRefine_CTetgen, NULL, 2));
     51: #endif
     52: #if defined(PETSC_HAVE_TETGEN)
     53:   PetscCall(DMGenerateRegister("tetgen", DMPlexGenerate_Tetgen, DMPlexRefine_Tetgen, NULL, 2));
     54: #endif
     55: #if defined(PETSC_HAVE_PRAGMATIC)
     56:   PetscCall(DMGenerateRegister("pragmatic", NULL, NULL, DMAdaptMetric_Pragmatic_Plex, -1));
     57: #endif
     58: #if defined(PETSC_HAVE_MMG)
     59:   PetscCall(DMGenerateRegister("mmg", NULL, NULL, DMAdaptMetric_Mmg_Plex, -1));
     60: #endif
     61: #if defined(PETSC_HAVE_PARMMG)
     62:   PetscCall(DMGenerateRegister("parmmg", NULL, NULL, DMAdaptMetric_ParMmg_Plex, -1));
     63: #endif
     64:   PetscCall(DMGenerateRegister("cellrefiner", NULL, NULL, DMPlexTransformAdaptLabel, -1));
     65:   PetscCall(DMGenerateRegister("forest", NULL, NULL, DMAdaptLabel_Forest, -1));
     66:   PetscFunctionReturn(PETSC_SUCCESS);
     67: }

     69: /*@C
     70:   DMGenerateRegister -  Adds a grid generator to `DM`

     72:   Not Collective, No Fortran Support

     74:   Input Parameters:
     75: + sname - name of a new user-defined grid generator
     76: . fnc   - generator function
     77: . rfnc  - refinement function
     78: . alfnc - adapt by label function
     79: - dim   - dimension of boundary of domain

     81:   Example Usage:
     82: .vb
     83:    DMGenerateRegister("my_generator", MyGeneratorCreate, MyGeneratorRefiner, MyGeneratorAdaptor, dim);
     84: .ve

     86:   Then, your generator can be chosen with the procedural interface via
     87: .vb
     88:   DMGenerate(dm, "my_generator",...)
     89: .ve
     90:   or at runtime via the option
     91: .vb
     92:   -dm_generator my_generator
     93: .ve

     95:   Level: advanced

     97:   Note:
     98:   `DMGenerateRegister()` may be called multiple times to add several user-defined generators

    100: .seealso: `DM`, `DMGenerateRegisterAll()`, `DMPlexGenerate()`, `DMGenerateRegisterDestroy()`
    101: @*/
    102: PetscErrorCode DMGenerateRegister(const char sname[], PetscErrorCode (*fnc)(DM, PetscBool, DM *), PetscErrorCode (*rfnc)(DM, PetscReal *, DM *), PetscErrorCode (*alfnc)(DM, Vec, DMLabel, DMLabel, DM *), PetscInt dim)
    103: {
    104:   DMGeneratorFunctionList entry;

    106:   PetscFunctionBegin;
    107:   PetscCall(PetscNew(&entry));
    108:   PetscCall(PetscStrallocpy(sname, &entry->name));
    109:   entry->generate = fnc;
    110:   entry->refine   = rfnc;
    111:   entry->adapt    = alfnc;
    112:   entry->dim      = dim;
    113:   entry->next     = NULL;
    114:   if (!DMGenerateList) DMGenerateList = entry;
    115:   else {
    116:     DMGeneratorFunctionList fl = DMGenerateList;
    117:     while (fl->next) fl = fl->next;
    118:     fl->next = entry;
    119:   }
    120:   PetscFunctionReturn(PETSC_SUCCESS);
    121: }

    123: PetscErrorCode DMGenerateRegisterDestroy(void)
    124: {
    125:   DMGeneratorFunctionList next, fl;

    127:   PetscFunctionBegin;
    128:   next = fl = DMGenerateList;
    129:   while (next) {
    130:     next = fl ? fl->next : NULL;
    131:     if (fl) PetscCall(PetscFree(fl->name));
    132:     PetscCall(PetscFree(fl));
    133:     fl = next;
    134:   }
    135:   DMGenerateList              = NULL;
    136:   DMGenerateRegisterAllCalled = PETSC_FALSE;
    137:   PetscFunctionReturn(PETSC_SUCCESS);
    138: }

    140: /*@
    141:   DMAdaptLabel - Adapt a `DM` based on a `DMLabel` with values interpreted as coarsening and refining flags.  Specific implementations of `DM` maybe have
    142:   specialized flags, but all implementations should accept flag values `DM_ADAPT_DETERMINE`, `DM_ADAPT_KEEP`, `DM_ADAPT_REFINE`, and,
    143:   `DM_ADAPT_COARSEN`.

    145:   Collective

    147:   Input Parameters:
    148: + dm    - the pre-adaptation `DM` object
    149: - label - label with the flags

    151:   Output Parameters:
    152: . dmAdapt - the adapted `DM` object: may be `NULL` if an adapted `DM` could not be produced.

    154:   Level: intermediate

    156: .seealso: `DM`, `DMAdaptMetric()`, `DMCoarsen()`, `DMRefine()`
    157: @*/
    158: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
    159: {
    160:   DMGeneratorFunctionList fl;
    161:   char                    adaptname[PETSC_MAX_PATH_LEN];
    162:   const char             *name;
    163:   PetscInt                dim;
    164:   PetscBool               flg, isForest, found = PETSC_FALSE;

    166:   PetscFunctionBegin;
    169:   PetscAssertPointer(dmAdapt, 3);
    170:   *dmAdapt = NULL;
    171:   PetscCall(DMGetDimension(dm, &dim));
    172:   PetscCall(DMIsForest(dm, &isForest));
    173:   name = isForest ? "forest" : "cellrefiner";
    174:   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_adaptor", adaptname, sizeof(adaptname), &flg));
    175:   if (flg) name = adaptname;

    177:   fl = DMGenerateList;
    178:   while (fl) {
    179:     PetscCall(PetscStrcmp(fl->name, name, &flg));
    180:     if (flg) {
    181:       PetscCall((*fl->adapt)(dm, NULL, label, NULL, dmAdapt));
    182:       found = PETSC_TRUE;
    183:     }
    184:     fl = fl->next;
    185:   }
    186:   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Grid adaptor %s not registered; you may need to add --download-%s to your ./configure options", name, name);
    187:   if (*dmAdapt) {
    188:     void *ctx;

    190:     (*dmAdapt)->prealloc_only = dm->prealloc_only; /* maybe this should go .... */
    191:     PetscCall(PetscFree((*dmAdapt)->vectype));
    192:     PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*dmAdapt)->vectype));
    193:     PetscCall(PetscFree((*dmAdapt)->mattype));
    194:     PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*dmAdapt)->mattype));
    195:     PetscCall(DMGetApplicationContext(dm, &ctx));
    196:     PetscCall(DMSetApplicationContext(*dmAdapt, ctx));
    197:   }
    198:   PetscFunctionReturn(PETSC_SUCCESS);
    199: }

    201: /*@
    202:   DMAdaptMetric - Generates a mesh adapted to the specified metric field.

    204:   Input Parameters:
    205: + dm      - The DM object
    206: . metric  - The metric to which the mesh is adapted, defined vertex-wise.
    207: . bdLabel - Label for boundary tags, which will be preserved in the output mesh. `bdLabel` should be `NULL` if there is no such label, and should be different from "_boundary_".
    208: - rgLabel - Label for cell tags, which will be preserved in the output mesh. `rgLabel` should be `NULL` if there is no such label, and should be different from "_regions_".

    210:   Output Parameter:
    211: . dmAdapt - Pointer to the `DM` object containing the adapted mesh

    213:   Note:
    214:   The label in the adapted mesh will be registered under the name of the input `DMLabel` object

    216:   Level: advanced

    218: .seealso: `DMAdaptLabel()`, `DMCoarsen()`, `DMRefine()`
    219: @*/
    220: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DMLabel rgLabel, DM *dmAdapt)
    221: {
    222:   DMGeneratorFunctionList fl;
    223:   char                    adaptname[PETSC_MAX_PATH_LEN];
    224:   const char             *name;
    225:   const char *const       adaptors[3] = {"pragmatic", "mmg", "parmmg"};
    226:   PetscInt                dim;
    227:   PetscBool               flg, found = PETSC_FALSE;

    229:   PetscFunctionBegin;
    234:   PetscAssertPointer(dmAdapt, 5);
    235:   *dmAdapt = NULL;
    236:   PetscCall(DMGetDimension(dm, &dim));
    237:   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_adaptor", adaptname, sizeof(adaptname), &flg));

    239:   /* Default to Mmg in serial and ParMmg in parallel */
    240:   if (flg) name = adaptname;
    241:   else {
    242:     MPI_Comm    comm;
    243:     PetscMPIInt size;

    245:     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
    246:     PetscCallMPI(MPI_Comm_size(comm, &size));
    247:     if (size == 1) name = adaptors[1];
    248:     else name = adaptors[2];
    249:   }

    251:   fl = DMGenerateList;
    252:   while (fl) {
    253:     PetscCall(PetscStrcmp(fl->name, name, &flg));
    254:     if (flg) {
    255:       PetscCall((*fl->adapt)(dm, metric, bdLabel, rgLabel, dmAdapt));
    256:       found = PETSC_TRUE;
    257:     }
    258:     fl = fl->next;
    259:   }
    260:   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Grid adaptor %s not registered; you may need to add --download-%s to your ./configure options", name, name);
    261:   if (*dmAdapt) {
    262:     (*dmAdapt)->prealloc_only = dm->prealloc_only; /* maybe this should go .... */
    263:     PetscCall(PetscFree((*dmAdapt)->vectype));
    264:     PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*dmAdapt)->vectype));
    265:     PetscCall(PetscFree((*dmAdapt)->mattype));
    266:     PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*dmAdapt)->mattype));
    267:   }
    268:   PetscFunctionReturn(PETSC_SUCCESS);
    269: }