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