From 27d420983963b50e58c6d952bb365eed2995bb2a Mon Sep 17 00:00:00 2001
From: mattijs <mattijs>
Date: Mon, 17 Oct 2011 18:31:41 +0100
Subject: [PATCH] ENH: PatchEdgeFaceWave: new wave method

---
 .../test/PatchEdgeFaceWave/Make/files         |   3 +
 .../test/PatchEdgeFaceWave/Make/options       |   7 +
 .../Test-PatchEdgeFaceWave.C                  | 132 ++++
 .../polyMesh/globalMeshData/globalMeshData.C  | 147 ++++
 .../polyMesh/globalMeshData/globalMeshData.H  |   7 +
 .../primitiveMesh/PatchTools/PatchTools.C     |   1 +
 .../primitiveMesh/PatchTools/PatchTools.H     |  51 ++
 .../PatchTools/PatchToolsMatch.C              | 137 ++++
 src/meshTools/Make/files                      |   9 +-
 .../PatchEdgeFaceWave/PatchEdgeFaceWave.C     | 681 ++++++++++++++++++
 .../PatchEdgeFaceWave/PatchEdgeFaceWave.H     | 368 ++++++++++
 .../PatchEdgeFaceWave/PatchEdgeFaceWaveName.C |  32 +
 .../PatchEdgeFaceWave/patchEdgeFaceInfo.C     |  50 ++
 .../PatchEdgeFaceWave/patchEdgeFaceInfo.H     | 212 ++++++
 .../PatchEdgeFaceWave/patchEdgeFaceInfoI.H    | 268 +++++++
 15 files changed, 2103 insertions(+), 2 deletions(-)
 create mode 100644 applications/test/PatchEdgeFaceWave/Make/files
 create mode 100644 applications/test/PatchEdgeFaceWave/Make/options
 create mode 100644 applications/test/PatchEdgeFaceWave/Test-PatchEdgeFaceWave.C
 create mode 100644 src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsMatch.C
 create mode 100644 src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWave.C
 create mode 100644 src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWave.H
 create mode 100644 src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWaveName.C
 create mode 100644 src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfo.C
 create mode 100644 src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfo.H
 create mode 100644 src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfoI.H

diff --git a/applications/test/PatchEdgeFaceWave/Make/files b/applications/test/PatchEdgeFaceWave/Make/files
new file mode 100644
index 00000000000..01051a35533
--- /dev/null
+++ b/applications/test/PatchEdgeFaceWave/Make/files
@@ -0,0 +1,3 @@
+Test-PatchEdgeFaceWave.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-PatchEdgeFaceWave
diff --git a/applications/test/PatchEdgeFaceWave/Make/options b/applications/test/PatchEdgeFaceWave/Make/options
new file mode 100644
index 00000000000..d27c95d033d
--- /dev/null
+++ b/applications/test/PatchEdgeFaceWave/Make/options
@@ -0,0 +1,7 @@
+EXE_INC = \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude
+
+EXE_LIBS = \
+    -lfiniteVolume \
+    -lmeshTools
diff --git a/applications/test/PatchEdgeFaceWave/Test-PatchEdgeFaceWave.C b/applications/test/PatchEdgeFaceWave/Test-PatchEdgeFaceWave.C
new file mode 100644
index 00000000000..2dfb19118b2
--- /dev/null
+++ b/applications/test/PatchEdgeFaceWave/Test-PatchEdgeFaceWave.C
@@ -0,0 +1,132 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Description
+    Test PatchEdgeFaceWave.
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "fvMesh.H"
+#include "volFields.H"
+#include "PatchEdgeFaceWave.H"
+#include "patchEdgeFaceInfo.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+int main(int argc, char *argv[])
+{
+    argList::validArgs.append("patch");
+
+#   include "setRootCase.H"
+#   include "createTime.H"
+#   include "createMesh.H"
+
+    const polyBoundaryMesh& patches = mesh.boundaryMesh();
+
+    // Get name of patch
+    const word patchName = args[1];
+
+    const polyPatch& patch = patches[patchName];
+
+    // Data on all edges and faces
+    List<patchEdgeFaceInfo> allEdgeInfo(patch.nEdges());
+    List<patchEdgeFaceInfo> allFaceInfo(patch.size());
+
+    // Initial seed
+    DynamicList<label> initialEdges;
+    DynamicList<patchEdgeFaceInfo> initialEdgesInfo;
+
+
+    // Just set an edge on the master
+    if (Pstream::master())
+    {
+        label edgeI = 0;
+        Info<< "Starting walk on edge " << edgeI << endl;
+
+        initialEdges.append(edgeI);
+        const edge& e = patch.edges()[edgeI];
+        initialEdgesInfo.append
+        (
+            patchEdgeFaceInfo
+            (
+                e.centre(patch.localPoints()),
+                0.0
+            )
+        );
+    }
+
+
+    // Walk
+    PatchEdgeFaceWave
+    <
+        primitivePatch,
+        patchEdgeFaceInfo
+    > calc
+    (
+        mesh,
+        patch,
+        initialEdges,
+        initialEdgesInfo,
+        allEdgeInfo,
+        allFaceInfo,
+        returnReduce(patch.nEdges(), sumOp<label>())
+    );
+
+
+    // Extract as patchField
+    volScalarField vsf
+    (
+        IOobject
+        (
+            "patchDist",
+            runTime.timeName(),
+            mesh,
+            IOobject::NO_READ,
+            IOobject::AUTO_WRITE
+        ),
+        mesh,
+        dimensionedScalar("patchDist", dimLength, 0.0)
+    );
+    scalarField pf(vsf.boundaryField()[patch.index()].size());
+    forAll(pf, faceI)
+    {
+        pf[faceI] = Foam::sqrt(allFaceInfo[faceI].distSqr());
+    }
+    vsf.boundaryField()[patch.index()] = pf;
+
+    Info<< "Writing patchDist volScalarField to " << runTime.value()
+        << endl;
+
+    vsf.write();
+
+
+    Info<< "\nEnd\n" << endl;
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C
index 9800ba6006d..d1b4926e763 100644
--- a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C
+++ b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C
@@ -46,6 +46,20 @@ defineTypeNameAndDebug(Foam::globalMeshData, 0);
 // Geometric matching tolerance. Factor of mesh bounding box.
 const Foam::scalar Foam::globalMeshData::matchTol_ = 1E-8;
 
+namespace Foam
+{
+template<>
+class minEqOp<labelPair>
+{
+public:
+    void operator()(labelPair& x, const labelPair& y) const
+    {
+        x[0] = min(x[0], y[0]);
+        x[1] = min(x[1], y[1]);
+    }
+};
+}
+
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -1063,6 +1077,128 @@ void Foam::globalMeshData::calcGlobalEdgeSlaves() const
 }
 
 
+void Foam::globalMeshData::calcGlobalEdgeOrientation() const
+{
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalEdgeOrientation() :"
+            << " calculating edge orientation w.r.t. master edge." << endl;
+    }
+
+    const globalIndex& globalPoints = globalPointNumbering();
+
+    // 1. Determine master point
+    labelList masterPoint;
+    {
+        const mapDistribute& map = globalPointSlavesMap();
+
+        masterPoint.setSize(map.constructSize());
+        masterPoint = labelMax;
+
+        for (label pointI = 0; pointI < coupledPatch().nPoints(); pointI++)
+        {
+            masterPoint[pointI] = globalPoints.toGlobal(pointI);
+        }
+        syncData
+        (
+            masterPoint,
+            globalPointSlaves(),
+            globalPointTransformedSlaves(),
+            map,
+            minEqOp<label>()
+        );
+    }
+
+    // Now all points should know who is master by comparing their global
+    // pointID with the masterPointID. We now can use this information
+    // to find the orientation of the master edge.
+
+    {
+        const mapDistribute& map = globalEdgeSlavesMap();
+        const labelListList& slaves = globalEdgeSlaves();
+        const labelListList& transformedSlaves = globalEdgeTransformedSlaves();
+
+        // Distribute orientation of master edge (in masterPoint numbering)
+        labelPairList masterEdgeVerts(map.constructSize());
+        masterEdgeVerts = labelPair(labelMax, labelMax);
+
+        for (label edgeI = 0; edgeI < coupledPatch().nEdges(); edgeI++)
+        {
+            if
+            (
+                (
+                    slaves[edgeI].size()
+                  + transformedSlaves[edgeI].size()
+                )
+              > 0
+            )
+            {
+                // I am master. Fill in my masterPoint equivalent.
+
+                const edge& e = coupledPatch().edges()[edgeI];
+                masterEdgeVerts[edgeI] = labelPair
+                (
+                    masterPoint[e[0]],
+                    masterPoint[e[1]]
+                );
+            }
+        }
+        syncData
+        (
+            masterEdgeVerts,
+            slaves,
+            transformedSlaves,
+            map,
+            minEqOp<labelPair>()
+        );
+
+        // Now check my edges on how they relate to the master's edgeVerts
+        globalEdgeOrientationPtr_.reset
+        (
+            new PackedBoolList(coupledPatch().nEdges())
+        );
+        PackedBoolList& globalEdgeOrientation = globalEdgeOrientationPtr_();
+
+        forAll(coupledPatch().edges(), edgeI)
+        {
+            const edge& e = coupledPatch().edges()[edgeI];
+            const labelPair masterE
+            (
+                masterPoint[e[0]],
+                masterPoint[e[1]]
+            );
+
+            label stat = labelPair::compare
+            (
+                masterE,
+                masterEdgeVerts[edgeI]
+            );
+            if (stat == 0)
+            {
+                FatalErrorIn
+                (
+                    "globalMeshData::calcGlobalEdgeOrientation() const"
+                )   << "problem : my edge:" << e
+                    << " in master points:" << masterE
+                    << " v.s. masterEdgeVerts:" << masterEdgeVerts[edgeI]
+                    << exit(FatalError);
+            }
+            else
+            {
+                globalEdgeOrientation[edgeI] = (stat == 1);
+            }
+        }
+    }
+
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalEdgeOrientation() :"
+            << " finished calculating edge orientation."
+            << endl;
+    }
+}
+
+
 // Calculate uncoupled boundary faces (without calculating
 // primitiveMesh::pointFaces())
 void Foam::globalMeshData::calcPointBoundaryFaces
@@ -1660,6 +1796,7 @@ void Foam::globalMeshData::clearOut()
     globalEdgeNumberingPtr_.clear();
     globalEdgeSlavesPtr_.clear();
     globalEdgeTransformedSlavesPtr_.clear();
+    globalEdgeOrientationPtr_.clear();
     globalEdgeSlavesMapPtr_.clear();
 
     // Face
@@ -2095,6 +2232,16 @@ const
 }
 
 
+const Foam::PackedBoolList& Foam::globalMeshData::globalEdgeOrientation() const
+{
+    if (!globalEdgeOrientationPtr_.valid())
+    {
+        calcGlobalEdgeOrientation();
+    }
+    return globalEdgeOrientationPtr_();
+}
+
+
 const Foam::mapDistribute& Foam::globalMeshData::globalEdgeSlavesMap() const
 {
     if (!globalEdgeSlavesMapPtr_.valid())
diff --git a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H
index 3fca52ae976..a3530dc86c3 100644
--- a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H
+++ b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H
@@ -95,6 +95,7 @@ class mapDistribute;
 template<class T> class EdgeMap;
 class globalIndex;
 class globalIndexAndTransform;
+class PackedBoolList;
 
 /*---------------------------------------------------------------------------*\
                            Class globalMeshData Declaration
@@ -191,6 +192,7 @@ class globalMeshData
             mutable autoPtr<globalIndex> globalEdgeNumberingPtr_;
             mutable autoPtr<labelListList> globalEdgeSlavesPtr_;
             mutable autoPtr<labelListList> globalEdgeTransformedSlavesPtr_;
+            mutable autoPtr<PackedBoolList> globalEdgeOrientationPtr_;
             mutable autoPtr<mapDistribute> globalEdgeSlavesMapPtr_;
 
 
@@ -297,6 +299,9 @@ class globalMeshData
             //- Calculate global edge addressing.
             void calcGlobalEdgeSlaves() const;
 
+            //- Calculate orientation w.r.t. edge master.
+            void calcGlobalEdgeOrientation() const;
+
 
         // Global boundary face/cell addressing
 
@@ -539,6 +544,8 @@ public:
                 const labelListList& globalEdgeSlaves() const;
                 const labelListList& globalEdgeTransformedSlaves() const;
                 const mapDistribute& globalEdgeSlavesMap() const;
+                //- Is my edge same orientation master edge
+                const PackedBoolList& globalEdgeOrientation() const;
 
             // Coupled point to boundary faces. These are uncoupled boundary
             // faces only but include empty patches.
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.C b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.C
index 4a40eac11aa..793411c162a 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.C
+++ b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.C
@@ -30,6 +30,7 @@ License
 #include "PatchToolsSearch.C"
 #include "PatchToolsSortEdges.C"
 #include "PatchToolsNormals.C"
+#include "PatchToolsMatch.C"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.H b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.H
index 80e50333bdf..e4ade383ef3 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.H
+++ b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.H
@@ -36,6 +36,7 @@ SourceFiles
     PatchToolsSearch.C
     PatchToolsSortEdges.C
     PatchToolsNormals.C
+    PatchToolsMatch.C
 
 \*---------------------------------------------------------------------------*/
 
@@ -51,6 +52,7 @@ namespace Foam
 {
 
 class polyMesh;
+class PackedBoolList;
 
 /*---------------------------------------------------------------------------*\
                          Class PatchTools Declaration
@@ -169,6 +171,55 @@ public:
     );
 
 
+    //- Find corresponding points on patches sharing the same points
+    //  p1PointLabels : points on p1 that were matched
+    //  p2PointLabels : corresponding points on p2
+    template
+    <
+        class Face1,
+        template<class> class FaceList1,
+        class PointField1,
+        class PointType1,
+        class Face2,
+        template<class> class FaceList2,
+        class PointField2,
+        class PointType2
+    >
+    static void matchPoints
+    (
+        const PrimitivePatch<Face1, FaceList1, PointField1, PointType1>& p1,
+        const PrimitivePatch<Face2, FaceList2, PointField2, PointType2>& p2,
+
+        labelList& p1PointLabels,
+        labelList& p2PointLabels
+    );
+
+    //- Find corresponding edges on patches sharing the same points
+    //  p1EdgeLabels    : edges on p1 that were matched
+    //  p2EdgeLabels    : corresponding edges on p2
+    //  sameOrientation : same orientation?
+    template
+    <
+        class Face1,
+        template<class> class FaceList1,
+        class PointField1,
+        class PointType1,
+        class Face2,
+        template<class> class FaceList2,
+        class PointField2,
+        class PointType2
+    >
+    static void matchEdges
+    (
+        const PrimitivePatch<Face1, FaceList1, PointField1, PointType1>& p1,
+        const PrimitivePatch<Face2, FaceList2, PointField2, PointType2>& p2,
+
+        labelList& p1EdgeLabels,
+        labelList& p2EdgeLabels,
+        PackedBoolList& sameOrientation
+    );
+
+
     //- Return parallel consistent point normals for patches (on boundary faces)
     //  using mesh points.
     template
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsMatch.C b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsMatch.C
new file mode 100644
index 00000000000..1af68e89912
--- /dev/null
+++ b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsMatch.C
@@ -0,0 +1,137 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "PatchTools.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template
+<
+    class Face1,
+    template<class> class FaceList1,
+    class PointField1,
+    class PointType1,
+    class Face2,
+    template<class> class FaceList2,
+    class PointField2,
+    class PointType2
+>
+void Foam::PatchTools::matchPoints
+(
+    const PrimitivePatch<Face1, FaceList1, PointField1, PointType1>& p1,
+    const PrimitivePatch<Face2, FaceList2, PointField2, PointType2>& p2,
+
+    labelList& p1PointLabels,
+    labelList& p2PointLabels
+)
+{
+    p1PointLabels.setSize(p1.nPoints());
+    p2PointLabels.setSize(p1.nPoints());
+
+    label nMatches = 0;
+
+    forAll(p1.meshPoints(), pointI)
+    {
+        label meshPointI = p1.meshPoints()[pointI];
+
+        Map<label>::const_iterator iter = p2.meshPointMap().find
+        (
+            meshPointI
+        );
+
+        if (iter != p2.meshPointMap().end())
+        {
+            p1PointLabels[nMatches] = pointI;
+            p2PointLabels[nMatches] = iter();
+            nMatches++;
+        }
+    }
+    p1PointLabels.setSize(nMatches);
+    p2PointLabels.setSize(nMatches);
+}
+
+
+template
+<
+    class Face1,
+    template<class> class FaceList1,
+    class PointField1,
+    class PointType1,
+    class Face2,
+    template<class> class FaceList2,
+    class PointField2,
+    class PointType2
+>
+void Foam::PatchTools::matchEdges
+(
+    const PrimitivePatch<Face1, FaceList1, PointField1, PointType1>& p1,
+    const PrimitivePatch<Face2, FaceList2, PointField2, PointType2>& p2,
+
+    labelList& p1EdgeLabels,
+    labelList& p2EdgeLabels,
+    PackedBoolList& sameOrientation
+)
+{
+    p1EdgeLabels.setSize(p1.nEdges());
+    p2EdgeLabels.setSize(p1.nEdges());
+    sameOrientation.setSize(p1.nEdges());
+    sameOrientation = 0;
+
+    label nMatches = 0;
+
+    EdgeMap<label> edgeToIndex(2*p1.nEdges());
+    forAll(p1.edges(), edgeI)
+    {
+        const edge& e = p1.edges()[edgeI];
+        const edge meshE
+        (
+            p1.meshPoints()[e[0]],
+            p1.meshPoints()[e[1]]
+        );
+        edgeToIndex.insert(meshE, edgeI);
+    }
+
+    forAll(p2.edges(), edgeI)
+    {
+        const edge& e = p2.edges()[edgeI];
+        const edge meshE(p2.meshPoints()[e[0]], p2.meshPoints()[e[1]]);
+
+        EdgeMap<label>::const_iterator iter = edgeToIndex.find(meshE);
+
+        if (iter != edgeToIndex.end())
+        {
+            p1EdgeLabels[nMatches] = iter();
+            p2EdgeLabels[nMatches] = edgeI;
+            sameOrientation[nMatches] = (meshE[0] == iter.key()[0]);
+            nMatches++;
+        }
+    }
+    p1EdgeLabels.setSize(nMatches);
+    p2EdgeLabels.setSize(nMatches);
+    sameOrientation.setSize(nMatches);
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/Make/files b/src/meshTools/Make/files
index 51be5477869..1c981f47887 100644
--- a/src/meshTools/Make/files
+++ b/src/meshTools/Make/files
@@ -30,8 +30,13 @@ meshSearch/meshSearch.C
 
 meshTools/meshTools.C
 
-PointEdgeWave/PointEdgeWaveName.C
-PointEdgeWave/pointEdgePoint.C
+pWave = PointEdgeWave
+$(pWave)/PointEdgeWaveName.C
+$(pWave)/pointEdgePoint.C
+
+patchWave = PatchEdgeFaceWave
+$(patchWave)/PatchEdgeFaceWaveName.C
+$(patchWave)/patchEdgeFaceInfo.C
 
 regionSplit/regionSplit.C
 
diff --git a/src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWave.C b/src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWave.C
new file mode 100644
index 00000000000..129d82ae12b
--- /dev/null
+++ b/src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWave.C
@@ -0,0 +1,681 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2004-2010 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "PatchEdgeFaceWave.H"
+#include "polyMesh.H"
+#include "globalMeshData.H"
+#include "PatchTools.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+Foam::scalar Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+propagationTol_ = 0.01;
+
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+Foam::label
+Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+dummyTrackData_ = 12345;
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+// Update info for edgeI, at position pt, with information from
+// neighbouring face.
+// Updates:
+//      - changedEdge_, changedEdges_,
+//      - statistics: nEvals_, nUnvisitedEdges_
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+bool Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+updateEdge
+(
+    const label edgeI,
+    const label neighbourFaceI,
+    const Type& neighbourInfo,
+    Type& edgeInfo
+)
+{
+    nEvals_++;
+
+    bool wasValid = edgeInfo.valid(td_);
+
+    bool propagate =
+        edgeInfo.updateEdge
+        (
+            mesh_,
+            patch_,
+            edgeI,
+            neighbourFaceI,
+            neighbourInfo,
+            propagationTol_,
+            td_
+        );
+
+    if (propagate)
+    {
+        if (!changedEdge_[edgeI])
+        {
+            changedEdge_[edgeI] = true;
+            changedEdges_.append(edgeI);
+        }
+    }
+
+    if (!wasValid && edgeInfo.valid(td_))
+    {
+        --nUnvisitedEdges_;
+    }
+
+    return propagate;
+}
+
+
+// Update info for faceI, at position pt, with information from
+// neighbouring edge.
+// Updates:
+//      - changedFace_, changedFaces_,
+//      - statistics: nEvals_, nUnvisitedFace_
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+bool Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+updateFace
+(
+    const label faceI,
+    const label neighbourEdgeI,
+    const Type& neighbourInfo,
+    Type& faceInfo
+)
+{
+    nEvals_++;
+
+    bool wasValid = faceInfo.valid(td_);
+
+    bool propagate =
+        faceInfo.updateFace
+        (
+            mesh_,
+            patch_,
+            faceI,
+            neighbourEdgeI,
+            neighbourInfo,
+            propagationTol_,
+            td_
+        );
+
+    if (propagate)
+    {
+        if (!changedFace_[faceI])
+        {
+            changedFace_[faceI] = true;
+            changedFaces_.append(faceI);
+        }
+    }
+
+    if (!wasValid && faceInfo.valid(td_))
+    {
+        --nUnvisitedFaces_;
+    }
+
+    return propagate;
+}
+
+
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+void Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+syncEdges()
+{
+    const globalMeshData& globalData = mesh_.globalData();
+    const mapDistribute& map = globalData.globalEdgeSlavesMap();
+    const PackedBoolList& cppOrientation = globalData.globalEdgeOrientation();
+
+    // Convert patch-edge data into cpp-edge data
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    //- Construct with all data in consistent orientation
+    List<Type> cppEdgeData(map.constructSize());
+
+    forAll(patchEdges_, i)
+    {
+        label patchEdgeI = patchEdges_[i];
+        label coupledEdgeI = coupledEdges_[i];
+
+        if (changedEdge_[patchEdgeI])
+        {
+            const Type& data = allEdgeInfo_[patchEdgeI];
+
+            // Patch-edge data needs to be converted into coupled-edge data
+            // (optionally flipped) and consistent in orientation with
+            // master of coupled edge (optionally flipped)
+            bool sameOrientation =
+            (
+                sameEdgeOrientation_[i]
+             == cppOrientation[coupledEdgeI]
+            );
+
+            cppEdgeData[coupledEdgeI].updateEdge
+            (
+                mesh_,
+                patch_,
+                data,
+                sameOrientation,
+                propagationTol_,
+                td_
+            );
+        }
+    }
+
+
+    // Synchronise
+    // ~~~~~~~~~~~
+
+    globalData.syncData
+    (
+        cppEdgeData,
+        globalData.globalEdgeSlaves(),
+        globalData.globalEdgeTransformedSlaves(),
+        map,
+        globalData.globalTransforms(),
+        updateOp<PrimitivePatchType, Type, TrackingData>
+        (
+            mesh_,
+            patch_,
+            propagationTol_,
+            td_
+        ),
+        transformOp<PrimitivePatchType, Type, TrackingData>
+        (
+            mesh_,
+            patch_,
+            propagationTol_,
+            td_
+        )
+    );
+
+
+    // Back from cpp-edge to patch-edge data
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    forAll(patchEdges_, i)
+    {
+        label patchEdgeI = patchEdges_[i];
+        label coupledEdgeI = coupledEdges_[i];
+
+        const Type& data = cppEdgeData[coupledEdgeI];
+
+        if (data.valid(td_))
+        {
+            bool sameOrientation =
+            (
+                sameEdgeOrientation_[i]
+             == cppOrientation[coupledEdgeI]
+            );
+
+            allEdgeInfo_[patchEdgeI].updateEdge
+            (
+                mesh_,
+                patch_,
+                data,
+                sameOrientation,
+                propagationTol_,
+                td_
+            );
+
+            if (!changedEdge_[patchEdgeI])
+            {
+                changedEdges_.append(patchEdgeI);
+                changedEdge_[patchEdgeI] = true;
+            }
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Iterate, propagating changedEdgesInfo across patch, until no change (or
+// maxIter reached). Initial edge values specified.
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+PatchEdgeFaceWave
+(
+    const polyMesh& mesh,
+    const PrimitivePatchType& patch,
+    const labelList& changedEdges,
+    const List<Type>& changedEdgesInfo,
+
+    UList<Type>& allEdgeInfo,
+    UList<Type>& allFaceInfo,
+
+    const label maxIter,
+    TrackingData& td
+)
+:
+    mesh_(mesh),
+    patch_(patch),
+    allEdgeInfo_(allEdgeInfo),
+    allFaceInfo_(allFaceInfo),
+    td_(td),
+    changedEdge_(patch_.nEdges()),
+    changedEdges_(patch_.size()),
+    changedFace_(patch_.size()),
+    changedFaces_(patch_.size()),
+    nEvals_(0),
+    nUnvisitedEdges_(patch_.nEdges()),
+    nUnvisitedFaces_(patch_.size())
+{
+    // Calculate addressing between patch_ and mesh.globalData().coupledPatch()
+    // for ease of synchronisation
+    PatchTools::matchEdges
+    (
+        patch_,
+        mesh_.globalData().coupledPatch(),
+
+        patchEdges_,
+        coupledEdges_,
+        sameEdgeOrientation_
+    );
+
+
+    if (allEdgeInfo_.size() != patch_.nEdges())
+    {
+        FatalErrorIn
+        (
+            "PatchEdgeFaceWave<Type, TrackingData>::PatchEdgeFaceWave"
+            "(const polyMesh&, const labelList&, const List<Type>,"
+            " List<Type>&, List<Type>&, const label maxIter)"
+        )   << "size of edgeInfo work array is not equal to the number"
+            << " of edges in the patch" << endl
+            << "    edgeInfo   :" << allEdgeInfo_.size() << endl
+            << "    patch.nEdges:" << patch_.nEdges()
+            << exit(FatalError);
+    }
+    if (allFaceInfo_.size() != patch_.size())
+    {
+        FatalErrorIn
+        (
+            "PatchEdgeFaceWave<Type, TrackingData>::PatchEdgeFaceWave"
+            "(const polyMesh&, const labelList&, const List<Type>,"
+            " List<Type>&, List<Type>&, const label maxIter)"
+        )   << "size of edgeInfo work array is not equal to the number"
+            << " of faces in the patch" << endl
+            << "    faceInfo   :" << allFaceInfo_.size() << endl
+            << "    patch.size:" << patch_.size()
+            << exit(FatalError);
+    }
+
+
+    // Set from initial changed edges data
+    setEdgeInfo(changedEdges, changedEdgesInfo);
+
+    if (debug)
+    {
+        Pout<< "Seed edges                : " << changedEdges_.size() << endl;
+    }
+
+    // Iterate until nothing changes
+    label iter = iterate(maxIter);
+
+    if ((maxIter > 0) && (iter >= maxIter))
+    {
+        FatalErrorIn
+        (
+            "PatchEdgeFaceWave<Type, TrackingData>::PatchEdgeFaceWave"
+            "(const polyMesh&, const labelList&, const List<Type>,"
+            " List<Type>&, List<Type>&, const label maxIter)"
+        )   << "Maximum number of iterations reached. Increase maxIter." << endl
+            << "    maxIter:" << maxIter << endl
+            << "    changedEdges:" << changedEdges_.size() << endl
+            << "    changedFaces:" << changedFaces_.size() << endl
+            << exit(FatalError);
+    }
+}
+
+
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+PatchEdgeFaceWave
+(
+    const polyMesh& mesh,
+    const PrimitivePatchType& patch,
+    UList<Type>& allEdgeInfo,
+    UList<Type>& allFaceInfo,
+    TrackingData& td
+)
+:
+    mesh_(mesh),
+    patch_(patch),
+    allEdgeInfo_(allEdgeInfo),
+    allFaceInfo_(allFaceInfo),
+    td_(td),
+    changedEdge_(patch_.nEdges()),
+    changedEdges_(patch_.nEdges()),
+    changedFace_(patch_.size()),
+    changedFaces_(patch_.size()),
+    nEvals_(0),
+    nUnvisitedEdges_(patch_.nEdges()),
+    nUnvisitedFaces_(patch_.size())
+{
+    // Calculate addressing between patch_ and mesh.globalData().coupledPatch()
+    // for ease of synchronisation
+    PatchTools::matchEdges
+    (
+        patch_,
+        mesh_.globalData().coupledPatch(),
+
+        patchEdges_,
+        coupledEdges_,
+        sameEdgeOrientation_
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+Foam::label Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+getUnsetEdges() const
+{
+    return nUnvisitedEdges_;
+}
+
+
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+Foam::label Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+getUnsetFaces() const
+{
+    return nUnvisitedFaces_;
+}
+
+
+// Copy edge information into member data
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+void Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+setEdgeInfo
+(
+    const labelList& changedEdges,
+    const List<Type>& changedEdgesInfo
+)
+{
+    forAll(changedEdges, changedEdgeI)
+    {
+        label edgeI = changedEdges[changedEdgeI];
+
+        bool wasValid = allEdgeInfo_[edgeI].valid(td_);
+
+        // Copy info for edgeI
+        allEdgeInfo_[edgeI] = changedEdgesInfo[changedEdgeI];
+
+        // Maintain count of unset edges
+        if (!wasValid && allEdgeInfo_[edgeI].valid(td_))
+        {
+            --nUnvisitedEdges_;
+        }
+
+        // Mark edgeI as changed, both on list and on edge itself.
+
+        if (!changedEdge_[edgeI])
+        {
+            changedEdge_[edgeI] = true;
+            changedEdges_.append(edgeI);
+        }
+    }
+}
+
+
+// Propagate information from face to edge. Return number of edges changed.
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+Foam::label Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+faceToEdge()
+{
+    changedEdges_.clear();
+    changedEdge_ = false;
+
+    forAll(changedFaces_, changedFaceI)
+    {
+        label faceI = changedFaces_[changedFaceI];
+
+        if (!changedFace_[faceI])
+        {
+            FatalErrorIn("PatchEdgeFaceWave<Type, TrackingData>::faceToEdge()")
+                << "face " << faceI
+                << " not marked as having been changed" << nl
+                << "This might be caused by multiple occurences of the same"
+                << " seed edge." << abort(FatalError);
+        }
+
+        const Type& neighbourWallInfo = allFaceInfo_[faceI];
+
+        // Evaluate all connected edges
+        const labelList& fEdges = patch_.faceEdges()[faceI];
+
+        forAll(fEdges, fEdgeI)
+        {
+            label edgeI = fEdges[fEdgeI];
+
+            Type& currentWallInfo = allEdgeInfo_[edgeI];
+
+            if (!currentWallInfo.equal(neighbourWallInfo, td_))
+            {
+                updateEdge
+                (
+                    edgeI,
+                    faceI,
+                    neighbourWallInfo,
+                    currentWallInfo
+                );
+            }
+        }
+    }
+
+
+    syncEdges();
+
+
+    if (debug)
+    {
+        Pout<< "Changed edges             : " << changedEdges_.size() << endl;
+    }
+
+    return returnReduce(changedEdges_.size(), sumOp<label>());
+}
+
+
+// Propagate information from edge to face. Return number of faces changed.
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+Foam::label Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+edgeToFace()
+{
+    changedFaces_.clear();
+    changedFace_ = false;
+
+    const labelListList& edgeFaces = patch_.edgeFaces();
+
+    forAll(changedEdges_, changedEdgeI)
+    {
+        label edgeI = changedEdges_[changedEdgeI];
+
+        if (!changedEdge_[edgeI])
+        {
+            FatalErrorIn("PatchEdgeFaceWave<Type, TrackingData>::edgeToFace()")
+                << "edge " << edgeI
+                << " not marked as having been changed" << nl
+                << "This might be caused by multiple occurences of the same"
+                << " seed edge." << abort(FatalError);
+        }
+
+        const Type& neighbourWallInfo = allEdgeInfo_[edgeI];
+
+        // Evaluate all connected faces
+
+        const labelList& eFaces = edgeFaces[edgeI];
+        forAll(eFaces, eFaceI)
+        {
+            label faceI = eFaces[eFaceI];
+
+            Type& currentWallInfo = allFaceInfo_[faceI];
+
+            if (!currentWallInfo.equal(neighbourWallInfo, td_))
+            {
+                updateFace
+                (
+                    faceI,
+                    edgeI,
+                    neighbourWallInfo,
+                    currentWallInfo
+                );
+            }
+        }
+    }
+
+    if (debug)
+    {
+        Pout<< "Changed faces             : " << changedFaces_.size() << endl;
+    }
+
+    return returnReduce(changedFaces_.size(), sumOp<label>());
+}
+
+
+// Iterate
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData
+>
+Foam::label Foam::PatchEdgeFaceWave<PrimitivePatchType, Type, TrackingData>::
+iterate
+(
+    const label maxIter
+)
+{
+    // Make sure coupled edges contain same info
+    syncEdges();
+
+    nEvals_ = 0;
+
+    label iter = 0;
+
+    while (iter < maxIter)
+    {
+        if (debug)
+        {
+            Pout<< "Iteration " << iter << endl;
+        }
+
+        label nFaces = edgeToFace();
+
+        if (debug)
+        {
+            Pout<< "Total changed faces       : " << nFaces << endl;
+        }
+
+        if (nFaces == 0)
+        {
+            break;
+        }
+
+        label nEdges = faceToEdge();
+
+        if (debug)
+        {
+            Pout<< "Total changed edges       : " << nEdges << nl
+                << "Total evaluations         : " << nEvals_ << nl
+                << "Remaining unvisited edges : " << nUnvisitedEdges_ << nl
+                << "Remaining unvisited faces : " << nUnvisitedFaces_ << nl
+                << endl;
+        }
+
+        if (nEdges == 0)
+        {
+            break;
+        }
+
+        iter++;
+    }
+
+    return iter;
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWave.H b/src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWave.H
new file mode 100644
index 00000000000..1551152c13b
--- /dev/null
+++ b/src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWave.H
@@ -0,0 +1,368 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2004-2010 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::PatchEdgeFaceWave
+
+Description
+    Wave propagation of information along patch. Every iteration
+    information goes through one layer of faces. Templated on information
+    that is transferred.
+
+SourceFiles
+    PatchEdgeFaceWave.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef PatchEdgeFaceWave_H
+#define PatchEdgeFaceWave_H
+
+#include "scalarField.H"
+#include "PackedBoolList.H"
+#include "PrimitivePatch.H"
+#include "vectorTensorTransform.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class polyMesh;
+
+/*---------------------------------------------------------------------------*\
+                    Class PatchEdgeFaceWaveName Declaration
+\*---------------------------------------------------------------------------*/
+
+TemplateName(PatchEdgeFaceWave);
+
+
+/*---------------------------------------------------------------------------*\
+                           Class PatchEdgeFaceWave Declaration
+\*---------------------------------------------------------------------------*/
+
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData = int
+>
+class PatchEdgeFaceWave
+:
+    public PatchEdgeFaceWaveName
+{
+  // Private static data
+
+        //- Relative tolerance. Stop propagation if relative changes
+        //  less than this tolerance (responsability for checking this is
+        //  up to Type implementation)
+        static scalar propagationTol_;
+
+        //- Used as default trackdata value to satisfy default template
+        //  argument.
+        static label dummyTrackData_;
+
+
+    // Private data
+
+        //- Reference to mesh
+        const polyMesh& mesh_;
+
+        //- Reference to patch
+        const PrimitivePatchType& patch_;
+
+        //- Wall information for all edges
+        UList<Type>& allEdgeInfo_;
+
+        //- Information on all patch faces
+        UList<Type>& allFaceInfo_;
+
+        //- Additional data to be passed into container
+        TrackingData& td_;
+
+        //- Has edge changed
+        PackedBoolList changedEdge_;
+
+        //- List of changed edges
+        DynamicList<label> changedEdges_;
+
+        //- Has face changed
+        PackedBoolList changedFace_;
+
+        //- List of changed faces
+        DynamicList<label> changedFaces_;
+
+        //- Number of evaluations
+        label nEvals_;
+
+        //- Number of unvisited faces/edges
+        label nUnvisitedEdges_;
+        label nUnvisitedFaces_;
+
+
+        // Addressing between edges of patch_ and globalData.coupledPatch()
+        labelList patchEdges_;
+        labelList coupledEdges_;
+        PackedBoolList sameEdgeOrientation_;
+
+
+    // Private Member Functions
+
+        //- Updates edgeInfo with information from neighbour. Updates all
+        //  statistics.
+        bool updateEdge
+        (
+            const label edgeI,
+            const label neighbourFaceI,
+            const Type& neighbourInfo,
+            Type& edgeInfo
+        );
+
+        //- Updates faceInfo with information from neighbour. Updates all
+        //  statistics.
+        bool updateFace
+        (
+            const label faceI,
+            const label neighbourEdgeI,
+            const Type& neighbourInfo,
+            Type& faceInfo
+        );
+
+        //- Update coupled edges
+        void syncEdges();
+
+        //- Disallow default bitwise copy construct
+        PatchEdgeFaceWave(const PatchEdgeFaceWave&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const PatchEdgeFaceWave&);
+
+
+public:
+
+    // Static Functions
+
+        //- Access to tolerance
+        static scalar propagationTol()
+        {
+            return propagationTol_;
+        }
+
+        //- Change tolerance
+        static void setPropagationTol(const scalar tol)
+        {
+            propagationTol_ = tol;
+        }
+
+
+    // Constructors
+
+        //- Construct from patch, list of changed edges with the Type
+        //  for these edges. Gets work arrays to operate on, one of size
+        //  number of patch edges, the other number of patch faces.
+        //  Iterates until nothing changes or maxIter reached.
+        //  (maxIter can be 0)
+        PatchEdgeFaceWave
+        (
+            const polyMesh& mesh,
+            const PrimitivePatchType& patch,
+            const labelList& initialEdges,
+            const List<Type>& initialEdgesInfo,
+            UList<Type>& allEdgeInfo,
+            UList<Type>& allFaceInfo,
+            const label maxIter,
+            TrackingData& td = dummyTrackData_
+        );
+
+        //- Construct from patch. Use setEdgeInfo and iterate() to do
+        //  actual calculation
+        PatchEdgeFaceWave
+        (
+            const polyMesh& mesh,
+            const PrimitivePatchType& patch,
+            UList<Type>& allEdgeInfo,
+            UList<Type>& allFaceInfo,
+            TrackingData& td = dummyTrackData_
+        );
+
+
+    // Member Functions
+
+        //- Access allEdgeInfo
+        UList<Type>& allEdgeInfo() const
+        {
+            return allEdgeInfo_;
+        }
+
+        //- Access allFaceInfo
+        UList<Type>& allFaceInfo() const
+        {
+            return allFaceInfo_;
+        }
+
+        //- Additional data to be passed into container
+        const TrackingData& data() const
+        {
+            return td_;
+        }
+
+        //- Get number of unvisited faces, i.e. faces that were not (yet)
+        //  reached from walking across patch. This can happen from
+        //  - not enough iterations done
+        //  - a disconnected patch
+        //  - a patch without walls in it
+        label getUnsetFaces() const;
+
+        label getUnsetEdges() const;
+
+        //- Copy initial data into allEdgeInfo_
+        void setEdgeInfo
+        (
+            const labelList& changedEdges,
+            const List<Type>& changedEdgesInfo
+        );
+
+        //- Propagate from edge to face. Returns total number of faces
+        //  (over all processors) changed.
+        label edgeToFace();
+
+        //- Propagate from face to edge. Returns total number of edges
+        //  (over all processors) changed.
+        label faceToEdge();
+
+        //- Iterate until no changes or maxIter reached. Returns actual
+        //  number of iterations.
+        label iterate(const label maxIter);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+//- Update operation
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData = int
+>
+class updateOp
+{
+    //- Additional data to be passed into container
+    const polyMesh& mesh_;
+    const PrimitivePatchType& patch_;
+    const scalar tol_;
+    TrackingData& td_;
+
+public:
+    updateOp
+    (
+        const polyMesh& mesh,
+        const PrimitivePatchType& patch,
+        const scalar tol,
+        TrackingData& td
+    )
+    :
+        mesh_(mesh),
+        patch_(patch),
+        tol_(tol),
+        td_(td)
+    {}
+
+    void operator()(Type& x, const Type& y) const
+    {
+        if (y.valid(td_))
+        {
+            x.updateEdge(mesh_, patch_, y, true, tol_, td_);
+        }
+    }
+};
+
+
+//- Transform operation
+template
+<
+    class PrimitivePatchType,
+    class Type,
+    class TrackingData = int
+>
+class transformOp
+{
+    //- Additional data to be passed into container
+    const polyMesh& mesh_;
+    const PrimitivePatchType& patch_;
+    const scalar tol_;
+    TrackingData& td_;
+
+public:
+    transformOp
+    (
+        const polyMesh& mesh,
+        const PrimitivePatchType& patch,
+        const scalar tol,
+        TrackingData& td
+    )
+    :
+        mesh_(mesh),
+        patch_(patch),
+        tol_(tol),
+        td_(td)
+    {}
+
+    void operator()
+    (
+        const vectorTensorTransform& vt,
+        const bool forward,
+        List<Type>& fld
+    ) const
+    {
+        if (forward)
+        {
+            forAll(fld, i)
+            {
+                fld[i].transform(mesh_, patch_, vt.R(), tol_, td_);
+            }
+        }
+        else
+        {
+            forAll(fld, i)
+            {
+                fld[i].transform(mesh_, patch_, vt.R().T(), tol_, td_);
+            }
+        }
+    }
+};
+
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+#   include "PatchEdgeFaceWave.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWaveName.C b/src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWaveName.C
new file mode 100644
index 00000000000..4ed5d675709
--- /dev/null
+++ b/src/meshTools/PatchEdgeFaceWave/PatchEdgeFaceWaveName.C
@@ -0,0 +1,32 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2004-2010 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "PatchEdgeFaceWave.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(Foam::PatchEdgeFaceWaveName, 0);
+
+// ************************************************************************* //
diff --git a/src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfo.C b/src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfo.C
new file mode 100644
index 00000000000..f6e72fed998
--- /dev/null
+++ b/src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfo.C
@@ -0,0 +1,50 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "patchEdgeFaceInfo.H"
+
+// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
+
+Foam::Ostream& Foam::operator<<
+(
+    Foam::Ostream& os,
+    const Foam::patchEdgeFaceInfo& wDist
+)
+{
+    return os << wDist.origin() << wDist.distSqr();
+}
+
+
+Foam::Istream& Foam::operator>>
+(
+    Foam::Istream& is,
+    Foam::patchEdgeFaceInfo& wDist
+)
+{
+    return is >> wDist.origin_ >> wDist.distSqr_;
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfo.H b/src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfo.H
new file mode 100644
index 00000000000..f02120d7d9a
--- /dev/null
+++ b/src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfo.H
@@ -0,0 +1,212 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::patchEdgeFaceInfo
+
+Description
+
+SourceFiles
+    patchEdgeFaceInfoI.H
+    patchEdgeFaceInfo.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef patchEdgeFaceInfo_H
+#define patchEdgeFaceInfo_H
+
+#include "point.H"
+#include "label.H"
+#include "scalar.H"
+#include "tensor.H"
+#include "pTraits.H"
+#include "primitivePatch.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class polyPatch;
+class polyMesh;
+
+/*---------------------------------------------------------------------------*\
+                           Class patchEdgeFaceInfo Declaration
+\*---------------------------------------------------------------------------*/
+
+class patchEdgeFaceInfo
+{
+    // Private data
+
+        //- position of nearest wall center
+        point origin_;
+
+        //- normal distance (squared) from point to origin
+        scalar distSqr_;
+
+
+    // Private Member Functions
+
+        //- Evaluate distance to point. Update distSqr, origin from whomever
+        //  is nearer pt. Return true if w2 is closer to point,
+        //  false otherwise.
+        template<class TrackingData>
+        inline bool update
+        (
+            const point&,
+            const patchEdgeFaceInfo& w2,
+            const scalar tol,
+            TrackingData& td
+        );
+
+        //- Combine current with w2. Update distSqr, origin if w2 has smaller
+        //  quantities and returns true.
+        template<class TrackingData>
+        inline bool update
+        (
+            const patchEdgeFaceInfo& w2,
+            const scalar tol,
+            TrackingData& td
+        );
+
+
+public:
+
+    // Constructors
+
+        //- Construct null
+        inline patchEdgeFaceInfo();
+
+        //- Construct from origin, distance
+        inline patchEdgeFaceInfo(const point&, const scalar);
+
+        //- Construct as copy
+        inline patchEdgeFaceInfo(const patchEdgeFaceInfo&);
+
+
+    // Member Functions
+
+        // Access
+
+            inline const point& origin() const;
+
+            inline scalar distSqr() const;
+
+
+        // Needed by meshWave
+
+            //- Check whether origin has been changed at all or
+            //  still contains original (invalid) value.
+            template<class TrackingData>
+            inline bool valid(TrackingData& td) const;
+
+            //- Apply rotation matrix
+            template<class TrackingData>
+            inline void transform
+            (
+                const polyMesh& mesh,
+                const primitivePatch& patch,
+                const tensor& rotTensor,
+                const scalar tol,
+                TrackingData& td
+            );
+
+            //- Influence of face on edge
+            template<class TrackingData>
+            inline bool updateEdge
+            (
+                const polyMesh& mesh,
+                const primitivePatch& patch,
+                const label edgeI,
+                const label faceI,
+                const patchEdgeFaceInfo& faceInfo,
+                const scalar tol,
+                TrackingData& td
+            );
+
+            //- New information for edge (from e.g. coupled edge)
+            template<class TrackingData>
+            inline bool updateEdge
+            (
+                const polyMesh& mesh,
+                const primitivePatch& patch,
+                const patchEdgeFaceInfo& edgeInfo,
+                const bool sameOrientation,
+                const scalar tol,
+                TrackingData& td
+            );
+
+            //- Influence of edge on face.
+            template<class TrackingData>
+            inline bool updateFace
+            (
+                const polyMesh& mesh,
+                const primitivePatch& patch,
+                const label faceI,
+                const label edgeI,
+                const patchEdgeFaceInfo& edgeInfo,
+                const scalar tol,
+                TrackingData& td
+            );
+
+            //- Same (like operator==)
+            template<class TrackingData>
+            inline bool equal(const patchEdgeFaceInfo&, TrackingData& td) const;
+
+
+    // Member Operators
+
+        // Needed for List IO
+        inline bool operator==(const patchEdgeFaceInfo&) const;
+        inline bool operator!=(const patchEdgeFaceInfo&) const;
+
+
+    // IOstream Operators
+
+        friend Ostream& operator<<(Ostream&, const patchEdgeFaceInfo&);
+        friend Istream& operator>>(Istream&, patchEdgeFaceInfo&);
+};
+
+
+//- Data associated with patchEdgeFaceInfo type are contiguous
+template<>
+inline bool contiguous<patchEdgeFaceInfo>()
+{
+    return true;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "patchEdgeFaceInfoI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfoI.H b/src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfoI.H
new file mode 100644
index 00000000000..881e586626a
--- /dev/null
+++ b/src/meshTools/PatchEdgeFaceWave/patchEdgeFaceInfoI.H
@@ -0,0 +1,268 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "polyMesh.H"
+#include "transform.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+// Update this with w2 if w2 nearer to pt.
+template<class TrackingData>
+inline bool Foam::patchEdgeFaceInfo::update
+(
+    const point& pt,
+    const patchEdgeFaceInfo& w2,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    scalar dist2 = magSqr(pt - w2.origin());
+
+    if (!valid(td))
+    {
+        // current not yet set so use any value
+        distSqr_ = dist2;
+        origin_ = w2.origin();
+
+        return true;
+    }
+
+    scalar diff = distSqr_ - dist2;
+
+    if (diff < 0)
+    {
+        // already nearer to pt
+        return false;
+    }
+
+    if ((diff < SMALL) || ((distSqr_ > SMALL) && (diff/distSqr_ < tol)))
+    {
+        // don't propagate small changes
+        return false;
+    }
+    else
+    {
+        // update with new values
+        distSqr_ = dist2;
+        origin_ = w2.origin();
+
+        return true;
+    }
+}
+
+
+// Update this with w2 (information on same edge)
+template<class TrackingData>
+inline bool Foam::patchEdgeFaceInfo::update
+(
+    const patchEdgeFaceInfo& w2,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    if (!valid(td))
+    {
+        // current not yet set so use any value
+        distSqr_ = w2.distSqr();
+        origin_ = w2.origin();
+
+        return true;
+    }
+
+    scalar diff = distSqr_ - w2.distSqr();
+
+    if (diff < 0)
+    {
+        // already nearer to pt
+        return false;
+    }
+
+    if ((diff < SMALL) || ((distSqr_ > SMALL) && (diff/distSqr_ < tol)))
+    {
+        // don't propagate small changes
+        return false;
+    }
+    else
+    {
+        // update with new values
+        distSqr_ =  w2.distSqr();
+        origin_ = w2.origin();
+
+        return true;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Null constructor
+inline Foam::patchEdgeFaceInfo::patchEdgeFaceInfo()
+:
+    origin_(point::max),
+    distSqr_(sqr(GREAT))
+{}
+
+
+// Construct from origin, distance
+inline Foam::patchEdgeFaceInfo::patchEdgeFaceInfo
+(
+    const point& origin,
+    const scalar distSqr
+)
+:
+    origin_(origin),
+    distSqr_(distSqr)
+{}
+
+
+// Construct as copy
+inline Foam::patchEdgeFaceInfo::patchEdgeFaceInfo(const patchEdgeFaceInfo& wpt)
+:
+    origin_(wpt.origin()),
+    distSqr_(wpt.distSqr())
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+inline const Foam::point& Foam::patchEdgeFaceInfo::origin() const
+{
+    return origin_;
+}
+
+
+inline Foam::scalar Foam::patchEdgeFaceInfo::distSqr() const
+{
+    return distSqr_;
+}
+
+
+template<class TrackingData>
+inline bool Foam::patchEdgeFaceInfo::valid(TrackingData& td) const
+{
+    return origin_ != point::max;
+}
+
+
+template<class TrackingData>
+inline void Foam::patchEdgeFaceInfo::transform
+(
+    const polyMesh& mesh,
+    const primitivePatch& patch,
+    const tensor& rotTensor,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    origin_ = Foam::transform(rotTensor, origin_);
+}
+
+
+template<class TrackingData>
+inline bool Foam::patchEdgeFaceInfo::updateEdge
+(
+    const polyMesh& mesh,
+    const primitivePatch& patch,
+    const label edgeI,
+    const label faceI,
+    const patchEdgeFaceInfo& faceInfo,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    const edge& e = patch.edges()[edgeI];
+    point eMid =
+        0.5
+      * (
+            patch.points()[patch.meshPoints()[e[0]]]
+          + patch.points()[patch.meshPoints()[e[1]]]
+        );
+    return update(eMid, faceInfo, tol, td);
+}
+
+
+template<class TrackingData>
+inline bool Foam::patchEdgeFaceInfo::updateEdge
+(
+    const polyMesh& mesh,
+    const primitivePatch& patch,
+    const patchEdgeFaceInfo& edgeInfo,
+    const bool sameOrientation,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    return update(edgeInfo, tol, td);
+}
+
+
+template<class TrackingData>
+inline bool Foam::patchEdgeFaceInfo::updateFace
+(
+    const polyMesh& mesh,
+    const primitivePatch& patch,
+    const label faceI,
+    const label edgeI,
+    const patchEdgeFaceInfo& edgeInfo,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    return update(patch.faceCentres()[faceI], edgeInfo, tol, td);
+}
+
+
+template <class TrackingData>
+inline bool Foam::patchEdgeFaceInfo::equal
+(
+    const patchEdgeFaceInfo& rhs,
+    TrackingData& td
+) const
+{
+    return operator==(rhs);
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+inline bool Foam::patchEdgeFaceInfo::operator==
+(
+    const Foam::patchEdgeFaceInfo& rhs
+) const
+{
+    return origin() == rhs.origin();
+}
+
+
+inline bool Foam::patchEdgeFaceInfo::operator!=
+(
+    const Foam::patchEdgeFaceInfo& rhs
+) const
+{
+    return !(*this == rhs);
+}
+
+
+// ************************************************************************* //
-- 
GitLab