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: /*@
124:   DMGenerateRegisterDestroy - Frees the list of `DM` mesh generators that were registered by `DMGenerateRegister()` or `DMGenerateRegisterAll()`.

126:   Not Collective

128:   Level: advanced

130: .seealso: `DM`, `DMGenerateRegister()`, `DMGenerateRegisterAll()`
131: @*/
132: PetscErrorCode DMGenerateRegisterDestroy(void)
133: {
134:   DMGeneratorFunctionList next, fl;

136:   PetscFunctionBegin;
137:   next = fl = DMGenerateList;
138:   while (next) {
139:     next = fl ? fl->next : NULL;
140:     if (fl) PetscCall(PetscFree(fl->name));
141:     PetscCall(PetscFree(fl));
142:     fl = next;
143:   }
144:   DMGenerateList              = NULL;
145:   DMGenerateRegisterAllCalled = PETSC_FALSE;
146:   PetscFunctionReturn(PETSC_SUCCESS);
147: }

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

154:   Collective

156:   Input Parameters:
157: + dm    - the pre-adaptation `DM` object
158: - label - label with the flags

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

163:   Level: intermediate

165: .seealso: `DM`, `DMAdaptMetric()`, `DMCoarsen()`, `DMRefine()`
166: @*/
167: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
168: {
169:   DMGeneratorFunctionList fl;
170:   char                    adaptname[PETSC_MAX_PATH_LEN];
171:   const char             *name;
172:   PetscInt                dim;
173:   PetscBool               flg, isForest, found = PETSC_FALSE;

175:   PetscFunctionBegin;
178:   PetscAssertPointer(dmAdapt, 3);
179:   *dmAdapt = NULL;
180:   PetscCall(DMGetDimension(dm, &dim));
181:   PetscCall(DMIsForest(dm, &isForest));
182:   name = isForest ? "forest" : "cellrefiner";
183:   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_adaptor", adaptname, sizeof(adaptname), &flg));
184:   if (flg) name = adaptname;

186:   fl = DMGenerateList;
187:   while (fl) {
188:     PetscCall(PetscStrcmp(fl->name, name, &flg));
189:     if (flg) {
190:       PetscCall((*fl->adapt)(dm, NULL, label, NULL, dmAdapt));
191:       found = PETSC_TRUE;
192:     }
193:     fl = fl->next;
194:   }
195:   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);
196:   if (*dmAdapt) {
197:     PetscCtx ctx;

199:     (*dmAdapt)->prealloc_only = dm->prealloc_only; /* maybe this should go .... */
200:     PetscCall(PetscFree((*dmAdapt)->vectype));
201:     PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*dmAdapt)->vectype));
202:     PetscCall(PetscFree((*dmAdapt)->mattype));
203:     PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*dmAdapt)->mattype));
204:     PetscCall(DMGetApplicationContext(dm, &ctx));
205:     PetscCall(DMSetApplicationContext(*dmAdapt, ctx));
206:   }
207:   PetscFunctionReturn(PETSC_SUCCESS);
208: }

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

213:   Input Parameters:
214: + dm      - The DM object
215: . metric  - The metric to which the mesh is adapted, defined vertex-wise.
216: . 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_".
217: - 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_".

219:   Output Parameter:
220: . dmAdapt - Pointer to the `DM` object containing the adapted mesh

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

225:   Level: advanced

227: .seealso: `DMAdaptLabel()`, `DMCoarsen()`, `DMRefine()`
228: @*/
229: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DMLabel rgLabel, DM *dmAdapt)
230: {
231:   DMGeneratorFunctionList fl;
232:   char                    adaptname[PETSC_MAX_PATH_LEN];
233:   const char             *name;
234:   const char *const       adaptors[3] = {"pragmatic", "mmg", "parmmg"};
235:   PetscInt                dim;
236:   PetscBool               flg, found = PETSC_FALSE;

238:   PetscFunctionBegin;
243:   PetscAssertPointer(dmAdapt, 5);
244:   *dmAdapt = NULL;
245:   PetscCall(DMGetDimension(dm, &dim));
246:   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_adaptor", adaptname, sizeof(adaptname), &flg));

248:   /* Default to Mmg in serial and ParMmg in parallel */
249:   if (flg) name = adaptname;
250:   else {
251:     MPI_Comm    comm;
252:     PetscMPIInt size;

254:     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
255:     PetscCallMPI(MPI_Comm_size(comm, &size));
256:     if (size == 1) name = adaptors[1];
257:     else name = adaptors[2];
258:   }

260:   fl = DMGenerateList;
261:   while (fl) {
262:     PetscCall(PetscStrcmp(fl->name, name, &flg));
263:     if (flg) {
264:       PetscCall((*fl->adapt)(dm, metric, bdLabel, rgLabel, dmAdapt));
265:       found = PETSC_TRUE;
266:     }
267:     fl = fl->next;
268:   }
269:   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);
270:   if (*dmAdapt) {
271:     (*dmAdapt)->prealloc_only = dm->prealloc_only; /* maybe this should go .... */
272:     PetscCall(PetscFree((*dmAdapt)->vectype));
273:     PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*dmAdapt)->vectype));
274:     PetscCall(PetscFree((*dmAdapt)->mattype));
275:     PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*dmAdapt)->mattype));
276:   }
277:   PetscFunctionReturn(PETSC_SUCCESS);
278: }