xref: /petsc/src/dm/impls/plex/plexorient.c (revision 17d25f2db07dd4879475c68cd38e18113aad1d04)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
284961fc4SMatthew G. Knepley #include <petscsf.h>
384961fc4SMatthew G. Knepley 
484961fc4SMatthew G. Knepley /*@
5b5a892a1SMatthew G. Knepley   DMPlexOrientPoint - Act with the given orientation on the cone points of this mesh point, and update its use in the mesh.
627d0e99aSVaclav Hapla 
727d0e99aSVaclav Hapla   Not Collective
827d0e99aSVaclav Hapla 
927d0e99aSVaclav Hapla   Input Parameters:
10a1cb98faSBarry Smith + dm - The `DM`
11b5a892a1SMatthew G. Knepley . p  - The mesh point
12b5a892a1SMatthew G. Knepley - o  - The orientation
1327d0e99aSVaclav Hapla 
1427d0e99aSVaclav Hapla   Level: intermediate
1527d0e99aSVaclav Hapla 
161cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexOrient()`, `DMPlexGetCone()`, `DMPlexGetConeOrientation()`, `DMPlexInterpolate()`, `DMPlexGetChart()`
1727d0e99aSVaclav Hapla @*/
18d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexOrientPoint(DM dm, PetscInt p, PetscInt o)
19d71ae5a4SJacob Faibussowitsch {
20b5a892a1SMatthew G. Knepley   DMPolytopeType  ct;
21b5a892a1SMatthew G. Knepley   const PetscInt *arr, *cone, *ornt, *support;
22b5a892a1SMatthew G. Knepley   PetscInt       *newcone, *newornt;
23b5a892a1SMatthew G. Knepley   PetscInt        coneSize, c, supportSize, s;
2427d0e99aSVaclav Hapla 
2527d0e99aSVaclav Hapla   PetscFunctionBegin;
2627d0e99aSVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, p, &ct));
2885036b15SMatthew G. Knepley   arr = DMPolytopeTypeGetArrangement(ct, o);
290851c46eSMatthew G. Knepley   if (!arr) PetscFunctionReturn(PETSC_SUCCESS);
309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, p, &cone));
329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
339566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, coneSize, MPIU_INT, &newcone));
349566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, coneSize, MPIU_INT, &newornt));
35b5a892a1SMatthew G. Knepley   for (c = 0; c < coneSize; ++c) {
36b5a892a1SMatthew G. Knepley     DMPolytopeType ft;
37b5a892a1SMatthew G. Knepley     PetscInt       nO;
3827d0e99aSVaclav Hapla 
399566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, cone[c], &ft));
4085036b15SMatthew G. Knepley     nO         = DMPolytopeTypeGetNumArrangements(ft) / 2;
41b5a892a1SMatthew G. Knepley     newcone[c] = cone[arr[c * 2 + 0]];
42b5a892a1SMatthew G. Knepley     newornt[c] = DMPolytopeTypeComposeOrientation(ft, arr[c * 2 + 1], ornt[arr[c * 2 + 0]]);
4363a3b9bcSJacob Faibussowitsch     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], cone[c]);
4427d0e99aSVaclav Hapla   }
459566063dSJacob Faibussowitsch   PetscCall(DMPlexSetCone(dm, p, newcone));
469566063dSJacob Faibussowitsch   PetscCall(DMPlexSetConeOrientation(dm, p, newornt));
479566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, coneSize, MPIU_INT, &newcone));
489566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, coneSize, MPIU_INT, &newornt));
49b5a892a1SMatthew G. Knepley   /* Update orientation of this point in the support points */
509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupport(dm, p, &support));
52b5a892a1SMatthew G. Knepley   for (s = 0; s < supportSize; ++s) {
539566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, support[s], &cone));
559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, support[s], &ornt));
56b5a892a1SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
57b5a892a1SMatthew G. Knepley       PetscInt po;
5827d0e99aSVaclav Hapla 
59b5a892a1SMatthew G. Knepley       if (cone[c] != p) continue;
60b5a892a1SMatthew G. Knepley       /* ornt[c] * 0 = target = po * o so that po = ornt[c] * o^{-1} */
61b5a892a1SMatthew G. Knepley       po = DMPolytopeTypeComposeOrientationInv(ct, ornt[c], o);
629566063dSJacob Faibussowitsch       PetscCall(DMPlexInsertConeOrientation(dm, support[s], c, po));
6384961fc4SMatthew G. Knepley     }
6484961fc4SMatthew G. Knepley   }
653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6684961fc4SMatthew G. Knepley }
6784961fc4SMatthew G. Knepley 
680851c46eSMatthew G. Knepley static PetscInt GetPointIndex(PetscInt point, PetscInt pStart, PetscInt pEnd, const PetscInt points[])
690851c46eSMatthew G. Knepley {
700851c46eSMatthew G. Knepley   if (points) {
710851c46eSMatthew G. Knepley     PetscInt loc;
720851c46eSMatthew G. Knepley 
730851c46eSMatthew G. Knepley     PetscCall(PetscFindInt(point, pEnd - pStart, points, &loc));
740851c46eSMatthew G. Knepley     if (loc >= 0) return loc;
750851c46eSMatthew G. Knepley   } else {
760851c46eSMatthew G. Knepley     if (point >= pStart && point < pEnd) return point - pStart;
770851c46eSMatthew G. Knepley   }
780851c46eSMatthew G. Knepley   return -1;
790851c46eSMatthew G. Knepley }
800851c46eSMatthew G. Knepley 
817b310ce2SMatthew G. Knepley /*
827b310ce2SMatthew G. Knepley   - Checks face match
837b310ce2SMatthew G. Knepley     - Flips non-matching
847b310ce2SMatthew G. Knepley   - Inserts faces of support cells in FIFO
857b310ce2SMatthew G. Knepley */
860851c46eSMatthew G. Knepley static PetscErrorCode DMPlexCheckFace_Internal(DM dm, PetscInt *faceFIFO, PetscInt *fTop, PetscInt *fBottom, IS cellIS, IS faceIS, PetscBT seenCells, PetscBT flippedCells, PetscBT seenFaces)
870851c46eSMatthew G. Knepley {
880851c46eSMatthew G. Knepley   const PetscInt *supp, *coneA, *coneB, *coneOA, *coneOB;
890851c46eSMatthew G. Knepley   PetscInt        suppSize, Ns = 0, coneSizeA, coneSizeB, posA = -1, posB = -1;
900851c46eSMatthew G. Knepley   PetscInt        face, dim, indC[3], indS[3], seenA, flippedA, seenB, flippedB, mismatch;
910851c46eSMatthew G. Knepley   const PetscInt *cells, *faces;
920851c46eSMatthew G. Knepley   PetscInt        cStart, cEnd, fStart, fEnd;
930851c46eSMatthew G. Knepley 
940851c46eSMatthew G. Knepley   PetscFunctionBegin;
950851c46eSMatthew G. Knepley   face = faceFIFO[(*fTop)++];
960851c46eSMatthew G. Knepley   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
970851c46eSMatthew G. Knepley   PetscCall(ISGetPointRange(faceIS, &fStart, &fEnd, &faces));
980851c46eSMatthew G. Knepley   PetscCall(DMPlexGetPointDepth(dm, cells ? cells[cStart] : cStart, &dim));
990851c46eSMatthew G. Knepley   PetscCall(DMPlexGetSupportSize(dm, face, &suppSize));
1000851c46eSMatthew G. Knepley   PetscCall(DMPlexGetSupport(dm, face, &supp));
1010851c46eSMatthew G. Knepley   // Filter the support
1020851c46eSMatthew G. Knepley   for (PetscInt s = 0; s < suppSize; ++s) {
1030851c46eSMatthew G. Knepley     // Filter support
1040851c46eSMatthew G. Knepley     indC[Ns] = GetPointIndex(supp[s], cStart, cEnd, cells);
1050851c46eSMatthew G. Knepley     indS[Ns] = s;
1060851c46eSMatthew G. Knepley     if (indC[Ns] >= 0) ++Ns;
1070851c46eSMatthew G. Knepley   }
1080851c46eSMatthew G. Knepley   if (Ns < 2) PetscFunctionReturn(PETSC_SUCCESS);
1090851c46eSMatthew G. Knepley   PetscCheck(Ns == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %" PetscInt_FMT, Ns);
1100851c46eSMatthew G. Knepley   PetscCheck(indC[0] >= 0 && indC[1] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Support cells %" PetscInt_FMT " (%" PetscInt_FMT ") and %" PetscInt_FMT " (%" PetscInt_FMT ") are not both valid", supp[0], indC[0], supp[1], indC[1]);
1110851c46eSMatthew G. Knepley   seenA    = PetscBTLookup(seenCells, indC[0]);
1120851c46eSMatthew G. Knepley   flippedA = PetscBTLookup(flippedCells, indC[0]) ? 1 : 0;
1130851c46eSMatthew G. Knepley   seenB    = PetscBTLookup(seenCells, indC[1]);
1140851c46eSMatthew G. Knepley   flippedB = PetscBTLookup(flippedCells, indC[1]) ? 1 : 0;
1150851c46eSMatthew G. Knepley 
1160851c46eSMatthew G. Knepley   PetscCall(DMPlexGetConeSize(dm, supp[indS[0]], &coneSizeA));
1170851c46eSMatthew G. Knepley   PetscCall(DMPlexGetConeSize(dm, supp[indS[1]], &coneSizeB));
1180851c46eSMatthew G. Knepley   PetscCall(DMPlexGetCone(dm, supp[indS[0]], &coneA));
1190851c46eSMatthew G. Knepley   PetscCall(DMPlexGetCone(dm, supp[indS[1]], &coneB));
1200851c46eSMatthew G. Knepley   PetscCall(DMPlexGetConeOrientation(dm, supp[indS[0]], &coneOA));
1210851c46eSMatthew G. Knepley   PetscCall(DMPlexGetConeOrientation(dm, supp[indS[1]], &coneOB));
1220851c46eSMatthew G. Knepley   for (PetscInt c = 0; c < coneSizeA; ++c) {
1230851c46eSMatthew G. Knepley     const PetscInt indF = GetPointIndex(coneA[c], fStart, fEnd, faces);
1240851c46eSMatthew G. Knepley 
1250851c46eSMatthew G. Knepley     // Filter cone
1260851c46eSMatthew G. Knepley     if (indF < 0) continue;
1270851c46eSMatthew G. Knepley     if (!PetscBTLookup(seenFaces, indF)) {
1280851c46eSMatthew G. Knepley       faceFIFO[(*fBottom)++] = coneA[c];
1290851c46eSMatthew G. Knepley       PetscCall(PetscBTSet(seenFaces, indF));
1300851c46eSMatthew G. Knepley     }
1310851c46eSMatthew G. Knepley     if (coneA[c] == face) posA = c;
1320851c46eSMatthew G. Knepley     PetscCheck(*fBottom <= fEnd - fStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %" PetscInt_FMT " was pushed exceeding capacity %" PetscInt_FMT " > %" PetscInt_FMT, coneA[c], *fBottom, fEnd - fStart);
1330851c46eSMatthew G. Knepley   }
1340851c46eSMatthew G. Knepley   PetscCheck(posA >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " could not be located in cell %" PetscInt_FMT, face, supp[indS[0]]);
1350851c46eSMatthew G. Knepley   for (PetscInt c = 0; c < coneSizeB; ++c) {
1360851c46eSMatthew G. Knepley     const PetscInt indF = GetPointIndex(coneB[c], fStart, fEnd, faces);
1370851c46eSMatthew G. Knepley 
1380851c46eSMatthew G. Knepley     // Filter cone
1390851c46eSMatthew G. Knepley     if (indF < 0) continue;
1400851c46eSMatthew G. Knepley     if (!PetscBTLookup(seenFaces, indF)) {
1410851c46eSMatthew G. Knepley       faceFIFO[(*fBottom)++] = coneB[c];
1420851c46eSMatthew G. Knepley       PetscCall(PetscBTSet(seenFaces, indF));
1430851c46eSMatthew G. Knepley     }
1440851c46eSMatthew G. Knepley     if (coneB[c] == face) posB = c;
1450851c46eSMatthew G. Knepley     PetscCheck(*fBottom <= fEnd - fStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %" PetscInt_FMT " was pushed exceeding capacity %" PetscInt_FMT " > %" PetscInt_FMT, coneA[c], *fBottom, fEnd - fStart);
1460851c46eSMatthew G. Knepley   }
1470851c46eSMatthew G. Knepley   PetscCheck(posB >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " could not be located in cell %" PetscInt_FMT, face, supp[indS[1]]);
1480851c46eSMatthew G. Knepley 
1490851c46eSMatthew G. Knepley   if (dim == 1) {
1500851c46eSMatthew G. Knepley     mismatch = posA == posB;
1510851c46eSMatthew G. Knepley   } else {
1520851c46eSMatthew G. Knepley     mismatch = coneOA[posA] == coneOB[posB];
1530851c46eSMatthew G. Knepley   }
1540851c46eSMatthew G. Knepley 
1550851c46eSMatthew G. Knepley   if (mismatch ^ (flippedA ^ flippedB)) {
1560851c46eSMatthew G. Knepley     PetscCheck(!seenA || !seenB, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen cells %" PetscInt_FMT " and %" PetscInt_FMT " do not match: Fault mesh is non-orientable", supp[indS[0]], supp[indS[1]]);
1570851c46eSMatthew G. Knepley     if (!seenA && !flippedA) {
1580851c46eSMatthew G. Knepley       PetscCall(PetscBTSet(flippedCells, indC[0]));
1590851c46eSMatthew G. Knepley     } else if (!seenB && !flippedB) {
1600851c46eSMatthew G. Knepley       PetscCall(PetscBTSet(flippedCells, indC[1]));
1610851c46eSMatthew G. Knepley     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
1620851c46eSMatthew G. Knepley   } else PetscCheck(!mismatch || !flippedA || !flippedB, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
1630851c46eSMatthew G. Knepley   PetscCall(PetscBTSet(seenCells, indC[0]));
1640851c46eSMatthew G. Knepley   PetscCall(PetscBTSet(seenCells, indC[1]));
1650851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1660851c46eSMatthew G. Knepley }
1670851c46eSMatthew G. Knepley 
1680851c46eSMatthew G. Knepley static PetscErrorCode DMPlexCheckFace_Old_Internal(DM dm, PetscInt *faceFIFO, PetscInt *fTop, PetscInt *fBottom, PetscInt cStart, PetscInt fStart, PetscInt fEnd, PetscBT seenCells, PetscBT flippedCells, PetscBT seenFaces)
169d71ae5a4SJacob Faibussowitsch {
1707b310ce2SMatthew G. Knepley   const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB;
1717b310ce2SMatthew G. Knepley   PetscInt        supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1;
1727b2de0fdSMatthew G. Knepley   PetscInt        face, dim, seenA, flippedA, seenB, flippedB, mismatch, c;
1737b310ce2SMatthew G. Knepley 
1747b310ce2SMatthew G. Knepley   PetscFunctionBegin;
1757b310ce2SMatthew G. Knepley   face = faceFIFO[(*fTop)++];
1769566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
1779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSize(dm, face, &supportSize));
1789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupport(dm, face, &support));
1793ba16761SJacob Faibussowitsch   if (supportSize < 2) PetscFunctionReturn(PETSC_SUCCESS);
18063a3b9bcSJacob Faibussowitsch   PetscCheck(supportSize == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %" PetscInt_FMT, supportSize);
1817b310ce2SMatthew G. Knepley   seenA    = PetscBTLookup(seenCells, support[0] - cStart);
1827b310ce2SMatthew G. Knepley   flippedA = PetscBTLookup(flippedCells, support[0] - cStart) ? 1 : 0;
1837b310ce2SMatthew G. Knepley   seenB    = PetscBTLookup(seenCells, support[1] - cStart);
1847b310ce2SMatthew G. Knepley   flippedB = PetscBTLookup(flippedCells, support[1] - cStart) ? 1 : 0;
1857b310ce2SMatthew G. Knepley 
1869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, support[0], &coneSizeA));
1879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, support[1], &coneSizeB));
1889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, support[0], &coneA));
1899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, support[1], &coneB));
1909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, support[0], &coneOA));
1919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, support[1], &coneOB));
1927b310ce2SMatthew G. Knepley   for (c = 0; c < coneSizeA; ++c) {
1937b310ce2SMatthew G. Knepley     if (!PetscBTLookup(seenFaces, coneA[c] - fStart)) {
1947b310ce2SMatthew G. Knepley       faceFIFO[(*fBottom)++] = coneA[c];
1959566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(seenFaces, coneA[c] - fStart));
1967b310ce2SMatthew G. Knepley     }
1977b310ce2SMatthew G. Knepley     if (coneA[c] == face) posA = c;
19863a3b9bcSJacob Faibussowitsch     PetscCheck(*fBottom <= fEnd - fStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %" PetscInt_FMT " was pushed exceeding capacity %" PetscInt_FMT " > %" PetscInt_FMT, coneA[c], *fBottom, fEnd - fStart);
1997b310ce2SMatthew G. Knepley   }
20063a3b9bcSJacob Faibussowitsch   PetscCheck(posA >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " could not be located in cell %" PetscInt_FMT, face, support[0]);
2017b310ce2SMatthew G. Knepley   for (c = 0; c < coneSizeB; ++c) {
2027b310ce2SMatthew G. Knepley     if (!PetscBTLookup(seenFaces, coneB[c] - fStart)) {
2037b310ce2SMatthew G. Knepley       faceFIFO[(*fBottom)++] = coneB[c];
2049566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(seenFaces, coneB[c] - fStart));
2057b310ce2SMatthew G. Knepley     }
2067b310ce2SMatthew G. Knepley     if (coneB[c] == face) posB = c;
20763a3b9bcSJacob Faibussowitsch     PetscCheck(*fBottom <= fEnd - fStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %" PetscInt_FMT " was pushed exceeding capacity %" PetscInt_FMT " > %" PetscInt_FMT, coneA[c], *fBottom, fEnd - fStart);
2087b310ce2SMatthew G. Knepley   }
20963a3b9bcSJacob Faibussowitsch   PetscCheck(posB >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " could not be located in cell %" PetscInt_FMT, face, support[1]);
2107b310ce2SMatthew G. Knepley 
2117b310ce2SMatthew G. Knepley   if (dim == 1) {
2127b310ce2SMatthew G. Knepley     mismatch = posA == posB;
2137b310ce2SMatthew G. Knepley   } else {
2147b310ce2SMatthew G. Knepley     mismatch = coneOA[posA] == coneOB[posB];
2157b310ce2SMatthew G. Knepley   }
2167b310ce2SMatthew G. Knepley 
2177b310ce2SMatthew G. Knepley   if (mismatch ^ (flippedA ^ flippedB)) {
21863a3b9bcSJacob Faibussowitsch     PetscCheck(!seenA || !seenB, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen cells %" PetscInt_FMT " and %" PetscInt_FMT " do not match: Fault mesh is non-orientable", support[0], support[1]);
2197b310ce2SMatthew G. Knepley     if (!seenA && !flippedA) {
2209566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(flippedCells, support[0] - cStart));
2217b310ce2SMatthew G. Knepley     } else if (!seenB && !flippedB) {
2229566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(flippedCells, support[1] - cStart));
2237b310ce2SMatthew G. Knepley     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
2241dca8a05SBarry Smith   } else PetscCheck(!mismatch || !flippedA || !flippedB, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
2259566063dSJacob Faibussowitsch   PetscCall(PetscBTSet(seenCells, support[0] - cStart));
2269566063dSJacob Faibussowitsch   PetscCall(PetscBTSet(seenCells, support[1] - cStart));
2273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2287b310ce2SMatthew G. Knepley }
2297b310ce2SMatthew G. Knepley 
2300851c46eSMatthew G. Knepley /*
2310851c46eSMatthew G. Knepley   DMPlexOrient_Serial - Compute valid orientation for local connected components
2320851c46eSMatthew G. Knepley 
2330851c46eSMatthew G. Knepley   Not collective
2340851c46eSMatthew G. Knepley 
2350851c46eSMatthew G. Knepley   Input Parameters:
2360851c46eSMatthew G. Knepley   + dm         - The `DM`
2370851c46eSMatthew G. Knepley   - cellHeight - The height of k-cells to be oriented
2380851c46eSMatthew G. Knepley 
2390851c46eSMatthew G. Knepley   Output Parameters:
2400851c46eSMatthew G. Knepley   + Ncomp        - The number of connected component
2410851c46eSMatthew G. Knepley   . cellComp     - The connected component for each local cell
2420851c46eSMatthew G. Knepley   . faceComp     - The connected component for each local face
2430851c46eSMatthew G. Knepley   - flippedCells - Marked cells should be inverted
2440851c46eSMatthew G. Knepley 
2450851c46eSMatthew G. Knepley   Level: developer
2460851c46eSMatthew G. Knepley 
2470851c46eSMatthew G. Knepley .seealso: `DMPlexOrient()``
2480851c46eSMatthew G. Knepley */
2490851c46eSMatthew G. Knepley static PetscErrorCode DMPlexOrient_Serial(DM dm, IS cellIS, IS faceIS, PetscInt *Ncomp, PetscInt cellComp[], PetscInt faceComp[], PetscBT flippedCells)
2500851c46eSMatthew G. Knepley {
2510851c46eSMatthew G. Knepley   PetscBT         seenCells, seenFaces;
2520851c46eSMatthew G. Knepley   PetscInt       *faceFIFO;
2530851c46eSMatthew G. Knepley   const PetscInt *cells = NULL, *faces = NULL;
2540851c46eSMatthew G. Knepley   PetscInt        cStart = 0, cEnd = 0, fStart = 0, fEnd = 0;
2550851c46eSMatthew G. Knepley 
2560851c46eSMatthew G. Knepley   PetscFunctionBegin;
2570851c46eSMatthew G. Knepley   if (cellIS) PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
2580851c46eSMatthew G. Knepley   if (faceIS) PetscCall(ISGetPointRange(faceIS, &fStart, &fEnd, &faces));
2590851c46eSMatthew G. Knepley   PetscCall(PetscBTCreate(cEnd - cStart, &seenCells));
2600851c46eSMatthew G. Knepley   PetscCall(PetscBTMemzero(cEnd - cStart, seenCells));
2610851c46eSMatthew G. Knepley   PetscCall(PetscBTCreate(fEnd - fStart, &seenFaces));
2620851c46eSMatthew G. Knepley   PetscCall(PetscBTMemzero(fEnd - fStart, seenFaces));
2630851c46eSMatthew G. Knepley   PetscCall(PetscMalloc1(fEnd - fStart, &faceFIFO));
2640851c46eSMatthew G. Knepley   *Ncomp = 0;
2650851c46eSMatthew G. Knepley   for (PetscInt c = 0; c < cEnd - cStart; ++c) cellComp[c] = -1;
2660851c46eSMatthew G. Knepley   do {
2670851c46eSMatthew G. Knepley     PetscInt cc, fTop, fBottom;
2680851c46eSMatthew G. Knepley 
2690851c46eSMatthew G. Knepley     // Look for first unmarked cell
2700851c46eSMatthew G. Knepley     for (cc = cStart; cc < cEnd; ++cc)
2710851c46eSMatthew G. Knepley       if (cellComp[cc - cStart] < 0) break;
2720851c46eSMatthew G. Knepley     if (cc >= cEnd) break;
2730851c46eSMatthew G. Knepley     // Initialize FIFO with first cell in component
2740851c46eSMatthew G. Knepley     {
2750851c46eSMatthew G. Knepley       const PetscInt  cell = cells ? cells[cc] : cc;
2760851c46eSMatthew G. Knepley       const PetscInt *cone;
2770851c46eSMatthew G. Knepley       PetscInt        coneSize;
2780851c46eSMatthew G. Knepley 
2790851c46eSMatthew G. Knepley       fTop = fBottom = 0;
2800851c46eSMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
2810851c46eSMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, cell, &cone));
2820851c46eSMatthew G. Knepley       for (PetscInt c = 0; c < coneSize; ++c) {
2830851c46eSMatthew G. Knepley         // Cell faces are guaranteed to be in the face set
2840851c46eSMatthew G. Knepley         faceFIFO[fBottom++] = cone[c];
2850851c46eSMatthew G. Knepley         PetscCall(PetscBTSet(seenFaces, GetPointIndex(cone[c], fStart, fEnd, faces)));
2860851c46eSMatthew G. Knepley       }
2870851c46eSMatthew G. Knepley       PetscCall(PetscBTSet(seenCells, cc - cStart));
2880851c46eSMatthew G. Knepley     }
2890851c46eSMatthew G. Knepley     // Consider each face in FIFO
2900851c46eSMatthew G. Knepley     while (fTop < fBottom) PetscCall(DMPlexCheckFace_Internal(dm, faceFIFO, &fTop, &fBottom, cellIS, faceIS, seenCells, flippedCells, seenFaces));
2910851c46eSMatthew G. Knepley     // Set component for cells and faces
2920851c46eSMatthew G. Knepley     for (PetscInt c = 0; c < cEnd - cStart; ++c) {
2930851c46eSMatthew G. Knepley       if (PetscBTLookup(seenCells, c)) cellComp[c] = *Ncomp;
2940851c46eSMatthew G. Knepley     }
2950851c46eSMatthew G. Knepley     for (PetscInt f = 0; f < fEnd - fStart; ++f) {
2960851c46eSMatthew G. Knepley       if (PetscBTLookup(seenFaces, f)) faceComp[f] = *Ncomp;
2970851c46eSMatthew G. Knepley     }
2980851c46eSMatthew G. Knepley     // Wipe seenCells and seenFaces for next component
2990851c46eSMatthew G. Knepley     PetscCall(PetscBTMemzero(fEnd - fStart, seenFaces));
3000851c46eSMatthew G. Knepley     PetscCall(PetscBTMemzero(cEnd - cStart, seenCells));
3010851c46eSMatthew G. Knepley     ++(*Ncomp);
3020851c46eSMatthew G. Knepley   } while (1);
3030851c46eSMatthew G. Knepley   PetscCall(PetscBTDestroy(&seenCells));
3040851c46eSMatthew G. Knepley   PetscCall(PetscBTDestroy(&seenFaces));
3050851c46eSMatthew G. Knepley   PetscCall(PetscFree(faceFIFO));
3060851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
3070851c46eSMatthew G. Knepley }
3080851c46eSMatthew G. Knepley 
30984961fc4SMatthew G. Knepley /*@
31084961fc4SMatthew G. Knepley   DMPlexOrient - Give a consistent orientation to the input mesh
31184961fc4SMatthew G. Knepley 
3122fe279fdSBarry Smith   Input Parameter:
313a1cb98faSBarry Smith . dm - The `DM`
31484961fc4SMatthew G. Knepley 
315a1cb98faSBarry Smith   Note:
316a1cb98faSBarry Smith   The orientation data for the `DM` are change in-place.
317a1cb98faSBarry Smith 
318a1cb98faSBarry Smith   This routine will fail for non-orientable surfaces, such as the Moebius strip.
31984961fc4SMatthew G. Knepley 
32084961fc4SMatthew G. Knepley   Level: advanced
32184961fc4SMatthew G. Knepley 
32260225df5SJacob Faibussowitsch .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`
32384961fc4SMatthew G. Knepley @*/
324d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexOrient(DM dm)
325d71ae5a4SJacob Faibussowitsch {
3260851c46eSMatthew G. Knepley #if 0
3270851c46eSMatthew G. Knepley   IS cellIS, faceIS;
3280851c46eSMatthew G. Knepley 
3290851c46eSMatthew G. Knepley   PetscFunctionBegin;
3300851c46eSMatthew G. Knepley   PetscCall(DMPlexGetAllCells_Internal(dm, &cellIS));
3310851c46eSMatthew G. Knepley   PetscCall(DMPlexGetAllFaces_Internal(dm, &faceIS));
3320851c46eSMatthew G. Knepley   PetscCall(DMPlexOrientCells_Internal(dm, cellIS, faceIS));
3330851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
3340851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&faceIS));
3350851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
3360851c46eSMatthew G. Knepley #else
33784961fc4SMatthew G. Knepley   MPI_Comm           comm;
338e1d83109SMatthew G. Knepley   PetscSF            sf;
339e1d83109SMatthew G. Knepley   const PetscInt    *lpoints;
340e1d83109SMatthew G. Knepley   const PetscSFNode *rpoints;
341e1d83109SMatthew G. Knepley   PetscSFNode       *rorntComp = NULL, *lorntComp = NULL;
3423d6051bcSMatthew G. Knepley   PetscInt          *numNeighbors, **neighbors, *locSupport = NULL;
343e1d83109SMatthew G. Knepley   PetscSFNode       *nrankComp;
344e1d83109SMatthew G. Knepley   PetscBool         *match, *flipped;
34584961fc4SMatthew G. Knepley   PetscBT            seenCells, flippedCells, seenFaces;
346e1d83109SMatthew G. Knepley   PetscInt          *faceFIFO, fTop, fBottom, *cellComp, *faceComp;
3477cadcfe8SMatthew G. Knepley   PetscInt           numLeaves, numRoots, dim, h, cStart, cEnd, c, cell, fStart, fEnd, face, off, totNeighbors = 0;
34839526728SToby Isaac   PetscMPIInt        rank, size, numComponents, comp = 0;
34939526728SToby Isaac   PetscBool          flg, flg2;
350a17aa47eSToby Isaac   PetscViewer        viewer = NULL, selfviewer = NULL;
35184961fc4SMatthew G. Knepley 
35284961fc4SMatthew G. Knepley   PetscFunctionBegin;
3539566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3549566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
3559566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
3569566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-orientation_view", &flg));
3579566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-orientation_view_synchronized", &flg2));
3589566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
3599566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &lpoints, &rpoints));
36084961fc4SMatthew G. Knepley   /* Truth Table
36184961fc4SMatthew G. Knepley      mismatch    flips   do action   mismatch   flipA ^ flipB   action
36284961fc4SMatthew G. Knepley          F       0 flips     no         F             F           F
36384961fc4SMatthew G. Knepley          F       1 flip      yes        F             T           T
36484961fc4SMatthew G. Knepley          F       2 flips     no         T             F           T
36584961fc4SMatthew G. Knepley          T       0 flips     yes        T             T           F
36684961fc4SMatthew G. Knepley          T       1 flip      no
36784961fc4SMatthew G. Knepley          T       2 flips     yes
36884961fc4SMatthew G. Knepley   */
3699566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
3709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &h));
3719566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
3729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, h + 1, &fStart, &fEnd));
3739566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(cEnd - cStart, &seenCells));
3749566063dSJacob Faibussowitsch   PetscCall(PetscBTMemzero(cEnd - cStart, seenCells));
3759566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(cEnd - cStart, &flippedCells));
3769566063dSJacob Faibussowitsch   PetscCall(PetscBTMemzero(cEnd - cStart, flippedCells));
3779566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(fEnd - fStart, &seenFaces));
3789566063dSJacob Faibussowitsch   PetscCall(PetscBTMemzero(fEnd - fStart, seenFaces));
3799566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(fEnd - fStart, &faceFIFO, cEnd - cStart, &cellComp, fEnd - fStart, &faceComp));
380e1d83109SMatthew G. Knepley   /*
381e1d83109SMatthew G. Knepley    OLD STYLE
382e1d83109SMatthew G. Knepley    - Add an integer array over cells and faces (component) for connected component number
383e1d83109SMatthew G. Knepley    Foreach component
384e1d83109SMatthew G. Knepley      - Mark the initial cell as seen
385e1d83109SMatthew G. Knepley      - Process component as usual
386e1d83109SMatthew G. Knepley      - Set component for all seenCells
387e1d83109SMatthew G. Knepley      - Wipe seenCells and seenFaces (flippedCells can stay)
388e1d83109SMatthew G. Knepley    - Generate parallel adjacency for component using SF and seenFaces
389e1d83109SMatthew G. Knepley    - Collect numComponents adj data from each proc to 0
390e1d83109SMatthew G. Knepley    - Build same serial graph
391e1d83109SMatthew G. Knepley    - Use same solver
39215229ffcSPierre Jolivet    - Use Scatterv to send back flipped flags for each component
393e1d83109SMatthew G. Knepley    - Negate flippedCells by component
394e1d83109SMatthew G. Knepley 
395e1d83109SMatthew G. Knepley    NEW STYLE
396e1d83109SMatthew G. Knepley    - Create the adj on each process
397e1d83109SMatthew G. Knepley    - Bootstrap to complete graph on proc 0
398e1d83109SMatthew G. Knepley   */
399e1d83109SMatthew G. Knepley   /* Loop over components */
400e1d83109SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) cellComp[cell - cStart] = -1;
401e1d83109SMatthew G. Knepley   do {
402e1d83109SMatthew G. Knepley     /* Look for first unmarked cell */
4039371c9d4SSatish Balay     for (cell = cStart; cell < cEnd; ++cell)
4049371c9d4SSatish Balay       if (cellComp[cell - cStart] < 0) break;
405e1d83109SMatthew G. Knepley     if (cell >= cEnd) break;
406e1d83109SMatthew G. Knepley     /* Initialize FIFO with first cell in component */
407e1d83109SMatthew G. Knepley     {
40884961fc4SMatthew G. Knepley       const PetscInt *cone;
40984961fc4SMatthew G. Knepley       PetscInt        coneSize;
41084961fc4SMatthew G. Knepley 
411e1d83109SMatthew G. Knepley       fTop = fBottom = 0;
4129566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
4139566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cell, &cone));
41484961fc4SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
41584961fc4SMatthew G. Knepley         faceFIFO[fBottom++] = cone[c];
4169566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(seenFaces, cone[c] - fStart));
41784961fc4SMatthew G. Knepley       }
4189566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(seenCells, cell - cStart));
41984961fc4SMatthew G. Knepley     }
42084961fc4SMatthew G. Knepley     /* Consider each face in FIFO */
4210851c46eSMatthew G. Knepley     while (fTop < fBottom) PetscCall(DMPlexCheckFace_Old_Internal(dm, faceFIFO, &fTop, &fBottom, cStart, fStart, fEnd, seenCells, flippedCells, seenFaces));
422e1d83109SMatthew G. Knepley     /* Set component for cells and faces */
423e1d83109SMatthew G. Knepley     for (cell = 0; cell < cEnd - cStart; ++cell) {
424e1d83109SMatthew G. Knepley       if (PetscBTLookup(seenCells, cell)) cellComp[cell] = comp;
425e1d83109SMatthew G. Knepley     }
426e1d83109SMatthew G. Knepley     for (face = 0; face < fEnd - fStart; ++face) {
427e1d83109SMatthew G. Knepley       if (PetscBTLookup(seenFaces, face)) faceComp[face] = comp;
428e1d83109SMatthew G. Knepley     }
429e1d83109SMatthew G. Knepley     /* Wipe seenCells and seenFaces for next component */
4309566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(fEnd - fStart, seenFaces));
4319566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(cEnd - cStart, seenCells));
432e1d83109SMatthew G. Knepley     ++comp;
433e1d83109SMatthew G. Knepley   } while (1);
434e1d83109SMatthew G. Knepley   numComponents = comp;
43584961fc4SMatthew G. Knepley   if (flg) {
43684961fc4SMatthew G. Knepley     PetscViewer v;
43784961fc4SMatthew G. Knepley 
4389566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
4399566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(v));
4409566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for serial flipped cells:\n", rank));
4419566063dSJacob Faibussowitsch     PetscCall(PetscBTView(cEnd - cStart, flippedCells, v));
4429566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(v));
4439566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(v));
44484961fc4SMatthew G. Knepley   }
44584961fc4SMatthew G. Knepley   /* Now all subdomains are oriented, but we need a consistent parallel orientation */
44684961fc4SMatthew G. Knepley   if (numLeaves >= 0) {
4473d6051bcSMatthew G. Knepley     PetscInt maxSupportSize, neighbor;
4483d6051bcSMatthew G. Knepley 
449e1d83109SMatthew G. Knepley     /* Store orientations of boundary faces*/
4503d6051bcSMatthew G. Knepley     PetscCall(DMPlexGetMaxSizes(dm, NULL, &maxSupportSize));
4513d6051bcSMatthew G. Knepley     PetscCall(PetscCalloc3(numRoots, &rorntComp, numRoots, &lorntComp, maxSupportSize, &locSupport));
45284961fc4SMatthew G. Knepley     for (face = fStart; face < fEnd; ++face) {
453e1d83109SMatthew G. Knepley       const PetscInt *cone, *support, *ornt;
4543d6051bcSMatthew G. Knepley       PetscInt        coneSize, supportSize, Ns = 0, s, l;
455e1d83109SMatthew G. Knepley 
4569566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, face, &supportSize));
4573d6051bcSMatthew G. Knepley       /* Ignore overlapping cells */
4589566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, face, &support));
4593d6051bcSMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
4603d6051bcSMatthew G. Knepley         PetscCall(PetscFindInt(support[s], numLeaves, lpoints, &l));
4613d6051bcSMatthew G. Knepley         if (l >= 0) continue;
4623d6051bcSMatthew G. Knepley         locSupport[Ns++] = support[s];
4633d6051bcSMatthew G. Knepley       }
4643d6051bcSMatthew G. Knepley       if (Ns != 1) continue;
4653d6051bcSMatthew G. Knepley       neighbor = locSupport[0];
4663d6051bcSMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, neighbor, &cone));
4673d6051bcSMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, neighbor, &coneSize));
4683d6051bcSMatthew G. Knepley       PetscCall(DMPlexGetConeOrientation(dm, neighbor, &ornt));
4699371c9d4SSatish Balay       for (c = 0; c < coneSize; ++c)
4709371c9d4SSatish Balay         if (cone[c] == face) break;
47184961fc4SMatthew G. Knepley       if (dim == 1) {
47284961fc4SMatthew G. Knepley         /* Use cone position instead, shifted to -1 or 1 */
4733d6051bcSMatthew G. Knepley         if (PetscBTLookup(flippedCells, neighbor - cStart)) rorntComp[face].rank = 1 - c * 2;
4746e1eb25cSMatthew G. Knepley         else rorntComp[face].rank = c * 2 - 1;
47584961fc4SMatthew G. Knepley       } else {
4763d6051bcSMatthew G. Knepley         if (PetscBTLookup(flippedCells, neighbor - cStart)) rorntComp[face].rank = ornt[c] < 0 ? -1 : 1;
477e1d83109SMatthew G. Knepley         else rorntComp[face].rank = ornt[c] < 0 ? 1 : -1;
47884961fc4SMatthew G. Knepley       }
479e1d83109SMatthew G. Knepley       rorntComp[face].index = faceComp[face - fStart];
48084961fc4SMatthew G. Knepley     }
481e1d83109SMatthew G. Knepley     /* Communicate boundary edge orientations */
4829566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(sf, MPIU_2INT, rorntComp, lorntComp, MPI_REPLACE));
4839566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(sf, MPIU_2INT, rorntComp, lorntComp, MPI_REPLACE));
484e1d83109SMatthew G. Knepley   }
485e1d83109SMatthew G. Knepley   /* Get process adjacency */
4869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numComponents, &numNeighbors, numComponents, &neighbors));
487a17aa47eSToby Isaac   viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm));
4889566063dSJacob Faibussowitsch   if (flg2) PetscCall(PetscViewerASCIIPushSynchronized(viewer));
4899566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
490e1d83109SMatthew G. Knepley   for (comp = 0; comp < numComponents; ++comp) {
491e1d83109SMatthew G. Knepley     PetscInt l, n;
49284961fc4SMatthew G. Knepley 
493e1d83109SMatthew G. Knepley     numNeighbors[comp] = 0;
4949566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(PetscMax(numLeaves, 0), &neighbors[comp]));
495e1d83109SMatthew G. Knepley     /* I know this is p^2 time in general, but for bounded degree its alright */
496e1d83109SMatthew G. Knepley     for (l = 0; l < numLeaves; ++l) {
497e1d83109SMatthew G. Knepley       const PetscInt face = lpoints[l];
498e1d83109SMatthew G. Knepley 
499e1d83109SMatthew G. Knepley       /* Find a representative face (edge) separating pairs of procs */
5003d6051bcSMatthew G. Knepley       if ((face >= fStart) && (face < fEnd) && (faceComp[face - fStart] == comp) && rorntComp[face].rank) {
501269a49d5SMatthew G. Knepley         const PetscInt rrank = rpoints[l].rank;
502e1d83109SMatthew G. Knepley         const PetscInt rcomp = lorntComp[face].index;
503e1d83109SMatthew G. Knepley 
5049371c9d4SSatish Balay         for (n = 0; n < numNeighbors[comp]; ++n)
5059371c9d4SSatish Balay           if ((rrank == rpoints[neighbors[comp][n]].rank) && (rcomp == lorntComp[lpoints[neighbors[comp][n]]].index)) break;
506e1d83109SMatthew G. Knepley         if (n >= numNeighbors[comp]) {
507e1d83109SMatthew G. Knepley           PetscInt supportSize;
508e1d83109SMatthew G. Knepley 
5099566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(dm, face, &supportSize));
51063a3b9bcSJacob Faibussowitsch           PetscCheck(supportSize == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Boundary faces should see one cell, not %" PetscInt_FMT, supportSize);
5119371c9d4SSatish Balay           if (flg)
5129371c9d4SSatish Balay             PetscCall(PetscViewerASCIIPrintf(selfviewer, "[%d]: component %d, Found representative leaf %" PetscInt_FMT " (face %" PetscInt_FMT ") connecting to face %" PetscInt_FMT " on (%" PetscInt_FMT ", %" PetscInt_FMT ") with orientation %" PetscInt_FMT "\n", rank, comp, l, face,
5139371c9d4SSatish Balay                                              rpoints[l].index, rrank, rcomp, lorntComp[face].rank));
514e1d83109SMatthew G. Knepley           neighbors[comp][numNeighbors[comp]++] = l;
515e1d83109SMatthew G. Knepley         }
516e1d83109SMatthew G. Knepley       }
517e1d83109SMatthew G. Knepley     }
518e1d83109SMatthew G. Knepley     totNeighbors += numNeighbors[comp];
519e1d83109SMatthew G. Knepley   }
5209566063dSJacob Faibussowitsch   PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
5219566063dSJacob Faibussowitsch   if (flg2) PetscCall(PetscViewerASCIIPopSynchronized(viewer));
5229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(totNeighbors, &nrankComp, totNeighbors, &match));
523e1d83109SMatthew G. Knepley   for (comp = 0, off = 0; comp < numComponents; ++comp) {
524e1d83109SMatthew G. Knepley     PetscInt n;
525e1d83109SMatthew G. Knepley 
526e1d83109SMatthew G. Knepley     for (n = 0; n < numNeighbors[comp]; ++n, ++off) {
527e1d83109SMatthew G. Knepley       const PetscInt face = lpoints[neighbors[comp][n]];
528e1d83109SMatthew G. Knepley       const PetscInt o    = rorntComp[face].rank * lorntComp[face].rank;
529e1d83109SMatthew G. Knepley 
530e1d83109SMatthew G. Knepley       if (o < 0) match[off] = PETSC_TRUE;
531e1d83109SMatthew G. Knepley       else if (o > 0) match[off] = PETSC_FALSE;
53263a3b9bcSJacob Faibussowitsch       else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid face %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ") neighbor: %" PetscInt_FMT " comp: %d", face, rorntComp[face].rank, lorntComp[face].rank, neighbors[comp][n], comp);
533e1d83109SMatthew G. Knepley       nrankComp[off].rank  = rpoints[neighbors[comp][n]].rank;
534e1d83109SMatthew G. Knepley       nrankComp[off].index = lorntComp[lpoints[neighbors[comp][n]]].index;
535e1d83109SMatthew G. Knepley     }
5369566063dSJacob Faibussowitsch     PetscCall(PetscFree(neighbors[comp]));
53784961fc4SMatthew G. Knepley   }
53884961fc4SMatthew G. Knepley   /* Collect the graph on 0 */
539e1d83109SMatthew G. Knepley   if (numLeaves >= 0) {
54084961fc4SMatthew G. Knepley     Mat          G;
54184961fc4SMatthew G. Knepley     PetscBT      seenProcs, flippedProcs;
54284961fc4SMatthew G. Knepley     PetscInt    *procFIFO, pTop, pBottom;
5437cadcfe8SMatthew G. Knepley     PetscInt    *N          = NULL, *Noff;
544e1d83109SMatthew G. Knepley     PetscSFNode *adj        = NULL;
54584961fc4SMatthew G. Knepley     PetscBool   *val        = NULL;
5467cadcfe8SMatthew G. Knepley     PetscMPIInt *recvcounts = NULL, *displs = NULL, *Nc, p, o;
5479852e123SBarry Smith     PetscMPIInt  size = 0;
54884961fc4SMatthew G. Knepley 
5499566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(numComponents, &flipped));
5509566063dSJacob Faibussowitsch     if (rank == 0) PetscCallMPI(MPI_Comm_size(comm, &size));
5519566063dSJacob Faibussowitsch     PetscCall(PetscCalloc4(size, &recvcounts, size + 1, &displs, size, &Nc, size + 1, &Noff));
5529566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Gather(&numComponents, 1, MPI_INT, Nc, 1, MPI_INT, 0, comm));
553ad540459SPierre Jolivet     for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + Nc[p];
5549566063dSJacob Faibussowitsch     if (rank == 0) PetscCall(PetscMalloc1(displs[size], &N));
5559566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Gatherv(numNeighbors, numComponents, MPIU_INT, N, Nc, displs, MPIU_INT, 0, comm));
5569852e123SBarry Smith     for (p = 0, o = 0; p < size; ++p) {
557e1d83109SMatthew G. Knepley       recvcounts[p] = 0;
558e1d83109SMatthew G. Knepley       for (c = 0; c < Nc[p]; ++c, ++o) recvcounts[p] += N[o];
55984961fc4SMatthew G. Knepley       displs[p + 1] = displs[p] + recvcounts[p];
56084961fc4SMatthew G. Knepley     }
5619566063dSJacob Faibussowitsch     if (rank == 0) PetscCall(PetscMalloc2(displs[size], &adj, displs[size], &val));
5629566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Gatherv(nrankComp, totNeighbors, MPIU_2INT, adj, recvcounts, displs, MPIU_2INT, 0, comm));
5639566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Gatherv(match, totNeighbors, MPIU_BOOL, val, recvcounts, displs, MPIU_BOOL, 0, comm));
5649566063dSJacob Faibussowitsch     PetscCall(PetscFree2(numNeighbors, neighbors));
565dd400576SPatrick Sanan     if (rank == 0) {
566ad540459SPierre Jolivet       for (p = 1; p <= size; ++p) Noff[p] = Noff[p - 1] + Nc[p - 1];
567a83982f3SMatthew G. Knepley       if (flg) {
568e1d83109SMatthew G. Knepley         PetscInt n;
569e1d83109SMatthew G. Knepley 
5709852e123SBarry Smith         for (p = 0, off = 0; p < size; ++p) {
571e1d83109SMatthew G. Knepley           for (c = 0; c < Nc[p]; ++c) {
57263a3b9bcSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "Proc %d Comp %" PetscInt_FMT ":\n", p, c));
57348a46eb9SPierre Jolivet             for (n = 0; n < N[Noff[p] + c]; ++n, ++off) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  edge (%" PetscInt_FMT ", %" PetscInt_FMT ") (%s):\n", adj[off].rank, adj[off].index, PetscBools[val[off]]));
57484961fc4SMatthew G. Knepley           }
57584961fc4SMatthew G. Knepley         }
57684961fc4SMatthew G. Knepley       }
57784961fc4SMatthew G. Knepley       /* Symmetrize the graph */
5789566063dSJacob Faibussowitsch       PetscCall(MatCreate(PETSC_COMM_SELF, &G));
5799566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(G, Noff[size], Noff[size], Noff[size], Noff[size]));
5809566063dSJacob Faibussowitsch       PetscCall(MatSetUp(G));
5819852e123SBarry Smith       for (p = 0, off = 0; p < size; ++p) {
582e1d83109SMatthew G. Knepley         for (c = 0; c < Nc[p]; ++c) {
583e1d83109SMatthew G. Knepley           const PetscInt r = Noff[p] + c;
584e1d83109SMatthew G. Knepley           PetscInt       n;
585e1d83109SMatthew G. Knepley 
586e1d83109SMatthew G. Knepley           for (n = 0; n < N[r]; ++n, ++off) {
587e1d83109SMatthew G. Knepley             const PetscInt    q = Noff[adj[off].rank] + adj[off].index;
588e1d83109SMatthew G. Knepley             const PetscScalar o = val[off] ? 1.0 : 0.0;
58984961fc4SMatthew G. Knepley 
5909566063dSJacob Faibussowitsch             PetscCall(MatSetValues(G, 1, &r, 1, &q, &o, INSERT_VALUES));
5919566063dSJacob Faibussowitsch             PetscCall(MatSetValues(G, 1, &q, 1, &r, &o, INSERT_VALUES));
59284961fc4SMatthew G. Knepley           }
59384961fc4SMatthew G. Knepley         }
594e1d83109SMatthew G. Knepley       }
5959566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(G, MAT_FINAL_ASSEMBLY));
5969566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(G, MAT_FINAL_ASSEMBLY));
59784961fc4SMatthew G. Knepley 
5989566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(Noff[size], &seenProcs));
5999566063dSJacob Faibussowitsch       PetscCall(PetscBTMemzero(Noff[size], seenProcs));
6009566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(Noff[size], &flippedProcs));
6019566063dSJacob Faibussowitsch       PetscCall(PetscBTMemzero(Noff[size], flippedProcs));
6029566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Noff[size], &procFIFO));
60384961fc4SMatthew G. Knepley       pTop = pBottom = 0;
6049852e123SBarry Smith       for (p = 0; p < Noff[size]; ++p) {
60584961fc4SMatthew G. Knepley         if (PetscBTLookup(seenProcs, p)) continue;
60684961fc4SMatthew G. Knepley         /* Initialize FIFO with next proc */
60784961fc4SMatthew G. Knepley         procFIFO[pBottom++] = p;
6089566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(seenProcs, p));
60984961fc4SMatthew G. Knepley         /* Consider each proc in FIFO */
61084961fc4SMatthew G. Knepley         while (pTop < pBottom) {
61184961fc4SMatthew G. Knepley           const PetscScalar *ornt;
61284961fc4SMatthew G. Knepley           const PetscInt    *neighbors;
613e1d83109SMatthew G. Knepley           PetscInt           proc, nproc, seen, flippedA, flippedB, mismatch, numNeighbors, n;
61484961fc4SMatthew G. Knepley 
61584961fc4SMatthew G. Knepley           proc     = procFIFO[pTop++];
61684961fc4SMatthew G. Knepley           flippedA = PetscBTLookup(flippedProcs, proc) ? 1 : 0;
6179566063dSJacob Faibussowitsch           PetscCall(MatGetRow(G, proc, &numNeighbors, &neighbors, &ornt));
61884961fc4SMatthew G. Knepley           /* Loop over neighboring procs */
61984961fc4SMatthew G. Knepley           for (n = 0; n < numNeighbors; ++n) {
62084961fc4SMatthew G. Knepley             nproc    = neighbors[n];
62184961fc4SMatthew G. Knepley             mismatch = PetscRealPart(ornt[n]) > 0.5 ? 0 : 1;
62284961fc4SMatthew G. Knepley             seen     = PetscBTLookup(seenProcs, nproc);
62384961fc4SMatthew G. Knepley             flippedB = PetscBTLookup(flippedProcs, nproc) ? 1 : 0;
62484961fc4SMatthew G. Knepley 
62584961fc4SMatthew G. Knepley             if (mismatch ^ (flippedA ^ flippedB)) {
62663a3b9bcSJacob Faibussowitsch               PetscCheck(!seen, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen procs %" PetscInt_FMT " and %" PetscInt_FMT " do not match: Fault mesh is non-orientable", proc, nproc);
62784961fc4SMatthew G. Knepley               if (!flippedB) {
6289566063dSJacob Faibussowitsch                 PetscCall(PetscBTSet(flippedProcs, nproc));
62984961fc4SMatthew G. Knepley               } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
6301dca8a05SBarry Smith             } else PetscCheck(!mismatch || !flippedA || !flippedB, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
63184961fc4SMatthew G. Knepley             if (!seen) {
63284961fc4SMatthew G. Knepley               procFIFO[pBottom++] = nproc;
6339566063dSJacob Faibussowitsch               PetscCall(PetscBTSet(seenProcs, nproc));
63484961fc4SMatthew G. Knepley             }
63584961fc4SMatthew G. Knepley           }
63684961fc4SMatthew G. Knepley         }
63784961fc4SMatthew G. Knepley       }
6389566063dSJacob Faibussowitsch       PetscCall(PetscFree(procFIFO));
6399566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&G));
6409566063dSJacob Faibussowitsch       PetscCall(PetscFree2(adj, val));
6419566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&seenProcs));
64284961fc4SMatthew G. Knepley     }
643e1d83109SMatthew G. Knepley     /* Scatter flip flags */
644e1d83109SMatthew G. Knepley     {
645e1d83109SMatthew G. Knepley       PetscBool *flips = NULL;
646e1d83109SMatthew G. Knepley 
647dd400576SPatrick Sanan       if (rank == 0) {
6489566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(Noff[size], &flips));
6499852e123SBarry Smith         for (p = 0; p < Noff[size]; ++p) {
650e1d83109SMatthew G. Knepley           flips[p] = PetscBTLookup(flippedProcs, p) ? PETSC_TRUE : PETSC_FALSE;
6519566063dSJacob Faibussowitsch           if (flg && flips[p]) PetscCall(PetscPrintf(comm, "Flipping Proc+Comp %d:\n", p));
652e1d83109SMatthew G. Knepley         }
653ad540459SPierre Jolivet         for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + Nc[p];
654e1d83109SMatthew G. Knepley       }
6559566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Scatterv(flips, Nc, displs, MPIU_BOOL, flipped, numComponents, MPIU_BOOL, 0, comm));
6569566063dSJacob Faibussowitsch       PetscCall(PetscFree(flips));
65784961fc4SMatthew G. Knepley     }
6589566063dSJacob Faibussowitsch     if (rank == 0) PetscCall(PetscBTDestroy(&flippedProcs));
6599566063dSJacob Faibussowitsch     PetscCall(PetscFree(N));
6609566063dSJacob Faibussowitsch     PetscCall(PetscFree4(recvcounts, displs, Nc, Noff));
6619566063dSJacob Faibussowitsch     PetscCall(PetscFree2(nrankComp, match));
662e1d83109SMatthew G. Knepley 
663e1d83109SMatthew G. Knepley     /* Decide whether to flip cells in each component */
6649371c9d4SSatish Balay     for (c = 0; c < cEnd - cStart; ++c) {
6659371c9d4SSatish Balay       if (flipped[cellComp[c]]) PetscCall(PetscBTNegate(flippedCells, c));
6669371c9d4SSatish Balay     }
6679566063dSJacob Faibussowitsch     PetscCall(PetscFree(flipped));
66884961fc4SMatthew G. Knepley   }
66984961fc4SMatthew G. Knepley   if (flg) {
67084961fc4SMatthew G. Knepley     PetscViewer v;
67184961fc4SMatthew G. Knepley 
6729566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
6739566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(v));
6749566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for parallel flipped cells:\n", rank));
6759566063dSJacob Faibussowitsch     PetscCall(PetscBTView(cEnd - cStart, flippedCells, v));
6769566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(v));
6779566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(v));
67884961fc4SMatthew G. Knepley   }
67984961fc4SMatthew G. Knepley   /* Reverse flipped cells in the mesh */
68084961fc4SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
68148a46eb9SPierre Jolivet     if (PetscBTLookup(flippedCells, c - cStart)) PetscCall(DMPlexOrientPoint(dm, c, -1));
68284961fc4SMatthew G. Knepley   }
6839566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&seenCells));
6849566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&flippedCells));
6859566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&seenFaces));
6869566063dSJacob Faibussowitsch   PetscCall(PetscFree2(numNeighbors, neighbors));
6873d6051bcSMatthew G. Knepley   PetscCall(PetscFree3(rorntComp, lorntComp, locSupport));
6889566063dSJacob Faibussowitsch   PetscCall(PetscFree3(faceFIFO, cellComp, faceComp));
6893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6900851c46eSMatthew G. Knepley #endif
6910851c46eSMatthew G. Knepley }
6920851c46eSMatthew G. Knepley 
6930851c46eSMatthew G. Knepley static PetscErrorCode CreateCellAndFaceIS_Private(DM dm, DMLabel label, IS *cellIS, IS *faceIS)
6940851c46eSMatthew G. Knepley {
6950851c46eSMatthew G. Knepley   IS              valueIS;
6960851c46eSMatthew G. Knepley   const PetscInt *values;
6970851c46eSMatthew G. Knepley   PetscInt        Nv, depth = 0;
6980851c46eSMatthew G. Knepley 
6990851c46eSMatthew G. Knepley   PetscFunctionBegin;
7000851c46eSMatthew G. Knepley   PetscCall(DMLabelGetValueIS(label, &valueIS));
7010851c46eSMatthew G. Knepley   PetscCall(ISGetLocalSize(valueIS, &Nv));
7020851c46eSMatthew G. Knepley   PetscCall(ISGetIndices(valueIS, &values));
7030851c46eSMatthew G. Knepley   for (PetscInt v = 0; v < Nv; ++v) {
7040851c46eSMatthew G. Knepley     const PetscInt val = values[v] < 0 || values[v] >= 100 ? 0 : values[v];
7050851c46eSMatthew G. Knepley 
7060851c46eSMatthew G. Knepley     depth = PetscMax(val, depth);
7070851c46eSMatthew G. Knepley   }
7080851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&valueIS));
7090851c46eSMatthew G. Knepley   PetscCheck(depth >= 1 || !Nv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Depth for interface must be at least 1, not %" PetscInt_FMT, depth);
7100851c46eSMatthew G. Knepley   PetscCall(DMLabelGetStratumIS(label, depth, cellIS));
7110851c46eSMatthew G. Knepley   PetscCall(DMLabelGetStratumIS(label, depth - 1, faceIS));
7120851c46eSMatthew G. Knepley   if (!(*cellIS)) PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, cellIS));
7130851c46eSMatthew G. Knepley   if (!(*faceIS)) PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, faceIS));
7140851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
7150851c46eSMatthew G. Knepley }
7160851c46eSMatthew G. Knepley 
7170851c46eSMatthew G. Knepley PetscErrorCode DMPlexOrientLabel(DM dm, DMLabel label)
7180851c46eSMatthew G. Knepley {
7190851c46eSMatthew G. Knepley   IS cellIS, faceIS;
7200851c46eSMatthew G. Knepley 
7210851c46eSMatthew G. Knepley   PetscFunctionBegin;
7220851c46eSMatthew G. Knepley   PetscCall(CreateCellAndFaceIS_Private(dm, label, &cellIS, &faceIS));
7230851c46eSMatthew G. Knepley   PetscCall(DMPlexOrientCells_Internal(dm, cellIS, faceIS));
7240851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
7250851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&faceIS));
7260851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
7270851c46eSMatthew G. Knepley }
7280851c46eSMatthew G. Knepley 
7290851c46eSMatthew G. Knepley PetscErrorCode DMPlexOrientCells_Internal(DM dm, IS cellIS, IS faceIS)
7300851c46eSMatthew G. Knepley {
7310851c46eSMatthew G. Knepley   MPI_Comm           comm;
7320851c46eSMatthew G. Knepley   PetscSF            sf;
7330851c46eSMatthew G. Knepley   const PetscInt    *lpoints;
7340851c46eSMatthew G. Knepley   const PetscSFNode *rpoints;
7350851c46eSMatthew G. Knepley   PetscSFNode       *rorntComp = NULL, *lorntComp = NULL;
7360851c46eSMatthew G. Knepley   PetscInt          *numNeighbors, **neighbors, *locSupp = NULL;
7370851c46eSMatthew G. Knepley   PetscSFNode       *nrankComp;
7380851c46eSMatthew G. Knepley   PetscBool         *match, *flipped;
7390851c46eSMatthew G. Knepley   PetscBT            flippedCells;
7400851c46eSMatthew G. Knepley   PetscInt          *cellComp, *faceComp;
7410851c46eSMatthew G. Knepley   const PetscInt    *cells = NULL, *faces = NULL;
7420851c46eSMatthew G. Knepley   PetscInt           cStart = 0, cEnd = 0, fStart = 0, fEnd = 0;
7430851c46eSMatthew G. Knepley   PetscInt           numLeaves, numRoots, dim, Ncomp, totNeighbors = 0;
7440851c46eSMatthew G. Knepley   PetscMPIInt        rank, size;
7450851c46eSMatthew G. Knepley   PetscBool          view, viewSync;
7460851c46eSMatthew G. Knepley   PetscViewer        viewer = NULL, selfviewer = NULL;
7470851c46eSMatthew G. Knepley 
7480851c46eSMatthew G. Knepley   PetscFunctionBegin;
7490851c46eSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
7500851c46eSMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7510851c46eSMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(comm, &size));
7520851c46eSMatthew G. Knepley   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-orientation_view", &view));
7530851c46eSMatthew G. Knepley   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-orientation_view_synchronized", &viewSync));
7540851c46eSMatthew G. Knepley 
7550851c46eSMatthew G. Knepley   if (cellIS) PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
7560851c46eSMatthew G. Knepley   if (faceIS) PetscCall(ISGetPointRange(faceIS, &fStart, &fEnd, &faces));
7570851c46eSMatthew G. Knepley   PetscCall(DMGetPointSF(dm, &sf));
7580851c46eSMatthew G. Knepley   PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &lpoints, &rpoints));
7590851c46eSMatthew G. Knepley   /* Truth Table
7600851c46eSMatthew G. Knepley      mismatch    flips   do action   mismatch   flipA ^ flipB   action
7610851c46eSMatthew G. Knepley          F       0 flips     no         F             F           F
7620851c46eSMatthew G. Knepley          F       1 flip      yes        F             T           T
7630851c46eSMatthew G. Knepley          F       2 flips     no         T             F           T
7640851c46eSMatthew G. Knepley          T       0 flips     yes        T             T           F
7650851c46eSMatthew G. Knepley          T       1 flip      no
7660851c46eSMatthew G. Knepley          T       2 flips     yes
7670851c46eSMatthew G. Knepley   */
7680851c46eSMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
7690851c46eSMatthew G. Knepley   PetscCall(PetscBTCreate(cEnd - cStart, &flippedCells));
7700851c46eSMatthew G. Knepley   PetscCall(PetscBTMemzero(cEnd - cStart, flippedCells));
7710851c46eSMatthew G. Knepley   PetscCall(PetscCalloc2(cEnd - cStart, &cellComp, fEnd - fStart, &faceComp));
7720851c46eSMatthew G. Knepley   /*
7730851c46eSMatthew G. Knepley    OLD STYLE
7740851c46eSMatthew G. Knepley    - Add an integer array over cells and faces (component) for connected component number
7750851c46eSMatthew G. Knepley    Foreach component
7760851c46eSMatthew G. Knepley      - Mark the initial cell as seen
7770851c46eSMatthew G. Knepley      - Process component as usual
7780851c46eSMatthew G. Knepley      - Set component for all seenCells
7790851c46eSMatthew G. Knepley      - Wipe seenCells and seenFaces (flippedCells can stay)
7800851c46eSMatthew G. Knepley    - Generate parallel adjacency for component using SF and seenFaces
7810851c46eSMatthew G. Knepley    - Collect Ncomp adj data from each proc to 0
7820851c46eSMatthew G. Knepley    - Build same serial graph
7830851c46eSMatthew G. Knepley    - Use same solver
7840851c46eSMatthew G. Knepley    - Use Scatterv to send back flipped flags for each component
7850851c46eSMatthew G. Knepley    - Negate flippedCells by component
7860851c46eSMatthew G. Knepley 
7870851c46eSMatthew G. Knepley    NEW STYLE
7880851c46eSMatthew G. Knepley    - Create the adj on each process
7890851c46eSMatthew G. Knepley    - Bootstrap to complete graph on proc 0
7900851c46eSMatthew G. Knepley   */
7910851c46eSMatthew G. Knepley   PetscCall(DMPlexOrient_Serial(dm, cellIS, faceIS, &Ncomp, cellComp, faceComp, flippedCells));
7920851c46eSMatthew G. Knepley   if (view) {
7930851c46eSMatthew G. Knepley     PetscViewer v;
7940851c46eSMatthew G. Knepley 
7950851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
7960851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(v));
7970851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for serial flipped cells:\n", rank));
7980851c46eSMatthew G. Knepley     PetscCall(PetscBTView(cEnd - cStart, flippedCells, v));
7990851c46eSMatthew G. Knepley     PetscCall(PetscViewerFlush(v));
8000851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(v));
8010851c46eSMatthew G. Knepley   }
8020851c46eSMatthew G. Knepley   /* Now all subdomains are oriented, but we need a consistent parallel orientation */
8030851c46eSMatthew G. Knepley   // TODO: This all has to be rewritten to filter cones/supports to the ISes
8040851c46eSMatthew G. Knepley   if (numLeaves >= 0) {
8050851c46eSMatthew G. Knepley     PetscInt maxSuppSize, neighbor;
8060851c46eSMatthew G. Knepley 
8070851c46eSMatthew G. Knepley     // Store orientations of boundary faces
8080851c46eSMatthew G. Knepley     PetscCall(DMPlexGetMaxSizes(dm, NULL, &maxSuppSize));
8090851c46eSMatthew G. Knepley     PetscCall(PetscCalloc3(numRoots, &rorntComp, numRoots, &lorntComp, maxSuppSize, &locSupp));
8100851c46eSMatthew G. Knepley     for (PetscInt f = fStart; f < fEnd; ++f) {
8110851c46eSMatthew G. Knepley       const PetscInt  face = faces ? faces[f] : f;
8120851c46eSMatthew G. Knepley       const PetscInt *cone, *supp, *ornt;
8130851c46eSMatthew G. Knepley       PetscInt        coneSize, suppSize, nind, c, Ns = 0;
8140851c46eSMatthew G. Knepley 
8150851c46eSMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, face, &suppSize));
8160851c46eSMatthew G. Knepley       PetscCall(DMPlexGetSupport(dm, face, &supp));
8170851c46eSMatthew G. Knepley       for (PetscInt s = 0; s < suppSize; ++s) {
8180851c46eSMatthew G. Knepley         PetscInt ind, l;
8190851c46eSMatthew G. Knepley 
8200851c46eSMatthew G. Knepley         // Filter support
8210851c46eSMatthew G. Knepley         ind = GetPointIndex(supp[s], cStart, cEnd, cells);
8220851c46eSMatthew G. Knepley         if (ind < 0) continue;
8230851c46eSMatthew G. Knepley         // Ignore overlapping cells
8240851c46eSMatthew G. Knepley         PetscCall(PetscFindInt(supp[s], numLeaves, lpoints, &l));
8250851c46eSMatthew G. Knepley         if (l >= 0) continue;
8260851c46eSMatthew G. Knepley         locSupp[Ns++] = supp[s];
8270851c46eSMatthew G. Knepley       }
828*17d25f2dSMatthew G. Knepley       PetscCheck(Ns < maxSuppSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Index %" PetscInt_FMT " exceeds array size %" PetscInt_FMT, Ns, maxSuppSize);
8290851c46eSMatthew G. Knepley       if (Ns != 1) continue;
8300851c46eSMatthew G. Knepley       neighbor = locSupp[0];
8310851c46eSMatthew G. Knepley       nind     = GetPointIndex(neighbor, cStart, cEnd, cells);
8320851c46eSMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, neighbor, &cone));
8330851c46eSMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, neighbor, &coneSize));
8340851c46eSMatthew G. Knepley       PetscCall(DMPlexGetConeOrientation(dm, neighbor, &ornt));
8350851c46eSMatthew G. Knepley       for (c = 0; c < coneSize; ++c)
8360851c46eSMatthew G. Knepley         if (cone[c] == face) break;
8370851c46eSMatthew G. Knepley       if (dim == 1) {
8380851c46eSMatthew G. Knepley         /* Use cone position instead, shifted to -1 or 1 */
8390851c46eSMatthew G. Knepley         if (PetscBTLookup(flippedCells, nind)) rorntComp[face].rank = 1 - c * 2;
8400851c46eSMatthew G. Knepley         else rorntComp[face].rank = c * 2 - 1;
8410851c46eSMatthew G. Knepley       } else {
8420851c46eSMatthew G. Knepley         if (PetscBTLookup(flippedCells, nind)) rorntComp[face].rank = ornt[c] < 0 ? -1 : 1;
8430851c46eSMatthew G. Knepley         else rorntComp[face].rank = ornt[c] < 0 ? 1 : -1;
8440851c46eSMatthew G. Knepley       }
8450851c46eSMatthew G. Knepley       rorntComp[face].index = faceComp[GetPointIndex(face, fStart, fEnd, faces)];
8460851c46eSMatthew G. Knepley     }
8470851c46eSMatthew G. Knepley     // Communicate boundary edge orientations
8480851c46eSMatthew G. Knepley     PetscCall(PetscSFBcastBegin(sf, MPIU_2INT, rorntComp, lorntComp, MPI_REPLACE));
8490851c46eSMatthew G. Knepley     PetscCall(PetscSFBcastEnd(sf, MPIU_2INT, rorntComp, lorntComp, MPI_REPLACE));
8500851c46eSMatthew G. Knepley   }
8510851c46eSMatthew G. Knepley   /* Get process adjacency */
8520851c46eSMatthew G. Knepley   PetscCall(PetscMalloc2(Ncomp, &numNeighbors, Ncomp, &neighbors));
8530851c46eSMatthew G. Knepley   viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm));
8540851c46eSMatthew G. Knepley   if (viewSync) PetscCall(PetscViewerASCIIPushSynchronized(viewer));
8550851c46eSMatthew G. Knepley   PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
8560851c46eSMatthew G. Knepley   for (PetscInt comp = 0; comp < Ncomp; ++comp) {
8570851c46eSMatthew G. Knepley     PetscInt n;
8580851c46eSMatthew G. Knepley 
8590851c46eSMatthew G. Knepley     numNeighbors[comp] = 0;
8600851c46eSMatthew G. Knepley     PetscCall(PetscMalloc1(PetscMax(numLeaves, 0), &neighbors[comp]));
8610851c46eSMatthew G. Knepley     /* I know this is p^2 time in general, but for bounded degree its alright */
8620851c46eSMatthew G. Knepley     for (PetscInt l = 0; l < numLeaves; ++l) {
8630851c46eSMatthew G. Knepley       const PetscInt face = lpoints[l];
8640851c46eSMatthew G. Knepley       PetscInt       find;
8650851c46eSMatthew G. Knepley 
8660851c46eSMatthew G. Knepley       /* Find a representative face (edge) separating pairs of procs */
8670851c46eSMatthew G. Knepley       find = GetPointIndex(face, fStart, fEnd, faces);
8680851c46eSMatthew G. Knepley       if ((find >= 0) && (faceComp[find] == comp) && rorntComp[face].rank) {
8690851c46eSMatthew G. Knepley         const PetscInt rrank = rpoints[l].rank;
8700851c46eSMatthew G. Knepley         const PetscInt rcomp = lorntComp[face].index;
8710851c46eSMatthew G. Knepley 
8720851c46eSMatthew G. Knepley         for (n = 0; n < numNeighbors[comp]; ++n)
8730851c46eSMatthew G. Knepley           if ((rrank == rpoints[neighbors[comp][n]].rank) && (rcomp == lorntComp[lpoints[neighbors[comp][n]]].index)) break;
8740851c46eSMatthew G. Knepley         if (n >= numNeighbors[comp]) {
8750851c46eSMatthew G. Knepley           const PetscInt *supp;
8760851c46eSMatthew G. Knepley           PetscInt        suppSize, Ns = 0;
8770851c46eSMatthew G. Knepley 
8780851c46eSMatthew G. Knepley           PetscCall(DMPlexGetSupport(dm, face, &supp));
8790851c46eSMatthew G. Knepley           PetscCall(DMPlexGetSupportSize(dm, face, &suppSize));
8800851c46eSMatthew G. Knepley           for (PetscInt s = 0; s < suppSize; ++s) {
8810851c46eSMatthew G. Knepley             // Filter support
8820851c46eSMatthew G. Knepley             if (GetPointIndex(supp[s], cStart, cEnd, cells) >= 0) ++Ns;
8830851c46eSMatthew G. Knepley           }
8840851c46eSMatthew G. Knepley           PetscCheck(Ns == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Boundary face %" PetscInt_FMT " should see one cell, not %" PetscInt_FMT, face, Ns);
8850851c46eSMatthew G. Knepley           if (view)
8860851c46eSMatthew G. Knepley             PetscCall(PetscViewerASCIIPrintf(selfviewer, "[%d]: component %" PetscInt_FMT ", Found representative leaf %" PetscInt_FMT " (face %" PetscInt_FMT ") connecting to face %" PetscInt_FMT " on (%" PetscInt_FMT ", %" PetscInt_FMT ") with orientation %" PetscInt_FMT "\n", rank, comp, l, face,
8870851c46eSMatthew G. Knepley                                              rpoints[l].index, rrank, rcomp, lorntComp[face].rank));
8880851c46eSMatthew G. Knepley           neighbors[comp][numNeighbors[comp]++] = l;
8890851c46eSMatthew G. Knepley         }
8900851c46eSMatthew G. Knepley       }
8910851c46eSMatthew G. Knepley     }
8920851c46eSMatthew G. Knepley     totNeighbors += numNeighbors[comp];
8930851c46eSMatthew G. Knepley   }
8940851c46eSMatthew G. Knepley   PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
8950851c46eSMatthew G. Knepley   if (viewSync) PetscCall(PetscViewerASCIIPopSynchronized(viewer));
8960851c46eSMatthew G. Knepley   PetscCall(PetscMalloc2(totNeighbors, &nrankComp, totNeighbors, &match));
8970851c46eSMatthew G. Knepley   for (PetscInt comp = 0, off = 0; comp < Ncomp; ++comp) {
8980851c46eSMatthew G. Knepley     for (PetscInt n = 0; n < numNeighbors[comp]; ++n, ++off) {
8990851c46eSMatthew G. Knepley       const PetscInt face = lpoints[neighbors[comp][n]];
9000851c46eSMatthew G. Knepley       const PetscInt o    = rorntComp[face].rank * lorntComp[face].rank;
9010851c46eSMatthew G. Knepley 
9020851c46eSMatthew G. Knepley       if (o < 0) match[off] = PETSC_TRUE;
9030851c46eSMatthew G. Knepley       else if (o > 0) match[off] = PETSC_FALSE;
9040851c46eSMatthew G. Knepley       else
9050851c46eSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid face %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ") neighbor: %" PetscInt_FMT " comp: %" PetscInt_FMT, face, rorntComp[face].rank, lorntComp[face].rank, neighbors[comp][n], comp);
9060851c46eSMatthew G. Knepley       nrankComp[off].rank  = rpoints[neighbors[comp][n]].rank;
9070851c46eSMatthew G. Knepley       nrankComp[off].index = lorntComp[lpoints[neighbors[comp][n]]].index;
9080851c46eSMatthew G. Knepley     }
9090851c46eSMatthew G. Knepley     PetscCall(PetscFree(neighbors[comp]));
9100851c46eSMatthew G. Knepley   }
9110851c46eSMatthew G. Knepley   /* Collect the graph on 0 */
9120851c46eSMatthew G. Knepley   if (numLeaves >= 0) {
9130851c46eSMatthew G. Knepley     Mat          G;
9140851c46eSMatthew G. Knepley     PetscBT      seenProcs, flippedProcs;
9150851c46eSMatthew G. Knepley     PetscInt    *procFIFO, pTop, pBottom;
9160851c46eSMatthew G. Knepley     PetscInt    *N          = NULL, *Noff;
9170851c46eSMatthew G. Knepley     PetscSFNode *adj        = NULL;
9180851c46eSMatthew G. Knepley     PetscBool   *val        = NULL;
9190851c46eSMatthew G. Knepley     PetscMPIInt *recvcounts = NULL, *displs = NULL, *Nc;
9200851c46eSMatthew G. Knepley     PetscMPIInt  size = 0;
9210851c46eSMatthew G. Knepley 
9220851c46eSMatthew G. Knepley     PetscCall(PetscCalloc1(Ncomp, &flipped));
9230851c46eSMatthew G. Knepley     if (rank == 0) PetscCallMPI(MPI_Comm_size(comm, &size));
9240851c46eSMatthew G. Knepley     PetscCall(PetscCalloc4(size, &recvcounts, size + 1, &displs, size, &Nc, size + 1, &Noff));
9250851c46eSMatthew G. Knepley     PetscCallMPI(MPI_Gather(&Ncomp, 1, MPI_INT, Nc, 1, MPI_INT, 0, comm));
9260851c46eSMatthew G. Knepley     for (PetscInt p = 0; p < size; ++p) displs[p + 1] = displs[p] + Nc[p];
9270851c46eSMatthew G. Knepley     if (rank == 0) PetscCall(PetscMalloc1(displs[size], &N));
9280851c46eSMatthew G. Knepley     PetscCallMPI(MPI_Gatherv(numNeighbors, Ncomp, MPIU_INT, N, Nc, displs, MPIU_INT, 0, comm));
9290851c46eSMatthew G. Knepley     for (PetscInt p = 0, o = 0; p < size; ++p) {
9300851c46eSMatthew G. Knepley       recvcounts[p] = 0;
9310851c46eSMatthew G. Knepley       for (PetscInt c = 0; c < Nc[p]; ++c, ++o) recvcounts[p] += N[o];
9320851c46eSMatthew G. Knepley       displs[p + 1] = displs[p] + recvcounts[p];
9330851c46eSMatthew G. Knepley     }
9340851c46eSMatthew G. Knepley     if (rank == 0) PetscCall(PetscMalloc2(displs[size], &adj, displs[size], &val));
9350851c46eSMatthew G. Knepley     PetscCallMPI(MPI_Gatherv(nrankComp, totNeighbors, MPIU_2INT, adj, recvcounts, displs, MPIU_2INT, 0, comm));
9360851c46eSMatthew G. Knepley     PetscCallMPI(MPI_Gatherv(match, totNeighbors, MPIU_BOOL, val, recvcounts, displs, MPIU_BOOL, 0, comm));
9370851c46eSMatthew G. Knepley     PetscCall(PetscFree2(numNeighbors, neighbors));
9380851c46eSMatthew G. Knepley     if (rank == 0) {
9390851c46eSMatthew G. Knepley       for (PetscInt p = 1; p <= size; ++p) Noff[p] = Noff[p - 1] + Nc[p - 1];
9400851c46eSMatthew G. Knepley       if (view) {
9410851c46eSMatthew G. Knepley         for (PetscInt p = 0, off = 0; p < size; ++p) {
9420851c46eSMatthew G. Knepley           for (PetscInt c = 0; c < Nc[p]; ++c) {
9430851c46eSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "Proc %" PetscInt_FMT " Comp %" PetscInt_FMT ":\n", p, c));
9440851c46eSMatthew G. Knepley             for (PetscInt n = 0; n < N[Noff[p] + c]; ++n, ++off) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  edge (%" PetscInt_FMT ", %" PetscInt_FMT ") (%s):\n", adj[off].rank, adj[off].index, PetscBools[val[off]]));
9450851c46eSMatthew G. Knepley           }
9460851c46eSMatthew G. Knepley         }
9470851c46eSMatthew G. Knepley       }
9480851c46eSMatthew G. Knepley       /* Symmetrize the graph */
9490851c46eSMatthew G. Knepley       PetscCall(MatCreate(PETSC_COMM_SELF, &G));
9500851c46eSMatthew G. Knepley       PetscCall(MatSetSizes(G, Noff[size], Noff[size], Noff[size], Noff[size]));
9510851c46eSMatthew G. Knepley       PetscCall(MatSetUp(G));
9520851c46eSMatthew G. Knepley       for (PetscInt p = 0, off = 0; p < size; ++p) {
9530851c46eSMatthew G. Knepley         for (PetscInt c = 0; c < Nc[p]; ++c) {
9540851c46eSMatthew G. Knepley           const PetscInt r = Noff[p] + c;
9550851c46eSMatthew G. Knepley 
9560851c46eSMatthew G. Knepley           for (PetscInt n = 0; n < N[r]; ++n, ++off) {
9570851c46eSMatthew G. Knepley             const PetscInt    q = Noff[adj[off].rank] + adj[off].index;
9580851c46eSMatthew G. Knepley             const PetscScalar o = val[off] ? 1.0 : 0.0;
9590851c46eSMatthew G. Knepley 
9600851c46eSMatthew G. Knepley             PetscCall(MatSetValues(G, 1, &r, 1, &q, &o, INSERT_VALUES));
9610851c46eSMatthew G. Knepley             PetscCall(MatSetValues(G, 1, &q, 1, &r, &o, INSERT_VALUES));
9620851c46eSMatthew G. Knepley           }
9630851c46eSMatthew G. Knepley         }
9640851c46eSMatthew G. Knepley       }
9650851c46eSMatthew G. Knepley       PetscCall(MatAssemblyBegin(G, MAT_FINAL_ASSEMBLY));
9660851c46eSMatthew G. Knepley       PetscCall(MatAssemblyEnd(G, MAT_FINAL_ASSEMBLY));
9670851c46eSMatthew G. Knepley 
9680851c46eSMatthew G. Knepley       PetscCall(PetscBTCreate(Noff[size], &seenProcs));
9690851c46eSMatthew G. Knepley       PetscCall(PetscBTMemzero(Noff[size], seenProcs));
9700851c46eSMatthew G. Knepley       PetscCall(PetscBTCreate(Noff[size], &flippedProcs));
9710851c46eSMatthew G. Knepley       PetscCall(PetscBTMemzero(Noff[size], flippedProcs));
9720851c46eSMatthew G. Knepley       PetscCall(PetscMalloc1(Noff[size], &procFIFO));
9730851c46eSMatthew G. Knepley       pTop = pBottom = 0;
9740851c46eSMatthew G. Knepley       for (PetscInt p = 0; p < Noff[size]; ++p) {
9750851c46eSMatthew G. Knepley         if (PetscBTLookup(seenProcs, p)) continue;
9760851c46eSMatthew G. Knepley         /* Initialize FIFO with next proc */
9770851c46eSMatthew G. Knepley         procFIFO[pBottom++] = p;
9780851c46eSMatthew G. Knepley         PetscCall(PetscBTSet(seenProcs, p));
9790851c46eSMatthew G. Knepley         /* Consider each proc in FIFO */
9800851c46eSMatthew G. Knepley         while (pTop < pBottom) {
9810851c46eSMatthew G. Knepley           const PetscScalar *ornt;
9820851c46eSMatthew G. Knepley           const PetscInt    *neighbors;
9830851c46eSMatthew G. Knepley           PetscInt           proc, nproc, seen, flippedA, flippedB, mismatch, numNeighbors;
9840851c46eSMatthew G. Knepley 
9850851c46eSMatthew G. Knepley           proc     = procFIFO[pTop++];
9860851c46eSMatthew G. Knepley           flippedA = PetscBTLookup(flippedProcs, proc) ? 1 : 0;
9870851c46eSMatthew G. Knepley           PetscCall(MatGetRow(G, proc, &numNeighbors, &neighbors, &ornt));
9880851c46eSMatthew G. Knepley           /* Loop over neighboring procs */
9890851c46eSMatthew G. Knepley           for (PetscInt n = 0; n < numNeighbors; ++n) {
9900851c46eSMatthew G. Knepley             nproc    = neighbors[n];
9910851c46eSMatthew G. Knepley             mismatch = PetscRealPart(ornt[n]) > 0.5 ? 0 : 1;
9920851c46eSMatthew G. Knepley             seen     = PetscBTLookup(seenProcs, nproc);
9930851c46eSMatthew G. Knepley             flippedB = PetscBTLookup(flippedProcs, nproc) ? 1 : 0;
9940851c46eSMatthew G. Knepley 
9950851c46eSMatthew G. Knepley             if (mismatch ^ (flippedA ^ flippedB)) {
9960851c46eSMatthew G. Knepley               PetscCheck(!seen, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen procs %" PetscInt_FMT " and %" PetscInt_FMT " do not match: Fault mesh is non-orientable", proc, nproc);
9970851c46eSMatthew G. Knepley               if (!flippedB) {
9980851c46eSMatthew G. Knepley                 PetscCall(PetscBTSet(flippedProcs, nproc));
9990851c46eSMatthew G. Knepley               } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
10000851c46eSMatthew G. Knepley             } else PetscCheck(!mismatch || !flippedA || !flippedB, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
10010851c46eSMatthew G. Knepley             if (!seen) {
10020851c46eSMatthew G. Knepley               procFIFO[pBottom++] = nproc;
10030851c46eSMatthew G. Knepley               PetscCall(PetscBTSet(seenProcs, nproc));
10040851c46eSMatthew G. Knepley             }
10050851c46eSMatthew G. Knepley           }
10060851c46eSMatthew G. Knepley         }
10070851c46eSMatthew G. Knepley       }
10080851c46eSMatthew G. Knepley       PetscCall(PetscFree(procFIFO));
10090851c46eSMatthew G. Knepley       PetscCall(MatDestroy(&G));
10100851c46eSMatthew G. Knepley       PetscCall(PetscFree2(adj, val));
10110851c46eSMatthew G. Knepley       PetscCall(PetscBTDestroy(&seenProcs));
10120851c46eSMatthew G. Knepley     }
10130851c46eSMatthew G. Knepley     /* Scatter flip flags */
10140851c46eSMatthew G. Knepley     {
10150851c46eSMatthew G. Knepley       PetscBool *flips = NULL;
10160851c46eSMatthew G. Knepley 
10170851c46eSMatthew G. Knepley       if (rank == 0) {
10180851c46eSMatthew G. Knepley         PetscCall(PetscMalloc1(Noff[size], &flips));
10190851c46eSMatthew G. Knepley         for (PetscInt p = 0; p < Noff[size]; ++p) {
10200851c46eSMatthew G. Knepley           flips[p] = PetscBTLookup(flippedProcs, p) ? PETSC_TRUE : PETSC_FALSE;
10210851c46eSMatthew G. Knepley           if (view && flips[p]) PetscCall(PetscPrintf(comm, "Flipping Proc+Comp %" PetscInt_FMT ":\n", p));
10220851c46eSMatthew G. Knepley         }
10230851c46eSMatthew G. Knepley         for (PetscInt p = 0; p < size; ++p) displs[p + 1] = displs[p] + Nc[p];
10240851c46eSMatthew G. Knepley       }
10250851c46eSMatthew G. Knepley       PetscCallMPI(MPI_Scatterv(flips, Nc, displs, MPIU_BOOL, flipped, Ncomp, MPIU_BOOL, 0, comm));
10260851c46eSMatthew G. Knepley       PetscCall(PetscFree(flips));
10270851c46eSMatthew G. Knepley     }
10280851c46eSMatthew G. Knepley     if (rank == 0) PetscCall(PetscBTDestroy(&flippedProcs));
10290851c46eSMatthew G. Knepley     PetscCall(PetscFree(N));
10300851c46eSMatthew G. Knepley     PetscCall(PetscFree4(recvcounts, displs, Nc, Noff));
10310851c46eSMatthew G. Knepley     PetscCall(PetscFree2(nrankComp, match));
10320851c46eSMatthew G. Knepley 
10330851c46eSMatthew G. Knepley     /* Decide whether to flip cells in each component */
10340851c46eSMatthew G. Knepley     for (PetscInt c = 0; c < cEnd - cStart; ++c) {
10350851c46eSMatthew G. Knepley       if (flipped[cellComp[c]]) PetscCall(PetscBTNegate(flippedCells, c));
10360851c46eSMatthew G. Knepley     }
10370851c46eSMatthew G. Knepley     PetscCall(PetscFree(flipped));
10380851c46eSMatthew G. Knepley   }
10390851c46eSMatthew G. Knepley   if (view) {
10400851c46eSMatthew G. Knepley     PetscViewer v;
10410851c46eSMatthew G. Knepley 
10420851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
10430851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(v));
10440851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for parallel flipped cells:\n", rank));
10450851c46eSMatthew G. Knepley     PetscCall(PetscBTView(cEnd - cStart, flippedCells, v));
10460851c46eSMatthew G. Knepley     PetscCall(PetscViewerFlush(v));
10470851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(v));
10480851c46eSMatthew G. Knepley   }
10490851c46eSMatthew G. Knepley   // Reverse flipped cells in the mesh
10500851c46eSMatthew G. Knepley   PetscViewer     v;
10510851c46eSMatthew G. Knepley   const PetscInt *degree = NULL;
10520851c46eSMatthew G. Knepley   PetscInt       *points;
10530851c46eSMatthew G. Knepley   PetscInt        pStart, pEnd;
10540851c46eSMatthew G. Knepley 
10550851c46eSMatthew G. Knepley   if (view) {
10560851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
10570851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(v));
10580851c46eSMatthew G. Knepley   }
10590851c46eSMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
10600851c46eSMatthew G. Knepley   if (numRoots >= 0) {
10610851c46eSMatthew G. Knepley     PetscCall(PetscSFComputeDegreeBegin(sf, &degree));
10620851c46eSMatthew G. Knepley     PetscCall(PetscSFComputeDegreeEnd(sf, &degree));
10630851c46eSMatthew G. Knepley   }
10640851c46eSMatthew G. Knepley   PetscCall(PetscCalloc1(pEnd - pStart, &points));
10650851c46eSMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
10660851c46eSMatthew G. Knepley     if (PetscBTLookup(flippedCells, c - cStart)) {
10670851c46eSMatthew G. Knepley       const PetscInt cell = cells ? cells[c] : c;
10680851c46eSMatthew G. Knepley 
10690851c46eSMatthew G. Knepley       PetscCall(DMPlexOrientPoint(dm, cell, -1));
10700851c46eSMatthew G. Knepley       if (degree && degree[cell]) points[cell] = 1;
10710851c46eSMatthew G. Knepley       if (view) PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]Flipping cell %" PetscInt_FMT "%s\n", rank, cell, degree && degree[cell] ? " and sending to overlap" : ""));
10720851c46eSMatthew G. Knepley     }
10730851c46eSMatthew G. Knepley   }
10740851c46eSMatthew G. Knepley   // Must propagate flips for cells in the overlap
10750851c46eSMatthew G. Knepley   if (numRoots >= 0) {
10760851c46eSMatthew G. Knepley     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, points, points, MPI_SUM));
10770851c46eSMatthew G. Knepley     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, points, points, MPI_SUM));
10780851c46eSMatthew G. Knepley   }
10790851c46eSMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
10800851c46eSMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
10810851c46eSMatthew G. Knepley 
10820851c46eSMatthew G. Knepley     if (points[cell] && !PetscBTLookup(flippedCells, c - cStart)) {
10830851c46eSMatthew G. Knepley       PetscCall(DMPlexOrientPoint(dm, cell, -1));
10840851c46eSMatthew G. Knepley       if (view) PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]Flipping cell %" PetscInt_FMT " through overlap\n", rank, cell));
10850851c46eSMatthew G. Knepley     }
10860851c46eSMatthew G. Knepley   }
10870851c46eSMatthew G. Knepley   if (view) {
10880851c46eSMatthew G. Knepley     PetscCall(PetscViewerFlush(v));
10890851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(v));
10900851c46eSMatthew G. Knepley   }
10910851c46eSMatthew G. Knepley   PetscCall(PetscFree(points));
10920851c46eSMatthew G. Knepley   PetscCall(PetscBTDestroy(&flippedCells));
10930851c46eSMatthew G. Knepley   PetscCall(PetscFree2(numNeighbors, neighbors));
10940851c46eSMatthew G. Knepley   PetscCall(PetscFree3(rorntComp, lorntComp, locSupp));
10950851c46eSMatthew G. Knepley   PetscCall(PetscFree2(cellComp, faceComp));
10960851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
109784961fc4SMatthew G. Knepley }
1098