Actual source code: plextransform.c

  1: #include <petsc/private/dmplextransformimpl.h>

  3: #include <petsc/private/petscfeimpl.h>

  5: PetscClassId DMPLEXTRANSFORM_CLASSID;

  7: PetscFunctionList DMPlexTransformList              = NULL;
  8: PetscBool         DMPlexTransformRegisterAllCalled = PETSC_FALSE;

 10: /* 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;

 16:   PetscFunctionBegin;
 17:   PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctO, DM_NUM_POLYTOPES + 1, &ctOInv));
 18:   for (d = 3; d >= dim; --d) {
 19:     for (c = 0; c <= DM_NUM_POLYTOPES; ++c) {
 20:       if (DMPolytopeTypeGetDim((DMPolytopeType)c) != d) continue;
 21:       ctO[off++] = c;
 22:     }
 23:   }
 24:   if (dim != 0) {
 25:     for (c = 0; c <= DM_NUM_POLYTOPES; ++c) {
 26:       if (DMPolytopeTypeGetDim((DMPolytopeType)c) != 0) continue;
 27:       ctO[off++] = c;
 28:     }
 29:   }
 30:   for (d = dim - 1; d > 0; --d) {
 31:     for (c = 0; c <= DM_NUM_POLYTOPES; ++c) {
 32:       if (DMPolytopeTypeGetDim((DMPolytopeType)c) != d) continue;
 33:       ctO[off++] = c;
 34:     }
 35:   }
 36:   for (c = 0; c <= DM_NUM_POLYTOPES; ++c) {
 37:     if (DMPolytopeTypeGetDim((DMPolytopeType)c) >= 0) continue;
 38:     ctO[off++] = c;
 39:   }
 40:   PetscCheck(off == DM_NUM_POLYTOPES + 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid offset %" PetscInt_FMT " for cell type order", off);
 41:   for (c = 0; c <= DM_NUM_POLYTOPES; ++c) ctOInv[ctO[c]] = c;
 42:   *ctOrder    = ctO;
 43:   *ctOrderInv = ctOInv;
 44:   PetscFunctionReturn(PETSC_SUCCESS);
 45: }

 47: /*@C
 48:   DMPlexTransformRegister - Adds a new transform component implementation

 50:   Not Collective

 52:   Input Parameters:
 53: + name        - The name of a new user-defined creation routine
 54: - create_func - The creation routine

 56:   Sample usage:
 57: .vb
 58:   DMPlexTransformRegister("my_transform", MyTransformCreate);
 59: .ve

 61:   Then, your transform type can be chosen with the procedural interface via
 62: .vb
 63:   DMPlexTransformCreate(MPI_Comm, DMPlexTransform *);
 64:   DMPlexTransformSetType(DMPlexTransform, "my_transform");
 65: .ve
 66:   or at runtime via the option
 67: .vb
 68:   -dm_plex_transform_type my_transform
 69: .ve

 71:   Level: advanced

 73:   Note:
 74:   `DMPlexTransformRegister()` may be called multiple times to add several user-defined transforms

 76: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformRegisterAll()`, `DMPlexTransformRegisterDestroy()`
 77: @*/
 78: PetscErrorCode DMPlexTransformRegister(const char name[], PetscErrorCode (*create_func)(DMPlexTransform))
 79: {
 80:   PetscFunctionBegin;
 81:   PetscCall(DMInitializePackage());
 82:   PetscCall(PetscFunctionListAdd(&DMPlexTransformList, name, create_func));
 83:   PetscFunctionReturn(PETSC_SUCCESS);
 84: }

 86: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Filter(DMPlexTransform);
 87: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Regular(DMPlexTransform);
 88: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_ToBox(DMPlexTransform);
 89: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Alfeld(DMPlexTransform);
 90: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_SBR(DMPlexTransform);
 91: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_BL(DMPlexTransform);
 92: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_1D(DMPlexTransform);
 93: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Extrude(DMPlexTransform);

 95: /*@C
 96:   DMPlexTransformRegisterAll - Registers all of the transform components in the `DM` package.

 98:   Not Collective

100:   Level: advanced

102: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransformType`, `DMRegisterAll()`, `DMPlexTransformRegisterDestroy()`
103: @*/
104: PetscErrorCode DMPlexTransformRegisterAll(void)
105: {
106:   PetscFunctionBegin;
107:   if (DMPlexTransformRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
108:   DMPlexTransformRegisterAllCalled = PETSC_TRUE;

110:   PetscCall(DMPlexTransformRegister(DMPLEXTRANSFORMFILTER, DMPlexTransformCreate_Filter));
111:   PetscCall(DMPlexTransformRegister(DMPLEXREFINEREGULAR, DMPlexTransformCreate_Regular));
112:   PetscCall(DMPlexTransformRegister(DMPLEXREFINETOBOX, DMPlexTransformCreate_ToBox));
113:   PetscCall(DMPlexTransformRegister(DMPLEXREFINEALFELD, DMPlexTransformCreate_Alfeld));
114:   PetscCall(DMPlexTransformRegister(DMPLEXREFINEBOUNDARYLAYER, DMPlexTransformCreate_BL));
115:   PetscCall(DMPlexTransformRegister(DMPLEXREFINESBR, DMPlexTransformCreate_SBR));
116:   PetscCall(DMPlexTransformRegister(DMPLEXREFINE1D, DMPlexTransformCreate_1D));
117:   PetscCall(DMPlexTransformRegister(DMPLEXEXTRUDE, DMPlexTransformCreate_Extrude));
118:   PetscFunctionReturn(PETSC_SUCCESS);
119: }

121: /*@C
122:   DMPlexTransformRegisterDestroy - This function destroys the registered `DMPlexTransformType`. It is called from `PetscFinalize()`.

124:   Level: developer

126: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMRegisterAll()`, `DMPlexTransformType`, `PetscInitialize()`
127: @*/
128: PetscErrorCode DMPlexTransformRegisterDestroy(void)
129: {
130:   PetscFunctionBegin;
131:   PetscCall(PetscFunctionListDestroy(&DMPlexTransformList));
132:   DMPlexTransformRegisterAllCalled = PETSC_FALSE;
133:   PetscFunctionReturn(PETSC_SUCCESS);
134: }

136: /*@
137:   DMPlexTransformCreate - Creates an empty transform object. The type can then be set with `DMPlexTransformSetType()`.

139:   Collective

141:   Input Parameter:
142: . comm - The communicator for the transform object

144:   Output Parameter:
145: . dm - The transform object

147:   Level: beginner

149: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformSetType()`, `DMPLEXREFINEREGULAR`, `DMPLEXTRANSFORMFILTER`
150: @*/
151: PetscErrorCode DMPlexTransformCreate(MPI_Comm comm, DMPlexTransform *tr)
152: {
153:   DMPlexTransform t;

155:   PetscFunctionBegin;
157:   *tr = NULL;
158:   PetscCall(DMInitializePackage());

160:   PetscCall(PetscHeaderCreate(t, DMPLEXTRANSFORM_CLASSID, "DMPlexTransform", "Mesh Transform", "DMPlexTransform", comm, DMPlexTransformDestroy, DMPlexTransformView));
161:   t->setupcalled = PETSC_FALSE;
162:   PetscCall(PetscCalloc2(DM_NUM_POLYTOPES, &t->coordFE, DM_NUM_POLYTOPES, &t->refGeom));
163:   *tr = t;
164:   PetscFunctionReturn(PETSC_SUCCESS);
165: }

167: /*@C
168:   DMPlexTransformSetType - Sets the particular implementation for a transform.

170:   Collective

172:   Input Parameters:
173: + tr     - The transform
174: - method - The name of the transform type

176:   Options Database Key:
177: . -dm_plex_transform_type <type> - Sets the transform type; see `DMPlexTransformType`

179:   Level: intermediate

181: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformGetType()`, `DMPlexTransformCreate()`
182: @*/
183: PetscErrorCode DMPlexTransformSetType(DMPlexTransform tr, DMPlexTransformType method)
184: {
185:   PetscErrorCode (*r)(DMPlexTransform);
186:   PetscBool match;

188:   PetscFunctionBegin;
190:   PetscCall(PetscObjectTypeCompare((PetscObject)tr, method, &match));
191:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

193:   PetscCall(DMPlexTransformRegisterAll());
194:   PetscCall(PetscFunctionListFind(DMPlexTransformList, method, &r));
195:   PetscCheck(r, PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DMPlexTransform type: %s", method);

197:   PetscTryTypeMethod(tr, destroy);
198:   PetscCall(PetscMemzero(tr->ops, sizeof(*tr->ops)));
199:   PetscCall(PetscObjectChangeTypeName((PetscObject)tr, method));
200:   PetscCall((*r)(tr));
201:   PetscFunctionReturn(PETSC_SUCCESS);
202: }

204: /*@C
205:   DMPlexTransformGetType - Gets the type name (as a string) from the transform.

207:   Not Collective

209:   Input Parameter:
210: . tr  - The `DMPlexTransform`

212:   Output Parameter:
213: . type - The `DMPlexTransformType` name

215:   Level: intermediate

217: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformSetType()`, `DMPlexTransformCreate()`
218: @*/
219: PetscErrorCode DMPlexTransformGetType(DMPlexTransform tr, DMPlexTransformType *type)
220: {
221:   PetscFunctionBegin;
224:   PetscCall(DMPlexTransformRegisterAll());
225:   *type = ((PetscObject)tr)->type_name;
226:   PetscFunctionReturn(PETSC_SUCCESS);
227: }

229: static PetscErrorCode DMPlexTransformView_Ascii(DMPlexTransform tr, PetscViewer v)
230: {
231:   PetscViewerFormat format;

233:   PetscFunctionBegin;
234:   PetscCall(PetscViewerGetFormat(v, &format));
235:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
236:     const PetscInt *trTypes = NULL;
237:     IS              trIS;
238:     PetscInt        cols = 8;
239:     PetscInt        Nrt  = 8, f, g;

241:     if (tr->trType) PetscCall(DMLabelView(tr->trType, v));
242:     PetscCall(PetscViewerASCIIPrintf(v, "Source Starts\n"));
243:     for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14s", DMPolytopeTypes[g]));
244:     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
245:     for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIIPrintf(v, " %14" PetscInt_FMT, tr->ctStart[f]));
246:     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
247:     PetscCall(PetscViewerASCIIPrintf(v, "Target Starts\n"));
248:     for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14s", DMPolytopeTypes[g]));
249:     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
250:     for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIIPrintf(v, " %14" PetscInt_FMT, tr->ctStartNew[f]));
251:     PetscCall(PetscViewerASCIIPrintf(v, "\n"));

253:     if (tr->trType) {
254:       PetscCall(DMLabelGetNumValues(tr->trType, &Nrt));
255:       PetscCall(DMLabelGetValueIS(tr->trType, &trIS));
256:       PetscCall(ISGetIndices(trIS, &trTypes));
257:     }
258:     PetscCall(PetscViewerASCIIPrintf(v, "Offsets\n"));
259:     PetscCall(PetscViewerASCIIPrintf(v, "     "));
260:     for (g = 0; g < cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14s", DMPolytopeTypes[g]));
261:     PetscCall(PetscViewerASCIIPrintf(v, "\n"));
262:     for (f = 0; f < Nrt; ++f) {
263:       PetscCall(PetscViewerASCIIPrintf(v, "%2" PetscInt_FMT "  |", trTypes ? trTypes[f] : f));
264:       for (g = 0; g < cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14" PetscInt_FMT, tr->offset[f * DM_NUM_POLYTOPES + g]));
265:       PetscCall(PetscViewerASCIIPrintf(v, " |\n"));
266:     }
267:     if (tr->trType) {
268:       PetscCall(ISRestoreIndices(trIS, &trTypes));
269:       PetscCall(ISDestroy(&trIS));
270:     }
271:   }
272:   PetscFunctionReturn(PETSC_SUCCESS);
273: }

275: /*@C
276:   DMPlexTransformView - Views a `DMPlexTransform`

278:   Collective

280:   Input Parameters:
281: + tr - the `DMPlexTransform` object to view
282: - v  - the viewer

284:   Level: beginner

286: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `PetscViewer`, `DMPlexTransformDestroy()`, `DMPlexTransformCreate()`
287: @*/
288: PetscErrorCode DMPlexTransformView(DMPlexTransform tr, PetscViewer v)
289: {
290:   PetscBool isascii;

292:   PetscFunctionBegin;
294:   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)tr), &v));
296:   PetscCheckSameComm(tr, 1, v, 2);
297:   PetscCall(PetscViewerCheckWritable(v));
298:   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)tr, v));
299:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &isascii));
300:   if (isascii) PetscCall(DMPlexTransformView_Ascii(tr, v));
301:   PetscTryTypeMethod(tr, view, v);
302:   PetscFunctionReturn(PETSC_SUCCESS);
303: }

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

308:   Collective

310:   Input Parameter:
311: . tr - the `DMPlexTransform` object to set options for

313:   Options Database Key:
314: . -dm_plex_transform_type - Set the transform type, e.g. refine_regular

316:   Level: intermediate

318: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()`
319: @*/
320: PetscErrorCode DMPlexTransformSetFromOptions(DMPlexTransform tr)
321: {
322:   char        typeName[1024];
323:   const char *defName = DMPLEXREFINEREGULAR;
324:   PetscBool   flg;

326:   PetscFunctionBegin;
328:   PetscObjectOptionsBegin((PetscObject)tr);
329:   PetscCall(PetscOptionsFList("-dm_plex_transform_type", "DMPlexTransform", "DMPlexTransformSetType", DMPlexTransformList, defName, typeName, 1024, &flg));
330:   if (flg) PetscCall(DMPlexTransformSetType(tr, typeName));
331:   else if (!((PetscObject)tr)->type_name) PetscCall(DMPlexTransformSetType(tr, defName));
332:   PetscTryTypeMethod(tr, setfromoptions, PetscOptionsObject);
333:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
334:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)tr, PetscOptionsObject));
335:   PetscOptionsEnd();
336:   PetscFunctionReturn(PETSC_SUCCESS);
337: }

339: /*@C
340:   DMPlexTransformDestroy - Destroys a `DMPlexTransform`

342:   Collective

344:   Input Parameter:
345: . tr - the transform object to destroy

347:   Level: beginner

349: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()`
350: @*/
351: PetscErrorCode DMPlexTransformDestroy(DMPlexTransform *tr)
352: {
353:   PetscInt c;

355:   PetscFunctionBegin;
356:   if (!*tr) PetscFunctionReturn(PETSC_SUCCESS);
358:   if (--((PetscObject)(*tr))->refct > 0) {
359:     *tr = NULL;
360:     PetscFunctionReturn(PETSC_SUCCESS);
361:   }

363:   if ((*tr)->ops->destroy) PetscCall((*(*tr)->ops->destroy)(*tr));
364:   PetscCall(DMDestroy(&(*tr)->dm));
365:   PetscCall(DMLabelDestroy(&(*tr)->active));
366:   PetscCall(DMLabelDestroy(&(*tr)->trType));
367:   PetscCall(PetscFree2((*tr)->ctOrderOld, (*tr)->ctOrderInvOld));
368:   PetscCall(PetscFree2((*tr)->ctOrderNew, (*tr)->ctOrderInvNew));
369:   PetscCall(PetscFree2((*tr)->ctStart, (*tr)->ctStartNew));
370:   PetscCall(PetscFree((*tr)->offset));
371:   PetscCall(PetscFree2((*tr)->depthStart, (*tr)->depthEnd));
372:   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
373:     PetscCall(PetscFEDestroy(&(*tr)->coordFE[c]));
374:     PetscCall(PetscFEGeomDestroy(&(*tr)->refGeom[c]));
375:   }
376:   if ((*tr)->trVerts) {
377:     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
378:       DMPolytopeType *rct;
379:       PetscInt       *rsize, *rcone, *rornt, Nct, n, r;

381:       if (DMPolytopeTypeGetDim((DMPolytopeType)c) > 0) {
382:         PetscCall(DMPlexTransformCellTransform((*tr), (DMPolytopeType)c, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
383:         for (n = 0; n < Nct; ++n) {
384:           if (rct[n] == DM_POLYTOPE_POINT) continue;
385:           for (r = 0; r < rsize[n]; ++r) PetscCall(PetscFree((*tr)->trSubVerts[c][rct[n]][r]));
386:           PetscCall(PetscFree((*tr)->trSubVerts[c][rct[n]]));
387:         }
388:       }
389:       PetscCall(PetscFree((*tr)->trSubVerts[c]));
390:       PetscCall(PetscFree((*tr)->trVerts[c]));
391:     }
392:   }
393:   PetscCall(PetscFree3((*tr)->trNv, (*tr)->trVerts, (*tr)->trSubVerts));
394:   PetscCall(PetscFree2((*tr)->coordFE, (*tr)->refGeom));
395:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
396:   PetscCall(PetscHeaderDestroy(tr));
397:   PetscFunctionReturn(PETSC_SUCCESS);
398: }

400: static PetscErrorCode DMPlexTransformCreateOffset_Internal(DMPlexTransform tr, PetscInt ctOrderOld[], PetscInt ctStart[], PetscInt **offset)
401: {
402:   DMLabel  trType = tr->trType;
403:   PetscInt c, cN, *off;

405:   PetscFunctionBegin;
406:   if (trType) {
407:     DM              dm;
408:     IS              rtIS;
409:     const PetscInt *reftypes;
410:     PetscInt        Nrt, r;

412:     PetscCall(DMPlexTransformGetDM(tr, &dm));
413:     PetscCall(DMLabelGetNumValues(trType, &Nrt));
414:     PetscCall(DMLabelGetValueIS(trType, &rtIS));
415:     PetscCall(ISGetIndices(rtIS, &reftypes));
416:     PetscCall(PetscCalloc1(Nrt * DM_NUM_POLYTOPES, &off));
417:     for (r = 0; r < Nrt; ++r) {
418:       const PetscInt  rt = reftypes[r];
419:       IS              rtIS;
420:       const PetscInt *points;
421:       DMPolytopeType  ct;
422:       PetscInt        np, p;

424:       PetscCall(DMLabelGetStratumIS(trType, rt, &rtIS));
425:       PetscCall(ISGetLocalSize(rtIS, &np));
426:       PetscCall(ISGetIndices(rtIS, &points));
427:       if (!np) continue;
428:       p = points[0];
429:       PetscCall(ISRestoreIndices(rtIS, &points));
430:       PetscCall(ISDestroy(&rtIS));
431:       PetscCall(DMPlexGetCellType(dm, p, &ct));
432:       for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) {
433:         const DMPolytopeType ctNew = (DMPolytopeType)cN;
434:         DMPolytopeType      *rct;
435:         PetscInt            *rsize, *cone, *ornt;
436:         PetscInt             Nct, n, s;

438:         if (DMPolytopeTypeGetDim(ct) < 0 || DMPolytopeTypeGetDim(ctNew) < 0) {
439:           off[r * DM_NUM_POLYTOPES + ctNew] = -1;
440:           break;
441:         }
442:         off[r * DM_NUM_POLYTOPES + ctNew] = 0;
443:         for (s = 0; s <= r; ++s) {
444:           const PetscInt st = reftypes[s];
445:           DMPolytopeType sct;
446:           PetscInt       q, qrt;

448:           PetscCall(DMLabelGetStratumIS(trType, st, &rtIS));
449:           PetscCall(ISGetLocalSize(rtIS, &np));
450:           PetscCall(ISGetIndices(rtIS, &points));
451:           if (!np) continue;
452:           q = points[0];
453:           PetscCall(ISRestoreIndices(rtIS, &points));
454:           PetscCall(ISDestroy(&rtIS));
455:           PetscCall(DMPlexGetCellType(dm, q, &sct));
456:           PetscCall(DMPlexTransformCellTransform(tr, sct, q, &qrt, &Nct, &rct, &rsize, &cone, &ornt));
457:           PetscCheck(st == qrt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Refine type %" PetscInt_FMT " of point %" PetscInt_FMT " does not match predicted type %" PetscInt_FMT, qrt, q, st);
458:           if (st == rt) {
459:             for (n = 0; n < Nct; ++n)
460:               if (rct[n] == ctNew) break;
461:             if (n == Nct) off[r * DM_NUM_POLYTOPES + ctNew] = -1;
462:             break;
463:           }
464:           for (n = 0; n < Nct; ++n) {
465:             if (rct[n] == ctNew) {
466:               PetscInt sn;

468:               PetscCall(DMLabelGetStratumSize(trType, st, &sn));
469:               off[r * DM_NUM_POLYTOPES + ctNew] += sn * rsize[n];
470:             }
471:           }
472:         }
473:       }
474:     }
475:     PetscCall(ISRestoreIndices(rtIS, &reftypes));
476:     PetscCall(ISDestroy(&rtIS));
477:   } else {
478:     PetscCall(PetscCalloc1(DM_NUM_POLYTOPES * DM_NUM_POLYTOPES, &off));
479:     for (c = DM_POLYTOPE_POINT; c < DM_NUM_POLYTOPES; ++c) {
480:       const DMPolytopeType ct = (DMPolytopeType)c;
481:       for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) {
482:         const DMPolytopeType ctNew = (DMPolytopeType)cN;
483:         DMPolytopeType      *rct;
484:         PetscInt            *rsize, *cone, *ornt;
485:         PetscInt             Nct, n, i;

487:         if (DMPolytopeTypeGetDim(ct) < 0 || DMPolytopeTypeGetDim(ctNew) < 0) {
488:           off[ct * DM_NUM_POLYTOPES + ctNew] = -1;
489:           continue;
490:         }
491:         off[ct * DM_NUM_POLYTOPES + ctNew] = 0;
492:         for (i = DM_POLYTOPE_POINT; i < DM_NUM_POLYTOPES; ++i) {
493:           const DMPolytopeType ict  = (DMPolytopeType)ctOrderOld[i];
494:           const DMPolytopeType ictn = (DMPolytopeType)ctOrderOld[i + 1];

496:           PetscCall(DMPlexTransformCellTransform(tr, ict, PETSC_DETERMINE, NULL, &Nct, &rct, &rsize, &cone, &ornt));
497:           if (ict == ct) {
498:             for (n = 0; n < Nct; ++n)
499:               if (rct[n] == ctNew) break;
500:             if (n == Nct) off[ct * DM_NUM_POLYTOPES + ctNew] = -1;
501:             break;
502:           }
503:           for (n = 0; n < Nct; ++n)
504:             if (rct[n] == ctNew) off[ct * DM_NUM_POLYTOPES + ctNew] += (ctStart[ictn] - ctStart[ict]) * rsize[n];
505:         }
506:       }
507:     }
508:   }
509:   *offset = off;
510:   PetscFunctionReturn(PETSC_SUCCESS);
511: }

513: PetscErrorCode DMPlexTransformSetUp(DMPlexTransform tr)
514: {
515:   DM             dm;
516:   DMPolytopeType ctCell;
517:   PetscInt       pStart, pEnd, p, c, celldim = 0;

519:   PetscFunctionBegin;
521:   if (tr->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
522:   PetscTryTypeMethod(tr, setup);
523:   PetscCall(DMPlexTransformGetDM(tr, &dm));
524:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
525:   if (pEnd > pStart) {
526:     PetscCall(DMPlexGetCellType(dm, 0, &ctCell));
527:   } else {
528:     PetscInt dim;

530:     PetscCall(DMGetDimension(dm, &dim));
531:     switch (dim) {
532:     case 0:
533:       ctCell = DM_POLYTOPE_POINT;
534:       break;
535:     case 1:
536:       ctCell = DM_POLYTOPE_SEGMENT;
537:       break;
538:     case 2:
539:       ctCell = DM_POLYTOPE_TRIANGLE;
540:       break;
541:     case 3:
542:       ctCell = DM_POLYTOPE_TETRAHEDRON;
543:       break;
544:     default:
545:       ctCell = DM_POLYTOPE_UNKNOWN;
546:     }
547:   }
548:   PetscCall(DMPlexCreateCellTypeOrder_Internal(DMPolytopeTypeGetDim(ctCell), &tr->ctOrderOld, &tr->ctOrderInvOld));
549:   for (p = pStart; p < pEnd; ++p) {
550:     DMPolytopeType  ct;
551:     DMPolytopeType *rct;
552:     PetscInt       *rsize, *cone, *ornt;
553:     PetscInt        Nct, n;

555:     PetscCall(DMPlexGetCellType(dm, p, &ct));
556:     PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell type for point %" PetscInt_FMT, p);
557:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt));
558:     for (n = 0; n < Nct; ++n) celldim = PetscMax(celldim, DMPolytopeTypeGetDim(rct[n]));
559:   }
560:   PetscCall(DMPlexCreateCellTypeOrder_Internal(celldim, &tr->ctOrderNew, &tr->ctOrderInvNew));
561:   /* Construct sizes and offsets for each cell type */
562:   if (!tr->ctStart) {
563:     PetscInt *ctS, *ctSN, *ctC, *ctCN;

565:     PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctS, DM_NUM_POLYTOPES + 1, &ctSN));
566:     PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctC, DM_NUM_POLYTOPES + 1, &ctCN));
567:     for (p = pStart; p < pEnd; ++p) {
568:       DMPolytopeType  ct;
569:       DMPolytopeType *rct;
570:       PetscInt       *rsize, *cone, *ornt;
571:       PetscInt        Nct, n;

573:       PetscCall(DMPlexGetCellType(dm, p, &ct));
574:       PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell type for point %" PetscInt_FMT, p);
575:       ++ctC[ct];
576:       PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt));
577:       for (n = 0; n < Nct; ++n) ctCN[rct[n]] += rsize[n];
578:     }
579:     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
580:       const PetscInt cto  = tr->ctOrderOld[c];
581:       const PetscInt cton = tr->ctOrderOld[c + 1];
582:       const PetscInt ctn  = tr->ctOrderNew[c];
583:       const PetscInt ctnn = tr->ctOrderNew[c + 1];

585:       ctS[cton]  = ctS[cto] + ctC[cto];
586:       ctSN[ctnn] = ctSN[ctn] + ctCN[ctn];
587:     }
588:     PetscCall(PetscFree2(ctC, ctCN));
589:     tr->ctStart    = ctS;
590:     tr->ctStartNew = ctSN;
591:   }
592:   PetscCall(DMPlexTransformCreateOffset_Internal(tr, tr->ctOrderOld, tr->ctStart, &tr->offset));
593:   // Compute depth information
594:   tr->depth = -1;
595:   for (c = 0; c < DM_NUM_POLYTOPES; ++c)
596:     if (tr->ctStartNew[tr->ctOrderNew[c + 1]] > tr->ctStartNew[tr->ctOrderNew[c]]) tr->depth = PetscMax(tr->depth, DMPolytopeTypeGetDim((DMPolytopeType)tr->ctOrderNew[c]));
597:   PetscCall(PetscMalloc2(tr->depth + 1, &tr->depthStart, tr->depth + 1, &tr->depthEnd));
598:   for (PetscInt d = 0; d <= tr->depth; ++d) {
599:     tr->depthStart[d] = PETSC_MAX_INT;
600:     tr->depthEnd[d]   = -1;
601:   }
602:   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
603:     const PetscInt dep = DMPolytopeTypeGetDim((DMPolytopeType)tr->ctOrderNew[c]);

605:     if (tr->ctStartNew[tr->ctOrderNew[c + 1]] <= tr->ctStartNew[tr->ctOrderNew[c]]) continue;
606:     tr->depthStart[dep] = PetscMin(tr->depthStart[dep], tr->ctStartNew[tr->ctOrderNew[c]]);
607:     tr->depthEnd[dep]   = PetscMax(tr->depthEnd[dep], tr->ctStartNew[tr->ctOrderNew[c + 1]]);
608:   }
609:   tr->setupcalled = PETSC_TRUE;
610:   PetscFunctionReturn(PETSC_SUCCESS);
611: }

613: PetscErrorCode DMPlexTransformGetDM(DMPlexTransform tr, DM *dm)
614: {
615:   PetscFunctionBegin;
618:   *dm = tr->dm;
619:   PetscFunctionReturn(PETSC_SUCCESS);
620: }

622: PetscErrorCode DMPlexTransformSetDM(DMPlexTransform tr, DM dm)
623: {
624:   PetscFunctionBegin;
627:   PetscCall(PetscObjectReference((PetscObject)dm));
628:   PetscCall(DMDestroy(&tr->dm));
629:   tr->dm = dm;
630:   PetscFunctionReturn(PETSC_SUCCESS);
631: }

633: PetscErrorCode DMPlexTransformGetActive(DMPlexTransform tr, DMLabel *active)
634: {
635:   PetscFunctionBegin;
638:   *active = tr->active;
639:   PetscFunctionReturn(PETSC_SUCCESS);
640: }

642: PetscErrorCode DMPlexTransformSetActive(DMPlexTransform tr, DMLabel active)
643: {
644:   PetscFunctionBegin;
647:   PetscCall(PetscObjectReference((PetscObject)active));
648:   PetscCall(DMLabelDestroy(&tr->active));
649:   tr->active = active;
650:   PetscFunctionReturn(PETSC_SUCCESS);
651: }

653: static PetscErrorCode DMPlexTransformGetCoordinateFE(DMPlexTransform tr, DMPolytopeType ct, PetscFE *fe)
654: {
655:   PetscFunctionBegin;
656:   if (!tr->coordFE[ct]) {
657:     PetscInt dim, cdim;

659:     dim = DMPolytopeTypeGetDim(ct);
660:     PetscCall(DMGetCoordinateDim(tr->dm, &cdim));
661:     PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, cdim, ct, 1, PETSC_DETERMINE, &tr->coordFE[ct]));
662:     {
663:       PetscDualSpace  dsp;
664:       PetscQuadrature quad;
665:       DM              K;
666:       PetscFEGeom    *cg;
667:       PetscScalar    *Xq;
668:       PetscReal      *xq, *wq;
669:       PetscInt        Nq, q;

671:       PetscCall(DMPlexTransformGetCellVertices(tr, ct, &Nq, &Xq));
672:       PetscCall(PetscMalloc1(Nq * cdim, &xq));
673:       for (q = 0; q < Nq * cdim; ++q) xq[q] = PetscRealPart(Xq[q]);
674:       PetscCall(PetscMalloc1(Nq, &wq));
675:       for (q = 0; q < Nq; ++q) wq[q] = 1.0;
676:       PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
677:       PetscCall(PetscQuadratureSetData(quad, dim, 1, Nq, xq, wq));
678:       PetscCall(PetscFESetQuadrature(tr->coordFE[ct], quad));

680:       PetscCall(PetscFEGetDualSpace(tr->coordFE[ct], &dsp));
681:       PetscCall(PetscDualSpaceGetDM(dsp, &K));
682:       PetscCall(PetscFEGeomCreate(quad, 1, cdim, PETSC_FALSE, &tr->refGeom[ct]));
683:       cg = tr->refGeom[ct];
684:       PetscCall(DMPlexComputeCellGeometryFEM(K, 0, NULL, cg->v, cg->J, cg->invJ, cg->detJ));
685:       PetscCall(PetscQuadratureDestroy(&quad));
686:     }
687:   }
688:   *fe = tr->coordFE[ct];
689:   PetscFunctionReturn(PETSC_SUCCESS);
690: }

692: PetscErrorCode DMPlexTransformSetDimensions_Internal(DMPlexTransform tr, DM dm, DM tdm)
693: {
694:   PetscInt dim, cdim;

696:   PetscFunctionBegin;
697:   PetscCall(DMGetDimension(dm, &dim));
698:   PetscCall(DMSetDimension(tdm, dim));
699:   PetscCall(DMGetCoordinateDim(dm, &cdim));
700:   PetscCall(DMSetCoordinateDim(tdm, cdim));
701:   PetscFunctionReturn(PETSC_SUCCESS);
702: }

704: /*@
705:   DMPlexTransformSetDimensions - Set the dimensions for the transformed `DM`

707:   Input Parameters:
708: + tr - The `DMPlexTransform` object
709: - dm - The original `DM`

711:   Output Parameter:
712: . tdm - The transformed `DM`

714:   Level: advanced

716: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
717: @*/
718: PetscErrorCode DMPlexTransformSetDimensions(DMPlexTransform tr, DM dm, DM tdm)
719: {
720:   PetscFunctionBegin;
721:   PetscUseTypeMethod(tr, setdimensions, dm, tdm);
722:   PetscFunctionReturn(PETSC_SUCCESS);
723: }

725: PetscErrorCode DMPlexTransformGetChart(DMPlexTransform tr, PetscInt *pStart, PetscInt *pEnd)
726: {
727:   PetscFunctionBegin;
728:   if (pStart) *pStart = 0;
729:   if (pEnd) *pEnd = tr->ctStartNew[tr->ctOrderNew[DM_NUM_POLYTOPES]];
730:   PetscFunctionReturn(PETSC_SUCCESS);
731: }

733: PetscErrorCode DMPlexTransformGetCellType(DMPlexTransform tr, PetscInt cell, DMPolytopeType *celltype)
734: {
735:   PetscInt ctNew;

737:   PetscFunctionBegin;
740:   /* TODO Can do bisection since everything is sorted */
741:   for (ctNew = DM_POLYTOPE_POINT; ctNew < DM_NUM_POLYTOPES; ++ctNew) {
742:     PetscInt ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]];

744:     if (cell >= ctSN && cell < ctEN) break;
745:   }
746:   PetscCheck(ctNew < DM_NUM_POLYTOPES, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " cannot be located in the transformed mesh", cell);
747:   *celltype = (DMPolytopeType)ctNew;
748:   PetscFunctionReturn(PETSC_SUCCESS);
749: }

751: PetscErrorCode DMPlexTransformGetDepth(DMPlexTransform tr, PetscInt *depth)
752: {
753:   PetscFunctionBegin;
755:   *depth = tr->depth;
756:   PetscFunctionReturn(PETSC_SUCCESS);
757: }

759: PetscErrorCode DMPlexTransformGetDepthStratum(DMPlexTransform tr, PetscInt depth, PetscInt *start, PetscInt *end)
760: {
761:   PetscFunctionBegin;
763:   if (start) *start = tr->depthStart[depth];
764:   if (end) *end = tr->depthEnd[depth];
765:   PetscFunctionReturn(PETSC_SUCCESS);
766: }

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

771:   Not Collective

773:   Input Parameters:
774: + tr    - The `DMPlexTransform`
775: . ct    - The type of the original point which produces the new point
776: . ctNew - The type of the new point
777: . p     - The original point which produces the new point
778: - r     - The replica number of the new point, meaning it is the rth point of type `ctNew` produced from `p`

780:   Output Parameter:
781: . pNew  - The new point number

783:   Level: developer

785: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSourcePoint()`, `DMPlexTransformCellTransform()`
786: @*/
787: PetscErrorCode DMPlexTransformGetTargetPoint(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType ctNew, PetscInt p, PetscInt r, PetscInt *pNew)
788: {
789:   DMPolytopeType *rct;
790:   PetscInt       *rsize, *cone, *ornt;
791:   PetscInt        rt, Nct, n, off, rp;
792:   DMLabel         trType = tr->trType;
793:   PetscInt        ctS = tr->ctStart[ct], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ct] + 1]];
794:   PetscInt        ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]];
795:   PetscInt        newp = ctSN, cind;

797:   PetscFunctionBeginHot;
798:   PetscCheck(!(p < ctS) && !(p >= ctE), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " is not a %s [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, DMPolytopeTypes[ct], ctS, ctE);
799:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, &rt, &Nct, &rct, &rsize, &cone, &ornt));
800:   if (trType) {
801:     PetscCall(DMLabelGetValueIndex(trType, rt, &cind));
802:     PetscCall(DMLabelGetStratumPointIndex(trType, rt, p, &rp));
803:     PetscCheck(rp >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell type %s point %" PetscInt_FMT " does not have refine type %" PetscInt_FMT, DMPolytopeTypes[ct], p, rt);
804:   } else {
805:     cind = ct;
806:     rp   = p - ctS;
807:   }
808:   off = tr->offset[cind * DM_NUM_POLYTOPES + ctNew];
809:   PetscCheck(off >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell type %s (%" PetscInt_FMT ") of point %" PetscInt_FMT " does not produce type %s for transform %s", DMPolytopeTypes[ct], rt, p, DMPolytopeTypes[ctNew], tr->hdr.type_name);
810:   newp += off;
811:   for (n = 0; n < Nct; ++n) {
812:     if (rct[n] == ctNew) {
813:       if (rsize[n] && r >= rsize[n])
814:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number %" PetscInt_FMT " should be in [0, %" PetscInt_FMT ") for subcell type %s in cell type %s", r, rsize[n], DMPolytopeTypes[rct[n]], DMPolytopeTypes[ct]);
815:       newp += rp * rsize[n] + r;
816:       break;
817:     }
818:   }

820:   PetscCheck(!(newp < ctSN) && !(newp >= ctEN), PETSC_COMM_SELF, PETSC_ERR_PLIB, "New point %" PetscInt_FMT " is not a %s [%" PetscInt_FMT ", %" PetscInt_FMT ")", newp, DMPolytopeTypes[ctNew], ctSN, ctEN);
821:   *pNew = newp;
822:   PetscFunctionReturn(PETSC_SUCCESS);
823: }

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

828:   Not Collective

830:   Input Parameters:
831: + tr    - The `DMPlexTransform`
832: - pNew  - The new point number

834:   Output Parameters:
835: + ct    - The type of the original point which produces the new point
836: . ctNew - The type of the new point
837: . p     - The original point which produces the new point
838: - r     - The replica number of the new point, meaning it is the rth point of type ctNew produced from p

840:   Level: developer

842: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetTargetPoint()`, `DMPlexTransformCellTransform()`
843: @*/
844: PetscErrorCode DMPlexTransformGetSourcePoint(DMPlexTransform tr, PetscInt pNew, DMPolytopeType *ct, DMPolytopeType *ctNew, PetscInt *p, PetscInt *r)
845: {
846:   DMLabel         trType = tr->trType;
847:   DMPolytopeType *rct, ctN;
848:   PetscInt       *rsize, *cone, *ornt;
849:   PetscInt        rt = -1, rtTmp, Nct, n, rp = 0, rO = 0, pO;
850:   PetscInt        offset = -1, ctS, ctE, ctO = 0, ctTmp, rtS;

852:   PetscFunctionBegin;
853:   PetscCall(DMPlexTransformGetCellType(tr, pNew, &ctN));
854:   if (trType) {
855:     DM              dm;
856:     IS              rtIS;
857:     const PetscInt *reftypes;
858:     PetscInt        Nrt, r, rtStart;

860:     PetscCall(DMPlexTransformGetDM(tr, &dm));
861:     PetscCall(DMLabelGetNumValues(trType, &Nrt));
862:     PetscCall(DMLabelGetValueIS(trType, &rtIS));
863:     PetscCall(ISGetIndices(rtIS, &reftypes));
864:     for (r = 0; r < Nrt; ++r) {
865:       const PetscInt off = tr->offset[r * DM_NUM_POLYTOPES + ctN];

867:       if (tr->ctStartNew[ctN] + off > pNew) continue;
868:       /* Check that any of this refinement type exist */
869:       /* TODO Actually keep track of the number produced here instead */
870:       if (off > offset) {
871:         rt     = reftypes[r];
872:         offset = off;
873:       }
874:     }
875:     PetscCall(ISRestoreIndices(rtIS, &reftypes));
876:     PetscCall(ISDestroy(&rtIS));
877:     PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew);
878:     /* TODO Map refinement types to cell types */
879:     PetscCall(DMLabelGetStratumBounds(trType, rt, &rtStart, NULL));
880:     PetscCheck(rtStart >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Refinement type %" PetscInt_FMT " has no source points", rt);
881:     for (ctO = 0; ctO < DM_NUM_POLYTOPES; ++ctO) {
882:       PetscInt ctS = tr->ctStart[ctO], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]];

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

891:       if (tr->ctStartNew[ctN] + off > pNew) continue;
892:       if (tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctTmp] + 1]] <= tr->ctStart[ctTmp]) continue;
893:       /* TODO Actually keep track of the number produced here instead */
894:       if (off > offset) {
895:         ctO    = ctTmp;
896:         offset = off;
897:       }
898:     }
899:     rt = -1;
900:     PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew);
901:   }
902:   ctS = tr->ctStart[ctO];
903:   ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]];
904:   if (trType) {
905:     for (rtS = ctS; rtS < ctE; ++rtS) {
906:       PetscInt val;
907:       PetscCall(DMLabelGetValue(trType, rtS, &val));
908:       if (val == rt) break;
909:     }
910:     PetscCheck(rtS < ctE, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find point of type %s with refine type %" PetscInt_FMT, DMPolytopeTypes[ctO], rt);
911:   } else rtS = ctS;
912:   PetscCall(DMPlexTransformCellTransform(tr, (DMPolytopeType)ctO, rtS, &rtTmp, &Nct, &rct, &rsize, &cone, &ornt));
913:   PetscCheck(!trType || rt == rtTmp, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " has refine type %" PetscInt_FMT " != %" PetscInt_FMT " refine type which produced point %" PetscInt_FMT, rtS, rtTmp, rt, pNew);
914:   for (n = 0; n < Nct; ++n) {
915:     if (rct[n] == ctN) {
916:       PetscInt tmp = pNew - tr->ctStartNew[ctN] - offset, val, c;

918:       if (trType) {
919:         for (c = ctS; c < ctE; ++c) {
920:           PetscCall(DMLabelGetValue(trType, c, &val));
921:           if (val == rt) {
922:             if (tmp < rsize[n]) break;
923:             tmp -= rsize[n];
924:           }
925:         }
926:         PetscCheck(c < ctE, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Parent point for target point %" PetscInt_FMT " could be not found", pNew);
927:         rp = c - ctS;
928:         rO = tmp;
929:       } else {
930:         // This assumes that all points of type ctO transform the same way
931:         rp = tmp / rsize[n];
932:         rO = tmp % rsize[n];
933:       }
934:       break;
935:     }
936:   }
937:   PetscCheck(n != Nct, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number for target point %" PetscInt_FMT " could be not found", pNew);
938:   pO = rp + ctS;
939:   PetscCheck(!(pO < ctS) && !(pO >= ctE), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Source point %" PetscInt_FMT " is not a %s [%" PetscInt_FMT ", %" PetscInt_FMT ")", pO, DMPolytopeTypes[ctO], ctS, ctE);
940:   if (ct) *ct = (DMPolytopeType)ctO;
941:   if (ctNew) *ctNew = (DMPolytopeType)ctN;
942:   if (p) *p = pO;
943:   if (r) *r = rO;
944:   PetscFunctionReturn(PETSC_SUCCESS);
945: }

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

950:   Input Parameters:
951: + tr     - The `DMPlexTransform` object
952: . source - The source cell type
953: - p      - The source point, which can also determine the refine type

955:   Output Parameters:
956: + rt     - The refine type for this point
957: . Nt     - The number of types produced by this point
958: . target - An array of length `Nt` giving the types produced
959: . size   - An array of length `Nt` giving the number of cells of each type produced
960: . cone   - An array of length `Nt`*size[t]*coneSize[t] giving the cell type for each point in the cone of each produced point
961: - ornt   - An array of length `Nt`*size[t]*coneSize[t] giving the orientation for each point in the cone of each produced point

963:   Level: advanced

965:   Notes:
966:   The cone array gives the cone of each subcell listed by the first three outputs. For each cone point, we
967:   need the cell type, point identifier, and orientation within the subcell. The orientation is with respect to the canonical
968:   division (described in these outputs) of the cell in the original mesh. The point identifier is given by
969: .vb
970:    the number of cones to be taken, or 0 for the current cell
971:    the cell cone point number at each level from which it is subdivided
972:    the replica number r of the subdivision.
973: .ve
974: The orientation is with respect to the canonical cone orientation. For example, the prescription for edge division is
975: .vb
976:    Nt     = 2
977:    target = {DM_POLYTOPE_POINT, DM_POLYTOPE_SEGMENT}
978:    size   = {1, 2}
979:    cone   = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 0, 0,  DM_POLYTOPE_POINT, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0}
980:    ornt   = {                         0,                       0,                        0,                          0}
981: .ve

983: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
984: @*/
985: PetscErrorCode DMPlexTransformCellTransform(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[])
986: {
987:   PetscFunctionBegin;
988:   PetscUseTypeMethod(tr, celltransform, source, p, rt, Nt, target, size, cone, ornt);
989:   PetscFunctionReturn(PETSC_SUCCESS);
990: }

992: PetscErrorCode DMPlexTransformGetSubcellOrientationIdentity(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew)
993: {
994:   PetscFunctionBegin;
995:   *rnew = r;
996:   *onew = DMPolytopeTypeComposeOrientation(tct, o, so);
997:   PetscFunctionReturn(PETSC_SUCCESS);
998: }

1000: /* Returns the same thing */
1001: PetscErrorCode DMPlexTransformCellTransformIdentity(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[])
1002: {
1003:   static DMPolytopeType vertexT[] = {DM_POLYTOPE_POINT};
1004:   static PetscInt       vertexS[] = {1};
1005:   static PetscInt       vertexC[] = {0};
1006:   static PetscInt       vertexO[] = {0};
1007:   static DMPolytopeType edgeT[]   = {DM_POLYTOPE_SEGMENT};
1008:   static PetscInt       edgeS[]   = {1};
1009:   static PetscInt       edgeC[]   = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0};
1010:   static PetscInt       edgeO[]   = {0, 0};
1011:   static DMPolytopeType tedgeT[]  = {DM_POLYTOPE_POINT_PRISM_TENSOR};
1012:   static PetscInt       tedgeS[]  = {1};
1013:   static PetscInt       tedgeC[]  = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0};
1014:   static PetscInt       tedgeO[]  = {0, 0};
1015:   static DMPolytopeType triT[]    = {DM_POLYTOPE_TRIANGLE};
1016:   static PetscInt       triS[]    = {1};
1017:   static PetscInt       triC[]    = {DM_POLYTOPE_SEGMENT, 1, 0, 0, DM_POLYTOPE_SEGMENT, 1, 1, 0, DM_POLYTOPE_SEGMENT, 1, 2, 0};
1018:   static PetscInt       triO[]    = {0, 0, 0};
1019:   static DMPolytopeType quadT[]   = {DM_POLYTOPE_QUADRILATERAL};
1020:   static PetscInt       quadS[]   = {1};
1021:   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};
1022:   static PetscInt       quadO[]   = {0, 0, 0, 0};
1023:   static DMPolytopeType tquadT[]  = {DM_POLYTOPE_SEG_PRISM_TENSOR};
1024:   static PetscInt       tquadS[]  = {1};
1025:   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};
1026:   static PetscInt       tquadO[]  = {0, 0, 0, 0};
1027:   static DMPolytopeType tetT[]    = {DM_POLYTOPE_TETRAHEDRON};
1028:   static PetscInt       tetS[]    = {1};
1029:   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};
1030:   static PetscInt       tetO[]    = {0, 0, 0, 0};
1031:   static DMPolytopeType hexT[]    = {DM_POLYTOPE_HEXAHEDRON};
1032:   static PetscInt       hexS[]    = {1};
1033:   static PetscInt       hexC[] = {DM_POLYTOPE_QUADRILATERAL, 1, 0, 0, DM_POLYTOPE_QUADRILATERAL, 1, 1, 0, DM_POLYTOPE_QUADRILATERAL, 1, 2, 0, DM_POLYTOPE_QUADRILATERAL, 1, 3, 0, DM_POLYTOPE_QUADRILATERAL, 1, 4, 0, DM_POLYTOPE_QUADRILATERAL, 1, 5, 0};
1034:   static PetscInt       hexO[] = {0, 0, 0, 0, 0, 0};
1035:   static DMPolytopeType tripT[]   = {DM_POLYTOPE_TRI_PRISM};
1036:   static PetscInt       tripS[]   = {1};
1037:   static PetscInt       tripC[]   = {DM_POLYTOPE_TRIANGLE, 1, 0, 0, DM_POLYTOPE_TRIANGLE, 1, 1, 0, DM_POLYTOPE_QUADRILATERAL, 1, 2, 0, DM_POLYTOPE_QUADRILATERAL, 1, 3, 0, DM_POLYTOPE_QUADRILATERAL, 1, 4, 0};
1038:   static PetscInt       tripO[]   = {0, 0, 0, 0, 0};
1039:   static DMPolytopeType ttripT[]  = {DM_POLYTOPE_TRI_PRISM_TENSOR};
1040:   static PetscInt       ttripS[]  = {1};
1041:   static PetscInt       ttripC[]  = {DM_POLYTOPE_TRIANGLE, 1, 0, 0, DM_POLYTOPE_TRIANGLE, 1, 1, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 2, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 3, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 4, 0};
1042:   static PetscInt       ttripO[]  = {0, 0, 0, 0, 0};
1043:   static DMPolytopeType tquadpT[] = {DM_POLYTOPE_QUAD_PRISM_TENSOR};
1044:   static PetscInt       tquadpS[] = {1};
1045:   static PetscInt       tquadpC[] = {DM_POLYTOPE_QUADRILATERAL,    1, 0, 0, DM_POLYTOPE_QUADRILATERAL,    1, 1, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 2, 0,
1046:                                      DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 3, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 4, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 5, 0};
1047:   static PetscInt       tquadpO[] = {0, 0, 0, 0, 0, 0};
1048:   static DMPolytopeType pyrT[]    = {DM_POLYTOPE_PYRAMID};
1049:   static PetscInt       pyrS[]    = {1};
1050:   static PetscInt       pyrC[]    = {DM_POLYTOPE_QUADRILATERAL, 1, 0, 0, DM_POLYTOPE_TRIANGLE, 1, 1, 0, DM_POLYTOPE_TRIANGLE, 1, 2, 0, DM_POLYTOPE_TRIANGLE, 1, 3, 0, DM_POLYTOPE_TRIANGLE, 1, 4, 0};
1051:   static PetscInt       pyrO[]    = {0, 0, 0, 0, 0};

1053:   PetscFunctionBegin;
1054:   if (rt) *rt = 0;
1055:   switch (source) {
1056:   case DM_POLYTOPE_POINT:
1057:     *Nt     = 1;
1058:     *target = vertexT;
1059:     *size   = vertexS;
1060:     *cone   = vertexC;
1061:     *ornt   = vertexO;
1062:     break;
1063:   case DM_POLYTOPE_SEGMENT:
1064:     *Nt     = 1;
1065:     *target = edgeT;
1066:     *size   = edgeS;
1067:     *cone   = edgeC;
1068:     *ornt   = edgeO;
1069:     break;
1070:   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1071:     *Nt     = 1;
1072:     *target = tedgeT;
1073:     *size   = tedgeS;
1074:     *cone   = tedgeC;
1075:     *ornt   = tedgeO;
1076:     break;
1077:   case DM_POLYTOPE_TRIANGLE:
1078:     *Nt     = 1;
1079:     *target = triT;
1080:     *size   = triS;
1081:     *cone   = triC;
1082:     *ornt   = triO;
1083:     break;
1084:   case DM_POLYTOPE_QUADRILATERAL:
1085:     *Nt     = 1;
1086:     *target = quadT;
1087:     *size   = quadS;
1088:     *cone   = quadC;
1089:     *ornt   = quadO;
1090:     break;
1091:   case DM_POLYTOPE_SEG_PRISM_TENSOR:
1092:     *Nt     = 1;
1093:     *target = tquadT;
1094:     *size   = tquadS;
1095:     *cone   = tquadC;
1096:     *ornt   = tquadO;
1097:     break;
1098:   case DM_POLYTOPE_TETRAHEDRON:
1099:     *Nt     = 1;
1100:     *target = tetT;
1101:     *size   = tetS;
1102:     *cone   = tetC;
1103:     *ornt   = tetO;
1104:     break;
1105:   case DM_POLYTOPE_HEXAHEDRON:
1106:     *Nt     = 1;
1107:     *target = hexT;
1108:     *size   = hexS;
1109:     *cone   = hexC;
1110:     *ornt   = hexO;
1111:     break;
1112:   case DM_POLYTOPE_TRI_PRISM:
1113:     *Nt     = 1;
1114:     *target = tripT;
1115:     *size   = tripS;
1116:     *cone   = tripC;
1117:     *ornt   = tripO;
1118:     break;
1119:   case DM_POLYTOPE_TRI_PRISM_TENSOR:
1120:     *Nt     = 1;
1121:     *target = ttripT;
1122:     *size   = ttripS;
1123:     *cone   = ttripC;
1124:     *ornt   = ttripO;
1125:     break;
1126:   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
1127:     *Nt     = 1;
1128:     *target = tquadpT;
1129:     *size   = tquadpS;
1130:     *cone   = tquadpC;
1131:     *ornt   = tquadpO;
1132:     break;
1133:   case DM_POLYTOPE_PYRAMID:
1134:     *Nt     = 1;
1135:     *target = pyrT;
1136:     *size   = pyrS;
1137:     *cone   = pyrC;
1138:     *ornt   = pyrO;
1139:     break;
1140:   default:
1141:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No refinement strategy for %s", DMPolytopeTypes[source]);
1142:   }
1143:   PetscFunctionReturn(PETSC_SUCCESS);
1144: }

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

1149:   Not Collective

1151:   Input Parameters:
1152: + tr  - The `DMPlexTransform`
1153: . sct - The source point cell type, from whom the new cell is being produced
1154: . sp  - The source point
1155: . so  - The orientation of the source point in its enclosing parent
1156: . tct - The target point cell type
1157: . r   - The replica number requested for the produced cell type
1158: - o   - The orientation of the replica

1160:   Output Parameters:
1161: + rnew - The replica number, given the orientation of the parent
1162: - onew - The replica orientation, given the orientation of the parent

1164:   Level: advanced

1166: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformCellTransform()`, `DMPlexTransformApply()`
1167: @*/
1168: PetscErrorCode DMPlexTransformGetSubcellOrientation(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew)
1169: {
1170:   PetscFunctionBeginHot;
1171:   PetscUseTypeMethod(tr, getsubcellorientation, sct, sp, so, tct, r, o, rnew, onew);
1172:   PetscFunctionReturn(PETSC_SUCCESS);
1173: }

1175: static PetscErrorCode DMPlexTransformSetConeSizes(DMPlexTransform tr, DM rdm)
1176: {
1177:   DM       dm;
1178:   PetscInt pStart, pEnd, p, pNew;

1180:   PetscFunctionBegin;
1181:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1182:   /* Must create the celltype label here so that we do not automatically try to compute the types */
1183:   PetscCall(DMCreateLabel(rdm, "celltype"));
1184:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1185:   for (p = pStart; p < pEnd; ++p) {
1186:     DMPolytopeType  ct;
1187:     DMPolytopeType *rct;
1188:     PetscInt       *rsize, *rcone, *rornt;
1189:     PetscInt        Nct, n, r;

1191:     PetscCall(DMPlexGetCellType(dm, p, &ct));
1192:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1193:     for (n = 0; n < Nct; ++n) {
1194:       for (r = 0; r < rsize[n]; ++r) {
1195:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1196:         PetscCall(DMPlexSetConeSize(rdm, pNew, DMPolytopeTypeGetConeSize(rct[n])));
1197:         PetscCall(DMPlexSetCellType(rdm, pNew, rct[n]));
1198:       }
1199:     }
1200:   }
1201:   /* Let the DM know we have set all the cell types */
1202:   {
1203:     DMLabel  ctLabel;
1204:     DM_Plex *plex = (DM_Plex *)rdm->data;

1206:     PetscCall(DMPlexGetCellTypeLabel(rdm, &ctLabel));
1207:     PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &plex->celltypeState));
1208:   }
1209:   PetscFunctionReturn(PETSC_SUCCESS);
1210: }

1212: PetscErrorCode DMPlexTransformGetConeSize(DMPlexTransform tr, PetscInt q, PetscInt *coneSize)
1213: {
1214:   DMPolytopeType ctNew;

1216:   PetscFunctionBegin;
1219:   PetscCall(DMPlexTransformGetCellType(tr, q, &ctNew));
1220:   *coneSize = DMPolytopeTypeGetConeSize((DMPolytopeType)ctNew);
1221:   PetscFunctionReturn(PETSC_SUCCESS);
1222: }

1224: /* The orientation o is for the interior of the cell p */
1225: static PetscErrorCode DMPlexTransformGetCone_Internal(DMPlexTransform tr, PetscInt p, PetscInt o, DMPolytopeType ct, DMPolytopeType ctNew, const PetscInt rcone[], PetscInt *coneoff, const PetscInt rornt[], PetscInt *orntoff, PetscInt coneNew[], PetscInt orntNew[])
1226: {
1227:   DM              dm;
1228:   const PetscInt  csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1229:   const PetscInt *cone;
1230:   PetscInt        c, coff = *coneoff, ooff = *orntoff;

1232:   PetscFunctionBegin;
1233:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1234:   PetscCall(DMPlexGetOrientedCone(dm, p, &cone, NULL));
1235:   for (c = 0; c < csizeNew; ++c) {
1236:     PetscInt             ppp   = -1;                            /* Parent Parent point: Parent of point pp */
1237:     PetscInt             pp    = p;                             /* Parent point: Point in the original mesh producing new cone point */
1238:     PetscInt             po    = 0;                             /* Orientation of parent point pp in parent parent point ppp */
1239:     DMPolytopeType       pct   = ct;                            /* Parent type: Cell type for parent of new cone point */
1240:     const PetscInt      *pcone = cone;                          /* Parent cone: Cone of parent point pp */
1241:     PetscInt             pr    = -1;                            /* Replica number of pp that produces new cone point  */
1242:     const DMPolytopeType ft    = (DMPolytopeType)rcone[coff++]; /* Cell type for new cone point of pNew */
1243:     const PetscInt       fn    = rcone[coff++];                 /* Number of cones of p that need to be taken when producing new cone point */
1244:     PetscInt             fo    = rornt[ooff++];                 /* Orientation of new cone point in pNew */
1245:     PetscInt             lc;

1247:     /* Get the type (pct) and point number (pp) of the parent point in the original mesh which produces this cone point */
1248:     for (lc = 0; lc < fn; ++lc) {
1249:       const PetscInt *parr = DMPolytopeTypeGetArrangment(pct, po);
1250:       const PetscInt  acp  = rcone[coff++];
1251:       const PetscInt  pcp  = parr[acp * 2];
1252:       const PetscInt  pco  = parr[acp * 2 + 1];
1253:       const PetscInt *ppornt;

1255:       ppp = pp;
1256:       pp  = pcone[pcp];
1257:       PetscCall(DMPlexGetCellType(dm, pp, &pct));
1258:       // Restore the parent cone from the last iterate
1259:       if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, ppp, &pcone, NULL));
1260:       PetscCall(DMPlexGetOrientedCone(dm, pp, &pcone, NULL));
1261:       PetscCall(DMPlexGetOrientedCone(dm, ppp, NULL, &ppornt));
1262:       po = DMPolytopeTypeComposeOrientation(pct, ppornt[pcp], pco);
1263:       PetscCall(DMPlexRestoreOrientedCone(dm, ppp, NULL, &ppornt));
1264:     }
1265:     if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, pp, &pcone, NULL));
1266:     pr = rcone[coff++];
1267:     /* Orientation po of pp maps (pr, fo) -> (pr', fo') */
1268:     PetscCall(DMPlexTransformGetSubcellOrientation(tr, pct, pp, fn ? po : o, ft, pr, fo, &pr, &fo));
1269:     PetscCall(DMPlexTransformGetTargetPoint(tr, pct, ft, pp, pr, &coneNew[c]));
1270:     orntNew[c] = fo;
1271:   }
1272:   PetscCall(DMPlexRestoreOrientedCone(dm, p, &cone, NULL));
1273:   *coneoff = coff;
1274:   *orntoff = ooff;
1275:   PetscFunctionReturn(PETSC_SUCCESS);
1276: }

1278: static PetscErrorCode DMPlexTransformSetCones(DMPlexTransform tr, DM rdm)
1279: {
1280:   DM             dm;
1281:   DMPolytopeType ct;
1282:   PetscInt      *coneNew, *orntNew;
1283:   PetscInt       maxConeSize = 0, pStart, pEnd, p, pNew;

1285:   PetscFunctionBegin;
1286:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1287:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1288:   PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew));
1289:   PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew));
1290:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1291:   for (p = pStart; p < pEnd; ++p) {
1292:     PetscInt        coff, ooff;
1293:     DMPolytopeType *rct;
1294:     PetscInt       *rsize, *rcone, *rornt;
1295:     PetscInt        Nct, n, r;

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

1302:       for (r = 0; r < rsize[n]; ++r) {
1303:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1304:         PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, ctNew, rcone, &coff, rornt, &ooff, coneNew, orntNew));
1305:         PetscCall(DMPlexSetCone(rdm, pNew, coneNew));
1306:         PetscCall(DMPlexSetConeOrientation(rdm, pNew, orntNew));
1307:       }
1308:     }
1309:   }
1310:   PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew));
1311:   PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew));
1312:   PetscCall(DMViewFromOptions(rdm, NULL, "-rdm_view"));
1313:   PetscCall(DMPlexSymmetrize(rdm));
1314:   PetscCall(DMPlexStratify(rdm));
1315:   PetscFunctionReturn(PETSC_SUCCESS);
1316: }

1318: PetscErrorCode DMPlexTransformGetConeOriented(DMPlexTransform tr, PetscInt q, PetscInt po, const PetscInt *cone[], const PetscInt *ornt[])
1319: {
1320:   DM              dm;
1321:   DMPolytopeType  ct, qct;
1322:   DMPolytopeType *rct;
1323:   PetscInt       *rsize, *rcone, *rornt, *qcone, *qornt;
1324:   PetscInt        maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0;

1326:   PetscFunctionBegin;
1330:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1331:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1332:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1333:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1334:   PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r));
1335:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1336:   for (n = 0; n < Nct; ++n) {
1337:     const DMPolytopeType ctNew    = rct[n];
1338:     const PetscInt       csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1339:     PetscInt             Nr       = rsize[n], fn, c;

1341:     if (ctNew == qct) Nr = r;
1342:     for (nr = 0; nr < Nr; ++nr) {
1343:       for (c = 0; c < csizeNew; ++c) {
1344:         ++coff;             /* Cell type of new cone point */
1345:         fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */
1346:         coff += fn;
1347:         ++coff; /* Replica number of new cone point */
1348:         ++ooff; /* Orientation of new cone point */
1349:       }
1350:     }
1351:     if (ctNew == qct) break;
1352:   }
1353:   PetscCall(DMPlexTransformGetCone_Internal(tr, p, po, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt));
1354:   *cone = qcone;
1355:   *ornt = qornt;
1356:   PetscFunctionReturn(PETSC_SUCCESS);
1357: }

1359: PetscErrorCode DMPlexTransformGetCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[])
1360: {
1361:   DM              dm;
1362:   DMPolytopeType  ct, qct;
1363:   DMPolytopeType *rct;
1364:   PetscInt       *rsize, *rcone, *rornt, *qcone, *qornt;
1365:   PetscInt        maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0;

1367:   PetscFunctionBegin;
1371:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1372:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1373:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1374:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1375:   PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r));
1376:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1377:   for (n = 0; n < Nct; ++n) {
1378:     const DMPolytopeType ctNew    = rct[n];
1379:     const PetscInt       csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1380:     PetscInt             Nr       = rsize[n], fn, c;

1382:     if (ctNew == qct) Nr = r;
1383:     for (nr = 0; nr < Nr; ++nr) {
1384:       for (c = 0; c < csizeNew; ++c) {
1385:         ++coff;             /* Cell type of new cone point */
1386:         fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */
1387:         coff += fn;
1388:         ++coff; /* Replica number of new cone point */
1389:         ++ooff; /* Orientation of new cone point */
1390:       }
1391:     }
1392:     if (ctNew == qct) break;
1393:   }
1394:   PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt));
1395:   if (cone) *cone = qcone;
1396:   else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1397:   if (ornt) *ornt = qornt;
1398:   else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1399:   PetscFunctionReturn(PETSC_SUCCESS);
1400: }

1402: PetscErrorCode DMPlexTransformRestoreCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[])
1403: {
1404:   DM dm;

1406:   PetscFunctionBegin;
1408:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1409:   if (cone) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, cone));
1410:   if (ornt) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, ornt));
1411:   PetscFunctionReturn(PETSC_SUCCESS);
1412: }

1414: static PetscErrorCode DMPlexTransformCreateCellVertices_Internal(DMPlexTransform tr)
1415: {
1416:   PetscInt ict;

1418:   PetscFunctionBegin;
1419:   PetscCall(PetscCalloc3(DM_NUM_POLYTOPES, &tr->trNv, DM_NUM_POLYTOPES, &tr->trVerts, DM_NUM_POLYTOPES, &tr->trSubVerts));
1420:   for (ict = DM_POLYTOPE_POINT; ict < DM_NUM_POLYTOPES; ++ict) {
1421:     const DMPolytopeType ct = (DMPolytopeType)ict;
1422:     DMPlexTransform      reftr;
1423:     DM                   refdm, trdm;
1424:     Vec                  coordinates;
1425:     const PetscScalar   *coords;
1426:     DMPolytopeType      *rct;
1427:     PetscInt            *rsize, *rcone, *rornt;
1428:     PetscInt             Nct, n, r, pNew;
1429:     PetscInt             trdim, vStart, vEnd, Nc;
1430:     const PetscInt       debug = 0;
1431:     const char          *typeName;

1433:     /* Since points are 0-dimensional, coordinates make no sense */
1434:     if (DMPolytopeTypeGetDim(ct) <= 0) continue;
1435:     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, ct, &refdm));
1436:     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &reftr));
1437:     PetscCall(DMPlexTransformSetDM(reftr, refdm));
1438:     PetscCall(DMPlexTransformGetType(tr, &typeName));
1439:     PetscCall(DMPlexTransformSetType(reftr, typeName));
1440:     PetscCall(DMPlexTransformSetUp(reftr));
1441:     PetscCall(DMPlexTransformApply(reftr, refdm, &trdm));

1443:     PetscCall(DMGetDimension(trdm, &trdim));
1444:     PetscCall(DMPlexGetDepthStratum(trdm, 0, &vStart, &vEnd));
1445:     tr->trNv[ct] = vEnd - vStart;
1446:     PetscCall(DMGetCoordinatesLocal(trdm, &coordinates));
1447:     PetscCall(VecGetLocalSize(coordinates, &Nc));
1448:     PetscCheck(tr->trNv[ct] * trdim == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell type %s, transformed coordinate size %" PetscInt_FMT " != %" PetscInt_FMT " size of coordinate storage", DMPolytopeTypes[ct], tr->trNv[ct] * trdim, Nc);
1449:     PetscCall(PetscCalloc1(Nc, &tr->trVerts[ct]));
1450:     PetscCall(VecGetArrayRead(coordinates, &coords));
1451:     PetscCall(PetscArraycpy(tr->trVerts[ct], coords, Nc));
1452:     PetscCall(VecRestoreArrayRead(coordinates, &coords));

1454:     PetscCall(PetscCalloc1(DM_NUM_POLYTOPES, &tr->trSubVerts[ct]));
1455:     PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1456:     for (n = 0; n < Nct; ++n) {
1457:       /* Since points are 0-dimensional, coordinates make no sense */
1458:       if (rct[n] == DM_POLYTOPE_POINT) continue;
1459:       PetscCall(PetscCalloc1(rsize[n], &tr->trSubVerts[ct][rct[n]]));
1460:       for (r = 0; r < rsize[n]; ++r) {
1461:         PetscInt *closure = NULL;
1462:         PetscInt  clSize, cl, Nv = 0;

1464:         PetscCall(PetscCalloc1(DMPolytopeTypeGetNumVertices(rct[n]), &tr->trSubVerts[ct][rct[n]][r]));
1465:         PetscCall(DMPlexTransformGetTargetPoint(reftr, ct, rct[n], 0, r, &pNew));
1466:         PetscCall(DMPlexGetTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure));
1467:         for (cl = 0; cl < clSize * 2; cl += 2) {
1468:           const PetscInt sv = closure[cl];

1470:           if ((sv >= vStart) && (sv < vEnd)) tr->trSubVerts[ct][rct[n]][r][Nv++] = sv - vStart;
1471:         }
1472:         PetscCall(DMPlexRestoreTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure));
1473:         PetscCheck(Nv == DMPolytopeTypeGetNumVertices(rct[n]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of vertices %" PetscInt_FMT " != %" PetscInt_FMT " for %s subcell %" PetscInt_FMT " from cell %s", Nv, DMPolytopeTypeGetNumVertices(rct[n]), DMPolytopeTypes[rct[n]], r, DMPolytopeTypes[ct]);
1474:       }
1475:     }
1476:     if (debug) {
1477:       DMPolytopeType *rct;
1478:       PetscInt       *rsize, *rcone, *rornt;
1479:       PetscInt        v, dE = trdim, d, off = 0;

1481:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %" PetscInt_FMT " vertices\n", DMPolytopeTypes[ct], tr->trNv[ct]));
1482:       for (v = 0; v < tr->trNv[ct]; ++v) {
1483:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  "));
1484:         for (d = 0; d < dE; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g ", (double)PetscRealPart(tr->trVerts[ct][off++])));
1485:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1486:       }

1488:       PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1489:       for (n = 0; n < Nct; ++n) {
1490:         if (rct[n] == DM_POLYTOPE_POINT) continue;
1491:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %s subvertices %" PetscInt_FMT "\n", DMPolytopeTypes[ct], DMPolytopeTypes[rct[n]], tr->trNv[ct]));
1492:         for (r = 0; r < rsize[n]; ++r) {
1493:           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  "));
1494:           for (v = 0; v < DMPolytopeTypeGetNumVertices(rct[n]); ++v) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT " ", tr->trSubVerts[ct][rct[n]][r][v]));
1495:           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1496:         }
1497:       }
1498:     }
1499:     PetscCall(DMDestroy(&refdm));
1500:     PetscCall(DMDestroy(&trdm));
1501:     PetscCall(DMPlexTransformDestroy(&reftr));
1502:   }
1503:   PetscFunctionReturn(PETSC_SUCCESS);
1504: }

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

1509:   Input Parameters:
1510: + tr - The `DMPlexTransform` object
1511: - ct - The cell type

1513:   Output Parameters:
1514: + Nv      - The number of transformed vertices in the closure of the reference cell of given type
1515: - trVerts - The coordinates of these vertices in the reference cell

1517:   Level: developer

1519: .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSubcellVertices()`
1520: @*/
1521: PetscErrorCode DMPlexTransformGetCellVertices(DMPlexTransform tr, DMPolytopeType ct, PetscInt *Nv, PetscScalar *trVerts[])
1522: {
1523:   PetscFunctionBegin;
1524:   if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr));
1525:   if (Nv) *Nv = tr->trNv[ct];
1526:   if (trVerts) *trVerts = tr->trVerts[ct];
1527:   PetscFunctionReturn(PETSC_SUCCESS);
1528: }

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

1533:   Input Parameters:
1534: + tr  - The `DMPlexTransform` object
1535: . ct  - The cell type
1536: . rct - The subcell type
1537: - r   - The subcell index

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

1542:   Level: developer

1544: .seealso:  `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetCellVertices()`
1545: @*/
1546: PetscErrorCode DMPlexTransformGetSubcellVertices(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, PetscInt *subVerts[])
1547: {
1548:   PetscFunctionBegin;
1549:   if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr));
1550:   PetscCheck(tr->trSubVerts[ct][rct], PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_WRONG, "Cell type %s does not produce %s", DMPolytopeTypes[ct], DMPolytopeTypes[rct]);
1551:   if (subVerts) *subVerts = tr->trSubVerts[ct][rct][r];
1552:   PetscFunctionReturn(PETSC_SUCCESS);
1553: }

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

1560:   PetscFunctionBeginHot;
1561:   PetscCheck(ct == DM_POLYTOPE_POINT, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for refined point type %s", DMPolytopeTypes[ct]);
1562:   for (d = 0; d < dE; ++d) out[d] = 0.0;
1563:   for (v = 0; v < Nv; ++v)
1564:     for (d = 0; d < dE; ++d) out[d] += in[v * dE + d];
1565:   for (d = 0; d < dE; ++d) out[d] /= Nv;
1566:   PetscFunctionReturn(PETSC_SUCCESS);
1567: }

1569: /*@
1570:   DMPlexTransformMapCoordinates - Calculate new coordinates for produced points

1572:   Not collective

1574:   Input Parameters:
1575: + tr   - The `DMPlexTransform`
1576: . pct  - The cell type of the parent, from whom the new cell is being produced
1577: . ct   - The type being produced
1578: . p    - The original point
1579: . r    - The replica number requested for the produced cell type
1580: . Nv   - Number of vertices in the closure of the parent cell
1581: . dE   - Spatial dimension
1582: - in   - array of size Nv*dE, holding coordinates of the vertices in the closure of the parent cell

1584:   Output Parameter:
1585: . out - The coordinates of the new vertices

1587:   Level: intermediate

1589: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransform`, `DMPlexTransformApply()`
1590: @*/
1591: PetscErrorCode DMPlexTransformMapCoordinates(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[])
1592: {
1593:   PetscFunctionBeginHot;
1594:   if (Nv) PetscUseTypeMethod(tr, mapcoordinates, pct, ct, p, r, Nv, dE, in, out);
1595:   PetscFunctionReturn(PETSC_SUCCESS);
1596: }

1598: static PetscErrorCode RefineLabel_Internal(DMPlexTransform tr, DMLabel label, DMLabel labelNew)
1599: {
1600:   DM              dm;
1601:   IS              valueIS;
1602:   const PetscInt *values;
1603:   PetscInt        defVal, Nv, val;

1605:   PetscFunctionBegin;
1606:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1607:   PetscCall(DMLabelGetDefaultValue(label, &defVal));
1608:   PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
1609:   PetscCall(DMLabelGetValueIS(label, &valueIS));
1610:   PetscCall(ISGetLocalSize(valueIS, &Nv));
1611:   PetscCall(ISGetIndices(valueIS, &values));
1612:   for (val = 0; val < Nv; ++val) {
1613:     IS              pointIS;
1614:     const PetscInt *points;
1615:     PetscInt        numPoints, p;

1617:     /* Ensure refined label is created with same number of strata as
1618:      * original (even if no entries here). */
1619:     PetscCall(DMLabelAddStratum(labelNew, values[val]));
1620:     PetscCall(DMLabelGetStratumIS(label, values[val], &pointIS));
1621:     PetscCall(ISGetLocalSize(pointIS, &numPoints));
1622:     PetscCall(ISGetIndices(pointIS, &points));
1623:     for (p = 0; p < numPoints; ++p) {
1624:       const PetscInt  point = points[p];
1625:       DMPolytopeType  ct;
1626:       DMPolytopeType *rct;
1627:       PetscInt       *rsize, *rcone, *rornt;
1628:       PetscInt        Nct, n, r, pNew = 0;

1630:       PetscCall(DMPlexGetCellType(dm, point, &ct));
1631:       PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1632:       for (n = 0; n < Nct; ++n) {
1633:         for (r = 0; r < rsize[n]; ++r) {
1634:           PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], point, r, &pNew));
1635:           PetscCall(DMLabelSetValue(labelNew, pNew, values[val]));
1636:         }
1637:       }
1638:     }
1639:     PetscCall(ISRestoreIndices(pointIS, &points));
1640:     PetscCall(ISDestroy(&pointIS));
1641:   }
1642:   PetscCall(ISRestoreIndices(valueIS, &values));
1643:   PetscCall(ISDestroy(&valueIS));
1644:   PetscFunctionReturn(PETSC_SUCCESS);
1645: }

1647: static PetscErrorCode DMPlexTransformCreateLabels(DMPlexTransform tr, DM rdm)
1648: {
1649:   DM       dm;
1650:   PetscInt numLabels, l;

1652:   PetscFunctionBegin;
1653:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1654:   PetscCall(DMGetNumLabels(dm, &numLabels));
1655:   for (l = 0; l < numLabels; ++l) {
1656:     DMLabel     label, labelNew;
1657:     const char *lname;
1658:     PetscBool   isDepth, isCellType;

1660:     PetscCall(DMGetLabelName(dm, l, &lname));
1661:     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
1662:     if (isDepth) continue;
1663:     PetscCall(PetscStrcmp(lname, "celltype", &isCellType));
1664:     if (isCellType) continue;
1665:     PetscCall(DMCreateLabel(rdm, lname));
1666:     PetscCall(DMGetLabel(dm, lname, &label));
1667:     PetscCall(DMGetLabel(rdm, lname, &labelNew));
1668:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
1669:   }
1670:   PetscFunctionReturn(PETSC_SUCCESS);
1671: }

1673: /* This refines the labels which define regions for fields and DSes since they are not in the list of labels for the DM */
1674: PetscErrorCode DMPlexTransformCreateDiscLabels(DMPlexTransform tr, DM rdm)
1675: {
1676:   DM       dm;
1677:   PetscInt Nf, f, Nds, s;

1679:   PetscFunctionBegin;
1680:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1681:   PetscCall(DMGetNumFields(dm, &Nf));
1682:   for (f = 0; f < Nf; ++f) {
1683:     DMLabel     label, labelNew;
1684:     PetscObject obj;
1685:     const char *lname;

1687:     PetscCall(DMGetField(rdm, f, &label, &obj));
1688:     if (!label) continue;
1689:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
1690:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew));
1691:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
1692:     PetscCall(DMSetField_Internal(rdm, f, labelNew, obj));
1693:     PetscCall(DMLabelDestroy(&labelNew));
1694:   }
1695:   PetscCall(DMGetNumDS(dm, &Nds));
1696:   for (s = 0; s < Nds; ++s) {
1697:     DMLabel     label, labelNew;
1698:     const char *lname;

1700:     PetscCall(DMGetRegionNumDS(rdm, s, &label, NULL, NULL, NULL));
1701:     if (!label) continue;
1702:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
1703:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew));
1704:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
1705:     PetscCall(DMSetRegionNumDS(rdm, s, labelNew, NULL, NULL, NULL));
1706:     PetscCall(DMLabelDestroy(&labelNew));
1707:   }
1708:   PetscFunctionReturn(PETSC_SUCCESS);
1709: }

1711: static PetscErrorCode DMPlexTransformCreateSF(DMPlexTransform tr, DM rdm)
1712: {
1713:   DM                 dm;
1714:   PetscSF            sf, sfNew;
1715:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
1716:   const PetscInt    *localPoints;
1717:   const PetscSFNode *remotePoints;
1718:   PetscInt          *localPointsNew;
1719:   PetscSFNode       *remotePointsNew;
1720:   PetscInt           pStartNew, pEndNew, pNew;
1721:   /* Brute force algorithm */
1722:   PetscSF         rsf;
1723:   PetscSection    s;
1724:   const PetscInt *rootdegree;
1725:   PetscInt       *rootPointsNew, *remoteOffsets;
1726:   PetscInt        numPointsNew, pStart, pEnd, p;

1728:   PetscFunctionBegin;
1729:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1730:   PetscCall(DMPlexGetChart(rdm, &pStartNew, &pEndNew));
1731:   PetscCall(DMGetPointSF(dm, &sf));
1732:   PetscCall(DMGetPointSF(rdm, &sfNew));
1733:   /* Calculate size of new SF */
1734:   PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints));
1735:   if (numRoots < 0) PetscFunctionReturn(PETSC_SUCCESS);
1736:   for (l = 0; l < numLeaves; ++l) {
1737:     const PetscInt  p = localPoints[l];
1738:     DMPolytopeType  ct;
1739:     DMPolytopeType *rct;
1740:     PetscInt       *rsize, *rcone, *rornt;
1741:     PetscInt        Nct, n;

1743:     PetscCall(DMPlexGetCellType(dm, p, &ct));
1744:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1745:     for (n = 0; n < Nct; ++n) numLeavesNew += rsize[n];
1746:   }
1747:   /* Send new root point numbers
1748:        It is possible to optimize for regular transforms by sending only the cell type offsets, but it seems a needless complication
1749:   */
1750:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1751:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &s));
1752:   PetscCall(PetscSectionSetChart(s, pStart, pEnd));
1753:   for (p = pStart; p < pEnd; ++p) {
1754:     DMPolytopeType  ct;
1755:     DMPolytopeType *rct;
1756:     PetscInt       *rsize, *rcone, *rornt;
1757:     PetscInt        Nct, n;

1759:     PetscCall(DMPlexGetCellType(dm, p, &ct));
1760:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1761:     for (n = 0; n < Nct; ++n) PetscCall(PetscSectionAddDof(s, p, rsize[n]));
1762:   }
1763:   PetscCall(PetscSectionSetUp(s));
1764:   PetscCall(PetscSectionGetStorageSize(s, &numPointsNew));
1765:   PetscCall(PetscSFCreateRemoteOffsets(sf, s, s, &remoteOffsets));
1766:   PetscCall(PetscSFCreateSectionSF(sf, s, remoteOffsets, s, &rsf));
1767:   PetscCall(PetscFree(remoteOffsets));
1768:   PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree));
1769:   PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree));
1770:   PetscCall(PetscMalloc1(numPointsNew, &rootPointsNew));
1771:   for (p = 0; p < numPointsNew; ++p) rootPointsNew[p] = -1;
1772:   for (p = pStart; p < pEnd; ++p) {
1773:     DMPolytopeType  ct;
1774:     DMPolytopeType *rct;
1775:     PetscInt       *rsize, *rcone, *rornt;
1776:     PetscInt        Nct, n, r, off;

1778:     if (!rootdegree[p - pStart]) continue;
1779:     PetscCall(PetscSectionGetOffset(s, p, &off));
1780:     PetscCall(DMPlexGetCellType(dm, p, &ct));
1781:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1782:     for (n = 0, m = 0; n < Nct; ++n) {
1783:       for (r = 0; r < rsize[n]; ++r, ++m) {
1784:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1785:         rootPointsNew[off + m] = pNew;
1786:       }
1787:     }
1788:   }
1789:   PetscCall(PetscSFBcastBegin(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE));
1790:   PetscCall(PetscSFBcastEnd(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE));
1791:   PetscCall(PetscSFDestroy(&rsf));
1792:   PetscCall(PetscMalloc1(numLeavesNew, &localPointsNew));
1793:   PetscCall(PetscMalloc1(numLeavesNew, &remotePointsNew));
1794:   for (l = 0, m = 0; l < numLeaves; ++l) {
1795:     const PetscInt  p = localPoints[l];
1796:     DMPolytopeType  ct;
1797:     DMPolytopeType *rct;
1798:     PetscInt       *rsize, *rcone, *rornt;
1799:     PetscInt        Nct, n, r, q, off;

1801:     PetscCall(PetscSectionGetOffset(s, p, &off));
1802:     PetscCall(DMPlexGetCellType(dm, p, &ct));
1803:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1804:     for (n = 0, q = 0; n < Nct; ++n) {
1805:       for (r = 0; r < rsize[n]; ++r, ++m, ++q) {
1806:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1807:         localPointsNew[m]        = pNew;
1808:         remotePointsNew[m].index = rootPointsNew[off + q];
1809:         remotePointsNew[m].rank  = remotePoints[l].rank;
1810:       }
1811:     }
1812:   }
1813:   PetscCall(PetscSectionDestroy(&s));
1814:   PetscCall(PetscFree(rootPointsNew));
1815:   /* SF needs sorted leaves to correctly calculate Gather */
1816:   {
1817:     PetscSFNode *rp, *rtmp;
1818:     PetscInt    *lp, *idx, *ltmp, i;

1820:     PetscCall(PetscMalloc1(numLeavesNew, &idx));
1821:     PetscCall(PetscMalloc1(numLeavesNew, &lp));
1822:     PetscCall(PetscMalloc1(numLeavesNew, &rp));
1823:     for (i = 0; i < numLeavesNew; ++i) {
1824:       PetscCheck(!(localPointsNew[i] < pStartNew) && !(localPointsNew[i] >= pEndNew), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local SF point %" PetscInt_FMT " (%" PetscInt_FMT ") not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", localPointsNew[i], i, pStartNew, pEndNew);
1825:       idx[i] = i;
1826:     }
1827:     PetscCall(PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx));
1828:     for (i = 0; i < numLeavesNew; ++i) {
1829:       lp[i] = localPointsNew[idx[i]];
1830:       rp[i] = remotePointsNew[idx[i]];
1831:     }
1832:     ltmp            = localPointsNew;
1833:     localPointsNew  = lp;
1834:     rtmp            = remotePointsNew;
1835:     remotePointsNew = rp;
1836:     PetscCall(PetscFree(idx));
1837:     PetscCall(PetscFree(ltmp));
1838:     PetscCall(PetscFree(rtmp));
1839:   }
1840:   PetscCall(PetscSFSetGraph(sfNew, pEndNew - pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER));
1841:   PetscFunctionReturn(PETSC_SUCCESS);
1842: }

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

1847:   Not Collective

1849:   Input Parameters:
1850: + tr  - The `DMPlexTransform`
1851: . ct  - The type of the parent cell
1852: . rct - The type of the produced cell
1853: . r   - The index of the produced cell
1854: - x   - The localized coordinates for the parent cell

1856:   Output Parameter:
1857: . xr  - The localized coordinates for the produced cell

1859:   Level: developer

1861: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexCellRefinerSetCoordinates()`
1862: @*/
1863: static PetscErrorCode DMPlexTransformMapLocalizedCoordinates(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, const PetscScalar x[], PetscScalar xr[])
1864: {
1865:   PetscFE  fe = NULL;
1866:   PetscInt cdim, v, *subcellV;

1868:   PetscFunctionBegin;
1869:   PetscCall(DMPlexTransformGetCoordinateFE(tr, ct, &fe));
1870:   PetscCall(DMPlexTransformGetSubcellVertices(tr, ct, rct, r, &subcellV));
1871:   PetscCall(PetscFEGetNumComponents(fe, &cdim));
1872:   for (v = 0; v < DMPolytopeTypeGetNumVertices(rct); ++v) PetscCall(PetscFEInterpolate_Static(fe, x, tr->refGeom[ct], subcellV[v], &xr[v * cdim]));
1873:   PetscFunctionReturn(PETSC_SUCCESS);
1874: }

1876: static PetscErrorCode DMPlexTransformSetCoordinates(DMPlexTransform tr, DM rdm)
1877: {
1878:   DM                 dm, cdm, cdmCell, cdmNew, cdmCellNew;
1879:   PetscSection       coordSection, coordSectionNew, coordSectionCell, coordSectionCellNew;
1880:   Vec                coordsLocal, coordsLocalNew, coordsLocalCell = NULL, coordsLocalCellNew;
1881:   const PetscScalar *coords;
1882:   PetscScalar       *coordsNew;
1883:   const PetscReal   *maxCell, *Lstart, *L;
1884:   PetscBool          localized, localizeVertices = PETSC_FALSE, localizeCells = PETSC_FALSE;
1885:   PetscInt           dE, dEo, d, cStart, cEnd, c, cStartNew, cEndNew, vStartNew, vEndNew, v, pStart, pEnd, p;

1887:   PetscFunctionBegin;
1888:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1889:   PetscCall(DMGetCoordinateDM(dm, &cdm));
1890:   PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
1891:   PetscCall(DMGetCoordinatesLocalized(dm, &localized));
1892:   PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
1893:   if (localized) {
1894:     /* Localize coordinates of new vertices */
1895:     localizeVertices = PETSC_TRUE;
1896:     /* If we do not have a mechanism for automatically localizing cell coordinates, we need to compute them explicitly for every divided cell */
1897:     if (!maxCell) localizeCells = PETSC_TRUE;
1898:   }
1899:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
1900:   PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &dEo));
1901:   if (maxCell) {
1902:     PetscReal maxCellNew[3];

1904:     for (d = 0; d < dEo; ++d) maxCellNew[d] = maxCell[d] / 2.0;
1905:     PetscCall(DMSetPeriodicity(rdm, maxCellNew, Lstart, L));
1906:   }
1907:   PetscCall(DMGetCoordinateDim(rdm, &dE));
1908:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionNew));
1909:   PetscCall(PetscSectionSetNumFields(coordSectionNew, 1));
1910:   PetscCall(PetscSectionSetFieldComponents(coordSectionNew, 0, dE));
1911:   PetscCall(DMPlexGetDepthStratum(rdm, 0, &vStartNew, &vEndNew));
1912:   PetscCall(PetscSectionSetChart(coordSectionNew, vStartNew, vEndNew));
1913:   /* Localization should be inherited */
1914:   /*   Stefano calculates parent cells for each new cell for localization */
1915:   /*   Localized cells need coordinates of closure */
1916:   for (v = vStartNew; v < vEndNew; ++v) {
1917:     PetscCall(PetscSectionSetDof(coordSectionNew, v, dE));
1918:     PetscCall(PetscSectionSetFieldDof(coordSectionNew, v, 0, dE));
1919:   }
1920:   PetscCall(PetscSectionSetUp(coordSectionNew));
1921:   PetscCall(DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew));

1923:   if (localizeCells) {
1924:     PetscCall(DMGetCoordinateDM(rdm, &cdmNew));
1925:     PetscCall(DMClone(cdmNew, &cdmCellNew));
1926:     PetscCall(DMSetCellCoordinateDM(rdm, cdmCellNew));
1927:     PetscCall(DMDestroy(&cdmCellNew));

1929:     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionCellNew));
1930:     PetscCall(PetscSectionSetNumFields(coordSectionCellNew, 1));
1931:     PetscCall(PetscSectionSetFieldComponents(coordSectionCellNew, 0, dE));
1932:     PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStartNew, &cEndNew));
1933:     PetscCall(PetscSectionSetChart(coordSectionCellNew, cStartNew, cEndNew));

1935:     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
1936:     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1937:     for (c = cStart; c < cEnd; ++c) {
1938:       PetscInt dof;

1940:       PetscCall(PetscSectionGetDof(coordSectionCell, c, &dof));
1941:       if (dof) {
1942:         DMPolytopeType  ct;
1943:         DMPolytopeType *rct;
1944:         PetscInt       *rsize, *rcone, *rornt;
1945:         PetscInt        dim, cNew, Nct, n, r;

1947:         PetscCall(DMPlexGetCellType(dm, c, &ct));
1948:         dim = DMPolytopeTypeGetDim(ct);
1949:         PetscCall(DMPlexTransformCellTransform(tr, ct, c, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1950:         /* This allows for different cell types */
1951:         for (n = 0; n < Nct; ++n) {
1952:           if (dim != DMPolytopeTypeGetDim(rct[n])) continue;
1953:           for (r = 0; r < rsize[n]; ++r) {
1954:             PetscInt *closure = NULL;
1955:             PetscInt  clSize, cl, Nv = 0;

1957:             PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], c, r, &cNew));
1958:             PetscCall(DMPlexGetTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure));
1959:             for (cl = 0; cl < clSize * 2; cl += 2) {
1960:               if ((closure[cl] >= vStartNew) && (closure[cl] < vEndNew)) ++Nv;
1961:             }
1962:             PetscCall(DMPlexRestoreTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure));
1963:             PetscCall(PetscSectionSetDof(coordSectionCellNew, cNew, Nv * dE));
1964:             PetscCall(PetscSectionSetFieldDof(coordSectionCellNew, cNew, 0, Nv * dE));
1965:           }
1966:         }
1967:       }
1968:     }
1969:     PetscCall(PetscSectionSetUp(coordSectionCellNew));
1970:     PetscCall(DMSetCellCoordinateSection(rdm, PETSC_DETERMINE, coordSectionCellNew));
1971:   }
1972:   PetscCall(DMViewFromOptions(dm, NULL, "-coarse_dm_view"));
1973:   {
1974:     VecType     vtype;
1975:     PetscInt    coordSizeNew, bs;
1976:     const char *name;

1978:     PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
1979:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalNew));
1980:     PetscCall(PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew));
1981:     PetscCall(VecSetSizes(coordsLocalNew, coordSizeNew, PETSC_DETERMINE));
1982:     PetscCall(PetscObjectGetName((PetscObject)coordsLocal, &name));
1983:     PetscCall(PetscObjectSetName((PetscObject)coordsLocalNew, name));
1984:     PetscCall(VecGetBlockSize(coordsLocal, &bs));
1985:     PetscCall(VecSetBlockSize(coordsLocalNew, dEo == dE ? bs : dE));
1986:     PetscCall(VecGetType(coordsLocal, &vtype));
1987:     PetscCall(VecSetType(coordsLocalNew, vtype));
1988:   }
1989:   PetscCall(VecGetArrayRead(coordsLocal, &coords));
1990:   PetscCall(VecGetArray(coordsLocalNew, &coordsNew));
1991:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1992:   /* First set coordinates for vertices */
1993:   for (p = pStart; p < pEnd; ++p) {
1994:     DMPolytopeType  ct;
1995:     DMPolytopeType *rct;
1996:     PetscInt       *rsize, *rcone, *rornt;
1997:     PetscInt        Nct, n, r;
1998:     PetscBool       hasVertex = PETSC_FALSE;

2000:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2001:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2002:     for (n = 0; n < Nct; ++n) {
2003:       if (rct[n] == DM_POLYTOPE_POINT) {
2004:         hasVertex = PETSC_TRUE;
2005:         break;
2006:       }
2007:     }
2008:     if (hasVertex) {
2009:       const PetscScalar *icoords = NULL;
2010:       const PetscScalar *array   = NULL;
2011:       PetscScalar       *pcoords = NULL;
2012:       PetscBool          isDG;
2013:       PetscInt           Nc, Nv, v, d;

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

2017:       icoords = pcoords;
2018:       Nv      = Nc / dEo;
2019:       if (ct != DM_POLYTOPE_POINT) {
2020:         if (localizeVertices && maxCell) {
2021:           PetscScalar anchor[3];

2023:           for (d = 0; d < dEo; ++d) anchor[d] = pcoords[d];
2024:           for (v = 0; v < Nv; ++v) PetscCall(DMLocalizeCoordinate_Internal(dm, dEo, anchor, &pcoords[v * dEo], &pcoords[v * dEo]));
2025:         }
2026:       }
2027:       for (n = 0; n < Nct; ++n) {
2028:         if (rct[n] != DM_POLYTOPE_POINT) continue;
2029:         for (r = 0; r < rsize[n]; ++r) {
2030:           PetscScalar vcoords[3];
2031:           PetscInt    vNew, off;

2033:           PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &vNew));
2034:           PetscCall(PetscSectionGetOffset(coordSectionNew, vNew, &off));
2035:           PetscCall(DMPlexTransformMapCoordinates(tr, ct, rct[n], p, r, Nv, dEo, icoords, vcoords));
2036:           PetscCall(DMPlexSnapToGeomModel(dm, p, dE, vcoords, &coordsNew[off]));
2037:         }
2038:       }
2039:       PetscCall(DMPlexRestoreCellCoordinates(dm, p, &isDG, &Nc, &array, &pcoords));
2040:     }
2041:   }
2042:   PetscCall(VecRestoreArrayRead(coordsLocal, &coords));
2043:   PetscCall(VecRestoreArray(coordsLocalNew, &coordsNew));
2044:   PetscCall(DMSetCoordinatesLocal(rdm, coordsLocalNew));
2045:   PetscCall(VecDestroy(&coordsLocalNew));
2046:   PetscCall(PetscSectionDestroy(&coordSectionNew));
2047:   /* Then set coordinates for cells by localizing */
2048:   if (!localizeCells) PetscCall(DMLocalizeCoordinates(rdm));
2049:   else {
2050:     VecType     vtype;
2051:     PetscInt    coordSizeNew, bs;
2052:     const char *name;

2054:     PetscCall(DMGetCellCoordinatesLocal(dm, &coordsLocalCell));
2055:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalCellNew));
2056:     PetscCall(PetscSectionGetStorageSize(coordSectionCellNew, &coordSizeNew));
2057:     PetscCall(VecSetSizes(coordsLocalCellNew, coordSizeNew, PETSC_DETERMINE));
2058:     PetscCall(PetscObjectGetName((PetscObject)coordsLocalCell, &name));
2059:     PetscCall(PetscObjectSetName((PetscObject)coordsLocalCellNew, name));
2060:     PetscCall(VecGetBlockSize(coordsLocalCell, &bs));
2061:     PetscCall(VecSetBlockSize(coordsLocalCellNew, dEo == dE ? bs : dE));
2062:     PetscCall(VecGetType(coordsLocalCell, &vtype));
2063:     PetscCall(VecSetType(coordsLocalCellNew, vtype));
2064:     PetscCall(VecGetArrayRead(coordsLocalCell, &coords));
2065:     PetscCall(VecGetArray(coordsLocalCellNew, &coordsNew));

2067:     for (p = pStart; p < pEnd; ++p) {
2068:       DMPolytopeType  ct;
2069:       DMPolytopeType *rct;
2070:       PetscInt       *rsize, *rcone, *rornt;
2071:       PetscInt        dof = 0, Nct, n, r;

2073:       PetscCall(DMPlexGetCellType(dm, p, &ct));
2074:       PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2075:       if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
2076:       if (dof) {
2077:         const PetscScalar *pcoords;

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

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

2087:             /* It looks like Stefano and Lisandro are allowing localized coordinates without defining the periodic boundary, which means that
2088:                DMLocalizeCoordinate_Internal() will not work. Localized coordinates will have to have obtained by the affine map of the larger
2089:                cell to the ones it produces. */
2090:             PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
2091:             PetscCall(PetscSectionGetOffset(coordSectionCellNew, pNew, &offNew));
2092:             PetscCall(DMPlexTransformMapLocalizedCoordinates(tr, ct, rct[n], r, pcoords, &coordsNew[offNew]));
2093:           }
2094:         }
2095:       }
2096:     }
2097:     PetscCall(VecRestoreArrayRead(coordsLocalCell, &coords));
2098:     PetscCall(VecRestoreArray(coordsLocalCellNew, &coordsNew));
2099:     PetscCall(DMSetCellCoordinatesLocal(rdm, coordsLocalCellNew));
2100:     PetscCall(VecDestroy(&coordsLocalCellNew));
2101:     PetscCall(PetscSectionDestroy(&coordSectionCellNew));
2102:   }
2103:   PetscFunctionReturn(PETSC_SUCCESS);
2104: }

2106: PetscErrorCode DMPlexTransformApply(DMPlexTransform tr, DM dm, DM *tdm)
2107: {
2108:   DM                     rdm;
2109:   DMPlexInterpolatedFlag interp;
2110:   PetscInt               pStart, pEnd;

2112:   PetscFunctionBegin;
2116:   PetscCall(DMPlexTransformSetDM(tr, dm));

2118:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &rdm));
2119:   PetscCall(DMSetType(rdm, DMPLEX));
2120:   PetscCall(DMPlexTransformSetDimensions(tr, dm, rdm));
2121:   /* Calculate number of new points of each depth */
2122:   PetscCall(DMPlexIsInterpolatedCollective(dm, &interp));
2123:   PetscCheck(interp == DMPLEX_INTERPOLATED_FULL, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be fully interpolated for regular refinement");
2124:   /* Step 1: Set chart */
2125:   PetscCall(DMPlexTransformGetChart(tr, &pStart, &pEnd));
2126:   PetscCall(DMPlexSetChart(rdm, pStart, pEnd));
2127:   /* Step 2: Set cone/support sizes (automatically stratifies) */
2128:   PetscCall(DMPlexTransformSetConeSizes(tr, rdm));
2129:   /* Step 3: Setup refined DM */
2130:   PetscCall(DMSetUp(rdm));
2131:   /* Step 4: Set cones and supports (automatically symmetrizes) */
2132:   PetscCall(DMPlexTransformSetCones(tr, rdm));
2133:   /* Step 5: Create pointSF */
2134:   PetscCall(DMPlexTransformCreateSF(tr, rdm));
2135:   /* Step 6: Create labels */
2136:   PetscCall(DMPlexTransformCreateLabels(tr, rdm));
2137:   /* Step 7: Set coordinates */
2138:   PetscCall(DMPlexTransformSetCoordinates(tr, rdm));
2139:   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, rdm));
2140:   // If the original DM was configured from options, the transformed DM should be as well
2141:   rdm->setfromoptionscalled = dm->setfromoptionscalled;

2143:   *tdm = rdm;
2144:   PetscFunctionReturn(PETSC_SUCCESS);
2145: }

2147: PetscErrorCode DMPlexTransformAdaptLabel(DM dm, PETSC_UNUSED Vec metric, DMLabel adaptLabel, PETSC_UNUSED DMLabel rgLabel, DM *rdm)
2148: {
2149:   DMPlexTransform tr;
2150:   DM              cdm, rcdm;
2151:   const char     *prefix;

2153:   PetscFunctionBegin;
2154:   PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr));
2155:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
2156:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix));
2157:   PetscCall(DMPlexTransformSetDM(tr, dm));
2158:   PetscCall(DMPlexTransformSetFromOptions(tr));
2159:   PetscCall(DMPlexTransformSetActive(tr, adaptLabel));
2160:   PetscCall(DMPlexTransformSetUp(tr));
2161:   PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_transform_view"));
2162:   PetscCall(DMPlexTransformApply(tr, dm, rdm));
2163:   PetscCall(DMCopyDisc(dm, *rdm));
2164:   PetscCall(DMGetCoordinateDM(dm, &cdm));
2165:   PetscCall(DMGetCoordinateDM(*rdm, &rcdm));
2166:   PetscCall(DMCopyDisc(cdm, rcdm));
2167:   PetscCall(DMPlexTransformCreateDiscLabels(tr, *rdm));
2168:   PetscCall(DMCopyDisc(dm, *rdm));
2169:   PetscCall(DMPlexTransformDestroy(&tr));
2170:   ((DM_Plex *)(*rdm)->data)->useHashLocation = ((DM_Plex *)dm->data)->useHashLocation;
2171:   PetscFunctionReturn(PETSC_SUCCESS);
2172: }