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