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, °ree)); 10750851c46eSMatthew G. Knepley PetscCall(PetscSFComputeDegreeEnd(sf, °ree)); 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