Exemple #1
0
//- Calculate the offset to the next layer
Foam::tmp<Foam::vectorField> Foam::layerAdditionRemovalMC::extrusionDir() const
{
    const polyMesh& mesh = topoChanger().mesh();
    const primitiveFacePatch& masterFaceLayer =
        mesh.faceZones()[faceZoneID_.index()]();

    const pointField& points = mesh.points();
    const labelList& mp = masterFaceLayer.meshPoints();

    tmp<vectorField> textrusionDir(new vectorField(mp.size()));
    vectorField& extrusionDir = textrusionDir();

    if (setLayerPairing())
    {
        if (debug)
        {
            Pout<< "void layerAdditionRemovalMC::extrusionDir() const "
                << " for object " << name() << " : "
                << "Using edges for point insertion" << endl;
        }

        // Detected a valid layer.  Grab the point and face collapse mapping
        const labelList& ptc = pointsPairing();

        forAll(extrusionDir, mpI)
        {
            extrusionDir[mpI] = points[ptc[mpI]] - points[mp[mpI]];
        }
    }
void Foam::layerAdditionRemoval::addCellLayer
(
    polyTopoChange& ref
) const
{
    // Insert the layer addition instructions into the topological change

    // Algorithm:
    // 1.  For every point in the master zone add a new point
    // 2.  For every face in the master zone add a cell
    // 3.  Go through all the edges of the master zone.  For all internal
    //     edges, add a face with the correct orientation and make it internal.
    //     For all boundary edges, find the patch it belongs to and add the
    //     face to this patch
    // 4.  Create a set of new faces on the patch image and assign them to be
    //     between the old master cells and the newly created cells
    // 5.  Modify all the faces in the patch such that they are located
    //     between the old slave cells and newly created cells

    if (debug)
    {
        Pout<< "void layerAdditionRemoval::addCellLayer("
            << "polyTopoChange& ref) const for object " << name() << " : "
            << "Adding cell layer" << endl;
    }

    // Create the points

    const polyMesh& mesh = topoChanger().mesh();
    const primitiveFacePatch& masterFaceLayer =
        mesh.faceZones()[faceZoneID_.index()]();

    const pointField& points = mesh.points();
    const labelList& mp = masterFaceLayer.meshPoints();

    // Calculation of point normals, using point pairing

    vectorField extrusionDir(mp.size());

    if (setLayerPairing())
    {
        if (debug)
        {
            Pout<< "void layerAdditionRemoval::addCellLayer("
                << "polyTopoChange& ref) const "
                << " for object " << name() << " : "
                << "Using edges for point insertion" << endl;
        }

        // Detected a valid layer.  Grab the point and face collapse mapping
        const labelList& ptc = pointsPairing();

        forAll (extrusionDir, mpI)
        {
            extrusionDir[mpI] = points[ptc[mpI]] - points[mp[mpI]];
        }
        extrusionDir *= addDelta_*maxLayerThickness_;
    }
void Foam::repatchCoverage::updateMesh(const mapPolyMesh&)
{
    // Mesh has changed topologically.  Update local topological data
    const polyMesh& mesh = topoChanger().mesh();

    masterCoveredPatchID_.update(mesh.boundaryMesh());
    masterUncoveredPatchID_.update(mesh.boundaryMesh());
    slaveCoveredPatchID_.update(mesh.boundaryMesh());
    slaveUncoveredPatchID_.update(mesh.boundaryMesh());
}
bool Foam::layerAdditionRemoval::changeTopology() const
{
    // Protect from multiple calculation in the same time-step
    if (triggerRemoval_ > -1 || triggerAddition_ > -1)
    {
        return true;
    }

    // Go through all the cells in the master layer and calculate
    // approximate layer thickness as the ratio of the cell volume and
    // face area in the face zone.
    // Layer addition:
    //     When the max thickness exceeds the threshold, trigger refinement.
    // Layer removal:
    //     When the min thickness falls below the threshold, trigger removal.

    const faceZone& fz = topoChanger().mesh().faceZones()[faceZoneID_.index()];
    const labelList& mc = fz.masterCells();

    const scalarField& V = topoChanger().mesh().cellVolumes();
    const vectorField& S = topoChanger().mesh().faceAreas();

    if (min(V) < -VSMALL)
    {
        FatalErrorIn("bool layerAdditionRemoval::changeTopology() const")
            << "negative cell volume. Error in mesh motion before "
            << "topological change.\n V: " << V
            << abort(FatalError);
    }

    scalar avgDelta = 0;
    scalar minDelta = GREAT;
    scalar maxDelta = 0;

    forAll (fz, faceI)
    {
        scalar curDelta = V[mc[faceI]]/mag(S[fz[faceI]]);
        avgDelta += curDelta;
        minDelta = min(minDelta, curDelta);
        maxDelta = max(maxDelta, curDelta);
    }
Exemple #5
0
void Foam::attachDetach::attachInterface
(
    polyTopoChange& ref
) const
{
    // Algorithm:
    // 1. Create the reverse patch out of the slave faces.
    // 2. Go through all the mesh points from the master and slave patch.
    //    If the point labels are different, insert them into the point
    //    renumbering list and remove them from the mesh.
    // 3. Remove all faces from the slave patch
    // 4. Modify all the faces from the master patch by making them internal
    //    between the faceCell cells for the two patches.  If the master owner
    //    is higher than the slave owner, turn the face around
    // 5. Get all the faces attached to the slave patch points.
    //    If they have not been removed, renumber them using the
    //    point renumbering list.

    if (debug)
    {
        Pout<< "void attachDetach::attachInterface("
            << "polyTopoChange& ref) const "
            << " for object " << name() << " : "
            << "Attaching interface" << endl;
    }

    const polyMesh& mesh = topoChanger().mesh();
    const faceList& faces = mesh.faces();
    const labelList& own = mesh.faceOwner();
    const labelList& nei = mesh.faceNeighbour();

    const polyPatch& masterPatch = mesh.boundaryMesh()[masterPatchID_.index()];
    const polyPatch& slavePatch = mesh.boundaryMesh()[slavePatchID_.index()];

    const label masterPatchStart = masterPatch.start();
    const label slavePatchStart = slavePatch.start();

    const labelList& slaveMeshPoints = slavePatch.meshPoints();

    const Map<label>& removedPointMap = pointMatchMap();

    const labelList removedPoints = removedPointMap.toc();

    forAll (removedPoints, pointI)
    {
        ref.setAction(polyRemovePoint(removedPoints[pointI]));
    }
bool Foam::layerAdditionRemoval::validCollapse() const
{
    // Check for valid layer collapse
    // - no boundary-to-boundary collapse

    if (debug)
    {
        Pout<< "Checking layer collapse for object " << name() << endl;
    }

    // Grab the face collapse mapping
    const polyMesh& mesh = topoChanger().mesh();

    const labelList& ftc = facesPairing();
    const labelList& mf = mesh.faceZones()[faceZoneID_.index()];

    label nBoundaryHits = 0;

    forAll(mf, facei)
    {
        if
        (
            !mesh.isInternalFace(mf[facei])
         && !mesh.isInternalFace(ftc[facei])
        )
        {
            nBoundaryHits++;
        }
    }


    if (debug)
    {
        Pout<< "Finished checking layer collapse for object "
            << name() <<".  Number of boundary-on-boundary hits: "
            << nBoundaryHits << endl;
    }

    if (returnReduce(nBoundaryHits, sumOp<label>()) > 0)
    {
        return false;
    }
    else
    {
        return true;
    }
}
void Foam::layerAdditionRemoval::removeCellLayer
(
    polyTopoChange& ref
) const
{
    // Algorithm for layer removal.  Second phase: topological change
    // 2)  Go through all the faces of the master cell layer and remove
    //     the ones that are not in the master face zone.
    //
    // 3)  Grab all the faces coming out of points that are collapsed
    //     and select the ones that are not marked for removal.  Go
    //     through the remaining faces and replace the point to remove by
    //     the equivalent point in the master face zone.
    if (debug)
    {
        Pout<< "Removing the cell layer for object " << name() << endl;
    }

    const polyMesh& mesh = topoChanger().mesh();

    const labelList& own = mesh.faceOwner();
    const labelList& nei = mesh.faceNeighbour();

    const labelList& ptc = pointsPairing();
    const labelList& ftc = facesPairing();

    // Remove all the cells from the master layer
    const labelList& mc =
        mesh.faceZones()[faceZoneID_.index()].masterCells();

    forAll(mc, facei)
    {
        label slaveSideCell = own[ftc[facei]];

        if (mesh.isInternalFace(ftc[facei]) && slaveSideCell == mc[facei])
        {
            // Owner cell of the face is being removed.
            // Grab the neighbour instead
            slaveSideCell = nei[ftc[facei]];
        }

        ref.setAction(polyRemoveCell(mc[facei], slaveSideCell));
    }
void Foam::layerAdditionRemoval::checkDefinition()
{
    if (!faceZoneID_.active())
    {
        FatalErrorIn
        (
            "void Foam::layerAdditionRemoval::checkDefinition()"
        )   << "Master face zone named " << faceZoneID_.name()
            << " cannot be found."
            << abort(FatalError);
    }

    if
    (
        minLayerThickness_ < VSMALL
     || maxLayerThickness_ < minLayerThickness_
    )
    {
        FatalErrorIn
        (
            "void Foam::layerAdditionRemoval::checkDefinition()"
        )   << "Incorrect layer thickness definition."
            << abort(FatalError);
    }

    if (topoChanger().mesh().faceZones()[faceZoneID_.index()].empty())
    {
        FatalErrorIn
        (
            "void Foam::layerAdditionRemoval::checkDefinition()"
        )   << "Face extrusion zone contains no faces. "
            << " Please check your mesh definition."
            << abort(FatalError);
    }

    if (debug)
    {
        Pout<< "Cell layer addition/removal object " << name() << " :" << nl
            << "    faceZoneID: " << faceZoneID_ << endl;
    }
}
void Foam::slidingInterface::clearCouple
(
    polyTopoChange& ref
) const
{
    if (debug)
    {
        Pout<< "void slidingInterface::clearCouple("
            << "polyTopoChange& ref) const for object " << name() << " : "
            << "Clearing old couple points and faces." << endl;
    }

    // Remove all points from the point zone

    const polyMesh& mesh = topoChanger().mesh();

    const labelList& cutPointZoneLabels =
        mesh.pointZones()[cutPointZoneID_.index()];

    forAll(cutPointZoneLabels, pointI)
    {
        ref.setAction(polyRemovePoint(cutPointZoneLabels[pointI]));
    }
void Foam::faceCracker::detachFaceCracker
(
    polyTopoChange& ref
) const
{
    if (debug)
    {
        Pout<< "void faceCracker::detachFaceCracker("
            << "polyTopoChange& ref) const "
            << " for object " << name() << " : "
            << "Detaching faces" << endl;
    }

    const polyMesh& mesh = topoChanger().mesh();
    const faceZoneMesh& zoneMesh = mesh.faceZones();

    const primitiveFacePatch& masterFaceLayer =
        zoneMesh[crackZoneID_.index()]();
    const pointField& points = mesh.points();
    const labelListList& meshEdgeFaces = mesh.edgeFaces();

    const labelList& mp = masterFaceLayer.meshPoints();
    const edgeList& zoneLocalEdges = masterFaceLayer.edges();

    const labelList& meshEdges = zoneMesh[crackZoneID_.index()].meshEdges();

    // Create the points

    labelList addedPoints(mp.size(), -1);

    // Go through boundary edges of the master patch.  If all the faces from
    // this patch are internal, mark the points in the addedPoints lookup
    // with their original labels to stop duplication
    label nIntEdges = masterFaceLayer.nInternalEdges();

    for
    (
        label curEdgeID = nIntEdges;
        curEdgeID < meshEdges.size();
        curEdgeID++
    )
    {
        const labelList& curFaces = meshEdgeFaces[meshEdges[curEdgeID]];

        bool edgeIsInternal = true;

        forAll (curFaces, faceI)
        {
            if (!mesh.isInternalFace(curFaces[faceI]))
            {
                // The edge belongs to a boundary face
                edgeIsInternal = false;
                break;
            }
        }

        if (edgeIsInternal)
        {
            // Reset the point creation
            addedPoints[zoneLocalEdges[curEdgeID].start()] =
                mp[zoneLocalEdges[curEdgeID].start()];

            addedPoints[zoneLocalEdges[curEdgeID].end()] =
                mp[zoneLocalEdges[curEdgeID].end()];
        }
    }

    // Create new points for face zone
    forAll (addedPoints, pointI)
    {
        if (addedPoints[pointI] < 0)
        {
            addedPoints[pointI] =
                ref.setAction
                (
                    polyAddPoint
                    (
                        points[mp[pointI]],        // point
                        mp[pointI],                // master point
                        -1,                        // zone ID
                        true                       // supports a cell
                    )
                );
        }
    }

    // Modify faces in the master zone and duplicate for the slave zone

    const labelList& mf = zoneMesh[crackZoneID_.index()];
    const boolList& mfFlip = zoneMesh[crackZoneID_.index()].flipMap();
    const faceList& zoneFaces = masterFaceLayer.localFaces();

    const faceList& faces = mesh.faces();
    const labelList& own = mesh.faceOwner();
    const labelList& nei = mesh.faceNeighbour();

    forAll (mf, faceI)
    {
        const label curFaceID = mf[faceI];

        // Build the face for the slave patch by renumbering
        const face oldFace = zoneFaces[faceI].reverseFace();

        face newFace(oldFace.size());

        forAll (oldFace, pointI)
        {
            newFace[pointI] = addedPoints[oldFace[pointI]];
        }

        if (mfFlip[faceI])
        {
            // Face needs to be flipped for the master patch
            ref.setAction
            (
                polyModifyFace
                (
                    faces[curFaceID].reverseFace(), // modified face
                    curFaceID,                  // label of face being modified
                    nei[curFaceID],                 // owner
                    -1,                             // neighbour
                    true,                           // face flip
                    crackPatchID_.index(),          // patch for face
                    false,                          // remove from zone
                    crackZoneID_.index(),           // zone for face
                    !mfFlip[faceI]                  // face flip in zone
                )
            );

            // Add renumbered face into the slave patch
            ref.setAction
            (
                polyAddFace
                (
                    newFace,                        // face
                    own[curFaceID],                 // owner
                    -1,                             // neighbour
                    -1,                             // master point
                    -1,                             // master edge
                    curFaceID,                      // master face
                    false,                          // flip flux
                    crackPatchID_.index(),          // patch to add the face to
                    -1,                             // zone for face
                    false                           // zone flip
                )
            );
        }
        else
        {
            // No flip
            ref.setAction
            (
                polyModifyFace
                (
                    faces[curFaceID],         // modified face
                    curFaceID,                // label of face being modified
                    own[curFaceID],           // owner
                    -1,                       // neighbour
                    false,                    // face flip
                    crackPatchID_.index(),    // patch for face
                    false,                    // remove from zone
                    crackZoneID_.index(),     // zone for face
                    mfFlip[faceI]             // face flip in zone
                )
            );

            // Add renumbered face into the slave patch
            ref.setAction
            (
                polyAddFace
                (
                    newFace,                        // face
                    nei[curFaceID],                 // owner
                    -1,                             // neighbour
                    -1,                             // master point
                    -1,                             // master edge
                    curFaceID,                      // master face
                    true,                           // flip flux
                    crackPatchID_.index(),          // patch to add the face to
                    -1,                             // zone for face
                    false                           // face flip in zone
                )
            );
        }
    }

    // Modify the remaining faces of the master cells to reconnect to the new
    // layer of faces.

    // Algorithm: Go through all the cells of the master zone and make
    // a map of faces to avoid duplicates.  Do not insert the faces in
    // the master patch (as they have already been dealt with).  Make
    // a master layer point renumbering map, which for every point in
    // the master layer gives its new label. Loop through all faces in
    // the map and attempt to renumber them using the master layer
    // point renumbering map.  Once the face is renumbered, compare it
    // with the original face; if they are the same, the face has not
    // changed; if not, modify the face but keep all of its old
    // attributes (apart from the vertex numbers).


    // Create the map of faces in the master cell layer
    // Bug-fix: PC, HJ and ZT, 19 Feb 2013

    labelHashSet masterCellFaceMap(12*mf.size());

    const labelListList& pointFaces = mesh.pointFaces();

    forAll(mf, faceI)
    {
        const labelList& curFacePoints = faces[mf[faceI]];

        forAll(curFacePoints, pointI)
        {
            const labelList& curPointFaces =
                pointFaces[curFacePoints[pointI]];

            forAll(curPointFaces, fI)
            {
                if
                (
                    zoneMesh.whichZone(curPointFaces[fI])
                 != crackZoneID_.index()
                )
                {
                    masterCellFaceMap.insert(curPointFaces[fI]);
                }
            }
        }
    }


//     // Create the map of faces in the master cell layer
//     const labelList& mc =
//         mesh.faceZones()[crackZoneID_.index()].masterCells();

//     labelHashSet masterCellFaceMap(6*mc.size());

//     const cellList& cells = mesh.cells();

//     forAll (mc, cellI)
//     {
//         const labelList& curFaces = cells[mc[cellI]];

//         forAll (curFaces, faceI)
//         {
//             // Check if the face belongs to the master patch; if not add it
//             if (zoneMesh.whichZone(curFaces[faceI]) != crackZoneID_.index())
//             {
//                 masterCellFaceMap.insert(curFaces[faceI]);
//             }
//         }
//     }

//     // Extend the map to include first neighbours of the master cells to
//     // deal with multiple corners.
//     { // Protection and memory management
//         // Make a map of master cells for quick reject
//         labelHashSet mcMap(2*mc.size());

//         forAll (mc, mcI)
//         {
//             mcMap.insert(mc[mcI]);
//         }

//         // Go through all the faces in the masterCellFaceMap.  If the
//         // cells around them are not already used, add all of their
//         // faces to the map
//         const labelList mcf = masterCellFaceMap.toc();

//         forAll (mcf, mcfI)
//         {
//             // Do the owner side
//             const label ownCell = own[mcf[mcfI]];

//             if (!mcMap.found(ownCell))
//             {
//                 // Cell not found. Add its faces to the map
//                 const cell& curFaces = cells[ownCell];

//                 forAll (curFaces, faceI)
//                 {
//                     masterCellFaceMap.insert(curFaces[faceI]);
//                 }
//             }

//             // Do the neighbour side if face is internal
//             if (mesh.isInternalFace(mcf[mcfI]))
//             {
//                 const label neiCell = nei[mcf[mcfI]];

//                 if (!mcMap.found(neiCell))
//                 {
//                     // Cell not found. Add its faces to the map
//                     const cell& curFaces = cells[neiCell];

//                     forAll (curFaces, faceI)
//                     {
//                         masterCellFaceMap.insert(curFaces[faceI]);
//                     }
//                 }
//             }
//         }
//     }

    // Create the master layer point map
    Map<label> masterLayerPointMap(2*mp.size());

    forAll (mp, pointI)
    {
        masterLayerPointMap.insert
        (
            mp[pointI],
            addedPoints[pointI]
        );
    }
bool Foam::slidingInterface::projectPoints() const
{
    if (debug)
    {
        Pout<< "bool slidingInterface::projectPoints() : "
            << " for object " << name() << " : "
            << "Projecting slave points onto master surface." << endl;
    }

    // Algorithm:
    // 1) Go through all the points of the master and slave patch and calculate
    //    minimum edge length coming from the point.  Calculate the point
    //    merge tolerance as the fraction of mimimum edge length.
    // 2) Project all the slave points onto the master patch
    //    in the normal direction.
    // 3) If some points have missed and the match is integral, the
    //    points in question will be adjusted.  Find the nearest face for
    //    those points and continue with the procedure.
    // 4) For every point, check all the points of the face it has hit.
    //    For every pair of points find if their distance is smaller than
    //    both the master and slave merge tolerance.  If so, the slave point
    //    is moved to the location of the master point.  Remember the master
    //    point index.
    // 5) For every unmerged slave point, check its distance to all the
    //    edges of the face it has hit.  If the distance is smaller than the
    //    edge merge tolerance, the point will be moved onto the edge.
    //    Remember the master edge index.
    // 6) The remaning slave points will be projected into faces.  Remember the
    //    master face index.
    // 7) For the points that miss the master patch, grab the nearest face
    //    on the master and leave the slave point where it started
    //    from and the miss is recorded.

    const polyMesh& mesh = topoChanger().mesh();

    const primitiveFacePatch& masterPatch =
        mesh.faceZones()[masterFaceZoneID_.index()]();

    const primitiveFacePatch& slavePatch =
        mesh.faceZones()[slaveFaceZoneID_.index()]();

    // Get references to local points, local edges and local faces
    // for master and slave patch
//     const labelList& masterMeshPoints = masterPatch.meshPoints();
    const pointField& masterLocalPoints = masterPatch.localPoints();
    const faceList& masterLocalFaces = masterPatch.localFaces();
    const edgeList& masterEdges = masterPatch.edges();
    const labelListList& masterEdgeFaces = masterPatch.edgeFaces();
    const labelListList& masterFaceEdges = masterPatch.faceEdges();
    const labelListList& masterFaceFaces = masterPatch.faceFaces();
//     Pout<< "Master patch.  Local points: " << masterLocalPoints << nl
//         << "Master patch.  Mesh points: " << masterPatch.meshPoints() << nl
//         << "Local faces: " << masterLocalFaces << nl
//         << "local edges: " << masterEdges << endl;

//     const labelList& slaveMeshPoints = slavePatch.meshPoints();
    const pointField& slaveLocalPoints = slavePatch.localPoints();
    const edgeList& slaveEdges = slavePatch.edges();
    const labelListList& slaveEdgeFaces = slavePatch.edgeFaces();
    const vectorField& slavePointNormals = slavePatch.pointNormals();
//     const vectorField& slaveFaceNormals = slavePatch.faceNormals();
//     Pout<< "Slave patch.  Local points: " << slaveLocalPoints << nl
//         << "Slave patch.  Mesh points: " << slavePatch.meshPoints() << nl
//         << "Local faces: " << slavePatch.localFaces() << nl
//         << "local edges: " << slaveEdges << endl;

    // Calculate min edge distance for points and faces

    // Calculate min edge length for the points and faces of master patch
    scalarField minMasterPointLength(masterLocalPoints.size(), GREAT);
    scalarField minMasterFaceLength(masterPatch.size(), GREAT);

    forAll(masterEdges, edgeI)
    {
        const edge& curEdge = masterEdges[edgeI];

        const scalar curLength =
            masterEdges[edgeI].mag(masterLocalPoints);

        // Do points
        minMasterPointLength[curEdge.start()] =
            min
            (
                minMasterPointLength[curEdge.start()],
                curLength
            );

        minMasterPointLength[curEdge.end()] =
            min
            (
                minMasterPointLength[curEdge.end()],
                curLength
            );

        // Do faces
        const labelList& curFaces = masterEdgeFaces[edgeI];

        forAll(curFaces, faceI)
        {
            minMasterFaceLength[curFaces[faceI]] =
                min
                (
                    minMasterFaceLength[curFaces[faceI]],
                    curLength
                );
        }
    }
bool Foam::layerAdditionRemoval::setLayerPairing() const
{
    // Note:
    // This is also the most complex part of the topological change.
    // Therefore it will be calculated here and stored as temporary
    // data until the actual topological change, after which it will
    // be cleared.

    // Algorithm for point collapse
    // 1)  Go through the master cell layer and for every face of
    //     the face zone find the opposite face in the master cell.
    //     Check the direction of the opposite face and adjust as
    //     necessary.  Check other faces to find an edge defining
    //     relative orientation of the two faces and adjust the face
    //     as necessary.  Once the face is adjusted, record the
    //     addressing between the master and slave vertex layer.

    const polyMesh& mesh = topoChanger().mesh();

    const labelList& mc =
        mesh.faceZones()[faceZoneID_.index()].masterCells();

    const labelList& mf = mesh.faceZones()[faceZoneID_.index()];

    const boolList& mfFlip =
        mesh.faceZones()[faceZoneID_.index()].flipMap();

    const faceList& faces = mesh.faces();
    const cellList& cells = mesh.cells();

    // Grab the local faces from the master zone
    const faceList& mlf =
        mesh.faceZones()[faceZoneID_.index()]().localFaces();

    const labelList& meshPoints =
        mesh.faceZones()[faceZoneID_.index()]().meshPoints();

    // Create a list of points to collapse for every point of
    // the master patch
    if (pointsPairingPtr_ || facesPairingPtr_)
    {
        FatalErrorIn
        (
            "void Foam::layerAdditionRemoval::setLayerPairing() const"
        )   << "Problem with layer pairing data"
            << abort(FatalError);
    }

    pointsPairingPtr_ = new labelList(meshPoints.size(), -1);
    labelList& ptc = *pointsPairingPtr_;

    facesPairingPtr_ = new labelList(mf.size(), -1);
    labelList& ftc = *facesPairingPtr_;
    // Pout<< "meshPoints: " << meshPoints << nl
    //      << "localPoints: "
    //     << mesh.faceZones()[faceZoneID_.index()]().localPoints()
    //     << endl;

    // For all faces, create the mapping
    label nPointErrors = 0;
    label nFaceErrors = 0;

    forAll(mf, faceI)
    {
        // Get the local master face
        face curLocalFace = mlf[faceI];

        // Flip face based on flip index to recover original orientation
        if (mfFlip[faceI])
        {
            curLocalFace.flip();
        }

        // Get the opposing face from the master cell
        oppositeFace lidFace =
            cells[mc[faceI]].opposingFace(mf[faceI], faces);

        if (!lidFace.found())
        {
            // This is not a valid layer; cannot continue
            nFaceErrors++;
            continue;
        }

// Pout<< "curMasterFace: " << faces[mf[faceI]] << nl
//     << "cell shape: " << mesh.cellShapes()[mc[faceI]] << nl
//     << "curLocalFace: " << curLocalFace << nl
//     << "lidFace: " << lidFace
//     << " master index: " << lidFace.masterIndex()
//     << " oppositeIndex: " << lidFace.oppositeIndex() << endl;

        // Grab the opposite face for face collapse addressing
        ftc[faceI] = lidFace.oppositeIndex();

        // Using the local face insert the points into the lid list
        forAll(curLocalFace, pointI)
        {
            const label clp = curLocalFace[pointI];

            if (ptc[clp] == -1)
            {
                // Point not mapped yet.  Insert the label
                ptc[clp] = lidFace[pointI];
            }
            else
            {
                // Point mapped from some other face.  Check the label
                if (ptc[clp] != lidFace[pointI])
                {
                    nPointErrors++;
//                     Pout<< "Topological error in cell layer pairing.  "
//                         << "This mesh is either topologically incorrect "
//                         << "or the master afce layer is not defined "
//                         << "consistently.  Please check the "
//                         << "face zone flip map." << nl
//                         << "First index: " << ptc[clp]
//                         << " new index: " << lidFace[pointI] << endl;
                }
            }
        }
//         Pout<< "ptc: " << ptc << endl;
    }
void Foam::attachDetach::checkDefinition()
{
    if
    (
        !faceZoneID_.active()
     || !masterPatchID_.active()
     || !slavePatchID_.active()
    )
    {
        FatalErrorInFunction
            << "Not all zones and patches needed in the definition "
            << "have been found.  Please check your mesh definition."
            << abort(FatalError);
    }

    const polyMesh& mesh = topoChanger().mesh();

    if (debug)
    {
        Pout<< "Attach/detach object " << name() << " :" << nl
            << "    faceZoneID:   " << faceZoneID_ << nl
            << "    masterPatchID: " << masterPatchID_ << nl
            << "    slavePatchID: " << slavePatchID_ << endl;
    }

    // Check the sizes and set up state
    if
    (
        mesh.boundaryMesh()[masterPatchID_.index()].empty()
     && mesh.boundaryMesh()[slavePatchID_.index()].empty()
    )
    {
        // Boundary is attached
        if (debug)
        {
            Pout<< "    Attached on construction" << endl;
        }

        state_ = ATTACHED;

        // Check if there are faces in the master zone
        if (mesh.faceZones()[faceZoneID_.index()].empty())
        {
            FatalErrorInFunction
                << "mesh definition."
                << abort(FatalError);
        }

        // Check that all the faces in the face zone are internal
        if (debug)
        {
            const labelList& addr = mesh.faceZones()[faceZoneID_.index()];

            DynamicList<label> bouFacesInZone(addr.size());

            forAll(addr, facei)
            {
                if (!mesh.isInternalFace(addr[facei]))
                {
                    bouFacesInZone.append(addr[facei]);
                }
            }

            if (bouFacesInZone.size())
            {
                FatalErrorInFunction
                    << "Found boundary faces in the zone defining "
                    << "attach/detach boundary "
                    << " for object " << name()
                    << " : .  This is not allowed." << nl
                    << "Boundary faces: " << bouFacesInZone
                    << abort(FatalError);
            }
        }
    }
    else
    {
        // Boundary is detached
        if (debug)
bool Foam::repatchCoverage::changeTopology() const
{
    // Check that masks are empty
    if (!uncMaster_.empty() || !uncSlave_.empty())
    {
        FatalErrorIn("bool repatchCoverage::changeTopology() const")
            << "Uncovered masks are not empty.  Topo change is out of sync"
            << abort(FatalError);
    }

    // Get mesh reference
    const polyMesh& mesh = topoChanger().mesh();

    const pointField& allPoints = mesh.allPoints();
    const faceList& allFaces = mesh.allFaces();

    // Collect all faces for interpolation

    // Master side
    const polyPatch& masterCoveredPatch =
        mesh.boundaryMesh()[masterCoveredPatchID_.index()];

    const polyPatch& masterUncoveredPatch =
        mesh.boundaryMesh()[masterUncoveredPatchID_.index()];

    faceList masterSide
    (
        masterCoveredPatch.size()
      + masterUncoveredPatch.size()
    );

    {
        label nFaces = 0;

        // Insert covered faces
        for
        (
            label faceI = masterCoveredPatch.start();
            faceI < masterCoveredPatch.start() + masterCoveredPatch.size();
            faceI++
        )
        {
            masterSide[nFaces] = allFaces[faceI];
            nFaces++;
        }

        // Insert uncovered faces
        for
        (
            label faceI = masterUncoveredPatch.start();
            faceI < masterUncoveredPatch.start() + masterUncoveredPatch.size();
            faceI++
        )
        {
            masterSide[nFaces] = allFaces[faceI];
            nFaces++;
        }
    }

    // Slave side
    const polyPatch& slaveCoveredPatch =
        mesh.boundaryMesh()[slaveCoveredPatchID_.index()];

    const polyPatch& slaveUncoveredPatch =
        mesh.boundaryMesh()[slaveUncoveredPatchID_.index()];

    faceList slaveSide
    (
        slaveCoveredPatch.size()
      + slaveUncoveredPatch.size()
    );

    {
        label nFaces = 0;

        // Insert covered faces
        for
        (
            label faceI = slaveCoveredPatch.start();
            faceI < slaveCoveredPatch.start() + slaveCoveredPatch.size();
            faceI++
        )
        {
            slaveSide[nFaces] = allFaces[faceI];
            nFaces++;
        }

        // Insert uncovered faces
        for
        (
            label faceI = slaveUncoveredPatch.start();
            faceI < slaveUncoveredPatch.start() + slaveUncoveredPatch.size();
            faceI++
        )
        {
            slaveSide[nFaces] = allFaces[faceI];
            nFaces++;
        }
    }

    // Create interpolator
    primitiveFacePatch master(masterSide, allPoints);
    primitiveFacePatch slave(slaveSide, allPoints);

    if
    (
        Pstream::parRun()
     && (
            (masterSide.empty() && !slaveSide.empty())
         || (!masterSide.empty() && slaveSide.empty())
        )
    )
    {
        FatalErrorIn("bool repatchCoverage::changeTopology() const")
            << "Parallel run with partial visibility"
            << abort(FatalError);
    }

    if (masterSide.empty() && slaveSide.empty())
    {
        // Empty master and slave patches.  No local topo change
        return false;
    }

    GGIInterpolation<primitiveFacePatch, primitiveFacePatch> patchToPatch
    (
        master,
        slave,
        tensorField::zero,  // forwardT
        tensorField::zero,  // reverseT
        vectorField::zero   // separation
    );

    // Check uncovered master and slave faces

    // Check uncovered master faces
    // All faces between 0 and masterCoveredPatch.size() - 1 should be covered
    // All faces between masterCoveredPatch.size() - 1 and
    //      uncoveredMaster.size() - 1 should be uncovered
    // If this is not the case, faces should be changed

    // Master side
    label nMasterChanges = 0;

    {
        // Set size of uncovered master mask.  This indicates a topo change
        // is in preparation
        uncMaster_.setSize(master.size(), false);

        const labelList& umf = patchToPatch.uncoveredMasterFaces();

        forAll(umf, umfI)
        {
            uncMaster_[umf[umfI]] = true;
        }

        // Check coverage
        forAll (uncMaster_, mfI)
        {
            if (uncMaster_[mfI] && mfI < masterCoveredPatch.size())
            {
                // Found uncovered master in covered section
                nMasterChanges++;
            }

            if (!uncMaster_[mfI] && mfI >= masterCoveredPatch.size())
            {
                // Found covered master in uncovered section
                nMasterChanges++;
            }
        }
    }

    // Slave side
    label nSlaveChanges = 0;

    {
        // Set size of uncovered master mask.  This indicates a topo change
        // is in preparation
        uncSlave_.setSize(slave.size(), false);

        const labelList& umf = patchToPatch.uncoveredSlaveFaces();

        forAll(umf, umfI)
        {
            uncSlave_[umf[umfI]] = true;
        }

        // Check coverage
        forAll (uncSlave_, mfI)
        {
            if (uncSlave_[mfI] && mfI < slaveCoveredPatch.size())
            {
                // Found uncovered slave in covered section
                nSlaveChanges++;
            }

            if (!uncSlave_[mfI] && mfI >= slaveCoveredPatch.size())
            {
                // Found covered slave in uncovered section
                nSlaveChanges++;
            }
        }
    }

    if (nMasterChanges > 0 || nSlaveChanges > 0)
    {
        InfoIn("bool repatchCoverage::changeTopology() const")
            << "Changing " << nMasterChanges << " master and "
            << nSlaveChanges << " slave faces"
            << endl;

        return true;
    }
    else
    {
        // Clear uncovered masks to indicate that the topological change
        // is not required
        uncMaster_.clear();
        uncSlave_.clear();

        return false;
    }
}
void Foam::slidingInterface::calcAttachedAddressing() const
{
    if (debug)
    {
        Pout<< "void Foam::slidingInterface::calcAttachedAddressing() const "
            << " for object " << name() << " : "
            << "Calculating zone face-cell addressing."
            << endl;
    }

    if (!attached_)
    {
        // Clear existing addressing
        clearAttachedAddressing();

        const polyMesh& mesh = topoChanger().mesh();

        const labelList& own = mesh.faceOwner();
        const labelList& nei = mesh.faceNeighbour();
        const faceZoneMesh& faceZones = mesh.faceZones();

        // Master side

        const primitiveFacePatch& masterPatch =
            faceZones[masterFaceZoneID_.index()]();

        const labelList& masterPatchFaces =
            faceZones[masterFaceZoneID_.index()];

        const boolList& masterFlip =
            faceZones[masterFaceZoneID_.index()].flipMap();

        masterFaceCellsPtr_ = new labelList(masterPatchFaces.size());
        labelList& mfc = *masterFaceCellsPtr_;

        forAll (masterPatchFaces, faceI)
        {
            if (masterFlip[faceI])
            {
                mfc[faceI] = nei[masterPatchFaces[faceI]];
            }
            else
            {
                mfc[faceI] = own[masterPatchFaces[faceI]];
            }
        }

        // Slave side

        const primitiveFacePatch& slavePatch =
            faceZones[slaveFaceZoneID_.index()]();

        const labelList& slavePatchFaces =
            faceZones[slaveFaceZoneID_.index()];

        const boolList& slaveFlip =
            faceZones[slaveFaceZoneID_.index()].flipMap();

        slaveFaceCellsPtr_ = new labelList(slavePatchFaces.size());
        labelList& sfc = *slaveFaceCellsPtr_;

        forAll (slavePatchFaces, faceI)
        {
            if (slaveFlip[faceI])
            {
                sfc[faceI] = nei[slavePatchFaces[faceI]];
            }
            else
            {
                sfc[faceI] = own[slavePatchFaces[faceI]];
            }
        }

        // Check that the addressing is valid
        if (min(mfc) < 0 || min(sfc) < 0)
        {
            if (debug)
            {
                forAll (mfc, faceI)
                {
                    if (mfc[faceI] < 0)
                    {
                        Pout << "No cell next to master patch face " << faceI
                            << ".  Global face no: " << mfc[faceI]
                            << " own: " << own[masterPatchFaces[faceI]]
                            << " nei: " << nei[masterPatchFaces[faceI]]
                            << " flip: " << masterFlip[faceI] << endl;
                    }
                }

                forAll (sfc, faceI)
                {
                    if (sfc[faceI] < 0)
                    {
                        Pout << "No cell next to slave patch face " << faceI
                            << ".  Global face no: " << sfc[faceI]
                            << " own: " << own[slavePatchFaces[faceI]]
                            << " nei: " << nei[slavePatchFaces[faceI]]
                            << " flip: " << slaveFlip[faceI] << endl;
                    }
                }
            }

            FatalErrorIn
            (
                "void slidingInterface::calcAttachedAddressing()"
                "const"
            )   << "Error is zone face-cell addressing.  Probable error in "
                << "decoupled mesh or sliding interface definition."
                << abort(FatalError);
        }

        // Calculate stick-out faces
        const labelListList& pointFaces = mesh.pointFaces();

        // Master side
        labelHashSet masterStickOutFaceMap
        (
            primitiveMesh::facesPerCell_*(masterPatch.size())
        );

        const labelList& masterMeshPoints = masterPatch.meshPoints();

        forAll (masterMeshPoints, pointI)
        {
            const labelList& curFaces = pointFaces[masterMeshPoints[pointI]];

            forAll (curFaces, faceI)
            {
                // Check if the face belongs to the master face zone;
                // if not add it
                if
                (
                    faceZones.whichZone(curFaces[faceI])
                 != masterFaceZoneID_.index()
                )
                {
                    masterStickOutFaceMap.insert(curFaces[faceI]);
                }
            }
        }

        masterStickOutFacesPtr_ = new labelList(masterStickOutFaceMap.toc());

        // Slave side
        labelHashSet slaveStickOutFaceMap
        (
            primitiveMesh::facesPerCell_*(slavePatch.size())
        );

        const labelList& slaveMeshPoints = slavePatch.meshPoints();

        forAll (slaveMeshPoints, pointI)
        {
            const labelList& curFaces = pointFaces[slaveMeshPoints[pointI]];

            forAll (curFaces, faceI)
            {
                // Check if the face belongs to the slave face zone;
                // if not add it
                if
                (
                    faceZones.whichZone(curFaces[faceI])
                 != slaveFaceZoneID_.index()
                )
                {
                    slaveStickOutFaceMap.insert(curFaces[faceI]);
                }
            }
        }

        slaveStickOutFacesPtr_ = new labelList(slaveStickOutFaceMap.toc());


        // Retired point addressing does not exist at this stage.
        // It will be filled when the interface is coupled.
        retiredPointMapPtr_ =
            new Map<label>
            (
                2*faceZones[slaveFaceZoneID_.index()]().nPoints()
            );

        // Ditto for cut point edge map.  This is a rough guess of its size
        //
        cutPointEdgePairMapPtr_ =
            new Map<Pair<edge> >
            (
                faceZones[slaveFaceZoneID_.index()]().nEdges()
            );
    }
void Foam::repatchCoverage::setRefinement(polyTopoChange& ref) const
{
    // Get mesh reference
    const polyMesh& mesh = topoChanger().mesh();

    const faceList& allFaces = mesh.allFaces();
    const faceZoneMesh& faceZones = mesh.faceZones();

    const labelList& owner = mesh.faceOwner();

    // Master side
    {
        // Get master patches

        const polyPatch& masterCoveredPatch =
            mesh.boundaryMesh()[masterCoveredPatchID_.index()];

        const label cStart = masterCoveredPatch.start();
        const label cSize = masterCoveredPatch.size();

        const polyPatch& masterUncoveredPatch =
            mesh.boundaryMesh()[masterUncoveredPatchID_.index()];

        const label uncStart = masterUncoveredPatch.start();

        // Adjust coverage
        forAll (uncMaster_, faceI)
        {
            if (uncMaster_[faceI] && faceI < masterCoveredPatch.size())
            {
                // Found uncovered face in covered section

                // Get face index
                const label faceIndex = cStart + faceI;

                // Find zone index
                const label faceZoneIndex = faceZones.whichZone(faceIndex);

                // Face flip
                bool faceZoneFlip = false;

                if (faceZoneIndex > -1)
                {
                    // Find face in zone
                    const label fizIndex =
                        faceZones[faceZoneIndex].whichFace(faceIndex);

                    faceZoneFlip =
                        faceZones[faceZoneIndex].flipMap()[fizIndex];
                }

                // Found uncovered master in covered section
                // Move to uncovered patch
                ref.setAction
                (
                    polyModifyFace
                    (
                        allFaces[faceIndex],             // modified face
                        faceIndex,                       // modified face index
                        owner[faceIndex],                // owner
                        -1,                              // neighbour
                        false,                           // face flip
                        masterUncoveredPatch.index(),    // patch for face
                        false,                           // remove from zone
                        faceZoneIndex,                   // zone for face
                        faceZoneFlip                     // face flip in zone
                    )
                );
            }

            if (!uncMaster_[faceI] && faceI >= masterCoveredPatch.size())
            {
                // Found covered face in uncovered section

                // Get face index
                const label faceIndex = uncStart - cSize + faceI;

                // Find zone index
                const label faceZoneIndex = faceZones.whichZone(faceIndex);

                // Face flip
                bool faceZoneFlip = false;

                if (faceZoneIndex > -1)
                {
                    // Find face in zone
                    const label fizIndex =
                        faceZones[faceZoneIndex].whichFace(faceIndex);

                    faceZoneFlip =
                        faceZones[faceZoneIndex].flipMap()[fizIndex];
                }

                // Found uncovered master in covered section
                // Move to uncovered patch
                ref.setAction
                (
                    polyModifyFace
                    (
                        allFaces[faceIndex],             // modified face
                        faceIndex,                       // modified face index
                        owner[faceIndex],                // owner
                        -1,                              // neighbour
                        false,                           // face flip
                        masterCoveredPatch.index(),      // patch for face
                        false,                           // remove from zone
                        faceZoneIndex,                   // zone for face
                        faceZoneFlip                     // face flip in zone
                    )
                );
            }
        }
    }

    {
        // Get slave patches

        const polyPatch& slaveCoveredPatch =
            mesh.boundaryMesh()[slaveCoveredPatchID_.index()];

        const label cStart = slaveCoveredPatch.start();
        const label cSize = slaveCoveredPatch.size();

        const polyPatch& slaveUncoveredPatch =
            mesh.boundaryMesh()[slaveUncoveredPatchID_.index()];

        const label uncStart = slaveUncoveredPatch.start();

        // Check coverage
        forAll (uncSlave_, faceI)
        {
            if (uncSlave_[faceI] && faceI < slaveCoveredPatch.size())
            {
                // Found uncovered face in covered section

                // Get face index
                const label faceIndex = cStart + faceI;

                // Find zone index
                const label faceZoneIndex = faceZones.whichZone(faceIndex);

                // Face flip
                bool faceZoneFlip = false;

                if (faceZoneIndex > -1)
                {
                    // Find face in zone
                    const label fizIndex =
                        faceZones[faceZoneIndex].whichFace(faceIndex);

                    faceZoneFlip =
                        faceZones[faceZoneIndex].flipMap()[fizIndex];
                }

                // Found uncovered slave in covered section
                // Move to uncovered patch
                ref.setAction
                (
                    polyModifyFace
                    (
                        allFaces[faceIndex],             // modified face
                        faceIndex,                       // modified face index
                        owner[faceIndex],                // owner
                        -1,                              // neighbour
                        false,                           // face flip
                        slaveUncoveredPatch.index(),    // patch for face
                        false,                           // remove from zone
                        faceZoneIndex,                   // zone for face
                        faceZoneFlip                     // face flip in zone
                    )
                );
            }

            if (!uncSlave_[faceI] && faceI >= slaveCoveredPatch.size())
            {
                // Found covered face in uncovered section

                // Get face index
                const label faceIndex = uncStart - cSize + faceI;

                // Find zone index
                const label faceZoneIndex = faceZones.whichZone(faceIndex);

                // Face flip
                bool faceZoneFlip = false;

                if (faceZoneIndex > -1)
                {
                    // Find face in zone
                    const label fizIndex =
                        faceZones[faceZoneIndex].whichFace(faceIndex);

                    faceZoneFlip =
                        faceZones[faceZoneIndex].flipMap()[fizIndex];
                }

                // Found uncovered slave in covered section
                // Move to uncovered patch
                ref.setAction
                (
                    polyModifyFace
                    (
                        allFaces[faceIndex],             // modified face
                        faceIndex,                       // modified face index
                        owner[faceIndex],                // owner
                        -1,                              // neighbour
                        false,                           // face flip
                        slaveCoveredPatch.index(),      // patch for face
                        false,                           // remove from zone
                        faceZoneIndex,                   // zone for face
                        faceZoneFlip                     // face flip in zone
                    )
                );
            }
        }
    }


    // Clear uncovered masks to indicate that the topological change
    // has been performed
    uncMaster_.clear();
    uncSlave_.clear();
}
void Foam::attachDetach::detachInterface
(
    polyTopoChange& ref
) const
{
    // Algorithm:
    // 1. Create new points for points of the master face zone
    // 2. Modify all faces of the master zone, by putting them into the master
    //    patch (look for orientation) and their renumbered mirror images
    //    into the slave patch
    // 3. Create a point renumbering list, giving a new point index for original
    //    points in the face patch
    // 4. Grab all faces in cells on the master side and renumber them 
    //    using the point renumbering list.  Exclude the ones that belong to
    //    the master face zone
    //
    // Note on point creation:
    // In order to take into account the issues related to partial
    // blocking in an attach/detach mesh modifier, special treatment
    // is required for the duplication of points on the edge of the
    // face zone.  Points which are shared only by internal edges need
    // not to be duplicated, as this would propagate the discontinuity
    // in the mesh beyond the face zone.  Therefore, before creating
    // the new points, check the external edge loop.  For each edge
    // check if the edge is internal (i.e. does not belong to a
    // patch); if so, exclude both of its points from duplication.

    if (debug)
    {
        Pout<< "void attachDetach::detachInterface("
            << "polyTopoChange& ref) const "
            << " for object " << name() << " : "
            << "Detaching interface" << endl;
    }

    const polyMesh& mesh = topoChanger().mesh();
    const faceZoneMesh& zoneMesh = mesh.faceZones();

    const primitiveFacePatch& masterFaceLayer = zoneMesh[faceZoneID_.index()]();
    const pointField& points = mesh.points();
    const labelListList& meshEdgeFaces = mesh.edgeFaces();

    const labelList& mp = masterFaceLayer.meshPoints();
    const edgeList& zoneLocalEdges = masterFaceLayer.edges();

    const labelList& meshEdges = zoneMesh[faceZoneID_.index()].meshEdges();

    // Create the points

    labelList addedPoints(mp.size(), -1);

    // Go through boundary edges of the master patch.  If all the faces from
    // this patch are internal, mark the points in the addedPoints lookup
    // with their original labels to stop duplication
    label nIntEdges = masterFaceLayer.nInternalEdges();

    for (label curEdgeID = nIntEdges; curEdgeID < meshEdges.size(); curEdgeID++)
    {
        const labelList& curFaces = meshEdgeFaces[meshEdges[curEdgeID]];

        bool edgeIsInternal = true;

        forAll (curFaces, faceI)
        {
            if (!mesh.isInternalFace(curFaces[faceI]))
            {
                // The edge belongs to a boundary face
                edgeIsInternal = false;
                break;
            }
        }

        if (edgeIsInternal)
        {
// Pout<< "Internal edge found: (" << mp[zoneLocalEdges[curEdgeID].start()] << " " << mp[zoneLocalEdges[curEdgeID].end()] << ")" << endl;

            // Reset the point creation
            addedPoints[zoneLocalEdges[curEdgeID].start()] =
                mp[zoneLocalEdges[curEdgeID].start()];

            addedPoints[zoneLocalEdges[curEdgeID].end()] =
                mp[zoneLocalEdges[curEdgeID].end()];
        }
    }
// Pout << "addedPoints before point creation: " << addedPoints << endl;

    // Create new points for face zone
    forAll (addedPoints, pointI)
    {
        if (addedPoints[pointI] < 0)
        {
            addedPoints[pointI] =
                ref.setAction
                (
                    polyAddPoint
                    (
                        points[mp[pointI]],        // point
                        mp[pointI],                // master point
                        -1,                        // zone ID
                        true                       // supports a cell
                    )
                );
// Pout << "Adding point " << points[mp[pointI]] << " for original point " << mp[pointI] << endl;
        }
    }

    // Modify faces in the master zone and duplicate for the slave zone

    const labelList& mf = zoneMesh[faceZoneID_.index()];
    const boolList& mfFlip = zoneMesh[faceZoneID_.index()].flipMap();
    const faceList& zoneFaces = masterFaceLayer.localFaces();

    const faceList& faces = mesh.faces();
    const labelList& own = mesh.faceOwner();
    const labelList& nei = mesh.faceNeighbour();

    forAll (mf, faceI)
    {
        const label curFaceID = mf[faceI];

        // Build the face for the slave patch by renumbering
        const face oldFace = zoneFaces[faceI].reverseFace();

        face newFace(oldFace.size());

        forAll (oldFace, pointI)
        {
            newFace[pointI] = addedPoints[oldFace[pointI]];
        }

        if (mfFlip[faceI])
        {
            // Face needs to be flipped for the master patch
            // No need to check for nei index: internal face.  HJ, 16/Dec/2008
            ref.setAction
            (
                polyModifyFace
                (
                    faces[curFaceID].reverseFace(), // modified face
                    curFaceID,                   // label of face being modified
                    nei[curFaceID],                 // owner
                    -1,                             // neighbour
                    true,                           // face flip
                    masterPatchID_.index(),         // patch for face
                    false,                          // remove from zone
                    faceZoneID_.index(),            // zone for face
                    !mfFlip[faceI]                  // face flip in zone
                )
            );

            // Add renumbered face into the slave patch
            ref.setAction
            (
                polyAddFace
                (
                    newFace,                        // face
                    own[curFaceID],                 // owner
                    -1,                             // neighbour
                    -1,                             // master point
                    -1,                             // master edge
                    curFaceID,                      // master face
                    false,                          // flip flux
                    slavePatchID_.index(),          // patch to add the face to
                    -1,                             // zone for face
                    false                           // zone flip
                )
            );
// Pout << "Flip.  Modifying face: " << faces[curFaceID].reverseFace() << " next to cell: " << nei[curFaceID] << " and adding face: " << newFace << " next to cell: " << own[curFaceID] << endl;
        }
        else
        {
            // No flip
            ref.setAction
            (
                polyModifyFace
                (
                    faces[curFaceID],         // modified face
                    curFaceID,                // label of face being modified
                    own[curFaceID],           // owner
                    -1,                       // neighbour
                    false,                    // face flip
                    masterPatchID_.index(),   // patch for face
                    false,                    // remove from zone
                    faceZoneID_.index(),      // zone for face
                    mfFlip[faceI]             // face flip in zone
                )
            );

            // Add renumbered face into the slave patch
            // No need to check for nei index: internal face.  HJ, 16/Dec/2008
            ref.setAction
            (
                polyAddFace
                (
                    newFace,                        // face
                    nei[curFaceID],                 // owner
                    -1,                             // neighbour
                    -1,                             // master point
                    -1,                             // master edge
                    curFaceID,                      // master face
                    true,                           // flip flux
                    slavePatchID_.index(),          // patch to add the face to
                    -1,                             // zone for face
                    false                           // face flip in zone
                )
            );
// Pout << "No flip.  Modifying face: " << faces[curFaceID] << " next to cell: " << own[curFaceID] << " and adding face: " << newFace << " next to cell: " << nei[curFaceID] << endl;
        }
    }

    // Modify the remaining faces of the master cells to reconnect to the new
    // layer of faces.

    // Algorithm: Go through all the cells of the master zone and make
    // a map of faces to avoid duplicates.  Do not insert the faces in
    // the master patch (as they have already been dealt with).  Make
    // a master layer point renumbering map, which for every point in
    // the master layer gives its new label. Loop through all faces in
    // the map and attempt to renumber them using the master layer
    // point renumbering map.  Once the face is renumbered, compare it
    // with the original face; if they are the same, the face has not
    // changed; if not, modify the face but keep all of its old
    // attributes (apart from the vertex numbers).

    // Create the map of faces in the master cell layer
    const labelList& mc =
        mesh.faceZones()[faceZoneID_.index()].masterCells();

    labelHashSet masterCellFaceMap(6*mc.size());

    const cellList& cells = mesh.cells();

    forAll (mc, cellI)
    {
        const labelList& curFaces = cells[mc[cellI]];

        forAll (curFaces, faceI)
        {
            // Check if the face belongs to the master patch; if not add it
            if (zoneMesh.whichZone(curFaces[faceI]) != faceZoneID_.index())
            {
                masterCellFaceMap.insert(curFaces[faceI]);
            }
        }
    }

    // Extend the map to include first neighbours of the master cells to
    // deal with multiple corners.
    { // Protection and memory management
        // Make a map of master cells for quick reject
        labelHashSet mcMap(2*mc.size());

        forAll (mc, mcI)
        {
            mcMap.insert(mc[mcI]);
        }

        // Go through all the faces in the masterCellFaceMap.  If the
        // cells around them are not already used, add all of their
        // faces to the map
        const labelList mcf = masterCellFaceMap.toc();

        forAll (mcf, mcfI)
        {
            // Do the owner side
            const label ownCell = own[mcf[mcfI]];

            if (!mcMap.found(ownCell))
            {
                // Cell not found. Add its faces to the map
                const cell& curFaces = cells[ownCell];

                forAll (curFaces, faceI)
                {
                    masterCellFaceMap.insert(curFaces[faceI]);
                }
            }

            // Do the neighbour side if face is internal
            if (mesh.isInternalFace(mcf[mcfI]))
            {
                const label neiCell = nei[mcf[mcfI]];

                if (!mcMap.found(neiCell))
                {
                    // Cell not found. Add its faces to the map
                    const cell& curFaces = cells[neiCell];

                    forAll (curFaces, faceI)
                    {
                        masterCellFaceMap.insert(curFaces[faceI]);
                    }
                }
            }