xref: /petsc/src/dm/impls/plex/plexorient.c (revision 28b400f66ebc7ae0049166a2294dfcd3df27e64b)
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:
1027d0e99aSVaclav Hapla + dm - The DM
11b5a892a1SMatthew G. Knepley . p  - The mesh point
12b5a892a1SMatthew G. Knepley - o  - The orientation
1327d0e99aSVaclav Hapla 
1427d0e99aSVaclav Hapla   Level: intermediate
1527d0e99aSVaclav Hapla 
1627d0e99aSVaclav Hapla .seealso: DMPlexOrient(), DMPlexGetCone(), DMPlexGetConeOrientation(), DMPlexInterpolate(), DMPlexGetChart()
1727d0e99aSVaclav Hapla @*/
18b5a892a1SMatthew G. Knepley PetscErrorCode DMPlexOrientPoint(DM dm, PetscInt p, PetscInt o)
1927d0e99aSVaclav Hapla {
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);
275f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetCellType(dm, p, &ct));
28b5a892a1SMatthew G. Knepley   arr  = DMPolytopeTypeGetArrangment(ct, o);
295f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetConeSize(dm, p, &coneSize));
305f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetCone(dm, p, &cone));
315f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetConeOrientation(dm, p, &ornt));
325f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetWorkArray(dm, coneSize, MPIU_INT, &newcone));
335f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetWorkArray(dm, coneSize, MPIU_INT, &newornt));
34b5a892a1SMatthew G. Knepley   for (c = 0; c < coneSize; ++c) {
35b5a892a1SMatthew G. Knepley     DMPolytopeType ft;
36b5a892a1SMatthew G. Knepley     PetscInt       nO;
3727d0e99aSVaclav Hapla 
385f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCellType(dm, cone[c], &ft));
39b5a892a1SMatthew G. Knepley     nO   = DMPolytopeTypeGetNumArrangments(ft)/2;
40b5a892a1SMatthew G. Knepley     newcone[c] = cone[arr[c*2+0]];
41b5a892a1SMatthew G. Knepley     newornt[c] = DMPolytopeTypeComposeOrientation(ft, arr[c*2+1], ornt[arr[c*2+0]]);
422c71b3e2SJacob Faibussowitsch     PetscCheckFalse(newornt[c] && (newornt[c] >= nO || newornt[c] < -nO),PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %D not in [%D,%D) for %s %D", newornt[c], -nO, nO, DMPolytopeTypes[ft], cone[c]);
4327d0e99aSVaclav Hapla   }
445f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexSetCone(dm, p, newcone));
455f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexSetConeOrientation(dm, p, newornt));
465f80ce2aSJacob Faibussowitsch   CHKERRQ(DMRestoreWorkArray(dm, coneSize, MPIU_INT, &newcone));
475f80ce2aSJacob Faibussowitsch   CHKERRQ(DMRestoreWorkArray(dm, coneSize, MPIU_INT, &newornt));
48b5a892a1SMatthew G. Knepley   /* Update orientation of this point in the support points */
495f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSupportSize(dm, p, &supportSize));
505f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSupport(dm, p, &support));
51b5a892a1SMatthew G. Knepley   for (s = 0; s < supportSize; ++s) {
525f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeSize(dm, support[s], &coneSize));
535f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCone(dm, support[s], &cone));
545f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeOrientation(dm, support[s], &ornt));
55b5a892a1SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
56b5a892a1SMatthew G. Knepley       PetscInt po;
5727d0e99aSVaclav Hapla 
58b5a892a1SMatthew G. Knepley       if (cone[c] != p) continue;
59b5a892a1SMatthew G. Knepley       /* ornt[c] * 0 = target = po * o so that po = ornt[c] * o^{-1} */
60b5a892a1SMatthew G. Knepley       po   = DMPolytopeTypeComposeOrientationInv(ct, ornt[c], o);
615f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexInsertConeOrientation(dm, support[s], c, po));
6284961fc4SMatthew G. Knepley     }
6384961fc4SMatthew G. Knepley   }
6484961fc4SMatthew G. Knepley   PetscFunctionReturn(0);
6584961fc4SMatthew G. Knepley }
6684961fc4SMatthew G. Knepley 
677b310ce2SMatthew G. Knepley /*
687b310ce2SMatthew G. Knepley   - Checks face match
697b310ce2SMatthew G. Knepley     - Flips non-matching
707b310ce2SMatthew G. Knepley   - Inserts faces of support cells in FIFO
717b310ce2SMatthew G. Knepley */
727b2de0fdSMatthew G. Knepley static PetscErrorCode DMPlexCheckFace_Internal(DM dm, PetscInt *faceFIFO, PetscInt *fTop, PetscInt *fBottom, PetscInt cStart, PetscInt fStart, PetscInt fEnd, PetscBT seenCells, PetscBT flippedCells, PetscBT seenFaces)
737b310ce2SMatthew G. Knepley {
747b310ce2SMatthew G. Knepley   const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB;
757b310ce2SMatthew G. Knepley   PetscInt        supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1;
767b2de0fdSMatthew G. Knepley   PetscInt        face, dim, seenA, flippedA, seenB, flippedB, mismatch, c;
777b310ce2SMatthew G. Knepley 
787b310ce2SMatthew G. Knepley   PetscFunctionBegin;
797b310ce2SMatthew G. Knepley   face = faceFIFO[(*fTop)++];
805f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(dm, &dim));
815f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSupportSize(dm, face, &supportSize));
825f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSupport(dm, face, &support));
837b310ce2SMatthew G. Knepley   if (supportSize < 2) PetscFunctionReturn(0);
842c71b3e2SJacob Faibussowitsch   PetscCheckFalse(supportSize != 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize);
857b310ce2SMatthew G. Knepley   seenA    = PetscBTLookup(seenCells,    support[0]-cStart);
867b310ce2SMatthew G. Knepley   flippedA = PetscBTLookup(flippedCells, support[0]-cStart) ? 1 : 0;
877b310ce2SMatthew G. Knepley   seenB    = PetscBTLookup(seenCells,    support[1]-cStart);
887b310ce2SMatthew G. Knepley   flippedB = PetscBTLookup(flippedCells, support[1]-cStart) ? 1 : 0;
897b310ce2SMatthew G. Knepley 
905f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetConeSize(dm, support[0], &coneSizeA));
915f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetConeSize(dm, support[1], &coneSizeB));
925f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetCone(dm, support[0], &coneA));
935f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetCone(dm, support[1], &coneB));
945f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetConeOrientation(dm, support[0], &coneOA));
955f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetConeOrientation(dm, support[1], &coneOB));
967b310ce2SMatthew G. Knepley   for (c = 0; c < coneSizeA; ++c) {
977b310ce2SMatthew G. Knepley     if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) {
987b310ce2SMatthew G. Knepley       faceFIFO[(*fBottom)++] = coneA[c];
995f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscBTSet(seenFaces, coneA[c]-fStart));
1007b310ce2SMatthew G. Knepley     }
1017b310ce2SMatthew G. Knepley     if (coneA[c] == face) posA = c;
1022c71b3e2SJacob Faibussowitsch     PetscCheckFalse(*fBottom > fEnd-fStart,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], *fBottom, fEnd-fStart);
1037b310ce2SMatthew G. Knepley   }
1042c71b3e2SJacob Faibussowitsch   PetscCheckFalse(posA < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]);
1057b310ce2SMatthew G. Knepley   for (c = 0; c < coneSizeB; ++c) {
1067b310ce2SMatthew G. Knepley     if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) {
1077b310ce2SMatthew G. Knepley       faceFIFO[(*fBottom)++] = coneB[c];
1085f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscBTSet(seenFaces, coneB[c]-fStart));
1097b310ce2SMatthew G. Knepley     }
1107b310ce2SMatthew G. Knepley     if (coneB[c] == face) posB = c;
1112c71b3e2SJacob Faibussowitsch     PetscCheckFalse(*fBottom > fEnd-fStart,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], *fBottom, fEnd-fStart);
1127b310ce2SMatthew G. Knepley   }
1132c71b3e2SJacob Faibussowitsch   PetscCheckFalse(posB < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]);
1147b310ce2SMatthew G. Knepley 
1157b310ce2SMatthew G. Knepley   if (dim == 1) {
1167b310ce2SMatthew G. Knepley     mismatch = posA == posB;
1177b310ce2SMatthew G. Knepley   } else {
1187b310ce2SMatthew G. Knepley     mismatch = coneOA[posA] == coneOB[posB];
1197b310ce2SMatthew G. Knepley   }
1207b310ce2SMatthew G. Knepley 
1217b310ce2SMatthew G. Knepley   if (mismatch ^ (flippedA ^ flippedB)) {
1222c71b3e2SJacob Faibussowitsch     PetscCheckFalse(seenA && seenB,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen cells %d and %d do not match: Fault mesh is non-orientable", support[0], support[1]);
1237b310ce2SMatthew G. Knepley     if (!seenA && !flippedA) {
1245f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscBTSet(flippedCells, support[0]-cStart));
1257b310ce2SMatthew G. Knepley     } else if (!seenB && !flippedB) {
1265f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscBTSet(flippedCells, support[1]-cStart));
1277b310ce2SMatthew G. Knepley     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
1282c71b3e2SJacob Faibussowitsch   } else PetscCheckFalse(mismatch && flippedA && flippedB,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
1295f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTSet(seenCells, support[0]-cStart));
1305f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTSet(seenCells, support[1]-cStart));
1317b310ce2SMatthew G. Knepley   PetscFunctionReturn(0);
1327b310ce2SMatthew G. Knepley }
1337b310ce2SMatthew G. Knepley 
13484961fc4SMatthew G. Knepley /*@
13584961fc4SMatthew G. Knepley   DMPlexOrient - Give a consistent orientation to the input mesh
13684961fc4SMatthew G. Knepley 
13784961fc4SMatthew G. Knepley   Input Parameters:
13884961fc4SMatthew G. Knepley . dm - The DM
13984961fc4SMatthew G. Knepley 
14084961fc4SMatthew G. Knepley   Note: The orientation data for the DM are change in-place.
14184961fc4SMatthew G. Knepley $ This routine will fail for non-orientable surfaces, such as the Moebius strip.
14284961fc4SMatthew G. Knepley 
14384961fc4SMatthew G. Knepley   Level: advanced
14484961fc4SMatthew G. Knepley 
14584961fc4SMatthew G. Knepley .seealso: DMCreate(), DMPLEX
14684961fc4SMatthew G. Knepley @*/
14784961fc4SMatthew G. Knepley PetscErrorCode DMPlexOrient(DM dm)
14884961fc4SMatthew G. Knepley {
14984961fc4SMatthew G. Knepley   MPI_Comm           comm;
150e1d83109SMatthew G. Knepley   PetscSF            sf;
151e1d83109SMatthew G. Knepley   const PetscInt    *lpoints;
152e1d83109SMatthew G. Knepley   const PetscSFNode *rpoints;
153e1d83109SMatthew G. Knepley   PetscSFNode       *rorntComp = NULL, *lorntComp = NULL;
154e1d83109SMatthew G. Knepley   PetscInt          *numNeighbors, **neighbors;
155e1d83109SMatthew G. Knepley   PetscSFNode       *nrankComp;
156e1d83109SMatthew G. Knepley   PetscBool         *match, *flipped;
15784961fc4SMatthew G. Knepley   PetscBT            seenCells, flippedCells, seenFaces;
158e1d83109SMatthew G. Knepley   PetscInt          *faceFIFO, fTop, fBottom, *cellComp, *faceComp;
1597cadcfe8SMatthew G. Knepley   PetscInt           numLeaves, numRoots, dim, h, cStart, cEnd, c, cell, fStart, fEnd, face, off, totNeighbors = 0;
16039526728SToby Isaac   PetscMPIInt        rank, size, numComponents, comp = 0;
16139526728SToby Isaac   PetscBool          flg, flg2;
162a17aa47eSToby Isaac   PetscViewer        viewer = NULL, selfviewer = NULL;
16384961fc4SMatthew G. Knepley 
16484961fc4SMatthew G. Knepley   PetscFunctionBegin;
1655f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectGetComm((PetscObject) dm, &comm));
1665f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm, &rank));
1675f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_size(comm, &size));
1685f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsHasName(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-orientation_view", &flg));
1695f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsHasName(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-orientation_view_synchronized", &flg2));
1705f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetPointSF(dm, &sf));
1715f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFGetGraph(sf, &numRoots, &numLeaves, &lpoints, &rpoints));
17284961fc4SMatthew G. Knepley   /* Truth Table
17384961fc4SMatthew G. Knepley      mismatch    flips   do action   mismatch   flipA ^ flipB   action
17484961fc4SMatthew G. Knepley          F       0 flips     no         F             F           F
17584961fc4SMatthew G. Knepley          F       1 flip      yes        F             T           T
17684961fc4SMatthew G. Knepley          F       2 flips     no         T             F           T
17784961fc4SMatthew G. Knepley          T       0 flips     yes        T             T           F
17884961fc4SMatthew G. Knepley          T       1 flip      no
17984961fc4SMatthew G. Knepley          T       2 flips     yes
18084961fc4SMatthew G. Knepley   */
1815f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(dm, &dim));
1825f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetVTKCellHeight(dm, &h));
1835f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetHeightStratum(dm, h,   &cStart, &cEnd));
1845f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd));
1855f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTCreate(cEnd - cStart, &seenCells));
1865f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTMemzero(cEnd - cStart, seenCells));
1875f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTCreate(cEnd - cStart, &flippedCells));
1885f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTMemzero(cEnd - cStart, flippedCells));
1895f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTCreate(fEnd - fStart, &seenFaces));
1905f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTMemzero(fEnd - fStart, seenFaces));
1915f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc3(fEnd - fStart, &faceFIFO, cEnd-cStart, &cellComp, fEnd-fStart, &faceComp));
192e1d83109SMatthew G. Knepley   /*
193e1d83109SMatthew G. Knepley    OLD STYLE
194e1d83109SMatthew G. Knepley    - Add an integer array over cells and faces (component) for connected component number
195e1d83109SMatthew G. Knepley    Foreach component
196e1d83109SMatthew G. Knepley      - Mark the initial cell as seen
197e1d83109SMatthew G. Knepley      - Process component as usual
198e1d83109SMatthew G. Knepley      - Set component for all seenCells
199e1d83109SMatthew G. Knepley      - Wipe seenCells and seenFaces (flippedCells can stay)
200e1d83109SMatthew G. Knepley    - Generate parallel adjacency for component using SF and seenFaces
201e1d83109SMatthew G. Knepley    - Collect numComponents adj data from each proc to 0
202e1d83109SMatthew G. Knepley    - Build same serial graph
203e1d83109SMatthew G. Knepley    - Use same solver
204e1d83109SMatthew G. Knepley    - Use Scatterv to to send back flipped flags for each component
205e1d83109SMatthew G. Knepley    - Negate flippedCells by component
206e1d83109SMatthew G. Knepley 
207e1d83109SMatthew G. Knepley    NEW STYLE
208e1d83109SMatthew G. Knepley    - Create the adj on each process
209e1d83109SMatthew G. Knepley    - Bootstrap to complete graph on proc 0
210e1d83109SMatthew G. Knepley   */
211e1d83109SMatthew G. Knepley   /* Loop over components */
212e1d83109SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) cellComp[cell-cStart] = -1;
213e1d83109SMatthew G. Knepley   do {
214e1d83109SMatthew G. Knepley     /* Look for first unmarked cell */
215e1d83109SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) if (cellComp[cell-cStart] < 0) break;
216e1d83109SMatthew G. Knepley     if (cell >= cEnd) break;
217e1d83109SMatthew G. Knepley     /* Initialize FIFO with first cell in component */
218e1d83109SMatthew G. Knepley     {
21984961fc4SMatthew G. Knepley       const PetscInt *cone;
22084961fc4SMatthew G. Knepley       PetscInt        coneSize;
22184961fc4SMatthew G. Knepley 
222e1d83109SMatthew G. Knepley       fTop = fBottom = 0;
2235f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetConeSize(dm, cell, &coneSize));
2245f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetCone(dm, cell, &cone));
22584961fc4SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
22684961fc4SMatthew G. Knepley         faceFIFO[fBottom++] = cone[c];
2275f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscBTSet(seenFaces, cone[c]-fStart));
22884961fc4SMatthew G. Knepley       }
2295f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscBTSet(seenCells, cell-cStart));
23084961fc4SMatthew G. Knepley     }
23184961fc4SMatthew G. Knepley     /* Consider each face in FIFO */
23284961fc4SMatthew G. Knepley     while (fTop < fBottom) {
2335f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexCheckFace_Internal(dm, faceFIFO, &fTop, &fBottom, cStart, fStart, fEnd, seenCells, flippedCells, seenFaces));
23484961fc4SMatthew G. Knepley     }
235e1d83109SMatthew G. Knepley     /* Set component for cells and faces */
236e1d83109SMatthew G. Knepley     for (cell = 0; cell < cEnd-cStart; ++cell) {
237e1d83109SMatthew G. Knepley       if (PetscBTLookup(seenCells, cell)) cellComp[cell] = comp;
238e1d83109SMatthew G. Knepley     }
239e1d83109SMatthew G. Knepley     for (face = 0; face < fEnd-fStart; ++face) {
240e1d83109SMatthew G. Knepley       if (PetscBTLookup(seenFaces, face)) faceComp[face] = comp;
241e1d83109SMatthew G. Knepley     }
242e1d83109SMatthew G. Knepley     /* Wipe seenCells and seenFaces for next component */
2435f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscBTMemzero(fEnd - fStart, seenFaces));
2445f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscBTMemzero(cEnd - cStart, seenCells));
245e1d83109SMatthew G. Knepley     ++comp;
246e1d83109SMatthew G. Knepley   } while (1);
247e1d83109SMatthew G. Knepley   numComponents = comp;
24884961fc4SMatthew G. Knepley   if (flg) {
24984961fc4SMatthew G. Knepley     PetscViewer v;
25084961fc4SMatthew G. Knepley 
2515f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIGetStdout(comm, &v));
2525f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPushSynchronized(v));
2535f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for serial flipped cells:\n", rank));
2545f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscBTView(cEnd-cStart, flippedCells, v));
2555f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerFlush(v));
2565f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPopSynchronized(v));
25784961fc4SMatthew G. Knepley   }
25884961fc4SMatthew G. Knepley   /* Now all subdomains are oriented, but we need a consistent parallel orientation */
25984961fc4SMatthew G. Knepley   if (numLeaves >= 0) {
260e1d83109SMatthew G. Knepley     /* Store orientations of boundary faces*/
2615f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc2(numRoots,&rorntComp,numRoots,&lorntComp));
26284961fc4SMatthew G. Knepley     for (face = fStart; face < fEnd; ++face) {
263e1d83109SMatthew G. Knepley       const PetscInt *cone, *support, *ornt;
264e1d83109SMatthew G. Knepley       PetscInt        coneSize, supportSize;
265e1d83109SMatthew G. Knepley 
2665f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetSupportSize(dm, face, &supportSize));
26784961fc4SMatthew G. Knepley       if (supportSize != 1) continue;
2685f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetSupport(dm, face, &support));
26984961fc4SMatthew G. Knepley 
2705f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetCone(dm, support[0], &cone));
2715f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetConeSize(dm, support[0], &coneSize));
2725f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetConeOrientation(dm, support[0], &ornt));
27384961fc4SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) if (cone[c] == face) break;
27484961fc4SMatthew G. Knepley       if (dim == 1) {
27584961fc4SMatthew G. Knepley         /* Use cone position instead, shifted to -1 or 1 */
2766e1eb25cSMatthew G. Knepley         if (PetscBTLookup(flippedCells, support[0]-cStart)) rorntComp[face].rank = 1-c*2;
2776e1eb25cSMatthew G. Knepley         else                                                rorntComp[face].rank = c*2-1;
27884961fc4SMatthew G. Knepley       } else {
279e1d83109SMatthew G. Knepley         if (PetscBTLookup(flippedCells, support[0]-cStart)) rorntComp[face].rank = ornt[c] < 0 ? -1 :  1;
280e1d83109SMatthew G. Knepley         else                                                rorntComp[face].rank = ornt[c] < 0 ?  1 : -1;
28184961fc4SMatthew G. Knepley       }
282e1d83109SMatthew G. Knepley       rorntComp[face].index = faceComp[face-fStart];
28384961fc4SMatthew G. Knepley     }
284e1d83109SMatthew G. Knepley     /* Communicate boundary edge orientations */
2855f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastBegin(sf, MPIU_2INT, rorntComp, lorntComp,MPI_REPLACE));
2865f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastEnd(sf, MPIU_2INT, rorntComp, lorntComp,MPI_REPLACE));
287e1d83109SMatthew G. Knepley   }
288e1d83109SMatthew G. Knepley   /* Get process adjacency */
2895f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(numComponents, &numNeighbors, numComponents, &neighbors));
290a17aa47eSToby Isaac   viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm));
2915f80ce2aSJacob Faibussowitsch   if (flg2) CHKERRQ(PetscViewerASCIIPushSynchronized(viewer));
2925f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&selfviewer));
293e1d83109SMatthew G. Knepley   for (comp = 0; comp < numComponents; ++comp) {
294e1d83109SMatthew G. Knepley     PetscInt  l, n;
29584961fc4SMatthew G. Knepley 
296e1d83109SMatthew G. Knepley     numNeighbors[comp] = 0;
2975f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(PetscMax(numLeaves, 0), &neighbors[comp]));
298e1d83109SMatthew G. Knepley     /* I know this is p^2 time in general, but for bounded degree its alright */
299e1d83109SMatthew G. Knepley     for (l = 0; l < numLeaves; ++l) {
300e1d83109SMatthew G. Knepley       const PetscInt face = lpoints[l];
301e1d83109SMatthew G. Knepley 
302e1d83109SMatthew G. Knepley       /* Find a representative face (edge) separating pairs of procs */
303e1d83109SMatthew G. Knepley       if ((face >= fStart) && (face < fEnd) && (faceComp[face-fStart] == comp)) {
304269a49d5SMatthew G. Knepley         const PetscInt rrank = rpoints[l].rank;
305e1d83109SMatthew G. Knepley         const PetscInt rcomp = lorntComp[face].index;
306e1d83109SMatthew G. Knepley 
307269a49d5SMatthew G. Knepley         for (n = 0; n < numNeighbors[comp]; ++n) if ((rrank == rpoints[neighbors[comp][n]].rank) && (rcomp == lorntComp[lpoints[neighbors[comp][n]]].index)) break;
308e1d83109SMatthew G. Knepley         if (n >= numNeighbors[comp]) {
309e1d83109SMatthew G. Knepley           PetscInt supportSize;
310e1d83109SMatthew G. Knepley 
3115f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetSupportSize(dm, face, &supportSize));
3122c71b3e2SJacob Faibussowitsch           PetscCheckFalse(supportSize != 1,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Boundary faces should see one cell, not %d", supportSize);
3135f80ce2aSJacob Faibussowitsch           if (flg) CHKERRQ(PetscViewerASCIIPrintf(selfviewer, "[%d]: component %d, Found representative leaf %d (face %d) connecting to face %d on (%d, %d) with orientation %d\n", rank, comp, l, face, rpoints[l].index, rrank, rcomp, lorntComp[face].rank));
314e1d83109SMatthew G. Knepley           neighbors[comp][numNeighbors[comp]++] = l;
315e1d83109SMatthew G. Knepley         }
316e1d83109SMatthew G. Knepley       }
317e1d83109SMatthew G. Knepley     }
318e1d83109SMatthew G. Knepley     totNeighbors += numNeighbors[comp];
319e1d83109SMatthew G. Knepley   }
3205f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&selfviewer));
3215f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerFlush(viewer));
3225f80ce2aSJacob Faibussowitsch   if (flg2) CHKERRQ(PetscViewerASCIIPopSynchronized(viewer));
3235f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(totNeighbors, &nrankComp, totNeighbors, &match));
324e1d83109SMatthew G. Knepley   for (comp = 0, off = 0; comp < numComponents; ++comp) {
325e1d83109SMatthew G. Knepley     PetscInt n;
326e1d83109SMatthew G. Knepley 
327e1d83109SMatthew G. Knepley     for (n = 0; n < numNeighbors[comp]; ++n, ++off) {
328e1d83109SMatthew G. Knepley       const PetscInt face = lpoints[neighbors[comp][n]];
329e1d83109SMatthew G. Knepley       const PetscInt o    = rorntComp[face].rank*lorntComp[face].rank;
330e1d83109SMatthew G. Knepley 
331e1d83109SMatthew G. Knepley       if      (o < 0) match[off] = PETSC_TRUE;
332e1d83109SMatthew G. Knepley       else if (o > 0) match[off] = PETSC_FALSE;
33398921bdaSJacob Faibussowitsch       else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid face %d (%d, %d) neighbor: %d comp: %d", face, rorntComp[face], lorntComp[face], neighbors[comp][n], comp);
334e1d83109SMatthew G. Knepley       nrankComp[off].rank  = rpoints[neighbors[comp][n]].rank;
335e1d83109SMatthew G. Knepley       nrankComp[off].index = lorntComp[lpoints[neighbors[comp][n]]].index;
336e1d83109SMatthew G. Knepley     }
3375f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(neighbors[comp]));
33884961fc4SMatthew G. Knepley   }
33984961fc4SMatthew G. Knepley   /* Collect the graph on 0 */
340e1d83109SMatthew G. Knepley   if (numLeaves >= 0) {
34184961fc4SMatthew G. Knepley     Mat          G;
34284961fc4SMatthew G. Knepley     PetscBT      seenProcs, flippedProcs;
34384961fc4SMatthew G. Knepley     PetscInt    *procFIFO, pTop, pBottom;
3447cadcfe8SMatthew G. Knepley     PetscInt    *N   = NULL, *Noff;
345e1d83109SMatthew G. Knepley     PetscSFNode *adj = NULL;
34684961fc4SMatthew G. Knepley     PetscBool   *val = NULL;
3477cadcfe8SMatthew G. Knepley     PetscMPIInt *recvcounts = NULL, *displs = NULL, *Nc, p, o;
3489852e123SBarry Smith     PetscMPIInt  size = 0;
34984961fc4SMatthew G. Knepley 
3505f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc1(numComponents, &flipped));
3515f80ce2aSJacob Faibussowitsch     if (rank == 0) CHKERRMPI(MPI_Comm_size(comm, &size));
3525f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc4(size, &recvcounts, size+1, &displs, size, &Nc, size+1, &Noff));
3535f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Gather(&numComponents, 1, MPI_INT, Nc, 1, MPI_INT, 0, comm));
3549852e123SBarry Smith     for (p = 0; p < size; ++p) {
355e1d83109SMatthew G. Knepley       displs[p+1] = displs[p] + Nc[p];
356e1d83109SMatthew G. Knepley     }
3575f80ce2aSJacob Faibussowitsch     if (rank == 0) CHKERRQ(PetscMalloc1(displs[size],&N));
3585f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Gatherv(numNeighbors, numComponents, MPIU_INT, N, Nc, displs, MPIU_INT, 0, comm));
3599852e123SBarry Smith     for (p = 0, o = 0; p < size; ++p) {
360e1d83109SMatthew G. Knepley       recvcounts[p] = 0;
361e1d83109SMatthew G. Knepley       for (c = 0; c < Nc[p]; ++c, ++o) recvcounts[p] += N[o];
36284961fc4SMatthew G. Knepley       displs[p+1] = displs[p] + recvcounts[p];
36384961fc4SMatthew G. Knepley     }
3645f80ce2aSJacob Faibussowitsch     if (rank == 0) CHKERRQ(PetscMalloc2(displs[size], &adj, displs[size], &val));
3655f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Gatherv(nrankComp, totNeighbors, MPIU_2INT, adj, recvcounts, displs, MPIU_2INT, 0, comm));
3665f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Gatherv(match, totNeighbors, MPIU_BOOL, val, recvcounts, displs, MPIU_BOOL, 0, comm));
3675f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree2(numNeighbors, neighbors));
368dd400576SPatrick Sanan     if (rank == 0) {
3699852e123SBarry Smith       for (p = 1; p <= size; ++p) {Noff[p] = Noff[p-1] + Nc[p-1];}
370a83982f3SMatthew G. Knepley       if (flg) {
371e1d83109SMatthew G. Knepley         PetscInt n;
372e1d83109SMatthew G. Knepley 
3739852e123SBarry Smith         for (p = 0, off = 0; p < size; ++p) {
374e1d83109SMatthew G. Knepley           for (c = 0; c < Nc[p]; ++c) {
3755f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "Proc %d Comp %d:\n", p, c));
376e1d83109SMatthew G. Knepley             for (n = 0; n < N[Noff[p]+c]; ++n, ++off) {
3775f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "  edge (%d, %d) (%d):\n", adj[off].rank, adj[off].index, val[off]));
378e1d83109SMatthew G. Knepley             }
37984961fc4SMatthew G. Knepley           }
38084961fc4SMatthew G. Knepley         }
38184961fc4SMatthew G. Knepley       }
38284961fc4SMatthew G. Knepley       /* Symmetrize the graph */
3835f80ce2aSJacob Faibussowitsch       CHKERRQ(MatCreate(PETSC_COMM_SELF, &G));
3845f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetSizes(G, Noff[size], Noff[size], Noff[size], Noff[size]));
3855f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetUp(G));
3869852e123SBarry Smith       for (p = 0, off = 0; p < size; ++p) {
387e1d83109SMatthew G. Knepley         for (c = 0; c < Nc[p]; ++c) {
388e1d83109SMatthew G. Knepley           const PetscInt r = Noff[p]+c;
389e1d83109SMatthew G. Knepley           PetscInt       n;
390e1d83109SMatthew G. Knepley 
391e1d83109SMatthew G. Knepley           for (n = 0; n < N[r]; ++n, ++off) {
392e1d83109SMatthew G. Knepley             const PetscInt    q = Noff[adj[off].rank] + adj[off].index;
393e1d83109SMatthew G. Knepley             const PetscScalar o = val[off] ? 1.0 : 0.0;
39484961fc4SMatthew G. Knepley 
3955f80ce2aSJacob Faibussowitsch             CHKERRQ(MatSetValues(G, 1, &r, 1, &q, &o, INSERT_VALUES));
3965f80ce2aSJacob Faibussowitsch             CHKERRQ(MatSetValues(G, 1, &q, 1, &r, &o, INSERT_VALUES));
39784961fc4SMatthew G. Knepley           }
39884961fc4SMatthew G. Knepley         }
399e1d83109SMatthew G. Knepley       }
4005f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAssemblyBegin(G, MAT_FINAL_ASSEMBLY));
4015f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAssemblyEnd(G, MAT_FINAL_ASSEMBLY));
40284961fc4SMatthew G. Knepley 
4035f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscBTCreate(Noff[size], &seenProcs));
4045f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscBTMemzero(Noff[size], seenProcs));
4055f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscBTCreate(Noff[size], &flippedProcs));
4065f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscBTMemzero(Noff[size], flippedProcs));
4075f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(Noff[size], &procFIFO));
40884961fc4SMatthew G. Knepley       pTop = pBottom = 0;
4099852e123SBarry Smith       for (p = 0; p < Noff[size]; ++p) {
41084961fc4SMatthew G. Knepley         if (PetscBTLookup(seenProcs, p)) continue;
41184961fc4SMatthew G. Knepley         /* Initialize FIFO with next proc */
41284961fc4SMatthew G. Knepley         procFIFO[pBottom++] = p;
4135f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscBTSet(seenProcs, p));
41484961fc4SMatthew G. Knepley         /* Consider each proc in FIFO */
41584961fc4SMatthew G. Knepley         while (pTop < pBottom) {
41684961fc4SMatthew G. Knepley           const PetscScalar *ornt;
41784961fc4SMatthew G. Knepley           const PetscInt    *neighbors;
418e1d83109SMatthew G. Knepley           PetscInt           proc, nproc, seen, flippedA, flippedB, mismatch, numNeighbors, n;
41984961fc4SMatthew G. Knepley 
42084961fc4SMatthew G. Knepley           proc     = procFIFO[pTop++];
42184961fc4SMatthew G. Knepley           flippedA = PetscBTLookup(flippedProcs, proc) ? 1 : 0;
4225f80ce2aSJacob Faibussowitsch           CHKERRQ(MatGetRow(G, proc, &numNeighbors, &neighbors, &ornt));
42384961fc4SMatthew G. Knepley           /* Loop over neighboring procs */
42484961fc4SMatthew G. Knepley           for (n = 0; n < numNeighbors; ++n) {
42584961fc4SMatthew G. Knepley             nproc    = neighbors[n];
42684961fc4SMatthew G. Knepley             mismatch = PetscRealPart(ornt[n]) > 0.5 ? 0 : 1;
42784961fc4SMatthew G. Knepley             seen     = PetscBTLookup(seenProcs, nproc);
42884961fc4SMatthew G. Knepley             flippedB = PetscBTLookup(flippedProcs, nproc) ? 1 : 0;
42984961fc4SMatthew G. Knepley 
43084961fc4SMatthew G. Knepley             if (mismatch ^ (flippedA ^ flippedB)) {
431*28b400f6SJacob Faibussowitsch               PetscCheck(!seen,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen procs %d and %d do not match: Fault mesh is non-orientable", proc, nproc);
43284961fc4SMatthew G. Knepley               if (!flippedB) {
4335f80ce2aSJacob Faibussowitsch                 CHKERRQ(PetscBTSet(flippedProcs, nproc));
43484961fc4SMatthew G. Knepley               } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
4352c71b3e2SJacob Faibussowitsch             } else PetscCheckFalse(mismatch && flippedA && flippedB,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
43684961fc4SMatthew G. Knepley             if (!seen) {
43784961fc4SMatthew G. Knepley               procFIFO[pBottom++] = nproc;
4385f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscBTSet(seenProcs, nproc));
43984961fc4SMatthew G. Knepley             }
44084961fc4SMatthew G. Knepley           }
44184961fc4SMatthew G. Knepley         }
44284961fc4SMatthew G. Knepley       }
4435f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(procFIFO));
4445f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDestroy(&G));
4455f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree2(adj, val));
4465f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscBTDestroy(&seenProcs));
44784961fc4SMatthew G. Knepley     }
448e1d83109SMatthew G. Knepley     /* Scatter flip flags */
449e1d83109SMatthew G. Knepley     {
450e1d83109SMatthew G. Knepley       PetscBool *flips = NULL;
451e1d83109SMatthew G. Knepley 
452dd400576SPatrick Sanan       if (rank == 0) {
4535f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscMalloc1(Noff[size], &flips));
4549852e123SBarry Smith         for (p = 0; p < Noff[size]; ++p) {
455e1d83109SMatthew G. Knepley           flips[p] = PetscBTLookup(flippedProcs, p) ? PETSC_TRUE : PETSC_FALSE;
4565f80ce2aSJacob Faibussowitsch           if (flg && flips[p]) CHKERRQ(PetscPrintf(comm, "Flipping Proc+Comp %d:\n", p));
457e1d83109SMatthew G. Knepley         }
4589852e123SBarry Smith         for (p = 0; p < size; ++p) {
459e1d83109SMatthew G. Knepley           displs[p+1] = displs[p] + Nc[p];
460e1d83109SMatthew G. Knepley         }
461e1d83109SMatthew G. Knepley       }
4625f80ce2aSJacob Faibussowitsch       CHKERRMPI(MPI_Scatterv(flips, Nc, displs, MPIU_BOOL, flipped, numComponents, MPIU_BOOL, 0, comm));
4635f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(flips));
46484961fc4SMatthew G. Knepley     }
4655f80ce2aSJacob Faibussowitsch     if (rank == 0) CHKERRQ(PetscBTDestroy(&flippedProcs));
4665f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(N));
4675f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree4(recvcounts, displs, Nc, Noff));
4685f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree2(nrankComp, match));
469e1d83109SMatthew G. Knepley 
470e1d83109SMatthew G. Knepley     /* Decide whether to flip cells in each component */
4715f80ce2aSJacob Faibussowitsch     for (c = 0; c < cEnd-cStart; ++c) {if (flipped[cellComp[c]]) CHKERRQ(PetscBTNegate(flippedCells, c));}
4725f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(flipped));
47384961fc4SMatthew G. Knepley   }
47484961fc4SMatthew G. Knepley   if (flg) {
47584961fc4SMatthew G. Knepley     PetscViewer v;
47684961fc4SMatthew G. Knepley 
4775f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIGetStdout(comm, &v));
4785f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPushSynchronized(v));
4795f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for parallel flipped cells:\n", rank));
4805f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscBTView(cEnd-cStart, flippedCells, v));
4815f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerFlush(v));
4825f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPopSynchronized(v));
48384961fc4SMatthew G. Knepley   }
48484961fc4SMatthew G. Knepley   /* Reverse flipped cells in the mesh */
48584961fc4SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
4860d366550SMatthew G. Knepley     if (PetscBTLookup(flippedCells, c-cStart)) {
4875f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexOrientPoint(dm, c, -1));
4880d366550SMatthew G. Knepley     }
48984961fc4SMatthew G. Knepley   }
4905f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTDestroy(&seenCells));
4915f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTDestroy(&flippedCells));
4925f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTDestroy(&seenFaces));
4935f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(numNeighbors, neighbors));
4945f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(rorntComp, lorntComp));
4955f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree3(faceFIFO, cellComp, faceComp));
49684961fc4SMatthew G. Knepley   PetscFunctionReturn(0);
49784961fc4SMatthew G. Knepley }
498