xref: /petsc/src/dm/impls/plex/transform/interface/plextransform.c (revision 9b529ac9d3e6c2bd81b4bb2dab3f698fdbcd19f2)
1 #include <petsc/private/dmplextransformimpl.h> /*I "petscdmplextransform.h" I*/
2 
3 #include <petsc/private/petscfeimpl.h> /* For PetscFEInterpolate_Static() */
4 
5 PetscClassId DMPLEXTRANSFORM_CLASSID;
6 
7 PetscFunctionList DMPlexTransformList              = NULL;
8 PetscBool         DMPlexTransformRegisterAllCalled = PETSC_FALSE;
9 
10 /* Construct cell type order since we must loop over cell types in depth order */
11 static PetscErrorCode DMPlexCreateCellTypeOrder_Internal(PetscInt dim, PetscInt *ctOrder[], PetscInt *ctOrderInv[])
12 {
13   PetscInt *ctO, *ctOInv;
14   PetscInt  c, d, off = 0;
15 
16   PetscFunctionBegin;
17   PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctO, DM_NUM_POLYTOPES + 1, &ctOInv));
18   for (d = 3; d >= dim; --d) {
19     for (c = 0; c <= DM_NUM_POLYTOPES; ++c) {
20       if (DMPolytopeTypeGetDim((DMPolytopeType)c) != d || c == DM_POLYTOPE_UNKNOWN_CELL || c == DM_POLYTOPE_UNKNOWN_FACE) continue;
21       ctO[off++] = c;
22     }
23   }
24   if (dim != 0) {
25     for (c = 0; c <= DM_NUM_POLYTOPES; ++c) {
26       if (DMPolytopeTypeGetDim((DMPolytopeType)c) != 0) continue;
27       ctO[off++] = c;
28     }
29   }
30   for (d = dim - 1; d > 0; --d) {
31     for (c = 0; c <= DM_NUM_POLYTOPES; ++c) {
32       if (DMPolytopeTypeGetDim((DMPolytopeType)c) != d || c == DM_POLYTOPE_UNKNOWN_CELL || c == DM_POLYTOPE_UNKNOWN_FACE) continue;
33       ctO[off++] = c;
34     }
35   }
36   for (c = 0; c <= DM_NUM_POLYTOPES; ++c) {
37     if (DMPolytopeTypeGetDim((DMPolytopeType)c) >= 0 && c != DM_POLYTOPE_UNKNOWN_CELL && c != DM_POLYTOPE_UNKNOWN_FACE) continue;
38     ctO[off++] = c;
39   }
40   PetscCheck(off == DM_NUM_POLYTOPES + 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid offset %" PetscInt_FMT " for cell type order", off);
41   for (c = 0; c <= DM_NUM_POLYTOPES; ++c) ctOInv[ctO[c]] = c;
42   *ctOrder    = ctO;
43   *ctOrderInv = ctOInv;
44   PetscFunctionReturn(PETSC_SUCCESS);
45 }
46 
47 /*@C
48   DMPlexTransformRegister - Adds a new transform component implementation
49 
50   Not Collective
51 
52   Input Parameters:
53 + name        - The name of a new user-defined creation routine
54 - create_func - The creation routine
55 
56   Example Usage:
57 .vb
58   DMPlexTransformRegister("my_transform", MyTransformCreate);
59 .ve
60 
61   Then, your transform type can be chosen with the procedural interface via
62 .vb
63   DMPlexTransformCreate(MPI_Comm, DMPlexTransform *);
64   DMPlexTransformSetType(DMPlexTransform, "my_transform");
65 .ve
66   or at runtime via the option
67 .vb
68   -dm_plex_transform_type my_transform
69 .ve
70 
71   Level: advanced
72 
73   Note:
74   `DMPlexTransformRegister()` may be called multiple times to add several user-defined transforms
75 
76 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformRegisterAll()`, `DMPlexTransformRegisterDestroy()`
77 @*/
78 PetscErrorCode DMPlexTransformRegister(const char name[], PetscErrorCode (*create_func)(DMPlexTransform))
79 {
80   PetscFunctionBegin;
81   PetscCall(DMInitializePackage());
82   PetscCall(PetscFunctionListAdd(&DMPlexTransformList, name, create_func));
83   PetscFunctionReturn(PETSC_SUCCESS);
84 }
85 
86 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Filter(DMPlexTransform);
87 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Regular(DMPlexTransform);
88 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_ToBox(DMPlexTransform);
89 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Alfeld(DMPlexTransform);
90 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_SBR(DMPlexTransform);
91 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_BL(DMPlexTransform);
92 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_1D(DMPlexTransform);
93 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Extrude(DMPlexTransform);
94 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Cohesive(DMPlexTransform);
95 
96 /*@C
97   DMPlexTransformRegisterAll - Registers all of the transform components in the `DM` package.
98 
99   Not Collective
100 
101   Level: advanced
102 
103 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransformType`, `DMRegisterAll()`, `DMPlexTransformRegisterDestroy()`
104 @*/
105 PetscErrorCode DMPlexTransformRegisterAll(void)
106 {
107   PetscFunctionBegin;
108   if (DMPlexTransformRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
109   DMPlexTransformRegisterAllCalled = PETSC_TRUE;
110 
111   PetscCall(DMPlexTransformRegister(DMPLEXTRANSFORMFILTER, DMPlexTransformCreate_Filter));
112   PetscCall(DMPlexTransformRegister(DMPLEXREFINEREGULAR, DMPlexTransformCreate_Regular));
113   PetscCall(DMPlexTransformRegister(DMPLEXREFINETOBOX, DMPlexTransformCreate_ToBox));
114   PetscCall(DMPlexTransformRegister(DMPLEXREFINEALFELD, DMPlexTransformCreate_Alfeld));
115   PetscCall(DMPlexTransformRegister(DMPLEXREFINEBOUNDARYLAYER, DMPlexTransformCreate_BL));
116   PetscCall(DMPlexTransformRegister(DMPLEXREFINESBR, DMPlexTransformCreate_SBR));
117   PetscCall(DMPlexTransformRegister(DMPLEXREFINE1D, DMPlexTransformCreate_1D));
118   PetscCall(DMPlexTransformRegister(DMPLEXEXTRUDE, DMPlexTransformCreate_Extrude));
119   PetscCall(DMPlexTransformRegister(DMPLEXCOHESIVEEXTRUDE, DMPlexTransformCreate_Cohesive));
120   PetscFunctionReturn(PETSC_SUCCESS);
121 }
122 
123 /*@C
124   DMPlexTransformRegisterDestroy - This function destroys the registered `DMPlexTransformType`. It is called from `PetscFinalize()`.
125 
126   Not collective
127 
128   Level: developer
129 
130 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMRegisterAll()`, `DMPlexTransformType`, `PetscInitialize()`
131 @*/
132 PetscErrorCode DMPlexTransformRegisterDestroy(void)
133 {
134   PetscFunctionBegin;
135   PetscCall(PetscFunctionListDestroy(&DMPlexTransformList));
136   DMPlexTransformRegisterAllCalled = PETSC_FALSE;
137   PetscFunctionReturn(PETSC_SUCCESS);
138 }
139 
140 /*@
141   DMPlexTransformCreate - Creates an empty transform object. The type can then be set with `DMPlexTransformSetType()`.
142 
143   Collective
144 
145   Input Parameter:
146 . comm - The communicator for the transform object
147 
148   Output Parameter:
149 . tr - The transform object
150 
151   Level: beginner
152 
153 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformSetType()`, `DMPLEXREFINEREGULAR`, `DMPLEXTRANSFORMFILTER`
154 @*/
155 PetscErrorCode DMPlexTransformCreate(MPI_Comm comm, DMPlexTransform *tr)
156 {
157   DMPlexTransform t;
158 
159   PetscFunctionBegin;
160   PetscAssertPointer(tr, 2);
161   *tr = NULL;
162   PetscCall(DMInitializePackage());
163 
164   PetscCall(PetscHeaderCreate(t, DMPLEXTRANSFORM_CLASSID, "DMPlexTransform", "Mesh Transform", "DMPlexTransform", comm, DMPlexTransformDestroy, DMPlexTransformView));
165   t->setupcalled = PETSC_FALSE;
166   PetscCall(PetscCalloc2(DM_NUM_POLYTOPES, &t->coordFE, DM_NUM_POLYTOPES, &t->refGeom));
167   *tr = t;
168   PetscFunctionReturn(PETSC_SUCCESS);
169 }
170 
171 /*@
172   DMPlexTransformSetType - Sets the particular implementation for a transform.
173 
174   Collective
175 
176   Input Parameters:
177 + tr     - The transform
178 - method - The name of the transform type
179 
180   Options Database Key:
181 . -dm_plex_transform_type <type> - Sets the transform type; see `DMPlexTransformType`
182 
183   Level: intermediate
184 
185 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformGetType()`, `DMPlexTransformCreate()`
186 @*/
187 PetscErrorCode DMPlexTransformSetType(DMPlexTransform tr, DMPlexTransformType method)
188 {
189   PetscErrorCode (*r)(DMPlexTransform);
190   PetscBool match;
191 
192   PetscFunctionBegin;
193   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
194   PetscCall(PetscObjectTypeCompare((PetscObject)tr, method, &match));
195   if (match) PetscFunctionReturn(PETSC_SUCCESS);
196 
197   PetscCall(DMPlexTransformRegisterAll());
198   PetscCall(PetscFunctionListFind(DMPlexTransformList, method, &r));
199   PetscCheck(r, PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DMPlexTransform type: %s", method);
200 
201   PetscTryTypeMethod(tr, destroy);
202   PetscCall(PetscMemzero(tr->ops, sizeof(*tr->ops)));
203   PetscCall(PetscObjectChangeTypeName((PetscObject)tr, method));
204   PetscCall((*r)(tr));
205   PetscFunctionReturn(PETSC_SUCCESS);
206 }
207 
208 /*@
209   DMPlexTransformGetType - Gets the type name (as a string) from the transform.
210 
211   Not Collective
212 
213   Input Parameter:
214 . tr - The `DMPlexTransform`
215 
216   Output Parameter:
217 . type - The `DMPlexTransformType` name
218 
219   Level: intermediate
220 
221 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformSetType()`, `DMPlexTransformCreate()`
222 @*/
223 PetscErrorCode DMPlexTransformGetType(DMPlexTransform tr, DMPlexTransformType *type)
224 {
225   PetscFunctionBegin;
226   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
227   PetscAssertPointer(type, 2);
228   PetscCall(DMPlexTransformRegisterAll());
229   *type = ((PetscObject)tr)->type_name;
230   PetscFunctionReturn(PETSC_SUCCESS);
231 }
232 
233 static PetscErrorCode DMPlexTransformView_Ascii(DMPlexTransform tr, PetscViewer v)
234 {
235   PetscViewerFormat format;
236 
237   PetscFunctionBegin;
238   PetscCall(PetscViewerGetFormat(v, &format));
239   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
240     const PetscInt *trTypes = NULL;
241     IS              trIS;
242     PetscInt        cols = 8;
243     PetscInt        Nrt  = 8, f, g;
244 
245     if (tr->trType) PetscCall(DMLabelView(tr->trType, v));
246     PetscCall(PetscViewerASCIIPrintf(v, "Source Starts\n"));
247     for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14s", DMPolytopeTypes[g]));
248     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
249     for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIIPrintf(v, " %14" PetscInt_FMT, tr->ctStart[f]));
250     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
251     PetscCall(PetscViewerASCIIPrintf(v, "Target Starts\n"));
252     for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14s", DMPolytopeTypes[g]));
253     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
254     for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIIPrintf(v, " %14" PetscInt_FMT, tr->ctStartNew[f]));
255     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
256 
257     if (tr->trType) {
258       PetscCall(DMLabelGetNumValues(tr->trType, &Nrt));
259       PetscCall(DMLabelGetValueIS(tr->trType, &trIS));
260       PetscCall(ISGetIndices(trIS, &trTypes));
261     }
262     PetscCall(PetscViewerASCIIPrintf(v, "Offsets\n"));
263     PetscCall(PetscViewerASCIIPrintf(v, "     "));
264     for (g = 0; g < cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14s", DMPolytopeTypes[g]));
265     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
266     for (f = 0; f < Nrt; ++f) {
267       PetscCall(PetscViewerASCIIPrintf(v, "%2" PetscInt_FMT "  |", trTypes ? trTypes[f] : f));
268       for (g = 0; g < cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14" PetscInt_FMT, tr->offset[f * DM_NUM_POLYTOPES + g]));
269       PetscCall(PetscViewerASCIIPrintf(v, " |\n"));
270     }
271     if (tr->trType) {
272       PetscCall(ISRestoreIndices(trIS, &trTypes));
273       PetscCall(ISDestroy(&trIS));
274     }
275   }
276   PetscFunctionReturn(PETSC_SUCCESS);
277 }
278 
279 /*@
280   DMPlexTransformView - Views a `DMPlexTransform`
281 
282   Collective
283 
284   Input Parameters:
285 + tr - the `DMPlexTransform` object to view
286 - v  - the viewer
287 
288   Level: beginner
289 
290 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `PetscViewer`, `DMPlexTransformDestroy()`, `DMPlexTransformCreate()`
291 @*/
292 PetscErrorCode DMPlexTransformView(DMPlexTransform tr, PetscViewer v)
293 {
294   PetscBool isascii;
295 
296   PetscFunctionBegin;
297   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
298   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)tr), &v));
299   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
300   PetscCheckSameComm(tr, 1, v, 2);
301   PetscCall(PetscViewerCheckWritable(v));
302   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)tr, v));
303   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &isascii));
304   if (isascii) PetscCall(DMPlexTransformView_Ascii(tr, v));
305   PetscTryTypeMethod(tr, view, v);
306   PetscFunctionReturn(PETSC_SUCCESS);
307 }
308 
309 /*@
310   DMPlexTransformSetFromOptions - Sets parameters in a transform from values in the options database
311 
312   Collective
313 
314   Input Parameter:
315 . tr - the `DMPlexTransform` object to set options for
316 
317   Options Database Keys:
318 + -dm_plex_transform_type                    - Set the transform type, e.g. refine_regular
319 . -dm_plex_transform_label_match_strata      - Only label points of the same stratum as the producing point
320 - -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
321 
322   Level: intermediate
323 
324 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()`
325 @*/
326 PetscErrorCode DMPlexTransformSetFromOptions(DMPlexTransform tr)
327 {
328   char        typeName[1024];
329   const char *defName = DMPLEXREFINEREGULAR;
330   PetscBool   flg;
331 
332   PetscFunctionBegin;
333   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
334   PetscObjectOptionsBegin((PetscObject)tr);
335   PetscCall(PetscOptionsFList("-dm_plex_transform_type", "DMPlexTransform", "DMPlexTransformSetType", DMPlexTransformList, defName, typeName, 1024, &flg));
336   if (flg) PetscCall(DMPlexTransformSetType(tr, typeName));
337   else if (!((PetscObject)tr)->type_name) PetscCall(DMPlexTransformSetType(tr, defName));
338   PetscCall(PetscOptionsBool("-dm_plex_transform_label_match_strata", "Only label points of the same stratum as the producing point", "", tr->labelMatchStrata, &tr->labelMatchStrata, NULL));
339   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));
340   PetscTryTypeMethod(tr, setfromoptions, PetscOptionsObject);
341   /* process any options handlers added with PetscObjectAddOptionsHandler() */
342   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)tr, PetscOptionsObject));
343   PetscOptionsEnd();
344   PetscFunctionReturn(PETSC_SUCCESS);
345 }
346 
347 /*@
348   DMPlexTransformDestroy - Destroys a `DMPlexTransform`
349 
350   Collective
351 
352   Input Parameter:
353 . tr - the transform object to destroy
354 
355   Level: beginner
356 
357 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()`
358 @*/
359 PetscErrorCode DMPlexTransformDestroy(DMPlexTransform *tr)
360 {
361   PetscInt c;
362 
363   PetscFunctionBegin;
364   if (!*tr) PetscFunctionReturn(PETSC_SUCCESS);
365   PetscValidHeaderSpecific(*tr, DMPLEXTRANSFORM_CLASSID, 1);
366   if (--((PetscObject)*tr)->refct > 0) {
367     *tr = NULL;
368     PetscFunctionReturn(PETSC_SUCCESS);
369   }
370 
371   PetscTryTypeMethod(*tr, destroy);
372   PetscCall(DMDestroy(&(*tr)->dm));
373   PetscCall(DMLabelDestroy(&(*tr)->active));
374   PetscCall(DMLabelDestroy(&(*tr)->trType));
375   PetscCall(PetscFree2((*tr)->ctOrderOld, (*tr)->ctOrderInvOld));
376   PetscCall(PetscFree2((*tr)->ctOrderNew, (*tr)->ctOrderInvNew));
377   PetscCall(PetscFree2((*tr)->ctStart, (*tr)->ctStartNew));
378   PetscCall(PetscFree((*tr)->offset));
379   PetscCall(PetscFree2((*tr)->depthStart, (*tr)->depthEnd));
380   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
381     PetscCall(PetscFEDestroy(&(*tr)->coordFE[c]));
382     PetscCall(PetscFEGeomDestroy(&(*tr)->refGeom[c]));
383   }
384   if ((*tr)->trVerts) {
385     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
386       DMPolytopeType *rct;
387       PetscInt       *rsize, *rcone, *rornt, Nct, n, r;
388 
389       if (DMPolytopeTypeGetDim((DMPolytopeType)c) > 0 && c != DM_POLYTOPE_UNKNOWN_CELL && c != DM_POLYTOPE_UNKNOWN_FACE) {
390         PetscCall(DMPlexTransformCellTransform(*tr, (DMPolytopeType)c, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
391         for (n = 0; n < Nct; ++n) {
392           if (rct[n] == DM_POLYTOPE_POINT) continue;
393           for (r = 0; r < rsize[n]; ++r) PetscCall(PetscFree((*tr)->trSubVerts[c][rct[n]][r]));
394           PetscCall(PetscFree((*tr)->trSubVerts[c][rct[n]]));
395         }
396       }
397       PetscCall(PetscFree((*tr)->trSubVerts[c]));
398       PetscCall(PetscFree((*tr)->trVerts[c]));
399     }
400   }
401   PetscCall(PetscFree3((*tr)->trNv, (*tr)->trVerts, (*tr)->trSubVerts));
402   PetscCall(PetscFree2((*tr)->coordFE, (*tr)->refGeom));
403   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
404   PetscCall(PetscHeaderDestroy(tr));
405   PetscFunctionReturn(PETSC_SUCCESS);
406 }
407 
408 static PetscErrorCode DMPlexTransformCreateOffset_Internal(DMPlexTransform tr, PetscInt ctOrderOld[], PetscInt ctStart[], PetscInt **offset)
409 {
410   DMLabel  trType = tr->trType;
411   PetscInt c, cN, *off;
412 
413   PetscFunctionBegin;
414   if (trType) {
415     DM              dm;
416     IS              rtIS;
417     const PetscInt *reftypes;
418     PetscInt        Nrt, r;
419 
420     PetscCall(DMPlexTransformGetDM(tr, &dm));
421     PetscCall(DMLabelGetNumValues(trType, &Nrt));
422     PetscCall(DMLabelGetValueIS(trType, &rtIS));
423     PetscCall(ISGetIndices(rtIS, &reftypes));
424     PetscCall(PetscCalloc1(Nrt * DM_NUM_POLYTOPES, &off));
425     for (r = 0; r < Nrt; ++r) {
426       const PetscInt  rt = reftypes[r];
427       IS              rtIS;
428       const PetscInt *points;
429       DMPolytopeType  ct;
430       PetscInt        np, p;
431 
432       PetscCall(DMLabelGetStratumIS(trType, rt, &rtIS));
433       PetscCall(ISGetLocalSize(rtIS, &np));
434       PetscCall(ISGetIndices(rtIS, &points));
435       if (!np) continue;
436       p = points[0];
437       PetscCall(ISRestoreIndices(rtIS, &points));
438       PetscCall(ISDestroy(&rtIS));
439       PetscCall(DMPlexGetCellType(dm, p, &ct));
440       for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) {
441         const DMPolytopeType ctNew = (DMPolytopeType)cN;
442         DMPolytopeType      *rct;
443         PetscInt            *rsize, *cone, *ornt;
444         PetscInt             Nct, n, s;
445 
446         if (DMPolytopeTypeGetDim(ct) < 0 || DMPolytopeTypeGetDim(ctNew) < 0) {
447           off[r * DM_NUM_POLYTOPES + ctNew] = -1;
448           break;
449         }
450         off[r * DM_NUM_POLYTOPES + ctNew] = 0;
451         for (s = 0; s <= r; ++s) {
452           const PetscInt st = reftypes[s];
453           DMPolytopeType sct;
454           PetscInt       q, qrt;
455 
456           PetscCall(DMLabelGetStratumIS(trType, st, &rtIS));
457           PetscCall(ISGetLocalSize(rtIS, &np));
458           PetscCall(ISGetIndices(rtIS, &points));
459           if (!np) continue;
460           q = points[0];
461           PetscCall(ISRestoreIndices(rtIS, &points));
462           PetscCall(ISDestroy(&rtIS));
463           PetscCall(DMPlexGetCellType(dm, q, &sct));
464           PetscCall(DMPlexTransformCellTransform(tr, sct, q, &qrt, &Nct, &rct, &rsize, &cone, &ornt));
465           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);
466           if (st == rt) {
467             for (n = 0; n < Nct; ++n)
468               if (rct[n] == ctNew) break;
469             if (n == Nct) off[r * DM_NUM_POLYTOPES + ctNew] = -1;
470             break;
471           }
472           for (n = 0; n < Nct; ++n) {
473             if (rct[n] == ctNew) {
474               PetscInt sn;
475 
476               PetscCall(DMLabelGetStratumSize(trType, st, &sn));
477               off[r * DM_NUM_POLYTOPES + ctNew] += sn * rsize[n];
478             }
479           }
480         }
481       }
482     }
483     PetscCall(ISRestoreIndices(rtIS, &reftypes));
484     PetscCall(ISDestroy(&rtIS));
485   } else {
486     PetscCall(PetscCalloc1(DM_NUM_POLYTOPES * DM_NUM_POLYTOPES, &off));
487     for (c = DM_POLYTOPE_POINT; c < DM_NUM_POLYTOPES; ++c) {
488       const DMPolytopeType ct = (DMPolytopeType)c;
489       for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) {
490         const DMPolytopeType ctNew = (DMPolytopeType)cN;
491         DMPolytopeType      *rct;
492         PetscInt            *rsize, *cone, *ornt;
493         PetscInt             Nct, n, i;
494 
495         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) {
496           off[ct * DM_NUM_POLYTOPES + ctNew] = -1;
497           continue;
498         }
499         off[ct * DM_NUM_POLYTOPES + ctNew] = 0;
500         for (i = DM_POLYTOPE_POINT; i < DM_NUM_POLYTOPES; ++i) {
501           const DMPolytopeType ict  = (DMPolytopeType)ctOrderOld[i];
502           const DMPolytopeType ictn = (DMPolytopeType)ctOrderOld[i + 1];
503 
504           PetscCall(DMPlexTransformCellTransform(tr, ict, PETSC_DETERMINE, NULL, &Nct, &rct, &rsize, &cone, &ornt));
505           if (ict == ct) {
506             for (n = 0; n < Nct; ++n)
507               if (rct[n] == ctNew) break;
508             if (n == Nct) off[ct * DM_NUM_POLYTOPES + ctNew] = -1;
509             break;
510           }
511           for (n = 0; n < Nct; ++n)
512             if (rct[n] == ctNew) off[ct * DM_NUM_POLYTOPES + ctNew] += (ctStart[ictn] - ctStart[ict]) * rsize[n];
513         }
514       }
515     }
516   }
517   *offset = off;
518   PetscFunctionReturn(PETSC_SUCCESS);
519 }
520 
521 /*@
522   DMPlexTransformSetUp - Create the tables that drive the transform
523 
524   Input Parameter:
525 . tr - The `DMPlexTransform` object
526 
527   Level: intermediate
528 
529 .seealso: [](plex_transform_table), [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
530 @*/
531 PetscErrorCode DMPlexTransformSetUp(DMPlexTransform tr)
532 {
533   DM             dm;
534   DMPolytopeType ctCell;
535   PetscInt       pStart, pEnd, p, c, celldim = 0;
536 
537   PetscFunctionBegin;
538   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
539   if (tr->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
540   PetscTryTypeMethod(tr, setup);
541   PetscCall(DMPlexTransformGetDM(tr, &dm));
542   PetscCall(DMSetSnapToGeomModel(dm, NULL));
543   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
544   if (pEnd > pStart) {
545     // Ignore cells hanging off of embedded surfaces
546     PetscInt c = pStart;
547 
548     ctCell = DM_POLYTOPE_FV_GHOST;
549     while (DMPolytopeTypeGetDim(ctCell) < 0) PetscCall(DMPlexGetCellType(dm, c++, &ctCell));
550   } else {
551     PetscInt dim;
552 
553     PetscCall(DMGetDimension(dm, &dim));
554     switch (dim) {
555     case 0:
556       ctCell = DM_POLYTOPE_POINT;
557       break;
558     case 1:
559       ctCell = DM_POLYTOPE_SEGMENT;
560       break;
561     case 2:
562       ctCell = DM_POLYTOPE_TRIANGLE;
563       break;
564     case 3:
565       ctCell = DM_POLYTOPE_TETRAHEDRON;
566       break;
567     default:
568       ctCell = DM_POLYTOPE_UNKNOWN;
569     }
570   }
571   PetscCall(DMPlexCreateCellTypeOrder_Internal(DMPolytopeTypeGetDim(ctCell), &tr->ctOrderOld, &tr->ctOrderInvOld));
572   for (p = pStart; p < pEnd; ++p) {
573     DMPolytopeType  ct;
574     DMPolytopeType *rct;
575     PetscInt       *rsize, *cone, *ornt;
576     PetscInt        Nct, n;
577 
578     PetscCall(DMPlexGetCellType(dm, p, &ct));
579     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);
580     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt));
581     for (n = 0; n < Nct; ++n) celldim = PetscMax(celldim, DMPolytopeTypeGetDim(rct[n]));
582   }
583   PetscCall(DMPlexCreateCellTypeOrder_Internal(celldim, &tr->ctOrderNew, &tr->ctOrderInvNew));
584   /* Construct sizes and offsets for each cell type */
585   if (!tr->ctStart) {
586     PetscInt *ctS, *ctSN, *ctC, *ctCN;
587 
588     PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctS, DM_NUM_POLYTOPES + 1, &ctSN));
589     PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctC, DM_NUM_POLYTOPES + 1, &ctCN));
590     for (p = pStart; p < pEnd; ++p) {
591       DMPolytopeType  ct;
592       DMPolytopeType *rct;
593       PetscInt       *rsize, *cone, *ornt;
594       PetscInt        Nct, n;
595 
596       PetscCall(DMPlexGetCellType(dm, p, &ct));
597       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);
598       ++ctC[ct];
599       PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt));
600       for (n = 0; n < Nct; ++n) ctCN[rct[n]] += rsize[n];
601     }
602     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
603       const PetscInt cto  = tr->ctOrderOld[c];
604       const PetscInt cton = tr->ctOrderOld[c + 1];
605       const PetscInt ctn  = tr->ctOrderNew[c];
606       const PetscInt ctnn = tr->ctOrderNew[c + 1];
607 
608       ctS[cton]  = ctS[cto] + ctC[cto];
609       ctSN[ctnn] = ctSN[ctn] + ctCN[ctn];
610     }
611     PetscCall(PetscFree2(ctC, ctCN));
612     tr->ctStart    = ctS;
613     tr->ctStartNew = ctSN;
614   }
615   PetscCall(DMPlexTransformCreateOffset_Internal(tr, tr->ctOrderOld, tr->ctStart, &tr->offset));
616   // Compute depth information
617   tr->depth = -1;
618   for (c = 0; c < DM_NUM_POLYTOPES; ++c)
619     if (tr->ctStartNew[tr->ctOrderNew[c + 1]] > tr->ctStartNew[tr->ctOrderNew[c]]) tr->depth = PetscMax(tr->depth, DMPolytopeTypeGetDim((DMPolytopeType)tr->ctOrderNew[c]));
620   PetscCall(PetscMalloc2(tr->depth + 1, &tr->depthStart, tr->depth + 1, &tr->depthEnd));
621   for (PetscInt d = 0; d <= tr->depth; ++d) {
622     tr->depthStart[d] = PETSC_INT_MAX;
623     tr->depthEnd[d]   = -1;
624   }
625   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
626     const PetscInt dep = DMPolytopeTypeGetDim((DMPolytopeType)tr->ctOrderNew[c]);
627 
628     if (tr->ctStartNew[tr->ctOrderNew[c + 1]] <= tr->ctStartNew[tr->ctOrderNew[c]]) continue;
629     tr->depthStart[dep] = PetscMin(tr->depthStart[dep], tr->ctStartNew[tr->ctOrderNew[c]]);
630     tr->depthEnd[dep]   = PetscMax(tr->depthEnd[dep], tr->ctStartNew[tr->ctOrderNew[c + 1]]);
631   }
632   tr->setupcalled = PETSC_TRUE;
633   PetscFunctionReturn(PETSC_SUCCESS);
634 }
635 
636 /*@
637   DMPlexTransformGetDM - Get the base `DM` for the transform
638 
639   Input Parameter:
640 . tr - The `DMPlexTransform` object
641 
642   Output Parameter:
643 . dm - The original `DM` which will be transformed
644 
645   Level: intermediate
646 
647 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetDM()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
648 @*/
649 PetscErrorCode DMPlexTransformGetDM(DMPlexTransform tr, DM *dm)
650 {
651   PetscFunctionBegin;
652   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
653   PetscAssertPointer(dm, 2);
654   *dm = tr->dm;
655   PetscFunctionReturn(PETSC_SUCCESS);
656 }
657 
658 /*@
659   DMPlexTransformSetDM - Set the base `DM` for the transform
660 
661   Input Parameters:
662 + tr - The `DMPlexTransform` object
663 - dm - The original `DM` which will be transformed
664 
665   Level: intermediate
666 
667   Note:
668   The user does not typically call this, as it is called by `DMPlexTransformApply()`.
669 
670 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetDM()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
671 @*/
672 PetscErrorCode DMPlexTransformSetDM(DMPlexTransform tr, DM dm)
673 {
674   PetscFunctionBegin;
675   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
676   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
677   PetscCall(PetscObjectReference((PetscObject)dm));
678   PetscCall(DMDestroy(&tr->dm));
679   tr->dm = dm;
680   PetscFunctionReturn(PETSC_SUCCESS);
681 }
682 
683 /*@
684   DMPlexTransformGetActive - Get the `DMLabel` marking the active points for the transform
685 
686   Input Parameter:
687 . tr - The `DMPlexTransform` object
688 
689   Output Parameter:
690 . active - The `DMLabel` indicating which points will be transformed
691 
692   Level: intermediate
693 
694 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
695 @*/
696 PetscErrorCode DMPlexTransformGetActive(DMPlexTransform tr, DMLabel *active)
697 {
698   PetscFunctionBegin;
699   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
700   PetscAssertPointer(active, 2);
701   *active = tr->active;
702   PetscFunctionReturn(PETSC_SUCCESS);
703 }
704 
705 /*@
706   DMPlexTransformSetActive - Set the `DMLabel` marking the active points for the transform
707 
708   Input Parameters:
709 + tr     - The `DMPlexTransform` object
710 - active - The original `DM` which will be transformed
711 
712   Level: intermediate
713 
714   Note:
715   This only applies to transforms that can operator on a subset of the mesh, listed in [](plex_transform_table).
716 
717 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetDM()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
718 @*/
719 PetscErrorCode DMPlexTransformSetActive(DMPlexTransform tr, DMLabel active)
720 {
721   PetscFunctionBegin;
722   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
723   if (active) PetscValidHeaderSpecific(active, DMLABEL_CLASSID, 2);
724   PetscCall(PetscObjectReference((PetscObject)active));
725   PetscCall(DMLabelDestroy(&tr->active));
726   tr->active = active;
727   PetscFunctionReturn(PETSC_SUCCESS);
728 }
729 
730 static PetscErrorCode DMPlexTransformGetCoordinateFE(DMPlexTransform tr, DMPolytopeType ct, PetscFE *fe)
731 {
732   PetscFunctionBegin;
733   if (!tr->coordFE[ct]) {
734     PetscInt dim, cdim;
735 
736     dim = DMPolytopeTypeGetDim(ct);
737     PetscCall(DMGetCoordinateDim(tr->dm, &cdim));
738     PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, cdim, ct, 1, PETSC_DETERMINE, &tr->coordFE[ct]));
739     {
740       PetscDualSpace  dsp;
741       PetscQuadrature quad;
742       DM              K;
743       PetscFEGeom    *cg;
744       PetscScalar    *Xq;
745       PetscReal      *xq, *wq;
746       PetscInt        Nq, q;
747 
748       PetscCall(DMPlexTransformGetCellVertices(tr, ct, &Nq, &Xq));
749       PetscCall(PetscMalloc1(Nq * cdim, &xq));
750       for (q = 0; q < Nq * cdim; ++q) xq[q] = PetscRealPart(Xq[q]);
751       PetscCall(PetscMalloc1(Nq, &wq));
752       for (q = 0; q < Nq; ++q) wq[q] = 1.0;
753       PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
754       PetscCall(PetscQuadratureSetData(quad, dim, 1, Nq, xq, wq));
755       PetscCall(PetscFESetQuadrature(tr->coordFE[ct], quad));
756 
757       PetscCall(PetscFEGetDualSpace(tr->coordFE[ct], &dsp));
758       PetscCall(PetscDualSpaceGetDM(dsp, &K));
759       PetscCall(PetscFEGeomCreate(quad, 1, cdim, PETSC_FALSE, &tr->refGeom[ct]));
760       cg = tr->refGeom[ct];
761       PetscCall(DMPlexComputeCellGeometryFEM(K, 0, NULL, cg->v, cg->J, cg->invJ, cg->detJ));
762       PetscCall(PetscQuadratureDestroy(&quad));
763     }
764   }
765   *fe = tr->coordFE[ct];
766   PetscFunctionReturn(PETSC_SUCCESS);
767 }
768 
769 PetscErrorCode DMPlexTransformSetDimensions_Internal(DMPlexTransform tr, DM dm, DM tdm)
770 {
771   PetscInt dim, cdim;
772 
773   PetscFunctionBegin;
774   PetscCall(DMGetDimension(dm, &dim));
775   PetscCall(DMSetDimension(tdm, dim));
776   PetscCall(DMGetCoordinateDim(dm, &cdim));
777   PetscCall(DMSetCoordinateDim(tdm, cdim));
778   PetscFunctionReturn(PETSC_SUCCESS);
779 }
780 
781 /*@
782   DMPlexTransformSetDimensions - Set the dimensions for the transformed `DM`
783 
784   Input Parameters:
785 + tr - The `DMPlexTransform` object
786 - dm - The original `DM`
787 
788   Output Parameter:
789 . tdm - The transformed `DM`
790 
791   Level: advanced
792 
793 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
794 @*/
795 PetscErrorCode DMPlexTransformSetDimensions(DMPlexTransform tr, DM dm, DM tdm)
796 {
797   PetscFunctionBegin;
798   PetscUseTypeMethod(tr, setdimensions, dm, tdm);
799   PetscFunctionReturn(PETSC_SUCCESS);
800 }
801 
802 PetscErrorCode DMPlexTransformGetChart(DMPlexTransform tr, PetscInt *pStart, PetscInt *pEnd)
803 {
804   PetscFunctionBegin;
805   if (pStart) *pStart = 0;
806   if (pEnd) *pEnd = tr->ctStartNew[tr->ctOrderNew[DM_NUM_POLYTOPES]];
807   PetscFunctionReturn(PETSC_SUCCESS);
808 }
809 
810 PetscErrorCode DMPlexTransformGetCellType(DMPlexTransform tr, PetscInt cell, DMPolytopeType *celltype)
811 {
812   PetscInt ctNew;
813 
814   PetscFunctionBegin;
815   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
816   PetscAssertPointer(celltype, 3);
817   /* TODO Can do bisection since everything is sorted */
818   for (ctNew = DM_POLYTOPE_POINT; ctNew < DM_NUM_POLYTOPES; ++ctNew) {
819     PetscInt ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]];
820 
821     if (cell >= ctSN && cell < ctEN) break;
822   }
823   PetscCheck(ctNew < DM_NUM_POLYTOPES, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " cannot be located in the transformed mesh", cell);
824   *celltype = (DMPolytopeType)ctNew;
825   PetscFunctionReturn(PETSC_SUCCESS);
826 }
827 
828 PetscErrorCode DMPlexTransformGetCellTypeStratum(DMPlexTransform tr, DMPolytopeType celltype, PetscInt *start, PetscInt *end)
829 {
830   PetscFunctionBegin;
831   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
832   if (start) *start = tr->ctStartNew[celltype];
833   if (end) *end = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[celltype] + 1]];
834   PetscFunctionReturn(PETSC_SUCCESS);
835 }
836 
837 PetscErrorCode DMPlexTransformGetDepth(DMPlexTransform tr, PetscInt *depth)
838 {
839   PetscFunctionBegin;
840   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
841   *depth = tr->depth;
842   PetscFunctionReturn(PETSC_SUCCESS);
843 }
844 
845 PetscErrorCode DMPlexTransformGetDepthStratum(DMPlexTransform tr, PetscInt depth, PetscInt *start, PetscInt *end)
846 {
847   PetscFunctionBegin;
848   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
849   if (start) *start = tr->depthStart[depth];
850   if (end) *end = tr->depthEnd[depth];
851   PetscFunctionReturn(PETSC_SUCCESS);
852 }
853 
854 /*@
855   DMPlexTransformGetTargetPoint - Get the number of a point in the transformed mesh based on information from the original mesh.
856 
857   Not Collective
858 
859   Input Parameters:
860 + tr    - The `DMPlexTransform`
861 . ct    - The type of the original point which produces the new point
862 . ctNew - The type of the new point
863 . p     - The original point which produces the new point
864 - r     - The replica number of the new point, meaning it is the rth point of type `ctNew` produced from `p`
865 
866   Output Parameter:
867 . pNew - The new point number
868 
869   Level: developer
870 
871 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSourcePoint()`, `DMPlexTransformCellTransform()`
872 @*/
873 PetscErrorCode DMPlexTransformGetTargetPoint(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType ctNew, PetscInt p, PetscInt r, PetscInt *pNew)
874 {
875   DMPolytopeType *rct;
876   PetscInt       *rsize, *cone, *ornt;
877   PetscInt        rt, Nct, n, off, rp;
878   DMLabel         trType = tr->trType;
879   PetscInt        ctS = tr->ctStart[ct], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ct] + 1]];
880   PetscInt        ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]];
881   PetscInt        newp = ctSN, cind;
882 
883   PetscFunctionBeginHot;
884   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);
885   PetscCall(DMPlexTransformCellTransform(tr, ct, p, &rt, &Nct, &rct, &rsize, &cone, &ornt));
886   if (trType) {
887     PetscCall(DMLabelGetValueIndex(trType, rt, &cind));
888     PetscCall(DMLabelGetStratumPointIndex(trType, rt, p, &rp));
889     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);
890   } else {
891     cind = ct;
892     rp   = p - ctS;
893   }
894   off = tr->offset[cind * DM_NUM_POLYTOPES + ctNew];
895   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);
896   newp += off;
897   for (n = 0; n < Nct; ++n) {
898     if (rct[n] == ctNew) {
899       if (rsize[n] && r >= rsize[n])
900         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]);
901       newp += rp * rsize[n] + r;
902       break;
903     }
904   }
905 
906   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);
907   *pNew = newp;
908   PetscFunctionReturn(PETSC_SUCCESS);
909 }
910 
911 /*@
912   DMPlexTransformGetSourcePoint - Get the number of a point in the original mesh based on information from the transformed mesh.
913 
914   Not Collective
915 
916   Input Parameters:
917 + tr   - The `DMPlexTransform`
918 - pNew - The new point number
919 
920   Output Parameters:
921 + ct    - The type of the original point which produces the new point
922 . ctNew - The type of the new point
923 . p     - The original point which produces the new point
924 - r     - The replica number of the new point, meaning it is the rth point of type ctNew produced from p
925 
926   Level: developer
927 
928 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetTargetPoint()`, `DMPlexTransformCellTransform()`
929 @*/
930 PetscErrorCode DMPlexTransformGetSourcePoint(DMPlexTransform tr, PetscInt pNew, DMPolytopeType *ct, DMPolytopeType *ctNew, PetscInt *p, PetscInt *r)
931 {
932   DMLabel         trType = tr->trType;
933   DMPolytopeType *rct, ctN;
934   PetscInt       *rsize, *cone, *ornt;
935   PetscInt        rt = -1, rtTmp, Nct, n, rp = 0, rO = 0, pO;
936   PetscInt        offset = -1, ctS, ctE, ctO = 0, ctTmp, rtS;
937 
938   PetscFunctionBegin;
939   PetscCall(DMPlexTransformGetCellType(tr, pNew, &ctN));
940   if (trType) {
941     DM              dm;
942     IS              rtIS;
943     const PetscInt *reftypes;
944     PetscInt        Nrt, r, rtStart;
945 
946     PetscCall(DMPlexTransformGetDM(tr, &dm));
947     PetscCall(DMLabelGetNumValues(trType, &Nrt));
948     PetscCall(DMLabelGetValueIS(trType, &rtIS));
949     PetscCall(ISGetIndices(rtIS, &reftypes));
950     for (r = 0; r < Nrt; ++r) {
951       const PetscInt off = tr->offset[r * DM_NUM_POLYTOPES + ctN];
952 
953       if (tr->ctStartNew[ctN] + off > pNew) continue;
954       /* Check that any of this refinement type exist */
955       /* TODO Actually keep track of the number produced here instead */
956       if (off > offset) {
957         rt     = reftypes[r];
958         offset = off;
959       }
960     }
961     PetscCall(ISRestoreIndices(rtIS, &reftypes));
962     PetscCall(ISDestroy(&rtIS));
963     PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew);
964     /* TODO Map refinement types to cell types */
965     PetscCall(DMLabelGetStratumBounds(trType, rt, &rtStart, NULL));
966     PetscCheck(rtStart >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Refinement type %" PetscInt_FMT " has no source points", rt);
967     for (ctO = 0; ctO < DM_NUM_POLYTOPES; ++ctO) {
968       PetscInt ctS = tr->ctStart[ctO], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]];
969 
970       if ((rtStart >= ctS) && (rtStart < ctE)) break;
971     }
972     PetscCheck(ctO != DM_NUM_POLYTOPES, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not determine a cell type for refinement type %" PetscInt_FMT, rt);
973   } else {
974     for (ctTmp = 0; ctTmp < DM_NUM_POLYTOPES; ++ctTmp) {
975       const PetscInt off = tr->offset[ctTmp * DM_NUM_POLYTOPES + ctN];
976 
977       if (tr->ctStartNew[ctN] + off > pNew) continue;
978       if (tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctTmp] + 1]] <= tr->ctStart[ctTmp]) continue;
979       /* TODO Actually keep track of the number produced here instead */
980       if (off > offset) {
981         ctO    = ctTmp;
982         offset = off;
983       }
984     }
985     rt = -1;
986     PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew);
987   }
988   ctS = tr->ctStart[ctO];
989   ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]];
990   if (trType) {
991     for (rtS = ctS; rtS < ctE; ++rtS) {
992       PetscInt val;
993       PetscCall(DMLabelGetValue(trType, rtS, &val));
994       if (val == rt) break;
995     }
996     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);
997   } else rtS = ctS;
998   PetscCall(DMPlexTransformCellTransform(tr, (DMPolytopeType)ctO, rtS, &rtTmp, &Nct, &rct, &rsize, &cone, &ornt));
999   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);
1000   for (n = 0; n < Nct; ++n) {
1001     if (rct[n] == ctN) {
1002       PetscInt tmp = pNew - tr->ctStartNew[ctN] - offset, val, c;
1003 
1004       if (trType) {
1005         for (c = ctS; c < ctE; ++c) {
1006           PetscCall(DMLabelGetValue(trType, c, &val));
1007           if (val == rt) {
1008             if (tmp < rsize[n]) break;
1009             tmp -= rsize[n];
1010           }
1011         }
1012         PetscCheck(c < ctE, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Parent point for target point %" PetscInt_FMT " could be not found", pNew);
1013         rp = c - ctS;
1014         rO = tmp;
1015       } else {
1016         // This assumes that all points of type ctO transform the same way
1017         rp = tmp / rsize[n];
1018         rO = tmp % rsize[n];
1019       }
1020       break;
1021     }
1022   }
1023   PetscCheck(n != Nct, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number for target point %" PetscInt_FMT " could be not found", pNew);
1024   pO = rp + ctS;
1025   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);
1026   if (ct) *ct = (DMPolytopeType)ctO;
1027   if (ctNew) *ctNew = (DMPolytopeType)ctN;
1028   if (p) *p = pO;
1029   if (r) *r = rO;
1030   PetscFunctionReturn(PETSC_SUCCESS);
1031 }
1032 
1033 /*@
1034   DMPlexTransformCellTransform - Describes the transform of a given source cell into a set of other target cells. These produced cells become the new mesh.
1035 
1036   Input Parameters:
1037 + tr     - The `DMPlexTransform` object
1038 . source - The source cell type
1039 - p      - The source point, which can also determine the refine type
1040 
1041   Output Parameters:
1042 + rt     - The refine type for this point
1043 . Nt     - The number of types produced by this point
1044 . target - An array of length `Nt` giving the types produced
1045 . size   - An array of length `Nt` giving the number of cells of each type produced
1046 . cone   - An array of length `Nt`*size[t]*coneSize[t] giving the cell type for each point in the cone of each produced point
1047 - ornt   - An array of length `Nt`*size[t]*coneSize[t] giving the orientation for each point in the cone of each produced point
1048 
1049   Level: advanced
1050 
1051   Notes:
1052   The cone array gives the cone of each subcell listed by the first three outputs. For each cone point, we
1053   need the cell type, point identifier, and orientation within the subcell. The orientation is with respect to the canonical
1054   division (described in these outputs) of the cell in the original mesh. The point identifier is given by
1055 .vb
1056    the number of cones to be taken, or 0 for the current cell
1057    the cell cone point number at each level from which it is subdivided
1058    the replica number r of the subdivision.
1059 .ve
1060   The orientation is with respect to the canonical cone orientation. For example, the prescription for edge division is
1061 .vb
1062    Nt     = 2
1063    target = {DM_POLYTOPE_POINT, DM_POLYTOPE_SEGMENT}
1064    size   = {1, 2}
1065    cone   = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 0, 0,  DM_POLYTOPE_POINT, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0}
1066    ornt   = {                         0,                       0,                        0,                          0}
1067 .ve
1068 
1069 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
1070 @*/
1071 PetscErrorCode DMPlexTransformCellTransform(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[])
1072 {
1073   PetscFunctionBegin;
1074   PetscUseTypeMethod(tr, celltransform, source, p, rt, Nt, target, size, cone, ornt);
1075   PetscFunctionReturn(PETSC_SUCCESS);
1076 }
1077 
1078 PetscErrorCode DMPlexTransformGetSubcellOrientationIdentity(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew)
1079 {
1080   PetscFunctionBegin;
1081   *rnew = r;
1082   *onew = DMPolytopeTypeComposeOrientation(tct, o, so);
1083   PetscFunctionReturn(PETSC_SUCCESS);
1084 }
1085 
1086 /* Returns the same thing */
1087 PetscErrorCode DMPlexTransformCellTransformIdentity(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[])
1088 {
1089   static DMPolytopeType vertexT[] = {DM_POLYTOPE_POINT};
1090   static PetscInt       vertexS[] = {1};
1091   static PetscInt       vertexC[] = {0};
1092   static PetscInt       vertexO[] = {0};
1093   static DMPolytopeType edgeT[]   = {DM_POLYTOPE_SEGMENT};
1094   static PetscInt       edgeS[]   = {1};
1095   static PetscInt       edgeC[]   = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0};
1096   static PetscInt       edgeO[]   = {0, 0};
1097   static DMPolytopeType tedgeT[]  = {DM_POLYTOPE_POINT_PRISM_TENSOR};
1098   static PetscInt       tedgeS[]  = {1};
1099   static PetscInt       tedgeC[]  = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0};
1100   static PetscInt       tedgeO[]  = {0, 0};
1101   static DMPolytopeType triT[]    = {DM_POLYTOPE_TRIANGLE};
1102   static PetscInt       triS[]    = {1};
1103   static PetscInt       triC[]    = {DM_POLYTOPE_SEGMENT, 1, 0, 0, DM_POLYTOPE_SEGMENT, 1, 1, 0, DM_POLYTOPE_SEGMENT, 1, 2, 0};
1104   static PetscInt       triO[]    = {0, 0, 0};
1105   static DMPolytopeType quadT[]   = {DM_POLYTOPE_QUADRILATERAL};
1106   static PetscInt       quadS[]   = {1};
1107   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};
1108   static PetscInt       quadO[]   = {0, 0, 0, 0};
1109   static DMPolytopeType tquadT[]  = {DM_POLYTOPE_SEG_PRISM_TENSOR};
1110   static PetscInt       tquadS[]  = {1};
1111   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};
1112   static PetscInt       tquadO[]  = {0, 0, 0, 0};
1113   static DMPolytopeType tetT[]    = {DM_POLYTOPE_TETRAHEDRON};
1114   static PetscInt       tetS[]    = {1};
1115   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};
1116   static PetscInt       tetO[]    = {0, 0, 0, 0};
1117   static DMPolytopeType hexT[]    = {DM_POLYTOPE_HEXAHEDRON};
1118   static PetscInt       hexS[]    = {1};
1119   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};
1120   static PetscInt       hexO[] = {0, 0, 0, 0, 0, 0};
1121   static DMPolytopeType tripT[]   = {DM_POLYTOPE_TRI_PRISM};
1122   static PetscInt       tripS[]   = {1};
1123   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};
1124   static PetscInt       tripO[]   = {0, 0, 0, 0, 0};
1125   static DMPolytopeType ttripT[]  = {DM_POLYTOPE_TRI_PRISM_TENSOR};
1126   static PetscInt       ttripS[]  = {1};
1127   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};
1128   static PetscInt       ttripO[]  = {0, 0, 0, 0, 0};
1129   static DMPolytopeType tquadpT[] = {DM_POLYTOPE_QUAD_PRISM_TENSOR};
1130   static PetscInt       tquadpS[] = {1};
1131   static PetscInt       tquadpC[] = {DM_POLYTOPE_QUADRILATERAL,    1, 0, 0, DM_POLYTOPE_QUADRILATERAL,    1, 1, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 2, 0,
1132                                      DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 3, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 4, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 5, 0};
1133   static PetscInt       tquadpO[] = {0, 0, 0, 0, 0, 0};
1134   static DMPolytopeType pyrT[]    = {DM_POLYTOPE_PYRAMID};
1135   static PetscInt       pyrS[]    = {1};
1136   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};
1137   static PetscInt       pyrO[]    = {0, 0, 0, 0, 0};
1138 
1139   PetscFunctionBegin;
1140   if (rt) *rt = 0;
1141   switch (source) {
1142   case DM_POLYTOPE_POINT:
1143     *Nt     = 1;
1144     *target = vertexT;
1145     *size   = vertexS;
1146     *cone   = vertexC;
1147     *ornt   = vertexO;
1148     break;
1149   case DM_POLYTOPE_SEGMENT:
1150     *Nt     = 1;
1151     *target = edgeT;
1152     *size   = edgeS;
1153     *cone   = edgeC;
1154     *ornt   = edgeO;
1155     break;
1156   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1157     *Nt     = 1;
1158     *target = tedgeT;
1159     *size   = tedgeS;
1160     *cone   = tedgeC;
1161     *ornt   = tedgeO;
1162     break;
1163   case DM_POLYTOPE_TRIANGLE:
1164     *Nt     = 1;
1165     *target = triT;
1166     *size   = triS;
1167     *cone   = triC;
1168     *ornt   = triO;
1169     break;
1170   case DM_POLYTOPE_QUADRILATERAL:
1171     *Nt     = 1;
1172     *target = quadT;
1173     *size   = quadS;
1174     *cone   = quadC;
1175     *ornt   = quadO;
1176     break;
1177   case DM_POLYTOPE_SEG_PRISM_TENSOR:
1178     *Nt     = 1;
1179     *target = tquadT;
1180     *size   = tquadS;
1181     *cone   = tquadC;
1182     *ornt   = tquadO;
1183     break;
1184   case DM_POLYTOPE_TETRAHEDRON:
1185     *Nt     = 1;
1186     *target = tetT;
1187     *size   = tetS;
1188     *cone   = tetC;
1189     *ornt   = tetO;
1190     break;
1191   case DM_POLYTOPE_HEXAHEDRON:
1192     *Nt     = 1;
1193     *target = hexT;
1194     *size   = hexS;
1195     *cone   = hexC;
1196     *ornt   = hexO;
1197     break;
1198   case DM_POLYTOPE_TRI_PRISM:
1199     *Nt     = 1;
1200     *target = tripT;
1201     *size   = tripS;
1202     *cone   = tripC;
1203     *ornt   = tripO;
1204     break;
1205   case DM_POLYTOPE_TRI_PRISM_TENSOR:
1206     *Nt     = 1;
1207     *target = ttripT;
1208     *size   = ttripS;
1209     *cone   = ttripC;
1210     *ornt   = ttripO;
1211     break;
1212   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
1213     *Nt     = 1;
1214     *target = tquadpT;
1215     *size   = tquadpS;
1216     *cone   = tquadpC;
1217     *ornt   = tquadpO;
1218     break;
1219   case DM_POLYTOPE_PYRAMID:
1220     *Nt     = 1;
1221     *target = pyrT;
1222     *size   = pyrS;
1223     *cone   = pyrC;
1224     *ornt   = pyrO;
1225     break;
1226   default:
1227     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No refinement strategy for %s", DMPolytopeTypes[source]);
1228   }
1229   PetscFunctionReturn(PETSC_SUCCESS);
1230 }
1231 
1232 /*@
1233   DMPlexTransformGetSubcellOrientation - Transform the replica number and orientation for a target point according to the group action for the source point
1234 
1235   Not Collective
1236 
1237   Input Parameters:
1238 + tr  - The `DMPlexTransform`
1239 . sct - The source point cell type, from whom the new cell is being produced
1240 . sp  - The source point
1241 . so  - The orientation of the source point in its enclosing parent
1242 . tct - The target point cell type
1243 . r   - The replica number requested for the produced cell type
1244 - o   - The orientation of the replica
1245 
1246   Output Parameters:
1247 + rnew - The replica number, given the orientation of the parent
1248 - onew - The replica orientation, given the orientation of the parent
1249 
1250   Level: advanced
1251 
1252 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformCellTransform()`, `DMPlexTransformApply()`
1253 @*/
1254 PetscErrorCode DMPlexTransformGetSubcellOrientation(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew)
1255 {
1256   PetscFunctionBeginHot;
1257   PetscUseTypeMethod(tr, getsubcellorientation, sct, sp, so, tct, r, o, rnew, onew);
1258   PetscFunctionReturn(PETSC_SUCCESS);
1259 }
1260 
1261 static PetscErrorCode DMPlexTransformSetConeSizes(DMPlexTransform tr, DM rdm)
1262 {
1263   DM       dm;
1264   PetscInt pStart, pEnd, p, pNew;
1265 
1266   PetscFunctionBegin;
1267   PetscCall(DMPlexTransformGetDM(tr, &dm));
1268   /* Must create the celltype label here so that we do not automatically try to compute the types */
1269   PetscCall(DMCreateLabel(rdm, "celltype"));
1270   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1271   for (p = pStart; p < pEnd; ++p) {
1272     DMPolytopeType  ct;
1273     DMPolytopeType *rct;
1274     PetscInt       *rsize, *rcone, *rornt;
1275     PetscInt        Nct, n, r;
1276 
1277     PetscCall(DMPlexGetCellType(dm, p, &ct));
1278     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1279     for (n = 0; n < Nct; ++n) {
1280       for (r = 0; r < rsize[n]; ++r) {
1281         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1282         PetscCall(DMPlexSetConeSize(rdm, pNew, DMPolytopeTypeGetConeSize(rct[n])));
1283         PetscCall(DMPlexSetCellType(rdm, pNew, rct[n]));
1284       }
1285     }
1286   }
1287   /* Let the DM know we have set all the cell types */
1288   {
1289     DMLabel  ctLabel;
1290     DM_Plex *plex = (DM_Plex *)rdm->data;
1291 
1292     PetscCall(DMPlexGetCellTypeLabel(rdm, &ctLabel));
1293     PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &plex->celltypeState));
1294   }
1295   PetscFunctionReturn(PETSC_SUCCESS);
1296 }
1297 
1298 PetscErrorCode DMPlexTransformGetConeSize(DMPlexTransform tr, PetscInt q, PetscInt *coneSize)
1299 {
1300   DMPolytopeType ctNew;
1301 
1302   PetscFunctionBegin;
1303   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
1304   PetscAssertPointer(coneSize, 3);
1305   PetscCall(DMPlexTransformGetCellType(tr, q, &ctNew));
1306   *coneSize = DMPolytopeTypeGetConeSize((DMPolytopeType)ctNew);
1307   PetscFunctionReturn(PETSC_SUCCESS);
1308 }
1309 
1310 /* The orientation o is for the interior of the cell p */
1311 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[])
1312 {
1313   DM              dm;
1314   const PetscInt  csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1315   const PetscInt *cone;
1316   PetscInt        c, coff = *coneoff, ooff = *orntoff;
1317 
1318   PetscFunctionBegin;
1319   PetscCall(DMPlexTransformGetDM(tr, &dm));
1320   PetscCall(DMPlexGetOrientedCone(dm, p, &cone, NULL));
1321   for (c = 0; c < csizeNew; ++c) {
1322     PetscInt             ppp   = -1;                            /* Parent Parent point: Parent of point pp */
1323     PetscInt             pp    = p;                             /* Parent point: Point in the original mesh producing new cone point */
1324     PetscInt             po    = 0;                             /* Orientation of parent point pp in parent parent point ppp */
1325     DMPolytopeType       pct   = ct;                            /* Parent type: Cell type for parent of new cone point */
1326     const PetscInt      *pcone = cone;                          /* Parent cone: Cone of parent point pp */
1327     PetscInt             pr    = -1;                            /* Replica number of pp that produces new cone point  */
1328     const DMPolytopeType ft    = (DMPolytopeType)rcone[coff++]; /* Cell type for new cone point of pNew */
1329     const PetscInt       fn    = rcone[coff++];                 /* Number of cones of p that need to be taken when producing new cone point */
1330     PetscInt             fo    = rornt[ooff++];                 /* Orientation of new cone point in pNew */
1331     PetscInt             lc;
1332 
1333     /* Get the type (pct) and point number (pp) of the parent point in the original mesh which produces this cone point */
1334     for (lc = 0; lc < fn; ++lc) {
1335       const PetscInt *parr = DMPolytopeTypeGetArrangement(pct, po);
1336       const PetscInt  acp  = rcone[coff++];
1337       const PetscInt  pcp  = parr[acp * 2];
1338       const PetscInt  pco  = parr[acp * 2 + 1];
1339       const PetscInt *ppornt;
1340 
1341       ppp = pp;
1342       pp  = pcone[pcp];
1343       PetscCall(DMPlexGetCellType(dm, pp, &pct));
1344       // Restore the parent cone from the last iterate
1345       if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, ppp, &pcone, NULL));
1346       PetscCall(DMPlexGetOrientedCone(dm, pp, &pcone, NULL));
1347       PetscCall(DMPlexGetOrientedCone(dm, ppp, NULL, &ppornt));
1348       po = DMPolytopeTypeComposeOrientation(pct, ppornt[pcp], pco);
1349       PetscCall(DMPlexRestoreOrientedCone(dm, ppp, NULL, &ppornt));
1350     }
1351     if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, pp, &pcone, NULL));
1352     pr = rcone[coff++];
1353     /* Orientation po of pp maps (pr, fo) -> (pr', fo') */
1354     PetscCall(DMPlexTransformGetSubcellOrientation(tr, pct, pp, fn ? po : o, ft, pr, fo, &pr, &fo));
1355     PetscCall(DMPlexTransformGetTargetPoint(tr, pct, ft, pp, pr, &coneNew[c]));
1356     orntNew[c] = fo;
1357   }
1358   PetscCall(DMPlexRestoreOrientedCone(dm, p, &cone, NULL));
1359   *coneoff = coff;
1360   *orntoff = ooff;
1361   PetscFunctionReturn(PETSC_SUCCESS);
1362 }
1363 
1364 static PetscErrorCode DMPlexTransformSetCones(DMPlexTransform tr, DM rdm)
1365 {
1366   DM             dm;
1367   DMPolytopeType ct;
1368   PetscInt      *coneNew, *orntNew;
1369   PetscInt       maxConeSize = 0, pStart, pEnd, p, pNew;
1370 
1371   PetscFunctionBegin;
1372   PetscCall(DMPlexTransformGetDM(tr, &dm));
1373   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1374   PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew));
1375   PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew));
1376   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1377   for (p = pStart; p < pEnd; ++p) {
1378     PetscInt        coff, ooff;
1379     DMPolytopeType *rct;
1380     PetscInt       *rsize, *rcone, *rornt;
1381     PetscInt        Nct, n, r;
1382 
1383     PetscCall(DMPlexGetCellType(dm, p, &ct));
1384     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1385     for (n = 0, coff = 0, ooff = 0; n < Nct; ++n) {
1386       const DMPolytopeType ctNew = rct[n];
1387 
1388       for (r = 0; r < rsize[n]; ++r) {
1389         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1390         PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, ctNew, rcone, &coff, rornt, &ooff, coneNew, orntNew));
1391         PetscCall(DMPlexSetCone(rdm, pNew, coneNew));
1392         PetscCall(DMPlexSetConeOrientation(rdm, pNew, orntNew));
1393       }
1394     }
1395   }
1396   PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew));
1397   PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew));
1398   PetscCall(DMViewFromOptions(rdm, NULL, "-rdm_view"));
1399   PetscCall(DMPlexSymmetrize(rdm));
1400   PetscCall(DMPlexStratify(rdm));
1401   PetscFunctionReturn(PETSC_SUCCESS);
1402 }
1403 
1404 PetscErrorCode DMPlexTransformGetConeOriented(DMPlexTransform tr, PetscInt q, PetscInt po, const PetscInt *cone[], const PetscInt *ornt[])
1405 {
1406   DM              dm;
1407   DMPolytopeType  ct, qct;
1408   DMPolytopeType *rct;
1409   PetscInt       *rsize, *rcone, *rornt, *qcone, *qornt;
1410   PetscInt        maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0;
1411 
1412   PetscFunctionBegin;
1413   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
1414   PetscAssertPointer(cone, 4);
1415   PetscAssertPointer(ornt, 5);
1416   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1417   PetscCall(DMPlexTransformGetDM(tr, &dm));
1418   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1419   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1420   PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r));
1421   PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1422   for (n = 0; n < Nct; ++n) {
1423     const DMPolytopeType ctNew    = rct[n];
1424     const PetscInt       csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1425     PetscInt             Nr       = rsize[n], fn, c;
1426 
1427     if (ctNew == qct) Nr = r;
1428     for (nr = 0; nr < Nr; ++nr) {
1429       for (c = 0; c < csizeNew; ++c) {
1430         ++coff;             /* Cell type of new cone point */
1431         fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */
1432         coff += fn;
1433         ++coff; /* Replica number of new cone point */
1434         ++ooff; /* Orientation of new cone point */
1435       }
1436     }
1437     if (ctNew == qct) break;
1438   }
1439   PetscCall(DMPlexTransformGetCone_Internal(tr, p, po, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt));
1440   *cone = qcone;
1441   *ornt = qornt;
1442   PetscFunctionReturn(PETSC_SUCCESS);
1443 }
1444 
1445 PetscErrorCode DMPlexTransformGetCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[])
1446 {
1447   DM              dm;
1448   DMPolytopeType  ct, qct;
1449   DMPolytopeType *rct;
1450   PetscInt       *rsize, *rcone, *rornt, *qcone, *qornt;
1451   PetscInt        maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0;
1452 
1453   PetscFunctionBegin;
1454   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
1455   if (cone) PetscAssertPointer(cone, 3);
1456   if (ornt) PetscAssertPointer(ornt, 4);
1457   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1458   PetscCall(DMPlexTransformGetDM(tr, &dm));
1459   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1460   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1461   PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r));
1462   PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1463   for (n = 0; n < Nct; ++n) {
1464     const DMPolytopeType ctNew    = rct[n];
1465     const PetscInt       csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1466     PetscInt             Nr       = rsize[n], fn, c;
1467 
1468     if (ctNew == qct) Nr = r;
1469     for (nr = 0; nr < Nr; ++nr) {
1470       for (c = 0; c < csizeNew; ++c) {
1471         ++coff;             /* Cell type of new cone point */
1472         fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */
1473         coff += fn;
1474         ++coff; /* Replica number of new cone point */
1475         ++ooff; /* Orientation of new cone point */
1476       }
1477     }
1478     if (ctNew == qct) break;
1479   }
1480   PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt));
1481   if (cone) *cone = qcone;
1482   else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1483   if (ornt) *ornt = qornt;
1484   else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1485   PetscFunctionReturn(PETSC_SUCCESS);
1486 }
1487 
1488 PetscErrorCode DMPlexTransformRestoreCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[])
1489 {
1490   DM dm;
1491 
1492   PetscFunctionBegin;
1493   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
1494   PetscCall(DMPlexTransformGetDM(tr, &dm));
1495   if (cone) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, cone));
1496   if (ornt) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, ornt));
1497   PetscFunctionReturn(PETSC_SUCCESS);
1498 }
1499 
1500 static PetscErrorCode DMPlexTransformCreateCellVertices_Internal(DMPlexTransform tr)
1501 {
1502   PetscInt ict;
1503 
1504   PetscFunctionBegin;
1505   PetscCall(PetscCalloc3(DM_NUM_POLYTOPES, &tr->trNv, DM_NUM_POLYTOPES, &tr->trVerts, DM_NUM_POLYTOPES, &tr->trSubVerts));
1506   for (ict = DM_POLYTOPE_POINT; ict < DM_NUM_POLYTOPES; ++ict) {
1507     const DMPolytopeType ct = (DMPolytopeType)ict;
1508     DMPlexTransform      reftr;
1509     DM                   refdm, trdm;
1510     Vec                  coordinates;
1511     const PetscScalar   *coords;
1512     DMPolytopeType      *rct;
1513     PetscInt            *rsize, *rcone, *rornt;
1514     PetscInt             Nct, n, r, pNew = 0;
1515     PetscInt             trdim, vStart, vEnd, Nc;
1516     const PetscInt       debug = 0;
1517     const char          *typeName;
1518 
1519     /* Since points are 0-dimensional, coordinates make no sense */
1520     if (DMPolytopeTypeGetDim(ct) <= 0 || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) continue;
1521     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, ct, &refdm));
1522     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &reftr));
1523     PetscCall(DMPlexTransformSetDM(reftr, refdm));
1524     PetscCall(DMPlexTransformGetType(tr, &typeName));
1525     PetscCall(DMPlexTransformSetType(reftr, typeName));
1526     PetscCall(DMPlexTransformSetUp(reftr));
1527     PetscCall(DMPlexTransformApply(reftr, refdm, &trdm));
1528 
1529     PetscCall(DMGetDimension(trdm, &trdim));
1530     PetscCall(DMPlexGetDepthStratum(trdm, 0, &vStart, &vEnd));
1531     tr->trNv[ct] = vEnd - vStart;
1532     PetscCall(DMGetCoordinatesLocal(trdm, &coordinates));
1533     PetscCall(VecGetLocalSize(coordinates, &Nc));
1534     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);
1535     PetscCall(PetscCalloc1(Nc, &tr->trVerts[ct]));
1536     PetscCall(VecGetArrayRead(coordinates, &coords));
1537     PetscCall(PetscArraycpy(tr->trVerts[ct], coords, Nc));
1538     PetscCall(VecRestoreArrayRead(coordinates, &coords));
1539 
1540     PetscCall(PetscCalloc1(DM_NUM_POLYTOPES, &tr->trSubVerts[ct]));
1541     PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1542     for (n = 0; n < Nct; ++n) {
1543       /* Since points are 0-dimensional, coordinates make no sense */
1544       if (rct[n] == DM_POLYTOPE_POINT) continue;
1545       PetscCall(PetscCalloc1(rsize[n], &tr->trSubVerts[ct][rct[n]]));
1546       for (r = 0; r < rsize[n]; ++r) {
1547         PetscInt *closure = NULL;
1548         PetscInt  clSize, cl, Nv = 0;
1549 
1550         PetscCall(PetscCalloc1(DMPolytopeTypeGetNumVertices(rct[n]), &tr->trSubVerts[ct][rct[n]][r]));
1551         PetscCall(DMPlexTransformGetTargetPoint(reftr, ct, rct[n], 0, r, &pNew));
1552         PetscCall(DMPlexGetTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure));
1553         for (cl = 0; cl < clSize * 2; cl += 2) {
1554           const PetscInt sv = closure[cl];
1555 
1556           if ((sv >= vStart) && (sv < vEnd)) tr->trSubVerts[ct][rct[n]][r][Nv++] = sv - vStart;
1557         }
1558         PetscCall(DMPlexRestoreTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure));
1559         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]);
1560       }
1561     }
1562     if (debug) {
1563       DMPolytopeType *rct;
1564       PetscInt       *rsize, *rcone, *rornt;
1565       PetscInt        v, dE = trdim, d, off = 0;
1566 
1567       PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %" PetscInt_FMT " vertices\n", DMPolytopeTypes[ct], tr->trNv[ct]));
1568       for (v = 0; v < tr->trNv[ct]; ++v) {
1569         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  "));
1570         for (d = 0; d < dE; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g ", (double)PetscRealPart(tr->trVerts[ct][off++])));
1571         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1572       }
1573 
1574       PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1575       for (n = 0; n < Nct; ++n) {
1576         if (rct[n] == DM_POLYTOPE_POINT) continue;
1577         PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %s subvertices %" PetscInt_FMT "\n", DMPolytopeTypes[ct], DMPolytopeTypes[rct[n]], tr->trNv[ct]));
1578         for (r = 0; r < rsize[n]; ++r) {
1579           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  "));
1580           for (v = 0; v < DMPolytopeTypeGetNumVertices(rct[n]); ++v) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT " ", tr->trSubVerts[ct][rct[n]][r][v]));
1581           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1582         }
1583       }
1584     }
1585     PetscCall(DMDestroy(&refdm));
1586     PetscCall(DMDestroy(&trdm));
1587     PetscCall(DMPlexTransformDestroy(&reftr));
1588   }
1589   PetscFunctionReturn(PETSC_SUCCESS);
1590 }
1591 
1592 /*@C
1593   DMPlexTransformGetCellVertices - Get the set of transformed vertices lying in the closure of a reference cell of given type
1594 
1595   Input Parameters:
1596 + tr - The `DMPlexTransform` object
1597 - ct - The cell type
1598 
1599   Output Parameters:
1600 + Nv      - The number of transformed vertices in the closure of the reference cell of given type
1601 - trVerts - The coordinates of these vertices in the reference cell
1602 
1603   Level: developer
1604 
1605 .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSubcellVertices()`
1606 @*/
1607 PetscErrorCode DMPlexTransformGetCellVertices(DMPlexTransform tr, DMPolytopeType ct, PetscInt *Nv, PetscScalar *trVerts[])
1608 {
1609   PetscFunctionBegin;
1610   if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr));
1611   if (Nv) *Nv = tr->trNv[ct];
1612   if (trVerts) *trVerts = tr->trVerts[ct];
1613   PetscFunctionReturn(PETSC_SUCCESS);
1614 }
1615 
1616 /*@C
1617   DMPlexTransformGetSubcellVertices - Get the set of transformed vertices defining a subcell in the reference cell of given type
1618 
1619   Input Parameters:
1620 + tr  - The `DMPlexTransform` object
1621 . ct  - The cell type
1622 . rct - The subcell type
1623 - r   - The subcell index
1624 
1625   Output Parameter:
1626 . subVerts - The indices of these vertices in the set of vertices returned by `DMPlexTransformGetCellVertices()`
1627 
1628   Level: developer
1629 
1630 .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetCellVertices()`
1631 @*/
1632 PetscErrorCode DMPlexTransformGetSubcellVertices(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, PetscInt *subVerts[])
1633 {
1634   PetscFunctionBegin;
1635   if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr));
1636   PetscCheck(tr->trSubVerts[ct][rct], PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_WRONG, "Cell type %s does not produce %s", DMPolytopeTypes[ct], DMPolytopeTypes[rct]);
1637   if (subVerts) *subVerts = tr->trSubVerts[ct][rct][r];
1638   PetscFunctionReturn(PETSC_SUCCESS);
1639 }
1640 
1641 /* Computes new vertex as the barycenter, or centroid */
1642 PetscErrorCode DMPlexTransformMapCoordinatesBarycenter_Internal(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[])
1643 {
1644   PetscInt v, d;
1645 
1646   PetscFunctionBeginHot;
1647   PetscCheck(ct == DM_POLYTOPE_POINT, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for refined point type %s", DMPolytopeTypes[ct]);
1648   for (d = 0; d < dE; ++d) out[d] = 0.0;
1649   for (v = 0; v < Nv; ++v)
1650     for (d = 0; d < dE; ++d) out[d] += in[v * dE + d];
1651   for (d = 0; d < dE; ++d) out[d] /= Nv;
1652   PetscFunctionReturn(PETSC_SUCCESS);
1653 }
1654 
1655 /*@
1656   DMPlexTransformMapCoordinates - Calculate new coordinates for produced points
1657 
1658   Not collective
1659 
1660   Input Parameters:
1661 + tr  - The `DMPlexTransform`
1662 . pct - The cell type of the parent, from whom the new cell is being produced
1663 . ct  - The type being produced
1664 . p   - The original point
1665 . r   - The replica number requested for the produced cell type
1666 . Nv  - Number of vertices in the closure of the parent cell
1667 . dE  - Spatial dimension
1668 - in  - array of size Nv*dE, holding coordinates of the vertices in the closure of the parent cell
1669 
1670   Output Parameter:
1671 . out - The coordinates of the new vertices
1672 
1673   Level: intermediate
1674 
1675 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`
1676 @*/
1677 PetscErrorCode DMPlexTransformMapCoordinates(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[])
1678 {
1679   PetscFunctionBeginHot;
1680   if (Nv) PetscUseTypeMethod(tr, mapcoordinates, pct, ct, p, r, Nv, dE, in, out);
1681   PetscFunctionReturn(PETSC_SUCCESS);
1682 }
1683 
1684 /*
1685   DMPlexTransformLabelProducedPoint_Private - Label a produced point based on its parent label
1686 
1687   Not Collective
1688 
1689   Input Parameters:
1690 + tr    - The `DMPlexTransform`
1691 . label - The label in the transformed mesh
1692 . pp    - The parent point in the original mesh
1693 . pct   - The cell type of the parent point
1694 . p     - The point in the transformed mesh
1695 . ct    - The cell type of the point
1696 . r     - The replica number of the point
1697 - val   - The label value of the parent point
1698 
1699   Level: developer
1700 
1701 .seealso: `DMPlexTransformCreateLabels()`, `RefineLabel_Internal()`
1702 */
1703 static PetscErrorCode DMPlexTransformLabelProducedPoint_Private(DMPlexTransform tr, DMLabel label, PetscInt pp, DMPolytopeType pct, PetscInt p, DMPolytopeType ct, PetscInt r, PetscInt val)
1704 {
1705   PetscFunctionBeginHot;
1706   if (tr->labelMatchStrata && pct != ct) PetscFunctionReturn(PETSC_SUCCESS);
1707   PetscCall(DMLabelSetValue(label, p, val + tr->labelReplicaInc * r));
1708   PetscFunctionReturn(PETSC_SUCCESS);
1709 }
1710 
1711 static PetscErrorCode RefineLabel_Internal(DMPlexTransform tr, DMLabel label, DMLabel labelNew)
1712 {
1713   DM              dm;
1714   IS              valueIS;
1715   const PetscInt *values;
1716   PetscInt        defVal, Nv, val;
1717 
1718   PetscFunctionBegin;
1719   PetscCall(DMPlexTransformGetDM(tr, &dm));
1720   PetscCall(DMLabelGetDefaultValue(label, &defVal));
1721   PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
1722   PetscCall(DMLabelGetValueIS(label, &valueIS));
1723   PetscCall(ISGetLocalSize(valueIS, &Nv));
1724   PetscCall(ISGetIndices(valueIS, &values));
1725   for (val = 0; val < Nv; ++val) {
1726     IS              pointIS;
1727     const PetscInt *points;
1728     PetscInt        numPoints, p;
1729 
1730     /* Ensure refined label is created with same number of strata as
1731      * original (even if no entries here). */
1732     PetscCall(DMLabelAddStratum(labelNew, values[val]));
1733     PetscCall(DMLabelGetStratumIS(label, values[val], &pointIS));
1734     PetscCall(ISGetLocalSize(pointIS, &numPoints));
1735     PetscCall(ISGetIndices(pointIS, &points));
1736     for (p = 0; p < numPoints; ++p) {
1737       const PetscInt  point = points[p];
1738       DMPolytopeType  ct;
1739       DMPolytopeType *rct;
1740       PetscInt       *rsize, *rcone, *rornt;
1741       PetscInt        Nct, n, r, pNew = 0;
1742 
1743       PetscCall(DMPlexGetCellType(dm, point, &ct));
1744       PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1745       for (n = 0; n < Nct; ++n) {
1746         for (r = 0; r < rsize[n]; ++r) {
1747           PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], point, r, &pNew));
1748           PetscCall(DMPlexTransformLabelProducedPoint_Private(tr, labelNew, point, ct, pNew, rct[n], r, values[val]));
1749         }
1750       }
1751     }
1752     PetscCall(ISRestoreIndices(pointIS, &points));
1753     PetscCall(ISDestroy(&pointIS));
1754   }
1755   PetscCall(ISRestoreIndices(valueIS, &values));
1756   PetscCall(ISDestroy(&valueIS));
1757   PetscFunctionReturn(PETSC_SUCCESS);
1758 }
1759 
1760 static PetscErrorCode DMPlexTransformCreateLabels(DMPlexTransform tr, DM rdm)
1761 {
1762   DM       dm;
1763   PetscInt numLabels, l;
1764 
1765   PetscFunctionBegin;
1766   PetscCall(DMPlexTransformGetDM(tr, &dm));
1767   PetscCall(DMGetNumLabels(dm, &numLabels));
1768   for (l = 0; l < numLabels; ++l) {
1769     DMLabel     label, labelNew;
1770     const char *lname;
1771     PetscBool   isDepth, isCellType;
1772 
1773     PetscCall(DMGetLabelName(dm, l, &lname));
1774     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
1775     if (isDepth) continue;
1776     PetscCall(PetscStrcmp(lname, "celltype", &isCellType));
1777     if (isCellType) continue;
1778     PetscCall(DMCreateLabel(rdm, lname));
1779     PetscCall(DMGetLabel(dm, lname, &label));
1780     PetscCall(DMGetLabel(rdm, lname, &labelNew));
1781     PetscCall(RefineLabel_Internal(tr, label, labelNew));
1782   }
1783   PetscFunctionReturn(PETSC_SUCCESS);
1784 }
1785 
1786 /* This refines the labels which define regions for fields and DSes since they are not in the list of labels for the DM */
1787 PetscErrorCode DMPlexTransformCreateDiscLabels(DMPlexTransform tr, DM rdm)
1788 {
1789   DM       dm;
1790   PetscInt Nf, f, Nds, s;
1791 
1792   PetscFunctionBegin;
1793   PetscCall(DMPlexTransformGetDM(tr, &dm));
1794   PetscCall(DMGetNumFields(dm, &Nf));
1795   for (f = 0; f < Nf; ++f) {
1796     DMLabel     label, labelNew;
1797     PetscObject obj;
1798     const char *lname;
1799 
1800     PetscCall(DMGetField(rdm, f, &label, &obj));
1801     if (!label) continue;
1802     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
1803     PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew));
1804     PetscCall(RefineLabel_Internal(tr, label, labelNew));
1805     PetscCall(DMSetField_Internal(rdm, f, labelNew, obj));
1806     PetscCall(DMLabelDestroy(&labelNew));
1807   }
1808   PetscCall(DMGetNumDS(dm, &Nds));
1809   for (s = 0; s < Nds; ++s) {
1810     DMLabel     label, labelNew;
1811     const char *lname;
1812 
1813     PetscCall(DMGetRegionNumDS(rdm, s, &label, NULL, NULL, NULL));
1814     if (!label) continue;
1815     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
1816     PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew));
1817     PetscCall(RefineLabel_Internal(tr, label, labelNew));
1818     PetscCall(DMSetRegionNumDS(rdm, s, labelNew, NULL, NULL, NULL));
1819     PetscCall(DMLabelDestroy(&labelNew));
1820   }
1821   PetscFunctionReturn(PETSC_SUCCESS);
1822 }
1823 
1824 static PetscErrorCode DMPlexTransformCreateSF(DMPlexTransform tr, DM rdm)
1825 {
1826   DM                 dm;
1827   PetscSF            sf, sfNew;
1828   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
1829   const PetscInt    *localPoints;
1830   const PetscSFNode *remotePoints;
1831   PetscInt          *localPointsNew;
1832   PetscSFNode       *remotePointsNew;
1833   PetscInt           pStartNew, pEndNew, pNew;
1834   /* Brute force algorithm */
1835   PetscSF         rsf;
1836   PetscSection    s;
1837   const PetscInt *rootdegree;
1838   PetscInt       *rootPointsNew, *remoteOffsets;
1839   PetscInt        numPointsNew, pStart, pEnd, p;
1840 
1841   PetscFunctionBegin;
1842   PetscCall(DMPlexTransformGetDM(tr, &dm));
1843   PetscCall(DMPlexGetChart(rdm, &pStartNew, &pEndNew));
1844   PetscCall(DMGetPointSF(dm, &sf));
1845   PetscCall(DMGetPointSF(rdm, &sfNew));
1846   /* Calculate size of new SF */
1847   PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints));
1848   if (numRoots < 0) PetscFunctionReturn(PETSC_SUCCESS);
1849   for (l = 0; l < numLeaves; ++l) {
1850     const PetscInt  p = localPoints[l];
1851     DMPolytopeType  ct;
1852     DMPolytopeType *rct;
1853     PetscInt       *rsize, *rcone, *rornt;
1854     PetscInt        Nct, n;
1855 
1856     PetscCall(DMPlexGetCellType(dm, p, &ct));
1857     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1858     for (n = 0; n < Nct; ++n) numLeavesNew += rsize[n];
1859   }
1860   /* Send new root point numbers
1861        It is possible to optimize for regular transforms by sending only the cell type offsets, but it seems a needless complication
1862   */
1863   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1864   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &s));
1865   PetscCall(PetscSectionSetChart(s, pStart, pEnd));
1866   for (p = pStart; p < pEnd; ++p) {
1867     DMPolytopeType  ct;
1868     DMPolytopeType *rct;
1869     PetscInt       *rsize, *rcone, *rornt;
1870     PetscInt        Nct, n;
1871 
1872     PetscCall(DMPlexGetCellType(dm, p, &ct));
1873     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1874     for (n = 0; n < Nct; ++n) PetscCall(PetscSectionAddDof(s, p, rsize[n]));
1875   }
1876   PetscCall(PetscSectionSetUp(s));
1877   PetscCall(PetscSectionGetStorageSize(s, &numPointsNew));
1878   PetscCall(PetscSFCreateRemoteOffsets(sf, s, s, &remoteOffsets));
1879   PetscCall(PetscSFCreateSectionSF(sf, s, remoteOffsets, s, &rsf));
1880   PetscCall(PetscFree(remoteOffsets));
1881   PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree));
1882   PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree));
1883   PetscCall(PetscMalloc1(numPointsNew, &rootPointsNew));
1884   for (p = 0; p < numPointsNew; ++p) rootPointsNew[p] = -1;
1885   for (p = pStart; p < pEnd; ++p) {
1886     DMPolytopeType  ct;
1887     DMPolytopeType *rct;
1888     PetscInt       *rsize, *rcone, *rornt;
1889     PetscInt        Nct, n, r, off;
1890 
1891     if (!rootdegree[p - pStart]) continue;
1892     PetscCall(PetscSectionGetOffset(s, p, &off));
1893     PetscCall(DMPlexGetCellType(dm, p, &ct));
1894     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1895     for (n = 0, m = 0; n < Nct; ++n) {
1896       for (r = 0; r < rsize[n]; ++r, ++m) {
1897         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1898         rootPointsNew[off + m] = pNew;
1899       }
1900     }
1901   }
1902   PetscCall(PetscSFBcastBegin(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE));
1903   PetscCall(PetscSFBcastEnd(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE));
1904   PetscCall(PetscSFDestroy(&rsf));
1905   PetscCall(PetscMalloc1(numLeavesNew, &localPointsNew));
1906   PetscCall(PetscMalloc1(numLeavesNew, &remotePointsNew));
1907   for (l = 0, m = 0; l < numLeaves; ++l) {
1908     const PetscInt  p = localPoints[l];
1909     DMPolytopeType  ct;
1910     DMPolytopeType *rct;
1911     PetscInt       *rsize, *rcone, *rornt;
1912     PetscInt        Nct, n, r, q, off;
1913 
1914     PetscCall(PetscSectionGetOffset(s, p, &off));
1915     PetscCall(DMPlexGetCellType(dm, p, &ct));
1916     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1917     for (n = 0, q = 0; n < Nct; ++n) {
1918       for (r = 0; r < rsize[n]; ++r, ++m, ++q) {
1919         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1920         localPointsNew[m]        = pNew;
1921         remotePointsNew[m].index = rootPointsNew[off + q];
1922         remotePointsNew[m].rank  = remotePoints[l].rank;
1923       }
1924     }
1925   }
1926   PetscCall(PetscSectionDestroy(&s));
1927   PetscCall(PetscFree(rootPointsNew));
1928   /* SF needs sorted leaves to correctly calculate Gather */
1929   {
1930     PetscSFNode *rp, *rtmp;
1931     PetscInt    *lp, *idx, *ltmp, i;
1932 
1933     PetscCall(PetscMalloc1(numLeavesNew, &idx));
1934     PetscCall(PetscMalloc1(numLeavesNew, &lp));
1935     PetscCall(PetscMalloc1(numLeavesNew, &rp));
1936     for (i = 0; i < numLeavesNew; ++i) {
1937       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);
1938       idx[i] = i;
1939     }
1940     PetscCall(PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx));
1941     for (i = 0; i < numLeavesNew; ++i) {
1942       lp[i] = localPointsNew[idx[i]];
1943       rp[i] = remotePointsNew[idx[i]];
1944     }
1945     ltmp            = localPointsNew;
1946     localPointsNew  = lp;
1947     rtmp            = remotePointsNew;
1948     remotePointsNew = rp;
1949     PetscCall(PetscFree(idx));
1950     PetscCall(PetscFree(ltmp));
1951     PetscCall(PetscFree(rtmp));
1952   }
1953   PetscCall(PetscSFSetGraph(sfNew, pEndNew - pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER));
1954   PetscFunctionReturn(PETSC_SUCCESS);
1955 }
1956 
1957 /*
1958   DMPlexCellRefinerMapLocalizedCoordinates - Given a cell of `DMPolytopeType` `ct` with localized coordinates `x`, generate localized coordinates `xr` for subcell `r` of type `rct`.
1959 
1960   Not Collective
1961 
1962   Input Parameters:
1963 + tr  - The `DMPlexTransform`
1964 . ct  - The type of the parent cell
1965 . rct - The type of the produced cell
1966 . r   - The index of the produced cell
1967 - x   - The localized coordinates for the parent cell
1968 
1969   Output Parameter:
1970 . xr  - The localized coordinates for the produced cell
1971 
1972   Level: developer
1973 
1974 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexCellRefinerSetCoordinates()`
1975 */
1976 static PetscErrorCode DMPlexTransformMapLocalizedCoordinates(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, const PetscScalar x[], PetscScalar xr[])
1977 {
1978   PetscFE  fe = NULL;
1979   PetscInt cdim, v, *subcellV;
1980 
1981   PetscFunctionBegin;
1982   PetscCall(DMPlexTransformGetCoordinateFE(tr, ct, &fe));
1983   PetscCall(DMPlexTransformGetSubcellVertices(tr, ct, rct, r, &subcellV));
1984   PetscCall(PetscFEGetNumComponents(fe, &cdim));
1985   for (v = 0; v < DMPolytopeTypeGetNumVertices(rct); ++v) PetscCall(PetscFEInterpolate_Static(fe, x, tr->refGeom[ct], subcellV[v], &xr[v * cdim]));
1986   PetscFunctionReturn(PETSC_SUCCESS);
1987 }
1988 
1989 static PetscErrorCode DMPlexTransformSetCoordinates(DMPlexTransform tr, DM rdm)
1990 {
1991   DM                 dm, cdm, cdmCell, cdmNew, cdmCellNew;
1992   PetscSection       coordSection, coordSectionNew, coordSectionCell, coordSectionCellNew;
1993   Vec                coordsLocal, coordsLocalNew, coordsLocalCell = NULL, coordsLocalCellNew;
1994   const PetscScalar *coords;
1995   PetscScalar       *coordsNew;
1996   const PetscReal   *maxCell, *Lstart, *L;
1997   PetscBool          localized, localizeVertices = PETSC_FALSE, localizeCells = PETSC_FALSE;
1998   PetscInt           dE, dEo, d, cStart, cEnd, c, cStartNew, cEndNew, vStartNew, vEndNew, v, pStart, pEnd, p;
1999 
2000   PetscFunctionBegin;
2001   PetscCall(DMPlexTransformGetDM(tr, &dm));
2002   PetscCall(DMGetCoordinateDM(dm, &cdm));
2003   PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
2004   PetscCall(DMGetCoordinatesLocalized(dm, &localized));
2005   PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
2006   if (localized) {
2007     /* Localize coordinates of new vertices */
2008     localizeVertices = PETSC_TRUE;
2009     /* If we do not have a mechanism for automatically localizing cell coordinates, we need to compute them explicitly for every divided cell */
2010     if (!maxCell) localizeCells = PETSC_TRUE;
2011   }
2012   PetscCall(DMGetCoordinateSection(dm, &coordSection));
2013   PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &dEo));
2014   if (maxCell) {
2015     PetscReal maxCellNew[3];
2016 
2017     for (d = 0; d < dEo; ++d) maxCellNew[d] = maxCell[d] / 2.0;
2018     PetscCall(DMSetPeriodicity(rdm, maxCellNew, Lstart, L));
2019   }
2020   PetscCall(DMGetCoordinateDim(rdm, &dE));
2021   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionNew));
2022   PetscCall(PetscSectionSetNumFields(coordSectionNew, 1));
2023   PetscCall(PetscSectionSetFieldComponents(coordSectionNew, 0, dE));
2024   PetscCall(DMPlexGetDepthStratum(rdm, 0, &vStartNew, &vEndNew));
2025   PetscCall(PetscSectionSetChart(coordSectionNew, vStartNew, vEndNew));
2026   /* Localization should be inherited */
2027   /*   Stefano calculates parent cells for each new cell for localization */
2028   /*   Localized cells need coordinates of closure */
2029   for (v = vStartNew; v < vEndNew; ++v) {
2030     PetscCall(PetscSectionSetDof(coordSectionNew, v, dE));
2031     PetscCall(PetscSectionSetFieldDof(coordSectionNew, v, 0, dE));
2032   }
2033   PetscCall(PetscSectionSetUp(coordSectionNew));
2034   PetscCall(DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew));
2035 
2036   if (localizeCells) {
2037     PetscCall(DMGetCoordinateDM(rdm, &cdmNew));
2038     PetscCall(DMClone(cdmNew, &cdmCellNew));
2039     PetscCall(DMSetCellCoordinateDM(rdm, cdmCellNew));
2040     PetscCall(DMDestroy(&cdmCellNew));
2041 
2042     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionCellNew));
2043     PetscCall(PetscSectionSetNumFields(coordSectionCellNew, 1));
2044     PetscCall(PetscSectionSetFieldComponents(coordSectionCellNew, 0, dE));
2045     PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStartNew, &cEndNew));
2046     PetscCall(PetscSectionSetChart(coordSectionCellNew, cStartNew, cEndNew));
2047 
2048     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
2049     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2050     for (c = cStart; c < cEnd; ++c) {
2051       PetscInt dof;
2052 
2053       PetscCall(PetscSectionGetDof(coordSectionCell, c, &dof));
2054       if (dof) {
2055         DMPolytopeType  ct;
2056         DMPolytopeType *rct;
2057         PetscInt       *rsize, *rcone, *rornt;
2058         PetscInt        dim, cNew, Nct, n, r;
2059 
2060         PetscCall(DMPlexGetCellType(dm, c, &ct));
2061         dim = DMPolytopeTypeGetDim(ct);
2062         PetscCall(DMPlexTransformCellTransform(tr, ct, c, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2063         /* This allows for different cell types */
2064         for (n = 0; n < Nct; ++n) {
2065           if (dim != DMPolytopeTypeGetDim(rct[n])) continue;
2066           for (r = 0; r < rsize[n]; ++r) {
2067             PetscInt *closure = NULL;
2068             PetscInt  clSize, cl, Nv = 0;
2069 
2070             PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], c, r, &cNew));
2071             PetscCall(DMPlexGetTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure));
2072             for (cl = 0; cl < clSize * 2; cl += 2) {
2073               if ((closure[cl] >= vStartNew) && (closure[cl] < vEndNew)) ++Nv;
2074             }
2075             PetscCall(DMPlexRestoreTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure));
2076             PetscCall(PetscSectionSetDof(coordSectionCellNew, cNew, Nv * dE));
2077             PetscCall(PetscSectionSetFieldDof(coordSectionCellNew, cNew, 0, Nv * dE));
2078           }
2079         }
2080       }
2081     }
2082     PetscCall(PetscSectionSetUp(coordSectionCellNew));
2083     PetscCall(DMSetCellCoordinateSection(rdm, PETSC_DETERMINE, coordSectionCellNew));
2084   }
2085   PetscCall(DMViewFromOptions(dm, NULL, "-coarse_dm_view"));
2086   {
2087     VecType     vtype;
2088     PetscInt    coordSizeNew, bs;
2089     const char *name;
2090 
2091     PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
2092     PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalNew));
2093     PetscCall(PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew));
2094     PetscCall(VecSetSizes(coordsLocalNew, coordSizeNew, PETSC_DETERMINE));
2095     PetscCall(PetscObjectGetName((PetscObject)coordsLocal, &name));
2096     PetscCall(PetscObjectSetName((PetscObject)coordsLocalNew, name));
2097     PetscCall(VecGetBlockSize(coordsLocal, &bs));
2098     PetscCall(VecSetBlockSize(coordsLocalNew, dEo == dE ? bs : dE));
2099     PetscCall(VecGetType(coordsLocal, &vtype));
2100     PetscCall(VecSetType(coordsLocalNew, vtype));
2101   }
2102   PetscCall(VecGetArrayRead(coordsLocal, &coords));
2103   PetscCall(VecGetArray(coordsLocalNew, &coordsNew));
2104   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
2105   /* First set coordinates for vertices */
2106   for (p = pStart; p < pEnd; ++p) {
2107     DMPolytopeType  ct;
2108     DMPolytopeType *rct;
2109     PetscInt       *rsize, *rcone, *rornt;
2110     PetscInt        Nct, n, r;
2111     PetscBool       hasVertex = PETSC_FALSE;
2112 
2113     PetscCall(DMPlexGetCellType(dm, p, &ct));
2114     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2115     for (n = 0; n < Nct; ++n) {
2116       if (rct[n] == DM_POLYTOPE_POINT) {
2117         hasVertex = PETSC_TRUE;
2118         break;
2119       }
2120     }
2121     if (hasVertex) {
2122       const PetscScalar *icoords = NULL;
2123       const PetscScalar *array   = NULL;
2124       PetscScalar       *pcoords = NULL;
2125       PetscBool          isDG;
2126       PetscInt           Nc, Nv, v, d;
2127 
2128       PetscCall(DMPlexGetCellCoordinates(dm, p, &isDG, &Nc, &array, &pcoords));
2129 
2130       icoords = pcoords;
2131       Nv      = Nc / dEo;
2132       if (ct != DM_POLYTOPE_POINT) {
2133         if (localizeVertices && maxCell) {
2134           PetscScalar anchor[3];
2135 
2136           for (d = 0; d < dEo; ++d) anchor[d] = pcoords[d];
2137           for (v = 0; v < Nv; ++v) PetscCall(DMLocalizeCoordinate_Internal(dm, dEo, anchor, &pcoords[v * dEo], &pcoords[v * dEo]));
2138         }
2139       }
2140       for (n = 0; n < Nct; ++n) {
2141         if (rct[n] != DM_POLYTOPE_POINT) continue;
2142         for (r = 0; r < rsize[n]; ++r) {
2143           PetscScalar vcoords[3];
2144           PetscInt    vNew, off;
2145 
2146           PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &vNew));
2147           PetscCall(PetscSectionGetOffset(coordSectionNew, vNew, &off));
2148           PetscCall(DMPlexTransformMapCoordinates(tr, ct, rct[n], p, r, Nv, dEo, icoords, vcoords));
2149           PetscCall(DMSnapToGeomModel(dm, p, dE, vcoords, &coordsNew[off]));
2150         }
2151       }
2152       PetscCall(DMPlexRestoreCellCoordinates(dm, p, &isDG, &Nc, &array, &pcoords));
2153     }
2154   }
2155   PetscCall(VecRestoreArrayRead(coordsLocal, &coords));
2156   PetscCall(VecRestoreArray(coordsLocalNew, &coordsNew));
2157   PetscCall(DMSetCoordinatesLocal(rdm, coordsLocalNew));
2158   PetscCall(VecDestroy(&coordsLocalNew));
2159   PetscCall(PetscSectionDestroy(&coordSectionNew));
2160   /* Then set coordinates for cells by localizing */
2161   if (!localizeCells) PetscCall(DMLocalizeCoordinates(rdm));
2162   else {
2163     VecType     vtype;
2164     PetscInt    coordSizeNew, bs;
2165     const char *name;
2166 
2167     PetscCall(DMGetCellCoordinatesLocal(dm, &coordsLocalCell));
2168     PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalCellNew));
2169     PetscCall(PetscSectionGetStorageSize(coordSectionCellNew, &coordSizeNew));
2170     PetscCall(VecSetSizes(coordsLocalCellNew, coordSizeNew, PETSC_DETERMINE));
2171     PetscCall(PetscObjectGetName((PetscObject)coordsLocalCell, &name));
2172     PetscCall(PetscObjectSetName((PetscObject)coordsLocalCellNew, name));
2173     PetscCall(VecGetBlockSize(coordsLocalCell, &bs));
2174     PetscCall(VecSetBlockSize(coordsLocalCellNew, dEo == dE ? bs : dE));
2175     PetscCall(VecGetType(coordsLocalCell, &vtype));
2176     PetscCall(VecSetType(coordsLocalCellNew, vtype));
2177     PetscCall(VecGetArrayRead(coordsLocalCell, &coords));
2178     PetscCall(VecGetArray(coordsLocalCellNew, &coordsNew));
2179 
2180     for (p = pStart; p < pEnd; ++p) {
2181       DMPolytopeType  ct;
2182       DMPolytopeType *rct;
2183       PetscInt       *rsize, *rcone, *rornt;
2184       PetscInt        dof = 0, Nct, n, r;
2185 
2186       PetscCall(DMPlexGetCellType(dm, p, &ct));
2187       PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2188       if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
2189       if (dof) {
2190         const PetscScalar *pcoords;
2191 
2192         PetscCall(DMPlexPointLocalRead(cdmCell, p, coords, &pcoords));
2193         for (n = 0; n < Nct; ++n) {
2194           const PetscInt Nr = rsize[n];
2195 
2196           if (DMPolytopeTypeGetDim(ct) != DMPolytopeTypeGetDim(rct[n])) continue;
2197           for (r = 0; r < Nr; ++r) {
2198             PetscInt pNew, offNew;
2199 
2200             /* It looks like Stefano and Lisandro are allowing localized coordinates without defining the periodic boundary, which means that
2201                DMLocalizeCoordinate_Internal() will not work. Localized coordinates will have to have obtained by the affine map of the larger
2202                cell to the ones it produces. */
2203             PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
2204             PetscCall(PetscSectionGetOffset(coordSectionCellNew, pNew, &offNew));
2205             PetscCall(DMPlexTransformMapLocalizedCoordinates(tr, ct, rct[n], r, pcoords, &coordsNew[offNew]));
2206           }
2207         }
2208       }
2209     }
2210     PetscCall(VecRestoreArrayRead(coordsLocalCell, &coords));
2211     PetscCall(VecRestoreArray(coordsLocalCellNew, &coordsNew));
2212     PetscCall(DMSetCellCoordinatesLocal(rdm, coordsLocalCellNew));
2213     PetscCall(VecDestroy(&coordsLocalCellNew));
2214     PetscCall(PetscSectionDestroy(&coordSectionCellNew));
2215   }
2216   PetscFunctionReturn(PETSC_SUCCESS);
2217 }
2218 
2219 /*@
2220   DMPlexTransformApply - Execute the transformation, producing another `DM`
2221 
2222   Collective
2223 
2224   Input Parameters:
2225 + tr - The `DMPlexTransform` object
2226 - dm - The original `DM`
2227 
2228   Output Parameter:
2229 . tdm - The transformed `DM`
2230 
2231   Level: intermediate
2232 
2233 .seealso: [](plex_transform_table), [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformCreate()`, `DMPlexTransformSetDM()`
2234 @*/
2235 PetscErrorCode DMPlexTransformApply(DMPlexTransform tr, DM dm, DM *tdm)
2236 {
2237   DM                     rdm;
2238   DMPlexInterpolatedFlag interp;
2239   PetscInt               pStart, pEnd;
2240 
2241   PetscFunctionBegin;
2242   PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1);
2243   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
2244   PetscAssertPointer(tdm, 3);
2245   PetscCall(PetscLogEventBegin(DMPLEX_Transform, tr, dm, 0, 0));
2246   PetscCall(DMPlexTransformSetDM(tr, dm));
2247 
2248   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &rdm));
2249   PetscCall(DMSetType(rdm, DMPLEX));
2250   PetscCall(DMPlexTransformSetDimensions(tr, dm, rdm));
2251   /* Calculate number of new points of each depth */
2252   PetscCall(DMPlexIsInterpolatedCollective(dm, &interp));
2253   PetscCheck(interp == DMPLEX_INTERPOLATED_FULL, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be fully interpolated for regular refinement");
2254   /* Step 1: Set chart */
2255   PetscCall(DMPlexTransformGetChart(tr, &pStart, &pEnd));
2256   PetscCall(DMPlexSetChart(rdm, pStart, pEnd));
2257   /* Step 2: Set cone/support sizes (automatically stratifies) */
2258   PetscCall(DMPlexTransformSetConeSizes(tr, rdm));
2259   /* Step 3: Setup refined DM */
2260   PetscCall(DMSetUp(rdm));
2261   /* Step 4: Set cones and supports (automatically symmetrizes) */
2262   PetscCall(DMPlexTransformSetCones(tr, rdm));
2263   /* Step 5: Create pointSF */
2264   PetscCall(DMPlexTransformCreateSF(tr, rdm));
2265   /* Step 6: Create labels */
2266   PetscCall(DMPlexTransformCreateLabels(tr, rdm));
2267   /* Step 7: Set coordinates */
2268   PetscCall(DMPlexTransformSetCoordinates(tr, rdm));
2269   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, rdm));
2270   // If the original DM was configured from options, the transformed DM should be as well
2271   rdm->setfromoptionscalled = dm->setfromoptionscalled;
2272   PetscCall(PetscLogEventEnd(DMPLEX_Transform, tr, dm, 0, 0));
2273   *tdm = rdm;
2274   PetscFunctionReturn(PETSC_SUCCESS);
2275 }
2276 
2277 PetscErrorCode DMPlexTransformAdaptLabel(DM dm, PETSC_UNUSED Vec metric, DMLabel adaptLabel, PETSC_UNUSED DMLabel rgLabel, DM *rdm)
2278 {
2279   DMPlexTransform tr;
2280   DM              cdm, rcdm;
2281   const char     *prefix;
2282 
2283   PetscFunctionBegin;
2284   PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr));
2285   PetscCall(PetscObjectSetName((PetscObject)tr, "Adapt Label Transform"));
2286   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
2287   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix));
2288   PetscCall(DMPlexTransformSetDM(tr, dm));
2289   PetscCall(DMPlexTransformSetFromOptions(tr));
2290   PetscCall(DMPlexTransformSetActive(tr, adaptLabel));
2291   PetscCall(DMPlexTransformSetUp(tr));
2292   PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_transform_view"));
2293   PetscCall(DMPlexTransformApply(tr, dm, rdm));
2294   PetscCall(DMCopyDisc(dm, *rdm));
2295   PetscCall(DMGetCoordinateDM(dm, &cdm));
2296   PetscCall(DMGetCoordinateDM(*rdm, &rcdm));
2297   PetscCall(DMCopyDisc(cdm, rcdm));
2298   PetscCall(DMPlexTransformCreateDiscLabels(tr, *rdm));
2299   PetscCall(DMCopyDisc(dm, *rdm));
2300   PetscCall(DMPlexTransformDestroy(&tr));
2301   ((DM_Plex *)(*rdm)->data)->useHashLocation = ((DM_Plex *)dm->data)->useHashLocation;
2302   PetscFunctionReturn(PETSC_SUCCESS);
2303 }
2304