Actual source code: plextransform.c

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

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

  6: PetscClassId DMPLEXTRANSFORM_CLASSID;

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

 11: PetscLogEvent DMPLEXTRANSFORM_SetUp, DMPLEXTRANSFORM_Apply, DMPLEXTRANSFORM_SetConeSizes, DMPLEXTRANSFORM_SetCones, DMPLEXTRANSFORM_CreateSF, DMPLEXTRANSFORM_CreateLabels, DMPLEXTRANSFORM_SetCoordinates, DMPLEXTRANSFORM_Check;

 13: /* Construct cell type order since we must loop over cell types in the same dimensional order they are stored in the plex if dm != NULL
 14:         OR in standard plex ordering if dm == NULL */
 15: static PetscErrorCode DMPlexCreateCellTypeOrder_Internal(DM dm, PetscInt dim, PetscInt *ctOrder[], PetscInt *ctOrderInv[])
 16: {
 17:   PetscInt *ctO, *ctOInv;
 18:   PetscInt  d, c, off = 0;
 19:   PetscInt  dimOrder[5] = {3, 2, 1, 0, -1};

 21:   PetscFunctionBegin;
 22:   PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctO, DM_NUM_POLYTOPES + 1, &ctOInv));
 23:   if (dm) { // Order the dimensions by their starting location
 24:     PetscInt hStart[4] = {-1, -1, -1, -1};
 25:     for (d = 0; d <= dim; ++d) PetscCall(DMPlexGetDepthStratum(dm, dim - d, &hStart[d], NULL));
 26:     PetscCall(PetscSortIntWithArray(dim + 1, hStart, &dimOrder[3 - dim]));
 27:   } else if (dim > 1) { // Standard plex ordering. dimOrder is in correct order if dim > 1
 28:     off             = 4 - dim;
 29:     dimOrder[off++] = 0;
 30:     for (d = dim - 1; d > 0; --d) dimOrder[off++] = d;
 31:   }

 33:   off = 0;
 34:   for (d = 0; d < 5; ++d) {
 35:     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
 36:       if (c == DM_POLYTOPE_UNKNOWN_CELL || c == DM_POLYTOPE_UNKNOWN_FACE) continue;
 37:       if (DMPolytopeTypeGetDim((DMPolytopeType)c) == dimOrder[d]) ctO[off++] = c;
 38:     }
 39:   }
 40:   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
 41:     if (c == DM_POLYTOPE_UNKNOWN_CELL || c == DM_POLYTOPE_UNKNOWN_FACE) ctO[off++] = c;
 42:   }
 43:   ctO[off++] = DM_NUM_POLYTOPES;
 44:   PetscCheck(off == DM_NUM_POLYTOPES + 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid offset %" PetscInt_FMT " for cell type order", off);

 46:   for (c = 0; c <= DM_NUM_POLYTOPES; ++c) ctOInv[ctO[c]] = c;

 48:   *ctOrder    = ctO;
 49:   *ctOrderInv = ctOInv;
 50:   PetscFunctionReturn(PETSC_SUCCESS);
 51: }

 53: /*@
 54:   DMPlexTransformRegister - Adds a new transform component implementation

 56:   Not Collective

 58:   Input Parameters:
 59: + name        - The name of a new user-defined creation routine
 60: - create_func - The creation routine

 62:   Example Usage:
 63: .vb
 64:   DMPlexTransformRegister("my_transform", MyTransformCreate);
 65: .ve

 67:   Then, your transform type can be chosen with the procedural interface via
 68: .vb
 69:   DMPlexTransformCreate(MPI_Comm, DMPlexTransform *);
 70:   DMPlexTransformSetType(DMPlexTransform, "my_transform");
 71: .ve
 72:   or at runtime via the option
 73: .vb
 74:   -dm_plex_transform_type my_transform
 75: .ve

 77:   Level: advanced

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

 82: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformRegisterAll()`, `DMPlexTransformRegisterDestroy()`
 83: @*/
 84: PetscErrorCode DMPlexTransformRegister(const char name[], PetscErrorCode (*create_func)(DMPlexTransform))
 85: {
 86:   PetscFunctionBegin;
 87:   PetscCall(DMInitializePackage());
 88:   PetscCall(PetscFunctionListAdd(&DMPlexTransformList, name, create_func));
 89:   PetscFunctionReturn(PETSC_SUCCESS);
 90: }

 92: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Filter(DMPlexTransform);
 93: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Regular(DMPlexTransform);
 94: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_ToBox(DMPlexTransform);
 95: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_ToSimplex(DMPlexTransform);
 96: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Alfeld(DMPlexTransform);
 97: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_SBR(DMPlexTransform);
 98: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_BL(DMPlexTransform);
 99: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_1D(DMPlexTransform);
100: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Extrude(DMPlexTransform);
101: PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Cohesive(DMPlexTransform);

103: /*@
104:   DMPlexTransformRegisterAll - Registers all of the transform components in the `DM` package.

106:   Not Collective

108:   Level: advanced

110: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransformType`, `DMRegisterAll()`, `DMPlexTransformRegisterDestroy()`
111: @*/
112: PetscErrorCode DMPlexTransformRegisterAll(void)
113: {
114:   PetscFunctionBegin;
115:   if (DMPlexTransformRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
116:   DMPlexTransformRegisterAllCalled = PETSC_TRUE;

118:   PetscCall(DMPlexTransformRegister(DMPLEXTRANSFORMFILTER, DMPlexTransformCreate_Filter));
119:   PetscCall(DMPlexTransformRegister(DMPLEXREFINEREGULAR, DMPlexTransformCreate_Regular));
120:   PetscCall(DMPlexTransformRegister(DMPLEXREFINETOBOX, DMPlexTransformCreate_ToBox));
121:   PetscCall(DMPlexTransformRegister(DMPLEXREFINETOSIMPLEX, DMPlexTransformCreate_ToSimplex));
122:   PetscCall(DMPlexTransformRegister(DMPLEXREFINEALFELD, DMPlexTransformCreate_Alfeld));
123:   PetscCall(DMPlexTransformRegister(DMPLEXREFINEBOUNDARYLAYER, DMPlexTransformCreate_BL));
124:   PetscCall(DMPlexTransformRegister(DMPLEXREFINESBR, DMPlexTransformCreate_SBR));
125:   PetscCall(DMPlexTransformRegister(DMPLEXREFINE1D, DMPlexTransformCreate_1D));
126:   PetscCall(DMPlexTransformRegister(DMPLEXEXTRUDETYPE, DMPlexTransformCreate_Extrude));
127:   PetscCall(DMPlexTransformRegister(DMPLEXCOHESIVEEXTRUDE, DMPlexTransformCreate_Cohesive));
128:   PetscFunctionReturn(PETSC_SUCCESS);
129: }

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

134:   Not collective

136:   Level: developer

138: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMRegisterAll()`, `DMPlexTransformType`, `PetscInitialize()`
139: @*/
140: PetscErrorCode DMPlexTransformRegisterDestroy(void)
141: {
142:   PetscFunctionBegin;
143:   PetscCall(PetscFunctionListDestroy(&DMPlexTransformList));
144:   DMPlexTransformRegisterAllCalled = PETSC_FALSE;
145:   PetscFunctionReturn(PETSC_SUCCESS);
146: }

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

151:   Collective

153:   Input Parameter:
154: . comm - The communicator for the transform object

156:   Output Parameter:
157: . tr - The transform object

159:   Level: beginner

161: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformSetType()`, `DMPLEXREFINEREGULAR`, `DMPLEXTRANSFORMFILTER`
162: @*/
163: PetscErrorCode DMPlexTransformCreate(MPI_Comm comm, DMPlexTransform *tr)
164: {
165:   DMPlexTransform t;

167:   PetscFunctionBegin;
168:   PetscAssertPointer(tr, 2);
169:   *tr = NULL;
170:   PetscCall(DMInitializePackage());

172:   PetscCall(PetscHeaderCreate(t, DMPLEXTRANSFORM_CLASSID, "DMPlexTransform", "Mesh Transform", "DMPlexTransform", comm, DMPlexTransformDestroy, DMPlexTransformView));
173:   t->setupcalled = PETSC_FALSE;
174:   t->redFactor   = 2.0;
175:   PetscCall(PetscCalloc2(DM_NUM_POLYTOPES, &t->coordFE, DM_NUM_POLYTOPES, &t->refGeom));
176:   *tr = t;
177:   PetscFunctionReturn(PETSC_SUCCESS);
178: }

180: /*@
181:   DMPlexTransformSetType - Sets the particular implementation for a transform.

183:   Collective

185:   Input Parameters:
186: + tr     - The transform
187: - method - The name of the transform type

189:   Options Database Key:
190: . -dm_plex_transform_type type - Sets the transform type; see `DMPlexTransformType`

192:   Level: intermediate

194: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformGetType()`, `DMPlexTransformCreate()`
195: @*/
196: PetscErrorCode DMPlexTransformSetType(DMPlexTransform tr, DMPlexTransformType method)
197: {
198:   PetscErrorCode (*r)(DMPlexTransform);
199:   PetscBool match;

201:   PetscFunctionBegin;
203:   PetscCall(PetscObjectTypeCompare((PetscObject)tr, method, &match));
204:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

206:   PetscCall(DMPlexTransformRegisterAll());
207:   PetscCall(PetscFunctionListFind(DMPlexTransformList, method, &r));
208:   PetscCheck(r, PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DMPlexTransform type: %s", method);

210:   PetscTryTypeMethod(tr, destroy);
211:   PetscCall(PetscMemzero(tr->ops, sizeof(*tr->ops)));
212:   PetscCall(PetscObjectChangeTypeName((PetscObject)tr, method));
213:   PetscCall((*r)(tr));
214:   PetscFunctionReturn(PETSC_SUCCESS);
215: }

217: /*@
218:   DMPlexTransformGetType - Gets the type name (as a string) from the transform.

220:   Not Collective

222:   Input Parameter:
223: . tr - The `DMPlexTransform`

225:   Output Parameter:
226: . type - The `DMPlexTransformType` name

228:   Level: intermediate

230: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformSetType()`, `DMPlexTransformCreate()`
231: @*/
232: PetscErrorCode DMPlexTransformGetType(DMPlexTransform tr, DMPlexTransformType *type)
233: {
234:   PetscFunctionBegin;
236:   PetscAssertPointer(type, 2);
237:   PetscCall(DMPlexTransformRegisterAll());
238:   *type = ((PetscObject)tr)->type_name;
239:   PetscFunctionReturn(PETSC_SUCCESS);
240: }

242: static PetscErrorCode DMPlexTransformView_Ascii(DMPlexTransform tr, PetscViewer v)
243: {
244:   PetscViewerFormat format;

246:   PetscFunctionBegin;
247:   PetscCall(PetscViewerGetFormat(v, &format));
248:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
249:     const PetscInt *trTypes = NULL;
250:     IS              trIS;
251:     PetscInt        cols = 8;
252:     PetscInt        Nrt  = 8, f, g;
253:     PetscMPIInt     size, rank;

255:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)tr), &rank));
256:     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)tr), &size));
257:     PetscCall(PetscViewerASCIIPushSynchronized(v));
258:     if (tr->trType) PetscCall(DMLabelView(tr->trType, v));
259:     if (size > 1) PetscCall(PetscViewerASCIISynchronizedPrintf(v, "Process: %d\n", rank));
260:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "Source Starts\n"));
261:     for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14s", DMPolytopeTypes[g]));
262:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "\n"));
263:     for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14" PetscInt_FMT, tr->ctStart[f]));
264:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "\n"));
265:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "Target Starts\n"));
266:     for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14s", DMPolytopeTypes[g]));
267:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "\n"));
268:     for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14" PetscInt_FMT, tr->ctStartNew[f]));
269:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "\n"));

271:     if (tr->trType) {
272:       PetscCall(DMLabelGetNumValues(tr->trType, &Nrt));
273:       PetscCall(DMLabelGetValueIS(tr->trType, &trIS));
274:       PetscCall(ISGetIndices(trIS, &trTypes));
275:     }
276:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "Offsets\n"));
277:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "     "));
278:     for (g = 0; g < cols; ++g) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14s", DMPolytopeTypes[g]));
279:     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "\n"));
280:     for (f = 0; f < Nrt; ++f) {
281:       PetscCall(PetscViewerASCIISynchronizedPrintf(v, "%2" PetscInt_FMT "  |", trTypes ? trTypes[f] : f));
282:       for (g = 0; g < cols; ++g) PetscCall(PetscViewerASCIISynchronizedPrintf(v, " %14" PetscInt_FMT, tr->offset[f * DM_NUM_POLYTOPES + g]));
283:       PetscCall(PetscViewerASCIISynchronizedPrintf(v, " |\n"));
284:     }
285:     if (tr->trType) {
286:       PetscCall(ISRestoreIndices(trIS, &trTypes));
287:       PetscCall(ISDestroy(&trIS));
288:     }
289:     PetscCall(PetscViewerFlush(v));
290:   }
291:   PetscFunctionReturn(PETSC_SUCCESS);
292: }

294: /*@
295:   DMPlexTransformView - Views a `DMPlexTransform`

297:   Collective

299:   Input Parameters:
300: + tr - the `DMPlexTransform` object to view
301: - v  - the viewer

303:   Level: beginner

305: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `PetscViewer`, `DMPlexTransformDestroy()`, `DMPlexTransformCreate()`
306: @*/
307: PetscErrorCode DMPlexTransformView(DMPlexTransform tr, PetscViewer v)
308: {
309:   PetscBool isascii;

311:   PetscFunctionBegin;
313:   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)tr), &v));
315:   PetscCheckSameComm(tr, 1, v, 2);
316:   PetscCall(PetscViewerCheckWritable(v));
317:   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)tr, v));
318:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &isascii));
319:   if (isascii) PetscCall(DMPlexTransformView_Ascii(tr, v));
320:   PetscTryTypeMethod(tr, view, v);
321:   PetscFunctionReturn(PETSC_SUCCESS);
322: }

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

327:   Collective

329:   Input Parameter:
330: . tr - the `DMPlexTransform` object to set options for

332:   Options Database Keys:
333: + -dm_plex_transform_type type               - Set the transform type, e.g. refine_regular
334: . -dm_plex_transform_label_match_strata      - Only label points of the same stratum as the producing point
335: . -dm_plex_transform_label_replica_inc inc   - Increment for the label value to be multiplied by the replica number, so that the new label value is oldValue + r * inc
336: . -dm_plex_transform_active name             - Name for active mesh label
337: - -dm_plex_transform_active_values v0,v1,... - Values in the active label

339:   Level: intermediate

341: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()`
342: @*/
343: PetscErrorCode DMPlexTransformSetFromOptions(DMPlexTransform tr)
344: {
345:   char        typeName[1024], active[PETSC_MAX_PATH_LEN];
346:   const char *defName = DMPLEXREFINEREGULAR;
347:   PetscBool   flg, match;

349:   PetscFunctionBegin;
351:   PetscObjectOptionsBegin((PetscObject)tr);
352:   PetscCall(PetscOptionsFList("-dm_plex_transform_type", "DMPlexTransform", "DMPlexTransformSetType", DMPlexTransformList, defName, typeName, sizeof(typeName), &flg));
353:   if (flg) PetscCall(DMPlexTransformSetType(tr, typeName));
354:   else if (!((PetscObject)tr)->type_name) PetscCall(DMPlexTransformSetType(tr, defName));
355:   PetscCall(PetscOptionsBool("-dm_plex_transform_label_match_strata", "Only label points of the same stratum as the producing point", "", tr->labelMatchStrata, &match, &flg));
356:   if (flg) PetscCall(DMPlexTransformSetMatchStrata(tr, match));
357:   PetscCall(PetscOptionsInt("-dm_plex_transform_label_replica_inc", "Increment for the label value to be multiplied by the replica number", "", tr->labelReplicaInc, &tr->labelReplicaInc, NULL));
358:   PetscCall(PetscOptionsString("-dm_plex_transform_active", "Name for active mesh label", "DMPlexTransformSetActive", active, active, sizeof(active), &flg));
359:   if (flg) {
360:     DM       dm;
361:     DMLabel  label;
362:     PetscInt values[16];
363:     PetscInt n = 16;

365:     PetscCall(DMPlexTransformGetDM(tr, &dm));
366:     PetscCall(DMGetLabel(dm, active, &label));
367:     PetscCall(PetscOptionsIntArray("-dm_plex_transform_active_values", "The label values to be active", "DMPlexTransformSetActive", values, &n, &flg));
368:     if (flg && n) {
369:       DMLabel newlabel;

371:       PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Active", &newlabel));
372:       for (PetscInt i = 0; i < n; ++i) {
373:         IS is;

375:         PetscCall(DMLabelGetStratumIS(label, values[i], &is));
376:         PetscCall(DMLabelInsertIS(newlabel, is, values[i]));
377:         PetscCall(ISDestroy(&is));
378:       }
379:       PetscCall(DMPlexTransformSetActive(tr, newlabel));
380:       PetscCall(DMLabelDestroy(&newlabel));
381:     } else {
382:       PetscCall(DMPlexTransformSetActive(tr, label));
383:     }
384:   }
385:   PetscTryTypeMethod(tr, setfromoptions, PetscOptionsObject);
386:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
387:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)tr, PetscOptionsObject));
388:   PetscOptionsEnd();
389:   PetscFunctionReturn(PETSC_SUCCESS);
390: }

392: /*@
393:   DMPlexTransformDestroy - Destroys a `DMPlexTransform`

395:   Collective

397:   Input Parameter:
398: . tr - the transform object to destroy

400:   Level: beginner

402: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()`
403: @*/
404: PetscErrorCode DMPlexTransformDestroy(DMPlexTransform *tr)
405: {
406:   PetscInt c;

408:   PetscFunctionBegin;
409:   if (!*tr) PetscFunctionReturn(PETSC_SUCCESS);
411:   if (--((PetscObject)*tr)->refct > 0) {
412:     *tr = NULL;
413:     PetscFunctionReturn(PETSC_SUCCESS);
414:   }

416:   PetscTryTypeMethod(*tr, destroy);
417:   PetscCall(DMDestroy(&(*tr)->dm));
418:   PetscCall(DMLabelDestroy(&(*tr)->active));
419:   PetscCall(DMLabelDestroy(&(*tr)->trType));
420:   PetscCall(PetscFree2((*tr)->ctOrderOld, (*tr)->ctOrderInvOld));
421:   PetscCall(PetscFree2((*tr)->ctOrderNew, (*tr)->ctOrderInvNew));
422:   PetscCall(PetscFree2((*tr)->ctStart, (*tr)->ctStartNew));
423:   PetscCall(PetscFree((*tr)->offset));
424:   PetscCall(PetscFree2((*tr)->depthStart, (*tr)->depthEnd));
425:   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
426:     PetscCall(PetscFEDestroy(&(*tr)->coordFE[c]));
427:     PetscCall(PetscFEGeomDestroy(&(*tr)->refGeom[c]));
428:   }
429:   if ((*tr)->trVerts) {
430:     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
431:       DMPolytopeType *rct;
432:       PetscInt       *rsize, *rcone, *rornt, Nct, n, r;

434:       if (DMPolytopeTypeGetDim((DMPolytopeType)c) > 0 && c != DM_POLYTOPE_UNKNOWN_CELL && c != DM_POLYTOPE_UNKNOWN_FACE) {
435:         PetscCall(DMPlexTransformCellTransform(*tr, (DMPolytopeType)c, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
436:         for (n = 0; n < Nct; ++n) {
437:           if (rct[n] == DM_POLYTOPE_POINT) continue;
438:           for (r = 0; r < rsize[n]; ++r) PetscCall(PetscFree((*tr)->trSubVerts[c][rct[n]][r]));
439:           PetscCall(PetscFree((*tr)->trSubVerts[c][rct[n]]));
440:         }
441:       }
442:       PetscCall(PetscFree((*tr)->trSubVerts[c]));
443:       PetscCall(PetscFree((*tr)->trVerts[c]));
444:     }
445:   }
446:   PetscCall(PetscFree3((*tr)->trNv, (*tr)->trVerts, (*tr)->trSubVerts));
447:   PetscCall(PetscFree2((*tr)->coordFE, (*tr)->refGeom));
448:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
449:   PetscCall(PetscHeaderDestroy(tr));
450:   PetscFunctionReturn(PETSC_SUCCESS);
451: }

453: static PetscErrorCode DMPlexTransformCreateOffset_Internal(DMPlexTransform tr, PetscInt ctOrderOld[], PetscInt ctStart[], PetscInt **offset)
454: {
455:   DMLabel  trType = tr->trType;
456:   PetscInt c, cN, *off;

458:   PetscFunctionBegin;
459:   if (trType) {
460:     DM              dm;
461:     IS              rtIS;
462:     const PetscInt *reftypes;
463:     PetscInt        Nrt;

465:     PetscCall(DMPlexTransformGetDM(tr, &dm));
466:     PetscCall(DMLabelGetNumValues(trType, &Nrt));
467:     PetscCall(DMLabelGetValueIS(trType, &rtIS));
468:     PetscCall(ISGetIndices(rtIS, &reftypes));
469:     PetscCall(PetscCalloc1(Nrt * DM_NUM_POLYTOPES, &off));
470:     for (PetscInt r = 0; r < Nrt; ++r) {
471:       const PetscInt  rt = reftypes[r];
472:       IS              rtIS;
473:       const PetscInt *points;
474:       DMPolytopeType  ct;
475:       PetscInt        np, p;

477:       PetscCall(DMLabelGetStratumIS(trType, rt, &rtIS));
478:       PetscCall(ISGetLocalSize(rtIS, &np));
479:       PetscCall(ISGetIndices(rtIS, &points));
480:       if (!np) continue;
481:       p = points[0];
482:       PetscCall(ISRestoreIndices(rtIS, &points));
483:       PetscCall(ISDestroy(&rtIS));
484:       PetscCall(DMPlexGetCellType(dm, p, &ct));
485:       for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) {
486:         const DMPolytopeType ctNew = (DMPolytopeType)cN;
487:         DMPolytopeType      *rct;
488:         PetscInt            *rsize, *cone, *ornt;
489:         PetscInt             Nct, n, s;

491:         if (DMPolytopeTypeGetDim(ct) < 0 || DMPolytopeTypeGetDim(ctNew) < 0) {
492:           off[r * DM_NUM_POLYTOPES + ctNew] = -1;
493:           break;
494:         }
495:         off[r * DM_NUM_POLYTOPES + ctNew] = 0;
496:         for (s = 0; s <= r; ++s) {
497:           const PetscInt st = reftypes[s];
498:           DMPolytopeType sct;
499:           PetscInt       q, qrt;

501:           PetscCall(DMLabelGetStratumIS(trType, st, &rtIS));
502:           PetscCall(ISGetLocalSize(rtIS, &np));
503:           PetscCall(ISGetIndices(rtIS, &points));
504:           if (!np) continue;
505:           q = points[0];
506:           PetscCall(ISRestoreIndices(rtIS, &points));
507:           PetscCall(ISDestroy(&rtIS));
508:           PetscCall(DMPlexGetCellType(dm, q, &sct));
509:           PetscCall(DMPlexTransformCellTransform(tr, sct, q, &qrt, &Nct, &rct, &rsize, &cone, &ornt));
510:           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);
511:           if (st == rt) {
512:             for (n = 0; n < Nct; ++n)
513:               if (rct[n] == ctNew) break;
514:             if (n == Nct) off[r * DM_NUM_POLYTOPES + ctNew] = -1;
515:             break;
516:           }
517:           for (n = 0; n < Nct; ++n) {
518:             if (rct[n] == ctNew) {
519:               PetscInt sn;

521:               PetscCall(DMLabelGetStratumSize(trType, st, &sn));
522:               off[r * DM_NUM_POLYTOPES + ctNew] += sn * rsize[n];
523:             }
524:           }
525:         }
526:       }
527:     }
528:     PetscCall(ISRestoreIndices(rtIS, &reftypes));
529:     PetscCall(ISDestroy(&rtIS));
530:   } else {
531:     PetscCall(PetscCalloc1(DM_NUM_POLYTOPES * DM_NUM_POLYTOPES, &off));
532:     for (c = DM_POLYTOPE_POINT; c < DM_NUM_POLYTOPES; ++c) {
533:       const DMPolytopeType ct = (DMPolytopeType)c;
534:       for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) {
535:         const DMPolytopeType ctNew = (DMPolytopeType)cN;
536:         DMPolytopeType      *rct;
537:         PetscInt            *rsize, *cone, *ornt;
538:         PetscInt             Nct, n, i;

540:         if (DMPolytopeTypeGetDim(ct) < 0 || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE || DMPolytopeTypeGetDim(ctNew) < 0 || ctNew == DM_POLYTOPE_UNKNOWN_CELL || ctNew == DM_POLYTOPE_UNKNOWN_FACE) {
541:           off[ct * DM_NUM_POLYTOPES + ctNew] = -1;
542:           continue;
543:         }
544:         off[ct * DM_NUM_POLYTOPES + ctNew] = 0;
545:         for (i = DM_POLYTOPE_POINT; i < DM_NUM_POLYTOPES; ++i) {
546:           const DMPolytopeType ict  = (DMPolytopeType)ctOrderOld[i];
547:           const DMPolytopeType ictn = (DMPolytopeType)ctOrderOld[i + 1];

549:           PetscCall(DMPlexTransformCellTransform(tr, ict, PETSC_DETERMINE, NULL, &Nct, &rct, &rsize, &cone, &ornt));
550:           if (ict == ct) {
551:             for (n = 0; n < Nct; ++n)
552:               if (rct[n] == ctNew) break;
553:             if (n == Nct) off[ct * DM_NUM_POLYTOPES + ctNew] = -1;
554:             break;
555:           }
556:           for (n = 0; n < Nct; ++n)
557:             if (rct[n] == ctNew) off[ct * DM_NUM_POLYTOPES + ctNew] += (ctStart[ictn] - ctStart[ict]) * rsize[n];
558:         }
559:       }
560:     }
561:   }
562:   *offset = off;
563:   PetscFunctionReturn(PETSC_SUCCESS);
564: }

566: /*@
567:   DMPlexTransformSetUp - Create the tables that drive the transform

569:   Input Parameter:
570: . tr - The `DMPlexTransform` object

572:   Level: intermediate

574: .seealso: [](plex_transform_table), [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
575: @*/
576: PetscErrorCode DMPlexTransformSetUp(DMPlexTransform tr)
577: {
578:   DMPolytopeType ctCell;
579:   DM             dm;
580:   PetscInt       pStart, pEnd, p, c, celldim = 0;

582:   PetscFunctionBegin;
584:   if (tr->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
585:   PetscCall(DMPlexTransformGetDM(tr, &dm));
586:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetUp, tr, dm, 0, 0));
587:   PetscTryTypeMethod(tr, setup);
588:   PetscCall(DMSetSnapToGeomModel(dm, NULL));
589:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));

591:   if (pEnd > pStart) {
592:     // Ignore cells hanging off of embedded surfaces
593:     PetscInt c = pStart;

595:     ctCell = DM_POLYTOPE_FV_GHOST;
596:     while (DMPolytopeTypeGetDim(ctCell) < 0) PetscCall(DMPlexGetCellType(dm, c++, &ctCell));
597:   } else {
598:     PetscInt dim;

600:     PetscCall(DMGetDimension(dm, &dim));
601:     switch (dim) {
602:     case 0:
603:       ctCell = DM_POLYTOPE_POINT;
604:       break;
605:     case 1:
606:       ctCell = DM_POLYTOPE_SEGMENT;
607:       break;
608:     case 2:
609:       ctCell = DM_POLYTOPE_TRIANGLE;
610:       break;
611:     case 3:
612:       ctCell = DM_POLYTOPE_TETRAHEDRON;
613:       break;
614:     default:
615:       ctCell = DM_POLYTOPE_UNKNOWN;
616:     }
617:   }
618:   PetscCall(DMPlexCreateCellTypeOrder_Internal(dm, DMPolytopeTypeGetDim(ctCell), &tr->ctOrderOld, &tr->ctOrderInvOld));
619:   for (p = pStart; p < pEnd; ++p) {
620:     DMPolytopeType  ct;
621:     DMPolytopeType *rct;
622:     PetscInt       *rsize, *cone, *ornt;
623:     PetscInt        Nct;

625:     PetscCall(DMPlexGetCellType(dm, p, &ct));
626:     PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell type for point %" PetscInt_FMT, p);
627:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt));
628:     for (PetscInt n = 0; n < Nct; ++n) celldim = PetscMax(celldim, DMPolytopeTypeGetDim(rct[n]));
629:   }
630:   PetscCall(DMPlexCreateCellTypeOrder_Internal(NULL, celldim, &tr->ctOrderNew, &tr->ctOrderInvNew));
631:   /* Construct sizes and offsets for each cell type */
632:   if (!tr->ctStart) {
633:     PetscInt *ctS, *ctSN, *ctC, *ctCN;

635:     PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctS, DM_NUM_POLYTOPES + 1, &ctSN));
636:     PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctC, DM_NUM_POLYTOPES + 1, &ctCN));
637:     for (p = pStart; p < pEnd; ++p) {
638:       DMPolytopeType  ct;
639:       DMPolytopeType *rct;
640:       PetscInt       *rsize, *cone, *ornt;
641:       PetscInt        Nct;

643:       PetscCall(DMPlexGetCellType(dm, p, &ct));
644:       PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell type for point %" PetscInt_FMT, p);
645:       ++ctC[ct];
646:       PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt));
647:       for (PetscInt n = 0; n < Nct; ++n) ctCN[rct[n]] += rsize[n];
648:     }
649:     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
650:       const PetscInt cto  = tr->ctOrderOld[c];
651:       const PetscInt cton = tr->ctOrderOld[c + 1];
652:       const PetscInt ctn  = tr->ctOrderNew[c];
653:       const PetscInt ctnn = tr->ctOrderNew[c + 1];

655:       ctS[cton]  = ctS[cto] + ctC[cto];
656:       ctSN[ctnn] = ctSN[ctn] + ctCN[ctn];
657:     }
658:     PetscCall(PetscFree2(ctC, ctCN));
659:     tr->ctStart    = ctS;
660:     tr->ctStartNew = ctSN;
661:   }
662:   PetscCall(DMPlexTransformCreateOffset_Internal(tr, tr->ctOrderOld, tr->ctStart, &tr->offset));
663:   // Compute depth information
664:   tr->depth = -1;
665:   for (c = 0; c < DM_NUM_POLYTOPES; ++c)
666:     if (tr->ctStartNew[tr->ctOrderNew[c + 1]] > tr->ctStartNew[tr->ctOrderNew[c]]) tr->depth = PetscMax(tr->depth, DMPolytopeTypeGetDim((DMPolytopeType)tr->ctOrderNew[c]));
667:   PetscCall(PetscMalloc2(tr->depth + 1, &tr->depthStart, tr->depth + 1, &tr->depthEnd));
668:   for (PetscInt d = 0; d <= tr->depth; ++d) {
669:     tr->depthStart[d] = PETSC_INT_MAX;
670:     tr->depthEnd[d]   = -1;
671:   }
672:   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
673:     const PetscInt dep = DMPolytopeTypeGetDim((DMPolytopeType)tr->ctOrderNew[c]);

675:     if (tr->ctStartNew[tr->ctOrderNew[c + 1]] <= tr->ctStartNew[tr->ctOrderNew[c]]) continue;
676:     tr->depthStart[dep] = PetscMin(tr->depthStart[dep], tr->ctStartNew[tr->ctOrderNew[c]]);
677:     tr->depthEnd[dep]   = PetscMax(tr->depthEnd[dep], tr->ctStartNew[tr->ctOrderNew[c + 1]]);
678:   }
679:   tr->setupcalled = PETSC_TRUE;
680:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetUp, tr, dm, 0, 0));
681:   PetscFunctionReturn(PETSC_SUCCESS);
682: }

684: /*@
685:   DMPlexTransformGetDM - Get the base `DM` for the transform

687:   Input Parameter:
688: . tr - The `DMPlexTransform` object

690:   Output Parameter:
691: . dm - The original `DM` which will be transformed

693:   Level: intermediate

695: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetDM()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
696: @*/
697: PetscErrorCode DMPlexTransformGetDM(DMPlexTransform tr, DM *dm)
698: {
699:   PetscFunctionBegin;
701:   PetscAssertPointer(dm, 2);
702:   *dm = tr->dm;
703:   PetscFunctionReturn(PETSC_SUCCESS);
704: }

706: /*@
707:   DMPlexTransformSetDM - Set the base `DM` for the transform

709:   Input Parameters:
710: + tr - The `DMPlexTransform` object
711: - dm - The original `DM` which will be transformed

713:   Level: intermediate

715:   Note:
716:   The user does not typically call this, as it is called by `DMPlexTransformApply()`.

718: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetDM()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
719: @*/
720: PetscErrorCode DMPlexTransformSetDM(DMPlexTransform tr, DM dm)
721: {
722:   PetscFunctionBegin;
724:   if (dm) {
726:     PetscCall(PetscObjectReference((PetscObject)dm));
727:   }
728:   PetscCall(DMDestroy(&tr->dm));
729:   tr->dm = dm;
730:   PetscFunctionReturn(PETSC_SUCCESS);
731: }

733: /*@
734:   DMPlexTransformGetActive - Get the `DMLabel` marking the active points for the transform

736:   Input Parameter:
737: . tr - The `DMPlexTransform` object

739:   Output Parameter:
740: . active - The `DMLabel` indicating which points will be transformed

742:   Level: intermediate

744: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
745: @*/
746: PetscErrorCode DMPlexTransformGetActive(DMPlexTransform tr, DMLabel *active)
747: {
748:   PetscFunctionBegin;
750:   PetscAssertPointer(active, 2);
751:   *active = tr->active;
752:   PetscFunctionReturn(PETSC_SUCCESS);
753: }

755: /*@
756:   DMPlexTransformSetActive - Set the `DMLabel` marking the active points for the transform

758:   Input Parameters:
759: + tr     - The `DMPlexTransform` object
760: - active - The `DMLabel` indicating which points will be transformed

762:   Level: intermediate

764:   Note:
765:   This only applies to transforms listed in [](plex_transform_table) that operate on a subset of the mesh.

767: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
768: @*/
769: PetscErrorCode DMPlexTransformSetActive(DMPlexTransform tr, DMLabel active)
770: {
771:   PetscFunctionBegin;
774:   PetscCall(PetscObjectReference((PetscObject)active));
775:   PetscCall(DMLabelDestroy(&tr->active));
776:   tr->active = active;
777:   PetscFunctionReturn(PETSC_SUCCESS);
778: }

780: /*@
781:   DMPlexTransformGetTransformTypes - Get the `DMLabel` marking the transform type of each point for the transform

783:   Input Parameter:
784: . tr - The `DMPlexTransform` object

786:   Output Parameter:
787: . trType - The `DMLabel` indicating the transform type for each point

789:   Level: intermediate

791: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexSetTransformType()`, `DMPlexTransformGetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
792: @*/
793: PetscErrorCode DMPlexTransformGetTransformTypes(DMPlexTransform tr, DMLabel *trType)
794: {
795:   PetscFunctionBegin;
797:   PetscAssertPointer(trType, 2);
798:   *trType = tr->trType;
799:   PetscFunctionReturn(PETSC_SUCCESS);
800: }

802: /*@
803:   DMPlexTransformSetTransformTypes - Set the `DMLabel` marking the transform type of each point for the transform

805:   Input Parameters:
806: + tr     - The `DMPlexTransform` object
807: - trType - The original `DM` which will be transformed

809:   Level: intermediate

811: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetTransformTypes()`, `DMPlexTransformGetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
812: @*/
813: PetscErrorCode DMPlexTransformSetTransformTypes(DMPlexTransform tr, DMLabel trType)
814: {
815:   PetscFunctionBegin;
818:   PetscCall(PetscObjectReference((PetscObject)trType));
819:   PetscCall(DMLabelDestroy(&tr->trType));
820:   tr->trType = trType;
821:   PetscFunctionReturn(PETSC_SUCCESS);
822: }

824: static PetscErrorCode DMPlexTransformGetCoordinateFE(DMPlexTransform tr, DMPolytopeType ct, PetscFE *fe)
825: {
826:   PetscFunctionBegin;
827:   if (!tr->coordFE[ct]) {
828:     PetscInt dim, cdim;

830:     dim = DMPolytopeTypeGetDim(ct);
831:     PetscCall(DMGetCoordinateDim(tr->dm, &cdim));
832:     PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, cdim, ct, 1, PETSC_DETERMINE, &tr->coordFE[ct]));
833:     {
834:       PetscDualSpace  dsp;
835:       PetscQuadrature quad;
836:       DM              K;
837:       PetscFEGeom    *cg;
838:       PetscScalar    *Xq;
839:       PetscReal      *xq, *wq;
840:       PetscInt        Nq;

842:       PetscCall(DMPlexTransformGetCellVertices(tr, ct, &Nq, &Xq));
843:       PetscCall(PetscMalloc1(Nq * cdim, &xq));
844:       for (PetscInt q = 0; q < Nq * cdim; ++q) xq[q] = PetscRealPart(Xq[q]);
845:       PetscCall(PetscMalloc1(Nq, &wq));
846:       for (PetscInt q = 0; q < Nq; ++q) wq[q] = 1.0;
847:       PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
848:       PetscCall(PetscQuadratureSetData(quad, dim, 1, Nq, xq, wq));
849:       PetscCall(PetscFESetQuadrature(tr->coordFE[ct], quad));

851:       PetscCall(PetscFEGetDualSpace(tr->coordFE[ct], &dsp));
852:       PetscCall(PetscDualSpaceGetDM(dsp, &K));
853:       PetscCall(PetscFEGeomCreate(quad, 1, cdim, PETSC_FEGEOM_BASIC, &tr->refGeom[ct]));
854:       cg = tr->refGeom[ct];
855:       PetscCall(DMPlexComputeCellGeometryFEM(K, 0, NULL, cg->v, cg->J, cg->invJ, cg->detJ));
856:       PetscCall(PetscQuadratureDestroy(&quad));
857:     }
858:   }
859:   *fe = tr->coordFE[ct];
860:   PetscFunctionReturn(PETSC_SUCCESS);
861: }

863: PetscErrorCode DMPlexTransformSetDimensions_Internal(DMPlexTransform tr, DM dm, DM tdm)
864: {
865:   PetscInt dim, cdim;

867:   PetscFunctionBegin;
868:   PetscCall(DMGetDimension(dm, &dim));
869:   PetscCall(DMSetDimension(tdm, dim));
870:   PetscCall(DMGetCoordinateDim(dm, &cdim));
871:   PetscCall(DMSetCoordinateDim(tdm, cdim));
872:   PetscFunctionReturn(PETSC_SUCCESS);
873: }

875: /*@
876:   DMPlexTransformSetDimensions - Set the dimensions for the transformed `DM`

878:   Input Parameters:
879: + tr - The `DMPlexTransform` object
880: - dm - The original `DM`

882:   Output Parameter:
883: . trdm - The transformed `DM`

885:   Level: advanced

887: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
888: @*/
889: PetscErrorCode DMPlexTransformSetDimensions(DMPlexTransform tr, DM dm, DM trdm)
890: {
891:   PetscFunctionBegin;
892:   PetscUseTypeMethod(tr, setdimensions, dm, trdm);
893:   PetscFunctionReturn(PETSC_SUCCESS);
894: }

896: /*@
897:   DMPlexTransformGetChart - Get the chart `[pStart, pEnd)` for the points produced by the transform

899:   Not Collective

901:   Input Parameter:
902: . tr - The `DMPlexTransform`

904:   Output Parameters:
905: + pStart - The first point in the transformed mesh, or `NULL` if not needed
906: - pEnd   - One past the last point in the transformed mesh, or `NULL` if not needed

908:   Level: developer

910: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformGetCellType()`, `DMPlexTransformGetCellTypeStratum()`
911: @*/
912: PetscErrorCode DMPlexTransformGetChart(DMPlexTransform tr, PetscInt *pStart, PetscInt *pEnd)
913: {
914:   PetscFunctionBegin;
915:   if (pStart) *pStart = 0;
916:   if (pEnd) *pEnd = tr->ctStartNew[tr->ctOrderNew[DM_NUM_POLYTOPES]];
917:   PetscFunctionReturn(PETSC_SUCCESS);
918: }

920: /*@
921:   DMPlexTransformGetCellType - Return the cell type for a point in the transformed mesh

923:   Not Collective

925:   Input Parameters:
926: + tr   - The `DMPlexTransform`
927: - cell - The point number in the transformed mesh

929:   Output Parameter:
930: . celltype - The `DMPolytopeType` of the point

932:   Level: developer

934: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetChart()`, `DMPlexTransformGetCellTypeStratum()`
935: @*/
936: PetscErrorCode DMPlexTransformGetCellType(DMPlexTransform tr, PetscInt cell, DMPolytopeType *celltype)
937: {
938:   PetscInt ctNew;

940:   PetscFunctionBegin;
942:   PetscAssertPointer(celltype, 3);
943:   /* TODO Can do bisection since everything is sorted */
944:   for (ctNew = DM_POLYTOPE_POINT; ctNew < DM_NUM_POLYTOPES; ++ctNew) {
945:     PetscInt ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]];

947:     if (cell >= ctSN && cell < ctEN) break;
948:   }
949:   PetscCheck(ctNew < DM_NUM_POLYTOPES, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " cannot be located in the transformed mesh", cell);
950:   *celltype = (DMPolytopeType)ctNew;
951:   PetscFunctionReturn(PETSC_SUCCESS);
952: }

954: /*@
955:   DMPlexTransformGetCellTypeStratum - Return the point range for a given cell type in the transformed mesh

957:   Not Collective

959:   Input Parameters:
960: + tr       - The `DMPlexTransform`
961: - celltype - The `DMPolytopeType` of the requested stratum

963:   Output Parameters:
964: + start - The first point of the stratum, or `NULL` if not needed
965: - end   - One past the last point of the stratum, or `NULL` if not needed

967:   Level: developer

969: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetCellType()`, `DMPlexTransformGetChart()`, `DMPlexGetDepthStratum()`
970: @*/
971: PetscErrorCode DMPlexTransformGetCellTypeStratum(DMPlexTransform tr, DMPolytopeType celltype, PetscInt *start, PetscInt *end)
972: {
973:   PetscFunctionBegin;
975:   if (start) *start = tr->ctStartNew[celltype];
976:   if (end) *end = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[celltype] + 1]];
977:   PetscFunctionReturn(PETSC_SUCCESS);
978: }

980: /*@
981:   DMPlexTransformGetDepth - Return the topological depth of the transformed mesh

983:   Not Collective

985:   Input Parameter:
986: . tr - The `DMPlexTransform`

988:   Output Parameter:
989: . depth - The depth of the transformed mesh

991:   Level: developer

993: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetDepthStratum()`, `DMPlexGetDepth()`
994: @*/
995: PetscErrorCode DMPlexTransformGetDepth(DMPlexTransform tr, PetscInt *depth)
996: {
997:   PetscFunctionBegin;
999:   *depth = tr->depth;
1000:   PetscFunctionReturn(PETSC_SUCCESS);
1001: }

1003: /*@
1004:   DMPlexTransformGetDepthStratum - Return the point range for a given depth in the transformed mesh

1006:   Not Collective

1008:   Input Parameters:
1009: + tr    - The `DMPlexTransform`
1010: - depth - The requested depth in the transformed mesh

1012:   Output Parameters:
1013: + start - The first point at the given depth, or `NULL` if not needed
1014: - end   - One past the last point at the given depth, or `NULL` if not needed

1016:   Level: developer

1018: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetDepth()`, `DMPlexGetDepthStratum()`
1019: @*/
1020: PetscErrorCode DMPlexTransformGetDepthStratum(DMPlexTransform tr, PetscInt depth, PetscInt *start, PetscInt *end)
1021: {
1022:   PetscFunctionBegin;
1024:   if (start) *start = tr->depthStart[depth];
1025:   if (end) *end = tr->depthEnd[depth];
1026:   PetscFunctionReturn(PETSC_SUCCESS);
1027: }

1029: /*@
1030:   DMPlexTransformGetMatchStrata - Get the flag which determines what points get added to the transformed labels

1032:   Not Collective

1034:   Input Parameter:
1035: . tr - The `DMPlexTransform`

1037:   Output Parameter:
1038: . match - If `PETSC_TRUE`, only add produced points at the same stratum as the original point to new labels

1040:   Level: intermediate

1042: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetMatchStrata()`, `DMPlexGetPointDepth()`
1043: @*/
1044: PetscErrorCode DMPlexTransformGetMatchStrata(DMPlexTransform tr, PetscBool *match)
1045: {
1046:   PetscFunctionBegin;
1048:   PetscAssertPointer(match, 2);
1049:   *match = tr->labelMatchStrata;
1050:   PetscFunctionReturn(PETSC_SUCCESS);
1051: }

1053: /*@
1054:   DMPlexTransformSetMatchStrata - Set the flag which determines what points get added to the transformed labels

1056:   Not Collective

1058:   Input Parameters:
1059: + tr    - The `DMPlexTransform`
1060: - match - If `PETSC_TRUE`, only add produced points at the same stratum as the original point to new labels

1062:   Level: intermediate

1064: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetMatchStrata()`, `DMPlexGetPointDepth()`
1065: @*/
1066: PetscErrorCode DMPlexTransformSetMatchStrata(DMPlexTransform tr, PetscBool match)
1067: {
1068:   PetscFunctionBegin;
1070:   tr->labelMatchStrata = match;
1071:   PetscFunctionReturn(PETSC_SUCCESS);
1072: }

1074: /*@
1075:   DMPlexTransformCheck - Verify that the given `DM`, produced by this `DMPlexTransform`, is valid

1077:   Input Parameters:
1078: + tr - The `DMPlexTransform` object
1079: - dm - The `DM` to check

1081:   Level: advanced

1083: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
1084: @*/
1085: PetscErrorCode DMPlexTransformCheck(DMPlexTransform tr, DM dm)
1086: {
1087:   PetscFunctionBegin;
1088:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_Check, tr, dm, 0, 0));
1089:   PetscTryTypeMethod(tr, check, dm);
1090:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_Check, tr, dm, 0, 0));
1091:   PetscFunctionReturn(PETSC_SUCCESS);
1092: }

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

1097:   Not Collective

1099:   Input Parameters:
1100: + tr    - The `DMPlexTransform`
1101: . ct    - The type of the original point which produces the new point
1102: . ctNew - The type of the new point
1103: . p     - The original point which produces the new point
1104: - r     - The replica number of the new point, meaning it is the rth point of type `ctNew` produced from `p`

1106:   Output Parameter:
1107: . pNew - The new point number

1109:   Level: developer

1111: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSourcePoint()`, `DMPlexTransformCellTransform()`
1112: @*/
1113: PetscErrorCode DMPlexTransformGetTargetPoint(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType ctNew, PetscInt p, PetscInt r, PetscInt *pNew)
1114: {
1115:   DMPolytopeType *rct;
1116:   PetscInt       *rsize, *cone, *ornt;
1117:   PetscInt        rt, Nct, n, off, rp;
1118:   DMLabel         trType = tr->trType;
1119:   PetscInt        ctS = tr->ctStart[ct], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ct] + 1]];
1120:   PetscInt        ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]];
1121:   PetscInt        newp = ctSN, cind;

1123:   PetscFunctionBeginHot;
1124:   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);
1125:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, &rt, &Nct, &rct, &rsize, &cone, &ornt));
1126:   if (trType) {
1127:     PetscCall(DMLabelGetValueIndex(trType, rt, &cind));
1128:     PetscCall(DMLabelGetStratumPointIndex(trType, rt, p, &rp));
1129:     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);
1130:   } else {
1131:     cind = ct;
1132:     rp   = p - ctS;
1133:   }
1134:   off = tr->offset[cind * DM_NUM_POLYTOPES + ctNew];
1135:   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);
1136:   newp += off;
1137:   for (n = 0; n < Nct; ++n) {
1138:     if (rct[n] == ctNew) {
1139:       PetscCheck(!rsize[n] || r < rsize[n], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number %" PetscInt_FMT " for point %" PetscInt_FMT " should be in [0, %" PetscInt_FMT ") for subcell type %s in cell type %s", r, p, rsize[n], DMPolytopeTypes[rct[n]], DMPolytopeTypes[ct]);
1140:       newp += rp * rsize[n] + r;
1141:       if (!(newp >= ctSN && newp <= ctEN)) {
1142:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "Problem with point %" PetscInt_FMT " %s replica %" PetscInt_FMT "\n", p, DMPolytopeTypes[ct], r));
1143:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  n %" PetscInt_FMT " rsize %" PetscInt_FMT " rt %" PetscInt_FMT " cind %" PetscInt_FMT " rp %" PetscInt_FMT "\n", n, rsize[n], rt, cind, rp));
1144:       }
1145:       break;
1146:     }
1147:   }

1149:   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);
1150:   *pNew = newp;
1151:   PetscFunctionReturn(PETSC_SUCCESS);
1152: }

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

1157:   Not Collective

1159:   Input Parameters:
1160: + tr   - The `DMPlexTransform`
1161: - pNew - The new point number

1163:   Output Parameters:
1164: + ct    - The type of the original point which produces the new point
1165: . ctNew - The type of the new point
1166: . p     - The original point which produces the new point
1167: - r     - The replica number of the new point, meaning it is the rth point of type ctNew produced from p

1169:   Level: developer

1171: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetTargetPoint()`, `DMPlexTransformCellTransform()`
1172: @*/
1173: PetscErrorCode DMPlexTransformGetSourcePoint(DMPlexTransform tr, PetscInt pNew, DMPolytopeType *ct, DMPolytopeType *ctNew, PetscInt *p, PetscInt *r)
1174: {
1175:   DMLabel         trType = tr->trType;
1176:   DMPolytopeType *rct, ctN;
1177:   PetscInt       *rsize, *cone, *ornt;
1178:   PetscInt        rt = -1, rtTmp, Nct, n, rp = 0, rO = 0, pO;
1179:   PetscInt        offset = -1, ctS, ctE, ctO = 0, ctTmp, rtS;

1181:   PetscFunctionBegin;
1182:   PetscCall(DMPlexTransformGetCellType(tr, pNew, &ctN));
1183:   if (trType) {
1184:     DM              dm;
1185:     IS              rtIS;
1186:     const PetscInt *reftypes;
1187:     PetscInt        Nrt, r;

1189:     PetscCall(DMPlexTransformGetDM(tr, &dm));
1190:     PetscCall(DMLabelGetNumValues(trType, &Nrt));
1191:     PetscCall(DMLabelGetValueIS(trType, &rtIS));
1192:     PetscCall(ISGetIndices(rtIS, &reftypes));
1193:     for (r = 0; r < Nrt; ++r) {
1194:       const PetscInt off = tr->offset[r * DM_NUM_POLYTOPES + ctN];

1196:       if (tr->ctStartNew[ctN] + off > pNew) continue;
1197:       /* Check that any of this refinement type exist */
1198:       /* TODO Actually keep track of the number produced here instead */
1199:       if (off > offset) {
1200:         rt     = reftypes[r];
1201:         offset = off;
1202:       }
1203:     }
1204:     PetscCall(ISRestoreIndices(rtIS, &reftypes));
1205:     PetscCall(ISDestroy(&rtIS));
1206:     PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew);
1207:     /* TODO Map refinement types to cell types */
1208:     PetscCall(DMLabelGetStratumBounds(trType, rt, &rtS, NULL));
1209:     PetscCheck(rtS >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Refinement type %" PetscInt_FMT " has no source points", rt);
1210:     for (ctO = 0; ctO < DM_NUM_POLYTOPES; ++ctO) {
1211:       PetscInt ctS = tr->ctStart[ctO], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]];

1213:       if ((rtS >= ctS) && (rtS < ctE)) break;
1214:     }
1215:     PetscCheck(ctO != DM_NUM_POLYTOPES, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not determine a cell type for refinement type %" PetscInt_FMT, rt);
1216:   } else {
1217:     for (ctTmp = 0; ctTmp < DM_NUM_POLYTOPES; ++ctTmp) {
1218:       const PetscInt off = tr->offset[ctTmp * DM_NUM_POLYTOPES + ctN];

1220:       if (tr->ctStartNew[ctN] + off > pNew) continue;
1221:       if (tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctTmp] + 1]] <= tr->ctStart[ctTmp]) continue;
1222:       /* TODO Actually keep track of the number produced here instead */
1223:       if (off > offset) {
1224:         ctO    = ctTmp;
1225:         offset = off;
1226:       }
1227:     }
1228:     rt = -1;
1229:     PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew);
1230:   }
1231:   ctS = tr->ctStart[ctO];
1232:   ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]];
1233:   if (!trType) rtS = ctS;
1234:   PetscCall(DMPlexTransformCellTransform(tr, (DMPolytopeType)ctO, rtS, &rtTmp, &Nct, &rct, &rsize, &cone, &ornt));
1235:   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);
1236:   for (n = 0; n < Nct; ++n) {
1237:     if (rct[n] == ctN) {
1238:       PetscInt tmp = pNew - tr->ctStartNew[ctN] - offset, c;

1240:       if (trType) {
1241:         IS              rtIS;
1242:         const PetscInt *points;
1243:         const PetscInt  idx = tmp / rsize[n];
1244:         PetscInt        pStart, pEnd;

1246:         PetscCall(DMLabelGetStratumIS(trType, rt, &rtIS));
1247:         PetscCall(ISGetPointRange(rtIS, &pStart, &pEnd, &points));
1248:         PetscCheck(idx < pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Parent point for target point %" PetscInt_FMT " could not be found due to invalid index %" PetscInt_FMT " not in range [0, %" PetscInt_FMT ")", pNew, idx, pEnd - pStart);
1249:         c = points ? points[idx] : pStart + idx;
1250:         PetscCall(ISRestorePointRange(rtIS, &pStart, &pEnd, &points));
1251:         PetscCall(ISDestroy(&rtIS));
1252:         rp = c - ctS;
1253:         rO = tmp % rsize[n];
1254:       } else {
1255:         // This assumes that all points of type ctO transform the same way
1256:         rp = tmp / rsize[n];
1257:         rO = tmp % rsize[n];
1258:       }
1259:       break;
1260:     }
1261:   }
1262:   PetscCheck(n != Nct, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number for target point %" PetscInt_FMT " could be not found", pNew);
1263:   pO = rp + ctS;
1264:   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);
1265:   if (ct) *ct = (DMPolytopeType)ctO;
1266:   if (ctNew) *ctNew = ctN;
1267:   if (p) *p = pO;
1268:   if (r) *r = rO;
1269:   PetscFunctionReturn(PETSC_SUCCESS);
1270: }

1272: /*@
1273:   DMPlexTransformCreateSplitCellLabel - Mark the cells of a transformed mesh whose source cell was genuinely split

1275:   Not Collective

1277:   Input Parameters:
1278: + tr - The `DMPlexTransform` that produced `dm`
1279: - dm - The transformed `DM`

1281:   Output Parameter:
1282: . label - A `DMLabel` marking with 1 the cells of `dm` whose source cell produced more than one cell

1284:   Level: advanced

1286:   Notes:
1287:   For `DMPLEXREFINESBR`, the label also marks cells whose source cell was not flagged in the active label,
1288:   since the transform splits further cells to restore conformity.

1290:   The transform is available only if saved with `DMPlexSetSaveTransform()`. Use `DMPlexGetTransform()` to get it.

1292: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetSourcePoint()`, `DMPlexTransformGetActive()`, `DMPlexGetTransform()`, `DMPlexLabelComplete()`
1293: @*/
1294: PetscErrorCode DMPlexTransformCreateSplitCellLabel(DMPlexTransform tr, DM dm, DMLabel *label)
1295: {
1296:   PetscHMapI children;
1297:   PetscInt  *source;
1298:   PetscInt   cStart, cEnd;

1300:   PetscFunctionBegin;
1303:   PetscAssertPointer(label, 3);
1304:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1305:   /* Count the cells each source point produced, rather than asking the transform how it refines a cell type, so that
1306:      this does not have to know how any particular transform reports its refinement types */
1307:   PetscCall(PetscHMapICreate(&children));
1308:   PetscCall(PetscMalloc1(cEnd - cStart, &source));
1309:   for (PetscInt c = cStart; c < cEnd; ++c) {
1310:     PetscInt p, n = 0;

1312:     PetscCall(DMPlexTransformGetSourcePoint(tr, c, NULL, NULL, &p, NULL));
1313:     PetscCall(PetscHMapIGetWithDefault(children, p, 0, &n));
1314:     PetscCall(PetscHMapISet(children, p, n + 1));
1315:     source[c - cStart] = p;
1316:   }
1317:   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "split cells", label));
1318:   for (PetscInt c = cStart; c < cEnd; ++c) {
1319:     PetscInt n = 0;

1321:     PetscCall(PetscHMapIGetWithDefault(children, source[c - cStart], 0, &n));
1322:     if (n > 1) PetscCall(DMLabelSetValue(*label, c, 1));
1323:   }
1324:   PetscCall(PetscFree(source));
1325:   PetscCall(PetscHMapIDestroy(&children));
1326:   PetscFunctionReturn(PETSC_SUCCESS);
1327: }

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

1332:   Input Parameters:
1333: + tr     - The `DMPlexTransform` object
1334: . source - The source cell type
1335: - p      - The source point, which can also determine the refine type

1337:   Output Parameters:
1338: + rt     - The refine type for this point
1339: . Nt     - The number of types produced by this point
1340: . target - An array of length `Nt` giving the types produced
1341: . size   - An array of length `Nt` giving the number of cells of each type produced
1342: . cone   - An array of length `Nt`*size[t]*coneSize[t] giving the cell type for each point in the cone of each produced point
1343: - ornt   - An array of length `Nt`*size[t]*coneSize[t] giving the orientation for each point in the cone of each produced point

1345:   Level: advanced

1347:   Notes:
1348:   The cone array gives the cone of each subcell listed by the first three outputs. For each cone point, we
1349:   need the cell type, point identifier, and orientation within the subcell. The orientation is with respect to the canonical
1350:   division (described in these outputs) of the cell in the original mesh. The point identifier is given by
1351: .vb
1352:    the number of cones to be taken, or 0 for the current cell
1353:    the cell cone point number at each level from which it is subdivided
1354:    the replica number r of the subdivision.
1355: .ve
1356:   The orientation is with respect to the canonical cone orientation. For example, the prescription for edge division is
1357: .vb
1358:    Nt     = 2
1359:    target = {DM_POLYTOPE_POINT, DM_POLYTOPE_SEGMENT}
1360:    size   = {1, 2}
1361:    cone   = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 0, 0,  DM_POLYTOPE_POINT, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0}
1362:    ornt   = {                         0,                       0,                        0,                          0}
1363: .ve

1365: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`
1366: @*/
1367: PetscErrorCode DMPlexTransformCellTransform(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[])
1368: {
1369:   PetscFunctionBegin;
1370:   PetscUseTypeMethod(tr, celltransform, source, p, rt, Nt, target, size, cone, ornt);
1371:   PetscFunctionReturn(PETSC_SUCCESS);
1372: }

1374: /*@
1375:   DMPlexTransformGetSubcellOrientationIdentity - Default `getsubcellorientation` implementation for transforms that reproduce the input mesh

1377:   Not Collective

1379:   Input Parameters:
1380: + tr  - The `DMPlexTransform`
1381: . sct - The source point cell type
1382: . sp  - The source point
1383: . so  - The orientation of the source point in its enclosing parent
1384: . tct - The target point cell type
1385: . r   - The replica number requested for the produced cell type
1386: - o   - The orientation of the replica

1388:   Output Parameters:
1389: + rnew - The replica number, given the orientation of the parent (returns `r`)
1390: - onew - The replica orientation composed with the source orientation

1392:   Level: developer

1394:   Note:
1395:   This is the identity variant used by transforms such as the "identity" refiner where each source
1396:   point produces itself, so the replica number is unchanged and the returned orientation is simply
1397:   `o` composed with `so` via `DMPolytopeTypeComposeOrientation()`.

1399: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetSubcellOrientation()`, `DMPlexTransformCellTransformIdentity()`, `DMPolytopeTypeComposeOrientation()`
1400: @*/
1401: PetscErrorCode DMPlexTransformGetSubcellOrientationIdentity(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew)
1402: {
1403:   PetscFunctionBegin;
1404:   *rnew = r;
1405:   *onew = DMPolytopeTypeComposeOrientation(tct, o, so);
1406:   PetscFunctionReturn(PETSC_SUCCESS);
1407: }

1409: /*@
1410:   DMPlexTransformCellTransformIdentity - Default `celltransform` implementation for transforms that reproduce the input mesh

1412:   Not Collective

1414:   Input Parameters:
1415: + tr     - The `DMPlexTransform`
1416: . source - The cell type of the source point
1417: - p      - The source point

1419:   Output Parameters:
1420: + rt     - Refinement type of the source point (set to 0), or `NULL`
1421: . Nt     - Number of target cell types produced (always 1)
1422: . target - Array of produced cell types (a single-element array containing `source`)
1423: . size   - Array of replica counts for each produced type (a single-element array containing 1)
1424: . cone   - Cone description used by `DMPlexTransformGetCone()`; encodes that the replica takes the entire parent cone
1425: - ornt   - Orientation array associated with `cone`; all zero for identity

1427:   Level: developer

1429:   Note:
1430:   This routine returns statically allocated arrays describing an identity refinement for each supported
1431:   `DMPolytopeType`; every source point produces a single replica of the same type with unchanged cone
1432:   and orientation.

1434: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformCellTransform()`, `DMPlexTransformGetSubcellOrientationIdentity()`
1435: @*/
1436: PetscErrorCode DMPlexTransformCellTransformIdentity(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[])
1437: {
1438:   static DMPolytopeType vertexT[] = {DM_POLYTOPE_POINT};
1439:   static PetscInt       vertexS[] = {1};
1440:   static PetscInt       vertexC[] = {0};
1441:   static PetscInt       vertexO[] = {0};
1442:   static DMPolytopeType edgeT[]   = {DM_POLYTOPE_SEGMENT};
1443:   static PetscInt       edgeS[]   = {1};
1444:   static PetscInt       edgeC[]   = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0};
1445:   static PetscInt       edgeO[]   = {0, 0};
1446:   static DMPolytopeType tedgeT[]  = {DM_POLYTOPE_POINT_PRISM_TENSOR};
1447:   static PetscInt       tedgeS[]  = {1};
1448:   static PetscInt       tedgeC[]  = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0};
1449:   static PetscInt       tedgeO[]  = {0, 0};
1450:   static DMPolytopeType triT[]    = {DM_POLYTOPE_TRIANGLE};
1451:   static PetscInt       triS[]    = {1};
1452:   static PetscInt       triC[]    = {DM_POLYTOPE_SEGMENT, 1, 0, 0, DM_POLYTOPE_SEGMENT, 1, 1, 0, DM_POLYTOPE_SEGMENT, 1, 2, 0};
1453:   static PetscInt       triO[]    = {0, 0, 0};
1454:   static DMPolytopeType quadT[]   = {DM_POLYTOPE_QUADRILATERAL};
1455:   static PetscInt       quadS[]   = {1};
1456:   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};
1457:   static PetscInt       quadO[]   = {0, 0, 0, 0};
1458:   static DMPolytopeType tquadT[]  = {DM_POLYTOPE_SEG_PRISM_TENSOR};
1459:   static PetscInt       tquadS[]  = {1};
1460:   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};
1461:   static PetscInt       tquadO[]  = {0, 0, 0, 0};
1462:   static DMPolytopeType tetT[]    = {DM_POLYTOPE_TETRAHEDRON};
1463:   static PetscInt       tetS[]    = {1};
1464:   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};
1465:   static PetscInt       tetO[]    = {0, 0, 0, 0};
1466:   static DMPolytopeType hexT[]    = {DM_POLYTOPE_HEXAHEDRON};
1467:   static PetscInt       hexS[]    = {1};
1468:   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};
1469:   static PetscInt       hexO[] = {0, 0, 0, 0, 0, 0};
1470:   static DMPolytopeType tripT[]   = {DM_POLYTOPE_TRI_PRISM};
1471:   static PetscInt       tripS[]   = {1};
1472:   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};
1473:   static PetscInt       tripO[]   = {0, 0, 0, 0, 0};
1474:   static DMPolytopeType ttripT[]  = {DM_POLYTOPE_TRI_PRISM_TENSOR};
1475:   static PetscInt       ttripS[]  = {1};
1476:   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};
1477:   static PetscInt       ttripO[]  = {0, 0, 0, 0, 0};
1478:   static DMPolytopeType tquadpT[] = {DM_POLYTOPE_QUAD_PRISM_TENSOR};
1479:   static PetscInt       tquadpS[] = {1};
1480:   static PetscInt       tquadpC[] = {DM_POLYTOPE_QUADRILATERAL,    1, 0, 0, DM_POLYTOPE_QUADRILATERAL,    1, 1, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 2, 0,
1481:                                      DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 3, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 4, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 5, 0};
1482:   static PetscInt       tquadpO[] = {0, 0, 0, 0, 0, 0};
1483:   static DMPolytopeType pyrT[]    = {DM_POLYTOPE_PYRAMID};
1484:   static PetscInt       pyrS[]    = {1};
1485:   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};
1486:   static PetscInt       pyrO[]    = {0, 0, 0, 0, 0};

1488:   PetscFunctionBegin;
1489:   if (rt) *rt = 0;
1490:   switch (source) {
1491:   case DM_POLYTOPE_POINT:
1492:     *Nt     = 1;
1493:     *target = vertexT;
1494:     *size   = vertexS;
1495:     *cone   = vertexC;
1496:     *ornt   = vertexO;
1497:     break;
1498:   case DM_POLYTOPE_SEGMENT:
1499:     *Nt     = 1;
1500:     *target = edgeT;
1501:     *size   = edgeS;
1502:     *cone   = edgeC;
1503:     *ornt   = edgeO;
1504:     break;
1505:   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1506:     *Nt     = 1;
1507:     *target = tedgeT;
1508:     *size   = tedgeS;
1509:     *cone   = tedgeC;
1510:     *ornt   = tedgeO;
1511:     break;
1512:   case DM_POLYTOPE_TRIANGLE:
1513:     *Nt     = 1;
1514:     *target = triT;
1515:     *size   = triS;
1516:     *cone   = triC;
1517:     *ornt   = triO;
1518:     break;
1519:   case DM_POLYTOPE_QUADRILATERAL:
1520:     *Nt     = 1;
1521:     *target = quadT;
1522:     *size   = quadS;
1523:     *cone   = quadC;
1524:     *ornt   = quadO;
1525:     break;
1526:   case DM_POLYTOPE_SEG_PRISM_TENSOR:
1527:     *Nt     = 1;
1528:     *target = tquadT;
1529:     *size   = tquadS;
1530:     *cone   = tquadC;
1531:     *ornt   = tquadO;
1532:     break;
1533:   case DM_POLYTOPE_TETRAHEDRON:
1534:     *Nt     = 1;
1535:     *target = tetT;
1536:     *size   = tetS;
1537:     *cone   = tetC;
1538:     *ornt   = tetO;
1539:     break;
1540:   case DM_POLYTOPE_HEXAHEDRON:
1541:     *Nt     = 1;
1542:     *target = hexT;
1543:     *size   = hexS;
1544:     *cone   = hexC;
1545:     *ornt   = hexO;
1546:     break;
1547:   case DM_POLYTOPE_TRI_PRISM:
1548:     *Nt     = 1;
1549:     *target = tripT;
1550:     *size   = tripS;
1551:     *cone   = tripC;
1552:     *ornt   = tripO;
1553:     break;
1554:   case DM_POLYTOPE_TRI_PRISM_TENSOR:
1555:     *Nt     = 1;
1556:     *target = ttripT;
1557:     *size   = ttripS;
1558:     *cone   = ttripC;
1559:     *ornt   = ttripO;
1560:     break;
1561:   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
1562:     *Nt     = 1;
1563:     *target = tquadpT;
1564:     *size   = tquadpS;
1565:     *cone   = tquadpC;
1566:     *ornt   = tquadpO;
1567:     break;
1568:   case DM_POLYTOPE_PYRAMID:
1569:     *Nt     = 1;
1570:     *target = pyrT;
1571:     *size   = pyrS;
1572:     *cone   = pyrC;
1573:     *ornt   = pyrO;
1574:     break;
1575:   default:
1576:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No refinement strategy for %s", DMPolytopeTypes[source]);
1577:   }
1578:   PetscFunctionReturn(PETSC_SUCCESS);
1579: }

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

1584:   Not Collective

1586:   Input Parameters:
1587: + tr  - The `DMPlexTransform`
1588: . sct - The source point cell type, from whom the new cell is being produced
1589: . sp  - The source point
1590: . so  - The orientation of the source point in its enclosing parent
1591: . tct - The target point cell type
1592: . r   - The replica number requested for the produced cell type
1593: - o   - The orientation of the replica

1595:   Output Parameters:
1596: + rnew - The replica number, given the orientation of the parent
1597: - onew - The replica orientation, given the orientation of the parent

1599:   Level: advanced

1601: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformCellTransform()`, `DMPlexTransformApply()`
1602: @*/
1603: PetscErrorCode DMPlexTransformGetSubcellOrientation(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew)
1604: {
1605:   PetscFunctionBeginHot;
1606:   PetscUseTypeMethod(tr, getsubcellorientation, sct, sp, so, tct, r, o, rnew, onew);
1607:   PetscFunctionReturn(PETSC_SUCCESS);
1608: }

1610: static PetscErrorCode DMPlexTransformSetConeSizes(DMPlexTransform tr, DM rdm)
1611: {
1612:   DM       dm;
1613:   PetscInt pStart, pEnd, pNew;

1615:   PetscFunctionBegin;
1616:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1617:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetConeSizes, tr, dm, 0, 0));
1618:   /* Must create the celltype label here so that we do not automatically try to compute the types */
1619:   PetscCall(DMCreateLabel(rdm, "celltype"));
1620:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1621:   for (PetscInt p = pStart; p < pEnd; ++p) {
1622:     DMPolytopeType  ct;
1623:     DMPolytopeType *rct;
1624:     PetscInt       *rsize, *rcone, *rornt;
1625:     PetscInt        Nct, n, r;

1627:     PetscCall(DMPlexGetCellType(dm, p, &ct));
1628:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1629:     for (n = 0; n < Nct; ++n) {
1630:       for (r = 0; r < rsize[n]; ++r) {
1631:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1632:         PetscCall(DMPlexSetConeSize(rdm, pNew, DMPolytopeTypeGetConeSize(rct[n])));
1633:         PetscCall(DMPlexSetCellType(rdm, pNew, rct[n]));
1634:       }
1635:     }
1636:   }
1637:   /* Let the DM know we have set all the cell types */
1638:   {
1639:     DMLabel  ctLabel;
1640:     DM_Plex *plex = (DM_Plex *)rdm->data;

1642:     PetscCall(DMPlexGetCellTypeLabel(rdm, &ctLabel));
1643:     PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &plex->celltypeState));
1644:   }
1645:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetConeSizes, tr, dm, 0, 0));
1646:   PetscFunctionReturn(PETSC_SUCCESS);
1647: }

1649: /*@
1650:   DMPlexTransformGetConeSize - Return the cone size of a point in the transformed mesh

1652:   Not Collective

1654:   Input Parameters:
1655: + tr - The `DMPlexTransform`
1656: - q  - The point number in the transformed mesh

1658:   Output Parameter:
1659: . coneSize - The number of points in the cone of `q`

1661:   Level: developer

1663: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetCone()`, `DMPlexTransformGetCellType()`, `DMPlexGetConeSize()`
1664: @*/
1665: PetscErrorCode DMPlexTransformGetConeSize(DMPlexTransform tr, PetscInt q, PetscInt *coneSize)
1666: {
1667:   DMPolytopeType ctNew;

1669:   PetscFunctionBegin;
1671:   PetscAssertPointer(coneSize, 3);
1672:   PetscCall(DMPlexTransformGetCellType(tr, q, &ctNew));
1673:   *coneSize = DMPolytopeTypeGetConeSize(ctNew);
1674:   PetscFunctionReturn(PETSC_SUCCESS);
1675: }

1677: /* The orientation o is for the interior of the cell p */
1678: 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[])
1679: {
1680:   DM              dm;
1681:   const PetscInt  csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1682:   const PetscInt *cone;
1683:   DMPolytopeType *newft = NULL;
1684:   PetscInt        c, coff = *coneoff, ooff = *orntoff;
1685:   PetscInt        dim, cr = 0, co = 0, nr, no;

1687:   PetscFunctionBegin;
1688:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1689:   PetscCall(DMPlexGetOrientedCone(dm, p, &cone, NULL));
1690:   // Check if we have to permute this cell
1691:   PetscCall(DMGetDimension(dm, &dim));
1692:   if (DMPolytopeTypeGetDim(ctNew) == dim && DMPolytopeTypeGetDim(ct) == dim - 1) {
1693:     PetscCall(DMPlexTransformGetSubcellOrientation(tr, ct, p, o, ctNew, cr, co, &nr, &no));
1694:     if (cr != nr || co != no) PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newft));
1695:   }
1696:   for (c = 0; c < csizeNew; ++c) {
1697:     PetscInt             ppp   = -1;                            /* Parent Parent point: Parent of point pp */
1698:     PetscInt             pp    = p;                             /* Parent point: Point in the original mesh producing new cone point */
1699:     PetscInt             po    = 0;                             /* Orientation of parent point pp in parent parent point ppp */
1700:     DMPolytopeType       pct   = ct;                            /* Parent type: Cell type for parent of new cone point */
1701:     const PetscInt      *pcone = cone;                          /* Parent cone: Cone of parent point pp */
1702:     PetscInt             pr    = -1;                            /* Replica number of pp that produces new cone point  */
1703:     const DMPolytopeType ft    = (DMPolytopeType)rcone[coff++]; /* Cell type for new cone point of pNew */
1704:     const PetscInt       fn    = rcone[coff++];                 /* Number of cones of p that need to be taken when producing new cone point */
1705:     PetscInt             fo    = rornt[ooff++];                 /* Orientation of new cone point in pNew */
1706:     PetscInt             lc;

1708:     /* Get the type (pct) and point number (pp) of the parent point in the original mesh which produces this cone point */
1709:     for (lc = 0; lc < fn; ++lc) {
1710:       const PetscInt *parr = DMPolytopeTypeGetArrangement(pct, po);
1711:       const PetscInt  acp  = rcone[coff++];
1712:       const PetscInt  pcp  = parr[acp * 2];
1713:       const PetscInt  pco  = parr[acp * 2 + 1];
1714:       const PetscInt *ppornt;

1716:       ppp = pp;
1717:       pp  = pcone[pcp];
1718:       PetscCall(DMPlexGetCellType(dm, pp, &pct));
1719:       // Restore the parent cone from the last iterate
1720:       if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, ppp, &pcone, NULL));
1721:       PetscCall(DMPlexGetOrientedCone(dm, pp, &pcone, NULL));
1722:       PetscCall(DMPlexGetOrientedCone(dm, ppp, NULL, &ppornt));
1723:       po = DMPolytopeTypeComposeOrientation(pct, ppornt[pcp], pco);
1724:       PetscCall(DMPlexRestoreOrientedCone(dm, ppp, NULL, &ppornt));
1725:     }
1726:     if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, pp, &pcone, NULL));
1727:     pr = rcone[coff++];
1728:     /* Orientation po of pp maps (pr, fo) -> (pr', fo') */
1729:     PetscCall(DMPlexTransformGetSubcellOrientation(tr, pct, pp, fn ? po : o, ft, pr, fo, &pr, &fo));
1730:     PetscCall(DMPlexTransformGetTargetPoint(tr, pct, ft, pp, pr, &coneNew[c]));
1731:     orntNew[c] = fo;
1732:     if (newft) newft[c] = ft;
1733:   }
1734:   PetscCall(DMPlexRestoreOrientedCone(dm, p, &cone, NULL));
1735:   if (newft) {
1736:     const PetscInt *arr;
1737:     PetscInt       *newcone, *newornt;

1739:     arr = DMPolytopeTypeGetArrangement(ctNew, no);
1740:     PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newcone));
1741:     PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newornt));
1742:     for (PetscInt c = 0; c < csizeNew; ++c) {
1743:       DMPolytopeType ft = newft[c];
1744:       PetscInt       nO;

1746:       nO         = DMPolytopeTypeGetNumArrangements(ft) / 2;
1747:       newcone[c] = coneNew[arr[c * 2 + 0]];
1748:       newornt[c] = DMPolytopeTypeComposeOrientation(ft, arr[c * 2 + 1], orntNew[arr[c * 2 + 0]]);
1749:       PetscCheck(!newornt[c] || !(newornt[c] >= nO || newornt[c] < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, newornt[c], -nO, nO, DMPolytopeTypes[ft], coneNew[c]);
1750:     }
1751:     for (PetscInt c = 0; c < csizeNew; ++c) {
1752:       coneNew[c] = newcone[c];
1753:       orntNew[c] = newornt[c];
1754:     }
1755:     PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newcone));
1756:     PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newornt));
1757:     PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newft));
1758:   }
1759:   *coneoff = coff;
1760:   *orntoff = ooff;
1761:   PetscFunctionReturn(PETSC_SUCCESS);
1762: }

1764: static PetscErrorCode DMPlexTransformSetCones(DMPlexTransform tr, DM rdm)
1765: {
1766:   DM             dm;
1767:   DMPolytopeType ct;
1768:   PetscInt      *coneNew, *orntNew;
1769:   PetscInt       maxConeSize = 0, pStart, pEnd, p, pNew;

1771:   PetscFunctionBegin;
1772:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1773:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetCones, tr, dm, 0, 0));
1774:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1775:   PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew));
1776:   PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew));
1777:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1778:   for (p = pStart; p < pEnd; ++p) {
1779:     PetscInt        coff, ooff;
1780:     DMPolytopeType *rct;
1781:     PetscInt       *rsize, *rcone, *rornt;
1782:     PetscInt        Nct, n, r;

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

1789:       for (r = 0; r < rsize[n]; ++r) {
1790:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
1791:         PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, ctNew, rcone, &coff, rornt, &ooff, coneNew, orntNew));
1792:         PetscCall(DMPlexSetCone(rdm, pNew, coneNew));
1793:         PetscCall(DMPlexSetConeOrientation(rdm, pNew, orntNew));
1794:       }
1795:     }
1796:   }
1797:   PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew));
1798:   PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew));
1799:   PetscCall(DMViewFromOptions(rdm, NULL, "-rdm_view"));
1800:   PetscCall(DMPlexSymmetrize(rdm));
1801:   PetscCall(DMPlexStratify(rdm));
1802:   PetscCall(DMPlexTransformOrderSupports(tr, dm, rdm));
1803:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetCones, tr, dm, 0, 0));
1804:   PetscFunctionReturn(PETSC_SUCCESS);
1805: }

1807: /*@
1808:   DMPlexTransformGetConeOriented - Return the cone of a point in the transformed mesh, computed using a specified parent orientation

1810:   Not Collective

1812:   Input Parameters:
1813: + tr - The `DMPlexTransform`
1814: . q  - The point number in the transformed mesh
1815: - po - The orientation of the parent cell in the original mesh to use when producing the cone

1817:   Output Parameters:
1818: + cone - The cone points, obtained from an internal work array
1819: - ornt - The orientations of the cone points, obtained from an internal work array

1821:   Level: developer

1823:   Note:
1824:   Both `cone` and `ornt` are returned in work arrays that must be released with `DMPlexTransformRestoreCone()`.

1826: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetCone()`, `DMPlexTransformRestoreCone()`, `DMPlexTransformGetConeSize()`
1827: @*/
1828: PetscErrorCode DMPlexTransformGetConeOriented(DMPlexTransform tr, PetscInt q, PetscInt po, const PetscInt *cone[], const PetscInt *ornt[])
1829: {
1830:   DM              dm;
1831:   DMPolytopeType  ct, qct;
1832:   DMPolytopeType *rct;
1833:   PetscInt       *rsize, *rcone, *rornt, *qcone, *qornt;
1834:   PetscInt        maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0;

1836:   PetscFunctionBegin;
1838:   PetscAssertPointer(cone, 4);
1839:   PetscAssertPointer(ornt, 5);
1840:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1841:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1842:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1843:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1844:   PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r));
1845:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1846:   for (n = 0; n < Nct; ++n) {
1847:     const DMPolytopeType ctNew    = rct[n];
1848:     const PetscInt       csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1849:     PetscInt             Nr       = rsize[n], fn, c;

1851:     if (ctNew == qct) Nr = r;
1852:     for (nr = 0; nr < Nr; ++nr) {
1853:       for (c = 0; c < csizeNew; ++c) {
1854:         ++coff;             /* Cell type of new cone point */
1855:         fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */
1856:         coff += fn;
1857:         ++coff; /* Replica number of new cone point */
1858:         ++ooff; /* Orientation of new cone point */
1859:       }
1860:     }
1861:     if (ctNew == qct) break;
1862:   }
1863:   PetscCall(DMPlexTransformGetCone_Internal(tr, p, po, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt));
1864:   *cone = qcone;
1865:   *ornt = qornt;
1866:   PetscFunctionReturn(PETSC_SUCCESS);
1867: }

1869: /*@
1870:   DMPlexTransformGetCone - Return the cone of a point in the transformed mesh

1872:   Not Collective

1874:   Input Parameters:
1875: + tr - The `DMPlexTransform`
1876: - q  - The point number in the transformed mesh

1878:   Output Parameters:
1879: + cone - The cone points, obtained from an internal work array, or `NULL` if not requested
1880: - ornt - The orientations of the cone points, obtained from an internal work array, or `NULL` if not requested

1882:   Level: developer

1884:   Note:
1885:   Any non-`NULL` output must be released with `DMPlexTransformRestoreCone()`.

1887: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformRestoreCone()`, `DMPlexTransformGetConeOriented()`, `DMPlexTransformGetConeSize()`, `DMPlexGetCone()`
1888: @*/
1889: PetscErrorCode DMPlexTransformGetCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[])
1890: {
1891:   DM              dm;
1892:   DMPolytopeType  ct, qct;
1893:   DMPolytopeType *rct;
1894:   PetscInt       *rsize, *rcone, *rornt, *qcone, *qornt;
1895:   PetscInt        maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0;

1897:   PetscFunctionBegin;
1899:   if (cone) PetscAssertPointer(cone, 3);
1900:   if (ornt) PetscAssertPointer(ornt, 4);
1901:   for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p));
1902:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1903:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1904:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1905:   PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r));
1906:   PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1907:   for (n = 0; n < Nct; ++n) {
1908:     const DMPolytopeType ctNew    = rct[n];
1909:     const PetscInt       csizeNew = DMPolytopeTypeGetConeSize(ctNew);
1910:     PetscInt             Nr       = rsize[n], fn, c;

1912:     if (ctNew == qct) Nr = r;
1913:     for (nr = 0; nr < Nr; ++nr) {
1914:       for (c = 0; c < csizeNew; ++c) {
1915:         ++coff;             /* Cell type of new cone point */
1916:         fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */
1917:         coff += fn;
1918:         ++coff; /* Replica number of new cone point */
1919:         ++ooff; /* Orientation of new cone point */
1920:       }
1921:     }
1922:     if (ctNew == qct) break;
1923:   }
1924:   PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt));
1925:   if (cone) *cone = qcone;
1926:   else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qcone));
1927:   if (ornt) *ornt = qornt;
1928:   else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qornt));
1929:   PetscFunctionReturn(PETSC_SUCCESS);
1930: }

1932: /*@
1933:   DMPlexTransformRestoreCone - Return the work arrays produced by `DMPlexTransformGetCone()` or `DMPlexTransformGetConeOriented()`

1935:   Not Collective

1937:   Input Parameters:
1938: + tr   - The `DMPlexTransform`
1939: . q    - The point number in the transformed mesh
1940: . cone - The cone points to release, or `NULL`
1941: - ornt - The orientations to release, or `NULL`

1943:   Level: developer

1945: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetCone()`, `DMPlexTransformGetConeOriented()`
1946: @*/
1947: PetscErrorCode DMPlexTransformRestoreCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[])
1948: {
1949:   DM dm;

1951:   PetscFunctionBegin;
1953:   PetscCall(DMPlexTransformGetDM(tr, &dm));
1954:   if (cone) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, cone));
1955:   if (ornt) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, ornt));
1956:   PetscFunctionReturn(PETSC_SUCCESS);
1957: }

1959: static PetscErrorCode DMPlexTransformCreateCellVertices_Internal(DMPlexTransform tr)
1960: {
1961:   PetscFunctionBegin;
1962:   PetscCall(PetscCalloc3(DM_NUM_POLYTOPES, &tr->trNv, DM_NUM_POLYTOPES, &tr->trVerts, DM_NUM_POLYTOPES, &tr->trSubVerts));
1963:   for (PetscInt ict = DM_POLYTOPE_POINT; ict < DM_NUM_POLYTOPES; ++ict) {
1964:     const DMPolytopeType ct = (DMPolytopeType)ict;
1965:     DMPlexTransform      reftr;
1966:     DM                   refdm, trdm;
1967:     Vec                  coordinates;
1968:     const PetscScalar   *coords;
1969:     DMPolytopeType      *rct;
1970:     PetscInt            *rsize, *rcone, *rornt;
1971:     PetscInt             Nct, n, r, pNew = 0;
1972:     PetscInt             trdim, vStart, vEnd, Nc;
1973:     const PetscInt       debug = 0;
1974:     const char          *typeName;

1976:     /* Since points are 0-dimensional, coordinates make no sense */
1977:     if (DMPolytopeTypeGetDim(ct) <= 0 || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) continue;
1978:     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, ct, &refdm));
1979:     PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &reftr));
1980:     PetscCall(DMPlexTransformSetDM(reftr, refdm));
1981:     PetscCall(DMPlexTransformGetType(tr, &typeName));
1982:     PetscCall(DMPlexTransformSetType(reftr, typeName));
1983:     PetscCall(DMPlexTransformSetUp(reftr));
1984:     PetscCall(DMPlexTransformApply(reftr, refdm, &trdm));

1986:     PetscCall(DMGetDimension(trdm, &trdim));
1987:     PetscCall(DMPlexGetDepthStratum(trdm, 0, &vStart, &vEnd));
1988:     tr->trNv[ct] = vEnd - vStart;
1989:     PetscCall(DMGetCoordinatesLocal(trdm, &coordinates));
1990:     PetscCall(VecGetLocalSize(coordinates, &Nc));
1991:     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);
1992:     PetscCall(PetscCalloc1(Nc, &tr->trVerts[ct]));
1993:     PetscCall(VecGetArrayRead(coordinates, &coords));
1994:     PetscCall(PetscArraycpy(tr->trVerts[ct], coords, Nc));
1995:     PetscCall(VecRestoreArrayRead(coordinates, &coords));

1997:     PetscCall(PetscCalloc1(DM_NUM_POLYTOPES, &tr->trSubVerts[ct]));
1998:     PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
1999:     for (n = 0; n < Nct; ++n) {
2000:       /* Since points are 0-dimensional, coordinates make no sense */
2001:       if (rct[n] == DM_POLYTOPE_POINT) continue;
2002:       PetscCall(PetscCalloc1(rsize[n], &tr->trSubVerts[ct][rct[n]]));
2003:       for (r = 0; r < rsize[n]; ++r) {
2004:         PetscInt *closure = NULL;
2005:         PetscInt  clSize, cl, Nv = 0;

2007:         PetscCall(PetscCalloc1(DMPolytopeTypeGetNumVertices(rct[n]), &tr->trSubVerts[ct][rct[n]][r]));
2008:         PetscCall(DMPlexTransformGetTargetPoint(reftr, ct, rct[n], 0, r, &pNew));
2009:         PetscCall(DMPlexGetTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure));
2010:         for (cl = 0; cl < clSize * 2; cl += 2) {
2011:           const PetscInt sv = closure[cl];

2013:           if ((sv >= vStart) && (sv < vEnd)) tr->trSubVerts[ct][rct[n]][r][Nv++] = sv - vStart;
2014:         }
2015:         PetscCall(DMPlexRestoreTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure));
2016:         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]);
2017:       }
2018:     }
2019:     if (debug) {
2020:       DMPolytopeType *rct;
2021:       PetscInt       *rsize, *rcone, *rornt;
2022:       PetscInt        v, dE = trdim, d, off = 0;

2024:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %" PetscInt_FMT " vertices\n", DMPolytopeTypes[ct], tr->trNv[ct]));
2025:       for (v = 0; v < tr->trNv[ct]; ++v) {
2026:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  "));
2027:         for (d = 0; d < dE; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g ", (double)PetscRealPart(tr->trVerts[ct][off++])));
2028:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
2029:       }

2031:       PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2032:       for (n = 0; n < Nct; ++n) {
2033:         if (rct[n] == DM_POLYTOPE_POINT) continue;
2034:         PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %s subvertices %" PetscInt_FMT "\n", DMPolytopeTypes[ct], DMPolytopeTypes[rct[n]], tr->trNv[ct]));
2035:         for (r = 0; r < rsize[n]; ++r) {
2036:           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  "));
2037:           for (v = 0; v < DMPolytopeTypeGetNumVertices(rct[n]); ++v) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT " ", tr->trSubVerts[ct][rct[n]][r][v]));
2038:           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
2039:         }
2040:       }
2041:     }
2042:     PetscCall(DMDestroy(&refdm));
2043:     PetscCall(DMDestroy(&trdm));
2044:     PetscCall(DMPlexTransformDestroy(&reftr));
2045:   }
2046:   PetscFunctionReturn(PETSC_SUCCESS);
2047: }

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

2052:   Input Parameters:
2053: + tr - The `DMPlexTransform` object
2054: - ct - The cell type

2056:   Output Parameters:
2057: + Nv      - The number of transformed vertices in the closure of the reference cell of given type
2058: - trVerts - The coordinates of these vertices in the reference cell

2060:   Level: developer

2062: .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSubcellVertices()`
2063: @*/
2064: PetscErrorCode DMPlexTransformGetCellVertices(DMPlexTransform tr, DMPolytopeType ct, PetscInt *Nv, PetscScalar *trVerts[])
2065: {
2066:   PetscFunctionBegin;
2067:   if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr));
2068:   if (Nv) *Nv = tr->trNv[ct];
2069:   if (trVerts) *trVerts = tr->trVerts[ct];
2070:   PetscFunctionReturn(PETSC_SUCCESS);
2071: }

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

2076:   Input Parameters:
2077: + tr  - The `DMPlexTransform` object
2078: . ct  - The cell type
2079: . rct - The subcell type
2080: - r   - The subcell index

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

2085:   Level: developer

2087: .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetCellVertices()`
2088: @*/
2089: PetscErrorCode DMPlexTransformGetSubcellVertices(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, PetscInt *subVerts[])
2090: {
2091:   PetscFunctionBegin;
2092:   if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr));
2093:   PetscCheck(tr->trSubVerts[ct][rct], PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_WRONG, "Cell type %s does not produce %s", DMPolytopeTypes[ct], DMPolytopeTypes[rct]);
2094:   if (subVerts) *subVerts = tr->trSubVerts[ct][rct][r];
2095:   PetscFunctionReturn(PETSC_SUCCESS);
2096: }

2098: /*@
2099:   DMPlexTransformOrderSupports - Reorder newly introduced point supports

2101:   Collective

2103:   Input Parameters:
2104: + tr   - The `DMPlexTransform`
2105: . dm   - The original `DM`
2106: - trdm - The transformed `DM` which is reordered

2108:   Level: intermediate

2110: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`
2111: @*/
2112: PetscErrorCode DMPlexTransformOrderSupports(DMPlexTransform tr, DM dm, DM trdm)
2113: {
2114:   PetscFunctionBegin;
2118:   PetscTryTypeMethod(tr, ordersupports, dm, trdm);
2119:   PetscFunctionReturn(PETSC_SUCCESS);
2120: }

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

2127:   PetscFunctionBeginHot;
2128:   PetscCheck(ct == DM_POLYTOPE_POINT, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for refined point type %s", DMPolytopeTypes[ct]);
2129:   for (d = 0; d < dE; ++d) out[d] = 0.0;
2130:   for (v = 0; v < Nv; ++v)
2131:     for (d = 0; d < dE; ++d) out[d] += in[v * dE + d];
2132:   for (d = 0; d < dE; ++d) out[d] /= Nv;
2133:   PetscFunctionReturn(PETSC_SUCCESS);
2134: }

2136: /*@
2137:   DMPlexTransformMapCoordinates - Calculate new coordinates for produced points

2139:   Not collective

2141:   Input Parameters:
2142: + tr  - The `DMPlexTransform`
2143: . pct - The cell type of the parent, from whom the new cell is being produced
2144: . ct  - The type being produced
2145: . p   - The original point
2146: . r   - The replica number requested for the produced cell type
2147: . Nv  - Number of vertices in the closure of the parent cell
2148: . dE  - Spatial dimension
2149: - in  - array of size Nv*dE, holding coordinates of the vertices in the closure of the parent cell

2151:   Output Parameter:
2152: . out - The coordinates of the new vertices

2154:   Level: intermediate

2156: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`
2157: @*/
2158: PetscErrorCode DMPlexTransformMapCoordinates(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[])
2159: {
2160:   PetscFunctionBeginHot;
2161:   if (Nv) PetscUseTypeMethod(tr, mapcoordinates, pct, ct, p, r, Nv, dE, in, out);
2162:   PetscFunctionReturn(PETSC_SUCCESS);
2163: }

2165: /*
2166:   DMPlexTransformLabelProducedPoint_Private - Label a produced point based on its parent label

2168:   Not Collective

2170:   Input Parameters:
2171: + tr    - The `DMPlexTransform`
2172: . label - The label in the transformed mesh
2173: . pp    - The parent point in the original mesh
2174: . pct   - The cell type of the parent point
2175: . p     - The point in the transformed mesh
2176: . ct    - The cell type of the point
2177: . r     - The replica number of the point
2178: - val   - The label value of the parent point

2180:   Level: developer

2182: .seealso: `DMPlexTransformCreateLabels()`, `RefineLabel_Internal()`
2183: */
2184: static PetscErrorCode DMPlexTransformLabelProducedPoint_Private(DMPlexTransform tr, DMLabel label, PetscInt pp, DMPolytopeType pct, PetscInt p, DMPolytopeType ct, PetscInt r, PetscInt val)
2185: {
2186:   PetscFunctionBeginHot;
2187:   if (tr->labelMatchStrata && pct != ct) PetscFunctionReturn(PETSC_SUCCESS);
2188:   PetscCall(DMLabelSetValue(label, p, val + tr->labelReplicaInc * r));
2189:   PetscFunctionReturn(PETSC_SUCCESS);
2190: }

2192: static PetscErrorCode RefineLabel_Internal(DMPlexTransform tr, DMLabel label, DMLabel labelNew)
2193: {
2194:   DM              dm;
2195:   IS              valueIS;
2196:   const PetscInt *values;
2197:   PetscInt        defVal, Nv, val;

2199:   PetscFunctionBegin;
2200:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2201:   PetscCall(DMLabelGetDefaultValue(label, &defVal));
2202:   PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
2203:   PetscCall(DMLabelGetValueIS(label, &valueIS));
2204:   PetscCall(ISGetLocalSize(valueIS, &Nv));
2205:   PetscCall(ISGetIndices(valueIS, &values));
2206:   for (val = 0; val < Nv; ++val) {
2207:     IS              pointIS;
2208:     const PetscInt *points;
2209:     PetscInt        numPoints, p;

2211:     /* Ensure refined label is created with same number of strata as
2212:      * original (even if no entries here). */
2213:     PetscCall(DMLabelAddStratum(labelNew, values[val]));
2214:     PetscCall(DMLabelGetStratumIS(label, values[val], &pointIS));
2215:     PetscCall(ISGetLocalSize(pointIS, &numPoints));
2216:     PetscCall(ISGetIndices(pointIS, &points));
2217:     for (p = 0; p < numPoints; ++p) {
2218:       const PetscInt  point = points[p];
2219:       DMPolytopeType  ct;
2220:       DMPolytopeType *rct;
2221:       PetscInt       *rsize, *rcone, *rornt;
2222:       PetscInt        Nct, n, r, pNew = 0;

2224:       PetscCall(DMPlexGetCellType(dm, point, &ct));
2225:       PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2226:       for (n = 0; n < Nct; ++n) {
2227:         for (r = 0; r < rsize[n]; ++r) {
2228:           PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], point, r, &pNew));
2229:           PetscCall(DMPlexTransformLabelProducedPoint_Private(tr, labelNew, point, ct, pNew, rct[n], r, values[val]));
2230:         }
2231:       }
2232:     }
2233:     PetscCall(ISRestoreIndices(pointIS, &points));
2234:     PetscCall(ISDestroy(&pointIS));
2235:   }
2236:   PetscCall(ISRestoreIndices(valueIS, &values));
2237:   PetscCall(ISDestroy(&valueIS));
2238:   PetscFunctionReturn(PETSC_SUCCESS);
2239: }

2241: static PetscErrorCode DMPlexTransformCreateLabels(DMPlexTransform tr, DM rdm)
2242: {
2243:   DM       dm;
2244:   PetscInt numLabels, l;

2246:   PetscFunctionBegin;
2247:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2248:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_CreateLabels, tr, dm, 0, 0));
2249:   PetscCall(DMGetNumLabels(dm, &numLabels));
2250:   for (l = 0; l < numLabels; ++l) {
2251:     DMLabel     label, labelNew;
2252:     const char *lname;
2253:     PetscBool   isDepth, isCellType;

2255:     PetscCall(DMGetLabelName(dm, l, &lname));
2256:     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
2257:     if (isDepth) continue;
2258:     PetscCall(PetscStrcmp(lname, "celltype", &isCellType));
2259:     if (isCellType) continue;
2260:     PetscCall(DMCreateLabel(rdm, lname));
2261:     PetscCall(DMGetLabel(dm, lname, &label));
2262:     PetscCall(DMGetLabel(rdm, lname, &labelNew));
2263:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
2264:   }
2265:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateLabels, tr, dm, 0, 0));
2266:   PetscFunctionReturn(PETSC_SUCCESS);
2267: }

2269: /*@
2270:   DMPlexTransformCreateDiscLabels - Refine the labels which define field and discrete system regions on the transformed `DM`

2272:   Not Collective

2274:   Input Parameters:
2275: + tr  - The `DMPlexTransform`
2276: - rdm - The refined `DM` produced by the transform

2278:   Level: developer

2280:   Note:
2281:   Region labels attached to fields (see `DMSetField()`) and to discrete systems (see `DMSetRegionNumDS()`) are
2282:   not automatically included in the list of `DM` labels, so this routine walks each field and each `PetscDS`
2283:   and updates the labels to refer to the refined points.

2285: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMSetField()`, `DMSetRegionNumDS()`
2286: @*/
2287: /* This refines the labels which define regions for fields and DSes since they are not in the list of labels for the DM */
2288: PetscErrorCode DMPlexTransformCreateDiscLabels(DMPlexTransform tr, DM rdm)
2289: {
2290:   DM       dm;
2291:   PetscInt Nf, f, Nds, s;

2293:   PetscFunctionBegin;
2294:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2295:   PetscCall(DMGetNumFields(dm, &Nf));
2296:   for (f = 0; f < Nf; ++f) {
2297:     DMLabel     label, labelNew;
2298:     PetscObject obj;
2299:     const char *lname;

2301:     PetscCall(DMGetField(rdm, f, &label, &obj));
2302:     if (!label) continue;
2303:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
2304:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew));
2305:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
2306:     PetscCall(DMSetField_Internal(rdm, f, labelNew, obj));
2307:     PetscCall(DMLabelDestroy(&labelNew));
2308:   }
2309:   PetscCall(DMGetNumDS(dm, &Nds));
2310:   for (s = 0; s < Nds; ++s) {
2311:     DMLabel     label, labelNew;
2312:     const char *lname;

2314:     PetscCall(DMGetRegionNumDS(rdm, s, &label, NULL, NULL, NULL));
2315:     if (!label) continue;
2316:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
2317:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew));
2318:     PetscCall(RefineLabel_Internal(tr, label, labelNew));
2319:     PetscCall(DMSetRegionNumDS(rdm, s, labelNew, NULL, NULL, NULL));
2320:     PetscCall(DMLabelDestroy(&labelNew));
2321:   }
2322:   PetscFunctionReturn(PETSC_SUCCESS);
2323: }

2325: static PetscErrorCode DMPlexTransformCreateSF(DMPlexTransform tr, DM rdm)
2326: {
2327:   DM                 dm;
2328:   PetscSF            sf, sfNew;
2329:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
2330:   const PetscInt    *localPoints;
2331:   const PetscSFNode *remotePoints;
2332:   PetscInt          *localPointsNew;
2333:   PetscSFNode       *remotePointsNew;
2334:   PetscInt           pStartNew, pEndNew, pNew;
2335:   /* Brute force algorithm */
2336:   PetscSF         rsf;
2337:   PetscSection    s;
2338:   const PetscInt *rootdegree;
2339:   PetscInt       *rootPointsNew, *remoteOffsets;
2340:   PetscInt        numPointsNew, pStart, pEnd, p;

2342:   PetscFunctionBegin;
2343:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2344:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0));
2345:   PetscCall(DMPlexGetChart(rdm, &pStartNew, &pEndNew));
2346:   PetscCall(DMGetPointSF(dm, &sf));
2347:   PetscCall(DMGetPointSF(rdm, &sfNew));
2348:   /* Calculate size of new SF */
2349:   PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints));
2350:   if (numRoots < 0) {
2351:     PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0));
2352:     PetscFunctionReturn(PETSC_SUCCESS);
2353:   }
2354:   for (l = 0; l < numLeaves; ++l) {
2355:     const PetscInt  p = localPoints ? localPoints[l] : l;
2356:     DMPolytopeType  ct;
2357:     DMPolytopeType *rct;
2358:     PetscInt       *rsize, *rcone, *rornt;
2359:     PetscInt        Nct, n;

2361:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2362:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2363:     for (n = 0; n < Nct; ++n) numLeavesNew += rsize[n];
2364:   }
2365:   /* Send new root point numbers
2366:        It is possible to optimize for regular transforms by sending only the cell type offsets, but it seems a needless complication
2367:   */
2368:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
2369:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &s));
2370:   PetscCall(PetscSectionSetChart(s, pStart, pEnd));
2371:   for (p = pStart; p < pEnd; ++p) {
2372:     DMPolytopeType  ct;
2373:     DMPolytopeType *rct;
2374:     PetscInt       *rsize, *rcone, *rornt;
2375:     PetscInt        Nct, n;

2377:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2378:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2379:     for (n = 0; n < Nct; ++n) PetscCall(PetscSectionAddDof(s, p, rsize[n]));
2380:   }
2381:   PetscCall(PetscSectionSetUp(s));
2382:   PetscCall(PetscSectionGetStorageSize(s, &numPointsNew));
2383:   PetscCall(PetscSFCreateRemoteOffsets(sf, s, s, &remoteOffsets));
2384:   PetscCall(PetscSFCreateSectionSF(sf, s, remoteOffsets, s, &rsf));
2385:   PetscCall(PetscFree(remoteOffsets));
2386:   PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree));
2387:   PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree));
2388:   PetscCall(PetscMalloc1(numPointsNew, &rootPointsNew));
2389:   for (p = 0; p < numPointsNew; ++p) rootPointsNew[p] = -1;
2390:   for (p = pStart; p < pEnd; ++p) {
2391:     DMPolytopeType  ct;
2392:     DMPolytopeType *rct;
2393:     PetscInt       *rsize, *rcone, *rornt;
2394:     PetscInt        Nct, n, r, off;

2396:     if (!rootdegree[p - pStart]) continue;
2397:     PetscCall(PetscSectionGetOffset(s, p, &off));
2398:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2399:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2400:     for (n = 0, m = 0; n < Nct; ++n) {
2401:       for (r = 0; r < rsize[n]; ++r, ++m) {
2402:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
2403:         rootPointsNew[off + m] = pNew;
2404:       }
2405:     }
2406:   }
2407:   PetscCall(PetscSFBcastBegin(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE));
2408:   PetscCall(PetscSFBcastEnd(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE));
2409:   PetscCall(PetscSFDestroy(&rsf));
2410:   PetscCall(PetscMalloc1(numLeavesNew, &localPointsNew));
2411:   PetscCall(PetscMalloc1(numLeavesNew, &remotePointsNew));
2412:   for (l = 0, m = 0; l < numLeaves; ++l) {
2413:     const PetscInt  p = localPoints ? localPoints[l] : l;
2414:     DMPolytopeType  ct;
2415:     DMPolytopeType *rct;
2416:     PetscInt       *rsize, *rcone, *rornt;
2417:     PetscInt        Nct, n, r, q, off;

2419:     PetscCall(PetscSectionGetOffset(s, p, &off));
2420:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2421:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2422:     for (n = 0, q = 0; n < Nct; ++n) {
2423:       for (r = 0; r < rsize[n]; ++r, ++m, ++q) {
2424:         PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
2425:         localPointsNew[m]        = pNew;
2426:         remotePointsNew[m].index = rootPointsNew[off + q];
2427:         remotePointsNew[m].rank  = remotePoints[l].rank;
2428:       }
2429:     }
2430:   }
2431:   PetscCall(PetscSectionDestroy(&s));
2432:   PetscCall(PetscFree(rootPointsNew));
2433:   /* SF needs sorted leaves to correctly calculate Gather */
2434:   {
2435:     PetscSFNode *rp, *rtmp;
2436:     PetscInt    *lp, *idx, *ltmp, i;

2438:     PetscCall(PetscMalloc1(numLeavesNew, &idx));
2439:     PetscCall(PetscMalloc1(numLeavesNew, &lp));
2440:     PetscCall(PetscMalloc1(numLeavesNew, &rp));
2441:     for (i = 0; i < numLeavesNew; ++i) {
2442:       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);
2443:       idx[i] = i;
2444:     }
2445:     PetscCall(PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx));
2446:     for (i = 0; i < numLeavesNew; ++i) {
2447:       lp[i] = localPointsNew[idx[i]];
2448:       rp[i] = remotePointsNew[idx[i]];
2449:     }
2450:     ltmp            = localPointsNew;
2451:     localPointsNew  = lp;
2452:     rtmp            = remotePointsNew;
2453:     remotePointsNew = rp;
2454:     PetscCall(PetscFree(idx));
2455:     PetscCall(PetscFree(ltmp));
2456:     PetscCall(PetscFree(rtmp));
2457:   }
2458:   PetscCall(PetscSFSetGraph(sfNew, pEndNew - pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER));
2459:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0));
2460:   if (PetscDefined(USE_DEBUG)) {
2461:     PetscInt overlap;

2463:     // Need to set overlap because some transforms put cells in the overlap
2464:     PetscCall(DMPlexGetOverlap(rdm, &overlap));
2465:     PetscCall(DMPlexSetOverlap(rdm, NULL, 1));
2466:     PetscCall(DMPlexCheckPointSF(rdm, sfNew, PETSC_FALSE));
2467:     PetscCall(DMPlexSetOverlap(rdm, NULL, overlap));
2468:   }
2469:   PetscFunctionReturn(PETSC_SUCCESS);
2470: }

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

2475:   Not Collective

2477:   Input Parameters:
2478: + tr  - The `DMPlexTransform`
2479: . ct  - The type of the parent cell
2480: . rct - The type of the produced cell
2481: . r   - The index of the produced cell
2482: - x   - The localized coordinates for the parent cell

2484:   Output Parameter:
2485: . xr  - The localized coordinates for the produced cell

2487:   Level: developer

2489: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexCellRefinerSetCoordinates()`
2490: */
2491: static PetscErrorCode DMPlexTransformMapLocalizedCoordinates(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, const PetscScalar x[], PetscScalar xr[])
2492: {
2493:   PetscFE  fe = NULL;
2494:   PetscInt cdim, v, *subcellV;

2496:   PetscFunctionBegin;
2497:   PetscCall(DMPlexTransformGetCoordinateFE(tr, ct, &fe));
2498:   PetscCall(DMPlexTransformGetSubcellVertices(tr, ct, rct, r, &subcellV));
2499:   PetscCall(PetscFEGetNumComponents(fe, &cdim));
2500:   for (v = 0; v < DMPolytopeTypeGetNumVertices(rct); ++v) PetscCall(PetscFEInterpolate_Static(fe, x, tr->refGeom[ct], subcellV[v], &xr[v * cdim]));
2501:   PetscFunctionReturn(PETSC_SUCCESS);
2502: }

2504: static PetscErrorCode DMPlexTransformSetCoordinates(DMPlexTransform tr, DM rdm)
2505: {
2506:   DM                 dm, cdm, cdmCell, cdmNew, cdmCellNew;
2507:   PetscSection       coordSection, coordSectionNew, coordSectionCell, coordSectionCellNew;
2508:   Vec                coordsLocal, coordsLocalNew, coordsLocalCell = NULL, coordsLocalCellNew;
2509:   const PetscScalar *coords;
2510:   PetscScalar       *coordsNew;
2511:   const PetscReal   *maxCell, *Lstart, *L;
2512:   PetscBool          localized, localizeVertices = PETSC_FALSE, localizeCells = PETSC_FALSE, sparseLocalize;
2513:   PetscInt           dE, dEo, d, cStart, cEnd, c, cStartNew, cEndNew, vStartNew, vEndNew, v, pStart, pEnd, p;

2515:   PetscFunctionBegin;
2516:   // Need to clear the DMField for coordinates
2517:   PetscCall(DMSetCoordinateField(rdm, NULL));
2518:   PetscCall(DMPlexTransformGetDM(tr, &dm));
2519:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetCoordinates, tr, dm, 0, 0));
2520:   PetscCall(DMGetCoordinateDM(dm, &cdm));
2521:   PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
2522:   PetscCall(DMGetCoordinatesLocalized(dm, &localized));
2523:   PetscCall(DMGetSparseLocalize(dm, &sparseLocalize));
2524:   PetscCall(DMSetSparseLocalize(rdm, sparseLocalize));
2525:   PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
2526:   if (localized) {
2527:     /* Localize coordinates of new vertices */
2528:     localizeVertices = PETSC_TRUE;
2529:     /* If we do not have a mechanism for automatically localizing cell coordinates, we need to compute them explicitly for every divided cell */
2530:     if (!maxCell) localizeCells = PETSC_TRUE;
2531:   }
2532:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
2533:   PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &dEo));
2534:   PetscCall(DMGetCoordinateDim(rdm, &dE));
2535:   if (maxCell) {
2536:     PetscReal *LstartNew, *LNew, *maxCellNew;

2538:     PetscCall(PetscMalloc3(dE, &LstartNew, dE, &LNew, dE, &maxCellNew));
2539:     for (d = 0; d < dEo; ++d) {
2540:       LstartNew[d]  = Lstart[d];
2541:       LNew[d]       = L[d];
2542:       maxCellNew[d] = maxCell[d] / tr->redFactor;
2543:     }
2544:     for (d = dEo; d < dE; ++d) {
2545:       LstartNew[d]  = 0.;
2546:       LNew[d]       = -1.;
2547:       maxCellNew[d] = -1.;
2548:     }
2549:     PetscCall(DMSetPeriodicity(rdm, maxCellNew, LstartNew, LNew));
2550:     PetscCall(PetscFree3(LstartNew, LNew, maxCellNew));
2551:   }
2552:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionNew));
2553:   PetscCall(PetscSectionSetNumFields(coordSectionNew, 1));
2554:   PetscCall(PetscSectionSetFieldComponents(coordSectionNew, 0, dE));
2555:   PetscCall(DMPlexGetDepthStratum(rdm, 0, &vStartNew, &vEndNew));
2556:   PetscCall(PetscSectionSetChart(coordSectionNew, vStartNew, vEndNew));
2557:   /* Localization should be inherited */
2558:   /*   Stefano calculates parent cells for each new cell for localization */
2559:   /*   Localized cells need coordinates of closure */
2560:   for (v = vStartNew; v < vEndNew; ++v) {
2561:     PetscCall(PetscSectionSetDof(coordSectionNew, v, dE));
2562:     PetscCall(PetscSectionSetFieldDof(coordSectionNew, v, 0, dE));
2563:   }
2564:   PetscCall(PetscSectionSetUp(coordSectionNew));
2565:   PetscCall(DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew));

2567:   if (localizeCells) {
2568:     PetscCall(DMGetCoordinateDM(rdm, &cdmNew));
2569:     PetscCall(DMClone(cdmNew, &cdmCellNew));
2570:     PetscCall(DMSetCellCoordinateDM(rdm, cdmCellNew));
2571:     PetscCall(DMDestroy(&cdmCellNew));

2573:     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionCellNew));
2574:     PetscCall(PetscSectionSetNumFields(coordSectionCellNew, 1));
2575:     PetscCall(PetscSectionSetFieldComponents(coordSectionCellNew, 0, dE));
2576:     PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStartNew, &cEndNew));
2577:     PetscCall(PetscSectionSetChart(coordSectionCellNew, cStartNew, cEndNew));

2579:     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
2580:     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2581:     for (c = cStart; c < cEnd; ++c) {
2582:       PetscInt dof;

2584:       PetscCall(PetscSectionGetDof(coordSectionCell, c, &dof));
2585:       if (dof) {
2586:         DMPolytopeType  ct;
2587:         DMPolytopeType *rct;
2588:         PetscInt       *rsize, *rcone, *rornt;
2589:         PetscInt        dim, cNew, Nct, n, r;

2591:         PetscCall(DMPlexGetCellType(dm, c, &ct));
2592:         dim = DMPolytopeTypeGetDim(ct);
2593:         PetscCall(DMPlexTransformCellTransform(tr, ct, c, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2594:         /* This allows for different cell types */
2595:         for (n = 0; n < Nct; ++n) {
2596:           if (dim != DMPolytopeTypeGetDim(rct[n])) continue;
2597:           for (r = 0; r < rsize[n]; ++r) {
2598:             PetscInt *closure = NULL;
2599:             PetscInt  clSize, cl, Nv = 0;

2601:             PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], c, r, &cNew));
2602:             PetscCall(DMPlexGetTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure));
2603:             for (cl = 0; cl < clSize * 2; cl += 2) {
2604:               if ((closure[cl] >= vStartNew) && (closure[cl] < vEndNew)) ++Nv;
2605:             }
2606:             PetscCall(DMPlexRestoreTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure));
2607:             PetscCall(PetscSectionSetDof(coordSectionCellNew, cNew, Nv * dE));
2608:             PetscCall(PetscSectionSetFieldDof(coordSectionCellNew, cNew, 0, Nv * dE));
2609:           }
2610:         }
2611:       }
2612:     }
2613:     PetscCall(PetscSectionSetUp(coordSectionCellNew));
2614:     PetscCall(DMSetCellCoordinateSection(rdm, PETSC_DETERMINE, coordSectionCellNew));
2615:   }
2616:   PetscCall(DMViewFromOptions(dm, NULL, "-coarse_dm_view"));
2617:   {
2618:     VecType     vtype;
2619:     PetscInt    coordSizeNew, bs;
2620:     const char *name;

2622:     PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
2623:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalNew));
2624:     PetscCall(PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew));
2625:     PetscCall(VecSetSizes(coordsLocalNew, coordSizeNew, PETSC_DETERMINE));
2626:     PetscCall(PetscObjectGetName((PetscObject)coordsLocal, &name));
2627:     PetscCall(PetscObjectSetName((PetscObject)coordsLocalNew, name));
2628:     PetscCall(VecGetBlockSize(coordsLocal, &bs));
2629:     PetscCall(VecSetBlockSize(coordsLocalNew, dEo == dE ? bs : dE));
2630:     PetscCall(VecGetType(coordsLocal, &vtype));
2631:     PetscCall(VecSetType(coordsLocalNew, vtype));
2632:   }
2633:   PetscCall(VecGetArrayRead(coordsLocal, &coords));
2634:   PetscCall(VecGetArray(coordsLocalNew, &coordsNew));
2635:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
2636:   /* First set coordinates for vertices */
2637:   for (p = pStart; p < pEnd; ++p) {
2638:     DMPolytopeType  ct;
2639:     DMPolytopeType *rct;
2640:     PetscInt       *rsize, *rcone, *rornt;
2641:     PetscInt        Nct, n, r;
2642:     PetscBool       hasVertex = PETSC_FALSE;

2644:     PetscCall(DMPlexGetCellType(dm, p, &ct));
2645:     PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2646:     for (n = 0; n < Nct; ++n) {
2647:       if (rct[n] == DM_POLYTOPE_POINT) {
2648:         hasVertex = PETSC_TRUE;
2649:         break;
2650:       }
2651:     }
2652:     if (hasVertex) {
2653:       const PetscScalar *icoords = NULL;
2654:       const PetscScalar *array   = NULL;
2655:       PetscScalar       *pcoords = NULL;
2656:       PetscBool          isDG;
2657:       PetscInt           Nc, Nv, v, d;

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

2661:       icoords = pcoords;
2662:       Nv      = Nc / dEo;
2663:       if (ct != DM_POLYTOPE_POINT) {
2664:         if (localizeVertices && maxCell) {
2665:           PetscScalar anchor[3];

2667:           for (d = 0; d < dEo; ++d) anchor[d] = pcoords[d];
2668:           for (v = 0; v < Nv; ++v) PetscCall(DMLocalizeCoordinate_Internal(dm, dEo, anchor, &pcoords[v * dEo], &pcoords[v * dEo]));
2669:         }
2670:       }
2671:       for (n = 0; n < Nct; ++n) {
2672:         if (rct[n] != DM_POLYTOPE_POINT) continue;
2673:         for (r = 0; r < rsize[n]; ++r) {
2674:           PetscScalar vcoords[3];
2675:           PetscInt    vNew, off;

2677:           PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &vNew));
2678:           PetscCall(PetscSectionGetOffset(coordSectionNew, vNew, &off));
2679:           PetscCall(DMPlexTransformMapCoordinates(tr, ct, rct[n], p, r, Nv, dEo, icoords, vcoords));
2680:           PetscCall(DMSnapToGeomModel(dm, p, dE, vcoords, &coordsNew[off]));
2681:         }
2682:       }
2683:       PetscCall(DMPlexRestoreCellCoordinates(dm, p, &isDG, &Nc, &array, &pcoords));
2684:     }
2685:   }
2686:   PetscCall(VecRestoreArrayRead(coordsLocal, &coords));
2687:   PetscCall(VecRestoreArray(coordsLocalNew, &coordsNew));
2688:   PetscCall(DMSetCoordinatesLocal(rdm, coordsLocalNew));
2689:   PetscCall(VecDestroy(&coordsLocalNew));
2690:   PetscCall(PetscSectionDestroy(&coordSectionNew));
2691:   /* Then set coordinates for cells by localizing */
2692:   if (!localizeCells) PetscCall(DMLocalizeCoordinates(rdm));
2693:   else {
2694:     VecType     vtype;
2695:     PetscInt    coordSizeNew, bs;
2696:     const char *name;

2698:     PetscCall(DMGetCellCoordinatesLocal(dm, &coordsLocalCell));
2699:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalCellNew));
2700:     PetscCall(PetscSectionGetStorageSize(coordSectionCellNew, &coordSizeNew));
2701:     PetscCall(VecSetSizes(coordsLocalCellNew, coordSizeNew, PETSC_DETERMINE));
2702:     PetscCall(PetscObjectGetName((PetscObject)coordsLocalCell, &name));
2703:     PetscCall(PetscObjectSetName((PetscObject)coordsLocalCellNew, name));
2704:     PetscCall(VecGetBlockSize(coordsLocalCell, &bs));
2705:     PetscCall(VecSetBlockSize(coordsLocalCellNew, dEo == dE ? bs : dE));
2706:     PetscCall(VecGetType(coordsLocalCell, &vtype));
2707:     PetscCall(VecSetType(coordsLocalCellNew, vtype));
2708:     PetscCall(VecGetArrayRead(coordsLocalCell, &coords));
2709:     PetscCall(VecGetArray(coordsLocalCellNew, &coordsNew));

2711:     for (p = pStart; p < pEnd; ++p) {
2712:       DMPolytopeType  ct;
2713:       DMPolytopeType *rct;
2714:       PetscInt       *rsize, *rcone, *rornt;
2715:       PetscInt        dof = 0, Nct, n, r;

2717:       PetscCall(DMPlexGetCellType(dm, p, &ct));
2718:       PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
2719:       if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
2720:       if (dof) {
2721:         const PetscScalar *pcoords;

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

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

2731:             /* It looks like Stefano and Lisandro are allowing localized coordinates without defining the periodic boundary, which means that
2732:                DMLocalizeCoordinate_Internal() will not work. Localized coordinates will have to have obtained by the affine map of the larger
2733:                cell to the ones it produces. */
2734:             PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew));
2735:             PetscCall(PetscSectionGetOffset(coordSectionCellNew, pNew, &offNew));
2736:             PetscCall(DMPlexTransformMapLocalizedCoordinates(tr, ct, rct[n], r, pcoords, &coordsNew[offNew]));
2737:           }
2738:         }
2739:       }
2740:     }
2741:     PetscCall(VecRestoreArrayRead(coordsLocalCell, &coords));
2742:     PetscCall(VecRestoreArray(coordsLocalCellNew, &coordsNew));
2743:     PetscCall(DMSetCellCoordinatesLocal(rdm, coordsLocalCellNew));
2744:     PetscCall(VecDestroy(&coordsLocalCellNew));
2745:     PetscCall(PetscSectionDestroy(&coordSectionCellNew));
2746:   }
2747:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetCoordinates, tr, dm, 0, 0));
2748:   PetscFunctionReturn(PETSC_SUCCESS);
2749: }

2751: /*@
2752:   DMPlexTransformApply - Execute the transformation, producing another `DM`

2754:   Collective

2756:   Input Parameters:
2757: + tr - The `DMPlexTransform` object
2758: - dm - The original `DM`

2760:   Output Parameter:
2761: . trdm - The transformed `DM`

2763:   Level: intermediate

2765:   Options Database Keys:
2766: + -dm_plex_transform_label_match_strata    - Only label points of the same stratum as the producing point
2767: . -dm_plex_transform_label_replica_inc num - Increment for the label value to be multiplied by the replica number
2768: - -dm_plex_transform_active name           - Name for active mesh label

2770: .seealso: [](plex_transform_table), [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformCreate()`, `DMPlexTransformSetDM()`
2771: @*/
2772: PetscErrorCode DMPlexTransformApply(DMPlexTransform tr, DM dm, DM *trdm)
2773: {
2774:   DM                     rdm;
2775:   DMPlexInterpolatedFlag interp;
2776:   PetscInt               pStart, pEnd;

2778:   PetscFunctionBegin;
2781:   PetscAssertPointer(trdm, 3);
2782:   PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_Apply, tr, dm, 0, 0));
2783:   PetscCall(DMPlexTransformSetDM(tr, dm));

2785:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &rdm));
2786:   PetscCall(DMSetType(rdm, DMPLEX));
2787:   PetscCall(DMPlexTransformSetDimensions(tr, dm, rdm));
2788:   /* Calculate number of new points of each depth */
2789:   PetscCall(DMPlexIsInterpolatedCollective(dm, &interp));
2790:   PetscCheck(interp == DMPLEX_INTERPOLATED_FULL, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be fully interpolated for regular refinement");
2791:   /* Step 1: Set chart */
2792:   PetscCall(DMPlexTransformGetChart(tr, &pStart, &pEnd));
2793:   PetscCall(DMPlexSetChart(rdm, pStart, pEnd));
2794:   /* Step 2: Set cone/support sizes (automatically stratifies) */
2795:   PetscCall(DMPlexTransformSetConeSizes(tr, rdm));
2796:   /* Step 3: Setup refined DM */
2797:   PetscCall(DMSetUp(rdm));
2798:   /* Step 4: Set cones and supports (automatically symmetrizes) */
2799:   PetscCall(DMPlexTransformSetCones(tr, rdm));
2800:   /* Step 5: Create pointSF */
2801:   PetscCall(DMPlexTransformCreateSF(tr, rdm));
2802:   /* Step 6: Create labels */
2803:   PetscCall(DMPlexTransformCreateLabels(tr, rdm));
2804:   /* Step 7: Set coordinates */
2805:   PetscCall(DMPlexTransformSetCoordinates(tr, rdm));
2806:   //   Do not copy periodicity, which was handled in DMPlexTransformSetCoordinates()
2807:   PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_TRUE, rdm));
2808:   // If the original DM was configured from options, the transformed DM should be as well
2809:   rdm->setfromoptionscalled = dm->setfromoptionscalled;
2810:   PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_Apply, tr, dm, 0, 0));
2811:   *trdm = rdm;
2812:   PetscFunctionReturn(PETSC_SUCCESS);
2813: }

2815: /*@
2816:   DMPlexTransformAdaptLabel - Adapt a `DMPLEX` using a `DMPlexTransform` driven by a `DMLabel` marking cells to be refined or coarsened.

2818:   Collective

2820:   Input Parameters:
2821: + dm         - the input `DMPLEX`
2822: . metric     - unused; present to conform to the `DMAdaptor` label-based interface
2823: . adaptLabel - a `DMLabel` marking cells with `DM_ADAPT_REFINE`, `DM_ADAPT_COARSEN`, etc.
2824: - rgLabel    - unused region-tag label; present to conform to the `DMAdaptor` interface

2826:   Output Parameter:
2827: . rdm - the adapted `DMPLEX`

2829:   Level: developer

2831:   Note:
2832:   This routine is registered as the "cellrefiner" adaptor by `DMGenerateRegisterAll()` and is invoked through `DMAdaptLabel()`.

2834: .seealso: `DMPLEX`, `DMPlexTransform`, `DMAdaptLabel()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()`, `DMLabel`
2835: @*/
2836: PetscErrorCode DMPlexTransformAdaptLabel(DM dm, PETSC_UNUSED Vec metric, DMLabel adaptLabel, PETSC_UNUSED DMLabel rgLabel, DM *rdm)
2837: {
2838:   DMPlexTransform tr;
2839:   DM              cdm, rcdm;
2840:   const char     *prefix;
2841:   PetscBool       save;

2843:   PetscFunctionBegin;
2844:   PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr));
2845:   PetscCall(PetscObjectSetName((PetscObject)tr, "Adapt Label Transform"));
2846:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
2847:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix));
2848:   PetscCall(DMPlexTransformSetDM(tr, dm));
2849:   PetscCall(DMPlexTransformSetFromOptions(tr));
2850:   if (adaptLabel) PetscCall(DMPlexTransformSetActive(tr, adaptLabel));
2851:   PetscCall(DMPlexTransformSetUp(tr));
2852:   PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_transform_view"));
2853:   PetscCall(DMPlexTransformApply(tr, dm, rdm));
2854:   PetscCall(DMCopyDisc(dm, *rdm));
2855:   PetscCall(DMGetCoordinateDM(dm, &cdm));
2856:   PetscCall(DMGetCoordinateDM(*rdm, &rcdm));
2857:   PetscCall(DMCopyDisc(cdm, rcdm));
2858:   PetscCall(DMPlexTransformCreateDiscLabels(tr, *rdm));
2859:   PetscCall(DMCopyDisc(dm, *rdm));
2860:   PetscCall(DMPlexGetSaveTransform(dm, &save));
2861:   if (save) PetscCall(DMPlexSetTransform(*rdm, tr));
2862:   PetscCall(DMPlexTransformDestroy(&tr));
2863:   ((DM_Plex *)(*rdm)->data)->useHashLocation = ((DM_Plex *)dm->data)->useHashLocation;
2864:   PetscFunctionReturn(PETSC_SUCCESS);
2865: }