Actual source code: plextransform.c

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

  3: #include <petsc/private/petscfeimpl.h>

  5: PetscClassId DMPLEXTRANSFORM_CLASSID;

  7: PetscFunctionList DMPlexTransformList              = NULL;
  8: PetscBool         DMPlexTransformRegisterAllCalled = PETSC_FALSE;

 10: PetscLogEvent DMPLEXTRANSFORM_SetUp, DMPLEXTRANSFORM_Apply, DMPLEXTRANSFORM_SetConeSizes, DMPLEXTRANSFORM_SetCones, DMPLEXTRANSFORM_CreateSF, DMPLEXTRANSFORM_CreateLabels, DMPLEXTRANSFORM_SetCoordinates;

 12: /* Construct cell type order since we must loop over cell types in the same dimensional order they are stored in the plex if dm != NULL
 13:         OR in standard plex ordering if dm == NULL */
 14: static PetscErrorCode DMPlexCreateCellTypeOrder_Internal(DM dm, PetscInt dim, PetscInt *ctOrder[], PetscInt *ctOrderInv[])
 15: {
 16:   PetscInt *ctO, *ctOInv;
 17:   PetscInt  d, c, off = 0;
 18:   PetscInt  dimOrder[5] = {3, 2, 1, 0, -1};

 20:   PetscFunctionBegin;
 21:   PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctO, DM_NUM_POLYTOPES + 1, &ctOInv));
 22:   if (dm) { // Order the dimensions by their starting location
 23:     PetscInt hStart[4] = {-1, -1, -1, -1};
 24:     for (d = 0; d <= dim; ++d) PetscCall(DMPlexGetDepthStratum(dm, dim - d, &hStart[d], NULL));
 25:     PetscCall(PetscSortIntWithArray(dim + 1, hStart, &dimOrder[3 - dim]));
 26:   } else if (dim > 1) { // Standard plex ordering. dimOrder is in correct order if dim > 1
 27:     off             = 4 - dim;
 28:     dimOrder[off++] = 0;
 29:     for (d = dim - 1; d > 0; --d) dimOrder[off++] = d;
 30:   }

 32:   off = 0;
 33:   for (d = 0; d < 5; ++d) {
 34:     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
 35:       if (c == DM_POLYTOPE_UNKNOWN_CELL || c == DM_POLYTOPE_UNKNOWN_FACE) continue;
 36:       if (DMPolytopeTypeGetDim((DMPolytopeType)c) == dimOrder[d]) ctO[off++] = c;
 37:     }
 38:   }
 39:   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
 40:     if (c == DM_POLYTOPE_UNKNOWN_CELL || c == DM_POLYTOPE_UNKNOWN_FACE) ctO[off++] = c;
 41:   }
 42:   ctO[off++] = DM_NUM_POLYTOPES;
 43:   PetscCheck(off == DM_NUM_POLYTOPES + 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid offset %" PetscInt_FMT " for cell type order", off);

 45:   for (c = 0; c <= DM_NUM_POLYTOPES; ++c) ctOInv[ctO[c]] = c;

 47:   *ctOrder    = ctO;
 48:   *ctOrderInv = ctOInv;
 49:   PetscFunctionReturn(PETSC_SUCCESS);
 50: }

 52: /*@
 53:   DMPlexTransformRegister - Adds a new transform component implementation

 55:   Not Collective

 57:   Input Parameters:
 58: + name        - The name of a new user-defined creation routine
 59: - create_func - The creation routine

 61:   Example Usage:
 62: .vb
 63:   DMPlexTransformRegister("my_transform", MyTransformCreate);
 64: .ve

 66:   Then, your transform type can be chosen with the procedural interface via
 67: .vb
 68:   DMPlexTransformCreate(MPI_Comm, DMPlexTransform *);
 69:   DMPlexTransformSetType(DMPlexTransform, "my_transform");
 70: .ve
 71:   or at runtime via the option
 72: .vb
 73:   -dm_plex_transform_type my_transform
 74: .ve

 76:   Level: advanced

 78:   Note:
 79:   `DMPlexTransformRegister()` may be called multiple times to add several user-defined transforms

 81: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformRegisterAll()`, `DMPlexTransformRegisterDestroy()`
 82: @*/
 83: PetscErrorCode DMPlexTransformRegister(const char name[], PetscErrorCode (*create_func)(DMPlexTransform))
 84: {
 85:   PetscFunctionBegin;
 86:   PetscCall(DMInitializePackage());
 87:   PetscCall(PetscFunctionListAdd(&DMPlexTransformList, name, create_func));
 88:   PetscFunctionReturn(PETSC_SUCCESS);
 89: }

 91: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Filter(DMPlexTransform);
 92: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Regular(DMPlexTransform);
 93: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_ToBox(DMPlexTransform);
 94: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_ToSimplex(DMPlexTransform);
 95: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Alfeld(DMPlexTransform);
 96: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_SBR(DMPlexTransform);
 97: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_BL(DMPlexTransform);
 98: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_1D(DMPlexTransform);
 99: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Extrude(DMPlexTransform);
100: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Cohesive(DMPlexTransform);

102: /*@
103:   DMPlexTransformRegisterAll - Registers all of the transform components in the `DM` package.

105:   Not Collective

107:   Level: advanced

109: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransformType`, `DMRegisterAll()`, `DMPlexTransformRegisterDestroy()`
110: @*/
111: PetscErrorCode DMPlexTransformRegisterAll(void)
112: {
113:   PetscFunctionBegin;
114:   if (DMPlexTransformRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
115:   DMPlexTransformRegisterAllCalled = PETSC_TRUE;

117:   PetscCall(DMPlexTransformRegister(DMPLEXTRANSFORMFILTER, DMPlexTransformCreate_Filter));
118:   PetscCall(DMPlexTransformRegister(DMPLEXREFINEREGULAR, DMPlexTransformCreate_Regular));
119:   PetscCall(DMPlexTransformRegister(DMPLEXREFINETOBOX, DMPlexTransformCreate_ToBox));
120:   PetscCall(DMPlexTransformRegister(DMPLEXREFINETOSIMPLEX, DMPlexTransformCreate_ToSimplex));
121:   PetscCall(DMPlexTransformRegister(DMPLEXREFINEALFELD, DMPlexTransformCreate_Alfeld));
122:   PetscCall(DMPlexTransformRegister(DMPLEXREFINEBOUNDARYLAYER, DMPlexTransformCreate_BL));
123:   PetscCall(DMPlexTransformRegister(DMPLEXREFINESBR, DMPlexTransformCreate_SBR));
124:   PetscCall(DMPlexTransformRegister(DMPLEXREFINE1D, DMPlexTransformCreate_1D));
125:   PetscCall(DMPlexTransformRegister(DMPLEXEXTRUDETYPE, DMPlexTransformCreate_Extrude));
126:   PetscCall(DMPlexTransformRegister(DMPLEXCOHESIVEEXTRUDE, DMPlexTransformCreate_Cohesive));
127:   PetscFunctionReturn(PETSC_SUCCESS);
128: }

130: /*@
131:   DMPlexTransformRegisterDestroy - This function destroys the registered `DMPlexTransformType`. It is called from `PetscFinalize()`.

133:   Not collective

135:   Level: developer

137: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMRegisterAll()`, `DMPlexTransformType`, `PetscInitialize()`
138: @*/
139: PetscErrorCode DMPlexTransformRegisterDestroy(void)
140: {
141:   PetscFunctionBegin;
142:   PetscCall(PetscFunctionListDestroy(&DMPlexTransformList));
143:   DMPlexTransformRegisterAllCalled = PETSC_FALSE;
144:   PetscFunctionReturn(PETSC_SUCCESS);
145: }

147: /*@
148:   DMPlexTransformCreate - Creates an empty transform object. The type can then be set with `DMPlexTransformSetType()`.

150:   Collective

152:   Input Parameter:
153: . comm - The communicator for the transform object

155:   Output Parameter:
156: . tr - The transform object

158:   Level: beginner

160: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformSetType()`, `DMPLEXREFINEREGULAR`, `DMPLEXTRANSFORMFILTER`
161: @*/
162: PetscErrorCode DMPlexTransformCreate(MPI_Comm comm, DMPlexTransform *tr)
163: {
164:   DMPlexTransform t;

166:   PetscFunctionBegin;
167:   PetscAssertPointer(tr, 2);
168:   *tr = NULL;
169:   PetscCall(DMInitializePackage());

171:   PetscCall(PetscHeaderCreate(t, DMPLEXTRANSFORM_CLASSID, "DMPlexTransform", "Mesh Transform", "DMPlexTransform", comm, DMPlexTransformDestroy, DMPlexTransformView));
172:   t->setupcalled = PETSC_FALSE;
173:   t->redFactor   = 2.0;
174:   PetscCall(PetscCalloc2(DM_NUM_POLYTOPES, &t->coordFE, DM_NUM_POLYTOPES, &t->refGeom));
175:   *tr = t;
176:   PetscFunctionReturn(PETSC_SUCCESS);
177: }

179: /*@
180:   DMPlexTransformSetType - Sets the particular implementation for a transform.

182:   Collective

184:   Input Parameters:
185: + tr     - The transform
186: - method - The name of the transform type

188:   Options Database Key:
189: . -dm_plex_transform_type type - Sets the transform type; see `DMPlexTransformType`

191:   Level: intermediate

193: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformGetType()`, `DMPlexTransformCreate()`
194: @*/
195: PetscErrorCode DMPlexTransformSetType(DMPlexTransform tr, DMPlexTransformType method)
196: {
197:   PetscErrorCode (*r)(DMPlexTransform);
198:   PetscBool match;

200:   PetscFunctionBegin;
202:   PetscCall(PetscObjectTypeCompare((PetscObject)tr, method, &match));
203:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

205:   PetscCall(DMPlexTransformRegisterAll());
206:   PetscCall(PetscFunctionListFind(DMPlexTransformList, method, &r));
207:   PetscCheck(r, PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DMPlexTransform type: %s", method);

209:   PetscTryTypeMethod(tr, destroy);
210:   PetscCall(PetscMemzero(tr->ops, sizeof(*tr->ops)));
211:   PetscCall(PetscObjectChangeTypeName((PetscObject)tr, method));
212:   PetscCall((*r)(tr));
213:   PetscFunctionReturn(PETSC_SUCCESS);
214: }

216: /*@
217:   DMPlexTransformGetType - Gets the type name (as a string) from the transform.

219:   Not Collective

221:   Input Parameter:
222: . tr - The `DMPlexTransform`

224:   Output Parameter:
225: . type - The `DMPlexTransformType` name

227:   Level: intermediate

229: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformSetType()`, `DMPlexTransformCreate()`
230: @*/
231: PetscErrorCode DMPlexTransformGetType(DMPlexTransform tr, DMPlexTransformType *type)
232: {
233:   PetscFunctionBegin;
235:   PetscAssertPointer(type, 2);
236:   PetscCall(DMPlexTransformRegisterAll());
237:   *type = ((PetscObject)tr)->type_name;
238:   PetscFunctionReturn(PETSC_SUCCESS);
239: }

241: static PetscErrorCode DMPlexTransformView_Ascii(DMPlexTransform tr, PetscViewer v)
242: {
243:   PetscViewerFormat format;

245:   PetscFunctionBegin;
246:   PetscCall(PetscViewerGetFormat(v, &format));
247:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
248:     const PetscInt *trTypes = NULL;
249:     IS              trIS;
250:     PetscInt        cols = 8;
251:     PetscInt        Nrt  = 8, f, g;
252:     PetscMPIInt     size, rank;

254:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)tr), &rank));
255:     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)tr), &size));
256:     PetscCall(PetscViewerASCIIPushSynchronized(v));
257:     if (tr->trType) PetscCall(DMLabelView(tr->trType, v));
258:     if (size > 1) PetscCall(PetscViewerASCIISynchronizedPrintf(v, "Process: %d\n", rank));
259:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "Source Starts\n"));
260:     for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14s", DMPolytopeTypes[g]));
261:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "\n"));
262:     for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14" PetscInt_FMT, tr->ctStart[f]));
263:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "\n"));
264:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "Target Starts\n"));
265:     for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14s", DMPolytopeTypes[g]));
266:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "\n"));
267:     for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14" PetscInt_FMT, tr->ctStartNew[f]));
268:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "\n"));

270:     if (tr->trType) {
271:       PetscCall(DMLabelGetNumValues(tr->trType, &Nrt));
272:       PetscCall(DMLabelGetValueIS(tr->trType, &trIS));
273:       PetscCall(ISGetIndices(trIS, &trTypes));
274:     }
275:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "Offsets\n"));
276:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "     "));
277:     for (g = 0; g < cols; ++g) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14s", DMPolytopeTypes[g]));
278:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "\n"));
279:     for (f = 0; f < Nrt; ++f) {
280:       PetscCall(PetscViewerASCIISynchronizedPrintf(v, "%2" PetscInt_FMT "  |", trTypes ? trTypes[f] : f));
281:       for (g = 0; g < cols; ++g) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14" PetscInt_FMT, tr->offset[f * DM_NUM_POLYTOPES + g]));
282:       PetscCall(PetscViewerASCIISynchronizedPrintf(v, " |\n"));
283:     }
284:     if (tr->trType) {
285:       PetscCall(ISRestoreIndices(trIS, &trTypes));
286:       PetscCall(ISDestroy(&trIS));
287:     }
288:     PetscCall(PetscViewerFlush(v));
289:   }
290:   PetscFunctionReturn(PETSC_SUCCESS);
291: }

293: /*@
294:   DMPlexTransformView - Views a `DMPlexTransform`

296:   Collective

298:   Input Parameters:
299: + tr - the `DMPlexTransform` object to view
300: - v  - the viewer

302:   Level: beginner

304: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `PetscViewer`, `DMPlexTransformDestroy()`, `DMPlexTransformCreate()`
305: @*/
306: PetscErrorCode DMPlexTransformView(DMPlexTransform tr, PetscViewer v)
307: {
308:   PetscBool isascii;

310:   PetscFunctionBegin;
312:   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)tr), &v));
314:   PetscCheckSameComm(tr, 1, v, 2);
315:   PetscCall(PetscViewerCheckWritable(v));
316:   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)tr, v));
317:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &isascii));
318:   if (isascii) PetscCall(DMPlexTransformView_Ascii(tr, v));
319:   PetscTryTypeMethod(tr, view, v);
320:   PetscFunctionReturn(PETSC_SUCCESS);
321: }

323: /*@
324:   DMPlexTransformSetFromOptions - Sets parameters in a transform from values in the options database

326:   Collective

328:   Input Parameter:
329: . tr - the `DMPlexTransform` object to set options for

331:   Options Database Keys:
332: + -dm_plex_transform_type type               - Set the transform type, e.g. refine_regular
333: . -dm_plex_transform_label_match_strata      - Only label points of the same stratum as the producing point
334: . -dm_plex_transform_label_replica_inc inc   - Increment for the label value to be multiplied by the replica number, so that the new label value is oldValue + r * inc
335: . -dm_plex_transform_active name             - Name for active mesh label
336: - -dm_plex_transform_active_values v0,v1,... - Values in the active label

338:   Level: intermediate

340: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()`
341: @*/
342: PetscErrorCode DMPlexTransformSetFromOptions(DMPlexTransform tr)
343: {
344:   char        typeName[1024], active[PETSC_MAX_PATH_LEN];
345:   const char *defName = DMPLEXREFINEREGULAR;
346:   PetscBool   flg, match;

348:   PetscFunctionBegin;
350:   PetscObjectOptionsBegin((PetscObject)tr);
351:   PetscCall(PetscOptionsFList("-dm_plex_transform_type", "DMPlexTransform", "DMPlexTransformSetType", DMPlexTransformList, defName, typeName, 1024, &flg));
352:   if (flg) PetscCall(DMPlexTransformSetType(tr, typeName));
353:   else if (!((PetscObject)tr)->type_name) PetscCall(DMPlexTransformSetType(tr, defName));
354:   PetscCall(PetscOptionsBool("-dm_plex_transform_label_match_strata", "Only label points of the same stratum as the producing point", "", tr->labelMatchStrata, &match, &flg));
355:   if (flg) PetscCall(DMPlexTransformSetMatchStrata(tr, match));
356:   PetscCall(PetscOptionsInt("-dm_plex_transform_label_replica_inc", "Increment for the label value to be multiplied by the replica number", "", tr->labelReplicaInc, &tr->labelReplicaInc, NULL));
357:   PetscCall(PetscOptionsString("-dm_plex_transform_active", "Name for active mesh label", "DMPlexTransformSetActive", active, active, sizeof(active), &flg));
358:   if (flg) {
359:     DM       dm;
360:     DMLabel  label;
361:     PetscInt values[16];
362:     PetscInt n = 16;

364:     PetscCall(DMPlexTransformGetDM(tr, &dm));
365:     PetscCall(DMGetLabel(dm, active, &label));
366:     PetscCall(PetscOptionsIntArray("-dm_plex_transform_active_values", "The label values to be active", "DMPlexTransformSetActive", values, &n, &flg));
367:     if (flg && n) {
368:       DMLabel newlabel;

370:       PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Active", &newlabel));
371:       for (PetscInt i = 0; i < n; ++i) {
372:         IS is;

374:         PetscCall(DMLabelGetStratumIS(label, values[i], &is));
375:         PetscCall(DMLabelInsertIS(newlabel, is, values[i]));
376:         PetscCall(ISDestroy(&is));
377:       }
378:       PetscCall(DMPlexTransformSetActive(tr, newlabel));
379:       PetscCall(DMLabelDestroy(&newlabel));
380:     } else {
381:       PetscCall(DMPlexTransformSetActive(tr, label));
382:     }
383:   }
384:   PetscTryTypeMethod(tr, setfromoptions, PetscOptionsObject);
385:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
386:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)tr, PetscOptionsObject));
387:   PetscOptionsEnd();
388:   PetscFunctionReturn(PETSC_SUCCESS);
389: }

391: /*@
392:   DMPlexTransformDestroy - Destroys a `DMPlexTransform`

394:   Collective

396:   Input Parameter:
397: . tr - the transform object to destroy

399:   Level: beginner

401: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()`
402: @*/
403: PetscErrorCode DMPlexTransformDestroy(DMPlexTransform *tr)
404: {
405:   PetscInt c;

407:   PetscFunctionBegin;
408:   if (!*tr) PetscFunctionReturn(PETSC_SUCCESS);
410:   if (--((PetscObject)*tr)->refct > 0) {
411:     *tr = NULL;
412:     PetscFunctionReturn(PETSC_SUCCESS);
413:   }

415:   PetscTryTypeMethod(*tr, destroy);
416:   PetscCall(DMDestroy(&(*tr)->dm));
417:   PetscCall(DMLabelDestroy(&(*tr)->active));
418:   PetscCall(DMLabelDestroy(&(*tr)->trType));
419:   PetscCall(PetscFree2((*tr)->ctOrderOld, (*tr)->ctOrderInvOld));
420:   PetscCall(PetscFree2((*tr)->ctOrderNew, (*tr)->ctOrderInvNew));
421:   PetscCall(PetscFree2((*tr)->ctStart, (*tr)->ctStartNew));
422:   PetscCall(PetscFree((*tr)->offset));
423:   PetscCall(PetscFree2((*tr)->depthStart, (*tr)->depthEnd));
424:   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
425:     PetscCall(PetscFEDestroy(&(*tr)->coordFE[c]));
426:     PetscCall(PetscFEGeomDestroy(&(*tr)->refGeom[c]));
427:   }
428:   if ((*tr)->trVerts) {
429:     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
430:       DMPolytopeType *rct;
431:       PetscInt       *rsize, *rcone, *rornt, Nct, n, r;

433:       if (DMPolytopeTypeGetDim((DMPolytopeType)c) > 0 && c != DM_POLYTOPE_UNKNOWN_CELL && c != DM_POLYTOPE_UNKNOWN_FACE) {
434:         PetscCall(DMPlexTransformCellTransform(*tr, (DMPolytopeType)c, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
435:         for (n = 0; n < Nct; ++n) {
436:           if (rct[n] == DM_POLYTOPE_POINT) continue;
437:           for (r = 0; r < rsize[n]; ++r) PetscCall(PetscFree((*tr)->trSubVerts[c][rct[n]][r]));
438:           PetscCall(PetscFree((*tr)->trSubVerts[c][rct[n]]));
439:         }
440:       }
441:       PetscCall(PetscFree((*tr)->trSubVerts[c]));
442:       PetscCall(PetscFree((*tr)->trVerts[c]));
443:     }
444:   }
445:   PetscCall(PetscFree3((*tr)->trNv, (*tr)->trVerts, (*tr)->trSubVerts));
446:   PetscCall(PetscFree2((*tr)->coordFE, (*tr)->refGeom));
447:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
448:   PetscCall(PetscHeaderDestroy(tr));
449:   PetscFunctionReturn(PETSC_SUCCESS);
450: }

452: static PetscErrorCode DMPlexTransformCreateOffset_Internal(DMPlexTransform tr, PetscInt ctOrderOld[], PetscInt ctStart[], PetscInt **offset)
453: {
454:   DMLabel  trType = tr->trType;
455:   PetscInt c, cN, *off;

457:   PetscFunctionBegin;
458:   if (trType) {
459:     DM              dm;
460:     IS              rtIS;
461:     const PetscInt *reftypes;
462:     PetscInt        Nrt;

464:     PetscCall(DMPlexTransformGetDM(tr, &dm));
465:     PetscCall(DMLabelGetNumValues(trType, &Nrt));
466:     PetscCall(DMLabelGetValueIS(trType, &rtIS));
467:     PetscCall(ISGetIndices(rtIS, &reftypes));
468:     PetscCall(PetscCalloc1(Nrt * DM_NUM_POLYTOPES, &off));
469:     for (PetscInt r = 0; r < Nrt; ++r) {
470:       const PetscInt  rt = reftypes[r];
471:       IS              rtIS;
472:       const PetscInt *points;
473:       DMPolytopeType  ct;
474:       PetscInt        np, p;

476:       PetscCall(DMLabelGetStratumIS(trType, rt, &rtIS));
477:       PetscCall(ISGetLocalSize(rtIS, &np));
478:       PetscCall(ISGetIndices(rtIS, &points));
479:       if (!np) continue;
480:       p = points[0];
481:       PetscCall(ISRestoreIndices(rtIS, &points));
482:       PetscCall(ISDestroy(&rtIS));
483:       PetscCall(DMPlexGetCellType(dm, p, &ct));
484:       for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) {
485:         const DMPolytopeType ctNew = (DMPolytopeType)cN;
486:         DMPolytopeType      *rct;
487:         PetscInt            *rsize, *cone, *ornt;
488:         PetscInt             Nct, n, s;

490:         if (DMPolytopeTypeGetDim(ct) < 0 || DMPolytopeTypeGetDim(ctNew) < 0) {
491:           off[r * DM_NUM_POLYTOPES + ctNew] = -1;
492:           break;
493:         }
494:         off[r * DM_NUM_POLYTOPES + ctNew] = 0;
495:         for (s = 0; s <= r; ++s) {
496:           const PetscInt st = reftypes[s];
497:           DMPolytopeType sct;
498:           PetscInt       q, qrt;

500:           PetscCall(DMLabelGetStratumIS(trType, st, &rtIS));
501:           PetscCall(ISGetLocalSize(rtIS, &np));
502:           PetscCall(ISGetIndices(rtIS, &points));
503:           if (!np) continue;
504:           q = points[0];
505:           PetscCall(ISRestoreIndices(rtIS, &points));
506:           PetscCall(ISDestroy(&rtIS));
507:           PetscCall(DMPlexGetCellType(dm, q, &sct));
508:           PetscCall(DMPlexTransformCellTransform(tr, sct, q, &qrt, &Nct, &rct, &rsize, &cone, &ornt));
509:           PetscCheck(st == qrt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Refine type %" PetscInt_FMT " of point %" PetscInt_FMT " does not match predicted type %" PetscInt_FMT, qrt, q, st);
510:           if (st == rt) {
511:             for (n = 0; n < Nct; ++n)
512:               if (rct[n] == ctNew) break;
513:             if (n == Nct) off[r * DM_NUM_POLYTOPES + ctNew] = -1;
514:             break;
515:           }
516:           for (n = 0; n < Nct; ++n) {
517:             if (rct[n] == ctNew) {
518:               PetscInt sn;

520:               PetscCall(DMLabelGetStratumSize(trType, st, &sn));
521:               off[r * DM_NUM_POLYTOPES + ctNew] += sn * rsize[n];
522:             }
523:           }
524:         }
525:       }
526:     }
527:     PetscCall(ISRestoreIndices(rtIS, &reftypes));
528:     PetscCall(ISDestroy(&rtIS));
529:   } else {
530:     PetscCall(PetscCalloc1(DM_NUM_POLYTOPES * DM_NUM_POLYTOPES, &off));
531:     for (c = DM_POLYTOPE_POINT; c < DM_NUM_POLYTOPES; ++c) {
532:       const DMPolytopeType ct = (DMPolytopeType)c;
533:       for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) {
534:         const DMPolytopeType ctNew = (DMPolytopeType)cN;
535:         DMPolytopeType      *rct;
536:         PetscInt            *rsize, *cone, *ornt;
537:         PetscInt             Nct, n, i;

539:         if (DMPolytopeTypeGetDim(ct) < 0 || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE || DMPolytopeTypeGetDim(ctNew) < 0 || ctNew == DM_POLYTOPE_UNKNOWN_CELL || ctNew == DM_POLYTOPE_UNKNOWN_FACE) {
540:           off[ct * DM_NUM_POLYTOPES + ctNew] = -1;
541:           continue;
542:         }
543:         off[ct * DM_NUM_POLYTOPES + ctNew] = 0;
544:         for (i = DM_POLYTOPE_POINT; i < DM_NUM_POLYTOPES; ++i) {
545:           const DMPolytopeType ict  = (DMPolytopeType)ctOrderOld[i];
546:           const DMPolytopeType ictn = (DMPolytopeType)ctOrderOld[i + 1];

548:           PetscCall(DMPlexTransformCellTransform(tr, ict, PETSC_DETERMINE, NULL, &Nct, &rct, &rsize, &cone, &ornt));
549:           if (ict == ct) {
550:             for (n = 0; n < Nct; ++n)
551:               if (rct[n] == ctNew) break;
552:             if (n == Nct) off[ct * DM_NUM_POLYTOPES + ctNew] = -1;
553:             break;
554:           }
555:           for (n = 0; n < Nct; ++n)
556:             if (rct[n] == ctNew) off[ct * DM_NUM_POLYTOPES + ctNew] += (ctStart[ictn] - ctStart[ict]) * rsize[n];
557:         }
558:       }
559:     }
560:   }
561:   *offset = off;
562:   PetscFunctionReturn(PETSC_SUCCESS);
563: }

565: /*@
566:   DMPlexTransformSetUp - Create the tables that drive the transform

568:   Input Parameter:
569: . tr - The `DMPlexTransform` object

571:   Level: intermediate

573: .seealso: [](plex_transform_table), [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
574: @*/
575: PetscErrorCode DMPlexTransformSetUp(DMPlexTransform tr)
576: {
577:   DMPolytopeType ctCell;
578:   DM             dm;
579:   PetscInt       pStart, pEnd, p, c, celldim = 0;

581:   PetscFunctionBegin;
583:   if (tr->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
584:   PetscCall(DMPlexTransformGetDM(tr, &dm));
585:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetUp, tr, dm, 0, 0));
586:   PetscTryTypeMethod(tr, setup);
587:   PetscCall(DMSetSnapToGeomModel(dm, NULL));
588:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));

590:   if (pEnd > pStart) {
591:     // Ignore cells hanging off of embedded surfaces
592:     PetscInt c = pStart;

594:     ctCell = DM_POLYTOPE_FV_GHOST;
595:     while (DMPolytopeTypeGetDim(ctCell) < 0) PetscCall(DMPlexGetCellType(dm, c++, &ctCell));
596:   } else {
597:     PetscInt dim;

599:     PetscCall(DMGetDimension(dm, &dim));
600:     switch (dim) {
601:     case 0:
602:       ctCell = DM_POLYTOPE_POINT;
603:       break;
604:     case 1:
605:       ctCell = DM_POLYTOPE_SEGMENT;
606:       break;
607:     case 2:
608:       ctCell = DM_POLYTOPE_TRIANGLE;
609:       break;
610:     case 3:
611:       ctCell = DM_POLYTOPE_TETRAHEDRON;
612:       break;
613:     default:
614:       ctCell = DM_POLYTOPE_UNKNOWN;
615:     }
616:   }
617:   PetscCall(DMPlexCreateCellTypeOrder_Internal(dm, DMPolytopeTypeGetDim(ctCell), &tr->ctOrderOld, &tr->ctOrderInvOld));
618:   for (p = pStart; p < pEnd; ++p) {
619:     DMPolytopeType  ct;
620:     DMPolytopeType *rct;
621:     PetscInt       *rsize, *cone, *ornt;
622:     PetscInt        Nct;

624:     PetscCall(DMPlexGetCellType(dm, p, &ct));
625:     PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell type for point %" PetscInt_FMT, p);
626:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt));
627:     for (PetscInt n = 0; n < Nct; ++n) celldim = PetscMax(celldim, DMPolytopeTypeGetDim(rct[n]));
628:   }
629:   PetscCall(DMPlexCreateCellTypeOrder_Internal(NULL, celldim, &tr->ctOrderNew, &tr->ctOrderInvNew));
630:   /* Construct sizes and offsets for each cell type */
631:   if (!tr->ctStart) {
632:     PetscInt *ctS, *ctSN, *ctC, *ctCN;

634:     PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctS, DM_NUM_POLYTOPES + 1, &ctSN));
635:     PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctC, DM_NUM_POLYTOPES + 1, &ctCN));
636:     for (p = pStart; p < pEnd; ++p) {
637:       DMPolytopeType  ct;
638:       DMPolytopeType *rct;
639:       PetscInt       *rsize, *cone, *ornt;
640:       PetscInt        Nct;

642:       PetscCall(DMPlexGetCellType(dm, p, &ct));
643:       PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell type for point %" PetscInt_FMT, p);
644:       ++ctC[ct];
645:       PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt));
646:       for (PetscInt n = 0; n < Nct; ++n) ctCN[rct[n]] += rsize[n];
647:     }
648:     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
649:       const PetscInt cto  = tr->ctOrderOld[c];
650:       const PetscInt cton = tr->ctOrderOld[c + 1];
651:       const PetscInt ctn  = tr->ctOrderNew[c];
652:       const PetscInt ctnn = tr->ctOrderNew[c + 1];

654:       ctS[cton]  = ctS[cto] + ctC[cto];
655:       ctSN[ctnn] = ctSN[ctn] + ctCN[ctn];
656:     }
657:     PetscCall(PetscFree2(ctC, ctCN));
658:     tr->ctStart    = ctS;
659:     tr->ctStartNew = ctSN;
660:   }
661:   PetscCall(DMPlexTransformCreateOffset_Internal(tr, tr->ctOrderOld, tr->ctStart, &tr->offset));
662:   // Compute depth information
663:   tr->depth = -1;
664:   for (c = 0; c < DM_NUM_POLYTOPES; ++c)
665:     if (tr->ctStartNew[tr->ctOrderNew[c + 1]] > tr->ctStartNew[tr->ctOrderNew[c]]) tr->depth = PetscMax(tr->depth, DMPolytopeTypeGetDim((DMPolytopeType)tr->ctOrderNew[c]));
666:   PetscCall(PetscMalloc2(tr->depth + 1, &tr->depthStart, tr->depth + 1, &tr->depthEnd));
667:   for (PetscInt d = 0; d <= tr->depth; ++d) {
668:     tr->depthStart[d] = PETSC_INT_MAX;
669:     tr->depthEnd[d]   = -1;
670:   }
671:   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
672:     const PetscInt dep = DMPolytopeTypeGetDim((DMPolytopeType)tr->ctOrderNew[c]);

674:     if (tr->ctStartNew[tr->ctOrderNew[c + 1]] <= tr->ctStartNew[tr->ctOrderNew[c]]) continue;
675:     tr->depthStart[dep] = PetscMin(tr->depthStart[dep], tr->ctStartNew[tr->ctOrderNew[c]]);
676:     tr->depthEnd[dep]   = PetscMax(tr->depthEnd[dep], tr->ctStartNew[tr->ctOrderNew[c + 1]]);
677:   }
678:   tr->setupcalled = PETSC_TRUE;
679:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetUp, tr, dm, 0, 0));
680:   PetscFunctionReturn(PETSC_SUCCESS);
681: }

683: /*@
684:   DMPlexTransformGetDM - Get the base `DM` for the transform

686:   Input Parameter:
687: . tr - The `DMPlexTransform` object

689:   Output Parameter:
690: . dm - The original `DM` which will be transformed

692:   Level: intermediate

694: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetDM()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
695: @*/
696: PetscErrorCode DMPlexTransformGetDM(DMPlexTransform tr, DM *dm)
697: {
698:   PetscFunctionBegin;
700:   PetscAssertPointer(dm, 2);
701:   *dm = tr->dm;
702:   PetscFunctionReturn(PETSC_SUCCESS);
703: }

705: /*@
706:   DMPlexTransformSetDM - Set the base `DM` for the transform

708:   Input Parameters:
709: + tr - The `DMPlexTransform` object
710: - dm - The original `DM` which will be transformed

712:   Level: intermediate

714:   Note:
715:   The user does not typically call this, as it is called by `DMPlexTransformApply()`.

717: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetDM()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
718: @*/
719: PetscErrorCode DMPlexTransformSetDM(DMPlexTransform tr, DM dm)
720: {
721:   PetscFunctionBegin;
723:   if (dm) {
725:     PetscCall(PetscObjectReference((PetscObject)dm));
726:   }
727:   PetscCall(DMDestroy(&tr->dm));
728:   tr->dm = dm;
729:   PetscFunctionReturn(PETSC_SUCCESS);
730: }

732: /*@
733:   DMPlexTransformGetActive - Get the `DMLabel` marking the active points for the transform

735:   Input Parameter:
736: . tr - The `DMPlexTransform` object

738:   Output Parameter:
739: . active - The `DMLabel` indicating which points will be transformed

741:   Level: intermediate

743: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
744: @*/
745: PetscErrorCode DMPlexTransformGetActive(DMPlexTransform tr, DMLabel *active)
746: {
747:   PetscFunctionBegin;
749:   PetscAssertPointer(active, 2);
750:   *active = tr->active;
751:   PetscFunctionReturn(PETSC_SUCCESS);
752: }

754: /*@
755:   DMPlexTransformSetActive - Set the `DMLabel` marking the active points for the transform

757:   Input Parameters:
758: + tr     - The `DMPlexTransform` object
759: - active - The `DMLabel` indicating which points will be transformed

761:   Level: intermediate

763:   Note:
764:   This only applies to transforms listed in [](plex_transform_table) that operate on a subset of the mesh.

766: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
767: @*/
768: PetscErrorCode DMPlexTransformSetActive(DMPlexTransform tr, DMLabel active)
769: {
770:   PetscFunctionBegin;
773:   PetscCall(PetscObjectReference((PetscObject)active));
774:   PetscCall(DMLabelDestroy(&tr->active));
775:   tr->active = active;
776:   PetscFunctionReturn(PETSC_SUCCESS);
777: }

779: /*@
780:   DMPlexTransformGetTransformTypes - Get the `DMLabel` marking the transform type of each point for the transform

782:   Input Parameter:
783: . tr - The `DMPlexTransform` object

785:   Output Parameter:
786: . trType - The `DMLabel` indicating the transform type for each point

788:   Level: intermediate

790: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexSetTransformType()`, `DMPlexTransformGetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
791: @*/
792: PetscErrorCode DMPlexTransformGetTransformTypes(DMPlexTransform tr, DMLabel *trType)
793: {
794:   PetscFunctionBegin;
796:   PetscAssertPointer(trType, 2);
797:   *trType = tr->trType;
798:   PetscFunctionReturn(PETSC_SUCCESS);
799: }

801: /*@
802:   DMPlexTransformSetTransformTypes - Set the `DMLabel` marking the transform type of each point for the transform

804:   Input Parameters:
805: + tr     - The `DMPlexTransform` object
806: - trType - The original `DM` which will be transformed

808:   Level: intermediate

810: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetTransformTypes()`, `DMPlexTransformGetActive())`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
811: @*/
812: PetscErrorCode DMPlexTransformSetTransformTypes(DMPlexTransform tr, DMLabel trType)
813: {
814:   PetscFunctionBegin;
817:   PetscCall(PetscObjectReference((PetscObject)trType));
818:   PetscCall(DMLabelDestroy(&tr->trType));
819:   tr->trType = trType;
820:   PetscFunctionReturn(PETSC_SUCCESS);
821: }

823: static PetscErrorCode DMPlexTransformGetCoordinateFE(DMPlexTransform tr, DMPolytopeType ct, PetscFE *fe)
824: {
825:   PetscFunctionBegin;
826:   if (!tr->coordFE[ct]) {
827:     PetscInt dim, cdim;

829:     dim = DMPolytopeTypeGetDim(ct);
830:     PetscCall(DMGetCoordinateDim(tr->dm, &cdim));
831:     PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, cdim, ct, 1, PETSC_DETERMINE, &tr->coordFE[ct]));
832:     {
833:       PetscDualSpace  dsp;
834:       PetscQuadrature quad;
835:       DM              K;
836:       PetscFEGeom    *cg;
837:       PetscScalar    *Xq;
838:       PetscReal      *xq, *wq;
839:       PetscInt        Nq;

841:       PetscCall(DMPlexTransformGetCellVertices(tr, ct, &Nq, &Xq));
842:       PetscCall(PetscMalloc1(Nq * cdim, &xq));
843:       for (PetscInt q = 0; q < Nq * cdim; ++q) xq[q] = PetscRealPart(Xq[q]);
844:       PetscCall(PetscMalloc1(Nq, &wq));
845:       for (PetscInt q = 0; q < Nq; ++q) wq[q] = 1.0;
846:       PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
847:       PetscCall(PetscQuadratureSetData(quad, dim, 1, Nq, xq, wq));
848:       PetscCall(PetscFESetQuadrature(tr->coordFE[ct], quad));

850:       PetscCall(PetscFEGetDualSpace(tr->coordFE[ct], &dsp));
851:       PetscCall(PetscDualSpaceGetDM(dsp, &K));
852:       PetscCall(PetscFEGeomCreate(quad, 1, cdim, PETSC_FEGEOM_BASIC, &tr->refGeom[ct]));
853:       cg = tr->refGeom[ct];
854:       PetscCall(DMPlexComputeCellGeometryFEM(K, 0, NULL, cg->v, cg->J, cg->invJ, cg->detJ));
855:       PetscCall(PetscQuadratureDestroy(&quad));
856:     }
857:   }
858:   *fe = tr->coordFE[ct];
859:   PetscFunctionReturn(PETSC_SUCCESS);
860: }

862: PetscErrorCode DMPlexTransformSetDimensions_Internal(DMPlexTransform tr, DM dm, DM tdm)
863: {
864:   PetscInt dim, cdim;

866:   PetscFunctionBegin;
867:   PetscCall(DMGetDimension(dm, &dim));
868:   PetscCall(DMSetDimension(tdm, dim));
869:   PetscCall(DMGetCoordinateDim(dm, &cdim));
870:   PetscCall(DMSetCoordinateDim(tdm, cdim));
871:   PetscFunctionReturn(PETSC_SUCCESS);
872: }

874: /*@
875:   DMPlexTransformSetDimensions - Set the dimensions for the transformed `DM`

877:   Input Parameters:
878: + tr - The `DMPlexTransform` object
879: - dm - The original `DM`

881:   Output Parameter:
882: . trdm - The transformed `DM`

884:   Level: advanced

886: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
887: @*/
888: PetscErrorCode DMPlexTransformSetDimensions(DMPlexTransform tr, DM dm, DM trdm)
889: {
890:   PetscFunctionBegin;
891:   PetscUseTypeMethod(tr, setdimensions, dm, trdm);
892:   PetscFunctionReturn(PETSC_SUCCESS);
893: }

895: /*@
896:   DMPlexTransformGetChart - Get the chart `[pStart, pEnd)` for the points produced by the transform

898:   Not Collective

900:   Input Parameter:
901: . tr - The `DMPlexTransform`

903:   Output Parameters:
904: + pStart - The first point in the transformed mesh, or `NULL` if not needed
905: - pEnd   - One past the last point in the transformed mesh, or `NULL` if not needed

907:   Level: developer

909: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformGetCellType()`, `DMPlexTransformGetCellTypeStratum()`
910: @*/
911: PetscErrorCode DMPlexTransformGetChart(DMPlexTransform tr, PetscInt *pStart, PetscInt *pEnd)
912: {
913:   PetscFunctionBegin;
914:   if (pStart) *pStart = 0;
915:   if (pEnd) *pEnd = tr->ctStartNew[tr->ctOrderNew[DM_NUM_POLYTOPES]];
916:   PetscFunctionReturn(PETSC_SUCCESS);
917: }

919: /*@
920:   DMPlexTransformGetCellType - Return the cell type for a point in the transformed mesh

922:   Not Collective

924:   Input Parameters:
925: + tr   - The `DMPlexTransform`
926: - cell - The point number in the transformed mesh

928:   Output Parameter:
929: . celltype - The `DMPolytopeType` of the point

931:   Level: developer

933: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetChart()`, `DMPlexTransformGetCellTypeStratum()`
934: @*/
935: PetscErrorCode DMPlexTransformGetCellType(DMPlexTransform tr, PetscInt cell, DMPolytopeType *celltype)
936: {
937:   PetscInt ctNew;

939:   PetscFunctionBegin;
941:   PetscAssertPointer(celltype, 3);
942:   /* TODO Can do bisection since everything is sorted */
943:   for (ctNew = DM_POLYTOPE_POINT; ctNew < DM_NUM_POLYTOPES; ++ctNew) {
944:     PetscInt ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]];

946:     if (cell >= ctSN && cell < ctEN) break;
947:   }
948:   PetscCheck(ctNew < DM_NUM_POLYTOPES, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " cannot be located in the transformed mesh", cell);
949:   *celltype = (DMPolytopeType)ctNew;
950:   PetscFunctionReturn(PETSC_SUCCESS);
951: }

953: /*@
954:   DMPlexTransformGetCellTypeStratum - Return the point range for a given cell type in the transformed mesh

956:   Not Collective

958:   Input Parameters:
959: + tr       - The `DMPlexTransform`
960: - celltype - The `DMPolytopeType` of the requested stratum

962:   Output Parameters:
963: + start - The first point of the stratum, or `NULL` if not needed
964: - end   - One past the last point of the stratum, or `NULL` if not needed

966:   Level: developer

968: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetCellType()`, `DMPlexTransformGetChart()`, `DMPlexGetDepthStratum()`
969: @*/
970: PetscErrorCode DMPlexTransformGetCellTypeStratum(DMPlexTransform tr, DMPolytopeType celltype, PetscInt *start, PetscInt *end)
971: {
972:   PetscFunctionBegin;
974:   if (start) *start = tr->ctStartNew[celltype];
975:   if (end) *end = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[celltype] + 1]];
976:   PetscFunctionReturn(PETSC_SUCCESS);
977: }

979: /*@
980:   DMPlexTransformGetDepth - Return the topological depth of the transformed mesh

982:   Not Collective

984:   Input Parameter:
985: . tr - The `DMPlexTransform`

987:   Output Parameter:
988: . depth - The depth of the transformed mesh

990:   Level: developer

992: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetDepthStratum()`, `DMPlexGetDepth()`
993: @*/
994: PetscErrorCode DMPlexTransformGetDepth(DMPlexTransform tr, PetscInt *depth)
995: {
996:   PetscFunctionBegin;
998:   *depth = tr->depth;
999:   PetscFunctionReturn(PETSC_SUCCESS);
1000: }

1002: /*@
1003:   DMPlexTransformGetDepthStratum - Return the point range for a given depth in the transformed mesh

1005:   Not Collective

1007:   Input Parameters:
1008: + tr    - The `DMPlexTransform`
1009: - depth - The requested depth in the transformed mesh

1011:   Output Parameters:
1012: + start - The first point at the given depth, or `NULL` if not needed
1013: - end   - One past the last point at the given depth, or `NULL` if not needed

1015:   Level: developer

1017: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetDepth()`, `DMPlexGetDepthStratum()`
1018: @*/
1019: PetscErrorCode DMPlexTransformGetDepthStratum(DMPlexTransform tr, PetscInt depth, PetscInt *start, PetscInt *end)
1020: {
1021:   PetscFunctionBegin;
1023:   if (start) *start = tr->depthStart[depth];
1024:   if (end) *end = tr->depthEnd[depth];
1025:   PetscFunctionReturn(PETSC_SUCCESS);
1026: }

1028: /*@
1029:   DMPlexTransformGetMatchStrata - Get the flag which determines what points get added to the transformed labels

1031:   Not Collective

1033:   Input Parameter:
1034: . tr - The `DMPlexTransform`

1036:   Output Parameter:
1037: . match - If `PETSC_TRUE`, only add produced points at the same stratum as the original point to new labels

1039:   Level: intermediate

1041: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetMatchStrata()`, `DMPlexGetPointDepth()`
1042: @*/
1043: PetscErrorCode DMPlexTransformGetMatchStrata(DMPlexTransform tr, PetscBool *match)
1044: {
1045:   PetscFunctionBegin;
1047:   PetscAssertPointer(match, 2);
1048:   *match = tr->labelMatchStrata;
1049:   PetscFunctionReturn(PETSC_SUCCESS);
1050: }

1052: /*@
1053:   DMPlexTransformSetMatchStrata - Set the flag which determines what points get added to the transformed labels

1055:   Not Collective

1057:   Input Parameters:
1058: + tr    - The `DMPlexTransform`
1059: - match - If `PETSC_TRUE`, only add produced points at the same stratum as the original point to new labels

1061:   Level: intermediate

1063: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetMatchStrata()`, `DMPlexGetPointDepth()`
1064: @*/
1065: PetscErrorCode DMPlexTransformSetMatchStrata(DMPlexTransform tr, PetscBool match)
1066: {
1067:   PetscFunctionBegin;
1069:   tr->labelMatchStrata = match;
1070:   PetscFunctionReturn(PETSC_SUCCESS);
1071: }

1073: /*@
1074:   DMPlexTransformCheck - Verify that the given `DM`, produced by this `DMPlexTransform`, is valid

1076:   Input Parameters:
1077: + tr - The `DMPlexTransform` object
1078: - dm - The `DM` to check

1080:   Level: advanced

1082: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
1083: @*/
1084: PetscErrorCode DMPlexTransformCheck(DMPlexTransform tr, DM dm)
1085: {
1086:   PetscFunctionBegin;
1087:   PetscTryTypeMethod(tr, check, dm);
1088:   PetscFunctionReturn(PETSC_SUCCESS);
1089: }

1091: /*@
1092:   DMPlexTransformGetTargetPoint - Get the number of a point in the transformed mesh based on information from the original mesh.

1094:   Not Collective

1096:   Input Parameters:
1097: + tr    - The `DMPlexTransform`
1098: . ct    - The type of the original point which produces the new point
1099: . ctNew - The type of the new point
1100: . p     - The original point which produces the new point
1101: - r     - The replica number of the new point, meaning it is the rth point of type `ctNew` produced from `p`

1103:   Output Parameter:
1104: . pNew - The new point number

1106:   Level: developer

1108: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSourcePoint()`, `DMPlexTransformCellTransform()`
1109: @*/
1110: PetscErrorCode DMPlexTransformGetTargetPoint(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType ctNew, PetscInt p, PetscInt r, PetscInt *pNew)
1111: {
1112:   DMPolytopeType *rct;
1113:   PetscInt       *rsize, *cone, *ornt;
1114:   PetscInt        rt, Nct, n, off, rp;
1115:   DMLabel         trType = tr->trType;
1116:   PetscInt        ctS = tr->ctStart[ct], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ct] + 1]];
1117:   PetscInt        ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]];
1118:   PetscInt        newp = ctSN, cind;

1120:   PetscFunctionBeginHot;
1121:   PetscCheck(p >= ctS && p < ctE, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " is not a %s [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, DMPolytopeTypes[ct], ctS, ctE);
1122:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, &rt, &Nct, &rct, &rsize, &cone, &ornt));
1123:   if (trType) {
1124:     PetscCall(DMLabelGetValueIndex(trType, rt, &cind));
1125:     PetscCall(DMLabelGetStratumPointIndex(trType, rt, p, &rp));
1126:     PetscCheck(rp >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell type %s point %" PetscInt_FMT " does not have refine type %" PetscInt_FMT, DMPolytopeTypes[ct], p, rt);
1127:   } else {
1128:     cind = ct;
1129:     rp   = p - ctS;
1130:   }
1131:   off = tr->offset[cind * DM_NUM_POLYTOPES + ctNew];
1132:   PetscCheck(off >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell type %s (%" PetscInt_FMT ") of point %" PetscInt_FMT " does not produce type %s for transform %s", DMPolytopeTypes[ct], rt, p, DMPolytopeTypes[ctNew], tr->hdr.type_name);
1133:   newp += off;
1134:   for (n = 0; n < Nct; ++n) {
1135:     if (rct[n] == ctNew) {
1136:       PetscCheck(!rsize[n] || r < rsize[n], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number %" PetscInt_FMT " for point %" PetscInt_FMT " should be in [0, %" PetscInt_FMT ") for subcell type %s in cell type %s", r, p, rsize[n], DMPolytopeTypes[rct[n]], DMPolytopeTypes[ct]);
1137:       newp += rp * rsize[n] + r;
1138:       if (!(newp >= ctSN && newp <= ctEN)) {
1139:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "Problem with point %" PetscInt_FMT " %s replica %" PetscInt_FMT "\n", p, DMPolytopeTypes[ct], r));
1140:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  n %" PetscInt_FMT " rsize %" PetscInt_FMT " rt %" PetscInt_FMT " cind %" PetscInt_FMT " rp %" PetscInt_FMT "\n", n, rsize[n], rt, cind, rp));
1141:       }
1142:       break;
1143:     }
1144:   }

1146:   PetscCheck(newp >= ctSN && newp < ctEN, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New point %" PetscInt_FMT " is not a %s [%" PetscInt_FMT ", %" PetscInt_FMT ")", newp, DMPolytopeTypes[ctNew], ctSN, ctEN);
1147:   *pNew = newp;
1148:   PetscFunctionReturn(PETSC_SUCCESS);
1149: }

1151: /*@
1152:   DMPlexTransformGetSourcePoint - Get the number of a point in the original mesh based on information from the transformed mesh.

1154:   Not Collective

1156:   Input Parameters:
1157: + tr   - The `DMPlexTransform`
1158: - pNew - The new point number

1160:   Output Parameters:
1161: + ct    - The type of the original point which produces the new point
1162: . ctNew - The type of the new point
1163: . p     - The original point which produces the new point
1164: - r     - The replica number of the new point, meaning it is the rth point of type ctNew produced from p

1166:   Level: developer

1168: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetTargetPoint()`, `DMPlexTransformCellTransform()`
1169: @*/
1170: PetscErrorCode DMPlexTransformGetSourcePoint(DMPlexTransform tr, PetscInt pNew, DMPolytopeType *ct, DMPolytopeType *ctNew, PetscInt *p, PetscInt *r)
1171: {
1172:   DMLabel         trType = tr->trType;
1173:   DMPolytopeType *rct, ctN;
1174:   PetscInt       *rsize, *cone, *ornt;
1175:   PetscInt        rt = -1, rtTmp, Nct, n, rp = 0, rO = 0, pO;
1176:   PetscInt        offset = -1, ctS, ctE, ctO = 0, ctTmp, rtS;

1178:   PetscFunctionBegin;
1179:   PetscCall(DMPlexTransformGetCellType(tr, pNew, &ctN));
1180:   if (trType) {
1181:     DM              dm;
1182:     IS              rtIS;
1183:     const PetscInt *reftypes;
1184:     PetscInt        Nrt, r, rtStart;

1186:     PetscCall(DMPlexTransformGetDM(tr, &dm));
1187:     PetscCall(DMLabelGetNumValues(trType, &Nrt));
1188:     PetscCall(DMLabelGetValueIS(trType, &rtIS));
1189:     PetscCall(ISGetIndices(rtIS, &reftypes));
1190:     for (r = 0; r < Nrt; ++r) {
1191:       const PetscInt off = tr->offset[r * DM_NUM_POLYTOPES + ctN];

1193:       if (tr->ctStartNew[ctN] + off > pNew) continue;
1194:       /* Check that any of this refinement type exist */
1195:       /* TODO Actually keep track of the number produced here instead */
1196:       if (off > offset) {
1197:         rt     = reftypes[r];
1198:         offset = off;
1199:       }
1200:     }
1201:     PetscCall(ISRestoreIndices(rtIS, &reftypes));
1202:     PetscCall(ISDestroy(&rtIS));
1203:     PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew);
1204:     /* TODO Map refinement types to cell types */
1205:     PetscCall(DMLabelGetStratumBounds(trType, rt, &rtStart, NULL));
1206:     PetscCheck(rtStart >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Refinement type %" PetscInt_FMT " has no source points", rt);
1207:     for (ctO = 0; ctO < DM_NUM_POLYTOPES; ++ctO) {
1208:       PetscInt ctS = tr->ctStart[ctO], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]];

1210:       if ((rtStart >= ctS) && (rtStart < ctE)) break;
1211:     }
1212:     PetscCheck(ctO != DM_NUM_POLYTOPES, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not determine a cell type for refinement type %" PetscInt_FMT, rt);
1213:   } else {
1214:     for (ctTmp = 0; ctTmp < DM_NUM_POLYTOPES; ++ctTmp) {
1215:       const PetscInt off = tr->offset[ctTmp * DM_NUM_POLYTOPES + ctN];

1217:       if (tr->ctStartNew[ctN] + off > pNew) continue;
1218:       if (tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctTmp] + 1]] <= tr->ctStart[ctTmp]) continue;
1219:       /* TODO Actually keep track of the number produced here instead */
1220:       if (off > offset) {
1221:         ctO    = ctTmp;
1222:         offset = off;
1223:       }
1224:     }
1225:     rt = -1;
1226:     PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew);
1227:   }
1228:   ctS = tr->ctStart[ctO];
1229:   ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]];
1230:   if (trType) {
1231:     for (rtS = ctS; rtS < ctE; ++rtS) {
1232:       PetscInt val;
1233:       PetscCall(DMLabelGetValue(trType, rtS, &val));
1234:       if (val == rt) break;
1235:     }
1236:     PetscCheck(rtS < ctE, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find point of type %s with refine type %" PetscInt_FMT, DMPolytopeTypes[ctO], rt);
1237:   } else rtS = ctS;
1238:   PetscCall(DMPlexTransformCellTransform(tr, (DMPolytopeType)ctO, rtS, &rtTmp, &Nct, &rct, &rsize, &cone, &ornt));
1239:   PetscCheck(!trType || rt == rtTmp, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " has refine type %" PetscInt_FMT " != %" PetscInt_FMT " refine type which produced point %" PetscInt_FMT, rtS, rtTmp, rt, pNew);
1240:   for (n = 0; n < Nct; ++n) {
1241:     if (rct[n] == ctN) {
1242:       PetscInt tmp = pNew - tr->ctStartNew[ctN] - offset, val, c;

1244:       if (trType) {
1245:         for (c = ctS; c < ctE; ++c) {
1246:           PetscCall(DMLabelGetValue(trType, c, &val));
1247:           if (val == rt) {
1248:             if (tmp < rsize[n]) break;
1249:             tmp -= rsize[n];
1250:           }
1251:         }
1252:         PetscCheck(c < ctE, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Parent point for target point %" PetscInt_FMT " could be not found", pNew);
1253:         rp = c - ctS;
1254:         rO = tmp;
1255:       } else {
1256:         // This assumes that all points of type ctO transform the same way
1257:         rp = tmp / rsize[n];
1258:         rO = tmp % rsize[n];
1259:       }
1260:       break;
1261:     }
1262:   }
1263:   PetscCheck(n != Nct, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number for target point %" PetscInt_FMT " could be not found", pNew);
1264:   pO = rp + ctS;
1265:   PetscCheck(!(pO < ctS) && !(pO >= ctE), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Source point %" PetscInt_FMT " is not a %s [%" PetscInt_FMT ", %" PetscInt_FMT ")", pO, DMPolytopeTypes[ctO], ctS, ctE);
1266:   if (ct) *ct = (DMPolytopeType)ctO;
1267:   if (ctNew) *ctNew = ctN;
1268:   if (p) *p = pO;
1269:   if (r) *r = rO;
1270:   PetscFunctionReturn(PETSC_SUCCESS);
1271: }

1273: /*@
1274:   DMPlexTransformCellTransform - Describes the transform of a given source cell into a set of other target cells. These produced cells become the new mesh.

1276:   Input Parameters:
1277: + tr     - The `DMPlexTransform` object
1278: . source - The source cell type
1279: - p      - The source point, which can also determine the refine type

1281:   Output Parameters:
1282: + rt     - The refine type for this point
1283: . Nt     - The number of types produced by this point
1284: . target - An array of length `Nt` giving the types produced
1285: . size   - An array of length `Nt` giving the number of cells of each type produced
1286: . cone   - An array of length `Nt`*size[t]*coneSize[t] giving the cell type for each point in the cone of each produced point
1287: - ornt   - An array of length `Nt`*size[t]*coneSize[t] giving the orientation for each point in the cone of each produced point

1289:   Level: advanced

1291:   Notes:
1292:   The cone array gives the cone of each subcell listed by the first three outputs. For each cone point, we
1293:   need the cell type, point identifier, and orientation within the subcell. The orientation is with respect to the canonical
1294:   division (described in these outputs) of the cell in the original mesh. The point identifier is given by
1295: .vb
1296:    the number of cones to be taken, or 0 for the current cell
1297:    the cell cone point number at each level from which it is subdivided
1298:    the replica number r of the subdivision.
1299: .ve
1300:   The orientation is with respect to the canonical cone orientation. For example, the prescription for edge division is
1301: .vb
1302:    Nt     = 2
1303:    target = {DM_POLYTOPE_POINT, DM_POLYTOPE_SEGMENT}
1304:    size   = {1, 2}
1305:    cone   = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 0, 0,  DM_POLYTOPE_POINT, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0}
1306:    ornt   = {                         0,                       0,                        0,                          0}
1307: .ve

1309: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
1310: @*/
1311: PetscErrorCode DMPlexTransformCellTransform(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[])
1312: {
1313:   PetscFunctionBegin;
1314:   PetscUseTypeMethod(tr, celltransform, source, p, rt, Nt, target, size, cone, ornt);
1315:   PetscFunctionReturn(PETSC_SUCCESS);
1316: }

1318: /*@
1319:   DMPlexTransformGetSubcellOrientationIdentity - Default `getsubcellorientation` implementation for transforms that reproduce the input mesh

1321:   Not Collective

1323:   Input Parameters:
1324: + tr  - The `DMPlexTransform`
1325: . sct - The source point cell type
1326: . sp  - The source point
1327: . so  - The orientation of the source point in its enclosing parent
1328: . tct - The target point cell type
1329: . r   - The replica number requested for the produced cell type
1330: - o   - The orientation of the replica

1332:   Output Parameters:
1333: + rnew - The replica number, given the orientation of the parent (returns `r`)
1334: - onew - The replica orientation composed with the source orientation

1336:   Level: developer

1338:   Note:
1339:   This is the identity variant used by transforms such as the "identity" refiner where each source
1340:   point produces itself, so the replica number is unchanged and the returned orientation is simply
1341:   `o` composed with `so` via `DMPolytopeTypeComposeOrientation()`.

1343: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetSubcellOrientation()`, `DMPlexTransformCellTransformIdentity()`, `DMPolytopeTypeComposeOrientation()`
1344: @*/
1345: PetscErrorCode DMPlexTransformGetSubcellOrientationIdentity(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew)
1346: {
1347:   PetscFunctionBegin;
1348:   *rnew = r;
1349:   *onew = DMPolytopeTypeComposeOrientation(tct, o, so);
1350:   PetscFunctionReturn(PETSC_SUCCESS);
1351: }

1353: /*@
1354:   DMPlexTransformCellTransformIdentity - Default `celltransform` implementation for transforms that reproduce the input mesh

1356:   Not Collective

1358:   Input Parameters:
1359: + tr     - The `DMPlexTransform`
1360: . source - The cell type of the source point
1361: - p      - The source point

1363:   Output Parameters:
1364: + rt     - Refinement type of the source point (set to 0), or `NULL`
1365: . Nt     - Number of target cell types produced (always 1)
1366: . target - Array of produced cell types (a single-element array containing `source`)
1367: . size   - Array of replica counts for each produced type (a single-element array containing 1)
1368: . cone   - Cone description used by `DMPlexTransformGetCone()`; encodes that the replica takes the entire parent cone
1369: - ornt   - Orientation array associated with `cone`; all zero for identity

1371:   Level: developer

1373:   Note:
1374:   This routine returns statically allocated arrays describing an identity refinement for each supported
1375:   `DMPolytopeType`; every source point produces a single replica of the same type with unchanged cone
1376:   and orientation.

1378: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformCellTransform()`, `DMPlexTransformGetSubcellOrientationIdentity()`
1379: @*/
1380: PetscErrorCode DMPlexTransformCellTransformIdentity(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[])
1381: {
1382:   static DMPolytopeType vertexT[] = {DM_POLYTOPE_POINT};
1383:   static PetscInt       vertexS[] = {1};
1384:   static PetscInt       vertexC[] = {0};
1385:   static PetscInt       vertexO[] = {0};
1386:   static DMPolytopeType edgeT[]   = {DM_POLYTOPE_SEGMENT};
1387:   static PetscInt       edgeS[]   = {1};
1388:   static PetscInt       edgeC[]   = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0};
1389:   static PetscInt       edgeO[]   = {0, 0};
1390:   static DMPolytopeType tedgeT[]  = {DM_POLYTOPE_POINT_PRISM_TENSOR};
1391:   static PetscInt       tedgeS[]  = {1};
1392:   static PetscInt       tedgeC[]  = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0};
1393:   static PetscInt       tedgeO[]  = {0, 0};
1394:   static DMPolytopeType triT[]    = {DM_POLYTOPE_TRIANGLE};
1395:   static PetscInt       triS[]    = {1};
1396:   static PetscInt       triC[]    = {DM_POLYTOPE_SEGMENT, 1, 0, 0, DM_POLYTOPE_SEGMENT, 1, 1, 0, DM_POLYTOPE_SEGMENT, 1, 2, 0};
1397:   static PetscInt       triO[]    = {0, 0, 0};
1398:   static DMPolytopeType quadT[]   = {DM_POLYTOPE_QUADRILATERAL};
1399:   static PetscInt       quadS[]   = {1};
1400:   static PetscInt       quadC[]   = {DM_POLYTOPE_SEGMENT, 1, 0, 0, DM_POLYTOPE_SEGMENT, 1, 1, 0, DM_POLYTOPE_SEGMENT, 1, 2, 0, DM_POLYTOPE_SEGMENT, 1, 3, 0};
1401:   static PetscInt       quadO[]   = {0, 0, 0, 0};
1402:   static DMPolytopeType tquadT[]  = {DM_POLYTOPE_SEG_PRISM_TENSOR};
1403:   static PetscInt       tquadS[]  = {1};
1404:   static PetscInt       tquadC[]  = {DM_POLYTOPE_SEGMENT, 1, 0, 0, DM_POLYTOPE_SEGMENT, 1, 1, 0, DM_POLYTOPE_POINT_PRISM_TENSOR, 1, 2, 0, DM_POLYTOPE_POINT_PRISM_TENSOR, 1, 3, 0};
1405:   static PetscInt       tquadO[]  = {0, 0, 0, 0};
1406:   static DMPolytopeType tetT[]    = {DM_POLYTOPE_TETRAHEDRON};
1407:   static PetscInt       tetS[]    = {1};
1408:   static PetscInt       tetC[]    = {DM_POLYTOPE_TRIANGLE, 1, 0, 0, DM_POLYTOPE_TRIANGLE, 1, 1, 0, DM_POLYTOPE_TRIANGLE, 1, 2, 0, DM_POLYTOPE_TRIANGLE, 1, 3, 0};
1409:   static PetscInt       tetO[]    = {0, 0, 0, 0};
1410:   static DMPolytopeType hexT[]    = {DM_POLYTOPE_HEXAHEDRON};
1411:   static PetscInt       hexS[]    = {1};
1412:   static PetscInt       hexC[] = {DM_POLYTOPE_QUADRILATERAL, 1, 0, 0, DM_POLYTOPE_QUADRILATERAL, 1, 1, 0, DM_POLYTOPE_QUADRILATERAL, 1, 2, 0, DM_POLYTOPE_QUADRILATERAL, 1, 3, 0, DM_POLYTOPE_QUADRILATERAL, 1, 4, 0, DM_POLYTOPE_QUADRILATERAL, 1, 5, 0};
1413:   static PetscInt       hexO[] = {0, 0, 0, 0, 0, 0};
1414:   static DMPolytopeType tripT[]   = {DM_POLYTOPE_TRI_PRISM};
1415:   static PetscInt       tripS[]   = {1};
1416:   static PetscInt       tripC[]   = {DM_POLYTOPE_TRIANGLE, 1, 0, 0, DM_POLYTOPE_TRIANGLE, 1, 1, 0, DM_POLYTOPE_QUADRILATERAL, 1, 2, 0, DM_POLYTOPE_QUADRILATERAL, 1, 3, 0, DM_POLYTOPE_QUADRILATERAL, 1, 4, 0};
1417:   static PetscInt       tripO[]   = {0, 0, 0, 0, 0};
1418:   static DMPolytopeType ttripT[]  = {DM_POLYTOPE_TRI_PRISM_TENSOR};
1419:   static PetscInt       ttripS[]  = {1};
1420:   static PetscInt       ttripC[]  = {DM_POLYTOPE_TRIANGLE, 1, 0, 0, DM_POLYTOPE_TRIANGLE, 1, 1, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 2, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 3, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 4, 0};
1421:   static PetscInt       ttripO[]  = {0, 0, 0, 0, 0};
1422:   static DMPolytopeType tquadpT[] = {DM_POLYTOPE_QUAD_PRISM_TENSOR};
1423:   static PetscInt       tquadpS[] = {1};
1424:   static PetscInt       tquadpC[] = {DM_POLYTOPE_QUADRILATERAL,    1, 0, 0, DM_POLYTOPE_QUADRILATERAL,    1, 1, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 2, 0,
1425:                                      DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 3, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 4, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 5, 0};
1426:   static PetscInt       tquadpO[] = {0, 0, 0, 0, 0, 0};
1427:   static DMPolytopeType pyrT[]    = {DM_POLYTOPE_PYRAMID};
1428:   static PetscInt       pyrS[]    = {1};
1429:   static PetscInt       pyrC[]    = {DM_POLYTOPE_QUADRILATERAL, 1, 0, 0, DM_POLYTOPE_TRIANGLE, 1, 1, 0, DM_POLYTOPE_TRIANGLE, 1, 2, 0, DM_POLYTOPE_TRIANGLE, 1, 3, 0, DM_POLYTOPE_TRIANGLE, 1, 4, 0};
1430:   static PetscInt       pyrO[]    = {0, 0, 0, 0, 0};

1432:   PetscFunctionBegin;
1433:   if (rt) *rt = 0;
1434:   switch (source) {
1435:   case DM_POLYTOPE_POINT:
1436:     *Nt     = 1;
1437:     *target = vertexT;
1438:     *size   = vertexS;
1439:     *cone   = vertexC;
1440:     *ornt   = vertexO;
1441:     break;
1442:   case DM_POLYTOPE_SEGMENT:
1443:     *Nt     = 1;
1444:     *target = edgeT;
1445:     *size   = edgeS;
1446:     *cone   = edgeC;
1447:     *ornt   = edgeO;
1448:     break;
1449:   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1450:     *Nt     = 1;
1451:     *target = tedgeT;
1452:     *size   = tedgeS;
1453:     *cone   = tedgeC;
1454:     *ornt   = tedgeO;
1455:     break;
1456:   case DM_POLYTOPE_TRIANGLE:
1457:     *Nt     = 1;
1458:     *target = triT;
1459:     *size   = triS;
1460:     *cone   = triC;
1461:     *ornt   = triO;
1462:     break;
1463:   case DM_POLYTOPE_QUADRILATERAL:
1464:     *Nt     = 1;
1465:     *target = quadT;
1466:     *size   = quadS;
1467:     *cone   = quadC;
1468:     *ornt   = quadO;
1469:     break;
1470:   case DM_POLYTOPE_SEG_PRISM_TENSOR:
1471:     *Nt     = 1;
1472:     *target = tquadT;
1473:     *size   = tquadS;
1474:     *cone   = tquadC;
1475:     *ornt   = tquadO;
1476:     break;
1477:   case DM_POLYTOPE_TETRAHEDRON:
1478:     *Nt     = 1;
1479:     *target = tetT;
1480:     *size   = tetS;
1481:     *cone   = tetC;
1482:     *ornt   = tetO;
1483:     break;
1484:   case DM_POLYTOPE_HEXAHEDRON:
1485:     *Nt     = 1;
1486:     *target = hexT;
1487:     *size   = hexS;
1488:     *cone   = hexC;
1489:     *ornt   = hexO;
1490:     break;
1491:   case DM_POLYTOPE_TRI_PRISM:
1492:     *Nt     = 1;
1493:     *target = tripT;
1494:     *size   = tripS;
1495:     *cone   = tripC;
1496:     *ornt   = tripO;
1497:     break;
1498:   case DM_POLYTOPE_TRI_PRISM_TENSOR:
1499:     *Nt     = 1;
1500:     *target = ttripT;
1501:     *size   = ttripS;
1502:     *cone   = ttripC;
1503:     *ornt   = ttripO;
1504:     break;
1505:   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
1506:     *Nt     = 1;
1507:     *target = tquadpT;
1508:     *size   = tquadpS;
1509:     *cone   = tquadpC;
1510:     *ornt   = tquadpO;
1511:     break;
1512:   case DM_POLYTOPE_PYRAMID:
1513:     *Nt     = 1;
1514:     *target = pyrT;
1515:     *size   = pyrS;
1516:     *cone   = pyrC;
1517:     *ornt   = pyrO;
1518:     break;
1519:   default:
1520:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No refinement strategy for %s", DMPolytopeTypes[source]);
1521:   }
1522:   PetscFunctionReturn(PETSC_SUCCESS);
1523: }

1525: /*@
1526:   DMPlexTransformGetSubcellOrientation - Transform the replica number and orientation for a target point according to the group action for the source point

1528:   Not Collective

1530:   Input Parameters:
1531: + tr  - The `DMPlexTransform`
1532: . sct - The source point cell type, from whom the new cell is being produced
1533: . sp  - The source point
1534: . so  - The orientation of the source point in its enclosing parent
1535: . tct - The target point cell type
1536: . r   - The replica number requested for the produced cell type
1537: - o   - The orientation of the replica

1539:   Output Parameters:
1540: + rnew - The replica number, given the orientation of the parent
1541: - onew - The replica orientation, given the orientation of the parent

1543:   Level: advanced

1545: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformCellTransform()`, `DMPlexTransformApply()`
1546: @*/
1547: PetscErrorCode DMPlexTransformGetSubcellOrientation(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew)
1548: {
1549:   PetscFunctionBeginHot;
1550:   PetscUseTypeMethod(tr, getsubcellorientation, sct, sp, so, tct, r, o, rnew, onew);
1551:   PetscFunctionReturn(PETSC_SUCCESS);
1552: }

1554: static PetscErrorCode DMPlexTransformSetConeSizes(DMPlexTransform tr, DM rdm)
1555: {
1556:   DM       dm;
1557:   PetscInt pStart, pEnd, pNew;

1559:   PetscFunctionBegin;
1560:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1561:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetConeSizes, tr, dm, 0, 0));
1562:   /* Must create the celltype label here so that we do not automatically try to compute the types */
1563:   PetscCall(DMCreateLabel(rdm, "celltype"));
1564:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1565:   for (PetscInt p = pStart; p < pEnd; ++p) {
1566:     DMPolytopeType  ct;
1567:     DMPolytopeType *rct;
1568:     PetscInt       *rsize, *rcone, *rornt;
1569:     PetscInt        Nct, n, r;

1571:     PetscCall(DMPlexGetCellType(dm, p, &ct));
1572:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1573:     for (n = 0; n < Nct; ++n) {
1574:       for (r = 0; r < rsize[n]; ++r) {
1575:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1576:         PetscCall(DMPlexSetConeSize(rdm, pNew, DMPolytopeTypeGetConeSize(rct[n])));
1577:         PetscCall(DMPlexSetCellType(rdm, pNew, rct[n]));
1578:       }
1579:     }
1580:   }
1581:   /* Let the DM know we have set all the cell types */
1582:   {
1583:     DMLabel  ctLabel;
1584:     DM_Plex *plex = (DM_Plex *)rdm->data;

1586:     PetscCall(DMPlexGetCellTypeLabel(rdm, &ctLabel));
1587:     PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &plex->celltypeState));
1588:   }
1589:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetConeSizes, tr, dm, 0, 0));
1590:   PetscFunctionReturn(PETSC_SUCCESS);
1591: }

1593: /*@
1594:   DMPlexTransformGetConeSize - Return the cone size of a point in the transformed mesh

1596:   Not Collective

1598:   Input Parameters:
1599: + tr - The `DMPlexTransform`
1600: - q  - The point number in the transformed mesh

1602:   Output Parameter:
1603: . coneSize - The number of points in the cone of `q`

1605:   Level: developer

1607: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetCone()`, `DMPlexTransformGetCellType()`, `DMPlexGetConeSize()`
1608: @*/
1609: PetscErrorCode DMPlexTransformGetConeSize(DMPlexTransform tr, PetscInt q, PetscInt *coneSize)
1610: {
1611:   DMPolytopeType ctNew;

1613:   PetscFunctionBegin;
1615:   PetscAssertPointer(coneSize, 3);
1616:   PetscCall(DMPlexTransformGetCellType(tr, q, &ctNew));
1617:   *coneSize = DMPolytopeTypeGetConeSize(ctNew);
1618:   PetscFunctionReturn(PETSC_SUCCESS);
1619: }

1621: /* The orientation o is for the interior of the cell p */
1622: static PetscErrorCode DMPlexTransformGetCone_Internal(DMPlexTransform tr, PetscInt p, PetscInt o, DMPolytopeType ct, DMPolytopeType ctNew, const PetscInt rcone[], PetscInt *coneoff, const PetscInt rornt[], PetscInt *orntoff, PetscInt coneNew[], PetscInt orntNew[])
1623: {
1624:   DM              dm;
1625:   const PetscInt  csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1626:   const PetscInt *cone;
1627:   DMPolytopeType *newft = NULL;
1628:   PetscInt        c, coff = *coneoff, ooff = *orntoff;
1629:   PetscInt        dim, cr = 0, co = 0, nr, no;

1631:   PetscFunctionBegin;
1632:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1633:   PetscCall(DMPlexGetOrientedCone(dm, p, &cone, NULL));
1634:   // Check if we have to permute this cell
1635:   PetscCall(DMGetDimension(dm, &dim));
1636:   if (DMPolytopeTypeGetDim(ctNew) == dim && DMPolytopeTypeGetDim(ct) == dim - 1) {
1637:     PetscCall(DMPlexTransformGetSubcellOrientation(tr, ct, p, o, ctNew, cr, co, &nr, &no));
1638:     if (cr != nr || co != no) PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newft));
1639:   }
1640:   for (c = 0; c < csizeNew; ++c) {
1641:     PetscInt             ppp   = -1;                            /* Parent Parent point: Parent of point pp */
1642:     PetscInt             pp    = p;                             /* Parent point: Point in the original mesh producing new cone point */
1643:     PetscInt             po    = 0;                             /* Orientation of parent point pp in parent parent point ppp */
1644:     DMPolytopeType       pct   = ct;                            /* Parent type: Cell type for parent of new cone point */
1645:     const PetscInt      *pcone = cone;                          /* Parent cone: Cone of parent point pp */
1646:     PetscInt             pr    = -1;                            /* Replica number of pp that produces new cone point  */
1647:     const DMPolytopeType ft    = (DMPolytopeType)rcone[coff++]; /* Cell type for new cone point of pNew */
1648:     const PetscInt       fn    = rcone[coff++];                 /* Number of cones of p that need to be taken when producing new cone point */
1649:     PetscInt             fo    = rornt[ooff++];                 /* Orientation of new cone point in pNew */
1650:     PetscInt             lc;

1652:     /* Get the type (pct) and point number (pp) of the parent point in the original mesh which produces this cone point */
1653:     for (lc = 0; lc < fn; ++lc) {
1654:       const PetscInt *parr = DMPolytopeTypeGetArrangement(pct, po);
1655:       const PetscInt  acp  = rcone[coff++];
1656:       const PetscInt  pcp  = parr[acp * 2];
1657:       const PetscInt  pco  = parr[acp * 2 + 1];
1658:       const PetscInt *ppornt;

1660:       ppp = pp;
1661:       pp  = pcone[pcp];
1662:       PetscCall(DMPlexGetCellType(dm, pp, &pct));
1663:       // Restore the parent cone from the last iterate
1664:       if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, ppp, &pcone, NULL));
1665:       PetscCall(DMPlexGetOrientedCone(dm, pp, &pcone, NULL));
1666:       PetscCall(DMPlexGetOrientedCone(dm, ppp, NULL, &ppornt));
1667:       po = DMPolytopeTypeComposeOrientation(pct, ppornt[pcp], pco);
1668:       PetscCall(DMPlexRestoreOrientedCone(dm, ppp, NULL, &ppornt));
1669:     }
1670:     if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, pp, &pcone, NULL));
1671:     pr = rcone[coff++];
1672:     /* Orientation po of pp maps (pr, fo) -> (pr', fo') */
1673:     PetscCall(DMPlexTransformGetSubcellOrientation(tr, pct, pp, fn ? po : o, ft, pr, fo, &pr, &fo));
1674:     PetscCall(DMPlexTransformGetTargetPoint(tr, pct, ft, pp, pr, &coneNew[c]));
1675:     orntNew[c] = fo;
1676:     if (newft) newft[c] = ft;
1677:   }
1678:   PetscCall(DMPlexRestoreOrientedCone(dm, p, &cone, NULL));
1679:   if (newft) {
1680:     const PetscInt *arr;
1681:     PetscInt       *newcone, *newornt;

1683:     arr = DMPolytopeTypeGetArrangement(ctNew, no);
1684:     PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newcone));
1685:     PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newornt));
1686:     for (PetscInt c = 0; c < csizeNew; ++c) {
1687:       DMPolytopeType ft = newft[c];
1688:       PetscInt       nO;

1690:       nO         = DMPolytopeTypeGetNumArrangements(ft) / 2;
1691:       newcone[c] = coneNew[arr[c * 2 + 0]];
1692:       newornt[c] = DMPolytopeTypeComposeOrientation(ft, arr[c * 2 + 1], orntNew[arr[c * 2 + 0]]);
1693:       PetscCheck(!newornt[c] || !(newornt[c] >= nO || newornt[c] < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, newornt[c], -nO, nO, DMPolytopeTypes[ft], coneNew[c]);
1694:     }
1695:     for (PetscInt c = 0; c < csizeNew; ++c) {
1696:       coneNew[c] = newcone[c];
1697:       orntNew[c] = newornt[c];
1698:     }
1699:     PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newcone));
1700:     PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newornt));
1701:     PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newft));
1702:   }
1703:   *coneoff = coff;
1704:   *orntoff = ooff;
1705:   PetscFunctionReturn(PETSC_SUCCESS);
1706: }

1708: static PetscErrorCode DMPlexTransformSetCones(DMPlexTransform tr, DM rdm)
1709: {
1710:   DM             dm;
1711:   DMPolytopeType ct;
1712:   PetscInt      *coneNew, *orntNew;
1713:   PetscInt       maxConeSize = 0, pStart, pEnd, p, pNew;

1715:   PetscFunctionBegin;
1716:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1717:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetCones, tr, dm, 0, 0));
1718:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1719:   PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew));
1720:   PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew));
1721:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1722:   for (p = pStart; p < pEnd; ++p) {
1723:     PetscInt        coff, ooff;
1724:     DMPolytopeType *rct;
1725:     PetscInt       *rsize, *rcone, *rornt;
1726:     PetscInt        Nct, n, r;

1728:     PetscCall(DMPlexGetCellType(dm, p, &ct));
1729:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1730:     for (n = 0, coff = 0, ooff = 0; n < Nct; ++n) {
1731:       const DMPolytopeType ctNew = rct[n];

1733:       for (r = 0; r < rsize[n]; ++r) {
1734:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1735:         PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, ctNew, rcone, &coff, rornt, &ooff, coneNew, orntNew));
1736:         PetscCall(DMPlexSetCone(rdm, pNew, coneNew));
1737:         PetscCall(DMPlexSetConeOrientation(rdm, pNew, orntNew));
1738:       }
1739:     }
1740:   }
1741:   PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew));
1742:   PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew));
1743:   PetscCall(DMViewFromOptions(rdm, NULL, "-rdm_view"));
1744:   PetscCall(DMPlexSymmetrize(rdm));
1745:   PetscCall(DMPlexStratify(rdm));
1746:   PetscCall(DMPlexTransformOrderSupports(tr, dm, rdm));
1747:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetCones, tr, dm, 0, 0));
1748:   PetscFunctionReturn(PETSC_SUCCESS);
1749: }

1751: /*@
1752:   DMPlexTransformGetConeOriented - Return the cone of a point in the transformed mesh, computed using a specified parent orientation

1754:   Not Collective

1756:   Input Parameters:
1757: + tr - The `DMPlexTransform`
1758: . q  - The point number in the transformed mesh
1759: - po - The orientation of the parent cell in the original mesh to use when producing the cone

1761:   Output Parameters:
1762: + cone - The cone points, obtained from an internal work array
1763: - ornt - The orientations of the cone points, obtained from an internal work array

1765:   Level: developer

1767:   Note:
1768:   Both `cone` and `ornt` are returned in work arrays that must be released with `DMPlexTransformRestoreCone()`.

1770: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetCone()`, `DMPlexTransformRestoreCone()`, `DMPlexTransformGetConeSize()`
1771: @*/
1772: PetscErrorCode DMPlexTransformGetConeOriented(DMPlexTransform tr, PetscInt q, PetscInt po, const PetscInt *cone[], const PetscInt *ornt[])
1773: {
1774:   DM              dm;
1775:   DMPolytopeType  ct, qct;
1776:   DMPolytopeType *rct;
1777:   PetscInt       *rsize, *rcone, *rornt, *qcone, *qornt;
1778:   PetscInt        maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0;

1780:   PetscFunctionBegin;
1782:   PetscAssertPointer(cone, 4);
1783:   PetscAssertPointer(ornt, 5);
1784:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1785:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1786:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1787:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1788:   PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r));
1789:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1790:   for (n = 0; n < Nct; ++n) {
1791:     const DMPolytopeType ctNew    = rct[n];
1792:     const PetscInt       csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1793:     PetscInt             Nr       = rsize[n], fn, c;

1795:     if (ctNew == qct) Nr = r;
1796:     for (nr = 0; nr < Nr; ++nr) {
1797:       for (c = 0; c < csizeNew; ++c) {
1798:         ++coff;             /* Cell type of new cone point */
1799:         fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */
1800:         coff += fn;
1801:         ++coff; /* Replica number of new cone point */
1802:         ++ooff; /* Orientation of new cone point */
1803:       }
1804:     }
1805:     if (ctNew == qct) break;
1806:   }
1807:   PetscCall(DMPlexTransformGetCone_Internal(tr, p, po, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt));
1808:   *cone = qcone;
1809:   *ornt = qornt;
1810:   PetscFunctionReturn(PETSC_SUCCESS);
1811: }

1813: /*@
1814:   DMPlexTransformGetCone - Return the cone of a point in the transformed mesh

1816:   Not Collective

1818:   Input Parameters:
1819: + tr - The `DMPlexTransform`
1820: - q  - The point number in the transformed mesh

1822:   Output Parameters:
1823: + cone - The cone points, obtained from an internal work array, or `NULL` if not requested
1824: - ornt - The orientations of the cone points, obtained from an internal work array, or `NULL` if not requested

1826:   Level: developer

1828:   Note:
1829:   Any non-`NULL` output must be released with `DMPlexTransformRestoreCone()`.

1831: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformRestoreCone()`, `DMPlexTransformGetConeOriented()`, `DMPlexTransformGetConeSize()`, `DMPlexGetCone()`
1832: @*/
1833: PetscErrorCode DMPlexTransformGetCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[])
1834: {
1835:   DM              dm;
1836:   DMPolytopeType  ct, qct;
1837:   DMPolytopeType *rct;
1838:   PetscInt       *rsize, *rcone, *rornt, *qcone, *qornt;
1839:   PetscInt        maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0;

1841:   PetscFunctionBegin;
1843:   if (cone) PetscAssertPointer(cone, 3);
1844:   if (ornt) PetscAssertPointer(ornt, 4);
1845:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1846:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1847:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1848:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1849:   PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r));
1850:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1851:   for (n = 0; n < Nct; ++n) {
1852:     const DMPolytopeType ctNew    = rct[n];
1853:     const PetscInt       csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1854:     PetscInt             Nr       = rsize[n], fn, c;

1856:     if (ctNew == qct) Nr = r;
1857:     for (nr = 0; nr < Nr; ++nr) {
1858:       for (c = 0; c < csizeNew; ++c) {
1859:         ++coff;             /* Cell type of new cone point */
1860:         fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */
1861:         coff += fn;
1862:         ++coff; /* Replica number of new cone point */
1863:         ++ooff; /* Orientation of new cone point */
1864:       }
1865:     }
1866:     if (ctNew == qct) break;
1867:   }
1868:   PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt));
1869:   if (cone) *cone = qcone;
1870:   else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1871:   if (ornt) *ornt = qornt;
1872:   else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1873:   PetscFunctionReturn(PETSC_SUCCESS);
1874: }

1876: /*@
1877:   DMPlexTransformRestoreCone - Return the work arrays produced by `DMPlexTransformGetCone()` or `DMPlexTransformGetConeOriented()`

1879:   Not Collective

1881:   Input Parameters:
1882: + tr   - The `DMPlexTransform`
1883: . q    - The point number in the transformed mesh
1884: . cone - The cone points to release, or `NULL`
1885: - ornt - The orientations to release, or `NULL`

1887:   Level: developer

1889: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetCone()`, `DMPlexTransformGetConeOriented()`
1890: @*/
1891: PetscErrorCode DMPlexTransformRestoreCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[])
1892: {
1893:   DM dm;

1895:   PetscFunctionBegin;
1897:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1898:   if (cone) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, cone));
1899:   if (ornt) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, ornt));
1900:   PetscFunctionReturn(PETSC_SUCCESS);
1901: }

1903: static PetscErrorCode DMPlexTransformCreateCellVertices_Internal(DMPlexTransform tr)
1904: {
1905:   PetscFunctionBegin;
1906:   PetscCall(PetscCalloc3(DM_NUM_POLYTOPES, &tr->trNv, DM_NUM_POLYTOPES, &tr->trVerts, DM_NUM_POLYTOPES, &tr->trSubVerts));
1907:   for (PetscInt ict = DM_POLYTOPE_POINT; ict < DM_NUM_POLYTOPES; ++ict) {
1908:     const DMPolytopeType ct = (DMPolytopeType)ict;
1909:     DMPlexTransform      reftr;
1910:     DM                   refdm, trdm;
1911:     Vec                  coordinates;
1912:     const PetscScalar   *coords;
1913:     DMPolytopeType      *rct;
1914:     PetscInt            *rsize, *rcone, *rornt;
1915:     PetscInt             Nct, n, r, pNew = 0;
1916:     PetscInt             trdim, vStart, vEnd, Nc;
1917:     const PetscInt       debug = 0;
1918:     const char          *typeName;

1920:     /* Since points are 0-dimensional, coordinates make no sense */
1921:     if (DMPolytopeTypeGetDim(ct) <= 0 || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) continue;
1922:     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, ct, &refdm));
1923:     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &reftr));
1924:     PetscCall(DMPlexTransformSetDM(reftr, refdm));
1925:     PetscCall(DMPlexTransformGetType(tr, &typeName));
1926:     PetscCall(DMPlexTransformSetType(reftr, typeName));
1927:     PetscCall(DMPlexTransformSetUp(reftr));
1928:     PetscCall(DMPlexTransformApply(reftr, refdm, &trdm));

1930:     PetscCall(DMGetDimension(trdm, &trdim));
1931:     PetscCall(DMPlexGetDepthStratum(trdm, 0, &vStart, &vEnd));
1932:     tr->trNv[ct] = vEnd - vStart;
1933:     PetscCall(DMGetCoordinatesLocal(trdm, &coordinates));
1934:     PetscCall(VecGetLocalSize(coordinates, &Nc));
1935:     PetscCheck(tr->trNv[ct] * trdim == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell type %s, transformed coordinate size %" PetscInt_FMT " != %" PetscInt_FMT " size of coordinate storage", DMPolytopeTypes[ct], tr->trNv[ct] * trdim, Nc);
1936:     PetscCall(PetscCalloc1(Nc, &tr->trVerts[ct]));
1937:     PetscCall(VecGetArrayRead(coordinates, &coords));
1938:     PetscCall(PetscArraycpy(tr->trVerts[ct], coords, Nc));
1939:     PetscCall(VecRestoreArrayRead(coordinates, &coords));

1941:     PetscCall(PetscCalloc1(DM_NUM_POLYTOPES, &tr->trSubVerts[ct]));
1942:     PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1943:     for (n = 0; n < Nct; ++n) {
1944:       /* Since points are 0-dimensional, coordinates make no sense */
1945:       if (rct[n] == DM_POLYTOPE_POINT) continue;
1946:       PetscCall(PetscCalloc1(rsize[n], &tr->trSubVerts[ct][rct[n]]));
1947:       for (r = 0; r < rsize[n]; ++r) {
1948:         PetscInt *closure = NULL;
1949:         PetscInt  clSize, cl, Nv = 0;

1951:         PetscCall(PetscCalloc1(DMPolytopeTypeGetNumVertices(rct[n]), &tr->trSubVerts[ct][rct[n]][r]));
1952:         PetscCall(DMPlexTransformGetTargetPoint(reftr, ct, rct[n], 0, r, &pNew));
1953:         PetscCall(DMPlexGetTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure));
1954:         for (cl = 0; cl < clSize * 2; cl += 2) {
1955:           const PetscInt sv = closure[cl];

1957:           if ((sv >= vStart) && (sv < vEnd)) tr->trSubVerts[ct][rct[n]][r][Nv++] = sv - vStart;
1958:         }
1959:         PetscCall(DMPlexRestoreTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure));
1960:         PetscCheck(Nv == DMPolytopeTypeGetNumVertices(rct[n]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of vertices %" PetscInt_FMT " != %" PetscInt_FMT " for %s subcell %" PetscInt_FMT " from cell %s", Nv, DMPolytopeTypeGetNumVertices(rct[n]), DMPolytopeTypes[rct[n]], r, DMPolytopeTypes[ct]);
1961:       }
1962:     }
1963:     if (debug) {
1964:       DMPolytopeType *rct;
1965:       PetscInt       *rsize, *rcone, *rornt;
1966:       PetscInt        v, dE = trdim, d, off = 0;

1968:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %" PetscInt_FMT " vertices\n", DMPolytopeTypes[ct], tr->trNv[ct]));
1969:       for (v = 0; v < tr->trNv[ct]; ++v) {
1970:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  "));
1971:         for (d = 0; d < dE; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g ", (double)PetscRealPart(tr->trVerts[ct][off++])));
1972:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1973:       }

1975:       PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1976:       for (n = 0; n < Nct; ++n) {
1977:         if (rct[n] == DM_POLYTOPE_POINT) continue;
1978:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %s subvertices %" PetscInt_FMT "\n", DMPolytopeTypes[ct], DMPolytopeTypes[rct[n]], tr->trNv[ct]));
1979:         for (r = 0; r < rsize[n]; ++r) {
1980:           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  "));
1981:           for (v = 0; v < DMPolytopeTypeGetNumVertices(rct[n]); ++v) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT " ", tr->trSubVerts[ct][rct[n]][r][v]));
1982:           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1983:         }
1984:       }
1985:     }
1986:     PetscCall(DMDestroy(&refdm));
1987:     PetscCall(DMDestroy(&trdm));
1988:     PetscCall(DMPlexTransformDestroy(&reftr));
1989:   }
1990:   PetscFunctionReturn(PETSC_SUCCESS);
1991: }

1993: /*@
1994:   DMPlexTransformGetCellVertices - Get the set of transformed vertices lying in the closure of a reference cell of given type

1996:   Input Parameters:
1997: + tr - The `DMPlexTransform` object
1998: - ct - The cell type

2000:   Output Parameters:
2001: + Nv      - The number of transformed vertices in the closure of the reference cell of given type
2002: - trVerts - The coordinates of these vertices in the reference cell

2004:   Level: developer

2006: .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSubcellVertices()`
2007: @*/
2008: PetscErrorCode DMPlexTransformGetCellVertices(DMPlexTransform tr, DMPolytopeType ct, PetscInt *Nv, PetscScalar *trVerts[])
2009: {
2010:   PetscFunctionBegin;
2011:   if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr));
2012:   if (Nv) *Nv = tr->trNv[ct];
2013:   if (trVerts) *trVerts = tr->trVerts[ct];
2014:   PetscFunctionReturn(PETSC_SUCCESS);
2015: }

2017: /*@
2018:   DMPlexTransformGetSubcellVertices - Get the set of transformed vertices defining a subcell in the reference cell of given type

2020:   Input Parameters:
2021: + tr  - The `DMPlexTransform` object
2022: . ct  - The cell type
2023: . rct - The subcell type
2024: - r   - The subcell index

2026:   Output Parameter:
2027: . subVerts - The indices of these vertices in the set of vertices returned by `DMPlexTransformGetCellVertices()`

2029:   Level: developer

2031: .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetCellVertices()`
2032: @*/
2033: PetscErrorCode DMPlexTransformGetSubcellVertices(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, PetscInt *subVerts[])
2034: {
2035:   PetscFunctionBegin;
2036:   if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr));
2037:   PetscCheck(tr->trSubVerts[ct][rct], PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_WRONG, "Cell type %s does not produce %s", DMPolytopeTypes[ct], DMPolytopeTypes[rct]);
2038:   if (subVerts) *subVerts = tr->trSubVerts[ct][rct][r];
2039:   PetscFunctionReturn(PETSC_SUCCESS);
2040: }

2042: /*@
2043:   DMPlexTransformOrderSupports - Reorder newly introduced point supports

2045:   Collective

2047:   Input Parameters:
2048: + tr   - The `DMPlexTransform`
2049: . dm   - The original `DM`
2050: - trdm - The transformed `DM` which is reordered

2052:   Level: intermediate

2054: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`
2055: @*/
2056: PetscErrorCode DMPlexTransformOrderSupports(DMPlexTransform tr, DM dm, DM trdm)
2057: {
2058:   PetscFunctionBegin;
2062:   PetscTryTypeMethod(tr, ordersupports, dm, trdm);
2063:   PetscFunctionReturn(PETSC_SUCCESS);
2064: }

2066: /* Computes new vertex as the barycenter, or centroid */
2067: PetscErrorCode DMPlexTransformMapCoordinatesBarycenter_Internal(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[])
2068: {
2069:   PetscInt v, d;

2071:   PetscFunctionBeginHot;
2072:   PetscCheck(ct == DM_POLYTOPE_POINT, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for refined point type %s", DMPolytopeTypes[ct]);
2073:   for (d = 0; d < dE; ++d) out[d] = 0.0;
2074:   for (v = 0; v < Nv; ++v)
2075:     for (d = 0; d < dE; ++d) out[d] += in[v * dE + d];
2076:   for (d = 0; d < dE; ++d) out[d] /= Nv;
2077:   PetscFunctionReturn(PETSC_SUCCESS);
2078: }

2080: /*@
2081:   DMPlexTransformMapCoordinates - Calculate new coordinates for produced points

2083:   Not collective

2085:   Input Parameters:
2086: + tr  - The `DMPlexTransform`
2087: . pct - The cell type of the parent, from whom the new cell is being produced
2088: . ct  - The type being produced
2089: . p   - The original point
2090: . r   - The replica number requested for the produced cell type
2091: . Nv  - Number of vertices in the closure of the parent cell
2092: . dE  - Spatial dimension
2093: - in  - array of size Nv*dE, holding coordinates of the vertices in the closure of the parent cell

2095:   Output Parameter:
2096: . out - The coordinates of the new vertices

2098:   Level: intermediate

2100: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`
2101: @*/
2102: PetscErrorCode DMPlexTransformMapCoordinates(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[])
2103: {
2104:   PetscFunctionBeginHot;
2105:   if (Nv) PetscUseTypeMethod(tr, mapcoordinates, pct, ct, p, r, Nv, dE, in, out);
2106:   PetscFunctionReturn(PETSC_SUCCESS);
2107: }

2109: /*
2110:   DMPlexTransformLabelProducedPoint_Private - Label a produced point based on its parent label

2112:   Not Collective

2114:   Input Parameters:
2115: + tr    - The `DMPlexTransform`
2116: . label - The label in the transformed mesh
2117: . pp    - The parent point in the original mesh
2118: . pct   - The cell type of the parent point
2119: . p     - The point in the transformed mesh
2120: . ct    - The cell type of the point
2121: . r     - The replica number of the point
2122: - val   - The label value of the parent point

2124:   Level: developer

2126: .seealso: `DMPlexTransformCreateLabels()`, `RefineLabel_Internal()`
2127: */
2128: static PetscErrorCode DMPlexTransformLabelProducedPoint_Private(DMPlexTransform tr, DMLabel label, PetscInt pp, DMPolytopeType pct, PetscInt p, DMPolytopeType ct, PetscInt r, PetscInt val)
2129: {
2130:   PetscFunctionBeginHot;
2131:   if (tr->labelMatchStrata && pct != ct) PetscFunctionReturn(PETSC_SUCCESS);
2132:   PetscCall(DMLabelSetValue(label, p, val + tr->labelReplicaInc * r));
2133:   PetscFunctionReturn(PETSC_SUCCESS);
2134: }

2136: static PetscErrorCode RefineLabel_Internal(DMPlexTransform tr, DMLabel label, DMLabel labelNew)
2137: {
2138:   DM              dm;
2139:   IS              valueIS;
2140:   const PetscInt *values;
2141:   PetscInt        defVal, Nv, val;

2143:   PetscFunctionBegin;
2144:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2145:   PetscCall(DMLabelGetDefaultValue(label, &defVal));
2146:   PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
2147:   PetscCall(DMLabelGetValueIS(label, &valueIS));
2148:   PetscCall(ISGetLocalSize(valueIS, &Nv));
2149:   PetscCall(ISGetIndices(valueIS, &values));
2150:   for (val = 0; val < Nv; ++val) {
2151:     IS              pointIS;
2152:     const PetscInt *points;
2153:     PetscInt        numPoints, p;

2155:     /* Ensure refined label is created with same number of strata as
2156:      * original (even if no entries here). */
2157:     PetscCall(DMLabelAddStratum(labelNew, values[val]));
2158:     PetscCall(DMLabelGetStratumIS(label, values[val], &pointIS));
2159:     PetscCall(ISGetLocalSize(pointIS, &numPoints));
2160:     PetscCall(ISGetIndices(pointIS, &points));
2161:     for (p = 0; p < numPoints; ++p) {
2162:       const PetscInt  point = points[p];
2163:       DMPolytopeType  ct;
2164:       DMPolytopeType *rct;
2165:       PetscInt       *rsize, *rcone, *rornt;
2166:       PetscInt        Nct, n, r, pNew = 0;

2168:       PetscCall(DMPlexGetCellType(dm, point, &ct));
2169:       PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2170:       for (n = 0; n < Nct; ++n) {
2171:         for (r = 0; r < rsize[n]; ++r) {
2172:           PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], point, r, &pNew));
2173:           PetscCall(DMPlexTransformLabelProducedPoint_Private(tr, labelNew, point, ct, pNew, rct[n], r, values[val]));
2174:         }
2175:       }
2176:     }
2177:     PetscCall(ISRestoreIndices(pointIS, &points));
2178:     PetscCall(ISDestroy(&pointIS));
2179:   }
2180:   PetscCall(ISRestoreIndices(valueIS, &values));
2181:   PetscCall(ISDestroy(&valueIS));
2182:   PetscFunctionReturn(PETSC_SUCCESS);
2183: }

2185: static PetscErrorCode DMPlexTransformCreateLabels(DMPlexTransform tr, DM rdm)
2186: {
2187:   DM       dm;
2188:   PetscInt numLabels, l;

2190:   PetscFunctionBegin;
2191:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2192:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_CreateLabels, tr, dm, 0, 0));
2193:   PetscCall(DMGetNumLabels(dm, &numLabels));
2194:   for (l = 0; l < numLabels; ++l) {
2195:     DMLabel     label, labelNew;
2196:     const char *lname;
2197:     PetscBool   isDepth, isCellType;

2199:     PetscCall(DMGetLabelName(dm, l, &lname));
2200:     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
2201:     if (isDepth) continue;
2202:     PetscCall(PetscStrcmp(lname, "celltype", &isCellType));
2203:     if (isCellType) continue;
2204:     PetscCall(DMCreateLabel(rdm, lname));
2205:     PetscCall(DMGetLabel(dm, lname, &label));
2206:     PetscCall(DMGetLabel(rdm, lname, &labelNew));
2207:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
2208:   }
2209:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateLabels, tr, dm, 0, 0));
2210:   PetscFunctionReturn(PETSC_SUCCESS);
2211: }

2213: /*@
2214:   DMPlexTransformCreateDiscLabels - Refine the labels which define field and discrete system regions on the transformed `DM`

2216:   Not Collective

2218:   Input Parameters:
2219: + tr  - The `DMPlexTransform`
2220: - rdm - The refined `DM` produced by the transform

2222:   Level: developer

2224:   Note:
2225:   Region labels attached to fields (see `DMSetField()`) and to discrete systems (see `DMSetRegionNumDS()`) are
2226:   not automatically included in the list of `DM` labels, so this routine walks each field and each `PetscDS`
2227:   and updates the labels to refer to the refined points.

2229: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMSetField()`, `DMSetRegionNumDS()`
2230: @*/
2231: /* This refines the labels which define regions for fields and DSes since they are not in the list of labels for the DM */
2232: PetscErrorCode DMPlexTransformCreateDiscLabels(DMPlexTransform tr, DM rdm)
2233: {
2234:   DM       dm;
2235:   PetscInt Nf, f, Nds, s;

2237:   PetscFunctionBegin;
2238:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2239:   PetscCall(DMGetNumFields(dm, &Nf));
2240:   for (f = 0; f < Nf; ++f) {
2241:     DMLabel     label, labelNew;
2242:     PetscObject obj;
2243:     const char *lname;

2245:     PetscCall(DMGetField(rdm, f, &label, &obj));
2246:     if (!label) continue;
2247:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
2248:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew));
2249:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
2250:     PetscCall(DMSetField_Internal(rdm, f, labelNew, obj));
2251:     PetscCall(DMLabelDestroy(&labelNew));
2252:   }
2253:   PetscCall(DMGetNumDS(dm, &Nds));
2254:   for (s = 0; s < Nds; ++s) {
2255:     DMLabel     label, labelNew;
2256:     const char *lname;

2258:     PetscCall(DMGetRegionNumDS(rdm, s, &label, NULL, NULL, NULL));
2259:     if (!label) continue;
2260:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
2261:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew));
2262:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
2263:     PetscCall(DMSetRegionNumDS(rdm, s, labelNew, NULL, NULL, NULL));
2264:     PetscCall(DMLabelDestroy(&labelNew));
2265:   }
2266:   PetscFunctionReturn(PETSC_SUCCESS);
2267: }

2269: static PetscErrorCode DMPlexTransformCreateSF(DMPlexTransform tr, DM rdm)
2270: {
2271:   DM                 dm;
2272:   PetscSF            sf, sfNew;
2273:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
2274:   const PetscInt    *localPoints;
2275:   const PetscSFNode *remotePoints;
2276:   PetscInt          *localPointsNew;
2277:   PetscSFNode       *remotePointsNew;
2278:   PetscInt           pStartNew, pEndNew, pNew;
2279:   /* Brute force algorithm */
2280:   PetscSF         rsf;
2281:   PetscSection    s;
2282:   const PetscInt *rootdegree;
2283:   PetscInt       *rootPointsNew, *remoteOffsets;
2284:   PetscInt        numPointsNew, pStart, pEnd, p;

2286:   PetscFunctionBegin;
2287:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2288:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0));
2289:   PetscCall(DMPlexGetChart(rdm, &pStartNew, &pEndNew));
2290:   PetscCall(DMGetPointSF(dm, &sf));
2291:   PetscCall(DMGetPointSF(rdm, &sfNew));
2292:   /* Calculate size of new SF */
2293:   PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints));
2294:   if (numRoots < 0) {
2295:     PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0));
2296:     PetscFunctionReturn(PETSC_SUCCESS);
2297:   }
2298:   for (l = 0; l < numLeaves; ++l) {
2299:     const PetscInt  p = localPoints ? localPoints[l] : l;
2300:     DMPolytopeType  ct;
2301:     DMPolytopeType *rct;
2302:     PetscInt       *rsize, *rcone, *rornt;
2303:     PetscInt        Nct, n;

2305:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2306:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2307:     for (n = 0; n < Nct; ++n) numLeavesNew += rsize[n];
2308:   }
2309:   /* Send new root point numbers
2310:        It is possible to optimize for regular transforms by sending only the cell type offsets, but it seems a needless complication
2311:   */
2312:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
2313:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &s));
2314:   PetscCall(PetscSectionSetChart(s, pStart, pEnd));
2315:   for (p = pStart; p < pEnd; ++p) {
2316:     DMPolytopeType  ct;
2317:     DMPolytopeType *rct;
2318:     PetscInt       *rsize, *rcone, *rornt;
2319:     PetscInt        Nct, n;

2321:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2322:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2323:     for (n = 0; n < Nct; ++n) PetscCall(PetscSectionAddDof(s, p, rsize[n]));
2324:   }
2325:   PetscCall(PetscSectionSetUp(s));
2326:   PetscCall(PetscSectionGetStorageSize(s, &numPointsNew));
2327:   PetscCall(PetscSFCreateRemoteOffsets(sf, s, s, &remoteOffsets));
2328:   PetscCall(PetscSFCreateSectionSF(sf, s, remoteOffsets, s, &rsf));
2329:   PetscCall(PetscFree(remoteOffsets));
2330:   PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree));
2331:   PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree));
2332:   PetscCall(PetscMalloc1(numPointsNew, &rootPointsNew));
2333:   for (p = 0; p < numPointsNew; ++p) rootPointsNew[p] = -1;
2334:   for (p = pStart; p < pEnd; ++p) {
2335:     DMPolytopeType  ct;
2336:     DMPolytopeType *rct;
2337:     PetscInt       *rsize, *rcone, *rornt;
2338:     PetscInt        Nct, n, r, off;

2340:     if (!rootdegree[p - pStart]) continue;
2341:     PetscCall(PetscSectionGetOffset(s, p, &off));
2342:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2343:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2344:     for (n = 0, m = 0; n < Nct; ++n) {
2345:       for (r = 0; r < rsize[n]; ++r, ++m) {
2346:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
2347:         rootPointsNew[off + m] = pNew;
2348:       }
2349:     }
2350:   }
2351:   PetscCall(PetscSFBcastBegin(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE));
2352:   PetscCall(PetscSFBcastEnd(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE));
2353:   PetscCall(PetscSFDestroy(&rsf));
2354:   PetscCall(PetscMalloc1(numLeavesNew, &localPointsNew));
2355:   PetscCall(PetscMalloc1(numLeavesNew, &remotePointsNew));
2356:   for (l = 0, m = 0; l < numLeaves; ++l) {
2357:     const PetscInt  p = localPoints ? localPoints[l] : l;
2358:     DMPolytopeType  ct;
2359:     DMPolytopeType *rct;
2360:     PetscInt       *rsize, *rcone, *rornt;
2361:     PetscInt        Nct, n, r, q, off;

2363:     PetscCall(PetscSectionGetOffset(s, p, &off));
2364:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2365:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2366:     for (n = 0, q = 0; n < Nct; ++n) {
2367:       for (r = 0; r < rsize[n]; ++r, ++m, ++q) {
2368:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
2369:         localPointsNew[m]        = pNew;
2370:         remotePointsNew[m].index = rootPointsNew[off + q];
2371:         remotePointsNew[m].rank  = remotePoints[l].rank;
2372:       }
2373:     }
2374:   }
2375:   PetscCall(PetscSectionDestroy(&s));
2376:   PetscCall(PetscFree(rootPointsNew));
2377:   /* SF needs sorted leaves to correctly calculate Gather */
2378:   {
2379:     PetscSFNode *rp, *rtmp;
2380:     PetscInt    *lp, *idx, *ltmp, i;

2382:     PetscCall(PetscMalloc1(numLeavesNew, &idx));
2383:     PetscCall(PetscMalloc1(numLeavesNew, &lp));
2384:     PetscCall(PetscMalloc1(numLeavesNew, &rp));
2385:     for (i = 0; i < numLeavesNew; ++i) {
2386:       PetscCheck(!(localPointsNew[i] < pStartNew) && !(localPointsNew[i] >= pEndNew), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local SF point %" PetscInt_FMT " (%" PetscInt_FMT ") not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", localPointsNew[i], i, pStartNew, pEndNew);
2387:       idx[i] = i;
2388:     }
2389:     PetscCall(PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx));
2390:     for (i = 0; i < numLeavesNew; ++i) {
2391:       lp[i] = localPointsNew[idx[i]];
2392:       rp[i] = remotePointsNew[idx[i]];
2393:     }
2394:     ltmp            = localPointsNew;
2395:     localPointsNew  = lp;
2396:     rtmp            = remotePointsNew;
2397:     remotePointsNew = rp;
2398:     PetscCall(PetscFree(idx));
2399:     PetscCall(PetscFree(ltmp));
2400:     PetscCall(PetscFree(rtmp));
2401:   }
2402:   PetscCall(PetscSFSetGraph(sfNew, pEndNew - pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER));
2403:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0));
2404:   if (PetscDefined(USE_DEBUG)) {
2405:     PetscInt overlap;

2407:     // Need to set overlap because some transforms put cells in the overlap
2408:     PetscCall(DMPlexGetOverlap(rdm, &overlap));
2409:     PetscCall(DMPlexSetOverlap(rdm, NULL, 1));
2410:     PetscCall(DMPlexCheckPointSF(rdm, sfNew, PETSC_FALSE));
2411:     PetscCall(DMPlexSetOverlap(rdm, NULL, overlap));
2412:   }
2413:   PetscFunctionReturn(PETSC_SUCCESS);
2414: }

2416: /*
2417:   DMPlexCellRefinerMapLocalizedCoordinates - Given a cell of `DMPolytopeType` `ct` with localized coordinates `x`, generate localized coordinates `xr` for subcell `r` of type `rct`.

2419:   Not Collective

2421:   Input Parameters:
2422: + tr  - The `DMPlexTransform`
2423: . ct  - The type of the parent cell
2424: . rct - The type of the produced cell
2425: . r   - The index of the produced cell
2426: - x   - The localized coordinates for the parent cell

2428:   Output Parameter:
2429: . xr  - The localized coordinates for the produced cell

2431:   Level: developer

2433: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexCellRefinerSetCoordinates()`
2434: */
2435: static PetscErrorCode DMPlexTransformMapLocalizedCoordinates(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, const PetscScalar x[], PetscScalar xr[])
2436: {
2437:   PetscFE  fe = NULL;
2438:   PetscInt cdim, v, *subcellV;

2440:   PetscFunctionBegin;
2441:   PetscCall(DMPlexTransformGetCoordinateFE(tr, ct, &fe));
2442:   PetscCall(DMPlexTransformGetSubcellVertices(tr, ct, rct, r, &subcellV));
2443:   PetscCall(PetscFEGetNumComponents(fe, &cdim));
2444:   for (v = 0; v < DMPolytopeTypeGetNumVertices(rct); ++v) PetscCall(PetscFEInterpolate_Static(fe, x, tr->refGeom[ct], subcellV[v], &xr[v * cdim]));
2445:   PetscFunctionReturn(PETSC_SUCCESS);
2446: }

2448: static PetscErrorCode DMPlexTransformSetCoordinates(DMPlexTransform tr, DM rdm)
2449: {
2450:   DM                 dm, cdm, cdmCell, cdmNew, cdmCellNew;
2451:   PetscSection       coordSection, coordSectionNew, coordSectionCell, coordSectionCellNew;
2452:   Vec                coordsLocal, coordsLocalNew, coordsLocalCell = NULL, coordsLocalCellNew;
2453:   const PetscScalar *coords;
2454:   PetscScalar       *coordsNew;
2455:   const PetscReal   *maxCell, *Lstart, *L;
2456:   PetscBool          localized, localizeVertices = PETSC_FALSE, localizeCells = PETSC_FALSE, sparseLocalize;
2457:   PetscInt           dE, dEo, d, cStart, cEnd, c, cStartNew, cEndNew, vStartNew, vEndNew, v, pStart, pEnd, p;

2459:   PetscFunctionBegin;
2460:   // Need to clear the DMField for coordinates
2461:   PetscCall(DMSetCoordinateField(rdm, NULL));
2462:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2463:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetCoordinates, tr, dm, 0, 0));
2464:   PetscCall(DMGetCoordinateDM(dm, &cdm));
2465:   PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
2466:   PetscCall(DMGetCoordinatesLocalized(dm, &localized));
2467:   PetscCall(DMGetSparseLocalize(dm, &sparseLocalize));
2468:   PetscCall(DMSetSparseLocalize(rdm, sparseLocalize));
2469:   PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
2470:   if (localized) {
2471:     /* Localize coordinates of new vertices */
2472:     localizeVertices = PETSC_TRUE;
2473:     /* If we do not have a mechanism for automatically localizing cell coordinates, we need to compute them explicitly for every divided cell */
2474:     if (!maxCell) localizeCells = PETSC_TRUE;
2475:   }
2476:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
2477:   PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &dEo));
2478:   PetscCall(DMGetCoordinateDim(rdm, &dE));
2479:   if (maxCell) {
2480:     PetscReal *LstartNew, *LNew, *maxCellNew;

2482:     PetscCall(PetscMalloc3(dE, &LstartNew, dE, &LNew, dE, &maxCellNew));
2483:     for (d = 0; d < dEo; ++d) {
2484:       LstartNew[d]  = Lstart[d];
2485:       LNew[d]       = L[d];
2486:       maxCellNew[d] = maxCell[d] / tr->redFactor;
2487:     }
2488:     for (d = dEo; d < dE; ++d) {
2489:       LstartNew[d]  = 0.;
2490:       LNew[d]       = -1.;
2491:       maxCellNew[d] = -1.;
2492:     }
2493:     PetscCall(DMSetPeriodicity(rdm, maxCellNew, LstartNew, LNew));
2494:     PetscCall(PetscFree3(LstartNew, LNew, maxCellNew));
2495:   }
2496:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionNew));
2497:   PetscCall(PetscSectionSetNumFields(coordSectionNew, 1));
2498:   PetscCall(PetscSectionSetFieldComponents(coordSectionNew, 0, dE));
2499:   PetscCall(DMPlexGetDepthStratum(rdm, 0, &vStartNew, &vEndNew));
2500:   PetscCall(PetscSectionSetChart(coordSectionNew, vStartNew, vEndNew));
2501:   /* Localization should be inherited */
2502:   /*   Stefano calculates parent cells for each new cell for localization */
2503:   /*   Localized cells need coordinates of closure */
2504:   for (v = vStartNew; v < vEndNew; ++v) {
2505:     PetscCall(PetscSectionSetDof(coordSectionNew, v, dE));
2506:     PetscCall(PetscSectionSetFieldDof(coordSectionNew, v, 0, dE));
2507:   }
2508:   PetscCall(PetscSectionSetUp(coordSectionNew));
2509:   PetscCall(DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew));

2511:   if (localizeCells) {
2512:     PetscCall(DMGetCoordinateDM(rdm, &cdmNew));
2513:     PetscCall(DMClone(cdmNew, &cdmCellNew));
2514:     PetscCall(DMSetCellCoordinateDM(rdm, cdmCellNew));
2515:     PetscCall(DMDestroy(&cdmCellNew));

2517:     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionCellNew));
2518:     PetscCall(PetscSectionSetNumFields(coordSectionCellNew, 1));
2519:     PetscCall(PetscSectionSetFieldComponents(coordSectionCellNew, 0, dE));
2520:     PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStartNew, &cEndNew));
2521:     PetscCall(PetscSectionSetChart(coordSectionCellNew, cStartNew, cEndNew));

2523:     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
2524:     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2525:     for (c = cStart; c < cEnd; ++c) {
2526:       PetscInt dof;

2528:       PetscCall(PetscSectionGetDof(coordSectionCell, c, &dof));
2529:       if (dof) {
2530:         DMPolytopeType  ct;
2531:         DMPolytopeType *rct;
2532:         PetscInt       *rsize, *rcone, *rornt;
2533:         PetscInt        dim, cNew, Nct, n, r;

2535:         PetscCall(DMPlexGetCellType(dm, c, &ct));
2536:         dim = DMPolytopeTypeGetDim(ct);
2537:         PetscCall(DMPlexTransformCellTransform(tr, ct, c, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2538:         /* This allows for different cell types */
2539:         for (n = 0; n < Nct; ++n) {
2540:           if (dim != DMPolytopeTypeGetDim(rct[n])) continue;
2541:           for (r = 0; r < rsize[n]; ++r) {
2542:             PetscInt *closure = NULL;
2543:             PetscInt  clSize, cl, Nv = 0;

2545:             PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], c, r, &cNew));
2546:             PetscCall(DMPlexGetTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure));
2547:             for (cl = 0; cl < clSize * 2; cl += 2) {
2548:               if ((closure[cl] >= vStartNew) && (closure[cl] < vEndNew)) ++Nv;
2549:             }
2550:             PetscCall(DMPlexRestoreTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure));
2551:             PetscCall(PetscSectionSetDof(coordSectionCellNew, cNew, Nv * dE));
2552:             PetscCall(PetscSectionSetFieldDof(coordSectionCellNew, cNew, 0, Nv * dE));
2553:           }
2554:         }
2555:       }
2556:     }
2557:     PetscCall(PetscSectionSetUp(coordSectionCellNew));
2558:     PetscCall(DMSetCellCoordinateSection(rdm, PETSC_DETERMINE, coordSectionCellNew));
2559:   }
2560:   PetscCall(DMViewFromOptions(dm, NULL, "-coarse_dm_view"));
2561:   {
2562:     VecType     vtype;
2563:     PetscInt    coordSizeNew, bs;
2564:     const char *name;

2566:     PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
2567:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalNew));
2568:     PetscCall(PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew));
2569:     PetscCall(VecSetSizes(coordsLocalNew, coordSizeNew, PETSC_DETERMINE));
2570:     PetscCall(PetscObjectGetName((PetscObject)coordsLocal, &name));
2571:     PetscCall(PetscObjectSetName((PetscObject)coordsLocalNew, name));
2572:     PetscCall(VecGetBlockSize(coordsLocal, &bs));
2573:     PetscCall(VecSetBlockSize(coordsLocalNew, dEo == dE ? bs : dE));
2574:     PetscCall(VecGetType(coordsLocal, &vtype));
2575:     PetscCall(VecSetType(coordsLocalNew, vtype));
2576:   }
2577:   PetscCall(VecGetArrayRead(coordsLocal, &coords));
2578:   PetscCall(VecGetArray(coordsLocalNew, &coordsNew));
2579:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
2580:   /* First set coordinates for vertices */
2581:   for (p = pStart; p < pEnd; ++p) {
2582:     DMPolytopeType  ct;
2583:     DMPolytopeType *rct;
2584:     PetscInt       *rsize, *rcone, *rornt;
2585:     PetscInt        Nct, n, r;
2586:     PetscBool       hasVertex = PETSC_FALSE;

2588:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2589:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2590:     for (n = 0; n < Nct; ++n) {
2591:       if (rct[n] == DM_POLYTOPE_POINT) {
2592:         hasVertex = PETSC_TRUE;
2593:         break;
2594:       }
2595:     }
2596:     if (hasVertex) {
2597:       const PetscScalar *icoords = NULL;
2598:       const PetscScalar *array   = NULL;
2599:       PetscScalar       *pcoords = NULL;
2600:       PetscBool          isDG;
2601:       PetscInt           Nc, Nv, v, d;

2603:       PetscCall(DMPlexGetCellCoordinates(dm, p, &isDG, &Nc, &array, &pcoords));

2605:       icoords = pcoords;
2606:       Nv      = Nc / dEo;
2607:       if (ct != DM_POLYTOPE_POINT) {
2608:         if (localizeVertices && maxCell) {
2609:           PetscScalar anchor[3];

2611:           for (d = 0; d < dEo; ++d) anchor[d] = pcoords[d];
2612:           for (v = 0; v < Nv; ++v) PetscCall(DMLocalizeCoordinate_Internal(dm, dEo, anchor, &pcoords[v * dEo], &pcoords[v * dEo]));
2613:         }
2614:       }
2615:       for (n = 0; n < Nct; ++n) {
2616:         if (rct[n] != DM_POLYTOPE_POINT) continue;
2617:         for (r = 0; r < rsize[n]; ++r) {
2618:           PetscScalar vcoords[3];
2619:           PetscInt    vNew, off;

2621:           PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &vNew));
2622:           PetscCall(PetscSectionGetOffset(coordSectionNew, vNew, &off));
2623:           PetscCall(DMPlexTransformMapCoordinates(tr, ct, rct[n], p, r, Nv, dEo, icoords, vcoords));
2624:           PetscCall(DMSnapToGeomModel(dm, p, dE, vcoords, &coordsNew[off]));
2625:         }
2626:       }
2627:       PetscCall(DMPlexRestoreCellCoordinates(dm, p, &isDG, &Nc, &array, &pcoords));
2628:     }
2629:   }
2630:   PetscCall(VecRestoreArrayRead(coordsLocal, &coords));
2631:   PetscCall(VecRestoreArray(coordsLocalNew, &coordsNew));
2632:   PetscCall(DMSetCoordinatesLocal(rdm, coordsLocalNew));
2633:   PetscCall(VecDestroy(&coordsLocalNew));
2634:   PetscCall(PetscSectionDestroy(&coordSectionNew));
2635:   /* Then set coordinates for cells by localizing */
2636:   if (!localizeCells) PetscCall(DMLocalizeCoordinates(rdm));
2637:   else {
2638:     VecType     vtype;
2639:     PetscInt    coordSizeNew, bs;
2640:     const char *name;

2642:     PetscCall(DMGetCellCoordinatesLocal(dm, &coordsLocalCell));
2643:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalCellNew));
2644:     PetscCall(PetscSectionGetStorageSize(coordSectionCellNew, &coordSizeNew));
2645:     PetscCall(VecSetSizes(coordsLocalCellNew, coordSizeNew, PETSC_DETERMINE));
2646:     PetscCall(PetscObjectGetName((PetscObject)coordsLocalCell, &name));
2647:     PetscCall(PetscObjectSetName((PetscObject)coordsLocalCellNew, name));
2648:     PetscCall(VecGetBlockSize(coordsLocalCell, &bs));
2649:     PetscCall(VecSetBlockSize(coordsLocalCellNew, dEo == dE ? bs : dE));
2650:     PetscCall(VecGetType(coordsLocalCell, &vtype));
2651:     PetscCall(VecSetType(coordsLocalCellNew, vtype));
2652:     PetscCall(VecGetArrayRead(coordsLocalCell, &coords));
2653:     PetscCall(VecGetArray(coordsLocalCellNew, &coordsNew));

2655:     for (p = pStart; p < pEnd; ++p) {
2656:       DMPolytopeType  ct;
2657:       DMPolytopeType *rct;
2658:       PetscInt       *rsize, *rcone, *rornt;
2659:       PetscInt        dof = 0, Nct, n, r;

2661:       PetscCall(DMPlexGetCellType(dm, p, &ct));
2662:       PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2663:       if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
2664:       if (dof) {
2665:         const PetscScalar *pcoords;

2667:         PetscCall(DMPlexPointLocalRead(cdmCell, p, coords, &pcoords));
2668:         for (n = 0; n < Nct; ++n) {
2669:           const PetscInt Nr = rsize[n];

2671:           if (DMPolytopeTypeGetDim(ct) != DMPolytopeTypeGetDim(rct[n])) continue;
2672:           for (r = 0; r < Nr; ++r) {
2673:             PetscInt pNew, offNew;

2675:             /* It looks like Stefano and Lisandro are allowing localized coordinates without defining the periodic boundary, which means that
2676:                DMLocalizeCoordinate_Internal() will not work. Localized coordinates will have to have obtained by the affine map of the larger
2677:                cell to the ones it produces. */
2678:             PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
2679:             PetscCall(PetscSectionGetOffset(coordSectionCellNew, pNew, &offNew));
2680:             PetscCall(DMPlexTransformMapLocalizedCoordinates(tr, ct, rct[n], r, pcoords, &coordsNew[offNew]));
2681:           }
2682:         }
2683:       }
2684:     }
2685:     PetscCall(VecRestoreArrayRead(coordsLocalCell, &coords));
2686:     PetscCall(VecRestoreArray(coordsLocalCellNew, &coordsNew));
2687:     PetscCall(DMSetCellCoordinatesLocal(rdm, coordsLocalCellNew));
2688:     PetscCall(VecDestroy(&coordsLocalCellNew));
2689:     PetscCall(PetscSectionDestroy(&coordSectionCellNew));
2690:   }
2691:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetCoordinates, tr, dm, 0, 0));
2692:   PetscFunctionReturn(PETSC_SUCCESS);
2693: }

2695: /*@
2696:   DMPlexTransformApply - Execute the transformation, producing another `DM`

2698:   Collective

2700:   Input Parameters:
2701: + tr - The `DMPlexTransform` object
2702: - dm - The original `DM`

2704:   Output Parameter:
2705: . trdm - The transformed `DM`

2707:   Level: intermediate

2709:   Options Database Keys:
2710: + -dm_plex_transform_label_match_strata    - Only label points of the same stratum as the producing point
2711: . -dm_plex_transform_label_replica_inc num - Increment for the label value to be multiplied by the replica number
2712: - -dm_plex_transform_active name           - Name for active mesh label

2714: .seealso: [](plex_transform_table), [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformCreate()`, `DMPlexTransformSetDM()`
2715: @*/
2716: PetscErrorCode DMPlexTransformApply(DMPlexTransform tr, DM dm, DM *trdm)
2717: {
2718:   DM                     rdm;
2719:   DMPlexInterpolatedFlag interp;
2720:   PetscInt               pStart, pEnd;

2722:   PetscFunctionBegin;
2725:   PetscAssertPointer(trdm, 3);
2726:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_Apply, tr, dm, 0, 0));
2727:   PetscCall(DMPlexTransformSetDM(tr, dm));

2729:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &rdm));
2730:   PetscCall(DMSetType(rdm, DMPLEX));
2731:   PetscCall(DMPlexTransformSetDimensions(tr, dm, rdm));
2732:   /* Calculate number of new points of each depth */
2733:   PetscCall(DMPlexIsInterpolatedCollective(dm, &interp));
2734:   PetscCheck(interp == DMPLEX_INTERPOLATED_FULL, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be fully interpolated for regular refinement");
2735:   /* Step 1: Set chart */
2736:   PetscCall(DMPlexTransformGetChart(tr, &pStart, &pEnd));
2737:   PetscCall(DMPlexSetChart(rdm, pStart, pEnd));
2738:   /* Step 2: Set cone/support sizes (automatically stratifies) */
2739:   PetscCall(DMPlexTransformSetConeSizes(tr, rdm));
2740:   /* Step 3: Setup refined DM */
2741:   PetscCall(DMSetUp(rdm));
2742:   /* Step 4: Set cones and supports (automatically symmetrizes) */
2743:   PetscCall(DMPlexTransformSetCones(tr, rdm));
2744:   /* Step 5: Create pointSF */
2745:   PetscCall(DMPlexTransformCreateSF(tr, rdm));
2746:   /* Step 6: Create labels */
2747:   PetscCall(DMPlexTransformCreateLabels(tr, rdm));
2748:   /* Step 7: Set coordinates */
2749:   PetscCall(DMPlexTransformSetCoordinates(tr, rdm));
2750:   //   Do not copy periodicity, which was handled in DMPlexTransformSetCoordinates()
2751:   PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_TRUE, rdm));
2752:   // If the original DM was configured from options, the transformed DM should be as well
2753:   rdm->setfromoptionscalled = dm->setfromoptionscalled;
2754:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_Apply, tr, dm, 0, 0));
2755:   *trdm = rdm;
2756:   PetscFunctionReturn(PETSC_SUCCESS);
2757: }

2759: /*@
2760:   DMPlexTransformAdaptLabel - Adapt a `DMPLEX` using a `DMPlexTransform` driven by a `DMLabel` marking cells to be refined or coarsened.

2762:   Collective

2764:   Input Parameters:
2765: + dm         - the input `DMPLEX`
2766: . metric     - unused; present to conform to the `DMAdaptor` label-based interface
2767: . adaptLabel - a `DMLabel` marking cells with `DM_ADAPT_REFINE`, `DM_ADAPT_COARSEN`, etc.
2768: - rgLabel    - unused region-tag label; present to conform to the `DMAdaptor` interface

2770:   Output Parameter:
2771: . rdm - the adapted `DMPLEX`

2773:   Level: developer

2775:   Note:
2776:   This routine is registered as the "cellrefiner" adaptor by `DMGenerateRegisterAll()` and is invoked through `DMAdaptLabel()`.

2778: .seealso: `DMPLEX`, `DMPlexTransform`, `DMAdaptLabel()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`, `DMLabel`
2779: @*/
2780: PetscErrorCode DMPlexTransformAdaptLabel(DM dm, PETSC_UNUSED Vec metric, DMLabel adaptLabel, PETSC_UNUSED DMLabel rgLabel, DM *rdm)
2781: {
2782:   DMPlexTransform tr;
2783:   DM              cdm, rcdm;
2784:   const char     *prefix;
2785:   PetscBool       save;

2787:   PetscFunctionBegin;
2788:   PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr));
2789:   PetscCall(PetscObjectSetName((PetscObject)tr, "Adapt Label Transform"));
2790:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
2791:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix));
2792:   PetscCall(DMPlexTransformSetDM(tr, dm));
2793:   PetscCall(DMPlexTransformSetFromOptions(tr));
2794:   if (adaptLabel) PetscCall(DMPlexTransformSetActive(tr, adaptLabel));
2795:   PetscCall(DMPlexTransformSetUp(tr));
2796:   PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_transform_view"));
2797:   PetscCall(DMPlexTransformApply(tr, dm, rdm));
2798:   PetscCall(DMCopyDisc(dm, *rdm));
2799:   PetscCall(DMGetCoordinateDM(dm, &cdm));
2800:   PetscCall(DMGetCoordinateDM(*rdm, &rcdm));
2801:   PetscCall(DMCopyDisc(cdm, rcdm));
2802:   PetscCall(DMPlexTransformCreateDiscLabels(tr, *rdm));
2803:   PetscCall(DMCopyDisc(dm, *rdm));
2804:   PetscCall(DMPlexGetSaveTransform(dm, &save));
2805:   if (save) PetscCall(DMPlexSetTransform(*rdm, tr));
2806:   PetscCall(DMPlexTransformDestroy(&tr));
2807:   ((DM_Plex *)(*rdm)->data)->useHashLocation = ((DM_Plex *)dm->data)->useHashLocation;
2808:   PetscFunctionReturn(PETSC_SUCCESS);
2809: }