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