xref: /petsc/src/dm/impls/plex/plexorient.c (revision 6de651791259086888749b9b3b45040d70227b54)
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) {
283*6de65179SMatthew G. Knepley         const PetscInt idx = GetPointIndex(cone[c], fStart, fEnd, faces);
284*6de65179SMatthew G. Knepley 
2850851c46eSMatthew G. Knepley         // Cell faces are guaranteed to be in the face set
286*6de65179SMatthew G. Knepley         PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " of cell %" PetscInt_FMT " is not present in the label", cone[c], cell);
2870851c46eSMatthew G. Knepley         faceFIFO[fBottom++] = cone[c];
288*6de65179SMatthew G. Knepley         PetscCall(PetscBTSet(seenFaces, idx));
2890851c46eSMatthew G. Knepley       }
2900851c46eSMatthew G. Knepley       PetscCall(PetscBTSet(seenCells, cc - cStart));
2910851c46eSMatthew G. Knepley     }
2920851c46eSMatthew G. Knepley     // Consider each face in FIFO
2930851c46eSMatthew G. Knepley     while (fTop < fBottom) PetscCall(DMPlexCheckFace_Internal(dm, faceFIFO, &fTop, &fBottom, cellIS, faceIS, seenCells, flippedCells, seenFaces));
2940851c46eSMatthew G. Knepley     // Set component for cells and faces
2950851c46eSMatthew G. Knepley     for (PetscInt c = 0; c < cEnd - cStart; ++c) {
2960851c46eSMatthew G. Knepley       if (PetscBTLookup(seenCells, c)) cellComp[c] = *Ncomp;
2970851c46eSMatthew G. Knepley     }
2980851c46eSMatthew G. Knepley     for (PetscInt f = 0; f < fEnd - fStart; ++f) {
2990851c46eSMatthew G. Knepley       if (PetscBTLookup(seenFaces, f)) faceComp[f] = *Ncomp;
3000851c46eSMatthew G. Knepley     }
3010851c46eSMatthew G. Knepley     // Wipe seenCells and seenFaces for next component
3020851c46eSMatthew G. Knepley     PetscCall(PetscBTMemzero(fEnd - fStart, seenFaces));
3030851c46eSMatthew G. Knepley     PetscCall(PetscBTMemzero(cEnd - cStart, seenCells));
3040851c46eSMatthew G. Knepley     ++(*Ncomp);
3050851c46eSMatthew G. Knepley   } while (1);
3060851c46eSMatthew G. Knepley   PetscCall(PetscBTDestroy(&seenCells));
3070851c46eSMatthew G. Knepley   PetscCall(PetscBTDestroy(&seenFaces));
3080851c46eSMatthew G. Knepley   PetscCall(PetscFree(faceFIFO));
3090851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
3100851c46eSMatthew G. Knepley }
3110851c46eSMatthew G. Knepley 
31284961fc4SMatthew G. Knepley /*@
31384961fc4SMatthew G. Knepley   DMPlexOrient - Give a consistent orientation to the input mesh
31484961fc4SMatthew G. Knepley 
3152fe279fdSBarry Smith   Input Parameter:
316a1cb98faSBarry Smith . dm - The `DM`
31784961fc4SMatthew G. Knepley 
318a1cb98faSBarry Smith   Note:
319a1cb98faSBarry Smith   The orientation data for the `DM` are change in-place.
320a1cb98faSBarry Smith 
321a1cb98faSBarry Smith   This routine will fail for non-orientable surfaces, such as the Moebius strip.
32284961fc4SMatthew G. Knepley 
32384961fc4SMatthew G. Knepley   Level: advanced
32484961fc4SMatthew G. Knepley 
32560225df5SJacob Faibussowitsch .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`
32684961fc4SMatthew G. Knepley @*/
327d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexOrient(DM dm)
328d71ae5a4SJacob Faibussowitsch {
3290851c46eSMatthew G. Knepley #if 0
3300851c46eSMatthew G. Knepley   IS cellIS, faceIS;
3310851c46eSMatthew G. Knepley 
3320851c46eSMatthew G. Knepley   PetscFunctionBegin;
3330851c46eSMatthew G. Knepley   PetscCall(DMPlexGetAllCells_Internal(dm, &cellIS));
3340851c46eSMatthew G. Knepley   PetscCall(DMPlexGetAllFaces_Internal(dm, &faceIS));
3350851c46eSMatthew G. Knepley   PetscCall(DMPlexOrientCells_Internal(dm, cellIS, faceIS));
3360851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
3370851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&faceIS));
3380851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
3390851c46eSMatthew G. Knepley #else
34084961fc4SMatthew G. Knepley   MPI_Comm           comm;
341e1d83109SMatthew G. Knepley   PetscSF            sf;
342e1d83109SMatthew G. Knepley   const PetscInt    *lpoints;
343e1d83109SMatthew G. Knepley   const PetscSFNode *rpoints;
344e1d83109SMatthew G. Knepley   PetscSFNode       *rorntComp = NULL, *lorntComp = NULL;
3453d6051bcSMatthew G. Knepley   PetscInt          *numNeighbors, **neighbors, *locSupport = NULL;
346e1d83109SMatthew G. Knepley   PetscSFNode       *nrankComp;
347e1d83109SMatthew G. Knepley   PetscBool         *match, *flipped;
34884961fc4SMatthew G. Knepley   PetscBT            seenCells, flippedCells, seenFaces;
349e1d83109SMatthew G. Knepley   PetscInt          *faceFIFO, fTop, fBottom, *cellComp, *faceComp;
3507cadcfe8SMatthew G. Knepley   PetscInt           numLeaves, numRoots, dim, h, cStart, cEnd, c, cell, fStart, fEnd, face, off, totNeighbors = 0;
35139526728SToby Isaac   PetscMPIInt        rank, size, numComponents, comp = 0;
35239526728SToby Isaac   PetscBool          flg, flg2;
353a17aa47eSToby Isaac   PetscViewer        viewer = NULL, selfviewer = NULL;
35484961fc4SMatthew G. Knepley 
35584961fc4SMatthew G. Knepley   PetscFunctionBegin;
3569566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3579566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
3589566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
3599566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-orientation_view", &flg));
3609566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-orientation_view_synchronized", &flg2));
3619566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
3629566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &lpoints, &rpoints));
36384961fc4SMatthew G. Knepley   /* Truth Table
36484961fc4SMatthew G. Knepley      mismatch    flips   do action   mismatch   flipA ^ flipB   action
36584961fc4SMatthew G. Knepley          F       0 flips     no         F             F           F
36684961fc4SMatthew G. Knepley          F       1 flip      yes        F             T           T
36784961fc4SMatthew G. Knepley          F       2 flips     no         T             F           T
36884961fc4SMatthew G. Knepley          T       0 flips     yes        T             T           F
36984961fc4SMatthew G. Knepley          T       1 flip      no
37084961fc4SMatthew G. Knepley          T       2 flips     yes
37184961fc4SMatthew G. Knepley   */
3729566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
3739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &h));
3749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd));
3759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, h + 1, &fStart, &fEnd));
3769566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(cEnd - cStart, &seenCells));
3779566063dSJacob Faibussowitsch   PetscCall(PetscBTMemzero(cEnd - cStart, seenCells));
3789566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(cEnd - cStart, &flippedCells));
3799566063dSJacob Faibussowitsch   PetscCall(PetscBTMemzero(cEnd - cStart, flippedCells));
3809566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(fEnd - fStart, &seenFaces));
3819566063dSJacob Faibussowitsch   PetscCall(PetscBTMemzero(fEnd - fStart, seenFaces));
3829566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(fEnd - fStart, &faceFIFO, cEnd - cStart, &cellComp, fEnd - fStart, &faceComp));
383e1d83109SMatthew G. Knepley   /*
384e1d83109SMatthew G. Knepley    OLD STYLE
385e1d83109SMatthew G. Knepley    - Add an integer array over cells and faces (component) for connected component number
386e1d83109SMatthew G. Knepley    Foreach component
387e1d83109SMatthew G. Knepley      - Mark the initial cell as seen
388e1d83109SMatthew G. Knepley      - Process component as usual
389e1d83109SMatthew G. Knepley      - Set component for all seenCells
390e1d83109SMatthew G. Knepley      - Wipe seenCells and seenFaces (flippedCells can stay)
391e1d83109SMatthew G. Knepley    - Generate parallel adjacency for component using SF and seenFaces
392e1d83109SMatthew G. Knepley    - Collect numComponents adj data from each proc to 0
393e1d83109SMatthew G. Knepley    - Build same serial graph
394e1d83109SMatthew G. Knepley    - Use same solver
39515229ffcSPierre Jolivet    - Use Scatterv to send back flipped flags for each component
396e1d83109SMatthew G. Knepley    - Negate flippedCells by component
397e1d83109SMatthew G. Knepley 
398e1d83109SMatthew G. Knepley    NEW STYLE
399e1d83109SMatthew G. Knepley    - Create the adj on each process
400e1d83109SMatthew G. Knepley    - Bootstrap to complete graph on proc 0
401e1d83109SMatthew G. Knepley   */
402e1d83109SMatthew G. Knepley   /* Loop over components */
403e1d83109SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) cellComp[cell - cStart] = -1;
404e1d83109SMatthew G. Knepley   do {
405e1d83109SMatthew G. Knepley     /* Look for first unmarked cell */
4069371c9d4SSatish Balay     for (cell = cStart; cell < cEnd; ++cell)
4079371c9d4SSatish Balay       if (cellComp[cell - cStart] < 0) break;
408e1d83109SMatthew G. Knepley     if (cell >= cEnd) break;
409e1d83109SMatthew G. Knepley     /* Initialize FIFO with first cell in component */
410e1d83109SMatthew G. Knepley     {
41184961fc4SMatthew G. Knepley       const PetscInt *cone;
41284961fc4SMatthew G. Knepley       PetscInt        coneSize;
41384961fc4SMatthew G. Knepley 
414e1d83109SMatthew G. Knepley       fTop = fBottom = 0;
4159566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
4169566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cell, &cone));
41784961fc4SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
41884961fc4SMatthew G. Knepley         faceFIFO[fBottom++] = cone[c];
4199566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(seenFaces, cone[c] - fStart));
42084961fc4SMatthew G. Knepley       }
4219566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(seenCells, cell - cStart));
42284961fc4SMatthew G. Knepley     }
42384961fc4SMatthew G. Knepley     /* Consider each face in FIFO */
4240851c46eSMatthew G. Knepley     while (fTop < fBottom) PetscCall(DMPlexCheckFace_Old_Internal(dm, faceFIFO, &fTop, &fBottom, cStart, fStart, fEnd, seenCells, flippedCells, seenFaces));
425e1d83109SMatthew G. Knepley     /* Set component for cells and faces */
426e1d83109SMatthew G. Knepley     for (cell = 0; cell < cEnd - cStart; ++cell) {
427e1d83109SMatthew G. Knepley       if (PetscBTLookup(seenCells, cell)) cellComp[cell] = comp;
428e1d83109SMatthew G. Knepley     }
429e1d83109SMatthew G. Knepley     for (face = 0; face < fEnd - fStart; ++face) {
430e1d83109SMatthew G. Knepley       if (PetscBTLookup(seenFaces, face)) faceComp[face] = comp;
431e1d83109SMatthew G. Knepley     }
432e1d83109SMatthew G. Knepley     /* Wipe seenCells and seenFaces for next component */
4339566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(fEnd - fStart, seenFaces));
4349566063dSJacob Faibussowitsch     PetscCall(PetscBTMemzero(cEnd - cStart, seenCells));
435e1d83109SMatthew G. Knepley     ++comp;
436e1d83109SMatthew G. Knepley   } while (1);
437e1d83109SMatthew G. Knepley   numComponents = comp;
43884961fc4SMatthew G. Knepley   if (flg) {
43984961fc4SMatthew G. Knepley     PetscViewer v;
44084961fc4SMatthew G. Knepley 
4419566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
4429566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(v));
4439566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for serial flipped cells:\n", rank));
4449566063dSJacob Faibussowitsch     PetscCall(PetscBTView(cEnd - cStart, flippedCells, v));
4459566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(v));
4469566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(v));
44784961fc4SMatthew G. Knepley   }
44884961fc4SMatthew G. Knepley   /* Now all subdomains are oriented, but we need a consistent parallel orientation */
44984961fc4SMatthew G. Knepley   if (numLeaves >= 0) {
4503d6051bcSMatthew G. Knepley     PetscInt maxSupportSize, neighbor;
4513d6051bcSMatthew G. Knepley 
452e1d83109SMatthew G. Knepley     /* Store orientations of boundary faces*/
4533d6051bcSMatthew G. Knepley     PetscCall(DMPlexGetMaxSizes(dm, NULL, &maxSupportSize));
4543d6051bcSMatthew G. Knepley     PetscCall(PetscCalloc3(numRoots, &rorntComp, numRoots, &lorntComp, maxSupportSize, &locSupport));
45584961fc4SMatthew G. Knepley     for (face = fStart; face < fEnd; ++face) {
456e1d83109SMatthew G. Knepley       const PetscInt *cone, *support, *ornt;
4573d6051bcSMatthew G. Knepley       PetscInt        coneSize, supportSize, Ns = 0, s, l;
458e1d83109SMatthew G. Knepley 
4599566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, face, &supportSize));
4603d6051bcSMatthew G. Knepley       /* Ignore overlapping cells */
4619566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, face, &support));
4623d6051bcSMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
4633d6051bcSMatthew G. Knepley         PetscCall(PetscFindInt(support[s], numLeaves, lpoints, &l));
4643d6051bcSMatthew G. Knepley         if (l >= 0) continue;
4653d6051bcSMatthew G. Knepley         locSupport[Ns++] = support[s];
4663d6051bcSMatthew G. Knepley       }
4673d6051bcSMatthew G. Knepley       if (Ns != 1) continue;
4683d6051bcSMatthew G. Knepley       neighbor = locSupport[0];
4693d6051bcSMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, neighbor, &cone));
4703d6051bcSMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, neighbor, &coneSize));
4713d6051bcSMatthew G. Knepley       PetscCall(DMPlexGetConeOrientation(dm, neighbor, &ornt));
4729371c9d4SSatish Balay       for (c = 0; c < coneSize; ++c)
4739371c9d4SSatish Balay         if (cone[c] == face) break;
47484961fc4SMatthew G. Knepley       if (dim == 1) {
47584961fc4SMatthew G. Knepley         /* Use cone position instead, shifted to -1 or 1 */
476835f2295SStefano Zampini         if (PetscBTLookup(flippedCells, neighbor - cStart)) rorntComp[face].rank = 1 - c * 2;
477835f2295SStefano Zampini         else rorntComp[face].rank = c * 2 - 1;
47884961fc4SMatthew G. Knepley       } else {
4793d6051bcSMatthew G. Knepley         if (PetscBTLookup(flippedCells, neighbor - cStart)) rorntComp[face].rank = ornt[c] < 0 ? -1 : 1;
480e1d83109SMatthew G. Knepley         else rorntComp[face].rank = ornt[c] < 0 ? 1 : -1;
48184961fc4SMatthew G. Knepley       }
482e1d83109SMatthew G. Knepley       rorntComp[face].index = faceComp[face - fStart];
48384961fc4SMatthew G. Knepley     }
484e1d83109SMatthew G. Knepley     /* Communicate boundary edge orientations */
4856497c311SBarry Smith     PetscCall(PetscSFBcastBegin(sf, MPIU_SF_NODE, rorntComp, lorntComp, MPI_REPLACE));
4866497c311SBarry Smith     PetscCall(PetscSFBcastEnd(sf, MPIU_SF_NODE, rorntComp, lorntComp, MPI_REPLACE));
487e1d83109SMatthew G. Knepley   }
488e1d83109SMatthew G. Knepley   /* Get process adjacency */
4899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numComponents, &numNeighbors, numComponents, &neighbors));
490a17aa47eSToby Isaac   viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm));
4919566063dSJacob Faibussowitsch   if (flg2) PetscCall(PetscViewerASCIIPushSynchronized(viewer));
4929566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
493e1d83109SMatthew G. Knepley   for (comp = 0; comp < numComponents; ++comp) {
494e1d83109SMatthew G. Knepley     PetscInt l, n;
49584961fc4SMatthew G. Knepley 
496e1d83109SMatthew G. Knepley     numNeighbors[comp] = 0;
4979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(PetscMax(numLeaves, 0), &neighbors[comp]));
498e1d83109SMatthew G. Knepley     /* I know this is p^2 time in general, but for bounded degree its alright */
499e1d83109SMatthew G. Knepley     for (l = 0; l < numLeaves; ++l) {
500e1d83109SMatthew G. Knepley       const PetscInt face = lpoints[l];
501e1d83109SMatthew G. Knepley 
502e1d83109SMatthew G. Knepley       /* Find a representative face (edge) separating pairs of procs */
5033d6051bcSMatthew G. Knepley       if ((face >= fStart) && (face < fEnd) && (faceComp[face - fStart] == comp) && rorntComp[face].rank) {
504835f2295SStefano Zampini         const PetscInt rrank = rpoints[l].rank;
505e1d83109SMatthew G. Knepley         const PetscInt rcomp = lorntComp[face].index;
506e1d83109SMatthew G. Knepley 
5079371c9d4SSatish Balay         for (n = 0; n < numNeighbors[comp]; ++n)
5089371c9d4SSatish Balay           if ((rrank == rpoints[neighbors[comp][n]].rank) && (rcomp == lorntComp[lpoints[neighbors[comp][n]]].index)) break;
509e1d83109SMatthew G. Knepley         if (n >= numNeighbors[comp]) {
510e1d83109SMatthew G. Knepley           PetscInt supportSize;
511e1d83109SMatthew G. Knepley 
5129566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(dm, face, &supportSize));
51363a3b9bcSJacob Faibussowitsch           PetscCheck(supportSize == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Boundary faces should see one cell, not %" PetscInt_FMT, supportSize);
5149371c9d4SSatish Balay           if (flg)
515835f2295SStefano Zampini             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,
516835f2295SStefano Zampini                                              rpoints[l].index, rrank, rcomp, lorntComp[face].rank));
517e1d83109SMatthew G. Knepley           neighbors[comp][numNeighbors[comp]++] = l;
518e1d83109SMatthew G. Knepley         }
519e1d83109SMatthew G. Knepley       }
520e1d83109SMatthew G. Knepley     }
521e1d83109SMatthew G. Knepley     totNeighbors += numNeighbors[comp];
522e1d83109SMatthew G. Knepley   }
5239566063dSJacob Faibussowitsch   PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
5249566063dSJacob Faibussowitsch   if (flg2) PetscCall(PetscViewerASCIIPopSynchronized(viewer));
5259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(totNeighbors, &nrankComp, totNeighbors, &match));
526e1d83109SMatthew G. Knepley   for (comp = 0, off = 0; comp < numComponents; ++comp) {
527e1d83109SMatthew G. Knepley     PetscInt n;
528e1d83109SMatthew G. Knepley 
529e1d83109SMatthew G. Knepley     for (n = 0; n < numNeighbors[comp]; ++n, ++off) {
530e1d83109SMatthew G. Knepley       const PetscInt face = lpoints[neighbors[comp][n]];
531e1d83109SMatthew G. Knepley       const PetscInt o    = rorntComp[face].rank * lorntComp[face].rank;
532e1d83109SMatthew G. Knepley 
533e1d83109SMatthew G. Knepley       if (o < 0) match[off] = PETSC_TRUE;
534e1d83109SMatthew G. Knepley       else if (o > 0) match[off] = PETSC_FALSE;
535835f2295SStefano Zampini       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);
536e1d83109SMatthew G. Knepley       nrankComp[off].rank  = rpoints[neighbors[comp][n]].rank;
537e1d83109SMatthew G. Knepley       nrankComp[off].index = lorntComp[lpoints[neighbors[comp][n]]].index;
538e1d83109SMatthew G. Knepley     }
5399566063dSJacob Faibussowitsch     PetscCall(PetscFree(neighbors[comp]));
54084961fc4SMatthew G. Knepley   }
54184961fc4SMatthew G. Knepley   /* Collect the graph on 0 */
542e1d83109SMatthew G. Knepley   if (numLeaves >= 0) {
54384961fc4SMatthew G. Knepley     Mat          G;
54484961fc4SMatthew G. Knepley     PetscBT      seenProcs, flippedProcs;
54584961fc4SMatthew G. Knepley     PetscInt    *procFIFO, pTop, pBottom;
5467cadcfe8SMatthew G. Knepley     PetscInt    *N          = NULL, *Noff;
547e1d83109SMatthew G. Knepley     PetscSFNode *adj        = NULL;
54884961fc4SMatthew G. Knepley     PetscBool   *val        = NULL;
5496497c311SBarry Smith     PetscMPIInt *recvcounts = NULL, *displs = NULL, *Nc, p, o, itotNeighbors;
5509852e123SBarry Smith     PetscMPIInt  size = 0;
55184961fc4SMatthew G. Knepley 
5529566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(numComponents, &flipped));
5539566063dSJacob Faibussowitsch     if (rank == 0) PetscCallMPI(MPI_Comm_size(comm, &size));
5549566063dSJacob Faibussowitsch     PetscCall(PetscCalloc4(size, &recvcounts, size + 1, &displs, size, &Nc, size + 1, &Noff));
5559566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Gather(&numComponents, 1, MPI_INT, Nc, 1, MPI_INT, 0, comm));
556ad540459SPierre Jolivet     for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + Nc[p];
5579566063dSJacob Faibussowitsch     if (rank == 0) PetscCall(PetscMalloc1(displs[size], &N));
5589566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Gatherv(numNeighbors, numComponents, MPIU_INT, N, Nc, displs, MPIU_INT, 0, comm));
5599852e123SBarry Smith     for (p = 0, o = 0; p < size; ++p) {
560e1d83109SMatthew G. Knepley       recvcounts[p] = 0;
561e1d83109SMatthew G. Knepley       for (c = 0; c < Nc[p]; ++c, ++o) recvcounts[p] += N[o];
56284961fc4SMatthew G. Knepley       displs[p + 1] = displs[p] + recvcounts[p];
56384961fc4SMatthew G. Knepley     }
5649566063dSJacob Faibussowitsch     if (rank == 0) PetscCall(PetscMalloc2(displs[size], &adj, displs[size], &val));
5656497c311SBarry Smith     PetscCall(PetscMPIIntCast(totNeighbors, &itotNeighbors));
5666497c311SBarry Smith     PetscCallMPI(MPI_Gatherv(nrankComp, itotNeighbors, MPIU_SF_NODE, adj, recvcounts, displs, MPIU_SF_NODE, 0, comm));
5676497c311SBarry Smith     PetscCallMPI(MPI_Gatherv(match, itotNeighbors, MPIU_BOOL, val, recvcounts, displs, MPIU_BOOL, 0, comm));
5689566063dSJacob Faibussowitsch     PetscCall(PetscFree2(numNeighbors, neighbors));
569dd400576SPatrick Sanan     if (rank == 0) {
570ad540459SPierre Jolivet       for (p = 1; p <= size; ++p) Noff[p] = Noff[p - 1] + Nc[p - 1];
571a83982f3SMatthew G. Knepley       if (flg) {
572e1d83109SMatthew G. Knepley         PetscInt n;
573e1d83109SMatthew G. Knepley 
5749852e123SBarry Smith         for (p = 0, off = 0; p < size; ++p) {
575e1d83109SMatthew G. Knepley           for (c = 0; c < Nc[p]; ++c) {
57663a3b9bcSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "Proc %d Comp %" PetscInt_FMT ":\n", p, c));
577835f2295SStefano Zampini             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]]));
57884961fc4SMatthew G. Knepley           }
57984961fc4SMatthew G. Knepley         }
58084961fc4SMatthew G. Knepley       }
58184961fc4SMatthew G. Knepley       /* Symmetrize the graph */
5829566063dSJacob Faibussowitsch       PetscCall(MatCreate(PETSC_COMM_SELF, &G));
5839566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(G, Noff[size], Noff[size], Noff[size], Noff[size]));
5849566063dSJacob Faibussowitsch       PetscCall(MatSetUp(G));
5859852e123SBarry Smith       for (p = 0, off = 0; p < size; ++p) {
586e1d83109SMatthew G. Knepley         for (c = 0; c < Nc[p]; ++c) {
587e1d83109SMatthew G. Knepley           const PetscInt r = Noff[p] + c;
588e1d83109SMatthew G. Knepley           PetscInt       n;
589e1d83109SMatthew G. Knepley 
590e1d83109SMatthew G. Knepley           for (n = 0; n < N[r]; ++n, ++off) {
591e1d83109SMatthew G. Knepley             const PetscInt    q = Noff[adj[off].rank] + adj[off].index;
592e1d83109SMatthew G. Knepley             const PetscScalar o = val[off] ? 1.0 : 0.0;
59384961fc4SMatthew G. Knepley 
5949566063dSJacob Faibussowitsch             PetscCall(MatSetValues(G, 1, &r, 1, &q, &o, INSERT_VALUES));
5959566063dSJacob Faibussowitsch             PetscCall(MatSetValues(G, 1, &q, 1, &r, &o, INSERT_VALUES));
59684961fc4SMatthew G. Knepley           }
59784961fc4SMatthew G. Knepley         }
598e1d83109SMatthew G. Knepley       }
5999566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(G, MAT_FINAL_ASSEMBLY));
6009566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(G, MAT_FINAL_ASSEMBLY));
60184961fc4SMatthew G. Knepley 
6029566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(Noff[size], &seenProcs));
6039566063dSJacob Faibussowitsch       PetscCall(PetscBTMemzero(Noff[size], seenProcs));
6049566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(Noff[size], &flippedProcs));
6059566063dSJacob Faibussowitsch       PetscCall(PetscBTMemzero(Noff[size], flippedProcs));
6069566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Noff[size], &procFIFO));
60784961fc4SMatthew G. Knepley       pTop = pBottom = 0;
6089852e123SBarry Smith       for (p = 0; p < Noff[size]; ++p) {
60984961fc4SMatthew G. Knepley         if (PetscBTLookup(seenProcs, p)) continue;
61084961fc4SMatthew G. Knepley         /* Initialize FIFO with next proc */
61184961fc4SMatthew G. Knepley         procFIFO[pBottom++] = p;
6129566063dSJacob Faibussowitsch         PetscCall(PetscBTSet(seenProcs, p));
61384961fc4SMatthew G. Knepley         /* Consider each proc in FIFO */
61484961fc4SMatthew G. Knepley         while (pTop < pBottom) {
61584961fc4SMatthew G. Knepley           const PetscScalar *ornt;
61684961fc4SMatthew G. Knepley           const PetscInt    *neighbors;
617e1d83109SMatthew G. Knepley           PetscInt           proc, nproc, seen, flippedA, flippedB, mismatch, numNeighbors, n;
61884961fc4SMatthew G. Knepley 
61984961fc4SMatthew G. Knepley           proc     = procFIFO[pTop++];
62084961fc4SMatthew G. Knepley           flippedA = PetscBTLookup(flippedProcs, proc) ? 1 : 0;
6219566063dSJacob Faibussowitsch           PetscCall(MatGetRow(G, proc, &numNeighbors, &neighbors, &ornt));
62284961fc4SMatthew G. Knepley           /* Loop over neighboring procs */
62384961fc4SMatthew G. Knepley           for (n = 0; n < numNeighbors; ++n) {
62484961fc4SMatthew G. Knepley             nproc    = neighbors[n];
62584961fc4SMatthew G. Knepley             mismatch = PetscRealPart(ornt[n]) > 0.5 ? 0 : 1;
62684961fc4SMatthew G. Knepley             seen     = PetscBTLookup(seenProcs, nproc);
62784961fc4SMatthew G. Knepley             flippedB = PetscBTLookup(flippedProcs, nproc) ? 1 : 0;
62884961fc4SMatthew G. Knepley 
62984961fc4SMatthew G. Knepley             if (mismatch ^ (flippedA ^ flippedB)) {
63063a3b9bcSJacob 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);
63184961fc4SMatthew G. Knepley               if (!flippedB) {
6329566063dSJacob Faibussowitsch                 PetscCall(PetscBTSet(flippedProcs, nproc));
63384961fc4SMatthew G. Knepley               } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
6341dca8a05SBarry Smith             } else PetscCheck(!mismatch || !flippedA || !flippedB, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
63584961fc4SMatthew G. Knepley             if (!seen) {
63684961fc4SMatthew G. Knepley               procFIFO[pBottom++] = nproc;
6379566063dSJacob Faibussowitsch               PetscCall(PetscBTSet(seenProcs, nproc));
63884961fc4SMatthew G. Knepley             }
63984961fc4SMatthew G. Knepley           }
64084961fc4SMatthew G. Knepley         }
64184961fc4SMatthew G. Knepley       }
6429566063dSJacob Faibussowitsch       PetscCall(PetscFree(procFIFO));
6439566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&G));
6449566063dSJacob Faibussowitsch       PetscCall(PetscFree2(adj, val));
6459566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&seenProcs));
64684961fc4SMatthew G. Knepley     }
647e1d83109SMatthew G. Knepley     /* Scatter flip flags */
648e1d83109SMatthew G. Knepley     {
649e1d83109SMatthew G. Knepley       PetscBool *flips = NULL;
650e1d83109SMatthew G. Knepley 
651dd400576SPatrick Sanan       if (rank == 0) {
6529566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(Noff[size], &flips));
6539852e123SBarry Smith         for (p = 0; p < Noff[size]; ++p) {
654e1d83109SMatthew G. Knepley           flips[p] = PetscBTLookup(flippedProcs, p) ? PETSC_TRUE : PETSC_FALSE;
6559566063dSJacob Faibussowitsch           if (flg && flips[p]) PetscCall(PetscPrintf(comm, "Flipping Proc+Comp %d:\n", p));
656e1d83109SMatthew G. Knepley         }
657ad540459SPierre Jolivet         for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + Nc[p];
658e1d83109SMatthew G. Knepley       }
6599566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Scatterv(flips, Nc, displs, MPIU_BOOL, flipped, numComponents, MPIU_BOOL, 0, comm));
6609566063dSJacob Faibussowitsch       PetscCall(PetscFree(flips));
66184961fc4SMatthew G. Knepley     }
6629566063dSJacob Faibussowitsch     if (rank == 0) PetscCall(PetscBTDestroy(&flippedProcs));
6639566063dSJacob Faibussowitsch     PetscCall(PetscFree(N));
6649566063dSJacob Faibussowitsch     PetscCall(PetscFree4(recvcounts, displs, Nc, Noff));
6659566063dSJacob Faibussowitsch     PetscCall(PetscFree2(nrankComp, match));
666e1d83109SMatthew G. Knepley 
667e1d83109SMatthew G. Knepley     /* Decide whether to flip cells in each component */
6689371c9d4SSatish Balay     for (c = 0; c < cEnd - cStart; ++c) {
6699371c9d4SSatish Balay       if (flipped[cellComp[c]]) PetscCall(PetscBTNegate(flippedCells, c));
6709371c9d4SSatish Balay     }
6719566063dSJacob Faibussowitsch     PetscCall(PetscFree(flipped));
67284961fc4SMatthew G. Knepley   }
67384961fc4SMatthew G. Knepley   if (flg) {
67484961fc4SMatthew G. Knepley     PetscViewer v;
67584961fc4SMatthew G. Knepley 
6769566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
6779566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(v));
6789566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for parallel flipped cells:\n", rank));
6799566063dSJacob Faibussowitsch     PetscCall(PetscBTView(cEnd - cStart, flippedCells, v));
6809566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(v));
6819566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(v));
68284961fc4SMatthew G. Knepley   }
68384961fc4SMatthew G. Knepley   /* Reverse flipped cells in the mesh */
68484961fc4SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
68548a46eb9SPierre Jolivet     if (PetscBTLookup(flippedCells, c - cStart)) PetscCall(DMPlexOrientPoint(dm, c, -1));
68684961fc4SMatthew G. Knepley   }
6879566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&seenCells));
6889566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&flippedCells));
6899566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&seenFaces));
6909566063dSJacob Faibussowitsch   PetscCall(PetscFree2(numNeighbors, neighbors));
6913d6051bcSMatthew G. Knepley   PetscCall(PetscFree3(rorntComp, lorntComp, locSupport));
6929566063dSJacob Faibussowitsch   PetscCall(PetscFree3(faceFIFO, cellComp, faceComp));
6933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6940851c46eSMatthew G. Knepley #endif
6950851c46eSMatthew G. Knepley }
6960851c46eSMatthew G. Knepley 
6970851c46eSMatthew G. Knepley static PetscErrorCode CreateCellAndFaceIS_Private(DM dm, DMLabel label, IS *cellIS, IS *faceIS)
6980851c46eSMatthew G. Knepley {
6990851c46eSMatthew G. Knepley   IS              valueIS;
7000851c46eSMatthew G. Knepley   const PetscInt *values;
7010851c46eSMatthew G. Knepley   PetscInt        Nv, depth = 0;
7020851c46eSMatthew G. Knepley 
7030851c46eSMatthew G. Knepley   PetscFunctionBegin;
7040851c46eSMatthew G. Knepley   PetscCall(DMLabelGetValueIS(label, &valueIS));
7050851c46eSMatthew G. Knepley   PetscCall(ISGetLocalSize(valueIS, &Nv));
7060851c46eSMatthew G. Knepley   PetscCall(ISGetIndices(valueIS, &values));
7070851c46eSMatthew G. Knepley   for (PetscInt v = 0; v < Nv; ++v) {
7080851c46eSMatthew G. Knepley     const PetscInt val = values[v] < 0 || values[v] >= 100 ? 0 : values[v];
709f369e074SMatthew G. Knepley     PetscInt       n;
7100851c46eSMatthew G. Knepley 
711f369e074SMatthew G. Knepley     PetscCall(DMLabelGetStratumSize(label, val, &n));
712f369e074SMatthew G. Knepley     if (!n) continue;
7130851c46eSMatthew G. Knepley     depth = PetscMax(val, depth);
7140851c46eSMatthew G. Knepley   }
7150851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&valueIS));
7160851c46eSMatthew 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);
7170851c46eSMatthew G. Knepley   PetscCall(DMLabelGetStratumIS(label, depth, cellIS));
7180851c46eSMatthew G. Knepley   PetscCall(DMLabelGetStratumIS(label, depth - 1, faceIS));
71957508eceSPierre Jolivet   if (!*cellIS) PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, cellIS));
72057508eceSPierre Jolivet   if (!*faceIS) PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, faceIS));
7210851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
7220851c46eSMatthew G. Knepley }
7230851c46eSMatthew G. Knepley 
7240851c46eSMatthew G. Knepley PetscErrorCode DMPlexOrientLabel(DM dm, DMLabel label)
7250851c46eSMatthew G. Knepley {
7260851c46eSMatthew G. Knepley   IS cellIS, faceIS;
7270851c46eSMatthew G. Knepley 
7280851c46eSMatthew G. Knepley   PetscFunctionBegin;
7290851c46eSMatthew G. Knepley   PetscCall(CreateCellAndFaceIS_Private(dm, label, &cellIS, &faceIS));
7300851c46eSMatthew G. Knepley   PetscCall(DMPlexOrientCells_Internal(dm, cellIS, faceIS));
7310851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
7320851c46eSMatthew G. Knepley   PetscCall(ISDestroy(&faceIS));
7330851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
7340851c46eSMatthew G. Knepley }
7350851c46eSMatthew G. Knepley 
7360851c46eSMatthew G. Knepley PetscErrorCode DMPlexOrientCells_Internal(DM dm, IS cellIS, IS faceIS)
7370851c46eSMatthew G. Knepley {
7380851c46eSMatthew G. Knepley   MPI_Comm           comm;
7390851c46eSMatthew G. Knepley   PetscSF            sf;
7400851c46eSMatthew G. Knepley   const PetscInt    *lpoints;
7410851c46eSMatthew G. Knepley   const PetscSFNode *rpoints;
7420851c46eSMatthew G. Knepley   PetscSFNode       *rorntComp = NULL, *lorntComp = NULL;
7430851c46eSMatthew G. Knepley   PetscInt          *numNeighbors, **neighbors, *locSupp = NULL;
7440851c46eSMatthew G. Knepley   PetscSFNode       *nrankComp;
7450851c46eSMatthew G. Knepley   PetscBool         *match, *flipped;
7460851c46eSMatthew G. Knepley   PetscBT            flippedCells;
7470851c46eSMatthew G. Knepley   PetscInt          *cellComp, *faceComp;
7480851c46eSMatthew G. Knepley   const PetscInt    *cells = NULL, *faces = NULL;
7490851c46eSMatthew G. Knepley   PetscInt           cStart = 0, cEnd = 0, fStart = 0, fEnd = 0;
7500851c46eSMatthew G. Knepley   PetscInt           numLeaves, numRoots, dim, Ncomp, totNeighbors = 0;
7510851c46eSMatthew G. Knepley   PetscMPIInt        rank, size;
7520851c46eSMatthew G. Knepley   PetscBool          view, viewSync;
7530851c46eSMatthew G. Knepley   PetscViewer        viewer = NULL, selfviewer = NULL;
7540851c46eSMatthew G. Knepley 
7550851c46eSMatthew G. Knepley   PetscFunctionBegin;
7560851c46eSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
7570851c46eSMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7580851c46eSMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(comm, &size));
7590851c46eSMatthew G. Knepley   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-orientation_view", &view));
7600851c46eSMatthew G. Knepley   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-orientation_view_synchronized", &viewSync));
7610851c46eSMatthew G. Knepley 
7620851c46eSMatthew G. Knepley   if (cellIS) PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
7630851c46eSMatthew G. Knepley   if (faceIS) PetscCall(ISGetPointRange(faceIS, &fStart, &fEnd, &faces));
7640851c46eSMatthew G. Knepley   PetscCall(DMGetPointSF(dm, &sf));
7650851c46eSMatthew G. Knepley   PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &lpoints, &rpoints));
7660851c46eSMatthew G. Knepley   /* Truth Table
7670851c46eSMatthew G. Knepley      mismatch    flips   do action   mismatch   flipA ^ flipB   action
7680851c46eSMatthew G. Knepley          F       0 flips     no         F             F           F
7690851c46eSMatthew G. Knepley          F       1 flip      yes        F             T           T
7700851c46eSMatthew G. Knepley          F       2 flips     no         T             F           T
7710851c46eSMatthew G. Knepley          T       0 flips     yes        T             T           F
7720851c46eSMatthew G. Knepley          T       1 flip      no
7730851c46eSMatthew G. Knepley          T       2 flips     yes
7740851c46eSMatthew G. Knepley   */
7750851c46eSMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
7760851c46eSMatthew G. Knepley   PetscCall(PetscBTCreate(cEnd - cStart, &flippedCells));
7770851c46eSMatthew G. Knepley   PetscCall(PetscBTMemzero(cEnd - cStart, flippedCells));
7780851c46eSMatthew G. Knepley   PetscCall(PetscCalloc2(cEnd - cStart, &cellComp, fEnd - fStart, &faceComp));
7790851c46eSMatthew G. Knepley   /*
7800851c46eSMatthew G. Knepley    OLD STYLE
7810851c46eSMatthew G. Knepley    - Add an integer array over cells and faces (component) for connected component number
7820851c46eSMatthew G. Knepley    Foreach component
7830851c46eSMatthew G. Knepley      - Mark the initial cell as seen
7840851c46eSMatthew G. Knepley      - Process component as usual
7850851c46eSMatthew G. Knepley      - Set component for all seenCells
7860851c46eSMatthew G. Knepley      - Wipe seenCells and seenFaces (flippedCells can stay)
7870851c46eSMatthew G. Knepley    - Generate parallel adjacency for component using SF and seenFaces
7880851c46eSMatthew G. Knepley    - Collect Ncomp adj data from each proc to 0
7890851c46eSMatthew G. Knepley    - Build same serial graph
7900851c46eSMatthew G. Knepley    - Use same solver
7910851c46eSMatthew G. Knepley    - Use Scatterv to send back flipped flags for each component
7920851c46eSMatthew G. Knepley    - Negate flippedCells by component
7930851c46eSMatthew G. Knepley 
7940851c46eSMatthew G. Knepley    NEW STYLE
7950851c46eSMatthew G. Knepley    - Create the adj on each process
7960851c46eSMatthew G. Knepley    - Bootstrap to complete graph on proc 0
7970851c46eSMatthew G. Knepley   */
7980851c46eSMatthew G. Knepley   PetscCall(DMPlexOrient_Serial(dm, cellIS, faceIS, &Ncomp, cellComp, faceComp, flippedCells));
7990851c46eSMatthew G. Knepley   if (view) {
8000851c46eSMatthew G. Knepley     PetscViewer v;
80176dc4c7dSMatthew G. Knepley     PetscInt    cdepth = -1;
8020851c46eSMatthew G. Knepley 
8030851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
8040851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(v));
80576dc4c7dSMatthew G. Knepley     if (cEnd > cStart) PetscCall(DMPlexGetPointDepth(dm, cells ? cells[cStart] : cStart, &cdepth));
80676dc4c7dSMatthew 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));
8070851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for serial flipped cells:\n", rank));
8080851c46eSMatthew G. Knepley     PetscCall(PetscBTView(cEnd - cStart, flippedCells, v));
8090851c46eSMatthew G. Knepley     PetscCall(PetscViewerFlush(v));
8100851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(v));
8110851c46eSMatthew G. Knepley   }
8120851c46eSMatthew G. Knepley   /* Now all subdomains are oriented, but we need a consistent parallel orientation */
8130851c46eSMatthew G. Knepley   // TODO: This all has to be rewritten to filter cones/supports to the ISes
8140851c46eSMatthew G. Knepley   if (numLeaves >= 0) {
8150851c46eSMatthew G. Knepley     PetscInt maxSuppSize, neighbor;
8160851c46eSMatthew G. Knepley 
8170851c46eSMatthew G. Knepley     // Store orientations of boundary faces
8180851c46eSMatthew G. Knepley     PetscCall(DMPlexGetMaxSizes(dm, NULL, &maxSuppSize));
8190851c46eSMatthew G. Knepley     PetscCall(PetscCalloc3(numRoots, &rorntComp, numRoots, &lorntComp, maxSuppSize, &locSupp));
8200851c46eSMatthew G. Knepley     for (PetscInt f = fStart; f < fEnd; ++f) {
8210851c46eSMatthew G. Knepley       const PetscInt  face = faces ? faces[f] : f;
8220851c46eSMatthew G. Knepley       const PetscInt *cone, *supp, *ornt;
8230851c46eSMatthew G. Knepley       PetscInt        coneSize, suppSize, nind, c, Ns = 0;
8240851c46eSMatthew G. Knepley 
8250851c46eSMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, face, &suppSize));
8260851c46eSMatthew G. Knepley       PetscCall(DMPlexGetSupport(dm, face, &supp));
8270851c46eSMatthew G. Knepley       for (PetscInt s = 0; s < suppSize; ++s) {
8280851c46eSMatthew G. Knepley         PetscInt ind, l;
8290851c46eSMatthew G. Knepley 
8300851c46eSMatthew G. Knepley         // Filter support
8310851c46eSMatthew G. Knepley         ind = GetPointIndex(supp[s], cStart, cEnd, cells);
8320851c46eSMatthew G. Knepley         if (ind < 0) continue;
8330851c46eSMatthew G. Knepley         // Ignore overlapping cells
8340851c46eSMatthew G. Knepley         PetscCall(PetscFindInt(supp[s], numLeaves, lpoints, &l));
8350851c46eSMatthew G. Knepley         if (l >= 0) continue;
8360851c46eSMatthew G. Knepley         locSupp[Ns++] = supp[s];
8370851c46eSMatthew G. Knepley       }
83817d25f2dSMatthew G. Knepley       PetscCheck(Ns < maxSuppSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Index %" PetscInt_FMT " exceeds array size %" PetscInt_FMT, Ns, maxSuppSize);
8390851c46eSMatthew G. Knepley       if (Ns != 1) continue;
8400851c46eSMatthew G. Knepley       neighbor = locSupp[0];
8410851c46eSMatthew G. Knepley       nind     = GetPointIndex(neighbor, cStart, cEnd, cells);
8420851c46eSMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, neighbor, &cone));
8430851c46eSMatthew G. Knepley       PetscCall(DMPlexGetConeSize(dm, neighbor, &coneSize));
8440851c46eSMatthew G. Knepley       PetscCall(DMPlexGetConeOrientation(dm, neighbor, &ornt));
8450851c46eSMatthew G. Knepley       for (c = 0; c < coneSize; ++c)
8460851c46eSMatthew G. Knepley         if (cone[c] == face) break;
8470851c46eSMatthew G. Knepley       if (dim == 1) {
8480851c46eSMatthew G. Knepley         /* Use cone position instead, shifted to -1 or 1 */
849835f2295SStefano Zampini         if (PetscBTLookup(flippedCells, nind)) rorntComp[face].rank = 1 - c * 2;
850835f2295SStefano Zampini         else rorntComp[face].rank = c * 2 - 1;
8510851c46eSMatthew G. Knepley       } else {
8520851c46eSMatthew G. Knepley         if (PetscBTLookup(flippedCells, nind)) rorntComp[face].rank = ornt[c] < 0 ? -1 : 1;
8530851c46eSMatthew G. Knepley         else rorntComp[face].rank = ornt[c] < 0 ? 1 : -1;
8540851c46eSMatthew G. Knepley       }
8550851c46eSMatthew G. Knepley       rorntComp[face].index = faceComp[GetPointIndex(face, fStart, fEnd, faces)];
8560851c46eSMatthew G. Knepley     }
8570851c46eSMatthew G. Knepley     // Communicate boundary edge orientations
8586497c311SBarry Smith     PetscCall(PetscSFBcastBegin(sf, MPIU_SF_NODE, rorntComp, lorntComp, MPI_REPLACE));
8596497c311SBarry Smith     PetscCall(PetscSFBcastEnd(sf, MPIU_SF_NODE, rorntComp, lorntComp, MPI_REPLACE));
8600851c46eSMatthew G. Knepley   }
8610851c46eSMatthew G. Knepley   /* Get process adjacency */
8620851c46eSMatthew G. Knepley   PetscCall(PetscMalloc2(Ncomp, &numNeighbors, Ncomp, &neighbors));
8630851c46eSMatthew G. Knepley   viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm));
8640851c46eSMatthew G. Knepley   if (viewSync) PetscCall(PetscViewerASCIIPushSynchronized(viewer));
8650851c46eSMatthew G. Knepley   PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
8660851c46eSMatthew G. Knepley   for (PetscInt comp = 0; comp < Ncomp; ++comp) {
8670851c46eSMatthew G. Knepley     PetscInt n;
8680851c46eSMatthew G. Knepley 
8690851c46eSMatthew G. Knepley     numNeighbors[comp] = 0;
8700851c46eSMatthew G. Knepley     PetscCall(PetscMalloc1(PetscMax(numLeaves, 0), &neighbors[comp]));
8710851c46eSMatthew G. Knepley     /* I know this is p^2 time in general, but for bounded degree its alright */
8720851c46eSMatthew G. Knepley     for (PetscInt l = 0; l < numLeaves; ++l) {
8730851c46eSMatthew G. Knepley       const PetscInt face = lpoints[l];
8740851c46eSMatthew G. Knepley       PetscInt       find;
8750851c46eSMatthew G. Knepley 
8760851c46eSMatthew G. Knepley       /* Find a representative face (edge) separating pairs of procs */
8770851c46eSMatthew G. Knepley       find = GetPointIndex(face, fStart, fEnd, faces);
8780851c46eSMatthew G. Knepley       if ((find >= 0) && (faceComp[find] == comp) && rorntComp[face].rank) {
8790851c46eSMatthew G. Knepley         const PetscInt rrank = rpoints[l].rank;
8800851c46eSMatthew G. Knepley         const PetscInt rcomp = lorntComp[face].index;
8810851c46eSMatthew G. Knepley 
8820851c46eSMatthew G. Knepley         for (n = 0; n < numNeighbors[comp]; ++n)
8830851c46eSMatthew G. Knepley           if ((rrank == rpoints[neighbors[comp][n]].rank) && (rcomp == lorntComp[lpoints[neighbors[comp][n]]].index)) break;
8840851c46eSMatthew G. Knepley         if (n >= numNeighbors[comp]) {
8850851c46eSMatthew G. Knepley           const PetscInt *supp;
8860851c46eSMatthew G. Knepley           PetscInt        suppSize, Ns = 0;
8870851c46eSMatthew G. Knepley 
8880851c46eSMatthew G. Knepley           PetscCall(DMPlexGetSupport(dm, face, &supp));
8890851c46eSMatthew G. Knepley           PetscCall(DMPlexGetSupportSize(dm, face, &suppSize));
8900851c46eSMatthew G. Knepley           for (PetscInt s = 0; s < suppSize; ++s) {
8910851c46eSMatthew G. Knepley             // Filter support
8920851c46eSMatthew G. Knepley             if (GetPointIndex(supp[s], cStart, cEnd, cells) >= 0) ++Ns;
8930851c46eSMatthew G. Knepley           }
8940851c46eSMatthew 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);
8950851c46eSMatthew G. Knepley           if (view)
896835f2295SStefano Zampini             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,
897835f2295SStefano Zampini                                              rpoints[l].index, rrank, rcomp, lorntComp[face].rank));
8980851c46eSMatthew G. Knepley           neighbors[comp][numNeighbors[comp]++] = l;
8990851c46eSMatthew G. Knepley         }
9000851c46eSMatthew G. Knepley       }
9010851c46eSMatthew G. Knepley     }
9020851c46eSMatthew G. Knepley     totNeighbors += numNeighbors[comp];
9030851c46eSMatthew G. Knepley   }
9040851c46eSMatthew G. Knepley   PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
9050851c46eSMatthew G. Knepley   if (viewSync) PetscCall(PetscViewerASCIIPopSynchronized(viewer));
9060851c46eSMatthew G. Knepley   PetscCall(PetscMalloc2(totNeighbors, &nrankComp, totNeighbors, &match));
9070851c46eSMatthew G. Knepley   for (PetscInt comp = 0, off = 0; comp < Ncomp; ++comp) {
9080851c46eSMatthew G. Knepley     for (PetscInt n = 0; n < numNeighbors[comp]; ++n, ++off) {
9090851c46eSMatthew G. Knepley       const PetscInt face = lpoints[neighbors[comp][n]];
9100851c46eSMatthew G. Knepley       const PetscInt o    = rorntComp[face].rank * lorntComp[face].rank;
9110851c46eSMatthew G. Knepley 
9120851c46eSMatthew G. Knepley       if (o < 0) match[off] = PETSC_TRUE;
9130851c46eSMatthew G. Knepley       else if (o > 0) match[off] = PETSC_FALSE;
9140851c46eSMatthew G. Knepley       else
915835f2295SStefano Zampini         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);
9160851c46eSMatthew G. Knepley       nrankComp[off].rank  = rpoints[neighbors[comp][n]].rank;
9170851c46eSMatthew G. Knepley       nrankComp[off].index = lorntComp[lpoints[neighbors[comp][n]]].index;
9180851c46eSMatthew G. Knepley     }
9190851c46eSMatthew G. Knepley     PetscCall(PetscFree(neighbors[comp]));
9200851c46eSMatthew G. Knepley   }
9210851c46eSMatthew G. Knepley   /* Collect the graph on 0 */
9220851c46eSMatthew G. Knepley   if (numLeaves >= 0) {
9230851c46eSMatthew G. Knepley     Mat          G;
9240851c46eSMatthew G. Knepley     PetscBT      seenProcs, flippedProcs;
9250851c46eSMatthew G. Knepley     PetscInt    *procFIFO, pTop, pBottom;
9260851c46eSMatthew G. Knepley     PetscInt    *N          = NULL, *Noff;
9270851c46eSMatthew G. Knepley     PetscSFNode *adj        = NULL;
9280851c46eSMatthew G. Knepley     PetscBool   *val        = NULL;
9290851c46eSMatthew G. Knepley     PetscMPIInt *recvcounts = NULL, *displs = NULL, *Nc;
9306497c311SBarry Smith     PetscMPIInt  size = 0, iNcomp, itotNeighbors;
9310851c46eSMatthew G. Knepley 
9320851c46eSMatthew G. Knepley     PetscCall(PetscCalloc1(Ncomp, &flipped));
9330851c46eSMatthew G. Knepley     if (rank == 0) PetscCallMPI(MPI_Comm_size(comm, &size));
9340851c46eSMatthew G. Knepley     PetscCall(PetscCalloc4(size, &recvcounts, size + 1, &displs, size, &Nc, size + 1, &Noff));
9350851c46eSMatthew G. Knepley     PetscCallMPI(MPI_Gather(&Ncomp, 1, MPI_INT, Nc, 1, MPI_INT, 0, comm));
9360851c46eSMatthew G. Knepley     for (PetscInt p = 0; p < size; ++p) displs[p + 1] = displs[p] + Nc[p];
9370851c46eSMatthew G. Knepley     if (rank == 0) PetscCall(PetscMalloc1(displs[size], &N));
9386497c311SBarry Smith     PetscCall(PetscMPIIntCast(Ncomp, &iNcomp));
9396497c311SBarry Smith     PetscCallMPI(MPI_Gatherv(numNeighbors, iNcomp, MPIU_INT, N, Nc, displs, MPIU_INT, 0, comm));
9400851c46eSMatthew G. Knepley     for (PetscInt p = 0, o = 0; p < size; ++p) {
9410851c46eSMatthew G. Knepley       recvcounts[p] = 0;
9420851c46eSMatthew G. Knepley       for (PetscInt c = 0; c < Nc[p]; ++c, ++o) recvcounts[p] += N[o];
9430851c46eSMatthew G. Knepley       displs[p + 1] = displs[p] + recvcounts[p];
9440851c46eSMatthew G. Knepley     }
9450851c46eSMatthew G. Knepley     if (rank == 0) PetscCall(PetscMalloc2(displs[size], &adj, displs[size], &val));
9466497c311SBarry Smith     PetscCall(PetscMPIIntCast(totNeighbors, &itotNeighbors));
9476497c311SBarry Smith     PetscCallMPI(MPI_Gatherv(nrankComp, itotNeighbors, MPIU_SF_NODE, adj, recvcounts, displs, MPIU_SF_NODE, 0, comm));
9486497c311SBarry Smith     PetscCallMPI(MPI_Gatherv(match, itotNeighbors, MPIU_BOOL, val, recvcounts, displs, MPIU_BOOL, 0, comm));
9490851c46eSMatthew G. Knepley     PetscCall(PetscFree2(numNeighbors, neighbors));
9500851c46eSMatthew G. Knepley     if (rank == 0) {
9510851c46eSMatthew G. Knepley       for (PetscInt p = 1; p <= size; ++p) Noff[p] = Noff[p - 1] + Nc[p - 1];
9520851c46eSMatthew G. Knepley       if (view) {
9530851c46eSMatthew G. Knepley         for (PetscInt p = 0, off = 0; p < size; ++p) {
9540851c46eSMatthew G. Knepley           for (PetscInt c = 0; c < Nc[p]; ++c) {
9550851c46eSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "Proc %" PetscInt_FMT " Comp %" PetscInt_FMT ":\n", p, c));
956835f2295SStefano Zampini             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]]));
9570851c46eSMatthew G. Knepley           }
9580851c46eSMatthew G. Knepley         }
9590851c46eSMatthew G. Knepley       }
9600851c46eSMatthew G. Knepley       /* Symmetrize the graph */
9610851c46eSMatthew G. Knepley       PetscCall(MatCreate(PETSC_COMM_SELF, &G));
9620851c46eSMatthew G. Knepley       PetscCall(MatSetSizes(G, Noff[size], Noff[size], Noff[size], Noff[size]));
9630851c46eSMatthew G. Knepley       PetscCall(MatSetUp(G));
9640851c46eSMatthew G. Knepley       for (PetscInt p = 0, off = 0; p < size; ++p) {
9650851c46eSMatthew G. Knepley         for (PetscInt c = 0; c < Nc[p]; ++c) {
9660851c46eSMatthew G. Knepley           const PetscInt r = Noff[p] + c;
9670851c46eSMatthew G. Knepley 
9680851c46eSMatthew G. Knepley           for (PetscInt n = 0; n < N[r]; ++n, ++off) {
9690851c46eSMatthew G. Knepley             const PetscInt    q = Noff[adj[off].rank] + adj[off].index;
9700851c46eSMatthew G. Knepley             const PetscScalar o = val[off] ? 1.0 : 0.0;
9710851c46eSMatthew G. Knepley 
9720851c46eSMatthew G. Knepley             PetscCall(MatSetValues(G, 1, &r, 1, &q, &o, INSERT_VALUES));
9730851c46eSMatthew G. Knepley             PetscCall(MatSetValues(G, 1, &q, 1, &r, &o, INSERT_VALUES));
9740851c46eSMatthew G. Knepley           }
9750851c46eSMatthew G. Knepley         }
9760851c46eSMatthew G. Knepley       }
9770851c46eSMatthew G. Knepley       PetscCall(MatAssemblyBegin(G, MAT_FINAL_ASSEMBLY));
9780851c46eSMatthew G. Knepley       PetscCall(MatAssemblyEnd(G, MAT_FINAL_ASSEMBLY));
9790851c46eSMatthew G. Knepley 
9800851c46eSMatthew G. Knepley       PetscCall(PetscBTCreate(Noff[size], &seenProcs));
9810851c46eSMatthew G. Knepley       PetscCall(PetscBTMemzero(Noff[size], seenProcs));
9820851c46eSMatthew G. Knepley       PetscCall(PetscBTCreate(Noff[size], &flippedProcs));
9830851c46eSMatthew G. Knepley       PetscCall(PetscBTMemzero(Noff[size], flippedProcs));
9840851c46eSMatthew G. Knepley       PetscCall(PetscMalloc1(Noff[size], &procFIFO));
9850851c46eSMatthew G. Knepley       pTop = pBottom = 0;
9860851c46eSMatthew G. Knepley       for (PetscInt p = 0; p < Noff[size]; ++p) {
9870851c46eSMatthew G. Knepley         if (PetscBTLookup(seenProcs, p)) continue;
9880851c46eSMatthew G. Knepley         /* Initialize FIFO with next proc */
9890851c46eSMatthew G. Knepley         procFIFO[pBottom++] = p;
9900851c46eSMatthew G. Knepley         PetscCall(PetscBTSet(seenProcs, p));
9910851c46eSMatthew G. Knepley         /* Consider each proc in FIFO */
9920851c46eSMatthew G. Knepley         while (pTop < pBottom) {
9930851c46eSMatthew G. Knepley           const PetscScalar *ornt;
9940851c46eSMatthew G. Knepley           const PetscInt    *neighbors;
9950851c46eSMatthew G. Knepley           PetscInt           proc, nproc, seen, flippedA, flippedB, mismatch, numNeighbors;
9960851c46eSMatthew G. Knepley 
9970851c46eSMatthew G. Knepley           proc     = procFIFO[pTop++];
9980851c46eSMatthew G. Knepley           flippedA = PetscBTLookup(flippedProcs, proc) ? 1 : 0;
9990851c46eSMatthew G. Knepley           PetscCall(MatGetRow(G, proc, &numNeighbors, &neighbors, &ornt));
10000851c46eSMatthew G. Knepley           /* Loop over neighboring procs */
10010851c46eSMatthew G. Knepley           for (PetscInt n = 0; n < numNeighbors; ++n) {
10020851c46eSMatthew G. Knepley             nproc    = neighbors[n];
10030851c46eSMatthew G. Knepley             mismatch = PetscRealPart(ornt[n]) > 0.5 ? 0 : 1;
10040851c46eSMatthew G. Knepley             seen     = PetscBTLookup(seenProcs, nproc);
10050851c46eSMatthew G. Knepley             flippedB = PetscBTLookup(flippedProcs, nproc) ? 1 : 0;
10060851c46eSMatthew G. Knepley 
10070851c46eSMatthew G. Knepley             if (mismatch ^ (flippedA ^ flippedB)) {
10080851c46eSMatthew 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);
10090851c46eSMatthew G. Knepley               if (!flippedB) {
10100851c46eSMatthew G. Knepley                 PetscCall(PetscBTSet(flippedProcs, nproc));
10110851c46eSMatthew G. Knepley               } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
10120851c46eSMatthew 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");
10130851c46eSMatthew G. Knepley             if (!seen) {
10140851c46eSMatthew G. Knepley               procFIFO[pBottom++] = nproc;
10150851c46eSMatthew G. Knepley               PetscCall(PetscBTSet(seenProcs, nproc));
10160851c46eSMatthew G. Knepley             }
10170851c46eSMatthew G. Knepley           }
10180851c46eSMatthew G. Knepley         }
10190851c46eSMatthew G. Knepley       }
10200851c46eSMatthew G. Knepley       PetscCall(PetscFree(procFIFO));
10210851c46eSMatthew G. Knepley       PetscCall(MatDestroy(&G));
10220851c46eSMatthew G. Knepley       PetscCall(PetscFree2(adj, val));
10230851c46eSMatthew G. Knepley       PetscCall(PetscBTDestroy(&seenProcs));
10240851c46eSMatthew G. Knepley     }
10250851c46eSMatthew G. Knepley     /* Scatter flip flags */
10260851c46eSMatthew G. Knepley     {
10270851c46eSMatthew G. Knepley       PetscBool *flips = NULL;
10280851c46eSMatthew G. Knepley 
10290851c46eSMatthew G. Knepley       if (rank == 0) {
10300851c46eSMatthew G. Knepley         PetscCall(PetscMalloc1(Noff[size], &flips));
10310851c46eSMatthew G. Knepley         for (PetscInt p = 0; p < Noff[size]; ++p) {
10320851c46eSMatthew G. Knepley           flips[p] = PetscBTLookup(flippedProcs, p) ? PETSC_TRUE : PETSC_FALSE;
10330851c46eSMatthew G. Knepley           if (view && flips[p]) PetscCall(PetscPrintf(comm, "Flipping Proc+Comp %" PetscInt_FMT ":\n", p));
10340851c46eSMatthew G. Knepley         }
10350851c46eSMatthew G. Knepley         for (PetscInt p = 0; p < size; ++p) displs[p + 1] = displs[p] + Nc[p];
10360851c46eSMatthew G. Knepley       }
10376497c311SBarry Smith       PetscCall(PetscMPIIntCast(Ncomp, &iNcomp));
10386497c311SBarry Smith       PetscCallMPI(MPI_Scatterv(flips, Nc, displs, MPIU_BOOL, flipped, iNcomp, MPIU_BOOL, 0, comm));
10390851c46eSMatthew G. Knepley       PetscCall(PetscFree(flips));
10400851c46eSMatthew G. Knepley     }
10410851c46eSMatthew G. Knepley     if (rank == 0) PetscCall(PetscBTDestroy(&flippedProcs));
10420851c46eSMatthew G. Knepley     PetscCall(PetscFree(N));
10430851c46eSMatthew G. Knepley     PetscCall(PetscFree4(recvcounts, displs, Nc, Noff));
10440851c46eSMatthew G. Knepley     PetscCall(PetscFree2(nrankComp, match));
10450851c46eSMatthew G. Knepley 
10460851c46eSMatthew G. Knepley     /* Decide whether to flip cells in each component */
10470851c46eSMatthew G. Knepley     for (PetscInt c = 0; c < cEnd - cStart; ++c) {
10480851c46eSMatthew G. Knepley       if (flipped[cellComp[c]]) PetscCall(PetscBTNegate(flippedCells, c));
10490851c46eSMatthew G. Knepley     }
10500851c46eSMatthew G. Knepley     PetscCall(PetscFree(flipped));
10510851c46eSMatthew G. Knepley   }
10520851c46eSMatthew G. Knepley   if (view) {
10530851c46eSMatthew G. Knepley     PetscViewer v;
10540851c46eSMatthew G. Knepley 
10550851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
10560851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(v));
10570851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for parallel flipped cells:\n", rank));
10580851c46eSMatthew G. Knepley     PetscCall(PetscBTView(cEnd - cStart, flippedCells, v));
10590851c46eSMatthew G. Knepley     PetscCall(PetscViewerFlush(v));
10600851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(v));
10610851c46eSMatthew G. Knepley   }
10620851c46eSMatthew G. Knepley   // Reverse flipped cells in the mesh
10630851c46eSMatthew G. Knepley   PetscViewer     v;
10640851c46eSMatthew G. Knepley   const PetscInt *degree = NULL;
10650851c46eSMatthew G. Knepley   PetscInt       *points;
10660851c46eSMatthew G. Knepley   PetscInt        pStart, pEnd;
10670851c46eSMatthew G. Knepley 
10680851c46eSMatthew G. Knepley   if (view) {
10690851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIGetStdout(comm, &v));
10700851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(v));
10710851c46eSMatthew G. Knepley   }
10720851c46eSMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
10730851c46eSMatthew G. Knepley   if (numRoots >= 0) {
10740851c46eSMatthew G. Knepley     PetscCall(PetscSFComputeDegreeBegin(sf, &degree));
10750851c46eSMatthew G. Knepley     PetscCall(PetscSFComputeDegreeEnd(sf, &degree));
10760851c46eSMatthew G. Knepley   }
10770851c46eSMatthew G. Knepley   PetscCall(PetscCalloc1(pEnd - pStart, &points));
10780851c46eSMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
10790851c46eSMatthew G. Knepley     if (PetscBTLookup(flippedCells, c - cStart)) {
10800851c46eSMatthew G. Knepley       const PetscInt cell = cells ? cells[c] : c;
10810851c46eSMatthew G. Knepley 
10820851c46eSMatthew G. Knepley       PetscCall(DMPlexOrientPoint(dm, cell, -1));
10830851c46eSMatthew G. Knepley       if (degree && degree[cell]) points[cell] = 1;
10840851c46eSMatthew G. Knepley       if (view) PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]Flipping cell %" PetscInt_FMT "%s\n", rank, cell, degree && degree[cell] ? " and sending to overlap" : ""));
10850851c46eSMatthew G. Knepley     }
10860851c46eSMatthew G. Knepley   }
10870851c46eSMatthew G. Knepley   // Must propagate flips for cells in the overlap
10880851c46eSMatthew G. Knepley   if (numRoots >= 0) {
10890851c46eSMatthew G. Knepley     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, points, points, MPI_SUM));
10900851c46eSMatthew G. Knepley     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, points, points, MPI_SUM));
10910851c46eSMatthew G. Knepley   }
10920851c46eSMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
10930851c46eSMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
10940851c46eSMatthew G. Knepley 
10950851c46eSMatthew G. Knepley     if (points[cell] && !PetscBTLookup(flippedCells, c - cStart)) {
10960851c46eSMatthew G. Knepley       PetscCall(DMPlexOrientPoint(dm, cell, -1));
10970851c46eSMatthew G. Knepley       if (view) PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d]Flipping cell %" PetscInt_FMT " through overlap\n", rank, cell));
10980851c46eSMatthew G. Knepley     }
10990851c46eSMatthew G. Knepley   }
11000851c46eSMatthew G. Knepley   if (view) {
11010851c46eSMatthew G. Knepley     PetscCall(PetscViewerFlush(v));
11020851c46eSMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(v));
11030851c46eSMatthew G. Knepley   }
11040851c46eSMatthew G. Knepley   PetscCall(PetscFree(points));
11050851c46eSMatthew G. Knepley   PetscCall(PetscBTDestroy(&flippedCells));
11060851c46eSMatthew G. Knepley   PetscCall(PetscFree2(numNeighbors, neighbors));
11070851c46eSMatthew G. Knepley   PetscCall(PetscFree3(rorntComp, lorntComp, locSupp));
11080851c46eSMatthew G. Knepley   PetscCall(PetscFree2(cellComp, faceComp));
11090851c46eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
111084961fc4SMatthew G. Knepley }
1111