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: /*@C
 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: /*@C
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: /*@C
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:   PetscCall(PetscCalloc2(DM_NUM_POLYTOPES, &t->coordFE, DM_NUM_POLYTOPES, &t->refGeom));
174:   *tr = t;
175:   PetscFunctionReturn(PETSC_SUCCESS);
176: }

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

181:   Collective

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

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

190:   Level: intermediate

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

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

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

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

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

218:   Not Collective

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

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

226:   Level: intermediate

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

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

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

252:     if (tr->trType) PetscCall(DMLabelView(tr->trType, v));
253:     PetscCall(PetscViewerASCIIPrintf(v, "Source Starts\n"));
254:     for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14s", DMPolytopeTypes[g]));
255:     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
256:     for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIIPrintf(v, " %14" PetscInt_FMT, tr->ctStart[f]));
257:     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
258:     PetscCall(PetscViewerASCIIPrintf(v, "Target Starts\n"));
259:     for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14s", DMPolytopeTypes[g]));
260:     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
261:     for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIIPrintf(v, " %14" PetscInt_FMT, tr->ctStartNew[f]));
262:     PetscCall(PetscViewerASCIIPrintf(v, "\n"));

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

286: /*@
287:   DMPlexTransformView - Views a `DMPlexTransform`

289:   Collective

291:   Input Parameters:
292: + tr - the `DMPlexTransform` object to view
293: - v  - the viewer

295:   Level: beginner

297: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `PetscViewer`, `DMPlexTransformDestroy()`, `DMPlexTransformCreate()`
298: @*/
299: PetscErrorCode DMPlexTransformView(DMPlexTransform tr, PetscViewer v)
300: {
301:   PetscBool isascii;

303:   PetscFunctionBegin;
305:   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)tr), &v));
307:   PetscCheckSameComm(tr, 1, v, 2);
308:   PetscCall(PetscViewerCheckWritable(v));
309:   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)tr, v));
310:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &isascii));
311:   if (isascii) PetscCall(DMPlexTransformView_Ascii(tr, v));
312:   PetscTryTypeMethod(tr, view, v);
313:   PetscFunctionReturn(PETSC_SUCCESS);
314: }

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

319:   Collective

321:   Input Parameter:
322: . tr - the `DMPlexTransform` object to set options for

324:   Options Database Keys:
325: + -dm_plex_transform_type type               - Set the transform type, e.g. refine_regular
326: . -dm_plex_transform_label_match_strata      - Only label points of the same stratum as the producing point
327: . -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
328: . -dm_plex_transform_active name             - Name for active mesh label
329: - -dm_plex_transform_active_values v0,v1,... - Values in the active label

331:   Level: intermediate

333: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()`
334: @*/
335: PetscErrorCode DMPlexTransformSetFromOptions(DMPlexTransform tr)
336: {
337:   char        typeName[1024], active[PETSC_MAX_PATH_LEN];
338:   const char *defName = DMPLEXREFINEREGULAR;
339:   PetscBool   flg, match;

341:   PetscFunctionBegin;
343:   PetscObjectOptionsBegin((PetscObject)tr);
344:   PetscCall(PetscOptionsFList("-dm_plex_transform_type", "DMPlexTransform", "DMPlexTransformSetType", DMPlexTransformList, defName, typeName, 1024, &flg));
345:   if (flg) PetscCall(DMPlexTransformSetType(tr, typeName));
346:   else if (!((PetscObject)tr)->type_name) PetscCall(DMPlexTransformSetType(tr, defName));
347:   PetscCall(PetscOptionsBool("-dm_plex_transform_label_match_strata", "Only label points of the same stratum as the producing point", "", tr->labelMatchStrata, &match, &flg));
348:   if (flg) PetscCall(DMPlexTransformSetMatchStrata(tr, match));
349:   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));
350:   PetscCall(PetscOptionsString("-dm_plex_transform_active", "Name for active mesh label", "DMPlexTransformSetActive", active, active, sizeof(active), &flg));
351:   if (flg) {
352:     DM       dm;
353:     DMLabel  label;
354:     PetscInt values[16];
355:     PetscInt n = 16;

357:     PetscCall(DMPlexTransformGetDM(tr, &dm));
358:     PetscCall(DMGetLabel(dm, active, &label));
359:     PetscCall(PetscOptionsIntArray("-dm_plex_transform_active_values", "The label values to be active", "DMPlexTransformSetActive", values, &n, &flg));
360:     if (flg && n) {
361:       DMLabel newlabel;

363:       PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Active", &newlabel));
364:       for (PetscInt i = 0; i < n; ++i) {
365:         IS is;

367:         PetscCall(DMLabelGetStratumIS(label, values[i], &is));
368:         PetscCall(DMLabelInsertIS(newlabel, is, values[i]));
369:         PetscCall(ISDestroy(&is));
370:       }
371:       PetscCall(DMPlexTransformSetActive(tr, newlabel));
372:       PetscCall(DMLabelDestroy(&newlabel));
373:     } else {
374:       PetscCall(DMPlexTransformSetActive(tr, label));
375:     }
376:   }
377:   PetscTryTypeMethod(tr, setfromoptions, PetscOptionsObject);
378:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
379:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)tr, PetscOptionsObject));
380:   PetscOptionsEnd();
381:   PetscFunctionReturn(PETSC_SUCCESS);
382: }

384: /*@
385:   DMPlexTransformDestroy - Destroys a `DMPlexTransform`

387:   Collective

389:   Input Parameter:
390: . tr - the transform object to destroy

392:   Level: beginner

394: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()`
395: @*/
396: PetscErrorCode DMPlexTransformDestroy(DMPlexTransform *tr)
397: {
398:   PetscInt c;

400:   PetscFunctionBegin;
401:   if (!*tr) PetscFunctionReturn(PETSC_SUCCESS);
403:   if (--((PetscObject)*tr)->refct > 0) {
404:     *tr = NULL;
405:     PetscFunctionReturn(PETSC_SUCCESS);
406:   }

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

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

445: static PetscErrorCode DMPlexTransformCreateOffset_Internal(DMPlexTransform tr, PetscInt ctOrderOld[], PetscInt ctStart[], PetscInt **offset)
446: {
447:   DMLabel  trType = tr->trType;
448:   PetscInt c, cN, *off;

450:   PetscFunctionBegin;
451:   if (trType) {
452:     DM              dm;
453:     IS              rtIS;
454:     const PetscInt *reftypes;
455:     PetscInt        Nrt, r;

457:     PetscCall(DMPlexTransformGetDM(tr, &dm));
458:     PetscCall(DMLabelGetNumValues(trType, &Nrt));
459:     PetscCall(DMLabelGetValueIS(trType, &rtIS));
460:     PetscCall(ISGetIndices(rtIS, &reftypes));
461:     PetscCall(PetscCalloc1(Nrt * DM_NUM_POLYTOPES, &off));
462:     for (r = 0; r < Nrt; ++r) {
463:       const PetscInt  rt = reftypes[r];
464:       IS              rtIS;
465:       const PetscInt *points;
466:       DMPolytopeType  ct;
467:       PetscInt        np, p;

469:       PetscCall(DMLabelGetStratumIS(trType, rt, &rtIS));
470:       PetscCall(ISGetLocalSize(rtIS, &np));
471:       PetscCall(ISGetIndices(rtIS, &points));
472:       if (!np) continue;
473:       p = points[0];
474:       PetscCall(ISRestoreIndices(rtIS, &points));
475:       PetscCall(ISDestroy(&rtIS));
476:       PetscCall(DMPlexGetCellType(dm, p, &ct));
477:       for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) {
478:         const DMPolytopeType ctNew = (DMPolytopeType)cN;
479:         DMPolytopeType      *rct;
480:         PetscInt            *rsize, *cone, *ornt;
481:         PetscInt             Nct, n, s;

483:         if (DMPolytopeTypeGetDim(ct) < 0 || DMPolytopeTypeGetDim(ctNew) < 0) {
484:           off[r * DM_NUM_POLYTOPES + ctNew] = -1;
485:           break;
486:         }
487:         off[r * DM_NUM_POLYTOPES + ctNew] = 0;
488:         for (s = 0; s <= r; ++s) {
489:           const PetscInt st = reftypes[s];
490:           DMPolytopeType sct;
491:           PetscInt       q, qrt;

493:           PetscCall(DMLabelGetStratumIS(trType, st, &rtIS));
494:           PetscCall(ISGetLocalSize(rtIS, &np));
495:           PetscCall(ISGetIndices(rtIS, &points));
496:           if (!np) continue;
497:           q = points[0];
498:           PetscCall(ISRestoreIndices(rtIS, &points));
499:           PetscCall(ISDestroy(&rtIS));
500:           PetscCall(DMPlexGetCellType(dm, q, &sct));
501:           PetscCall(DMPlexTransformCellTransform(tr, sct, q, &qrt, &Nct, &rct, &rsize, &cone, &ornt));
502:           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);
503:           if (st == rt) {
504:             for (n = 0; n < Nct; ++n)
505:               if (rct[n] == ctNew) break;
506:             if (n == Nct) off[r * DM_NUM_POLYTOPES + ctNew] = -1;
507:             break;
508:           }
509:           for (n = 0; n < Nct; ++n) {
510:             if (rct[n] == ctNew) {
511:               PetscInt sn;

513:               PetscCall(DMLabelGetStratumSize(trType, st, &sn));
514:               off[r * DM_NUM_POLYTOPES + ctNew] += sn * rsize[n];
515:             }
516:           }
517:         }
518:       }
519:     }
520:     PetscCall(ISRestoreIndices(rtIS, &reftypes));
521:     PetscCall(ISDestroy(&rtIS));
522:   } else {
523:     PetscCall(PetscCalloc1(DM_NUM_POLYTOPES * DM_NUM_POLYTOPES, &off));
524:     for (c = DM_POLYTOPE_POINT; c < DM_NUM_POLYTOPES; ++c) {
525:       const DMPolytopeType ct = (DMPolytopeType)c;
526:       for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) {
527:         const DMPolytopeType ctNew = (DMPolytopeType)cN;
528:         DMPolytopeType      *rct;
529:         PetscInt            *rsize, *cone, *ornt;
530:         PetscInt             Nct, n, i;

532:         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) {
533:           off[ct * DM_NUM_POLYTOPES + ctNew] = -1;
534:           continue;
535:         }
536:         off[ct * DM_NUM_POLYTOPES + ctNew] = 0;
537:         for (i = DM_POLYTOPE_POINT; i < DM_NUM_POLYTOPES; ++i) {
538:           const DMPolytopeType ict  = (DMPolytopeType)ctOrderOld[i];
539:           const DMPolytopeType ictn = (DMPolytopeType)ctOrderOld[i + 1];

541:           PetscCall(DMPlexTransformCellTransform(tr, ict, PETSC_DETERMINE, NULL, &Nct, &rct, &rsize, &cone, &ornt));
542:           if (ict == ct) {
543:             for (n = 0; n < Nct; ++n)
544:               if (rct[n] == ctNew) break;
545:             if (n == Nct) off[ct * DM_NUM_POLYTOPES + ctNew] = -1;
546:             break;
547:           }
548:           for (n = 0; n < Nct; ++n)
549:             if (rct[n] == ctNew) off[ct * DM_NUM_POLYTOPES + ctNew] += (ctStart[ictn] - ctStart[ict]) * rsize[n];
550:         }
551:       }
552:     }
553:   }
554:   *offset = off;
555:   PetscFunctionReturn(PETSC_SUCCESS);
556: }

558: /*@
559:   DMPlexTransformSetUp - Create the tables that drive the transform

561:   Input Parameter:
562: . tr - The `DMPlexTransform` object

564:   Level: intermediate

566: .seealso: [](plex_transform_table), [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
567: @*/
568: PetscErrorCode DMPlexTransformSetUp(DMPlexTransform tr)
569: {
570:   DMPolytopeType ctCell;
571:   DM             dm;
572:   PetscInt       pStart, pEnd, p, c, celldim = 0;

574:   PetscFunctionBegin;
576:   if (tr->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
577:   PetscCall(DMPlexTransformGetDM(tr, &dm));
578:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetUp, tr, dm, 0, 0));
579:   PetscTryTypeMethod(tr, setup);
580:   PetscCall(DMSetSnapToGeomModel(dm, NULL));
581:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));

583:   if (pEnd > pStart) {
584:     // Ignore cells hanging off of embedded surfaces
585:     PetscInt c = pStart;

587:     ctCell = DM_POLYTOPE_FV_GHOST;
588:     while (DMPolytopeTypeGetDim(ctCell) < 0) PetscCall(DMPlexGetCellType(dm, c++, &ctCell));
589:   } else {
590:     PetscInt dim;

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

617:     PetscCall(DMPlexGetCellType(dm, p, &ct));
618:     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);
619:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt));
620:     for (n = 0; n < Nct; ++n) celldim = PetscMax(celldim, DMPolytopeTypeGetDim(rct[n]));
621:   }
622:   PetscCall(DMPlexCreateCellTypeOrder_Internal(NULL, celldim, &tr->ctOrderNew, &tr->ctOrderInvNew));
623:   /* Construct sizes and offsets for each cell type */
624:   if (!tr->ctStart) {
625:     PetscInt *ctS, *ctSN, *ctC, *ctCN;

627:     PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctS, DM_NUM_POLYTOPES + 1, &ctSN));
628:     PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctC, DM_NUM_POLYTOPES + 1, &ctCN));
629:     for (p = pStart; p < pEnd; ++p) {
630:       DMPolytopeType  ct;
631:       DMPolytopeType *rct;
632:       PetscInt       *rsize, *cone, *ornt;
633:       PetscInt        Nct, n;

635:       PetscCall(DMPlexGetCellType(dm, p, &ct));
636:       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);
637:       ++ctC[ct];
638:       PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt));
639:       for (n = 0; n < Nct; ++n) ctCN[rct[n]] += rsize[n];
640:     }
641:     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
642:       const PetscInt cto  = tr->ctOrderOld[c];
643:       const PetscInt cton = tr->ctOrderOld[c + 1];
644:       const PetscInt ctn  = tr->ctOrderNew[c];
645:       const PetscInt ctnn = tr->ctOrderNew[c + 1];

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

667:     if (tr->ctStartNew[tr->ctOrderNew[c + 1]] <= tr->ctStartNew[tr->ctOrderNew[c]]) continue;
668:     tr->depthStart[dep] = PetscMin(tr->depthStart[dep], tr->ctStartNew[tr->ctOrderNew[c]]);
669:     tr->depthEnd[dep]   = PetscMax(tr->depthEnd[dep], tr->ctStartNew[tr->ctOrderNew[c + 1]]);
670:   }
671:   tr->setupcalled = PETSC_TRUE;
672:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetUp, tr, dm, 0, 0));
673:   PetscFunctionReturn(PETSC_SUCCESS);
674: }

676: /*@
677:   DMPlexTransformGetDM - Get the base `DM` for the transform

679:   Input Parameter:
680: . tr - The `DMPlexTransform` object

682:   Output Parameter:
683: . dm - The original `DM` which will be transformed

685:   Level: intermediate

687: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetDM()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
688: @*/
689: PetscErrorCode DMPlexTransformGetDM(DMPlexTransform tr, DM *dm)
690: {
691:   PetscFunctionBegin;
693:   PetscAssertPointer(dm, 2);
694:   *dm = tr->dm;
695:   PetscFunctionReturn(PETSC_SUCCESS);
696: }

698: /*@
699:   DMPlexTransformSetDM - Set the base `DM` for the transform

701:   Input Parameters:
702: + tr - The `DMPlexTransform` object
703: - dm - The original `DM` which will be transformed

705:   Level: intermediate

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

710: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetDM()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
711: @*/
712: PetscErrorCode DMPlexTransformSetDM(DMPlexTransform tr, DM dm)
713: {
714:   PetscFunctionBegin;
717:   PetscCall(PetscObjectReference((PetscObject)dm));
718:   PetscCall(DMDestroy(&tr->dm));
719:   tr->dm = dm;
720:   PetscFunctionReturn(PETSC_SUCCESS);
721: }

723: /*@
724:   DMPlexTransformGetActive - Get the `DMLabel` marking the active points for the transform

726:   Input Parameter:
727: . tr - The `DMPlexTransform` object

729:   Output Parameter:
730: . active - The `DMLabel` indicating which points will be transformed

732:   Level: intermediate

734: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
735: @*/
736: PetscErrorCode DMPlexTransformGetActive(DMPlexTransform tr, DMLabel *active)
737: {
738:   PetscFunctionBegin;
740:   PetscAssertPointer(active, 2);
741:   *active = tr->active;
742:   PetscFunctionReturn(PETSC_SUCCESS);
743: }

745: /*@
746:   DMPlexTransformSetActive - Set the `DMLabel` marking the active points for the transform

748:   Input Parameters:
749: + tr     - The `DMPlexTransform` object
750: - active - The `DMLabel` indicating which points will be transformed

752:   Level: intermediate

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

757: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
758: @*/
759: PetscErrorCode DMPlexTransformSetActive(DMPlexTransform tr, DMLabel active)
760: {
761:   PetscFunctionBegin;
764:   PetscCall(PetscObjectReference((PetscObject)active));
765:   PetscCall(DMLabelDestroy(&tr->active));
766:   tr->active = active;
767:   PetscFunctionReturn(PETSC_SUCCESS);
768: }

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

773:   Input Parameter:
774: . tr - The `DMPlexTransform` object

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

779:   Level: intermediate

781: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexSetTransformType()`, `DMPlexTransformGetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
782: @*/
783: PetscErrorCode DMPlexTransformGetTransformTypes(DMPlexTransform tr, DMLabel *trType)
784: {
785:   PetscFunctionBegin;
787:   PetscAssertPointer(trType, 2);
788:   *trType = tr->trType;
789:   PetscFunctionReturn(PETSC_SUCCESS);
790: }

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

795:   Input Parameters:
796: + tr     - The `DMPlexTransform` object
797: - trType - The original `DM` which will be transformed

799:   Level: intermediate

801: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetTransformTypes()`, `DMPlexTransformGetActive())`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
802: @*/
803: PetscErrorCode DMPlexTransformSetTransformTypes(DMPlexTransform tr, DMLabel trType)
804: {
805:   PetscFunctionBegin;
808:   PetscCall(PetscObjectReference((PetscObject)trType));
809:   PetscCall(DMLabelDestroy(&tr->trType));
810:   tr->trType = trType;
811:   PetscFunctionReturn(PETSC_SUCCESS);
812: }

814: static PetscErrorCode DMPlexTransformGetCoordinateFE(DMPlexTransform tr, DMPolytopeType ct, PetscFE *fe)
815: {
816:   PetscFunctionBegin;
817:   if (!tr->coordFE[ct]) {
818:     PetscInt dim, cdim;

820:     dim = DMPolytopeTypeGetDim(ct);
821:     PetscCall(DMGetCoordinateDim(tr->dm, &cdim));
822:     PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, cdim, ct, 1, PETSC_DETERMINE, &tr->coordFE[ct]));
823:     {
824:       PetscDualSpace  dsp;
825:       PetscQuadrature quad;
826:       DM              K;
827:       PetscFEGeom    *cg;
828:       PetscScalar    *Xq;
829:       PetscReal      *xq, *wq;
830:       PetscInt        Nq, q;

832:       PetscCall(DMPlexTransformGetCellVertices(tr, ct, &Nq, &Xq));
833:       PetscCall(PetscMalloc1(Nq * cdim, &xq));
834:       for (q = 0; q < Nq * cdim; ++q) xq[q] = PetscRealPart(Xq[q]);
835:       PetscCall(PetscMalloc1(Nq, &wq));
836:       for (q = 0; q < Nq; ++q) wq[q] = 1.0;
837:       PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
838:       PetscCall(PetscQuadratureSetData(quad, dim, 1, Nq, xq, wq));
839:       PetscCall(PetscFESetQuadrature(tr->coordFE[ct], quad));

841:       PetscCall(PetscFEGetDualSpace(tr->coordFE[ct], &dsp));
842:       PetscCall(PetscDualSpaceGetDM(dsp, &K));
843:       PetscCall(PetscFEGeomCreate(quad, 1, cdim, PETSC_FEGEOM_BASIC, &tr->refGeom[ct]));
844:       cg = tr->refGeom[ct];
845:       PetscCall(DMPlexComputeCellGeometryFEM(K, 0, NULL, cg->v, cg->J, cg->invJ, cg->detJ));
846:       PetscCall(PetscQuadratureDestroy(&quad));
847:     }
848:   }
849:   *fe = tr->coordFE[ct];
850:   PetscFunctionReturn(PETSC_SUCCESS);
851: }

853: PetscErrorCode DMPlexTransformSetDimensions_Internal(DMPlexTransform tr, DM dm, DM tdm)
854: {
855:   PetscInt dim, cdim;

857:   PetscFunctionBegin;
858:   PetscCall(DMGetDimension(dm, &dim));
859:   PetscCall(DMSetDimension(tdm, dim));
860:   PetscCall(DMGetCoordinateDim(dm, &cdim));
861:   PetscCall(DMSetCoordinateDim(tdm, cdim));
862:   PetscFunctionReturn(PETSC_SUCCESS);
863: }

865: /*@
866:   DMPlexTransformSetDimensions - Set the dimensions for the transformed `DM`

868:   Input Parameters:
869: + tr - The `DMPlexTransform` object
870: - dm - The original `DM`

872:   Output Parameter:
873: . trdm - The transformed `DM`

875:   Level: advanced

877: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
878: @*/
879: PetscErrorCode DMPlexTransformSetDimensions(DMPlexTransform tr, DM dm, DM trdm)
880: {
881:   PetscFunctionBegin;
882:   PetscUseTypeMethod(tr, setdimensions, dm, trdm);
883:   PetscFunctionReturn(PETSC_SUCCESS);
884: }

886: PetscErrorCode DMPlexTransformGetChart(DMPlexTransform tr, PetscInt *pStart, PetscInt *pEnd)
887: {
888:   PetscFunctionBegin;
889:   if (pStart) *pStart = 0;
890:   if (pEnd) *pEnd = tr->ctStartNew[tr->ctOrderNew[DM_NUM_POLYTOPES]];
891:   PetscFunctionReturn(PETSC_SUCCESS);
892: }

894: PetscErrorCode DMPlexTransformGetCellType(DMPlexTransform tr, PetscInt cell, DMPolytopeType *celltype)
895: {
896:   PetscInt ctNew;

898:   PetscFunctionBegin;
900:   PetscAssertPointer(celltype, 3);
901:   /* TODO Can do bisection since everything is sorted */
902:   for (ctNew = DM_POLYTOPE_POINT; ctNew < DM_NUM_POLYTOPES; ++ctNew) {
903:     PetscInt ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]];

905:     if (cell >= ctSN && cell < ctEN) break;
906:   }
907:   PetscCheck(ctNew < DM_NUM_POLYTOPES, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " cannot be located in the transformed mesh", cell);
908:   *celltype = (DMPolytopeType)ctNew;
909:   PetscFunctionReturn(PETSC_SUCCESS);
910: }

912: PetscErrorCode DMPlexTransformGetCellTypeStratum(DMPlexTransform tr, DMPolytopeType celltype, PetscInt *start, PetscInt *end)
913: {
914:   PetscFunctionBegin;
916:   if (start) *start = tr->ctStartNew[celltype];
917:   if (end) *end = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[celltype] + 1]];
918:   PetscFunctionReturn(PETSC_SUCCESS);
919: }

921: PetscErrorCode DMPlexTransformGetDepth(DMPlexTransform tr, PetscInt *depth)
922: {
923:   PetscFunctionBegin;
925:   *depth = tr->depth;
926:   PetscFunctionReturn(PETSC_SUCCESS);
927: }

929: PetscErrorCode DMPlexTransformGetDepthStratum(DMPlexTransform tr, PetscInt depth, PetscInt *start, PetscInt *end)
930: {
931:   PetscFunctionBegin;
933:   if (start) *start = tr->depthStart[depth];
934:   if (end) *end = tr->depthEnd[depth];
935:   PetscFunctionReturn(PETSC_SUCCESS);
936: }

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

941:   Not Collective

943:   Input Parameter:
944: . tr - The `DMPlexTransform`

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

949:   Level: intermediate

951: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetMatchStrata()`, `DMPlexGetPointDepth()`
952: @*/
953: PetscErrorCode DMPlexTransformGetMatchStrata(DMPlexTransform tr, PetscBool *match)
954: {
955:   PetscFunctionBegin;
957:   PetscAssertPointer(match, 2);
958:   *match = tr->labelMatchStrata;
959:   PetscFunctionReturn(PETSC_SUCCESS);
960: }

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

965:   Not Collective

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

971:   Level: intermediate

973: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetMatchStrata()`, `DMPlexGetPointDepth()`
974: @*/
975: PetscErrorCode DMPlexTransformSetMatchStrata(DMPlexTransform tr, PetscBool match)
976: {
977:   PetscFunctionBegin;
979:   tr->labelMatchStrata = match;
980:   PetscFunctionReturn(PETSC_SUCCESS);
981: }

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

986:   Not Collective

988:   Input Parameters:
989: + tr    - The `DMPlexTransform`
990: . ct    - The type of the original point which produces the new point
991: . ctNew - The type of the new point
992: . p     - The original point which produces the new point
993: - r     - The replica number of the new point, meaning it is the rth point of type `ctNew` produced from `p`

995:   Output Parameter:
996: . pNew - The new point number

998:   Level: developer

1000: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSourcePoint()`, `DMPlexTransformCellTransform()`
1001: @*/
1002: PetscErrorCode DMPlexTransformGetTargetPoint(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType ctNew, PetscInt p, PetscInt r, PetscInt *pNew)
1003: {
1004:   DMPolytopeType *rct;
1005:   PetscInt       *rsize, *cone, *ornt;
1006:   PetscInt        rt, Nct, n, off, rp;
1007:   DMLabel         trType = tr->trType;
1008:   PetscInt        ctS = tr->ctStart[ct], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ct] + 1]];
1009:   PetscInt        ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]];
1010:   PetscInt        newp = ctSN, cind;

1012:   PetscFunctionBeginHot;
1013:   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);
1014:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, &rt, &Nct, &rct, &rsize, &cone, &ornt));
1015:   if (trType) {
1016:     PetscCall(DMLabelGetValueIndex(trType, rt, &cind));
1017:     PetscCall(DMLabelGetStratumPointIndex(trType, rt, p, &rp));
1018:     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);
1019:   } else {
1020:     cind = ct;
1021:     rp   = p - ctS;
1022:   }
1023:   off = tr->offset[cind * DM_NUM_POLYTOPES + ctNew];
1024:   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);
1025:   newp += off;
1026:   for (n = 0; n < Nct; ++n) {
1027:     if (rct[n] == ctNew) {
1028:       if (rsize[n] && r >= rsize[n])
1029:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number %" PetscInt_FMT " should be in [0, %" PetscInt_FMT ") for subcell type %s in cell type %s", r, rsize[n], DMPolytopeTypes[rct[n]], DMPolytopeTypes[ct]);
1030:       newp += rp * rsize[n] + r;
1031:       break;
1032:     }
1033:   }

1035:   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);
1036:   *pNew = newp;
1037:   PetscFunctionReturn(PETSC_SUCCESS);
1038: }

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

1043:   Not Collective

1045:   Input Parameters:
1046: + tr   - The `DMPlexTransform`
1047: - pNew - The new point number

1049:   Output Parameters:
1050: + ct    - The type of the original point which produces the new point
1051: . ctNew - The type of the new point
1052: . p     - The original point which produces the new point
1053: - r     - The replica number of the new point, meaning it is the rth point of type ctNew produced from p

1055:   Level: developer

1057: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetTargetPoint()`, `DMPlexTransformCellTransform()`
1058: @*/
1059: PetscErrorCode DMPlexTransformGetSourcePoint(DMPlexTransform tr, PetscInt pNew, DMPolytopeType *ct, DMPolytopeType *ctNew, PetscInt *p, PetscInt *r)
1060: {
1061:   DMLabel         trType = tr->trType;
1062:   DMPolytopeType *rct, ctN;
1063:   PetscInt       *rsize, *cone, *ornt;
1064:   PetscInt        rt = -1, rtTmp, Nct, n, rp = 0, rO = 0, pO;
1065:   PetscInt        offset = -1, ctS, ctE, ctO = 0, ctTmp, rtS;

1067:   PetscFunctionBegin;
1068:   PetscCall(DMPlexTransformGetCellType(tr, pNew, &ctN));
1069:   if (trType) {
1070:     DM              dm;
1071:     IS              rtIS;
1072:     const PetscInt *reftypes;
1073:     PetscInt        Nrt, r, rtStart;

1075:     PetscCall(DMPlexTransformGetDM(tr, &dm));
1076:     PetscCall(DMLabelGetNumValues(trType, &Nrt));
1077:     PetscCall(DMLabelGetValueIS(trType, &rtIS));
1078:     PetscCall(ISGetIndices(rtIS, &reftypes));
1079:     for (r = 0; r < Nrt; ++r) {
1080:       const PetscInt off = tr->offset[r * DM_NUM_POLYTOPES + ctN];

1082:       if (tr->ctStartNew[ctN] + off > pNew) continue;
1083:       /* Check that any of this refinement type exist */
1084:       /* TODO Actually keep track of the number produced here instead */
1085:       if (off > offset) {
1086:         rt     = reftypes[r];
1087:         offset = off;
1088:       }
1089:     }
1090:     PetscCall(ISRestoreIndices(rtIS, &reftypes));
1091:     PetscCall(ISDestroy(&rtIS));
1092:     PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew);
1093:     /* TODO Map refinement types to cell types */
1094:     PetscCall(DMLabelGetStratumBounds(trType, rt, &rtStart, NULL));
1095:     PetscCheck(rtStart >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Refinement type %" PetscInt_FMT " has no source points", rt);
1096:     for (ctO = 0; ctO < DM_NUM_POLYTOPES; ++ctO) {
1097:       PetscInt ctS = tr->ctStart[ctO], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]];

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

1106:       if (tr->ctStartNew[ctN] + off > pNew) continue;
1107:       if (tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctTmp] + 1]] <= tr->ctStart[ctTmp]) continue;
1108:       /* TODO Actually keep track of the number produced here instead */
1109:       if (off > offset) {
1110:         ctO    = ctTmp;
1111:         offset = off;
1112:       }
1113:     }
1114:     rt = -1;
1115:     PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew);
1116:   }
1117:   ctS = tr->ctStart[ctO];
1118:   ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]];
1119:   if (trType) {
1120:     for (rtS = ctS; rtS < ctE; ++rtS) {
1121:       PetscInt val;
1122:       PetscCall(DMLabelGetValue(trType, rtS, &val));
1123:       if (val == rt) break;
1124:     }
1125:     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);
1126:   } else rtS = ctS;
1127:   PetscCall(DMPlexTransformCellTransform(tr, (DMPolytopeType)ctO, rtS, &rtTmp, &Nct, &rct, &rsize, &cone, &ornt));
1128:   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);
1129:   for (n = 0; n < Nct; ++n) {
1130:     if (rct[n] == ctN) {
1131:       PetscInt tmp = pNew - tr->ctStartNew[ctN] - offset, val, c;

1133:       if (trType) {
1134:         for (c = ctS; c < ctE; ++c) {
1135:           PetscCall(DMLabelGetValue(trType, c, &val));
1136:           if (val == rt) {
1137:             if (tmp < rsize[n]) break;
1138:             tmp -= rsize[n];
1139:           }
1140:         }
1141:         PetscCheck(c < ctE, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Parent point for target point %" PetscInt_FMT " could be not found", pNew);
1142:         rp = c - ctS;
1143:         rO = tmp;
1144:       } else {
1145:         // This assumes that all points of type ctO transform the same way
1146:         rp = tmp / rsize[n];
1147:         rO = tmp % rsize[n];
1148:       }
1149:       break;
1150:     }
1151:   }
1152:   PetscCheck(n != Nct, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number for target point %" PetscInt_FMT " could be not found", pNew);
1153:   pO = rp + ctS;
1154:   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);
1155:   if (ct) *ct = (DMPolytopeType)ctO;
1156:   if (ctNew) *ctNew = ctN;
1157:   if (p) *p = pO;
1158:   if (r) *r = rO;
1159:   PetscFunctionReturn(PETSC_SUCCESS);
1160: }

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

1165:   Input Parameters:
1166: + tr     - The `DMPlexTransform` object
1167: . source - The source cell type
1168: - p      - The source point, which can also determine the refine type

1170:   Output Parameters:
1171: + rt     - The refine type for this point
1172: . Nt     - The number of types produced by this point
1173: . target - An array of length `Nt` giving the types produced
1174: . size   - An array of length `Nt` giving the number of cells of each type produced
1175: . cone   - An array of length `Nt`*size[t]*coneSize[t] giving the cell type for each point in the cone of each produced point
1176: - ornt   - An array of length `Nt`*size[t]*coneSize[t] giving the orientation for each point in the cone of each produced point

1178:   Level: advanced

1180:   Notes:
1181:   The cone array gives the cone of each subcell listed by the first three outputs. For each cone point, we
1182:   need the cell type, point identifier, and orientation within the subcell. The orientation is with respect to the canonical
1183:   division (described in these outputs) of the cell in the original mesh. The point identifier is given by
1184: .vb
1185:    the number of cones to be taken, or 0 for the current cell
1186:    the cell cone point number at each level from which it is subdivided
1187:    the replica number r of the subdivision.
1188: .ve
1189:   The orientation is with respect to the canonical cone orientation. For example, the prescription for edge division is
1190: .vb
1191:    Nt     = 2
1192:    target = {DM_POLYTOPE_POINT, DM_POLYTOPE_SEGMENT}
1193:    size   = {1, 2}
1194:    cone   = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 0, 0,  DM_POLYTOPE_POINT, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0}
1195:    ornt   = {                         0,                       0,                        0,                          0}
1196: .ve

1198: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
1199: @*/
1200: PetscErrorCode DMPlexTransformCellTransform(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[])
1201: {
1202:   PetscFunctionBegin;
1203:   PetscUseTypeMethod(tr, celltransform, source, p, rt, Nt, target, size, cone, ornt);
1204:   PetscFunctionReturn(PETSC_SUCCESS);
1205: }

1207: PetscErrorCode DMPlexTransformGetSubcellOrientationIdentity(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew)
1208: {
1209:   PetscFunctionBegin;
1210:   *rnew = r;
1211:   *onew = DMPolytopeTypeComposeOrientation(tct, o, so);
1212:   PetscFunctionReturn(PETSC_SUCCESS);
1213: }

1215: /* Returns the same thing */
1216: PetscErrorCode DMPlexTransformCellTransformIdentity(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[])
1217: {
1218:   static DMPolytopeType vertexT[] = {DM_POLYTOPE_POINT};
1219:   static PetscInt       vertexS[] = {1};
1220:   static PetscInt       vertexC[] = {0};
1221:   static PetscInt       vertexO[] = {0};
1222:   static DMPolytopeType edgeT[]   = {DM_POLYTOPE_SEGMENT};
1223:   static PetscInt       edgeS[]   = {1};
1224:   static PetscInt       edgeC[]   = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0};
1225:   static PetscInt       edgeO[]   = {0, 0};
1226:   static DMPolytopeType tedgeT[]  = {DM_POLYTOPE_POINT_PRISM_TENSOR};
1227:   static PetscInt       tedgeS[]  = {1};
1228:   static PetscInt       tedgeC[]  = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0};
1229:   static PetscInt       tedgeO[]  = {0, 0};
1230:   static DMPolytopeType triT[]    = {DM_POLYTOPE_TRIANGLE};
1231:   static PetscInt       triS[]    = {1};
1232:   static PetscInt       triC[]    = {DM_POLYTOPE_SEGMENT, 1, 0, 0, DM_POLYTOPE_SEGMENT, 1, 1, 0, DM_POLYTOPE_SEGMENT, 1, 2, 0};
1233:   static PetscInt       triO[]    = {0, 0, 0};
1234:   static DMPolytopeType quadT[]   = {DM_POLYTOPE_QUADRILATERAL};
1235:   static PetscInt       quadS[]   = {1};
1236:   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};
1237:   static PetscInt       quadO[]   = {0, 0, 0, 0};
1238:   static DMPolytopeType tquadT[]  = {DM_POLYTOPE_SEG_PRISM_TENSOR};
1239:   static PetscInt       tquadS[]  = {1};
1240:   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};
1241:   static PetscInt       tquadO[]  = {0, 0, 0, 0};
1242:   static DMPolytopeType tetT[]    = {DM_POLYTOPE_TETRAHEDRON};
1243:   static PetscInt       tetS[]    = {1};
1244:   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};
1245:   static PetscInt       tetO[]    = {0, 0, 0, 0};
1246:   static DMPolytopeType hexT[]    = {DM_POLYTOPE_HEXAHEDRON};
1247:   static PetscInt       hexS[]    = {1};
1248:   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};
1249:   static PetscInt       hexO[] = {0, 0, 0, 0, 0, 0};
1250:   static DMPolytopeType tripT[]   = {DM_POLYTOPE_TRI_PRISM};
1251:   static PetscInt       tripS[]   = {1};
1252:   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};
1253:   static PetscInt       tripO[]   = {0, 0, 0, 0, 0};
1254:   static DMPolytopeType ttripT[]  = {DM_POLYTOPE_TRI_PRISM_TENSOR};
1255:   static PetscInt       ttripS[]  = {1};
1256:   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};
1257:   static PetscInt       ttripO[]  = {0, 0, 0, 0, 0};
1258:   static DMPolytopeType tquadpT[] = {DM_POLYTOPE_QUAD_PRISM_TENSOR};
1259:   static PetscInt       tquadpS[] = {1};
1260:   static PetscInt       tquadpC[] = {DM_POLYTOPE_QUADRILATERAL,    1, 0, 0, DM_POLYTOPE_QUADRILATERAL,    1, 1, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 2, 0,
1261:                                      DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 3, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 4, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 5, 0};
1262:   static PetscInt       tquadpO[] = {0, 0, 0, 0, 0, 0};
1263:   static DMPolytopeType pyrT[]    = {DM_POLYTOPE_PYRAMID};
1264:   static PetscInt       pyrS[]    = {1};
1265:   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};
1266:   static PetscInt       pyrO[]    = {0, 0, 0, 0, 0};

1268:   PetscFunctionBegin;
1269:   if (rt) *rt = 0;
1270:   switch (source) {
1271:   case DM_POLYTOPE_POINT:
1272:     *Nt     = 1;
1273:     *target = vertexT;
1274:     *size   = vertexS;
1275:     *cone   = vertexC;
1276:     *ornt   = vertexO;
1277:     break;
1278:   case DM_POLYTOPE_SEGMENT:
1279:     *Nt     = 1;
1280:     *target = edgeT;
1281:     *size   = edgeS;
1282:     *cone   = edgeC;
1283:     *ornt   = edgeO;
1284:     break;
1285:   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1286:     *Nt     = 1;
1287:     *target = tedgeT;
1288:     *size   = tedgeS;
1289:     *cone   = tedgeC;
1290:     *ornt   = tedgeO;
1291:     break;
1292:   case DM_POLYTOPE_TRIANGLE:
1293:     *Nt     = 1;
1294:     *target = triT;
1295:     *size   = triS;
1296:     *cone   = triC;
1297:     *ornt   = triO;
1298:     break;
1299:   case DM_POLYTOPE_QUADRILATERAL:
1300:     *Nt     = 1;
1301:     *target = quadT;
1302:     *size   = quadS;
1303:     *cone   = quadC;
1304:     *ornt   = quadO;
1305:     break;
1306:   case DM_POLYTOPE_SEG_PRISM_TENSOR:
1307:     *Nt     = 1;
1308:     *target = tquadT;
1309:     *size   = tquadS;
1310:     *cone   = tquadC;
1311:     *ornt   = tquadO;
1312:     break;
1313:   case DM_POLYTOPE_TETRAHEDRON:
1314:     *Nt     = 1;
1315:     *target = tetT;
1316:     *size   = tetS;
1317:     *cone   = tetC;
1318:     *ornt   = tetO;
1319:     break;
1320:   case DM_POLYTOPE_HEXAHEDRON:
1321:     *Nt     = 1;
1322:     *target = hexT;
1323:     *size   = hexS;
1324:     *cone   = hexC;
1325:     *ornt   = hexO;
1326:     break;
1327:   case DM_POLYTOPE_TRI_PRISM:
1328:     *Nt     = 1;
1329:     *target = tripT;
1330:     *size   = tripS;
1331:     *cone   = tripC;
1332:     *ornt   = tripO;
1333:     break;
1334:   case DM_POLYTOPE_TRI_PRISM_TENSOR:
1335:     *Nt     = 1;
1336:     *target = ttripT;
1337:     *size   = ttripS;
1338:     *cone   = ttripC;
1339:     *ornt   = ttripO;
1340:     break;
1341:   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
1342:     *Nt     = 1;
1343:     *target = tquadpT;
1344:     *size   = tquadpS;
1345:     *cone   = tquadpC;
1346:     *ornt   = tquadpO;
1347:     break;
1348:   case DM_POLYTOPE_PYRAMID:
1349:     *Nt     = 1;
1350:     *target = pyrT;
1351:     *size   = pyrS;
1352:     *cone   = pyrC;
1353:     *ornt   = pyrO;
1354:     break;
1355:   default:
1356:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No refinement strategy for %s", DMPolytopeTypes[source]);
1357:   }
1358:   PetscFunctionReturn(PETSC_SUCCESS);
1359: }

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

1364:   Not Collective

1366:   Input Parameters:
1367: + tr  - The `DMPlexTransform`
1368: . sct - The source point cell type, from whom the new cell is being produced
1369: . sp  - The source point
1370: . so  - The orientation of the source point in its enclosing parent
1371: . tct - The target point cell type
1372: . r   - The replica number requested for the produced cell type
1373: - o   - The orientation of the replica

1375:   Output Parameters:
1376: + rnew - The replica number, given the orientation of the parent
1377: - onew - The replica orientation, given the orientation of the parent

1379:   Level: advanced

1381: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformCellTransform()`, `DMPlexTransformApply()`
1382: @*/
1383: PetscErrorCode DMPlexTransformGetSubcellOrientation(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew)
1384: {
1385:   PetscFunctionBeginHot;
1386:   PetscUseTypeMethod(tr, getsubcellorientation, sct, sp, so, tct, r, o, rnew, onew);
1387:   PetscFunctionReturn(PETSC_SUCCESS);
1388: }

1390: static PetscErrorCode DMPlexTransformSetConeSizes(DMPlexTransform tr, DM rdm)
1391: {
1392:   DM       dm;
1393:   PetscInt pStart, pEnd, pNew;

1395:   PetscFunctionBegin;
1396:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1397:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetConeSizes, tr, dm, 0, 0));
1398:   /* Must create the celltype label here so that we do not automatically try to compute the types */
1399:   PetscCall(DMCreateLabel(rdm, "celltype"));
1400:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1401:   for (PetscInt p = pStart; p < pEnd; ++p) {
1402:     DMPolytopeType  ct;
1403:     DMPolytopeType *rct;
1404:     PetscInt       *rsize, *rcone, *rornt;
1405:     PetscInt        Nct, n, r;

1407:     PetscCall(DMPlexGetCellType(dm, p, &ct));
1408:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1409:     for (n = 0; n < Nct; ++n) {
1410:       for (r = 0; r < rsize[n]; ++r) {
1411:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1412:         PetscCall(DMPlexSetConeSize(rdm, pNew, DMPolytopeTypeGetConeSize(rct[n])));
1413:         PetscCall(DMPlexSetCellType(rdm, pNew, rct[n]));
1414:       }
1415:     }
1416:   }
1417:   /* Let the DM know we have set all the cell types */
1418:   {
1419:     DMLabel  ctLabel;
1420:     DM_Plex *plex = (DM_Plex *)rdm->data;

1422:     PetscCall(DMPlexGetCellTypeLabel(rdm, &ctLabel));
1423:     PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &plex->celltypeState));
1424:   }
1425:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetConeSizes, tr, dm, 0, 0));
1426:   PetscFunctionReturn(PETSC_SUCCESS);
1427: }

1429: PetscErrorCode DMPlexTransformGetConeSize(DMPlexTransform tr, PetscInt q, PetscInt *coneSize)
1430: {
1431:   DMPolytopeType ctNew;

1433:   PetscFunctionBegin;
1435:   PetscAssertPointer(coneSize, 3);
1436:   PetscCall(DMPlexTransformGetCellType(tr, q, &ctNew));
1437:   *coneSize = DMPolytopeTypeGetConeSize(ctNew);
1438:   PetscFunctionReturn(PETSC_SUCCESS);
1439: }

1441: /* The orientation o is for the interior of the cell p */
1442: 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[])
1443: {
1444:   DM              dm;
1445:   const PetscInt  csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1446:   const PetscInt *cone;
1447:   DMPolytopeType *newft = NULL;
1448:   PetscInt        c, coff = *coneoff, ooff = *orntoff;
1449:   PetscInt        dim, cr = 0, co = 0, nr, no;

1451:   PetscFunctionBegin;
1452:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1453:   PetscCall(DMPlexGetOrientedCone(dm, p, &cone, NULL));
1454:   // Check if we have to permute this cell
1455:   PetscCall(DMGetDimension(dm, &dim));
1456:   if (DMPolytopeTypeGetDim(ctNew) == dim && DMPolytopeTypeGetDim(ct) == dim - 1) {
1457:     PetscCall(DMPlexTransformGetSubcellOrientation(tr, ct, p, o, ctNew, cr, co, &nr, &no));
1458:     if (cr != nr || co != no) PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newft));
1459:   }
1460:   for (c = 0; c < csizeNew; ++c) {
1461:     PetscInt             ppp   = -1;                            /* Parent Parent point: Parent of point pp */
1462:     PetscInt             pp    = p;                             /* Parent point: Point in the original mesh producing new cone point */
1463:     PetscInt             po    = 0;                             /* Orientation of parent point pp in parent parent point ppp */
1464:     DMPolytopeType       pct   = ct;                            /* Parent type: Cell type for parent of new cone point */
1465:     const PetscInt      *pcone = cone;                          /* Parent cone: Cone of parent point pp */
1466:     PetscInt             pr    = -1;                            /* Replica number of pp that produces new cone point  */
1467:     const DMPolytopeType ft    = (DMPolytopeType)rcone[coff++]; /* Cell type for new cone point of pNew */
1468:     const PetscInt       fn    = rcone[coff++];                 /* Number of cones of p that need to be taken when producing new cone point */
1469:     PetscInt             fo    = rornt[ooff++];                 /* Orientation of new cone point in pNew */
1470:     PetscInt             lc;

1472:     /* Get the type (pct) and point number (pp) of the parent point in the original mesh which produces this cone point */
1473:     for (lc = 0; lc < fn; ++lc) {
1474:       const PetscInt *parr = DMPolytopeTypeGetArrangement(pct, po);
1475:       const PetscInt  acp  = rcone[coff++];
1476:       const PetscInt  pcp  = parr[acp * 2];
1477:       const PetscInt  pco  = parr[acp * 2 + 1];
1478:       const PetscInt *ppornt;

1480:       ppp = pp;
1481:       pp  = pcone[pcp];
1482:       PetscCall(DMPlexGetCellType(dm, pp, &pct));
1483:       // Restore the parent cone from the last iterate
1484:       if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, ppp, &pcone, NULL));
1485:       PetscCall(DMPlexGetOrientedCone(dm, pp, &pcone, NULL));
1486:       PetscCall(DMPlexGetOrientedCone(dm, ppp, NULL, &ppornt));
1487:       po = DMPolytopeTypeComposeOrientation(pct, ppornt[pcp], pco);
1488:       PetscCall(DMPlexRestoreOrientedCone(dm, ppp, NULL, &ppornt));
1489:     }
1490:     if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, pp, &pcone, NULL));
1491:     pr = rcone[coff++];
1492:     /* Orientation po of pp maps (pr, fo) -> (pr', fo') */
1493:     PetscCall(DMPlexTransformGetSubcellOrientation(tr, pct, pp, fn ? po : o, ft, pr, fo, &pr, &fo));
1494:     PetscCall(DMPlexTransformGetTargetPoint(tr, pct, ft, pp, pr, &coneNew[c]));
1495:     orntNew[c] = fo;
1496:     if (newft) newft[c] = ft;
1497:   }
1498:   PetscCall(DMPlexRestoreOrientedCone(dm, p, &cone, NULL));
1499:   if (newft) {
1500:     const PetscInt *arr;
1501:     PetscInt       *newcone, *newornt;

1503:     arr = DMPolytopeTypeGetArrangement(ctNew, no);
1504:     PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newcone));
1505:     PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newornt));
1506:     for (PetscInt c = 0; c < csizeNew; ++c) {
1507:       DMPolytopeType ft = newft[c];
1508:       PetscInt       nO;

1510:       nO         = DMPolytopeTypeGetNumArrangements(ft) / 2;
1511:       newcone[c] = coneNew[arr[c * 2 + 0]];
1512:       newornt[c] = DMPolytopeTypeComposeOrientation(ft, arr[c * 2 + 1], orntNew[arr[c * 2 + 0]]);
1513:       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]);
1514:     }
1515:     for (PetscInt c = 0; c < csizeNew; ++c) {
1516:       coneNew[c] = newcone[c];
1517:       orntNew[c] = newornt[c];
1518:     }
1519:     PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newcone));
1520:     PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newornt));
1521:     PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newft));
1522:   }
1523:   *coneoff = coff;
1524:   *orntoff = ooff;
1525:   PetscFunctionReturn(PETSC_SUCCESS);
1526: }

1528: static PetscErrorCode DMPlexTransformSetCones(DMPlexTransform tr, DM rdm)
1529: {
1530:   DM             dm;
1531:   DMPolytopeType ct;
1532:   PetscInt      *coneNew, *orntNew;
1533:   PetscInt       maxConeSize = 0, pStart, pEnd, p, pNew;

1535:   PetscFunctionBegin;
1536:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1537:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetCones, tr, dm, 0, 0));
1538:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1539:   PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew));
1540:   PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew));
1541:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1542:   for (p = pStart; p < pEnd; ++p) {
1543:     PetscInt        coff, ooff;
1544:     DMPolytopeType *rct;
1545:     PetscInt       *rsize, *rcone, *rornt;
1546:     PetscInt        Nct, n, r;

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

1553:       for (r = 0; r < rsize[n]; ++r) {
1554:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1555:         PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, ctNew, rcone, &coff, rornt, &ooff, coneNew, orntNew));
1556:         PetscCall(DMPlexSetCone(rdm, pNew, coneNew));
1557:         PetscCall(DMPlexSetConeOrientation(rdm, pNew, orntNew));
1558:       }
1559:     }
1560:   }
1561:   PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew));
1562:   PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew));
1563:   PetscCall(DMViewFromOptions(rdm, NULL, "-rdm_view"));
1564:   PetscCall(DMPlexSymmetrize(rdm));
1565:   PetscCall(DMPlexStratify(rdm));
1566:   PetscTryTypeMethod(tr, ordersupports, dm, rdm);
1567:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetCones, tr, dm, 0, 0));
1568:   PetscFunctionReturn(PETSC_SUCCESS);
1569: }

1571: PetscErrorCode DMPlexTransformGetConeOriented(DMPlexTransform tr, PetscInt q, PetscInt po, const PetscInt *cone[], const PetscInt *ornt[])
1572: {
1573:   DM              dm;
1574:   DMPolytopeType  ct, qct;
1575:   DMPolytopeType *rct;
1576:   PetscInt       *rsize, *rcone, *rornt, *qcone, *qornt;
1577:   PetscInt        maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0;

1579:   PetscFunctionBegin;
1581:   PetscAssertPointer(cone, 4);
1582:   PetscAssertPointer(ornt, 5);
1583:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1584:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1585:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1586:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1587:   PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r));
1588:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1589:   for (n = 0; n < Nct; ++n) {
1590:     const DMPolytopeType ctNew    = rct[n];
1591:     const PetscInt       csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1592:     PetscInt             Nr       = rsize[n], fn, c;

1594:     if (ctNew == qct) Nr = r;
1595:     for (nr = 0; nr < Nr; ++nr) {
1596:       for (c = 0; c < csizeNew; ++c) {
1597:         ++coff;             /* Cell type of new cone point */
1598:         fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */
1599:         coff += fn;
1600:         ++coff; /* Replica number of new cone point */
1601:         ++ooff; /* Orientation of new cone point */
1602:       }
1603:     }
1604:     if (ctNew == qct) break;
1605:   }
1606:   PetscCall(DMPlexTransformGetCone_Internal(tr, p, po, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt));
1607:   *cone = qcone;
1608:   *ornt = qornt;
1609:   PetscFunctionReturn(PETSC_SUCCESS);
1610: }

1612: PetscErrorCode DMPlexTransformGetCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[])
1613: {
1614:   DM              dm;
1615:   DMPolytopeType  ct, qct;
1616:   DMPolytopeType *rct;
1617:   PetscInt       *rsize, *rcone, *rornt, *qcone, *qornt;
1618:   PetscInt        maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0;

1620:   PetscFunctionBegin;
1622:   if (cone) PetscAssertPointer(cone, 3);
1623:   if (ornt) PetscAssertPointer(ornt, 4);
1624:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1625:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1626:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1627:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1628:   PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r));
1629:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1630:   for (n = 0; n < Nct; ++n) {
1631:     const DMPolytopeType ctNew    = rct[n];
1632:     const PetscInt       csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1633:     PetscInt             Nr       = rsize[n], fn, c;

1635:     if (ctNew == qct) Nr = r;
1636:     for (nr = 0; nr < Nr; ++nr) {
1637:       for (c = 0; c < csizeNew; ++c) {
1638:         ++coff;             /* Cell type of new cone point */
1639:         fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */
1640:         coff += fn;
1641:         ++coff; /* Replica number of new cone point */
1642:         ++ooff; /* Orientation of new cone point */
1643:       }
1644:     }
1645:     if (ctNew == qct) break;
1646:   }
1647:   PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt));
1648:   if (cone) *cone = qcone;
1649:   else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1650:   if (ornt) *ornt = qornt;
1651:   else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1652:   PetscFunctionReturn(PETSC_SUCCESS);
1653: }

1655: PetscErrorCode DMPlexTransformRestoreCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[])
1656: {
1657:   DM dm;

1659:   PetscFunctionBegin;
1661:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1662:   if (cone) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, cone));
1663:   if (ornt) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, ornt));
1664:   PetscFunctionReturn(PETSC_SUCCESS);
1665: }

1667: static PetscErrorCode DMPlexTransformCreateCellVertices_Internal(DMPlexTransform tr)
1668: {
1669:   PetscInt ict;

1671:   PetscFunctionBegin;
1672:   PetscCall(PetscCalloc3(DM_NUM_POLYTOPES, &tr->trNv, DM_NUM_POLYTOPES, &tr->trVerts, DM_NUM_POLYTOPES, &tr->trSubVerts));
1673:   for (ict = DM_POLYTOPE_POINT; ict < DM_NUM_POLYTOPES; ++ict) {
1674:     const DMPolytopeType ct = (DMPolytopeType)ict;
1675:     DMPlexTransform      reftr;
1676:     DM                   refdm, trdm;
1677:     Vec                  coordinates;
1678:     const PetscScalar   *coords;
1679:     DMPolytopeType      *rct;
1680:     PetscInt            *rsize, *rcone, *rornt;
1681:     PetscInt             Nct, n, r, pNew = 0;
1682:     PetscInt             trdim, vStart, vEnd, Nc;
1683:     const PetscInt       debug = 0;
1684:     const char          *typeName;

1686:     /* Since points are 0-dimensional, coordinates make no sense */
1687:     if (DMPolytopeTypeGetDim(ct) <= 0 || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) continue;
1688:     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, ct, &refdm));
1689:     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &reftr));
1690:     PetscCall(DMPlexTransformSetDM(reftr, refdm));
1691:     PetscCall(DMPlexTransformGetType(tr, &typeName));
1692:     PetscCall(DMPlexTransformSetType(reftr, typeName));
1693:     PetscCall(DMPlexTransformSetUp(reftr));
1694:     PetscCall(DMPlexTransformApply(reftr, refdm, &trdm));

1696:     PetscCall(DMGetDimension(trdm, &trdim));
1697:     PetscCall(DMPlexGetDepthStratum(trdm, 0, &vStart, &vEnd));
1698:     tr->trNv[ct] = vEnd - vStart;
1699:     PetscCall(DMGetCoordinatesLocal(trdm, &coordinates));
1700:     PetscCall(VecGetLocalSize(coordinates, &Nc));
1701:     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);
1702:     PetscCall(PetscCalloc1(Nc, &tr->trVerts[ct]));
1703:     PetscCall(VecGetArrayRead(coordinates, &coords));
1704:     PetscCall(PetscArraycpy(tr->trVerts[ct], coords, Nc));
1705:     PetscCall(VecRestoreArrayRead(coordinates, &coords));

1707:     PetscCall(PetscCalloc1(DM_NUM_POLYTOPES, &tr->trSubVerts[ct]));
1708:     PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1709:     for (n = 0; n < Nct; ++n) {
1710:       /* Since points are 0-dimensional, coordinates make no sense */
1711:       if (rct[n] == DM_POLYTOPE_POINT) continue;
1712:       PetscCall(PetscCalloc1(rsize[n], &tr->trSubVerts[ct][rct[n]]));
1713:       for (r = 0; r < rsize[n]; ++r) {
1714:         PetscInt *closure = NULL;
1715:         PetscInt  clSize, cl, Nv = 0;

1717:         PetscCall(PetscCalloc1(DMPolytopeTypeGetNumVertices(rct[n]), &tr->trSubVerts[ct][rct[n]][r]));
1718:         PetscCall(DMPlexTransformGetTargetPoint(reftr, ct, rct[n], 0, r, &pNew));
1719:         PetscCall(DMPlexGetTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure));
1720:         for (cl = 0; cl < clSize * 2; cl += 2) {
1721:           const PetscInt sv = closure[cl];

1723:           if ((sv >= vStart) && (sv < vEnd)) tr->trSubVerts[ct][rct[n]][r][Nv++] = sv - vStart;
1724:         }
1725:         PetscCall(DMPlexRestoreTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure));
1726:         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]);
1727:       }
1728:     }
1729:     if (debug) {
1730:       DMPolytopeType *rct;
1731:       PetscInt       *rsize, *rcone, *rornt;
1732:       PetscInt        v, dE = trdim, d, off = 0;

1734:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %" PetscInt_FMT " vertices\n", DMPolytopeTypes[ct], tr->trNv[ct]));
1735:       for (v = 0; v < tr->trNv[ct]; ++v) {
1736:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  "));
1737:         for (d = 0; d < dE; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g ", (double)PetscRealPart(tr->trVerts[ct][off++])));
1738:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1739:       }

1741:       PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1742:       for (n = 0; n < Nct; ++n) {
1743:         if (rct[n] == DM_POLYTOPE_POINT) continue;
1744:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %s subvertices %" PetscInt_FMT "\n", DMPolytopeTypes[ct], DMPolytopeTypes[rct[n]], tr->trNv[ct]));
1745:         for (r = 0; r < rsize[n]; ++r) {
1746:           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  "));
1747:           for (v = 0; v < DMPolytopeTypeGetNumVertices(rct[n]); ++v) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT " ", tr->trSubVerts[ct][rct[n]][r][v]));
1748:           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1749:         }
1750:       }
1751:     }
1752:     PetscCall(DMDestroy(&refdm));
1753:     PetscCall(DMDestroy(&trdm));
1754:     PetscCall(DMPlexTransformDestroy(&reftr));
1755:   }
1756:   PetscFunctionReturn(PETSC_SUCCESS);
1757: }

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

1762:   Input Parameters:
1763: + tr - The `DMPlexTransform` object
1764: - ct - The cell type

1766:   Output Parameters:
1767: + Nv      - The number of transformed vertices in the closure of the reference cell of given type
1768: - trVerts - The coordinates of these vertices in the reference cell

1770:   Level: developer

1772: .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSubcellVertices()`
1773: @*/
1774: PetscErrorCode DMPlexTransformGetCellVertices(DMPlexTransform tr, DMPolytopeType ct, PetscInt *Nv, PetscScalar *trVerts[])
1775: {
1776:   PetscFunctionBegin;
1777:   if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr));
1778:   if (Nv) *Nv = tr->trNv[ct];
1779:   if (trVerts) *trVerts = tr->trVerts[ct];
1780:   PetscFunctionReturn(PETSC_SUCCESS);
1781: }

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

1786:   Input Parameters:
1787: + tr  - The `DMPlexTransform` object
1788: . ct  - The cell type
1789: . rct - The subcell type
1790: - r   - The subcell index

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

1795:   Level: developer

1797: .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetCellVertices()`
1798: @*/
1799: PetscErrorCode DMPlexTransformGetSubcellVertices(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, PetscInt *subVerts[])
1800: {
1801:   PetscFunctionBegin;
1802:   if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr));
1803:   PetscCheck(tr->trSubVerts[ct][rct], PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_WRONG, "Cell type %s does not produce %s", DMPolytopeTypes[ct], DMPolytopeTypes[rct]);
1804:   if (subVerts) *subVerts = tr->trSubVerts[ct][rct][r];
1805:   PetscFunctionReturn(PETSC_SUCCESS);
1806: }

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

1813:   PetscFunctionBeginHot;
1814:   PetscCheck(ct == DM_POLYTOPE_POINT, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for refined point type %s", DMPolytopeTypes[ct]);
1815:   for (d = 0; d < dE; ++d) out[d] = 0.0;
1816:   for (v = 0; v < Nv; ++v)
1817:     for (d = 0; d < dE; ++d) out[d] += in[v * dE + d];
1818:   for (d = 0; d < dE; ++d) out[d] /= Nv;
1819:   PetscFunctionReturn(PETSC_SUCCESS);
1820: }

1822: /*@
1823:   DMPlexTransformMapCoordinates - Calculate new coordinates for produced points

1825:   Not collective

1827:   Input Parameters:
1828: + tr  - The `DMPlexTransform`
1829: . pct - The cell type of the parent, from whom the new cell is being produced
1830: . ct  - The type being produced
1831: . p   - The original point
1832: . r   - The replica number requested for the produced cell type
1833: . Nv  - Number of vertices in the closure of the parent cell
1834: . dE  - Spatial dimension
1835: - in  - array of size Nv*dE, holding coordinates of the vertices in the closure of the parent cell

1837:   Output Parameter:
1838: . out - The coordinates of the new vertices

1840:   Level: intermediate

1842: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`
1843: @*/
1844: PetscErrorCode DMPlexTransformMapCoordinates(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[])
1845: {
1846:   PetscFunctionBeginHot;
1847:   if (Nv) PetscUseTypeMethod(tr, mapcoordinates, pct, ct, p, r, Nv, dE, in, out);
1848:   PetscFunctionReturn(PETSC_SUCCESS);
1849: }

1851: /*
1852:   DMPlexTransformLabelProducedPoint_Private - Label a produced point based on its parent label

1854:   Not Collective

1856:   Input Parameters:
1857: + tr    - The `DMPlexTransform`
1858: . label - The label in the transformed mesh
1859: . pp    - The parent point in the original mesh
1860: . pct   - The cell type of the parent point
1861: . p     - The point in the transformed mesh
1862: . ct    - The cell type of the point
1863: . r     - The replica number of the point
1864: - val   - The label value of the parent point

1866:   Level: developer

1868: .seealso: `DMPlexTransformCreateLabels()`, `RefineLabel_Internal()`
1869: */
1870: static PetscErrorCode DMPlexTransformLabelProducedPoint_Private(DMPlexTransform tr, DMLabel label, PetscInt pp, DMPolytopeType pct, PetscInt p, DMPolytopeType ct, PetscInt r, PetscInt val)
1871: {
1872:   PetscFunctionBeginHot;
1873:   if (tr->labelMatchStrata && pct != ct) PetscFunctionReturn(PETSC_SUCCESS);
1874:   PetscCall(DMLabelSetValue(label, p, val + tr->labelReplicaInc * r));
1875:   PetscFunctionReturn(PETSC_SUCCESS);
1876: }

1878: static PetscErrorCode RefineLabel_Internal(DMPlexTransform tr, DMLabel label, DMLabel labelNew)
1879: {
1880:   DM              dm;
1881:   IS              valueIS;
1882:   const PetscInt *values;
1883:   PetscInt        defVal, Nv, val;

1885:   PetscFunctionBegin;
1886:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1887:   PetscCall(DMLabelGetDefaultValue(label, &defVal));
1888:   PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
1889:   PetscCall(DMLabelGetValueIS(label, &valueIS));
1890:   PetscCall(ISGetLocalSize(valueIS, &Nv));
1891:   PetscCall(ISGetIndices(valueIS, &values));
1892:   for (val = 0; val < Nv; ++val) {
1893:     IS              pointIS;
1894:     const PetscInt *points;
1895:     PetscInt        numPoints, p;

1897:     /* Ensure refined label is created with same number of strata as
1898:      * original (even if no entries here). */
1899:     PetscCall(DMLabelAddStratum(labelNew, values[val]));
1900:     PetscCall(DMLabelGetStratumIS(label, values[val], &pointIS));
1901:     PetscCall(ISGetLocalSize(pointIS, &numPoints));
1902:     PetscCall(ISGetIndices(pointIS, &points));
1903:     for (p = 0; p < numPoints; ++p) {
1904:       const PetscInt  point = points[p];
1905:       DMPolytopeType  ct;
1906:       DMPolytopeType *rct;
1907:       PetscInt       *rsize, *rcone, *rornt;
1908:       PetscInt        Nct, n, r, pNew = 0;

1910:       PetscCall(DMPlexGetCellType(dm, point, &ct));
1911:       PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1912:       for (n = 0; n < Nct; ++n) {
1913:         for (r = 0; r < rsize[n]; ++r) {
1914:           PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], point, r, &pNew));
1915:           PetscCall(DMPlexTransformLabelProducedPoint_Private(tr, labelNew, point, ct, pNew, rct[n], r, values[val]));
1916:         }
1917:       }
1918:     }
1919:     PetscCall(ISRestoreIndices(pointIS, &points));
1920:     PetscCall(ISDestroy(&pointIS));
1921:   }
1922:   PetscCall(ISRestoreIndices(valueIS, &values));
1923:   PetscCall(ISDestroy(&valueIS));
1924:   PetscFunctionReturn(PETSC_SUCCESS);
1925: }

1927: static PetscErrorCode DMPlexTransformCreateLabels(DMPlexTransform tr, DM rdm)
1928: {
1929:   DM       dm;
1930:   PetscInt numLabels, l;

1932:   PetscFunctionBegin;
1933:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1934:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_CreateLabels, tr, dm, 0, 0));
1935:   PetscCall(DMGetNumLabels(dm, &numLabels));
1936:   for (l = 0; l < numLabels; ++l) {
1937:     DMLabel     label, labelNew;
1938:     const char *lname;
1939:     PetscBool   isDepth, isCellType;

1941:     PetscCall(DMGetLabelName(dm, l, &lname));
1942:     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
1943:     if (isDepth) continue;
1944:     PetscCall(PetscStrcmp(lname, "celltype", &isCellType));
1945:     if (isCellType) continue;
1946:     PetscCall(DMCreateLabel(rdm, lname));
1947:     PetscCall(DMGetLabel(dm, lname, &label));
1948:     PetscCall(DMGetLabel(rdm, lname, &labelNew));
1949:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
1950:   }
1951:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateLabels, tr, dm, 0, 0));
1952:   PetscFunctionReturn(PETSC_SUCCESS);
1953: }

1955: /* This refines the labels which define regions for fields and DSes since they are not in the list of labels for the DM */
1956: PetscErrorCode DMPlexTransformCreateDiscLabels(DMPlexTransform tr, DM rdm)
1957: {
1958:   DM       dm;
1959:   PetscInt Nf, f, Nds, s;

1961:   PetscFunctionBegin;
1962:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1963:   PetscCall(DMGetNumFields(dm, &Nf));
1964:   for (f = 0; f < Nf; ++f) {
1965:     DMLabel     label, labelNew;
1966:     PetscObject obj;
1967:     const char *lname;

1969:     PetscCall(DMGetField(rdm, f, &label, &obj));
1970:     if (!label) continue;
1971:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
1972:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew));
1973:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
1974:     PetscCall(DMSetField_Internal(rdm, f, labelNew, obj));
1975:     PetscCall(DMLabelDestroy(&labelNew));
1976:   }
1977:   PetscCall(DMGetNumDS(dm, &Nds));
1978:   for (s = 0; s < Nds; ++s) {
1979:     DMLabel     label, labelNew;
1980:     const char *lname;

1982:     PetscCall(DMGetRegionNumDS(rdm, s, &label, NULL, NULL, NULL));
1983:     if (!label) continue;
1984:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
1985:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew));
1986:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
1987:     PetscCall(DMSetRegionNumDS(rdm, s, labelNew, NULL, NULL, NULL));
1988:     PetscCall(DMLabelDestroy(&labelNew));
1989:   }
1990:   PetscFunctionReturn(PETSC_SUCCESS);
1991: }

1993: static PetscErrorCode DMPlexTransformCreateSF(DMPlexTransform tr, DM rdm)
1994: {
1995:   DM                 dm;
1996:   PetscSF            sf, sfNew;
1997:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
1998:   const PetscInt    *localPoints;
1999:   const PetscSFNode *remotePoints;
2000:   PetscInt          *localPointsNew;
2001:   PetscSFNode       *remotePointsNew;
2002:   PetscInt           pStartNew, pEndNew, pNew;
2003:   /* Brute force algorithm */
2004:   PetscSF         rsf;
2005:   PetscSection    s;
2006:   const PetscInt *rootdegree;
2007:   PetscInt       *rootPointsNew, *remoteOffsets;
2008:   PetscInt        numPointsNew, pStart, pEnd, p;

2010:   PetscFunctionBegin;
2011:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2012:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0));
2013:   PetscCall(DMPlexGetChart(rdm, &pStartNew, &pEndNew));
2014:   PetscCall(DMGetPointSF(dm, &sf));
2015:   PetscCall(DMGetPointSF(rdm, &sfNew));
2016:   /* Calculate size of new SF */
2017:   PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints));
2018:   if (numRoots < 0) {
2019:     PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0));
2020:     PetscFunctionReturn(PETSC_SUCCESS);
2021:   }
2022:   for (l = 0; l < numLeaves; ++l) {
2023:     const PetscInt  p = localPoints[l];
2024:     DMPolytopeType  ct;
2025:     DMPolytopeType *rct;
2026:     PetscInt       *rsize, *rcone, *rornt;
2027:     PetscInt        Nct, n;

2029:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2030:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2031:     for (n = 0; n < Nct; ++n) numLeavesNew += rsize[n];
2032:   }
2033:   /* Send new root point numbers
2034:        It is possible to optimize for regular transforms by sending only the cell type offsets, but it seems a needless complication
2035:   */
2036:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
2037:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &s));
2038:   PetscCall(PetscSectionSetChart(s, pStart, pEnd));
2039:   for (p = pStart; p < pEnd; ++p) {
2040:     DMPolytopeType  ct;
2041:     DMPolytopeType *rct;
2042:     PetscInt       *rsize, *rcone, *rornt;
2043:     PetscInt        Nct, n;

2045:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2046:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2047:     for (n = 0; n < Nct; ++n) PetscCall(PetscSectionAddDof(s, p, rsize[n]));
2048:   }
2049:   PetscCall(PetscSectionSetUp(s));
2050:   PetscCall(PetscSectionGetStorageSize(s, &numPointsNew));
2051:   PetscCall(PetscSFCreateRemoteOffsets(sf, s, s, &remoteOffsets));
2052:   PetscCall(PetscSFCreateSectionSF(sf, s, remoteOffsets, s, &rsf));
2053:   PetscCall(PetscFree(remoteOffsets));
2054:   PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree));
2055:   PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree));
2056:   PetscCall(PetscMalloc1(numPointsNew, &rootPointsNew));
2057:   for (p = 0; p < numPointsNew; ++p) rootPointsNew[p] = -1;
2058:   for (p = pStart; p < pEnd; ++p) {
2059:     DMPolytopeType  ct;
2060:     DMPolytopeType *rct;
2061:     PetscInt       *rsize, *rcone, *rornt;
2062:     PetscInt        Nct, n, r, off;

2064:     if (!rootdegree[p - pStart]) continue;
2065:     PetscCall(PetscSectionGetOffset(s, p, &off));
2066:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2067:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2068:     for (n = 0, m = 0; n < Nct; ++n) {
2069:       for (r = 0; r < rsize[n]; ++r, ++m) {
2070:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
2071:         rootPointsNew[off + m] = pNew;
2072:       }
2073:     }
2074:   }
2075:   PetscCall(PetscSFBcastBegin(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE));
2076:   PetscCall(PetscSFBcastEnd(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE));
2077:   PetscCall(PetscSFDestroy(&rsf));
2078:   PetscCall(PetscMalloc1(numLeavesNew, &localPointsNew));
2079:   PetscCall(PetscMalloc1(numLeavesNew, &remotePointsNew));
2080:   for (l = 0, m = 0; l < numLeaves; ++l) {
2081:     const PetscInt  p = localPoints[l];
2082:     DMPolytopeType  ct;
2083:     DMPolytopeType *rct;
2084:     PetscInt       *rsize, *rcone, *rornt;
2085:     PetscInt        Nct, n, r, q, off;

2087:     PetscCall(PetscSectionGetOffset(s, p, &off));
2088:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2089:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2090:     for (n = 0, q = 0; n < Nct; ++n) {
2091:       for (r = 0; r < rsize[n]; ++r, ++m, ++q) {
2092:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
2093:         localPointsNew[m]        = pNew;
2094:         remotePointsNew[m].index = rootPointsNew[off + q];
2095:         remotePointsNew[m].rank  = remotePoints[l].rank;
2096:       }
2097:     }
2098:   }
2099:   PetscCall(PetscSectionDestroy(&s));
2100:   PetscCall(PetscFree(rootPointsNew));
2101:   /* SF needs sorted leaves to correctly calculate Gather */
2102:   {
2103:     PetscSFNode *rp, *rtmp;
2104:     PetscInt    *lp, *idx, *ltmp, i;

2106:     PetscCall(PetscMalloc1(numLeavesNew, &idx));
2107:     PetscCall(PetscMalloc1(numLeavesNew, &lp));
2108:     PetscCall(PetscMalloc1(numLeavesNew, &rp));
2109:     for (i = 0; i < numLeavesNew; ++i) {
2110:       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);
2111:       idx[i] = i;
2112:     }
2113:     PetscCall(PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx));
2114:     for (i = 0; i < numLeavesNew; ++i) {
2115:       lp[i] = localPointsNew[idx[i]];
2116:       rp[i] = remotePointsNew[idx[i]];
2117:     }
2118:     ltmp            = localPointsNew;
2119:     localPointsNew  = lp;
2120:     rtmp            = remotePointsNew;
2121:     remotePointsNew = rp;
2122:     PetscCall(PetscFree(idx));
2123:     PetscCall(PetscFree(ltmp));
2124:     PetscCall(PetscFree(rtmp));
2125:   }
2126:   PetscCall(PetscSFSetGraph(sfNew, pEndNew - pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER));
2127:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0));
2128:   PetscFunctionReturn(PETSC_SUCCESS);
2129: }

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

2134:   Not Collective

2136:   Input Parameters:
2137: + tr  - The `DMPlexTransform`
2138: . ct  - The type of the parent cell
2139: . rct - The type of the produced cell
2140: . r   - The index of the produced cell
2141: - x   - The localized coordinates for the parent cell

2143:   Output Parameter:
2144: . xr  - The localized coordinates for the produced cell

2146:   Level: developer

2148: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexCellRefinerSetCoordinates()`
2149: */
2150: static PetscErrorCode DMPlexTransformMapLocalizedCoordinates(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, const PetscScalar x[], PetscScalar xr[])
2151: {
2152:   PetscFE  fe = NULL;
2153:   PetscInt cdim, v, *subcellV;

2155:   PetscFunctionBegin;
2156:   PetscCall(DMPlexTransformGetCoordinateFE(tr, ct, &fe));
2157:   PetscCall(DMPlexTransformGetSubcellVertices(tr, ct, rct, r, &subcellV));
2158:   PetscCall(PetscFEGetNumComponents(fe, &cdim));
2159:   for (v = 0; v < DMPolytopeTypeGetNumVertices(rct); ++v) PetscCall(PetscFEInterpolate_Static(fe, x, tr->refGeom[ct], subcellV[v], &xr[v * cdim]));
2160:   PetscFunctionReturn(PETSC_SUCCESS);
2161: }

2163: static PetscErrorCode DMPlexTransformSetCoordinates(DMPlexTransform tr, DM rdm)
2164: {
2165:   DM                 dm, cdm, cdmCell, cdmNew, cdmCellNew;
2166:   PetscSection       coordSection, coordSectionNew, coordSectionCell, coordSectionCellNew;
2167:   Vec                coordsLocal, coordsLocalNew, coordsLocalCell = NULL, coordsLocalCellNew;
2168:   const PetscScalar *coords;
2169:   PetscScalar       *coordsNew;
2170:   const PetscReal   *maxCell, *Lstart, *L;
2171:   PetscBool          localized, localizeVertices = PETSC_FALSE, localizeCells = PETSC_FALSE, sparseLocalize;
2172:   PetscInt           dE, dEo, d, cStart, cEnd, c, cStartNew, cEndNew, vStartNew, vEndNew, v, pStart, pEnd, p;

2174:   PetscFunctionBegin;
2175:   // Need to clear the DMField for coordinates
2176:   PetscCall(DMSetCoordinateField(rdm, NULL));
2177:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2178:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetCoordinates, tr, dm, 0, 0));
2179:   PetscCall(DMGetCoordinateDM(dm, &cdm));
2180:   PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
2181:   PetscCall(DMGetCoordinatesLocalized(dm, &localized));
2182:   PetscCall(DMGetSparseLocalize(dm, &sparseLocalize));
2183:   PetscCall(DMSetSparseLocalize(rdm, sparseLocalize));
2184:   PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
2185:   if (localized) {
2186:     /* Localize coordinates of new vertices */
2187:     localizeVertices = PETSC_TRUE;
2188:     /* If we do not have a mechanism for automatically localizing cell coordinates, we need to compute them explicitly for every divided cell */
2189:     if (!maxCell) localizeCells = PETSC_TRUE;
2190:   }
2191:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
2192:   PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &dEo));
2193:   if (maxCell) {
2194:     PetscReal maxCellNew[3];

2196:     for (d = 0; d < dEo; ++d) maxCellNew[d] = maxCell[d] / 2.0;
2197:     PetscCall(DMSetPeriodicity(rdm, maxCellNew, Lstart, L));
2198:   }
2199:   PetscCall(DMGetCoordinateDim(rdm, &dE));
2200:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionNew));
2201:   PetscCall(PetscSectionSetNumFields(coordSectionNew, 1));
2202:   PetscCall(PetscSectionSetFieldComponents(coordSectionNew, 0, dE));
2203:   PetscCall(DMPlexGetDepthStratum(rdm, 0, &vStartNew, &vEndNew));
2204:   PetscCall(PetscSectionSetChart(coordSectionNew, vStartNew, vEndNew));
2205:   /* Localization should be inherited */
2206:   /*   Stefano calculates parent cells for each new cell for localization */
2207:   /*   Localized cells need coordinates of closure */
2208:   for (v = vStartNew; v < vEndNew; ++v) {
2209:     PetscCall(PetscSectionSetDof(coordSectionNew, v, dE));
2210:     PetscCall(PetscSectionSetFieldDof(coordSectionNew, v, 0, dE));
2211:   }
2212:   PetscCall(PetscSectionSetUp(coordSectionNew));
2213:   PetscCall(DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew));

2215:   if (localizeCells) {
2216:     PetscCall(DMGetCoordinateDM(rdm, &cdmNew));
2217:     PetscCall(DMClone(cdmNew, &cdmCellNew));
2218:     PetscCall(DMSetCellCoordinateDM(rdm, cdmCellNew));
2219:     PetscCall(DMDestroy(&cdmCellNew));

2221:     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionCellNew));
2222:     PetscCall(PetscSectionSetNumFields(coordSectionCellNew, 1));
2223:     PetscCall(PetscSectionSetFieldComponents(coordSectionCellNew, 0, dE));
2224:     PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStartNew, &cEndNew));
2225:     PetscCall(PetscSectionSetChart(coordSectionCellNew, cStartNew, cEndNew));

2227:     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
2228:     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2229:     for (c = cStart; c < cEnd; ++c) {
2230:       PetscInt dof;

2232:       PetscCall(PetscSectionGetDof(coordSectionCell, c, &dof));
2233:       if (dof) {
2234:         DMPolytopeType  ct;
2235:         DMPolytopeType *rct;
2236:         PetscInt       *rsize, *rcone, *rornt;
2237:         PetscInt        dim, cNew, Nct, n, r;

2239:         PetscCall(DMPlexGetCellType(dm, c, &ct));
2240:         dim = DMPolytopeTypeGetDim(ct);
2241:         PetscCall(DMPlexTransformCellTransform(tr, ct, c, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2242:         /* This allows for different cell types */
2243:         for (n = 0; n < Nct; ++n) {
2244:           if (dim != DMPolytopeTypeGetDim(rct[n])) continue;
2245:           for (r = 0; r < rsize[n]; ++r) {
2246:             PetscInt *closure = NULL;
2247:             PetscInt  clSize, cl, Nv = 0;

2249:             PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], c, r, &cNew));
2250:             PetscCall(DMPlexGetTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure));
2251:             for (cl = 0; cl < clSize * 2; cl += 2) {
2252:               if ((closure[cl] >= vStartNew) && (closure[cl] < vEndNew)) ++Nv;
2253:             }
2254:             PetscCall(DMPlexRestoreTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure));
2255:             PetscCall(PetscSectionSetDof(coordSectionCellNew, cNew, Nv * dE));
2256:             PetscCall(PetscSectionSetFieldDof(coordSectionCellNew, cNew, 0, Nv * dE));
2257:           }
2258:         }
2259:       }
2260:     }
2261:     PetscCall(PetscSectionSetUp(coordSectionCellNew));
2262:     PetscCall(DMSetCellCoordinateSection(rdm, PETSC_DETERMINE, coordSectionCellNew));
2263:   }
2264:   PetscCall(DMViewFromOptions(dm, NULL, "-coarse_dm_view"));
2265:   {
2266:     VecType     vtype;
2267:     PetscInt    coordSizeNew, bs;
2268:     const char *name;

2270:     PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
2271:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalNew));
2272:     PetscCall(PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew));
2273:     PetscCall(VecSetSizes(coordsLocalNew, coordSizeNew, PETSC_DETERMINE));
2274:     PetscCall(PetscObjectGetName((PetscObject)coordsLocal, &name));
2275:     PetscCall(PetscObjectSetName((PetscObject)coordsLocalNew, name));
2276:     PetscCall(VecGetBlockSize(coordsLocal, &bs));
2277:     PetscCall(VecSetBlockSize(coordsLocalNew, dEo == dE ? bs : dE));
2278:     PetscCall(VecGetType(coordsLocal, &vtype));
2279:     PetscCall(VecSetType(coordsLocalNew, vtype));
2280:   }
2281:   PetscCall(VecGetArrayRead(coordsLocal, &coords));
2282:   PetscCall(VecGetArray(coordsLocalNew, &coordsNew));
2283:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
2284:   /* First set coordinates for vertices */
2285:   for (p = pStart; p < pEnd; ++p) {
2286:     DMPolytopeType  ct;
2287:     DMPolytopeType *rct;
2288:     PetscInt       *rsize, *rcone, *rornt;
2289:     PetscInt        Nct, n, r;
2290:     PetscBool       hasVertex = PETSC_FALSE;

2292:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2293:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2294:     for (n = 0; n < Nct; ++n) {
2295:       if (rct[n] == DM_POLYTOPE_POINT) {
2296:         hasVertex = PETSC_TRUE;
2297:         break;
2298:       }
2299:     }
2300:     if (hasVertex) {
2301:       const PetscScalar *icoords = NULL;
2302:       const PetscScalar *array   = NULL;
2303:       PetscScalar       *pcoords = NULL;
2304:       PetscBool          isDG;
2305:       PetscInt           Nc, Nv, v, d;

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

2309:       icoords = pcoords;
2310:       Nv      = Nc / dEo;
2311:       if (ct != DM_POLYTOPE_POINT) {
2312:         if (localizeVertices && maxCell) {
2313:           PetscScalar anchor[3];

2315:           for (d = 0; d < dEo; ++d) anchor[d] = pcoords[d];
2316:           for (v = 0; v < Nv; ++v) PetscCall(DMLocalizeCoordinate_Internal(dm, dEo, anchor, &pcoords[v * dEo], &pcoords[v * dEo]));
2317:         }
2318:       }
2319:       for (n = 0; n < Nct; ++n) {
2320:         if (rct[n] != DM_POLYTOPE_POINT) continue;
2321:         for (r = 0; r < rsize[n]; ++r) {
2322:           PetscScalar vcoords[3];
2323:           PetscInt    vNew, off;

2325:           PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &vNew));
2326:           PetscCall(PetscSectionGetOffset(coordSectionNew, vNew, &off));
2327:           PetscCall(DMPlexTransformMapCoordinates(tr, ct, rct[n], p, r, Nv, dEo, icoords, vcoords));
2328:           PetscCall(DMSnapToGeomModel(dm, p, dE, vcoords, &coordsNew[off]));
2329:         }
2330:       }
2331:       PetscCall(DMPlexRestoreCellCoordinates(dm, p, &isDG, &Nc, &array, &pcoords));
2332:     }
2333:   }
2334:   PetscCall(VecRestoreArrayRead(coordsLocal, &coords));
2335:   PetscCall(VecRestoreArray(coordsLocalNew, &coordsNew));
2336:   PetscCall(DMSetCoordinatesLocal(rdm, coordsLocalNew));
2337:   PetscCall(VecDestroy(&coordsLocalNew));
2338:   PetscCall(PetscSectionDestroy(&coordSectionNew));
2339:   /* Then set coordinates for cells by localizing */
2340:   if (!localizeCells) PetscCall(DMLocalizeCoordinates(rdm));
2341:   else {
2342:     VecType     vtype;
2343:     PetscInt    coordSizeNew, bs;
2344:     const char *name;

2346:     PetscCall(DMGetCellCoordinatesLocal(dm, &coordsLocalCell));
2347:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalCellNew));
2348:     PetscCall(PetscSectionGetStorageSize(coordSectionCellNew, &coordSizeNew));
2349:     PetscCall(VecSetSizes(coordsLocalCellNew, coordSizeNew, PETSC_DETERMINE));
2350:     PetscCall(PetscObjectGetName((PetscObject)coordsLocalCell, &name));
2351:     PetscCall(PetscObjectSetName((PetscObject)coordsLocalCellNew, name));
2352:     PetscCall(VecGetBlockSize(coordsLocalCell, &bs));
2353:     PetscCall(VecSetBlockSize(coordsLocalCellNew, dEo == dE ? bs : dE));
2354:     PetscCall(VecGetType(coordsLocalCell, &vtype));
2355:     PetscCall(VecSetType(coordsLocalCellNew, vtype));
2356:     PetscCall(VecGetArrayRead(coordsLocalCell, &coords));
2357:     PetscCall(VecGetArray(coordsLocalCellNew, &coordsNew));

2359:     for (p = pStart; p < pEnd; ++p) {
2360:       DMPolytopeType  ct;
2361:       DMPolytopeType *rct;
2362:       PetscInt       *rsize, *rcone, *rornt;
2363:       PetscInt        dof = 0, Nct, n, r;

2365:       PetscCall(DMPlexGetCellType(dm, p, &ct));
2366:       PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2367:       if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
2368:       if (dof) {
2369:         const PetscScalar *pcoords;

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

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

2379:             /* It looks like Stefano and Lisandro are allowing localized coordinates without defining the periodic boundary, which means that
2380:                DMLocalizeCoordinate_Internal() will not work. Localized coordinates will have to have obtained by the affine map of the larger
2381:                cell to the ones it produces. */
2382:             PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
2383:             PetscCall(PetscSectionGetOffset(coordSectionCellNew, pNew, &offNew));
2384:             PetscCall(DMPlexTransformMapLocalizedCoordinates(tr, ct, rct[n], r, pcoords, &coordsNew[offNew]));
2385:           }
2386:         }
2387:       }
2388:     }
2389:     PetscCall(VecRestoreArrayRead(coordsLocalCell, &coords));
2390:     PetscCall(VecRestoreArray(coordsLocalCellNew, &coordsNew));
2391:     PetscCall(DMSetCellCoordinatesLocal(rdm, coordsLocalCellNew));
2392:     PetscCall(VecDestroy(&coordsLocalCellNew));
2393:     PetscCall(PetscSectionDestroy(&coordSectionCellNew));
2394:   }
2395:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetCoordinates, tr, dm, 0, 0));
2396:   PetscFunctionReturn(PETSC_SUCCESS);
2397: }

2399: /*@
2400:   DMPlexTransformApply - Execute the transformation, producing another `DM`

2402:   Collective

2404:   Input Parameters:
2405: + tr - The `DMPlexTransform` object
2406: - dm - The original `DM`

2408:   Output Parameter:
2409: . trdm - The transformed `DM`

2411:   Level: intermediate

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

2418: .seealso: [](plex_transform_table), [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformCreate()`, `DMPlexTransformSetDM()`
2419: @*/
2420: PetscErrorCode DMPlexTransformApply(DMPlexTransform tr, DM dm, DM *trdm)
2421: {
2422:   DM                     rdm;
2423:   DMPlexInterpolatedFlag interp;
2424:   PetscInt               pStart, pEnd;

2426:   PetscFunctionBegin;
2429:   PetscAssertPointer(trdm, 3);
2430:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_Apply, tr, dm, 0, 0));
2431:   PetscCall(DMPlexTransformSetDM(tr, dm));

2433:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &rdm));
2434:   PetscCall(DMSetType(rdm, DMPLEX));
2435:   PetscCall(DMPlexTransformSetDimensions(tr, dm, rdm));
2436:   /* Calculate number of new points of each depth */
2437:   PetscCall(DMPlexIsInterpolatedCollective(dm, &interp));
2438:   PetscCheck(interp == DMPLEX_INTERPOLATED_FULL, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be fully interpolated for regular refinement");
2439:   /* Step 1: Set chart */
2440:   PetscCall(DMPlexTransformGetChart(tr, &pStart, &pEnd));
2441:   PetscCall(DMPlexSetChart(rdm, pStart, pEnd));
2442:   /* Step 2: Set cone/support sizes (automatically stratifies) */
2443:   PetscCall(DMPlexTransformSetConeSizes(tr, rdm));
2444:   /* Step 3: Setup refined DM */
2445:   PetscCall(DMSetUp(rdm));
2446:   /* Step 4: Set cones and supports (automatically symmetrizes) */
2447:   PetscCall(DMPlexTransformSetCones(tr, rdm));
2448:   /* Step 5: Create pointSF */
2449:   PetscCall(DMPlexTransformCreateSF(tr, rdm));
2450:   /* Step 6: Create labels */
2451:   PetscCall(DMPlexTransformCreateLabels(tr, rdm));
2452:   /* Step 7: Set coordinates */
2453:   PetscCall(DMPlexTransformSetCoordinates(tr, rdm));
2454:   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, rdm));
2455:   // If the original DM was configured from options, the transformed DM should be as well
2456:   rdm->setfromoptionscalled = dm->setfromoptionscalled;
2457:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_Apply, tr, dm, 0, 0));
2458:   *trdm = rdm;
2459:   PetscFunctionReturn(PETSC_SUCCESS);
2460: }

2462: PetscErrorCode DMPlexTransformAdaptLabel(DM dm, PETSC_UNUSED Vec metric, DMLabel adaptLabel, PETSC_UNUSED DMLabel rgLabel, DM *rdm)
2463: {
2464:   DMPlexTransform tr;
2465:   DM              cdm, rcdm;
2466:   const char     *prefix;
2467:   PetscBool       save;

2469:   PetscFunctionBegin;
2470:   PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr));
2471:   PetscCall(PetscObjectSetName((PetscObject)tr, "Adapt Label Transform"));
2472:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
2473:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix));
2474:   PetscCall(DMPlexTransformSetDM(tr, dm));
2475:   PetscCall(DMPlexTransformSetFromOptions(tr));
2476:   if (adaptLabel) PetscCall(DMPlexTransformSetActive(tr, adaptLabel));
2477:   PetscCall(DMPlexTransformSetUp(tr));
2478:   PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_transform_view"));
2479:   PetscCall(DMPlexTransformApply(tr, dm, rdm));
2480:   PetscCall(DMCopyDisc(dm, *rdm));
2481:   PetscCall(DMGetCoordinateDM(dm, &cdm));
2482:   PetscCall(DMGetCoordinateDM(*rdm, &rcdm));
2483:   PetscCall(DMCopyDisc(cdm, rcdm));
2484:   PetscCall(DMPlexTransformCreateDiscLabels(tr, *rdm));
2485:   PetscCall(DMCopyDisc(dm, *rdm));
2486:   PetscCall(DMPlexGetSaveTransform(dm, &save));
2487:   if (save) PetscCall(DMPlexSetTransform(*rdm, tr));
2488:   PetscCall(DMPlexTransformDestroy(&tr));
2489:   ((DM_Plex *)(*rdm)->data)->useHashLocation = ((DM_Plex *)dm->data)->useHashLocation;
2490:   PetscFunctionReturn(PETSC_SUCCESS);
2491: }