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