xref: /petsc/src/dm/interface/dmperiodicity.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
16858538eSMatthew G. Knepley #include <petsc/private/dmimpl.h> /*I      "petscdm.h"          I*/
26858538eSMatthew G. Knepley 
36858538eSMatthew G. Knepley #include <petscdmplex.h>
46858538eSMatthew G. Knepley 
56858538eSMatthew G. Knepley /*@C
66858538eSMatthew G. Knepley   DMGetPeriodicity - Get the description of mesh periodicity
76858538eSMatthew G. Knepley 
86858538eSMatthew G. Knepley   Input Parameter:
96858538eSMatthew G. Knepley . dm      - The DM object
106858538eSMatthew G. Knepley 
116858538eSMatthew G. Knepley   Output Parameters:
126858538eSMatthew G. Knepley + maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
134fb89dddSMatthew G. Knepley . Lstart  - If we assume the mesh is a torus, this is the start of each coordinate, or NULL for 0.0
146858538eSMatthew G. Knepley - L       - If we assume the mesh is a torus, this is the length of each coordinate, otherwise it is < 0.0
156858538eSMatthew G. Knepley 
166858538eSMatthew G. Knepley   Level: developer
176858538eSMatthew G. Knepley 
186858538eSMatthew G. Knepley .seealso: `DMGetPeriodicity()`
196858538eSMatthew G. Knepley @*/
20*9371c9d4SSatish Balay PetscErrorCode DMGetPeriodicity(DM dm, const PetscReal **maxCell, const PetscReal **Lstart, const PetscReal **L) {
216858538eSMatthew G. Knepley   PetscFunctionBegin;
226858538eSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
236858538eSMatthew G. Knepley   if (maxCell) *maxCell = dm->maxCell;
244fb89dddSMatthew G. Knepley   if (Lstart) *Lstart = dm->Lstart;
254fb89dddSMatthew G. Knepley   if (L) *L = dm->L;
266858538eSMatthew G. Knepley   PetscFunctionReturn(0);
276858538eSMatthew G. Knepley }
286858538eSMatthew G. Knepley 
296858538eSMatthew G. Knepley /*@C
306858538eSMatthew G. Knepley   DMSetPeriodicity - Set the description of mesh periodicity
316858538eSMatthew G. Knepley 
326858538eSMatthew G. Knepley   Input Parameters:
336858538eSMatthew G. Knepley + dm      - The DM object
346858538eSMatthew G. Knepley . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates. Pass NULL to remove such information.
354fb89dddSMatthew G. Knepley . Lstart  - If we assume the mesh is a torus, this is the start of each coordinate, or NULL for 0.0
366858538eSMatthew G. Knepley - L       - If we assume the mesh is a torus, this is the length of each coordinate, otherwise it is < 0.0
376858538eSMatthew G. Knepley 
386858538eSMatthew G. Knepley   Level: developer
396858538eSMatthew G. Knepley 
406858538eSMatthew G. Knepley .seealso: `DMGetPeriodicity()`
416858538eSMatthew G. Knepley @*/
42*9371c9d4SSatish Balay PetscErrorCode DMSetPeriodicity(DM dm, const PetscReal maxCell[], const PetscReal Lstart[], const PetscReal L[]) {
436858538eSMatthew G. Knepley   PetscInt dim, d;
446858538eSMatthew G. Knepley 
456858538eSMatthew G. Knepley   PetscFunctionBegin;
466858538eSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
476858538eSMatthew G. Knepley   if (maxCell) { PetscValidRealPointer(maxCell, 2); }
484fb89dddSMatthew G. Knepley   if (Lstart) { PetscValidRealPointer(Lstart, 3); }
494fb89dddSMatthew G. Knepley   if (L) { PetscValidRealPointer(L, 4); }
506858538eSMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
516858538eSMatthew G. Knepley   if (maxCell) {
526858538eSMatthew G. Knepley     if (!dm->maxCell) PetscCall(PetscMalloc1(dim, &dm->maxCell));
536858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
546858538eSMatthew G. Knepley   } else { /* remove maxCell information to disable automatic computation of localized vertices */
556858538eSMatthew G. Knepley     PetscCall(PetscFree(dm->maxCell));
566858538eSMatthew G. Knepley     dm->maxCell = NULL;
576858538eSMatthew G. Knepley   }
584fb89dddSMatthew G. Knepley   if (Lstart) {
594fb89dddSMatthew G. Knepley     if (!dm->Lstart) PetscCall(PetscMalloc1(dim, &dm->Lstart));
604fb89dddSMatthew G. Knepley     for (d = 0; d < dim; ++d) dm->Lstart[d] = Lstart[d];
614fb89dddSMatthew G. Knepley   } else { /* remove L information to disable automatic computation of localized vertices */
624fb89dddSMatthew G. Knepley     PetscCall(PetscFree(dm->Lstart));
634fb89dddSMatthew G. Knepley     dm->Lstart = NULL;
644fb89dddSMatthew G. Knepley   }
656858538eSMatthew G. Knepley   if (L) {
666858538eSMatthew G. Knepley     if (!dm->L) PetscCall(PetscMalloc1(dim, &dm->L));
676858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
686858538eSMatthew G. Knepley   } else { /* remove L information to disable automatic computation of localized vertices */
696858538eSMatthew G. Knepley     PetscCall(PetscFree(dm->L));
706858538eSMatthew G. Knepley     dm->L = NULL;
716858538eSMatthew G. Knepley   }
726858538eSMatthew G. Knepley   PetscCheck((dm->maxCell && dm->L) || (!dm->maxCell && !dm->L), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot set only one of maxCell/L");
736858538eSMatthew G. Knepley   PetscFunctionReturn(0);
746858538eSMatthew G. Knepley }
756858538eSMatthew G. Knepley 
766858538eSMatthew G. Knepley /*@
776858538eSMatthew G. Knepley   DMLocalizeCoordinate - If a mesh is periodic (a torus with lengths L_i, some of which can be infinite), project the coordinate onto [0, L_i) in each dimension.
786858538eSMatthew G. Knepley 
796858538eSMatthew G. Knepley   Input Parameters:
806858538eSMatthew G. Knepley + dm     - The DM
816858538eSMatthew G. Knepley . in     - The input coordinate point (dim numbers)
826858538eSMatthew G. Knepley - endpoint - Include the endpoint L_i
836858538eSMatthew G. Knepley 
846858538eSMatthew G. Knepley   Output Parameter:
856858538eSMatthew G. Knepley . out - The localized coordinate point
866858538eSMatthew G. Knepley 
876858538eSMatthew G. Knepley   Level: developer
886858538eSMatthew G. Knepley 
896858538eSMatthew G. Knepley .seealso: `DMLocalizeCoordinates()`, `DMLocalizeAddCoordinate()`
906858538eSMatthew G. Knepley @*/
91*9371c9d4SSatish Balay PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[]) {
926858538eSMatthew G. Knepley   PetscInt dim, d;
936858538eSMatthew G. Knepley 
946858538eSMatthew G. Knepley   PetscFunctionBegin;
956858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDim(dm, &dim));
966858538eSMatthew G. Knepley   if (!dm->maxCell) {
976858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) out[d] = in[d];
986858538eSMatthew G. Knepley   } else {
996858538eSMatthew G. Knepley     if (endpoint) {
1006858538eSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
1016858538eSMatthew G. Knepley         if ((PetscAbsReal(PetscRealPart(in[d]) / dm->L[d] - PetscFloorReal(PetscRealPart(in[d]) / dm->L[d])) < PETSC_SMALL) && (PetscRealPart(in[d]) / dm->L[d] > PETSC_SMALL)) {
1026858538eSMatthew G. Knepley           out[d] = in[d] - dm->L[d] * (PetscFloorReal(PetscRealPart(in[d]) / dm->L[d]) - 1);
1036858538eSMatthew G. Knepley         } else {
1046858538eSMatthew G. Knepley           out[d] = in[d] - dm->L[d] * PetscFloorReal(PetscRealPart(in[d]) / dm->L[d]);
1056858538eSMatthew G. Knepley         }
1066858538eSMatthew G. Knepley       }
1076858538eSMatthew G. Knepley     } else {
108*9371c9d4SSatish Balay       for (d = 0; d < dim; ++d) { out[d] = in[d] - dm->L[d] * PetscFloorReal(PetscRealPart(in[d]) / dm->L[d]); }
1096858538eSMatthew G. Knepley     }
1106858538eSMatthew G. Knepley   }
1116858538eSMatthew G. Knepley   PetscFunctionReturn(0);
1126858538eSMatthew G. Knepley }
1136858538eSMatthew G. Knepley 
1146858538eSMatthew G. Knepley /*
1156858538eSMatthew G. Knepley   DMLocalizeCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer.
1166858538eSMatthew G. Knepley 
1176858538eSMatthew G. Knepley   Input Parameters:
1186858538eSMatthew G. Knepley + dm     - The DM
1196858538eSMatthew G. Knepley . dim    - The spatial dimension
1206858538eSMatthew G. Knepley . anchor - The anchor point, the input point can be no more than maxCell away from it
1216858538eSMatthew G. Knepley - in     - The input coordinate point (dim numbers)
1226858538eSMatthew G. Knepley 
1236858538eSMatthew G. Knepley   Output Parameter:
1246858538eSMatthew G. Knepley . out - The localized coordinate point
1256858538eSMatthew G. Knepley 
1266858538eSMatthew G. Knepley   Level: developer
1276858538eSMatthew G. Knepley 
1286858538eSMatthew G. Knepley   Note: This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell
1296858538eSMatthew G. Knepley 
1306858538eSMatthew G. Knepley .seealso: `DMLocalizeCoordinates()`, `DMLocalizeAddCoordinate()`
1316858538eSMatthew G. Knepley */
132*9371c9d4SSatish Balay PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[]) {
1336858538eSMatthew G. Knepley   PetscInt d;
1346858538eSMatthew G. Knepley 
1356858538eSMatthew G. Knepley   PetscFunctionBegin;
1366858538eSMatthew G. Knepley   if (!dm->maxCell) {
1376858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) out[d] = in[d];
1386858538eSMatthew G. Knepley   } else {
1396858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) {
1406858538eSMatthew G. Knepley       if ((dm->L[d] > 0.0) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
1416858538eSMatthew G. Knepley         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
1426858538eSMatthew G. Knepley       } else {
1436858538eSMatthew G. Knepley         out[d] = in[d];
1446858538eSMatthew G. Knepley       }
1456858538eSMatthew G. Knepley     }
1466858538eSMatthew G. Knepley   }
1476858538eSMatthew G. Knepley   PetscFunctionReturn(0);
1486858538eSMatthew G. Knepley }
1496858538eSMatthew G. Knepley 
150*9371c9d4SSatish Balay PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[]) {
1516858538eSMatthew G. Knepley   PetscInt d;
1526858538eSMatthew G. Knepley 
1536858538eSMatthew G. Knepley   PetscFunctionBegin;
1546858538eSMatthew G. Knepley   if (!dm->maxCell) {
1556858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) out[d] = in[d];
1566858538eSMatthew G. Knepley   } else {
1576858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) {
1586858538eSMatthew G. Knepley       if ((dm->L[d] > 0.0) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
1596858538eSMatthew G. Knepley         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
1606858538eSMatthew G. Knepley       } else {
1616858538eSMatthew G. Knepley         out[d] = in[d];
1626858538eSMatthew G. Knepley       }
1636858538eSMatthew G. Knepley     }
1646858538eSMatthew G. Knepley   }
1656858538eSMatthew G. Knepley   PetscFunctionReturn(0);
1666858538eSMatthew G. Knepley }
1676858538eSMatthew G. Knepley 
1686858538eSMatthew G. Knepley /*
1696858538eSMatthew G. Knepley   DMLocalizeAddCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer.
1706858538eSMatthew G. Knepley 
1716858538eSMatthew G. Knepley   Input Parameters:
1726858538eSMatthew G. Knepley + dm     - The DM
1736858538eSMatthew G. Knepley . dim    - The spatial dimension
1746858538eSMatthew G. Knepley . anchor - The anchor point, the input point can be no more than maxCell away from it
1756858538eSMatthew G. Knepley . in     - The input coordinate delta (dim numbers)
1766858538eSMatthew G. Knepley - out    - The input coordinate point (dim numbers)
1776858538eSMatthew G. Knepley 
1786858538eSMatthew G. Knepley   Output Parameter:
1796858538eSMatthew G. Knepley . out    - The localized coordinate in + out
1806858538eSMatthew G. Knepley 
1816858538eSMatthew G. Knepley   Level: developer
1826858538eSMatthew G. Knepley 
1836858538eSMatthew G. Knepley   Note: This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell
1846858538eSMatthew G. Knepley 
1856858538eSMatthew G. Knepley .seealso: `DMLocalizeCoordinates()`, `DMLocalizeCoordinate()`
1866858538eSMatthew G. Knepley */
187*9371c9d4SSatish Balay PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[]) {
1886858538eSMatthew G. Knepley   PetscInt d;
1896858538eSMatthew G. Knepley 
1906858538eSMatthew G. Knepley   PetscFunctionBegin;
1916858538eSMatthew G. Knepley   if (!dm->maxCell) {
1926858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) out[d] += in[d];
1936858538eSMatthew G. Knepley   } else {
1946858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) {
1956858538eSMatthew G. Knepley       const PetscReal maxC = dm->maxCell[d];
1966858538eSMatthew G. Knepley 
1976858538eSMatthew G. Knepley       if ((dm->L[d] > 0.0) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
1986858538eSMatthew G. Knepley         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
1996858538eSMatthew G. Knepley 
2006858538eSMatthew G. Knepley         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
2016858538eSMatthew G. Knepley           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "%" PetscInt_FMT "-Coordinate %g more than %g away from anchor %g", d, (double)PetscRealPart(in[d]), (double)maxC, (double)PetscRealPart(anchor[d]));
2026858538eSMatthew G. Knepley         out[d] += newCoord;
2036858538eSMatthew G. Knepley       } else {
2046858538eSMatthew G. Knepley         out[d] += in[d];
2056858538eSMatthew G. Knepley       }
2066858538eSMatthew G. Knepley     }
2076858538eSMatthew G. Knepley   }
2086858538eSMatthew G. Knepley   PetscFunctionReturn(0);
2096858538eSMatthew G. Knepley }
2106858538eSMatthew G. Knepley 
2116858538eSMatthew G. Knepley /*@
2126858538eSMatthew G. Knepley   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
2136858538eSMatthew G. Knepley 
2146858538eSMatthew G. Knepley   Not collective
2156858538eSMatthew G. Knepley 
2166858538eSMatthew G. Knepley   Input Parameter:
2176858538eSMatthew G. Knepley . dm - The DM
2186858538eSMatthew G. Knepley 
2196858538eSMatthew G. Knepley   Output Parameter:
2206858538eSMatthew G. Knepley   areLocalized - True if localized
2216858538eSMatthew G. Knepley 
2226858538eSMatthew G. Knepley   Level: developer
2236858538eSMatthew G. Knepley 
2246858538eSMatthew G. Knepley .seealso: `DMLocalizeCoordinates()`, `DMGetCoordinatesLocalized()`, `DMSetPeriodicity()`
2256858538eSMatthew G. Knepley @*/
226*9371c9d4SSatish Balay PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm, PetscBool *areLocalized) {
2276858538eSMatthew G. Knepley   PetscFunctionBegin;
2286858538eSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2296858538eSMatthew G. Knepley   PetscValidBoolPointer(areLocalized, 2);
2306858538eSMatthew G. Knepley   *areLocalized = dm->coordinates[1].dim < 0 ? PETSC_FALSE : PETSC_TRUE;
2316858538eSMatthew G. Knepley   PetscFunctionReturn(0);
2326858538eSMatthew G. Knepley }
2336858538eSMatthew G. Knepley 
2346858538eSMatthew G. Knepley /*@
2356858538eSMatthew G. Knepley   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
2366858538eSMatthew G. Knepley 
2376858538eSMatthew G. Knepley   Collective on dm
2386858538eSMatthew G. Knepley 
2396858538eSMatthew G. Knepley   Input Parameter:
2406858538eSMatthew G. Knepley . dm - The DM
2416858538eSMatthew G. Knepley 
2426858538eSMatthew G. Knepley   Output Parameter:
2436858538eSMatthew G. Knepley   areLocalized - True if localized
2446858538eSMatthew G. Knepley 
2456858538eSMatthew G. Knepley   Level: developer
2466858538eSMatthew G. Knepley 
2476858538eSMatthew G. Knepley .seealso: `DMLocalizeCoordinates()`, `DMSetPeriodicity()`, `DMGetCoordinatesLocalizedLocal()`
2486858538eSMatthew G. Knepley @*/
249*9371c9d4SSatish Balay PetscErrorCode DMGetCoordinatesLocalized(DM dm, PetscBool *areLocalized) {
2506858538eSMatthew G. Knepley   PetscBool localized;
2516858538eSMatthew G. Knepley 
2526858538eSMatthew G. Knepley   PetscFunctionBegin;
2536858538eSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2546858538eSMatthew G. Knepley   PetscValidBoolPointer(areLocalized, 2);
2556858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalizedLocal(dm, &localized));
2566858538eSMatthew G. Knepley   PetscCall(MPIU_Allreduce(&localized, areLocalized, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
2576858538eSMatthew G. Knepley   PetscFunctionReturn(0);
2586858538eSMatthew G. Knepley }
2596858538eSMatthew G. Knepley 
2606858538eSMatthew G. Knepley /*@
2616858538eSMatthew G. Knepley   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
2626858538eSMatthew G. Knepley 
2636858538eSMatthew G. Knepley   Collective on dm
2646858538eSMatthew G. Knepley 
2656858538eSMatthew G. Knepley   Input Parameter:
2666858538eSMatthew G. Knepley . dm - The DM
2676858538eSMatthew G. Knepley 
2686858538eSMatthew G. Knepley   Level: developer
2696858538eSMatthew G. Knepley 
2706858538eSMatthew G. Knepley .seealso: `DMSetPeriodicity()`, `DMLocalizeCoordinate()`, `DMLocalizeAddCoordinate()`
2716858538eSMatthew G. Knepley @*/
272*9371c9d4SSatish Balay PetscErrorCode DMLocalizeCoordinates(DM dm) {
2736858538eSMatthew G. Knepley   DM               cdm, cdgdm, cplex, plex;
2746858538eSMatthew G. Knepley   PetscSection     cs, csDG;
2756858538eSMatthew G. Knepley   Vec              coordinates, cVec;
2766858538eSMatthew G. Knepley   PetscScalar     *coordsDG, *anchor, *localized;
2774fb89dddSMatthew G. Knepley   const PetscReal *Lstart, *L;
2786858538eSMatthew G. Knepley   PetscInt         Nc, vStart, vEnd, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, bs, coordSize;
2796858538eSMatthew G. Knepley   PetscBool        isLocalized, sparseLocalize = dm->sparseLocalize, useDG = PETSC_FALSE, useDGGlobal;
2806858538eSMatthew G. Knepley   PetscInt         maxHeight = 0, h;
2816858538eSMatthew G. Knepley   PetscInt        *pStart = NULL, *pEnd = NULL;
2826858538eSMatthew G. Knepley   MPI_Comm         comm;
2836858538eSMatthew G. Knepley 
2846858538eSMatthew G. Knepley   PetscFunctionBegin;
2856858538eSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2864fb89dddSMatthew G. Knepley   PetscCall(DMGetPeriodicity(dm, NULL, &Lstart, &L));
2876858538eSMatthew G. Knepley   /* Cannot automatically localize without L and maxCell right now */
2886858538eSMatthew G. Knepley   if (!L) PetscFunctionReturn(0);
2896858538eSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2906858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalized(dm, &isLocalized));
2916858538eSMatthew G. Knepley   if (isLocalized) PetscFunctionReturn(0);
2926858538eSMatthew G. Knepley 
2936858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &cdm));
2946858538eSMatthew G. Knepley   PetscCall(DMConvert(dm, DMPLEX, &plex));
2956858538eSMatthew G. Knepley   PetscCall(DMConvert(cdm, DMPLEX, &cplex));
2966858538eSMatthew G. Knepley   if (cplex) {
2976858538eSMatthew G. Knepley     PetscCall(DMPlexGetDepthStratum(cplex, 0, &vStart, &vEnd));
2986858538eSMatthew G. Knepley     PetscCall(DMPlexGetMaxProjectionHeight(cplex, &maxHeight));
2996858538eSMatthew G. Knepley     PetscCall(DMGetWorkArray(dm, 2 * (maxHeight + 1), MPIU_INT, &pStart));
3006858538eSMatthew G. Knepley     pEnd     = &pStart[maxHeight + 1];
3016858538eSMatthew G. Knepley     newStart = vStart;
3026858538eSMatthew G. Knepley     newEnd   = vEnd;
3036858538eSMatthew G. Knepley     for (h = 0; h <= maxHeight; h++) {
3046858538eSMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(cplex, h, &pStart[h], &pEnd[h]));
3056858538eSMatthew G. Knepley       newStart = PetscMin(newStart, pStart[h]);
3066858538eSMatthew G. Knepley       newEnd   = PetscMax(newEnd, pEnd[h]);
3076858538eSMatthew G. Knepley     }
3086858538eSMatthew G. Knepley   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
3096858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3106858538eSMatthew G. Knepley   PetscCheck(coordinates, comm, PETSC_ERR_SUP, "Missing local coordinate vector");
3116858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateSection(dm, &cs));
3126858538eSMatthew G. Knepley   PetscCall(VecGetBlockSize(coordinates, &bs));
3136858538eSMatthew G. Knepley   PetscCall(PetscSectionGetChart(cs, &sStart, &sEnd));
3146858538eSMatthew G. Knepley 
3156858538eSMatthew G. Knepley   PetscCall(PetscSectionCreate(comm, &csDG));
3166858538eSMatthew G. Knepley   PetscCall(PetscSectionSetNumFields(csDG, 1));
3176858538eSMatthew G. Knepley   PetscCall(PetscSectionGetFieldComponents(cs, 0, &Nc));
3186858538eSMatthew G. Knepley   PetscCall(PetscSectionSetFieldComponents(csDG, 0, Nc));
3196858538eSMatthew G. Knepley   PetscCall(PetscSectionSetChart(csDG, newStart, newEnd));
3206858538eSMatthew G. Knepley   PetscCheck(bs == Nc, comm, PETSC_ERR_ARG_INCOMP, "Coordinate block size %" PetscInt_FMT " != %" PetscInt_FMT " number of components", bs, Nc);
3216858538eSMatthew G. Knepley 
3226858538eSMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, 2 * Nc, MPIU_SCALAR, &anchor));
3236858538eSMatthew G. Knepley   localized = &anchor[Nc];
3246858538eSMatthew G. Knepley   for (h = 0; h <= maxHeight; h++) {
3256858538eSMatthew G. Knepley     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
3266858538eSMatthew G. Knepley 
3276858538eSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
3286858538eSMatthew G. Knepley       PetscScalar   *cellCoords = NULL;
3296858538eSMatthew G. Knepley       DMPolytopeType ct;
3306858538eSMatthew G. Knepley       PetscInt       dof, d, p;
3316858538eSMatthew G. Knepley 
3326858538eSMatthew G. Knepley       PetscCall(DMPlexGetCellType(plex, c, &ct));
3336858538eSMatthew G. Knepley       if (ct == DM_POLYTOPE_FV_GHOST) continue;
3346858538eSMatthew G. Knepley       PetscCall(DMPlexVecGetClosure(cplex, cs, coordinates, c, &dof, &cellCoords));
3356858538eSMatthew G. Knepley       PetscCheck(!(dof % Nc), comm, PETSC_ERR_ARG_INCOMP, "Coordinate size on cell %" PetscInt_FMT " closure %" PetscInt_FMT " not divisible by %" PetscInt_FMT " number of components", c, dof, Nc);
3366858538eSMatthew G. Knepley       for (d = 0; d < Nc; ++d) anchor[d] = cellCoords[d];
3376858538eSMatthew G. Knepley       for (p = 0; p < dof / Nc; ++p) {
3386858538eSMatthew G. Knepley         PetscCall(DMLocalizeCoordinate_Internal(dm, Nc, anchor, &cellCoords[p * Nc], localized));
339*9371c9d4SSatish Balay         for (d = 0; d < Nc; ++d)
340*9371c9d4SSatish Balay           if (cellCoords[p * Nc + d] != localized[d]) break;
3416858538eSMatthew G. Knepley         if (d < Nc) break;
3426858538eSMatthew G. Knepley       }
3436858538eSMatthew G. Knepley       if (p < dof / Nc) useDG = PETSC_TRUE;
3446858538eSMatthew G. Knepley       if (p < dof / Nc || !sparseLocalize) {
3456858538eSMatthew G. Knepley         PetscCall(PetscSectionSetDof(csDG, c, dof));
3466858538eSMatthew G. Knepley         PetscCall(PetscSectionSetFieldDof(csDG, c, 0, dof));
3476858538eSMatthew G. Knepley       }
3486858538eSMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(cplex, cs, coordinates, c, &dof, &cellCoords));
3496858538eSMatthew G. Knepley     }
3506858538eSMatthew G. Knepley   }
3516858538eSMatthew G. Knepley   PetscCallMPI(MPI_Allreduce(&useDG, &useDGGlobal, 1, MPIU_BOOL, MPI_LOR, comm));
3526858538eSMatthew G. Knepley   if (!useDGGlobal) goto end;
3536858538eSMatthew G. Knepley 
3546858538eSMatthew G. Knepley   PetscCall(PetscSectionSetUp(csDG));
3556858538eSMatthew G. Knepley   PetscCall(PetscSectionGetStorageSize(csDG, &coordSize));
3566858538eSMatthew G. Knepley   PetscCall(VecCreate(PETSC_COMM_SELF, &cVec));
3576858538eSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)cVec, "coordinates"));
3586858538eSMatthew G. Knepley   PetscCall(VecSetBlockSize(cVec, bs));
3596858538eSMatthew G. Knepley   PetscCall(VecSetSizes(cVec, coordSize, PETSC_DETERMINE));
3606858538eSMatthew G. Knepley   PetscCall(VecSetType(cVec, VECSTANDARD));
3616858538eSMatthew G. Knepley   PetscCall(VecGetArray(cVec, &coordsDG));
3626858538eSMatthew G. Knepley   for (h = 0; h <= maxHeight; h++) {
3636858538eSMatthew G. Knepley     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
3646858538eSMatthew G. Knepley 
3656858538eSMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
3666858538eSMatthew G. Knepley       PetscScalar *cellCoords = NULL;
3676858538eSMatthew G. Knepley       PetscInt     p          = 0, q, dof, cdof, d, offDG;
3686858538eSMatthew G. Knepley 
3696858538eSMatthew G. Knepley       PetscCall(PetscSectionGetDof(csDG, c, &cdof));
3706858538eSMatthew G. Knepley       if (!cdof) continue;
3716858538eSMatthew G. Knepley       PetscCall(DMPlexVecGetClosure(cplex, cs, coordinates, c, &dof, &cellCoords));
3726858538eSMatthew G. Knepley       PetscCall(PetscSectionGetOffset(csDG, c, &offDG));
3737c48043bSMatthew G. Knepley       // TODO The coordinates are set in closure order, which might not be the tensor order
3746858538eSMatthew G. Knepley       for (q = 0; q < dof / Nc; ++q) {
3756858538eSMatthew G. Knepley         // Select a trial anchor
3766858538eSMatthew G. Knepley         for (d = 0; d < Nc; ++d) anchor[d] = cellCoords[q * Nc + d];
3776858538eSMatthew G. Knepley         for (p = 0; p < dof / Nc; ++p) {
3786858538eSMatthew G. Knepley           PetscCall(DMLocalizeCoordinate_Internal(dm, Nc, anchor, &cellCoords[p * Nc], &coordsDG[offDG + p * Nc]));
3794fb89dddSMatthew G. Knepley           // We need the cell to fit into the torus [lower, lower+L)
3806858538eSMatthew G. Knepley           for (d = 0; d < Nc; ++d)
3814fb89dddSMatthew G. Knepley             if (L[d] > 0. && ((PetscRealPart(coordsDG[offDG + p * Nc + d]) < (Lstart ? Lstart[d] : 0.)) || (PetscRealPart(coordsDG[offDG + p * Nc + d]) > (Lstart ? Lstart[d] : 0.) + L[d]))) break;
3826858538eSMatthew G. Knepley           if (d < Nc) break;
3836858538eSMatthew G. Knepley         }
3846858538eSMatthew G. Knepley         if (p == dof / Nc) break;
3856858538eSMatthew G. Knepley       }
3864fb89dddSMatthew G. Knepley       PetscCheck(p == dof / Nc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " does not fit into the torus %s[0, L]", c, Lstart ? "Lstart + " : "");
3876858538eSMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(cplex, cs, coordinates, c, &dof, &cellCoords));
3886858538eSMatthew G. Knepley     }
3896858538eSMatthew G. Knepley   }
3906858538eSMatthew G. Knepley   PetscCall(VecRestoreArray(cVec, &coordsDG));
3916858538eSMatthew G. Knepley   PetscCall(DMClone(cdm, &cdgdm));
3926858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateDM(dm, cdgdm));
3936858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateSection(dm, PETSC_DETERMINE, csDG));
3946858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinatesLocal(dm, cVec));
3956858538eSMatthew G. Knepley   PetscCall(VecDestroy(&cVec));
3967c48043bSMatthew G. Knepley   // Convert the discretization
3977c48043bSMatthew G. Knepley   {
3987c48043bSMatthew G. Knepley     PetscFE         fe, dgfe;
3997c48043bSMatthew G. Knepley     PetscSpace      P;
4007c48043bSMatthew G. Knepley     PetscDualSpace  Q, dgQ;
4017c48043bSMatthew G. Knepley     PetscQuadrature q, fq;
4027c48043bSMatthew G. Knepley     PetscClassId    id;
4037c48043bSMatthew G. Knepley 
4047c48043bSMatthew G. Knepley     PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe));
4057c48043bSMatthew G. Knepley     PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
4067c48043bSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
4077c48043bSMatthew G. Knepley       PetscCall(PetscFEGetBasisSpace(fe, &P));
4087c48043bSMatthew G. Knepley       PetscCall(PetscObjectReference((PetscObject)P));
4097c48043bSMatthew G. Knepley       PetscCall(PetscFEGetDualSpace(fe, &Q));
4107c48043bSMatthew G. Knepley       PetscCall(PetscDualSpaceDuplicate(Q, &dgQ));
4117c48043bSMatthew G. Knepley       PetscCall(PetscDualSpaceLagrangeSetContinuity(dgQ, PETSC_FALSE));
4127c48043bSMatthew G. Knepley       PetscCall(PetscDualSpaceSetUp(dgQ));
4137c48043bSMatthew G. Knepley       PetscCall(PetscFEGetQuadrature(fe, &q));
4147c48043bSMatthew G. Knepley       PetscCall(PetscObjectReference((PetscObject)q));
4157c48043bSMatthew G. Knepley       PetscCall(PetscFEGetFaceQuadrature(fe, &fq));
4167c48043bSMatthew G. Knepley       PetscCall(PetscObjectReference((PetscObject)fq));
4177c48043bSMatthew G. Knepley       PetscCall(PetscFECreateFromSpaces(P, dgQ, q, fq, &dgfe));
4187c48043bSMatthew G. Knepley       PetscCall(DMSetField(cdgdm, 0, NULL, (PetscObject)dgfe));
4197c48043bSMatthew G. Knepley       PetscCall(PetscFEDestroy(&dgfe));
4207c48043bSMatthew G. Knepley       PetscCall(DMCreateDS(cdgdm));
4217c48043bSMatthew G. Knepley     }
4227c48043bSMatthew G. Knepley   }
4236858538eSMatthew G. Knepley   PetscCall(DMDestroy(&cdgdm));
4246858538eSMatthew G. Knepley 
4256858538eSMatthew G. Knepley end:
4266858538eSMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor));
4276858538eSMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, 2 * (maxHeight + 1), MPIU_INT, &pStart));
4286858538eSMatthew G. Knepley   PetscCall(PetscSectionDestroy(&csDG));
4296858538eSMatthew G. Knepley   PetscCall(DMDestroy(&plex));
4306858538eSMatthew G. Knepley   PetscCall(DMDestroy(&cplex));
4316858538eSMatthew G. Knepley   PetscFunctionReturn(0);
4326858538eSMatthew G. Knepley }
433