xref: /petsc/src/dm/impls/plex/plexorient.c (revision 57508ece14a6b1339c0bbf016ecd72f673a062b0)
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 
733387f462SBarry Smith     PetscCallAbort(PETSC_COMM_SELF, 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 
2475ef53592SPierre Jolivet .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 */
4736497c311SBarry Smith         if (PetscBTLookup(flippedCells, neighbor - cStart)) rorntComp[face].rank = (PetscMPIInt)(1 - c * 2);
4746497c311SBarry Smith         else rorntComp[face].rank = (PetscMPIInt)(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 */
4826497c311SBarry Smith     PetscCall(PetscSFBcastBegin(sf, MPIU_SF_NODE, rorntComp, lorntComp, MPI_REPLACE));
4836497c311SBarry Smith     PetscCall(PetscSFBcastEnd(sf, MPIU_SF_NODE, 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) {
5016497c311SBarry Smith         const PetscMPIInt rrank = (PetscMPIInt)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)
5126497c311SBarry Smith             PetscCall(PetscViewerASCIIPrintf(selfviewer, "[%d]: component %d, Found representative leaf %" PetscInt_FMT " (face %" PetscInt_FMT ") connecting to face %" PetscInt_FMT " on (%d, %" PetscInt_FMT ") with orientation %d\n", rank, comp, l, face,
5136497c311SBarry Smith                                              rpoints[l].index, rrank, rcomp, (PetscMPIInt)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;
5326497c311SBarry Smith       else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid face %" PetscInt_FMT " (%d, %d) neighbor: %" PetscInt_FMT " comp: %d", face, (PetscMPIInt)rorntComp[face].rank, (PetscMPIInt)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;
5466497c311SBarry Smith     PetscMPIInt *recvcounts = NULL, *displs = NULL, *Nc, p, o, itotNeighbors;
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));
5626497c311SBarry Smith     PetscCall(PetscMPIIntCast(totNeighbors, &itotNeighbors));
5636497c311SBarry Smith     PetscCallMPI(MPI_Gatherv(nrankComp, itotNeighbors, MPIU_SF_NODE, adj, recvcounts, displs, MPIU_SF_NODE, 0, comm));
5646497c311SBarry Smith     PetscCallMPI(MPI_Gatherv(match, itotNeighbors, MPIU_BOOL, val, recvcounts, displs, MPIU_BOOL, 0, comm));
5659566063dSJacob Faibussowitsch     PetscCall(PetscFree2(numNeighbors, neighbors));
566dd400576SPatrick Sanan     if (rank == 0) {
567ad540459SPierre Jolivet       for (p = 1; p <= size; ++p) Noff[p] = Noff[p - 1] + Nc[p - 1];
568a83982f3SMatthew G. Knepley       if (flg) {
569e1d83109SMatthew G. Knepley         PetscInt n;
570e1d83109SMatthew G. Knepley 
5719852e123SBarry Smith         for (p = 0, off = 0; p < size; ++p) {
572e1d83109SMatthew G. Knepley           for (c = 0; c < Nc[p]; ++c) {
57363a3b9bcSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "Proc %d Comp %" PetscInt_FMT ":\n", p, c));
5746497c311SBarry Smith             for (n = 0; n < N[Noff[p] + c]; ++n, ++off) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  edge (%d, %" PetscInt_FMT ") (%s):\n", (PetscMPIInt)adj[off].rank, adj[off].index, PetscBools[val[off]]));
57584961fc4SMatthew G. Knepley           }
57684961fc4SMatthew G. Knepley         }
57784961fc4SMatthew G. Knepley       }
57884961fc4SMatthew G. Knepley       /* Symmetrize the graph */
5799566063dSJacob Faibussowitsch       PetscCall(MatCreate(PETSC_COMM_SELF, &G));
5809566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(G, Noff[size], Noff[size], Noff[size], Noff[size]));
5819566063dSJacob Faibussowitsch       PetscCall(MatSetUp(G));
5829852e123SBarry Smith       for (p = 0, off = 0; p < size; ++p) {
583e1d83109SMatthew G. Knepley         for (c = 0; c < Nc[p]; ++c) {
584e1d83109SMatthew G. Knepley           const PetscInt r = Noff[p] + c;
585e1d83109SMatthew G. Knepley           PetscInt       n;
586e1d83109SMatthew G. Knepley 
587e1d83109SMatthew G. Knepley           for (n = 0; n < N[r]; ++n, ++off) {
588e1d83109SMatthew G. Knepley             const PetscInt    q = Noff[adj[off].rank] + adj[off].index;
589e1d83109SMatthew G. Knepley             const PetscScalar o = val[off] ? 1.0 : 0.0;
59084961fc4SMatthew G. Knepley 
5919566063dSJacob Faibussowitsch             PetscCall(MatSetValues(G, 1, &r, 1, &q, &o, INSERT_VALUES));
5929566063dSJacob Faibussowitsch             PetscCall(MatSetValues(G, 1, &q, 1, &r, &o, INSERT_VALUES));
59384961fc4SMatthew G. Knepley           }
59484961fc4SMatthew G. Knepley         }
595e1d83109SMatthew G. Knepley       }
5969566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(G, MAT_FINAL_ASSEMBLY));
5979566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(G, MAT_FINAL_ASSEMBLY));
59884961fc4SMatthew G. Knepley 
5999566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(Noff[size], &seenProcs));
6009566063dSJacob Faibussowitsch       PetscCall(PetscBTMemzero(Noff[size], seenProcs));
6019566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(Noff[size], &flippedProcs));
6029566063dSJacob Faibussowitsch       PetscCall(PetscBTMemzero(Noff[size], flippedProcs));
6039566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Noff[size], &procFIFO));
60484961fc4SMatthew G. Knepley       pTop = pBottom = 0;
6059852e123SBarry Smith       for (p = 0; p < Noff[size]; ++p) {
60684961fc4SMatthew G. Knepley         if (PetscBTLookup(seenProcs, p)) continue;
60784961fc4SMatthew G. Knepley         /* Initialize FIFO with next proc */
60884961fc4SMatthew G. Knepley         procFIFO[pBottom++] = p;
6099566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(seenProcs, p));
61084961fc4SMatthew G. Knepley         /* Consider each proc in FIFO */
61184961fc4SMatthew G. Knepley         while (pTop < pBottom) {
61284961fc4SMatthew G. Knepley           const PetscScalar *ornt;
61384961fc4SMatthew G. Knepley           const PetscInt    *neighbors;
614e1d83109SMatthew G. Knepley           PetscInt           proc, nproc, seen, flippedA, flippedB, mismatch, numNeighbors, n;
61584961fc4SMatthew G. Knepley 
61684961fc4SMatthew G. Knepley           proc     = procFIFO[pTop++];
61784961fc4SMatthew G. Knepley           flippedA = PetscBTLookup(flippedProcs, proc) ? 1 : 0;
6189566063dSJacob Faibussowitsch           PetscCall(MatGetRow(G, proc, &numNeighbors, &neighbors, &ornt));
61984961fc4SMatthew G. Knepley           /* Loop over neighboring procs */
62084961fc4SMatthew G. Knepley           for (n = 0; n < numNeighbors; ++n) {
62184961fc4SMatthew G. Knepley             nproc    = neighbors[n];
62284961fc4SMatthew G. Knepley             mismatch = PetscRealPart(ornt[n]) > 0.5 ? 0 : 1;
62384961fc4SMatthew G. Knepley             seen     = PetscBTLookup(seenProcs, nproc);
62484961fc4SMatthew G. Knepley             flippedB = PetscBTLookup(flippedProcs, nproc) ? 1 : 0;
62584961fc4SMatthew G. Knepley 
62684961fc4SMatthew G. Knepley             if (mismatch ^ (flippedA ^ flippedB)) {
62763a3b9bcSJacob 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);
62884961fc4SMatthew G. Knepley               if (!flippedB) {
6299566063dSJacob Faibussowitsch                 PetscCall(PetscBTSet(flippedProcs, nproc));
63084961fc4SMatthew G. Knepley               } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
6311dca8a05SBarry Smith             } else PetscCheck(!mismatch || !flippedA || !flippedB, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
63284961fc4SMatthew G. Knepley             if (!seen) {
63384961fc4SMatthew G. Knepley               procFIFO[pBottom++] = nproc;
6349566063dSJacob Faibussowitsch               PetscCall(PetscBTSet(seenProcs, nproc));
63584961fc4SMatthew G. Knepley             }
63684961fc4SMatthew G. Knepley           }
63784961fc4SMatthew G. Knepley         }
63884961fc4SMatthew G. Knepley       }
6399566063dSJacob Faibussowitsch       PetscCall(PetscFree(procFIFO));
6409566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&G));
6419566063dSJacob Faibussowitsch       PetscCall(PetscFree2(adj, val));
6429566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&seenProcs));
64384961fc4SMatthew G. Knepley     }
644e1d83109SMatthew G. Knepley     /* Scatter flip flags */
645e1d83109SMatthew G. Knepley     {
646e1d83109SMatthew G. Knepley       PetscBool *flips = NULL;
647e1d83109SMatthew G. Knepley 
648dd400576SPatrick Sanan       if (rank == 0) {
6499566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(Noff[size], &flips));
6509852e123SBarry Smith         for (p = 0; p < Noff[size]; ++p) {
651e1d83109SMatthew G. Knepley           flips[p] = PetscBTLookup(flippedProcs, p) ? PETSC_TRUE : PETSC_FALSE;
6529566063dSJacob Faibussowitsch           if (flg && flips[p]) PetscCall(PetscPrintf(comm, "Flipping Proc+Comp %d:\n", p));
653e1d83109SMatthew G. Knepley         }
654ad540459SPierre Jolivet         for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + Nc[p];
655e1d83109SMatthew G. Knepley       }
6569566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Scatterv(flips, Nc, displs, MPIU_BOOL, flipped, numComponents, MPIU_BOOL, 0, comm));
6579566063dSJacob Faibussowitsch       PetscCall(PetscFree(flips));
65884961fc4SMatthew G. Knepley     }
6599566063dSJacob Faibussowitsch     if (rank == 0) PetscCall(PetscBTDestroy(&flippedProcs));
6609566063dSJacob Faibussowitsch     PetscCall(PetscFree(N));
6619566063dSJacob Faibussowitsch     PetscCall(PetscFree4(recvcounts, displs, Nc, Noff));
6629566063dSJacob Faibussowitsch     PetscCall(PetscFree2(nrankComp, match));
663e1d83109SMatthew G. Knepley 
664e1d83109SMatthew G. Knepley     /* Decide whether to flip cells in each component */
6659371c9d4SSatish Balay     for (c = 0; c < cEnd - cStart; ++c) {
6669371c9d4SSatish Balay       if (flipped[cellComp[c]]) PetscCall(PetscBTNegate(flippedCells, c));
6679371c9d4SSatish Balay     }
6689566063dSJacob Faibussowitsch     PetscCall(PetscFree(flipped));
66984961fc4SMatthew G. Knepley   }
67084961fc4SMatthew G. Knepley   if (flg) {
67184961fc4SMatthew G. Knepley     PetscViewer v;
67284961fc4SMatthew G. Knepley 
6739566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
6749566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(v));
6759566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for parallel flipped cells:\n", rank));
6769566063dSJacob Faibussowitsch     PetscCall(PetscBTView(cEnd - cStart, flippedCells, v));
6779566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(v));
6789566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(v));
67984961fc4SMatthew G. Knepley   }
68084961fc4SMatthew G. Knepley   /* Reverse flipped cells in the mesh */
68184961fc4SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
68248a46eb9SPierre Jolivet     if (PetscBTLookup(flippedCells, c - cStart)) PetscCall(DMPlexOrientPoint(dm, c, -1));
68384961fc4SMatthew G. Knepley   }
6849566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&seenCells));
6859566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&flippedCells));
6869566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&seenFaces));
6879566063dSJacob Faibussowitsch   PetscCall(PetscFree2(numNeighbors, neighbors));
6883d6051bcSMatthew G. Knepley   PetscCall(PetscFree3(rorntComp, lorntComp, locSupport));
6899566063dSJacob Faibussowitsch   PetscCall(PetscFree3(faceFIFO, cellComp, faceComp));
6903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6910851c46eSMatthew G. Knepley #endif
6920851c46eSMatthew G. Knepley }
6930851c46eSMatthew G. Knepley 
6940851c46eSMatthew G. Knepley static PetscErrorCode CreateCellAndFaceIS_Private(DM dm, DMLabel label, IS *cellIS, IS *faceIS)
6950851c46eSMatthew G. Knepley {
6960851c46eSMatthew G. Knepley   IS              valueIS;
6970851c46eSMatthew G. Knepley   const PetscInt *values;
6980851c46eSMatthew G. Knepley   PetscInt        Nv, depth = 0;
6990851c46eSMatthew G. Knepley 
7000851c46eSMatthew G. Knepley   PetscFunctionBegin;
7010851c46eSMatthew G. Knepley   PetscCall(DMLabelGetValueIS(label, &valueIS));
7020851c46eSMatthew G. Knepley   PetscCall(ISGetLocalSize(valueIS, &Nv));
7030851c46eSMatthew G. Knepley   PetscCall(ISGetIndices(valueIS, &values));
7040851c46eSMatthew G. Knepley   for (PetscInt v = 0; v < Nv; ++v) {
7050851c46eSMatthew G. Knepley     const PetscInt val = values[v] < 0 || values[v] >= 100 ? 0 : values[v];
706f369e074SMatthew G. Knepley     PetscInt       n;
7070851c46eSMatthew G. Knepley 
708f369e074SMatthew G. Knepley     PetscCall(DMLabelGetStratumSize(label, val, &n));
709f369e074SMatthew G. Knepley     if (!n) continue;
7100851c46eSMatthew G. Knepley     depth = PetscMax(val, depth);
7110851c46eSMatthew G. Knepley   }
7120851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&valueIS));
7130851c46eSMatthew 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);
7140851c46eSMatthew G. Knepley   PetscCall(DMLabelGetStratumIS(label, depth, cellIS));
7150851c46eSMatthew G. Knepley   PetscCall(DMLabelGetStratumIS(label, depth - 1, faceIS));
716*57508eceSPierre Jolivet   if (!*cellIS) PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, cellIS));
717*57508eceSPierre Jolivet   if (!*faceIS) PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, faceIS));
7180851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
7190851c46eSMatthew G. Knepley }
7200851c46eSMatthew G. Knepley 
7210851c46eSMatthew G. Knepley PetscErrorCode DMPlexOrientLabel(DM dm, DMLabel label)
7220851c46eSMatthew G. Knepley {
7230851c46eSMatthew G. Knepley   IS cellIS, faceIS;
7240851c46eSMatthew G. Knepley 
7250851c46eSMatthew G. Knepley   PetscFunctionBegin;
7260851c46eSMatthew G. Knepley   PetscCall(CreateCellAndFaceIS_Private(dm, label, &cellIS, &faceIS));
7270851c46eSMatthew G. Knepley   PetscCall(DMPlexOrientCells_Internal(dm, cellIS, faceIS));
7280851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
7290851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&faceIS));
7300851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
7310851c46eSMatthew G. Knepley }
7320851c46eSMatthew G. Knepley 
7330851c46eSMatthew G. Knepley PetscErrorCode DMPlexOrientCells_Internal(DM dm, IS cellIS, IS faceIS)
7340851c46eSMatthew G. Knepley {
7350851c46eSMatthew G. Knepley   MPI_Comm           comm;
7360851c46eSMatthew G. Knepley   PetscSF            sf;
7370851c46eSMatthew G. Knepley   const PetscInt    *lpoints;
7380851c46eSMatthew G. Knepley   const PetscSFNode *rpoints;
7390851c46eSMatthew G. Knepley   PetscSFNode       *rorntComp = NULL, *lorntComp = NULL;
7400851c46eSMatthew G. Knepley   PetscInt          *numNeighbors, **neighbors, *locSupp = NULL;
7410851c46eSMatthew G. Knepley   PetscSFNode       *nrankComp;
7420851c46eSMatthew G. Knepley   PetscBool         *match, *flipped;
7430851c46eSMatthew G. Knepley   PetscBT            flippedCells;
7440851c46eSMatthew G. Knepley   PetscInt          *cellComp, *faceComp;
7450851c46eSMatthew G. Knepley   const PetscInt    *cells = NULL, *faces = NULL;
7460851c46eSMatthew G. Knepley   PetscInt           cStart = 0, cEnd = 0, fStart = 0, fEnd = 0;
7470851c46eSMatthew G. Knepley   PetscInt           numLeaves, numRoots, dim, Ncomp, totNeighbors = 0;
7480851c46eSMatthew G. Knepley   PetscMPIInt        rank, size;
7490851c46eSMatthew G. Knepley   PetscBool          view, viewSync;
7500851c46eSMatthew G. Knepley   PetscViewer        viewer = NULL, selfviewer = NULL;
7510851c46eSMatthew G. Knepley 
7520851c46eSMatthew G. Knepley   PetscFunctionBegin;
7530851c46eSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
7540851c46eSMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7550851c46eSMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(comm, &size));
7560851c46eSMatthew G. Knepley   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-orientation_view", &view));
7570851c46eSMatthew G. Knepley   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-orientation_view_synchronized", &viewSync));
7580851c46eSMatthew G. Knepley 
7590851c46eSMatthew G. Knepley   if (cellIS) PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
7600851c46eSMatthew G. Knepley   if (faceIS) PetscCall(ISGetPointRange(faceIS, &fStart, &fEnd, &faces));
7610851c46eSMatthew G. Knepley   PetscCall(DMGetPointSF(dm, &sf));
7620851c46eSMatthew G. Knepley   PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &lpoints, &rpoints));
7630851c46eSMatthew G. Knepley   /* Truth Table
7640851c46eSMatthew G. Knepley      mismatch    flips   do action   mismatch   flipA ^ flipB   action
7650851c46eSMatthew G. Knepley          F       0 flips     no         F             F           F
7660851c46eSMatthew G. Knepley          F       1 flip      yes        F             T           T
7670851c46eSMatthew G. Knepley          F       2 flips     no         T             F           T
7680851c46eSMatthew G. Knepley          T       0 flips     yes        T             T           F
7690851c46eSMatthew G. Knepley          T       1 flip      no
7700851c46eSMatthew G. Knepley          T       2 flips     yes
7710851c46eSMatthew G. Knepley   */
7720851c46eSMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
7730851c46eSMatthew G. Knepley   PetscCall(PetscBTCreate(cEnd - cStart, &flippedCells));
7740851c46eSMatthew G. Knepley   PetscCall(PetscBTMemzero(cEnd - cStart, flippedCells));
7750851c46eSMatthew G. Knepley   PetscCall(PetscCalloc2(cEnd - cStart, &cellComp, fEnd - fStart, &faceComp));
7760851c46eSMatthew G. Knepley   /*
7770851c46eSMatthew G. Knepley    OLD STYLE
7780851c46eSMatthew G. Knepley    - Add an integer array over cells and faces (component) for connected component number
7790851c46eSMatthew G. Knepley    Foreach component
7800851c46eSMatthew G. Knepley      - Mark the initial cell as seen
7810851c46eSMatthew G. Knepley      - Process component as usual
7820851c46eSMatthew G. Knepley      - Set component for all seenCells
7830851c46eSMatthew G. Knepley      - Wipe seenCells and seenFaces (flippedCells can stay)
7840851c46eSMatthew G. Knepley    - Generate parallel adjacency for component using SF and seenFaces
7850851c46eSMatthew G. Knepley    - Collect Ncomp adj data from each proc to 0
7860851c46eSMatthew G. Knepley    - Build same serial graph
7870851c46eSMatthew G. Knepley    - Use same solver
7880851c46eSMatthew G. Knepley    - Use Scatterv to send back flipped flags for each component
7890851c46eSMatthew G. Knepley    - Negate flippedCells by component
7900851c46eSMatthew G. Knepley 
7910851c46eSMatthew G. Knepley    NEW STYLE
7920851c46eSMatthew G. Knepley    - Create the adj on each process
7930851c46eSMatthew G. Knepley    - Bootstrap to complete graph on proc 0
7940851c46eSMatthew G. Knepley   */
7950851c46eSMatthew G. Knepley   PetscCall(DMPlexOrient_Serial(dm, cellIS, faceIS, &Ncomp, cellComp, faceComp, flippedCells));
7960851c46eSMatthew G. Knepley   if (view) {
7970851c46eSMatthew G. Knepley     PetscViewer v;
79876dc4c7dSMatthew G. Knepley     PetscInt    cdepth = -1;
7990851c46eSMatthew G. Knepley 
8000851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
8010851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(v));
80276dc4c7dSMatthew G. Knepley     if (cEnd > cStart) PetscCall(DMPlexGetPointDepth(dm, cells ? cells[cStart] : cStart, &cdepth));
80376dc4c7dSMatthew G. Knepley     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]New Orientation %" PetscInt_FMT " cells (depth %" PetscInt_FMT ") and %" PetscInt_FMT " faces\n", rank, cEnd - cStart, cdepth, fEnd - fStart));
8040851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for serial flipped cells:\n", rank));
8050851c46eSMatthew G. Knepley     PetscCall(PetscBTView(cEnd - cStart, flippedCells, v));
8060851c46eSMatthew G. Knepley     PetscCall(PetscViewerFlush(v));
8070851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(v));
8080851c46eSMatthew G. Knepley   }
8090851c46eSMatthew G. Knepley   /* Now all subdomains are oriented, but we need a consistent parallel orientation */
8100851c46eSMatthew G. Knepley   // TODO: This all has to be rewritten to filter cones/supports to the ISes
8110851c46eSMatthew G. Knepley   if (numLeaves >= 0) {
8120851c46eSMatthew G. Knepley     PetscInt maxSuppSize, neighbor;
8130851c46eSMatthew G. Knepley 
8140851c46eSMatthew G. Knepley     // Store orientations of boundary faces
8150851c46eSMatthew G. Knepley     PetscCall(DMPlexGetMaxSizes(dm, NULL, &maxSuppSize));
8160851c46eSMatthew G. Knepley     PetscCall(PetscCalloc3(numRoots, &rorntComp, numRoots, &lorntComp, maxSuppSize, &locSupp));
8170851c46eSMatthew G. Knepley     for (PetscInt f = fStart; f < fEnd; ++f) {
8180851c46eSMatthew G. Knepley       const PetscInt  face = faces ? faces[f] : f;
8190851c46eSMatthew G. Knepley       const PetscInt *cone, *supp, *ornt;
8200851c46eSMatthew G. Knepley       PetscInt        coneSize, suppSize, nind, c, Ns = 0;
8210851c46eSMatthew G. Knepley 
8220851c46eSMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, face, &suppSize));
8230851c46eSMatthew G. Knepley       PetscCall(DMPlexGetSupport(dm, face, &supp));
8240851c46eSMatthew G. Knepley       for (PetscInt s = 0; s < suppSize; ++s) {
8250851c46eSMatthew G. Knepley         PetscInt ind, l;
8260851c46eSMatthew G. Knepley 
8270851c46eSMatthew G. Knepley         // Filter support
8280851c46eSMatthew G. Knepley         ind = GetPointIndex(supp[s], cStart, cEnd, cells);
8290851c46eSMatthew G. Knepley         if (ind < 0) continue;
8300851c46eSMatthew G. Knepley         // Ignore overlapping cells
8310851c46eSMatthew G. Knepley         PetscCall(PetscFindInt(supp[s], numLeaves, lpoints, &l));
8320851c46eSMatthew G. Knepley         if (l >= 0) continue;
8330851c46eSMatthew G. Knepley         locSupp[Ns++] = supp[s];
8340851c46eSMatthew G. Knepley       }
83517d25f2dSMatthew G. Knepley       PetscCheck(Ns < maxSuppSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Index %" PetscInt_FMT " exceeds array size %" PetscInt_FMT, Ns, maxSuppSize);
8360851c46eSMatthew G. Knepley       if (Ns != 1) continue;
8370851c46eSMatthew G. Knepley       neighbor = locSupp[0];
8380851c46eSMatthew G. Knepley       nind     = GetPointIndex(neighbor, cStart, cEnd, cells);
8390851c46eSMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, neighbor, &cone));
8400851c46eSMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, neighbor, &coneSize));
8410851c46eSMatthew G. Knepley       PetscCall(DMPlexGetConeOrientation(dm, neighbor, &ornt));
8420851c46eSMatthew G. Knepley       for (c = 0; c < coneSize; ++c)
8430851c46eSMatthew G. Knepley         if (cone[c] == face) break;
8440851c46eSMatthew G. Knepley       if (dim == 1) {
8450851c46eSMatthew G. Knepley         /* Use cone position instead, shifted to -1 or 1 */
8466497c311SBarry Smith         if (PetscBTLookup(flippedCells, nind)) rorntComp[face].rank = (PetscMPIInt)(1 - c * 2);
8476497c311SBarry Smith         else rorntComp[face].rank = (PetscMPIInt)(c * 2 - 1);
8480851c46eSMatthew G. Knepley       } else {
8490851c46eSMatthew G. Knepley         if (PetscBTLookup(flippedCells, nind)) rorntComp[face].rank = ornt[c] < 0 ? -1 : 1;
8500851c46eSMatthew G. Knepley         else rorntComp[face].rank = ornt[c] < 0 ? 1 : -1;
8510851c46eSMatthew G. Knepley       }
8520851c46eSMatthew G. Knepley       rorntComp[face].index = faceComp[GetPointIndex(face, fStart, fEnd, faces)];
8530851c46eSMatthew G. Knepley     }
8540851c46eSMatthew G. Knepley     // Communicate boundary edge orientations
8556497c311SBarry Smith     PetscCall(PetscSFBcastBegin(sf, MPIU_SF_NODE, rorntComp, lorntComp, MPI_REPLACE));
8566497c311SBarry Smith     PetscCall(PetscSFBcastEnd(sf, MPIU_SF_NODE, rorntComp, lorntComp, MPI_REPLACE));
8570851c46eSMatthew G. Knepley   }
8580851c46eSMatthew G. Knepley   /* Get process adjacency */
8590851c46eSMatthew G. Knepley   PetscCall(PetscMalloc2(Ncomp, &numNeighbors, Ncomp, &neighbors));
8600851c46eSMatthew G. Knepley   viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm));
8610851c46eSMatthew G. Knepley   if (viewSync) PetscCall(PetscViewerASCIIPushSynchronized(viewer));
8620851c46eSMatthew G. Knepley   PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
8630851c46eSMatthew G. Knepley   for (PetscInt comp = 0; comp < Ncomp; ++comp) {
8640851c46eSMatthew G. Knepley     PetscInt n;
8650851c46eSMatthew G. Knepley 
8660851c46eSMatthew G. Knepley     numNeighbors[comp] = 0;
8670851c46eSMatthew G. Knepley     PetscCall(PetscMalloc1(PetscMax(numLeaves, 0), &neighbors[comp]));
8680851c46eSMatthew G. Knepley     /* I know this is p^2 time in general, but for bounded degree its alright */
8690851c46eSMatthew G. Knepley     for (PetscInt l = 0; l < numLeaves; ++l) {
8700851c46eSMatthew G. Knepley       const PetscInt face = lpoints[l];
8710851c46eSMatthew G. Knepley       PetscInt       find;
8720851c46eSMatthew G. Knepley 
8730851c46eSMatthew G. Knepley       /* Find a representative face (edge) separating pairs of procs */
8740851c46eSMatthew G. Knepley       find = GetPointIndex(face, fStart, fEnd, faces);
8750851c46eSMatthew G. Knepley       if ((find >= 0) && (faceComp[find] == comp) && rorntComp[face].rank) {
8760851c46eSMatthew G. Knepley         const PetscInt rrank = rpoints[l].rank;
8770851c46eSMatthew G. Knepley         const PetscInt rcomp = lorntComp[face].index;
8780851c46eSMatthew G. Knepley 
8790851c46eSMatthew G. Knepley         for (n = 0; n < numNeighbors[comp]; ++n)
8800851c46eSMatthew G. Knepley           if ((rrank == rpoints[neighbors[comp][n]].rank) && (rcomp == lorntComp[lpoints[neighbors[comp][n]]].index)) break;
8810851c46eSMatthew G. Knepley         if (n >= numNeighbors[comp]) {
8820851c46eSMatthew G. Knepley           const PetscInt *supp;
8830851c46eSMatthew G. Knepley           PetscInt        suppSize, Ns = 0;
8840851c46eSMatthew G. Knepley 
8850851c46eSMatthew G. Knepley           PetscCall(DMPlexGetSupport(dm, face, &supp));
8860851c46eSMatthew G. Knepley           PetscCall(DMPlexGetSupportSize(dm, face, &suppSize));
8870851c46eSMatthew G. Knepley           for (PetscInt s = 0; s < suppSize; ++s) {
8880851c46eSMatthew G. Knepley             // Filter support
8890851c46eSMatthew G. Knepley             if (GetPointIndex(supp[s], cStart, cEnd, cells) >= 0) ++Ns;
8900851c46eSMatthew G. Knepley           }
8910851c46eSMatthew 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);
8920851c46eSMatthew G. Knepley           if (view)
8936497c311SBarry Smith             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 %d\n", rank, comp, l, face,
8946497c311SBarry Smith                                              rpoints[l].index, rrank, rcomp, (PetscMPIInt)lorntComp[face].rank));
8950851c46eSMatthew G. Knepley           neighbors[comp][numNeighbors[comp]++] = l;
8960851c46eSMatthew G. Knepley         }
8970851c46eSMatthew G. Knepley       }
8980851c46eSMatthew G. Knepley     }
8990851c46eSMatthew G. Knepley     totNeighbors += numNeighbors[comp];
9000851c46eSMatthew G. Knepley   }
9010851c46eSMatthew G. Knepley   PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
9020851c46eSMatthew G. Knepley   if (viewSync) PetscCall(PetscViewerASCIIPopSynchronized(viewer));
9030851c46eSMatthew G. Knepley   PetscCall(PetscMalloc2(totNeighbors, &nrankComp, totNeighbors, &match));
9040851c46eSMatthew G. Knepley   for (PetscInt comp = 0, off = 0; comp < Ncomp; ++comp) {
9050851c46eSMatthew G. Knepley     for (PetscInt n = 0; n < numNeighbors[comp]; ++n, ++off) {
9060851c46eSMatthew G. Knepley       const PetscInt face = lpoints[neighbors[comp][n]];
9070851c46eSMatthew G. Knepley       const PetscInt o    = rorntComp[face].rank * lorntComp[face].rank;
9080851c46eSMatthew G. Knepley 
9090851c46eSMatthew G. Knepley       if (o < 0) match[off] = PETSC_TRUE;
9100851c46eSMatthew G. Knepley       else if (o > 0) match[off] = PETSC_FALSE;
9110851c46eSMatthew G. Knepley       else
9126497c311SBarry Smith         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid face %" PetscInt_FMT " (%d, %d) neighbor: %" PetscInt_FMT " comp: %" PetscInt_FMT, face, (PetscMPIInt)rorntComp[face].rank, (PetscMPIInt)lorntComp[face].rank, neighbors[comp][n], comp);
9130851c46eSMatthew G. Knepley       nrankComp[off].rank  = rpoints[neighbors[comp][n]].rank;
9140851c46eSMatthew G. Knepley       nrankComp[off].index = lorntComp[lpoints[neighbors[comp][n]]].index;
9150851c46eSMatthew G. Knepley     }
9160851c46eSMatthew G. Knepley     PetscCall(PetscFree(neighbors[comp]));
9170851c46eSMatthew G. Knepley   }
9180851c46eSMatthew G. Knepley   /* Collect the graph on 0 */
9190851c46eSMatthew G. Knepley   if (numLeaves >= 0) {
9200851c46eSMatthew G. Knepley     Mat          G;
9210851c46eSMatthew G. Knepley     PetscBT      seenProcs, flippedProcs;
9220851c46eSMatthew G. Knepley     PetscInt    *procFIFO, pTop, pBottom;
9230851c46eSMatthew G. Knepley     PetscInt    *N          = NULL, *Noff;
9240851c46eSMatthew G. Knepley     PetscSFNode *adj        = NULL;
9250851c46eSMatthew G. Knepley     PetscBool   *val        = NULL;
9260851c46eSMatthew G. Knepley     PetscMPIInt *recvcounts = NULL, *displs = NULL, *Nc;
9276497c311SBarry Smith     PetscMPIInt  size = 0, iNcomp, itotNeighbors;
9280851c46eSMatthew G. Knepley 
9290851c46eSMatthew G. Knepley     PetscCall(PetscCalloc1(Ncomp, &flipped));
9300851c46eSMatthew G. Knepley     if (rank == 0) PetscCallMPI(MPI_Comm_size(comm, &size));
9310851c46eSMatthew G. Knepley     PetscCall(PetscCalloc4(size, &recvcounts, size + 1, &displs, size, &Nc, size + 1, &Noff));
9320851c46eSMatthew G. Knepley     PetscCallMPI(MPI_Gather(&Ncomp, 1, MPI_INT, Nc, 1, MPI_INT, 0, comm));
9330851c46eSMatthew G. Knepley     for (PetscInt p = 0; p < size; ++p) displs[p + 1] = displs[p] + Nc[p];
9340851c46eSMatthew G. Knepley     if (rank == 0) PetscCall(PetscMalloc1(displs[size], &N));
9356497c311SBarry Smith     PetscCall(PetscMPIIntCast(Ncomp, &iNcomp));
9366497c311SBarry Smith     PetscCallMPI(MPI_Gatherv(numNeighbors, iNcomp, MPIU_INT, N, Nc, displs, MPIU_INT, 0, comm));
9370851c46eSMatthew G. Knepley     for (PetscInt p = 0, o = 0; p < size; ++p) {
9380851c46eSMatthew G. Knepley       recvcounts[p] = 0;
9390851c46eSMatthew G. Knepley       for (PetscInt c = 0; c < Nc[p]; ++c, ++o) recvcounts[p] += N[o];
9400851c46eSMatthew G. Knepley       displs[p + 1] = displs[p] + recvcounts[p];
9410851c46eSMatthew G. Knepley     }
9420851c46eSMatthew G. Knepley     if (rank == 0) PetscCall(PetscMalloc2(displs[size], &adj, displs[size], &val));
9436497c311SBarry Smith     PetscCall(PetscMPIIntCast(totNeighbors, &itotNeighbors));
9446497c311SBarry Smith     PetscCallMPI(MPI_Gatherv(nrankComp, itotNeighbors, MPIU_SF_NODE, adj, recvcounts, displs, MPIU_SF_NODE, 0, comm));
9456497c311SBarry Smith     PetscCallMPI(MPI_Gatherv(match, itotNeighbors, MPIU_BOOL, val, recvcounts, displs, MPIU_BOOL, 0, comm));
9460851c46eSMatthew G. Knepley     PetscCall(PetscFree2(numNeighbors, neighbors));
9470851c46eSMatthew G. Knepley     if (rank == 0) {
9480851c46eSMatthew G. Knepley       for (PetscInt p = 1; p <= size; ++p) Noff[p] = Noff[p - 1] + Nc[p - 1];
9490851c46eSMatthew G. Knepley       if (view) {
9500851c46eSMatthew G. Knepley         for (PetscInt p = 0, off = 0; p < size; ++p) {
9510851c46eSMatthew G. Knepley           for (PetscInt c = 0; c < Nc[p]; ++c) {
9520851c46eSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "Proc %" PetscInt_FMT " Comp %" PetscInt_FMT ":\n", p, c));
9536497c311SBarry Smith             for (PetscInt n = 0; n < N[Noff[p] + c]; ++n, ++off) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  edge (%d, %" PetscInt_FMT ") (%s):\n", (PetscMPIInt)adj[off].rank, adj[off].index, PetscBools[val[off]]));
9540851c46eSMatthew G. Knepley           }
9550851c46eSMatthew G. Knepley         }
9560851c46eSMatthew G. Knepley       }
9570851c46eSMatthew G. Knepley       /* Symmetrize the graph */
9580851c46eSMatthew G. Knepley       PetscCall(MatCreate(PETSC_COMM_SELF, &G));
9590851c46eSMatthew G. Knepley       PetscCall(MatSetSizes(G, Noff[size], Noff[size], Noff[size], Noff[size]));
9600851c46eSMatthew G. Knepley       PetscCall(MatSetUp(G));
9610851c46eSMatthew G. Knepley       for (PetscInt p = 0, off = 0; p < size; ++p) {
9620851c46eSMatthew G. Knepley         for (PetscInt c = 0; c < Nc[p]; ++c) {
9630851c46eSMatthew G. Knepley           const PetscInt r = Noff[p] + c;
9640851c46eSMatthew G. Knepley 
9650851c46eSMatthew G. Knepley           for (PetscInt n = 0; n < N[r]; ++n, ++off) {
9660851c46eSMatthew G. Knepley             const PetscInt    q = Noff[adj[off].rank] + adj[off].index;
9670851c46eSMatthew G. Knepley             const PetscScalar o = val[off] ? 1.0 : 0.0;
9680851c46eSMatthew G. Knepley 
9690851c46eSMatthew G. Knepley             PetscCall(MatSetValues(G, 1, &r, 1, &q, &o, INSERT_VALUES));
9700851c46eSMatthew G. Knepley             PetscCall(MatSetValues(G, 1, &q, 1, &r, &o, INSERT_VALUES));
9710851c46eSMatthew G. Knepley           }
9720851c46eSMatthew G. Knepley         }
9730851c46eSMatthew G. Knepley       }
9740851c46eSMatthew G. Knepley       PetscCall(MatAssemblyBegin(G, MAT_FINAL_ASSEMBLY));
9750851c46eSMatthew G. Knepley       PetscCall(MatAssemblyEnd(G, MAT_FINAL_ASSEMBLY));
9760851c46eSMatthew G. Knepley 
9770851c46eSMatthew G. Knepley       PetscCall(PetscBTCreate(Noff[size], &seenProcs));
9780851c46eSMatthew G. Knepley       PetscCall(PetscBTMemzero(Noff[size], seenProcs));
9790851c46eSMatthew G. Knepley       PetscCall(PetscBTCreate(Noff[size], &flippedProcs));
9800851c46eSMatthew G. Knepley       PetscCall(PetscBTMemzero(Noff[size], flippedProcs));
9810851c46eSMatthew G. Knepley       PetscCall(PetscMalloc1(Noff[size], &procFIFO));
9820851c46eSMatthew G. Knepley       pTop = pBottom = 0;
9830851c46eSMatthew G. Knepley       for (PetscInt p = 0; p < Noff[size]; ++p) {
9840851c46eSMatthew G. Knepley         if (PetscBTLookup(seenProcs, p)) continue;
9850851c46eSMatthew G. Knepley         /* Initialize FIFO with next proc */
9860851c46eSMatthew G. Knepley         procFIFO[pBottom++] = p;
9870851c46eSMatthew G. Knepley         PetscCall(PetscBTSet(seenProcs, p));
9880851c46eSMatthew G. Knepley         /* Consider each proc in FIFO */
9890851c46eSMatthew G. Knepley         while (pTop < pBottom) {
9900851c46eSMatthew G. Knepley           const PetscScalar *ornt;
9910851c46eSMatthew G. Knepley           const PetscInt    *neighbors;
9920851c46eSMatthew G. Knepley           PetscInt           proc, nproc, seen, flippedA, flippedB, mismatch, numNeighbors;
9930851c46eSMatthew G. Knepley 
9940851c46eSMatthew G. Knepley           proc     = procFIFO[pTop++];
9950851c46eSMatthew G. Knepley           flippedA = PetscBTLookup(flippedProcs, proc) ? 1 : 0;
9960851c46eSMatthew G. Knepley           PetscCall(MatGetRow(G, proc, &numNeighbors, &neighbors, &ornt));
9970851c46eSMatthew G. Knepley           /* Loop over neighboring procs */
9980851c46eSMatthew G. Knepley           for (PetscInt n = 0; n < numNeighbors; ++n) {
9990851c46eSMatthew G. Knepley             nproc    = neighbors[n];
10000851c46eSMatthew G. Knepley             mismatch = PetscRealPart(ornt[n]) > 0.5 ? 0 : 1;
10010851c46eSMatthew G. Knepley             seen     = PetscBTLookup(seenProcs, nproc);
10020851c46eSMatthew G. Knepley             flippedB = PetscBTLookup(flippedProcs, nproc) ? 1 : 0;
10030851c46eSMatthew G. Knepley 
10040851c46eSMatthew G. Knepley             if (mismatch ^ (flippedA ^ flippedB)) {
10050851c46eSMatthew 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);
10060851c46eSMatthew G. Knepley               if (!flippedB) {
10070851c46eSMatthew G. Knepley                 PetscCall(PetscBTSet(flippedProcs, nproc));
10080851c46eSMatthew G. Knepley               } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
10090851c46eSMatthew 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");
10100851c46eSMatthew G. Knepley             if (!seen) {
10110851c46eSMatthew G. Knepley               procFIFO[pBottom++] = nproc;
10120851c46eSMatthew G. Knepley               PetscCall(PetscBTSet(seenProcs, nproc));
10130851c46eSMatthew G. Knepley             }
10140851c46eSMatthew G. Knepley           }
10150851c46eSMatthew G. Knepley         }
10160851c46eSMatthew G. Knepley       }
10170851c46eSMatthew G. Knepley       PetscCall(PetscFree(procFIFO));
10180851c46eSMatthew G. Knepley       PetscCall(MatDestroy(&G));
10190851c46eSMatthew G. Knepley       PetscCall(PetscFree2(adj, val));
10200851c46eSMatthew G. Knepley       PetscCall(PetscBTDestroy(&seenProcs));
10210851c46eSMatthew G. Knepley     }
10220851c46eSMatthew G. Knepley     /* Scatter flip flags */
10230851c46eSMatthew G. Knepley     {
10240851c46eSMatthew G. Knepley       PetscBool *flips = NULL;
10250851c46eSMatthew G. Knepley 
10260851c46eSMatthew G. Knepley       if (rank == 0) {
10270851c46eSMatthew G. Knepley         PetscCall(PetscMalloc1(Noff[size], &flips));
10280851c46eSMatthew G. Knepley         for (PetscInt p = 0; p < Noff[size]; ++p) {
10290851c46eSMatthew G. Knepley           flips[p] = PetscBTLookup(flippedProcs, p) ? PETSC_TRUE : PETSC_FALSE;
10300851c46eSMatthew G. Knepley           if (view && flips[p]) PetscCall(PetscPrintf(comm, "Flipping Proc+Comp %" PetscInt_FMT ":\n", p));
10310851c46eSMatthew G. Knepley         }
10320851c46eSMatthew G. Knepley         for (PetscInt p = 0; p < size; ++p) displs[p + 1] = displs[p] + Nc[p];
10330851c46eSMatthew G. Knepley       }
10346497c311SBarry Smith       PetscCall(PetscMPIIntCast(Ncomp, &iNcomp));
10356497c311SBarry Smith       PetscCallMPI(MPI_Scatterv(flips, Nc, displs, MPIU_BOOL, flipped, iNcomp, MPIU_BOOL, 0, comm));
10360851c46eSMatthew G. Knepley       PetscCall(PetscFree(flips));
10370851c46eSMatthew G. Knepley     }
10380851c46eSMatthew G. Knepley     if (rank == 0) PetscCall(PetscBTDestroy(&flippedProcs));
10390851c46eSMatthew G. Knepley     PetscCall(PetscFree(N));
10400851c46eSMatthew G. Knepley     PetscCall(PetscFree4(recvcounts, displs, Nc, Noff));
10410851c46eSMatthew G. Knepley     PetscCall(PetscFree2(nrankComp, match));
10420851c46eSMatthew G. Knepley 
10430851c46eSMatthew G. Knepley     /* Decide whether to flip cells in each component */
10440851c46eSMatthew G. Knepley     for (PetscInt c = 0; c < cEnd - cStart; ++c) {
10450851c46eSMatthew G. Knepley       if (flipped[cellComp[c]]) PetscCall(PetscBTNegate(flippedCells, c));
10460851c46eSMatthew G. Knepley     }
10470851c46eSMatthew G. Knepley     PetscCall(PetscFree(flipped));
10480851c46eSMatthew G. Knepley   }
10490851c46eSMatthew G. Knepley   if (view) {
10500851c46eSMatthew G. Knepley     PetscViewer v;
10510851c46eSMatthew G. Knepley 
10520851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
10530851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(v));
10540851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for parallel flipped cells:\n", rank));
10550851c46eSMatthew G. Knepley     PetscCall(PetscBTView(cEnd - cStart, flippedCells, v));
10560851c46eSMatthew G. Knepley     PetscCall(PetscViewerFlush(v));
10570851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(v));
10580851c46eSMatthew G. Knepley   }
10590851c46eSMatthew G. Knepley   // Reverse flipped cells in the mesh
10600851c46eSMatthew G. Knepley   PetscViewer     v;
10610851c46eSMatthew G. Knepley   const PetscInt *degree = NULL;
10620851c46eSMatthew G. Knepley   PetscInt       *points;
10630851c46eSMatthew G. Knepley   PetscInt        pStart, pEnd;
10640851c46eSMatthew G. Knepley 
10650851c46eSMatthew G. Knepley   if (view) {
10660851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
10670851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(v));
10680851c46eSMatthew G. Knepley   }
10690851c46eSMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
10700851c46eSMatthew G. Knepley   if (numRoots >= 0) {
10710851c46eSMatthew G. Knepley     PetscCall(PetscSFComputeDegreeBegin(sf, &degree));
10720851c46eSMatthew G. Knepley     PetscCall(PetscSFComputeDegreeEnd(sf, &degree));
10730851c46eSMatthew G. Knepley   }
10740851c46eSMatthew G. Knepley   PetscCall(PetscCalloc1(pEnd - pStart, &points));
10750851c46eSMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
10760851c46eSMatthew G. Knepley     if (PetscBTLookup(flippedCells, c - cStart)) {
10770851c46eSMatthew G. Knepley       const PetscInt cell = cells ? cells[c] : c;
10780851c46eSMatthew G. Knepley 
10790851c46eSMatthew G. Knepley       PetscCall(DMPlexOrientPoint(dm, cell, -1));
10800851c46eSMatthew G. Knepley       if (degree && degree[cell]) points[cell] = 1;
10810851c46eSMatthew G. Knepley       if (view) PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]Flipping cell %" PetscInt_FMT "%s\n", rank, cell, degree && degree[cell] ? " and sending to overlap" : ""));
10820851c46eSMatthew G. Knepley     }
10830851c46eSMatthew G. Knepley   }
10840851c46eSMatthew G. Knepley   // Must propagate flips for cells in the overlap
10850851c46eSMatthew G. Knepley   if (numRoots >= 0) {
10860851c46eSMatthew G. Knepley     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, points, points, MPI_SUM));
10870851c46eSMatthew G. Knepley     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, points, points, MPI_SUM));
10880851c46eSMatthew G. Knepley   }
10890851c46eSMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
10900851c46eSMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
10910851c46eSMatthew G. Knepley 
10920851c46eSMatthew G. Knepley     if (points[cell] && !PetscBTLookup(flippedCells, c - cStart)) {
10930851c46eSMatthew G. Knepley       PetscCall(DMPlexOrientPoint(dm, cell, -1));
10940851c46eSMatthew G. Knepley       if (view) PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]Flipping cell %" PetscInt_FMT " through overlap\n", rank, cell));
10950851c46eSMatthew G. Knepley     }
10960851c46eSMatthew G. Knepley   }
10970851c46eSMatthew G. Knepley   if (view) {
10980851c46eSMatthew G. Knepley     PetscCall(PetscViewerFlush(v));
10990851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(v));
11000851c46eSMatthew G. Knepley   }
11010851c46eSMatthew G. Knepley   PetscCall(PetscFree(points));
11020851c46eSMatthew G. Knepley   PetscCall(PetscBTDestroy(&flippedCells));
11030851c46eSMatthew G. Knepley   PetscCall(PetscFree2(numNeighbors, neighbors));
11040851c46eSMatthew G. Knepley   PetscCall(PetscFree3(rorntComp, lorntComp, locSupp));
11050851c46eSMatthew G. Knepley   PetscCall(PetscFree2(cellComp, faceComp));
11060851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
110784961fc4SMatthew G. Knepley }
1108