From b4a742fc893ae4721d5c90b0003e310b7e5b1a08 Mon Sep 17 00:00:00 2001
From: laurence <laurence>
Date: Wed, 18 Sep 2013 15:31:58 +0100
Subject: [PATCH] ENH: collapseEdges: Points now get a priority. The higher the
 number, the more likely the collapse will be towards that point

---
 .../advanced/collapseEdges/collapseEdges.C    |   65 +-
 .../conformalVoronoiMesh.C                    |   20 +-
 .../conformalVoronoiMesh.H                    |   15 +-
 .../conformalVoronoiMeshCalcDualMesh.C        |  458 ++--
 .../conformalVoronoiMeshIO.C                  |  200 +-
 .../indexedCell/indexedCell.H                 |    5 +
 .../indexedCell/indexedCellI.H                |   81 +
 .../indexedVertex/indexedVertex.H             |    2 +
 .../indexedVertex/indexedVertexEnum.C         |    8 +-
 .../indexedVertex/indexedVertexEnum.H         |   28 +-
 .../indexedVertex/indexedVertexI.H            |   20 +
 src/dynamicMesh/Make/files                    |    1 +
 .../polyMeshFilter/polyMeshFilter.C           | 1882 +++++++----------
 .../polyMeshFilter/polyMeshFilter.H           |   85 +-
 .../polyTopoChange/edgeCollapser.C            |  270 ++-
 15 files changed, 1428 insertions(+), 1712 deletions(-)

diff --git a/applications/utilities/mesh/advanced/collapseEdges/collapseEdges.C b/applications/utilities/mesh/advanced/collapseEdges/collapseEdges.C
index 7a07b63d8f0..0515205c788 100644
--- a/applications/utilities/mesh/advanced/collapseEdges/collapseEdges.C
+++ b/applications/utilities/mesh/advanced/collapseEdges/collapseEdges.C
@@ -95,24 +95,56 @@ int main(int argc, char *argv[])
     const bool collapseFaces = args.optionFound("collapseFaces");
     const bool collapseFaceZone = args.optionFound("collapseFaceZone");
 
+    if (collapseFaces && collapseFaceZone)
+    {
+        FatalErrorIn("main(int, char*[])")
+            << "Both face zone collapsing and face collapsing have been"
+            << "selected. Choose only one of:" << nl
+            << "    -collapseFaces" << nl
+            << "    -collapseFaceZone <faceZoneName>"
+            << abort(FatalError);
+    }
+
+    labelIOList pointPriority
+    (
+        IOobject
+        (
+            "pointPriority",
+            runTime.timeName(),
+            runTime,
+            IOobject::READ_IF_PRESENT,
+            IOobject::AUTO_WRITE
+        ),
+        labelList(mesh.nPoints(), labelMin)
+    );
+
     forAll(timeDirs, timeI)
     {
         runTime.setTime(timeDirs[timeI], timeI);
 
         Info<< "Time = " << runTime.timeName() << endl;
 
-        polyMeshFilter meshFilter(mesh);
+        autoPtr<polyMeshFilter> meshFilterPtr;
 
-        // newMesh will be empty until it is filtered
-        const autoPtr<fvMesh>& newMesh = meshFilter.filteredMesh();
+        label nBadFaces = 0;
 
-        // Filter small edges only. This reduces the number of faces so that
-        // the face filtering is sped up.
-        label nBadFaces = meshFilter.filterEdges(0);
         {
-            polyTopoChange meshMod(newMesh);
+            meshFilterPtr.set(new polyMeshFilter(mesh, pointPriority));
+            polyMeshFilter& meshFilter = meshFilterPtr();
+
+            // newMesh will be empty until it is filtered
+            const autoPtr<fvMesh>& newMesh = meshFilter.filteredMesh();
+
+            // Filter small edges only. This reduces the number of faces so that
+            // the face filtering is sped up.
+            nBadFaces = meshFilter.filterEdges(0);
+            {
+                polyTopoChange meshMod(newMesh);
 
-            meshMod.changeMesh(mesh, false);
+                meshMod.changeMesh(mesh, false);
+            }
+
+            pointPriority = meshFilter.pointPriority();
         }
 
         if (collapseFaceZone)
@@ -121,18 +153,30 @@ int main(int argc, char *argv[])
 
             const faceZone& fZone = mesh.faceZones()[faceZoneName];
 
+            meshFilterPtr.reset(new polyMeshFilter(mesh, pointPriority));
+            polyMeshFilter& meshFilter = meshFilterPtr();
+
+            const autoPtr<fvMesh>& newMesh = meshFilter.filteredMesh();
+
             // Filter faces. Pass in the number of bad faces that are present
             // from the previous edge filtering to use as a stopping criterion.
-            meshFilter.filterFaceZone(fZone);
+            meshFilter.filter(fZone);
             {
                 polyTopoChange meshMod(newMesh);
 
                 meshMod.changeMesh(mesh, false);
             }
+
+            pointPriority = meshFilter.pointPriority();
         }
 
         if (collapseFaces)
         {
+            meshFilterPtr.reset(new polyMeshFilter(mesh, pointPriority));
+            polyMeshFilter& meshFilter = meshFilterPtr();
+
+            const autoPtr<fvMesh>& newMesh = meshFilter.filteredMesh();
+
             // Filter faces. Pass in the number of bad faces that are present
             // from the previous edge filtering to use as a stopping criterion.
             meshFilter.filter(nBadFaces);
@@ -141,6 +185,8 @@ int main(int argc, char *argv[])
 
                 meshMod.changeMesh(mesh, false);
             }
+
+            pointPriority = meshFilter.pointPriority();
         }
 
         // Write resulting mesh
@@ -157,6 +203,7 @@ int main(int argc, char *argv[])
             << runTime.timeName() << nl << endl;
 
         mesh.write();
+        pointPriority.write();
     }
 
     Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
diff --git a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C
index 8224492921d..e5a5d9e1bf6 100644
--- a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C
+++ b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C
@@ -41,9 +41,26 @@ License
 
 namespace Foam
 {
-defineTypeNameAndDebug(conformalVoronoiMesh, 0);
+    defineTypeNameAndDebug(conformalVoronoiMesh, 0);
+
+    template<>
+    const char* Foam::NamedEnum
+    <
+        Foam::conformalVoronoiMesh::dualMeshPointType,
+        5
+    >::names[] =
+    {
+        "internal",
+        "surface",
+        "featureEdge",
+        "featurePoint",
+        "constrained"
+    };
 }
 
+const Foam::NamedEnum<Foam::conformalVoronoiMesh::dualMeshPointType, 5>
+    Foam::conformalVoronoiMesh::dualMeshPointTypeNames_;
+
 
 // * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
 
@@ -1600,7 +1617,6 @@ void Foam::conformalVoronoiMesh::move()
         printVertexInfo(Info);
     }
 
-    // Write the intermediate mesh, do not filter the dual faces.
     if (time().outputTime())
     {
         writeMesh(time().timeName());
diff --git a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H
index eb75909d1c2..1daffd4c745 100644
--- a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H
+++ b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H
@@ -120,6 +120,17 @@ private:
 
     // Static data
 
+        enum dualMeshPointType
+        {
+            internal     = 0,
+            surface      = 1,
+            featureEdge  = 2,
+            featurePoint = 3,
+            constrained  = 4
+        };
+
+        static const NamedEnum<dualMeshPointType, 5> dualMeshPointTypeNames_;
+
         static const scalar searchConeAngle;
 
         static const scalar searchAngleOppositeSurface;
@@ -682,14 +693,12 @@ private:
         //- Merge vertices that are identical
         void mergeIdenticalDualVertices
         (
-            const pointField& pts,
-            const labelList& boundaryPts
+            const pointField& pts
         );
 
         label mergeIdenticalDualVertices
         (
             const pointField& pts,
-            const labelList& boundaryPts,
             Map<label>& dualPtIndexMap
         ) const;
 
diff --git a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C
index 4e70aab9649..c96fad1e490 100644
--- a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C
+++ b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C
@@ -207,209 +207,214 @@ void Foam::conformalVoronoiMesh::checkCells()
 }
 
 
-void Foam::conformalVoronoiMesh::checkDuals()
-{
-    List<List<Point> > pointFieldList(Pstream::nProcs());
-
-    List<Point> duals(number_of_finite_cells());
-
-//    PackedBoolList bPoints(number_of_finite_cells());
-
-//    indexDualVertices(duals, bPoints);
-
-    label count = 0;//duals.size();
-
-    duals.setSize(number_of_finite_cells());
-
-    globalIndex gIndex(number_of_vertices());
-
-    for
-    (
-        Delaunay::Finite_cells_iterator cit = finite_cells_begin();
-        cit != finite_cells_end();
-        ++cit
-    )
-    {
-        if (cit->hasFarPoint())
-        {
-            continue;
-        }
-
-        duals[count++] = cit->circumcenter();
-
-//        List<labelPair> cellVerticesPair(4);
-//        List<Point> cellVertices(4);
+//void Foam::conformalVoronoiMesh::checkDuals()
+//{
+//    List<List<Point> > pointFieldList(Pstream::nProcs());
+//
+//    List<Point> duals(number_of_finite_cells());
+//
+//    typedef CGAL::Exact_predicates_exact_constructions_kernel       EK2;
+//    typedef CGAL::Regular_triangulation_euclidean_traits_3<EK2>     EK;
+//    typedef CGAL::Cartesian_converter<baseK::Kernel, EK2>  To_exact;
+//    typedef CGAL::Cartesian_converter<EK2, baseK::Kernel>  Back_from_exact;
+//
+////    PackedBoolList bPoints(number_of_finite_cells());
 //
-//        for (label vI = 0; vI < 4; ++vI)
+////    indexDualVertices(duals, bPoints);
+//
+//    label count = 0;//duals.size();
+//
+//    duals.setSize(number_of_finite_cells());
+//
+//    globalIndex gIndex(number_of_vertices());
+//
+//    for
+//    (
+//        Delaunay::Finite_cells_iterator cit = finite_cells_begin();
+//        cit != finite_cells_end();
+//        ++cit
+//    )
+//    {
+//        if (cit->hasFarPoint())
 //        {
-//            cellVerticesPair[vI] = labelPair
-//            (
-//                cit->vertex(vI)->procIndex(),
-//                cit->vertex(vI)->index()
-//            );
-//            cellVertices[vI] = cit->vertex(vI)->point();
+//            continue;
 //        }
 //
-//        labelList oldToNew;
-//        sortedOrder(cellVerticesPair, oldToNew);
-//        oldToNew = invert(oldToNew.size(), oldToNew);
-//        inplaceReorder(oldToNew, cellVerticesPair);
-//        inplaceReorder(oldToNew, cellVertices);
+//        duals[count++] = cit->circumcenter();
 //
-//        duals[count++] = CGAL::circumcenter
-//        (
-//            cellVertices[0],
-//            cellVertices[1],
-//            cellVertices[2],
-//            cellVertices[3]
-//        );
-
-//        To_exact to_exact;
-//        Back_from_exact back_from_exact;
-//        EK::Construct_circumcenter_3 exact_circumcenter =
-//            EK().construct_circumcenter_3_object();
+////        List<labelPair> cellVerticesPair(4);
+////        List<Point> cellVertices(4);
+////
+////        for (label vI = 0; vI < 4; ++vI)
+////        {
+////            cellVerticesPair[vI] = labelPair
+////            (
+////                cit->vertex(vI)->procIndex(),
+////                cit->vertex(vI)->index()
+////            );
+////            cellVertices[vI] = cit->vertex(vI)->point();
+////        }
+////
+////        labelList oldToNew;
+////        sortedOrder(cellVerticesPair, oldToNew);
+////        oldToNew = invert(oldToNew.size(), oldToNew);
+////        inplaceReorder(oldToNew, cellVerticesPair);
+////        inplaceReorder(oldToNew, cellVertices);
+////
+////        duals[count++] = CGAL::circumcenter
+////        (
+////            cellVertices[0],
+////            cellVertices[1],
+////            cellVertices[2],
+////            cellVertices[3]
+////        );
 //
-//        duals[count++] = topoint
-//        (
-//            back_from_exact
-//            (
-//                exact_circumcenter
-//                (
-//                    to_exact(cit->vertex(0)->point()),
-//                    to_exact(cit->vertex(1)->point()),
-//                    to_exact(cit->vertex(2)->point()),
-//                    to_exact(cit->vertex(3)->point())
-//                )
-//            )
-//        );
-    }
-
-    Pout<< "Duals Calculated " << count << endl;
-
-    duals.setSize(count);
-
-    pointFieldList[Pstream::myProcNo()] = duals;
-
-    Pstream::gatherList(pointFieldList);
-
-    if (Pstream::master())
-    {
-        Info<< "Checking on master processor the dual locations of each " << nl
-            << "processor point list against the master dual list." << nl
-            << "There are " << pointFieldList.size() << " processors" << nl
-            << "The size of each processor's dual list is:" << endl;
-
-        forAll(pointFieldList, pfI)
-        {
-            Info<< "    Proc " << pfI << " has " << pointFieldList[pfI].size()
-                << " duals" << endl;
-        }
-
-        label nNonMatches = 0;
-        label nNearMatches = 0;
-        label nExactMatches = 0;
-
-        forAll(pointFieldList[0], pI)
-        {
-            const Point& masterPoint = pointFieldList[0][pI];
-
-            bool foundMatch = false;
-            bool foundNearMatch = false;
-
-            scalar minCloseness = GREAT;
-            Point closestPoint(0, 0, 0);
-
-            forAll(pointFieldList, pfI)
-            {
-                if (pfI == 0)
-                {
-                    continue;
-                }
-
-//                label pfI = 1;
-
-                forAll(pointFieldList[pfI], pISlave)
-                {
-                    const Point& slavePoint
-                        = pointFieldList[pfI][pISlave];
-
-                    if (masterPoint == slavePoint)
-                    {
-                        foundMatch = true;
-                        break;
-                    }
-
-                    const scalar closeness = mag
-                    (
-                        topoint(masterPoint) - topoint(slavePoint)
-                    );
-
-                    if (closeness < 1e-12)
-                    {
-                        foundNearMatch = true;
-                    }
-                    else
-                    {
-                        if (closeness < minCloseness)
-                        {
-                            minCloseness = closeness;
-                            closestPoint = slavePoint;
-                        }
-                    }
-                }
-
-                if (!foundMatch)
-                {
-                    if (foundNearMatch)
-                    {
-                        CGAL::Gmpq x(CGAL::to_double(masterPoint.x()));
-                        CGAL::Gmpq y(CGAL::to_double(masterPoint.y()));
-                        CGAL::Gmpq z(CGAL::to_double(masterPoint.z()));
-
-                        std::cout<< "master = " << x << " " << y << " " << z
-                            << std::endl;
-
-                        CGAL::Gmpq xs(CGAL::to_double(closestPoint.x()));
-                        CGAL::Gmpq ys(CGAL::to_double(closestPoint.y()));
-                        CGAL::Gmpq zs(CGAL::to_double(closestPoint.z()));
-                        std::cout<< "slave  = " << xs << " " << ys << " " << zs
-                            << std::endl;
-
-                        nNearMatches++;
-                    }
-                    else
-                    {
-                        nNonMatches++;
-                        Info<< "    Closest point to " << masterPoint << " is "
-                            << closestPoint << nl
-                            << "    Separation is " << minCloseness << endl;
-
-                        CGAL::Gmpq x(CGAL::to_double(masterPoint.x()));
-                        CGAL::Gmpq y(CGAL::to_double(masterPoint.y()));
-                        CGAL::Gmpq z(CGAL::to_double(masterPoint.z()));
-
-                        std::cout<< "master = " << x << " " << y << " " << z
-                                 << std::endl;
-
-                        CGAL::Gmpq xs(CGAL::to_double(closestPoint.x()));
-                        CGAL::Gmpq ys(CGAL::to_double(closestPoint.y()));
-                        CGAL::Gmpq zs(CGAL::to_double(closestPoint.z()));
-                        std::cout<< "slave  = " << xs << " " << ys << " " << zs
-                                 << std::endl;
-                    }
-                }
-                else
-                {
-                    nExactMatches++;
-                }
-            }
-        }
-
-        Info<< "Found " << nNonMatches << " non-matching duals" << nl
-            << " and " << nNearMatches << " near matches"
-            << " and " << nExactMatches << " exact matches" << endl;
-    }
-}
+////        To_exact to_exact;
+////        Back_from_exact back_from_exact;
+////        EK::Construct_circumcenter_3 exact_circumcenter =
+////            EK().construct_circumcenter_3_object();
+////
+////        duals[count++] = topoint
+////        (
+////            back_from_exact
+////            (
+////                exact_circumcenter
+////                (
+////                    to_exact(cit->vertex(0)->point()),
+////                    to_exact(cit->vertex(1)->point()),
+////                    to_exact(cit->vertex(2)->point()),
+////                    to_exact(cit->vertex(3)->point())
+////                )
+////            )
+////        );
+//    }
+//
+//    Pout<< "Duals Calculated " << count << endl;
+//
+//    duals.setSize(count);
+//
+//    pointFieldList[Pstream::myProcNo()] = duals;
+//
+//    Pstream::gatherList(pointFieldList);
+//
+//    if (Pstream::master())
+//    {
+//        Info<< "Checking on master processor the dual locations of each " << nl
+//            << "processor point list against the master dual list." << nl
+//            << "There are " << pointFieldList.size() << " processors" << nl
+//            << "The size of each processor's dual list is:" << endl;
+//
+//        forAll(pointFieldList, pfI)
+//        {
+//            Info<< "    Proc " << pfI << " has " << pointFieldList[pfI].size()
+//                << " duals" << endl;
+//        }
+//
+//        label nNonMatches = 0;
+//        label nNearMatches = 0;
+//        label nExactMatches = 0;
+//
+//        forAll(pointFieldList[0], pI)
+//        {
+//            const Point& masterPoint = pointFieldList[0][pI];
+//
+//            bool foundMatch = false;
+//            bool foundNearMatch = false;
+//
+//            scalar minCloseness = GREAT;
+//            Point closestPoint(0, 0, 0);
+//
+//            forAll(pointFieldList, pfI)
+//            {
+//                if (pfI == 0)
+//                {
+//                    continue;
+//                }
+//
+////                label pfI = 1;
+//
+//                forAll(pointFieldList[pfI], pISlave)
+//                {
+//                    const Point& slavePoint
+//                        = pointFieldList[pfI][pISlave];
+//
+//                    if (masterPoint == slavePoint)
+//                    {
+//                        foundMatch = true;
+//                        break;
+//                    }
+//
+//                    const scalar closeness = mag
+//                    (
+//                        topoint(masterPoint) - topoint(slavePoint)
+//                    );
+//
+//                    if (closeness < 1e-12)
+//                    {
+//                        foundNearMatch = true;
+//                    }
+//                    else
+//                    {
+//                        if (closeness < minCloseness)
+//                        {
+//                            minCloseness = closeness;
+//                            closestPoint = slavePoint;
+//                        }
+//                    }
+//                }
+//
+//                if (!foundMatch)
+//                {
+//                    if (foundNearMatch)
+//                    {
+//                        CGAL::Gmpq x(CGAL::to_double(masterPoint.x()));
+//                        CGAL::Gmpq y(CGAL::to_double(masterPoint.y()));
+//                        CGAL::Gmpq z(CGAL::to_double(masterPoint.z()));
+//
+//                        std::cout<< "master = " << x << " " << y << " " << z
+//                            << std::endl;
+//
+//                        CGAL::Gmpq xs(CGAL::to_double(closestPoint.x()));
+//                        CGAL::Gmpq ys(CGAL::to_double(closestPoint.y()));
+//                        CGAL::Gmpq zs(CGAL::to_double(closestPoint.z()));
+//                        std::cout<< "slave  = " << xs << " " << ys << " " << zs
+//                            << std::endl;
+//
+//                        nNearMatches++;
+//                    }
+//                    else
+//                    {
+//                        nNonMatches++;
+//                        Info<< "    Closest point to " << masterPoint << " is "
+//                            << closestPoint << nl
+//                            << "    Separation is " << minCloseness << endl;
+//
+//                        CGAL::Gmpq x(CGAL::to_double(masterPoint.x()));
+//                        CGAL::Gmpq y(CGAL::to_double(masterPoint.y()));
+//                        CGAL::Gmpq z(CGAL::to_double(masterPoint.z()));
+//
+//                        std::cout<< "master = " << x << " " << y << " " << z
+//                                 << std::endl;
+//
+//                        CGAL::Gmpq xs(CGAL::to_double(closestPoint.x()));
+//                        CGAL::Gmpq ys(CGAL::to_double(closestPoint.y()));
+//                        CGAL::Gmpq zs(CGAL::to_double(closestPoint.z()));
+//                        std::cout<< "slave  = " << xs << " " << ys << " " << zs
+//                                 << std::endl;
+//                    }
+//                }
+//                else
+//                {
+//                    nExactMatches++;
+//                }
+//            }
+//        }
+//
+//        Info<< "Found " << nNonMatches << " non-matching duals" << nl
+//            << " and " << nNearMatches << " near matches"
+//            << " and " << nExactMatches << " exact matches" << endl;
+//    }
+//}
 
 
 void Foam::conformalVoronoiMesh::checkVertices()
@@ -578,7 +583,7 @@ void Foam::conformalVoronoiMesh::calcDualMesh
         Info<< nl << "Merging identical points" << endl;
 
         // There is no guarantee that a merge of close points is no-risk
-        mergeIdenticalDualVertices(points, boundaryPts);
+        mergeIdenticalDualVertices(points);
     }
 
     // Final dual face and owner neighbour construction
@@ -813,8 +818,7 @@ void Foam::conformalVoronoiMesh::calcTetMesh
 
 void Foam::conformalVoronoiMesh::mergeIdenticalDualVertices
 (
-    const pointField& pts,
-    const labelList& boundaryPts
+    const pointField& pts
 )
 {
     // Assess close points to be merged
@@ -829,7 +833,6 @@ void Foam::conformalVoronoiMesh::mergeIdenticalDualVertices
         nPtsMerged = mergeIdenticalDualVertices
         (
             pts,
-            boundaryPts,
             dualPtIndexMap
         );
 
@@ -851,7 +854,6 @@ void Foam::conformalVoronoiMesh::mergeIdenticalDualVertices
 Foam::label Foam::conformalVoronoiMesh::mergeIdenticalDualVertices
 (
     const pointField& pts,
-    const labelList& boundaryPts,
     Map<label>& dualPtIndexMap
 ) const
 {
@@ -883,6 +885,19 @@ Foam::label Foam::conformalVoronoiMesh::mergeIdenticalDualVertices
 
             if (p1 == p2)
             {
+//                if (c1->parallelDualVertex() || c2->parallelDualVertex())
+//                {
+//                    if (c1->vertexLowestProc() < c2->vertexLowestProc())
+//                    {
+//                        dualPtIndexMap.insert(c1I, c1I);
+//                        dualPtIndexMap.insert(c2I, c1I);
+//                    }
+//                    else
+//                    {
+//                        dualPtIndexMap.insert(c1I, c2I);
+//                        dualPtIndexMap.insert(c2I, c2I);
+//                    }
+//                }
                 if (c1I < c2I)
                 {
                     dualPtIndexMap.insert(c1I, c1I);
@@ -1338,13 +1353,13 @@ void Foam::conformalVoronoiMesh::checkCellSizing()
 
     timeCheck("Start of Cell Sizing");
 
-    labelList boundaryPts(number_of_finite_cells(), -1);
+    labelList boundaryPts(number_of_finite_cells(), internal);
     pointField ptsField;
 
     indexDualVertices(ptsField, boundaryPts);
 
     // Merge close dual vertices.
-    mergeIdenticalDualVertices(ptsField, boundaryPts);
+    mergeIdenticalDualVertices(ptsField);
 
     autoPtr<polyMesh> meshPtr = createPolyMeshFromPoints(ptsField);
     const polyMesh& pMesh = meshPtr();
@@ -1755,7 +1770,7 @@ void Foam::conformalVoronoiMesh::indexDualVertices
     boundaryPts.setSize
     (
         number_of_finite_cells() + nConstrainedVertices,
-        -1
+        internal
     );
 
     if (foamyHexMeshControls().guardFeaturePoints())
@@ -1774,7 +1789,7 @@ void Foam::conformalVoronoiMesh::indexDualVertices
                     topoint(vit->point());
 
                 boundaryPts[number_of_finite_cells() + nConstrainedVertices] =
-                    1;
+                    constrained;
 
                 nConstrainedVertices++;
             }
@@ -1974,15 +1989,40 @@ void Foam::conformalVoronoiMesh::indexDualVertices
 
             if (cit->boundaryDualVertex())
             {
-                if (cit->featureEdgeDualVertex())
+                if (cit->featurePointDualVertex())
                 {
-                    boundaryPts[cit->cellIndex()] = 1;
+                    boundaryPts[cit->cellIndex()] = featurePoint;
+                }
+                else if (cit->featureEdgeDualVertex())
+                {
+                    boundaryPts[cit->cellIndex()] = featureEdge;
                 }
                 else
                 {
-                    boundaryPts[cit->cellIndex()] = 0;
+                    boundaryPts[cit->cellIndex()] = surface;
                 }
             }
+            else if
+            (
+                cit->baffleBoundaryDualVertex()
+            )
+            {
+                boundaryPts[cit->cellIndex()] = surface;
+            }
+            else if
+            (
+                cit->vertex(0)->featureEdgePoint()
+             && cit->vertex(1)->featureEdgePoint()
+             && cit->vertex(2)->featureEdgePoint()
+             && cit->vertex(3)->featureEdgePoint()
+            )
+            {
+                boundaryPts[cit->cellIndex()] = featureEdge;
+            }
+            else
+            {
+                boundaryPts[cit->cellIndex()] = internal;
+            }
         }
         else
         {
diff --git a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C
index 4f02fb67f60..d733b33e35a 100644
--- a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C
+++ b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C
@@ -958,7 +958,7 @@ void Foam::conformalVoronoiMesh::writeMesh
     {
         Info<< nl << "Filtering edges on polyMesh" << nl << endl;
 
-        meshFilter.reset(new polyMeshFilter(mesh));
+        meshFilter.reset(new polyMeshFilter(mesh, boundaryPts));
 
         // Filter small edges only. This reduces the number of faces so that
         // the face filtering is sped up.
@@ -974,9 +974,28 @@ void Foam::conformalVoronoiMesh::writeMesh
 
     if (foamyHexMeshControls().filterFaces())
     {
+        labelIOList boundaryPtsIO
+        (
+            IOobject
+            (
+                "pointPriority",
+                instance,
+                time(),
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            labelList(mesh.nPoints(), labelMin)
+        );
+
+        forAll(mesh.points(), ptI)
+        {
+            boundaryPtsIO[ptI] = mesh.pointZones().whichZone(ptI);
+        }
+
+
         Info<< nl << "Filtering faces on polyMesh" << nl << endl;
 
-        meshFilter.reset(new polyMeshFilter(mesh));
+        meshFilter.reset(new polyMeshFilter(mesh, boundaryPtsIO));
 
         meshFilter().filter(nInitialBadFaces);
         {
@@ -1005,158 +1024,43 @@ void Foam::conformalVoronoiMesh::writeMesh
             << endl;
     }
 
-
-//    volTensorField alignments
-//    (
-//        IOobject
-//        (
-//            "alignmentsField",
-//            runTime_.timeName(),
-//            runTime_,
-//            IOobject::NO_READ,
-//            IOobject::AUTO_WRITE
-//        ),
-//        mesh,
-//        tensor::zero
-//    );
-//
-//    forAll(mesh.cellCentres(), pI)
-//    {
-//        Vertex_handle nearV =
-//            nearest_vertex
-//            (
-//                toPoint<Point>(mesh.cellCentres()[pI])
-//            );
-//        alignments[pI] = nearV->alignment();
-//    }
-//    alignments.write();
-//
-//    {
-//        volVectorField alignmentx
-//        (
-//            IOobject
-//            (
-//                "alignmentsx",
-//                runTime_.timeName(),
-//                runTime_,
-//                IOobject::NO_READ,
-//                IOobject::AUTO_WRITE
-//            ),
-//            mesh,
-//            vector::zero
-//        );
-//        forAll(alignmentx, aI)
-//        {
-//            alignmentx[aI] = alignments[aI].x();
-//        }
-//        alignmentx.write();
-//    }
-//    {
-//        volVectorField alignmenty
-//        (
-//            IOobject
-//            (
-//                "alignmentsy",
-//                runTime_.timeName(),
-//                runTime_,
-//                IOobject::NO_READ,
-//                IOobject::AUTO_WRITE
-//            ),
-//            mesh,
-//            vector::zero
-//        );
-//        forAll(alignmenty, aI)
-//        {
-//            alignmenty[aI] = alignments[aI].y();
-//        }
-//        alignmenty.write();
-//    }
-//    {
-//        volVectorField alignmentz
-//        (
-//            IOobject
-//            (
-//                "alignmentsz",
-//                runTime_.timeName(),
-//                runTime_,
-//                IOobject::NO_READ,
-//                IOobject::AUTO_WRITE
-//            ),
-//            mesh,
-//            vector::zero
-//        );
-//        forAll(alignmentz, aI)
-//        {
-//            alignmentz[aI] = alignments[aI].z();
-//        }
-//        alignmentz.write();
-//    }
-
-
-    labelIOList boundaryIOPts
-    (
-        IOobject
+    {
+        pointScalarField boundaryPtsScalarField
         (
-            "boundaryPoints",
-            instance,
-            runTime_,
-            IOobject::NO_READ,
-            IOobject::AUTO_WRITE
-        ),
-        boundaryPts
-    );
+            IOobject
+            (
+                "boundaryPoints_collapsed",
+                instance,
+                time(),
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE
+            ),
+            pointMesh::New(mesh),
+            scalar(labelMin)
+        );
 
-    // Dump list of boundary points
-    forAll(mesh.boundaryMesh(), patchI)
-    {
-        const polyPatch& pp = mesh.boundaryMesh()[patchI];
+        labelIOList boundaryPtsIO
+        (
+            IOobject
+            (
+                "pointPriority",
+                instance,
+                time(),
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE
+            ),
+            labelList(mesh.nPoints(), labelMin)
+        );
 
-        if (!isA<coupledPolyPatch>(pp))
+        forAll(mesh.points(), ptI)
         {
-            forAll(pp, fI)
-            {
-                const face& boundaryFace = pp[fI];
-
-                forAll(boundaryFace, pI)
-                {
-                    const label boundaryPointI = boundaryFace[pI];
-
-                    boundaryIOPts[boundaryPointI] = boundaryPts[boundaryPointI];
-                }
-            }
+            boundaryPtsScalarField[ptI] = mesh.pointZones().whichZone(ptI);
+            boundaryPtsIO[ptI] = mesh.pointZones().whichZone(ptI);
         }
-    }
-
-    boundaryIOPts.write();
 
-//    forAllConstIter(labelHashSet, pointsInPatch, pI)
-//    {
-//        const Foam::point& ptMaster = mesh.points()[pI.key()];
-//
-//        forAllConstIter(labelHashSet, pointsInPatch, ptI)
-//        {
-//            if (ptI.key() != pI.key())
-//            {
-//                const Foam::point& ptSlave = mesh.points()[ptI.key()];
-//
-//                const scalar dist = mag(ptMaster - ptSlave);
-//                if (ptMaster == ptSlave)
-//                {
-//                    Pout<< "Point(" << pI.key() << ") " << ptMaster
-//                        << " == "
-//                        << "(" << ptI.key() << ") " << ptSlave
-//                        << endl;
-//                }
-//                else if (dist == 0)
-//                {
-//                    Pout<< "Point(" << pI.key() << ") " << ptMaster
-//                        << " ~= "
-//                        << "(" << ptI.key() << ") " << ptSlave
-//                        << endl;
-//                }
-//            }
-//        }
-//    }
+        boundaryPtsScalarField.write();
+        boundaryPtsIO.write();
+    }
 
 //    writeCellSizes(mesh);
 
diff --git a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCell.H b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCell.H
index 82bbe43b953..15b155d85b1 100644
--- a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCell.H
+++ b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCell.H
@@ -176,6 +176,9 @@ public:
         //- Does the Delaunay cell have a far point
         inline bool hasFarPoint() const;
 
+        //- Does the Delaunay cell have a referred point
+        inline bool hasReferredPoint() const;
+
         //- Does the Delaunay cell have a feature point
         inline bool hasFeaturePoint() const;
 
@@ -216,6 +219,8 @@ public:
         //  least one Delaunay vertex outside and at least one inside
         inline bool boundaryDualVertex() const;
 
+        inline bool baffleBoundaryDualVertex() const;
+
         //- A dual vertex on a feature edge will result from this Delaunay cell
         inline bool featureEdgeDualVertex() const;
 
diff --git a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellI.H b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellI.H
index 2f5d076138e..6c55a8eb307 100644
--- a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellI.H
+++ b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellI.H
@@ -189,6 +189,19 @@ inline bool CGAL::indexedCell<Gt, Cb>::hasFarPoint() const
 }
 
 
+template<class Gt, class Cb>
+inline bool CGAL::indexedCell<Gt, Cb>::hasReferredPoint() const
+{
+    return
+    (
+        this->vertex(0)->referred()
+     || this->vertex(1)->referred()
+     || this->vertex(2)->referred()
+     || this->vertex(3)->referred()
+    );
+}
+
+
 template<class Gt, class Cb>
 inline bool CGAL::indexedCell<Gt, Cb>::hasFeaturePoint() const
 {
@@ -372,6 +385,14 @@ inline bool CGAL::indexedCell<Gt, Cb>::anyInternalOrBoundaryDualVertex() const
 template<class Gt, class Cb>
 inline bool CGAL::indexedCell<Gt, Cb>::boundaryDualVertex() const
 {
+//    return
+//    (
+//        this->vertex(0)->boundaryPoint()
+//     && this->vertex(1)->boundaryPoint()
+//     && this->vertex(2)->boundaryPoint()
+//     && this->vertex(3)->boundaryPoint()
+//    );
+
     return
     (
         (
@@ -387,6 +408,41 @@ inline bool CGAL::indexedCell<Gt, Cb>::boundaryDualVertex() const
         || this->vertex(3)->externalBoundaryPoint()
         )
     );
+
+//    Foam::label nBoundaryPoints = 0;
+//
+//    for (Foam::label i = 0; i < 4; ++i)
+//    {
+//        Vertex_handle v = this->vertex(i);
+//
+//        if (v->boundaryPoint())
+//        {
+//            nBoundaryPoints++;
+//        }
+//    }
+//
+//    return (nBoundaryPoints > 1);
+}
+
+
+template<class Gt, class Cb>
+inline bool CGAL::indexedCell<Gt, Cb>::baffleBoundaryDualVertex() const
+{
+    return
+    (
+        (
+           this->vertex(0)->internalBafflePoint()
+        || this->vertex(1)->internalBafflePoint()
+        || this->vertex(2)->internalBafflePoint()
+        || this->vertex(3)->internalBafflePoint()
+        )
+     && (
+           this->vertex(0)->externalBafflePoint()
+        || this->vertex(1)->externalBafflePoint()
+        || this->vertex(2)->externalBafflePoint()
+        || this->vertex(3)->externalBafflePoint()
+        )
+    );
 }
 
 
@@ -400,6 +456,31 @@ inline bool CGAL::indexedCell<Gt, Cb>::featureEdgeDualVertex() const
      && this->vertex(2)->featureEdgePoint()
      && this->vertex(3)->featureEdgePoint()
     );
+//        (
+//            this->vertex(0)->featureEdgePoint()
+//         || this->vertex(1)->featureEdgePoint()
+//         || this->vertex(2)->featureEdgePoint()
+//         || this->vertex(3)->featureEdgePoint()
+//        )
+//     && (
+//            (
+//                this->vertex(0)->featureEdgePoint()
+//             || this->vertex(0)->featurePoint()
+//            )
+//         && (
+//                this->vertex(1)->featureEdgePoint()
+//             || this->vertex(1)->featurePoint()
+//            )
+//         && (
+//                this->vertex(2)->featureEdgePoint()
+//             || this->vertex(2)->featurePoint()
+//            )
+//         && (
+//                this->vertex(3)->featureEdgePoint()
+//             || this->vertex(3)->featurePoint()
+//            )
+//        )
+//    );
 }
 
 
diff --git a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertex.H b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertex.H
index b556be66cc4..362e457d748 100644
--- a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertex.H
+++ b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertex.H
@@ -243,8 +243,10 @@ public:
         inline bool surfacePoint() const;
 
         inline bool internalBoundaryPoint() const;
+        inline bool internalBafflePoint() const;
 
         inline bool externalBoundaryPoint() const;
+        inline bool externalBafflePoint() const;
 
         inline bool constrained() const;
 
diff --git a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.C b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.C
index d0ac9717827..34c933e162f 100644
--- a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.C
+++ b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.C
@@ -30,13 +30,17 @@ License
 
 template<>
 const char*
-Foam::NamedEnum<Foam::indexedVertexEnum::vertexType, 11>::names[] =
+Foam::NamedEnum<Foam::indexedVertexEnum::vertexType, 15>::names[] =
 {
     "Unassigned",
     "Internal",
     "InternalNearBoundary",
     "InternalSurface",
+    "InternalSurfaceBaffle",
+    "ExternalSurfaceBaffle",
     "InternalFeatureEdge",
+    "InternalFeatureEdgeBaffle",
+    "ExternalFeatureEdgeBaffle",
     "InternalFeaturePoint",
     "ExternalSurface",
     "ExternalFeatureEdge",
@@ -45,7 +49,7 @@ Foam::NamedEnum<Foam::indexedVertexEnum::vertexType, 11>::names[] =
     "Constrained"
 };
 
-const Foam::NamedEnum<Foam::indexedVertexEnum::vertexType, 11>
+const Foam::NamedEnum<Foam::indexedVertexEnum::vertexType, 15>
 Foam::indexedVertexEnum::vertexTypeNames_;
 
 
diff --git a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.H b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.H
index 072470d6732..c606f815d2d 100644
--- a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.H
+++ b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.H
@@ -49,17 +49,21 @@ public:
 
     enum vertexType
     {
-        vtUnassigned            = 0,
-        vtInternal              = 1,
-        vtInternalNearBoundary  = 2,
-        vtInternalSurface       = 3,
-        vtInternalFeatureEdge   = 4,
-        vtInternalFeaturePoint  = 5,
-        vtExternalSurface       = 6,
-        vtExternalFeatureEdge   = 7,
-        vtExternalFeaturePoint  = 8,
-        vtFar                   = 9,
-        vtConstrained           = 10
+        vtUnassigned                = 0,
+        vtInternal                  = 1,
+        vtInternalNearBoundary      = 2,
+        vtInternalSurface           = 3,
+        vtInternalSurfaceBaffle     = 4,
+        vtExternalSurfaceBaffle     = 5,
+        vtInternalFeatureEdge       = 6,
+        vtInternalFeatureEdgeBaffle = 7,
+        vtExternalFeatureEdgeBaffle = 8,
+        vtInternalFeaturePoint      = 9,
+        vtExternalSurface           = 10,
+        vtExternalFeatureEdge       = 11,
+        vtExternalFeaturePoint      = 12,
+        vtFar                       = 13,
+        vtConstrained               = 14
     };
 
     enum vertexMotion
@@ -68,7 +72,7 @@ public:
         movable = 1
     };
 
-    static const Foam::NamedEnum<vertexType, 11> vertexTypeNames_;
+    static const Foam::NamedEnum<vertexType, 15> vertexTypeNames_;
 
     static const Foam::NamedEnum<vertexMotion, 2> vertexMotionNames_;
 
diff --git a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexI.H b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexI.H
index 76a77da47dd..c5930395c3d 100644
--- a/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexI.H
+++ b/applications/utilities/mesh/generation/foamyHexMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexI.H
@@ -307,6 +307,16 @@ inline bool CGAL::indexedVertex<Gt, Vb>::internalBoundaryPoint() const
     return type_ >= vtInternalSurface && type_ <= vtInternalFeaturePoint;
 }
 
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::internalBafflePoint() const
+{
+    return
+    (
+        type_ == vtInternalSurfaceBaffle
+     || type_ == vtInternalFeatureEdgeBaffle
+    );
+}
+
 
 template<class Gt, class Vb>
 inline bool CGAL::indexedVertex<Gt, Vb>::externalBoundaryPoint() const
@@ -314,6 +324,16 @@ inline bool CGAL::indexedVertex<Gt, Vb>::externalBoundaryPoint() const
     return type_ >= vtExternalSurface && type_ <= vtExternalFeaturePoint;
 }
 
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::externalBafflePoint() const
+{
+    return
+    (
+        type_ == vtExternalSurfaceBaffle
+     || type_ == vtExternalFeatureEdgeBaffle
+    );
+}
+
 
 template<class Gt, class Vb>
 inline bool CGAL::indexedVertex<Gt, Vb>::constrained() const
diff --git a/src/dynamicMesh/Make/files b/src/dynamicMesh/Make/files
index 6429d3b4a5d..f769607f949 100644
--- a/src/dynamicMesh/Make/files
+++ b/src/dynamicMesh/Make/files
@@ -99,6 +99,7 @@ createShellMesh/createShellMesh.C
 
 extrudePatchMesh/extrudePatchMesh.C
 
+polyMeshFilter/polyMeshFilterSettings.C
 polyMeshFilter/polyMeshFilter.C
 
 LIB = $(FOAM_LIBBIN)/libdynamicMesh
diff --git a/src/dynamicMesh/polyMeshFilter/polyMeshFilter.C b/src/dynamicMesh/polyMeshFilter/polyMeshFilter.C
index 0c18d84e4fd..7e629d1c3c9 100644
--- a/src/dynamicMesh/polyMeshFilter/polyMeshFilter.C
+++ b/src/dynamicMesh/polyMeshFilter/polyMeshFilter.C
@@ -78,1100 +78,894 @@ Foam::autoPtr<Foam::fvMesh> Foam::polyMeshFilter::copyMesh(const fvMesh& mesh)
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-void Foam::polyMeshFilter::updatePointErrorCount
-(
-    const PackedBoolList& isErrorPoint,
-    const labelList& oldToNewMesh,
-    labelList& pointErrorCount
-) const
+Foam::label Foam::polyMeshFilter::filterFacesLoop(const label nOriginalBadFaces)
 {
-    forAll(mesh_.points(), pI)
-    {
-        if (isErrorPoint[oldToNewMesh[pI]])
-        {
-            pointErrorCount[pI]++;
-        }
-    }
-}
+    label nBadFaces = labelMax;
+    label nOuterIterations = 0;
 
+    // Maintain the number of times a point has been part of a bad face
+    labelList pointErrorCount(mesh_.nPoints(), 0);
 
-void Foam::polyMeshFilter::checkMeshEdgesAndRelaxEdges
-(
-    const polyMesh& newMesh,
-    const labelList& oldToNewMesh,
-    const PackedBoolList& isErrorPoint,
-    const labelList& pointErrorCount
-)
-{
-    const edgeList& edges = mesh_.edges();
+    PackedBoolList newErrorPoint(mesh_.nPoints());
+    edgeCollapser::checkMeshQuality
+    (
+        mesh_,
+        meshQualityCoeffDict(),
+        newErrorPoint
+    );
 
-    forAll(edges, edgeI)
+    bool newBadFaces = true;
+
+    // Main loop
+    // ~~~~~~~~~
+    // It tries and do some collapses, checks the resulting mesh and
+    // 'freezes' some edges (by marking in minEdgeLen) and tries again.
+    // This will iterate ultimately to the situation where every edge is
+    // frozen and nothing gets collapsed.
+    while
+    (
+        nOuterIterations < maxIterations()
+     //&& nBadFaces > nOriginalBadFaces
+     && newBadFaces
+    )
     {
-        const edge& e = edges[edgeI];
-        label newStart = oldToNewMesh[e[0]];
-        label newEnd = oldToNewMesh[e[1]];
+        Info<< nl << "Outer Iteration = " << nOuterIterations++ << nl
+            << endl;
 
-        if
-        (
-            pointErrorCount[e[0]] >= maxPointErrorCount_
-         || pointErrorCount[e[1]] >= maxPointErrorCount_
-        )
-        {
-            minEdgeLen_[edgeI] = 0;
-        }
+        printScalarFieldStats("Edge Filter Factor", minEdgeLen_);
+        printScalarFieldStats("Face Filter Factor", faceFilterFactor_);
 
-        if
-        (
-            (newStart >= 0 && isErrorPoint[newStart])
-         || (newEnd >= 0 && isErrorPoint[newEnd])
-        )
-        {
-            minEdgeLen_[edgeI] *= edgeReductionFactor_;
-        }
-    }
+        // Reset the new mesh to the old mesh
+        newMeshPtr_ = copyMesh(mesh_);
+        fvMesh& newMesh = newMeshPtr_();
 
-    syncTools::syncEdgeList(mesh_, minEdgeLen_, minEqOp<scalar>(), scalar(0.0));
+        scalarField newMeshFaceFilterFactor = faceFilterFactor_;
+        pointPriority_.reset(new labelList(originalPointPriority_));
+
+        labelList origToCurrentPointMap(identity(newMesh.nPoints()));
 
-    for (label smoothIter = 0; smoothIter < maxSmoothIters_; ++smoothIter)
-    {
-        // Smooth minEdgeLen
-        forAll(mesh_.edges(), edgeI)
         {
-            const edge& e = mesh_.edges()[edgeI];
+            label nInnerIterations = 0;
+            label nPrevLocalCollapse = labelMax;
 
-            scalar sumMinEdgeLen = 0;
-            label nEdges = 0;
+            Info<< incrIndent;
 
-            forAll(e, pointI)
+            while (true)
             {
-                const labelList& pEdges = mesh_.pointEdges()[e[pointI]];
+                Info<< nl << indent << "Inner iteration = "
+                    << nInnerIterations++ << nl << incrIndent << endl;
 
-                forAll(pEdges, pEdgeI)
+                label nLocalCollapse = filterFaces
+                (
+                    newMesh,
+                    newMeshFaceFilterFactor,
+                    origToCurrentPointMap
+                );
+                Info<< decrIndent;
+
+                if
+                (
+                    nLocalCollapse >= nPrevLocalCollapse
+                 || nLocalCollapse == 0
+                )
                 {
-                    const label pEdge = pEdges[pEdgeI];
-                    sumMinEdgeLen += minEdgeLen_[pEdge];
-                    nEdges++;
+                    Info<< decrIndent;
+                    break;
+                }
+                else
+                {
+                    nPrevLocalCollapse = nLocalCollapse;
                 }
             }
-
-            minEdgeLen_[edgeI] = min
-            (
-                minEdgeLen_[edgeI],
-                sumMinEdgeLen/nEdges
-            );
         }
 
-        syncTools::syncEdgeList
-        (
-            mesh_,
-            minEdgeLen_,
-            minEqOp<scalar>(),
-            scalar(0.0)
-        );
-    }
-}
-
-
-void Foam::polyMeshFilter::checkMeshFacesAndRelaxEdges
-(
-    const polyMesh& newMesh,
-    const labelList& oldToNewMesh,
-    const PackedBoolList& isErrorPoint,
-    const labelList& pointErrorCount
-)
-{
-    const faceList& faces = mesh_.faces();
-
-    forAll(faces, faceI)
-    {
-        const face& f = faces[faceI];
+        scalarField newMeshMinEdgeLen = minEdgeLen_;
 
-        forAll(f, fpI)
         {
-            const label ptIndex = oldToNewMesh[f[fpI]];
+            label nInnerIterations = 0;
+            label nPrevLocalCollapse = labelMax;
 
-            if (pointErrorCount[f[fpI]] >= maxPointErrorCount_)
-            {
-                faceFilterFactor_[faceI] = 0;
-            }
+            Info<< incrIndent;
 
-            if (isErrorPoint[ptIndex])
+            while (true)
             {
-                faceFilterFactor_[faceI] *= faceReductionFactor_;
-
-                break;
-            }
-        }
-    }
-
-    syncTools::syncFaceList(mesh_, faceFilterFactor_, minEqOp<scalar>());
-
-    for (label smoothIter = 0; smoothIter < maxSmoothIters_; ++smoothIter)
-    {
-        // Smooth faceFilterFactor
-        forAll(faces, faceI)
-        {
-            const labelList& fEdges = mesh_.faceEdges()[faceI];
-
-            scalar sumFaceFilterFactors = 0;
-            label nFaces = 0;
-
-            // This is important: Only smooth around faces that share an
-            // edge with a bad face
-            bool skipFace = true;
+                Info<< nl << indent << "Inner iteration = "
+                    << nInnerIterations++ << nl << incrIndent << endl;
 
-            forAll(fEdges, fEdgeI)
-            {
-                const labelList& eFaces = mesh_.edgeFaces()[fEdges[fEdgeI]];
+                label nLocalCollapse = filterEdges
+                (
+                    newMesh,
+                    newMeshMinEdgeLen,
+                    origToCurrentPointMap
+                );
+                Info<< decrIndent;
 
-                forAll(eFaces, eFaceI)
+                if
+                (
+                    nLocalCollapse >= nPrevLocalCollapse
+                 || nLocalCollapse == 0
+                )
                 {
-                    const label eFace = eFaces[eFaceI];
-
-                    const face& f = faces[eFace];
-
-                    forAll(f, fpI)
-                    {
-                        const label ptIndex = oldToNewMesh[f[fpI]];
-
-                        if (isErrorPoint[ptIndex])
-                        {
-                            skipFace = false;
-                            break;
-                        }
-                    }
-
-                    if (eFace != faceI)
-                    {
-                        sumFaceFilterFactors += faceFilterFactor_[eFace];
-                        nFaces++;
-                    }
+                    Info<< decrIndent;
+                    break;
+                }
+                else
+                {
+                    nPrevLocalCollapse = nLocalCollapse;
                 }
             }
+        }
 
-            if (skipFace)
-            {
-                continue;
-            }
 
-            faceFilterFactor_[faceI] = min
+        // Mesh check
+        // ~~~~~~~~~~~~~~~~~~
+        // Do not allow collapses in regions of error.
+        // Updates minEdgeLen, nRelaxedEdges
+
+        if (controlMeshQuality())
+        {
+            PackedBoolList isErrorPoint(newMesh.nPoints());
+            nBadFaces = edgeCollapser::checkMeshQuality
             (
-                faceFilterFactor_[faceI],
-                sumFaceFilterFactors/nFaces
+                newMesh,
+                meshQualityCoeffDict(),
+                isErrorPoint
             );
-        }
-
-        // Face filter factor needs to be synchronised!
-        syncTools::syncFaceList(mesh_, faceFilterFactor_, minEqOp<scalar>());
-    }
-}
 
+            Info<< nl << "    Number of bad faces     : " << nBadFaces << nl
+                << "    Number of marked points : "
+                << returnReduce(isErrorPoint.count(), sumOp<unsigned int>())
+                << endl;
 
-Foam::labelList Foam::polyMeshFilter::findBoundaryPoints
-(
-    const polyMesh& mesh//,
-//    labelIOList& boundaryIOPts
-) const
-{
-    const polyBoundaryMesh& bMesh = mesh.boundaryMesh();
+            updatePointErrorCount
+            (
+                isErrorPoint,
+                origToCurrentPointMap,
+                pointErrorCount
+            );
 
-    labelList boundaryPoint(mesh.nPoints(), -1);
+            checkMeshEdgesAndRelaxEdges
+            (
+                newMesh,
+                origToCurrentPointMap,
+                isErrorPoint,
+                pointErrorCount
+            );
 
-    // Get all processor boundary points and the processor patch label
-    // that they are on.
-    forAll(bMesh, patchI)
-    {
-        const polyPatch& patch = bMesh[patchI];
+            checkMeshFacesAndRelaxEdges
+            (
+                newMesh,
+                origToCurrentPointMap,
+                isErrorPoint,
+                pointErrorCount
+            );
 
-        if (!isA<coupledPolyPatch>(patch))
-        {
-            forAll(patch, fI)
+            newBadFaces = false;
+            forAll(mesh_.points(), pI)
             {
-                const face& f = patch[fI];
-
-                forAll(f, fp)
+                if (isErrorPoint[origToCurrentPointMap[pI]])
                 {
-                    boundaryPoint[f[fp]] = 0; //boundaryIOPts[f[fp]];
+                    if (!newErrorPoint[pI])
+                    {
+                        newBadFaces = true;
+                        break;
+                    }
                 }
             }
-        }
-    }
-
-    syncTools::syncPointList
-    (
-        mesh,
-        boundaryPoint,
-        maxEqOp<label>(),
-        labelMin
-    );
-
-    return boundaryPoint;
-}
-
-
-void Foam::polyMeshFilter::printScalarFieldStats
-(
-    const string desc,
-    const scalarField& fld
-) const
-{
-    Info<< incrIndent << indent << desc
-        << ": min = " << returnReduce(min(fld), minOp<scalar>())
-        << " av = "
-        << returnReduce(sum(fld), sumOp<scalar>())
-          /returnReduce(fld.size(), sumOp<label>())
-        << " max = " << returnReduce(max(fld), maxOp<scalar>())
-        << decrIndent << endl;
-}
 
-
-void Foam::polyMeshFilter::mapOldMeshEdgeFieldToNewMesh
-(
-    const polyMesh& newMesh,
-    const labelList& pointMap,
-    scalarField& newMeshMinEdgeLen
-) const
-{
-    scalarField tmp(newMesh.nEdges());
-
-    const edgeList& newEdges = newMesh.edges();
-
-    forAll(newEdges, newEdgeI)
-    {
-        const edge& newEdge = newEdges[newEdgeI];
-        const label pStart = newEdge.start();
-        const label pEnd = newEdge.end();
-
-        tmp[newEdgeI] = min
-        (
-            newMeshMinEdgeLen[pointMap[pStart]],
-            newMeshMinEdgeLen[pointMap[pEnd]]
-        );
-    }
-
-    newMeshMinEdgeLen.transfer(tmp);
-
-    syncTools::syncEdgeList
-    (
-        newMesh,
-        newMeshMinEdgeLen,
-        maxEqOp<scalar>(),
-        scalar(0.0)
-    );
-}
-
-
-void Foam::polyMeshFilter::mapOldMeshFaceFieldToNewMesh
-(
-    const polyMesh& newMesh,
-    const labelList& faceMap,
-    scalarField& newMeshFaceFilterFactor
-) const
-{
-    scalarField tmp(newMesh.nFaces());
-
-    forAll(faceMap, newFaceI)
-    {
-        const label oldFaceI = faceMap[newFaceI];
-
-        tmp[newFaceI] = newMeshFaceFilterFactor[oldFaceI];
-    }
-
-    newMeshFaceFilterFactor.transfer(tmp);
-
-    syncTools::syncFaceList
-    (
-        newMesh,
-        newMeshFaceFilterFactor,
-        maxEqOp<scalar>()
-    );
+            reduce(newBadFaces, orOp<bool>());
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+    return nBadFaces;
 }
 
 
-void Foam::polyMeshFilter::updateOldToNewPointMap
+Foam::label Foam::polyMeshFilter::filterFaces
 (
-    const labelList& currToNew,
+    polyMesh& newMesh,
+    scalarField& newMeshFaceFilterFactor,
     labelList& origToCurrentPointMap
-) const
+)
 {
-    forAll(origToCurrentPointMap, origPointI)
+    // Per edge collapse status
+    PackedBoolList collapseEdge(newMesh.nEdges());
+
+    Map<point> collapsePointToLocation(newMesh.nPoints());
+
+    edgeCollapser collapser(newMesh, collapseFacesCoeffDict());
+
     {
-        label oldPointI = origToCurrentPointMap[origPointI];
+        // Collapse faces
+        labelPair nCollapsedPtEdge = collapser.markSmallSliverFaces
+        (
+            newMeshFaceFilterFactor,
+            pointPriority_(),
+            collapseEdge,
+            collapsePointToLocation
+        );
 
-        if (oldPointI < currToNew.size())
+        label nCollapsed = 0;
+        forAll(nCollapsedPtEdge, collapseTypeI)
         {
-            label newPointI = currToNew[oldPointI];
+            nCollapsed += nCollapsedPtEdge[collapseTypeI];
+        }
 
-            if (newPointI != -1)
-            {
-                origToCurrentPointMap[origPointI] = newPointI;
-            }
+        reduce(nCollapsed, sumOp<label>());
+
+        label nToPoint = returnReduce(nCollapsedPtEdge.first(), sumOp<label>());
+        label nToEdge = returnReduce(nCollapsedPtEdge.second(), sumOp<label>());
+
+        Info<< indent
+            << "Collapsing " << nCollapsed << " faces "
+            << "(to point = " << nToPoint << ", to edge = " << nToEdge << ")"
+            << endl;
+
+        if (nCollapsed == 0)
+        {
+            return 0;
         }
     }
-}
-
 
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+    // Merge edge collapses into consistent collapse-network.
+    // Make sure no cells get collapsed.
+    List<pointEdgeCollapse> allPointInfo;
+    const globalIndex globalPoints(newMesh.nPoints());
 
-Foam::polyMeshFilter::polyMeshFilter(const fvMesh& mesh)
-:
-    mesh_(mesh),
-    newMeshPtr_(),
-    dict_
-    (
-        IOobject
-        (
-            "collapseDict",
-            mesh.time().system(),
-            mesh.time(),
-            IOobject::MUST_READ,
-            IOobject::NO_WRITE
-        )
-    ),
-    controlMeshQuality_
-    (
-        dict_.lookupOrDefault<Switch>("controlMeshQuality", false)
-    ),
-    collapseEdgesCoeffDict_(dict_.subDict("collapseEdgesCoeffs")),
-    collapseFacesCoeffDict_(dict_.subOrEmptyDict("collapseFacesCoeffs")),
-    meshQualityCoeffDict_(dict_.subOrEmptyDict("controlMeshQualityCoeffs")),
-    minLen_(readScalar(collapseEdgesCoeffDict_.lookup("minimumEdgeLength"))),
-    maxCos_
-    (
-        ::cos
-        (
-            degToRad
-            (
-                readScalar(collapseEdgesCoeffDict_.lookup("maximumMergeAngle"))
-            )
-        )
-    ),
-    edgeReductionFactor_
-    (
-        meshQualityCoeffDict_.lookupOrDefault<scalar>("edgeReductionFactor", -1)
-    ),
-    maxIterations_
-    (
-        meshQualityCoeffDict_.lookupOrAddDefault<label>("maximumIterations", 1)
-    ),
-    maxSmoothIters_
-    (
-        meshQualityCoeffDict_.lookupOrAddDefault<label>
-        (
-            "maximumSmoothingIterations",
-            0
-        )
-    ),
-    initialFaceLengthFactor_
-    (
-        collapseFacesCoeffDict_.lookupOrAddDefault<scalar>
-        (
-            "initialFaceLengthFactor",
-            -1
-        )
-    ),
-    faceReductionFactor_
-    (
-        meshQualityCoeffDict_.lookupOrAddDefault<scalar>
-        (
-            "faceReductionFactor",
-            -1
-        )
-    ),
-    maxPointErrorCount_
+    collapser.consistentCollapse
     (
-        meshQualityCoeffDict_.lookupOrAddDefault<label>("maxPointErrorCount", 0)
-    ),
-    minEdgeLen_(),
-    faceFilterFactor_()
-{
-    Info<< "Merging:" << nl
-        << "    edges with length less than " << minLen_ << " metres" << nl
-        << "    edges split by a point with edges in line to within "
-        << radToDeg(::acos(maxCos_)) << " degrees" << nl
-        << "    Minimum edge length reduction factor = "
-        << edgeReductionFactor_ << nl
-        << endl;
+        globalPoints,
+        pointPriority_(),
+        collapsePointToLocation,
+        collapseEdge,
+        allPointInfo
+    );
 
-    if (collapseFacesCoeffDict_.empty())
-    {
-        Info<< "Face collapsing is off" << endl;
-    }
-    else
+    label nLocalCollapse = collapseEdge.count();
+
+    reduce(nLocalCollapse, sumOp<label>());
+    Info<< nl << indent << "Collapsing " << nLocalCollapse
+        << " edges after synchronisation and PointEdgeWave" << endl;
+
+    if (nLocalCollapse == 0)
     {
-        Info<< "Face collapsing is on" << endl;
-        Info<< "    Initial face length factor = "<< initialFaceLengthFactor_
-            << endl;
+        return 0;
     }
 
-    Info<< "Control mesh quality = " << controlMeshQuality_.asText() << endl;
-
-    if (controlMeshQuality_)
     {
-        Info<< "    Minimum edge length reduction factor = "
-            << edgeReductionFactor_ << nl
-            << "    Minimum face area reduction factor = "
-            << faceReductionFactor_ << endl;
+        // Apply collapses to current mesh
+        polyTopoChange newMeshMod(newMesh);
 
-        Info<< "    Maximum number of collapse iterations = " << maxIterations_
-            << endl;
+        // Insert mesh refinement into polyTopoChange.
+        collapser.setRefinement(allPointInfo, newMeshMod);
 
-        Info<< "    Maximum number of edge/face reduction factor smoothing "
-            << "iterations = " << maxSmoothIters_ << endl;
+        Info<< indent << "Apply changes to the current mesh" << endl;
 
-        Info<< "    Maximum number of times a point can contribute to bad "
-            << "faces across " << nl
-            << "    collapse iterations = " << maxPointErrorCount_
-            << endl;
-    }
+        // Apply changes to current mesh
+        autoPtr<mapPolyMesh> newMapPtr = newMeshMod.changeMesh
+        (
+            newMesh,
+            false
+        );
+        const mapPolyMesh& newMap = newMapPtr();
 
-    Info<< "Selectively disabling wanted collapses until resulting quality"
-        << " satisfies constraints in system/meshQualityDict" << nl
-        << endl;
-}
+        // Update fields
+        newMesh.updateMesh(newMap);
+        if (newMap.hasMotionPoints())
+        {
+            newMesh.movePoints(newMap.preMotionPoints());
+        }
 
+        updatePointPriorities(newMesh, newMap.pointMap());
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+        mapOldMeshFaceFieldToNewMesh
+        (
+            newMesh,
+            newMap.faceMap(),
+            newMeshFaceFilterFactor
+        );
 
-Foam::polyMeshFilter::~polyMeshFilter()
-{}
+        updateOldToNewPointMap
+        (
+            newMap.reversePointMap(),
+            origToCurrentPointMap
+        );
+    }
 
+    return nLocalCollapse;
+}
 
-// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-Foam::label Foam::polyMeshFilter::filter(const label nOriginalBadFaces)
+Foam::label Foam::polyMeshFilter::filterEdges
+(
+    polyMesh& newMesh,
+    scalarField& newMeshMinEdgeLen,
+    labelList& origToCurrentPointMap
+)
 {
-    label nBadFaces = labelMax;
-    label nOuterIterations = 0;
+    // Per edge collapse status
+    PackedBoolList collapseEdge(newMesh.nEdges());
 
-    minEdgeLen_.resize(mesh_.nEdges(), minLen_);
-    faceFilterFactor_.resize(mesh_.nFaces(), initialFaceLengthFactor_);
+    Map<point> collapsePointToLocation(newMesh.nPoints());
 
-    // Maintain the number of times a point has been part of a bad face
-    labelList pointErrorCount(mesh_.nPoints(), 0);
+    edgeCollapser collapser(newMesh, collapseFacesCoeffDict());
 
-    PackedBoolList newErrorPoint(mesh_.nPoints());
-    edgeCollapser::checkMeshQuality
+    // Work out which edges to collapse
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    // This is by looking at minEdgeLen (to avoid frozen edges)
+    // and marking in collapseEdge.
+    label nSmallCollapsed = collapser.markSmallEdges
     (
-        mesh_,
-        meshQualityCoeffDict_,
-        newErrorPoint
+        newMeshMinEdgeLen,
+        pointPriority_(),
+        collapseEdge,
+        collapsePointToLocation
     );
 
-    bool newBadFaces = true;
+    reduce(nSmallCollapsed, sumOp<label>());
+    Info<< indent << "Collapsing " << nSmallCollapsed
+        << " small edges" << endl;
 
-    // Main loop
-    // ~~~~~~~~~
-    // It tries and do some collapses, checks the resulting mesh and
-    // 'freezes' some edges (by marking in minEdgeLen) and tries again.
-    // This will iterate ultimately to the situation where every edge is
-    // frozen and nothing gets collapsed.
-    while
+    // Merge inline edges
+    label nMerged = collapser.markMergeEdges
     (
-        nOuterIterations < maxIterations_
-     //&& nBadFaces > nOriginalBadFaces
-     && newBadFaces
-    )
-    {
-        Info<< nl << "Outer Iteration = " << nOuterIterations++ << nl
-            << endl;
-
-        printScalarFieldStats("Edge Filter Factor", minEdgeLen_);
-        printScalarFieldStats("Face Filter Factor", faceFilterFactor_);
-
-        // Reset the new mesh to the old mesh
-        newMeshPtr_ = copyMesh(mesh_);
-        fvMesh& newMesh = newMeshPtr_();
+        maxCos(),
+        pointPriority_(),
+        collapseEdge,
+        collapsePointToLocation
+    );
 
-        scalarField newMeshFaceFilterFactor = faceFilterFactor_;
+    reduce(nMerged, sumOp<label>());
+    Info<< indent << "Collapsing " << nMerged << " in line edges"
+        << endl;
 
-        labelList origToCurrentPointMap(identity(newMesh.nPoints()));
-        {
+    if (nMerged + nSmallCollapsed == 0)
+    {
+        return 0;
+    }
 
-            label nInnerIterations = 0;
-            label nPrevLocalCollapse = labelMax;
+    // Merge edge collapses into consistent collapse-network.
+    // Make sure no cells get collapsed.
+    List<pointEdgeCollapse> allPointInfo;
+    const globalIndex globalPoints(newMesh.nPoints());
 
-            Info<< incrIndent;
+    collapser.consistentCollapse
+    (
+        globalPoints,
+        pointPriority_(),
+        collapsePointToLocation,
+        collapseEdge,
+        allPointInfo
+    );
 
-            while (true)
-            {
-                Info<< nl << indent << "Inner iteration = "
-                    << nInnerIterations++ << nl << incrIndent << endl;
+    label nLocalCollapse = collapseEdge.count();
 
-                // Per edge collapse status
-                PackedBoolList collapseEdge(newMesh.nEdges());
+    reduce(nLocalCollapse, sumOp<label>());
+    Info<< nl << indent << "Collapsing " << nLocalCollapse
+        << " edges after synchronisation and PointEdgeWave" << endl;
 
-                Map<point> collapsePointToLocation(newMesh.nPoints());
+    if (nLocalCollapse == 0)
+    {
+        return 0;
+    }
 
-                // Mark points on boundary
-                const labelList boundaryPoint = findBoundaryPoints(newMesh);
+    // Apply collapses to current mesh
+    polyTopoChange newMeshMod(newMesh);
 
-                edgeCollapser collapser(newMesh, collapseFacesCoeffDict_);
+    // Insert mesh refinement into polyTopoChange.
+    collapser.setRefinement(allPointInfo, newMeshMod);
 
-                {
-                    // Collapse faces
-                    labelPair nCollapsedPtEdge = collapser.markSmallSliverFaces
-                    (
-                        newMeshFaceFilterFactor,
-                        boundaryPoint,
-                        collapseEdge,
-                        collapsePointToLocation
-                    );
-
-                    label nCollapsed = 0;
-                    forAll(nCollapsedPtEdge, collapseTypeI)
-                    {
-                        nCollapsed += nCollapsedPtEdge[collapseTypeI];
-                    }
+    Info<< indent << "Apply changes to the current mesh" << endl;
 
-                    reduce(nCollapsed, sumOp<label>());
-
-                    Info<< indent
-                        << "Collapsing " << nCollapsed << " faces"
-                        << " (to point = "
-                        << returnReduce
-                           (
-                               nCollapsedPtEdge.first(),
-                               sumOp<label>()
-                           )
-                        << ", to edge = "
-                        << returnReduce
-                           (
-                               nCollapsedPtEdge.second(),
-                               sumOp<label>()
-                           )
-                        << ")" << endl;
-
-                    if (nCollapsed == 0)
-                    {
-                        Info<< decrIndent;
-                        Info<< decrIndent;
-                        break;
-                    }
-                }
+    // Apply changes to current mesh
+    autoPtr<mapPolyMesh> newMapPtr = newMeshMod.changeMesh
+    (
+        newMesh,
+        false
+    );
+    const mapPolyMesh& newMap = newMapPtr();
 
-                // Merge edge collapses into consistent collapse-network.
-                // Make sure no cells get collapsed.
-                List<pointEdgeCollapse> allPointInfo;
-                const globalIndex globalPoints(newMesh.nPoints());
+    // Update fields
+    newMesh.updateMesh(newMap);
+    if (newMap.hasMotionPoints())
+    {
+        newMesh.movePoints(newMap.preMotionPoints());
+    }
 
-                collapser.consistentCollapse
-                (
-                    globalPoints,
-                    boundaryPoint,
-                    collapsePointToLocation,
-                    collapseEdge,
-                    allPointInfo
-                );
+    // Synchronise the factors
+    mapOldMeshEdgeFieldToNewMesh
+    (
+        newMesh,
+        newMap.pointMap(),
+        newMeshMinEdgeLen
+    );
 
-                label nLocalCollapse = collapseEdge.count();
+    updateOldToNewPointMap
+    (
+        newMap.reversePointMap(),
+        origToCurrentPointMap
+    );
 
-                reduce(nLocalCollapse, sumOp<label>());
-                Info<< nl << indent << "Collapsing " << nLocalCollapse
-                    << " edges after synchronisation and PointEdgeWave" << endl;
+    updatePointPriorities(newMesh, newMap.pointMap());
 
-                if (nLocalCollapse >= nPrevLocalCollapse)
-                {
-                    Info<< decrIndent;
-                    Info<< decrIndent;
-                    break;
-                }
-                else
-                {
-                    nPrevLocalCollapse = nLocalCollapse;
-                }
+    return nLocalCollapse;
+}
 
-                {
-                    // Apply collapses to current mesh
-                    polyTopoChange newMeshMod(newMesh);
-
-                    // Insert mesh refinement into polyTopoChange.
-                    collapser.setRefinement(allPointInfo, newMeshMod);
-
-                    Info<< indent << "Apply changes to the current mesh"
-                        << decrIndent << endl;
-
-                    // Apply changes to current mesh
-                    autoPtr<mapPolyMesh> newMapPtr = newMeshMod.changeMesh
-                    (
-                        newMesh,
-                        false
-                    );
-                    const mapPolyMesh& newMap = newMapPtr();
-
-                    // Update fields
-                    newMesh.updateMesh(newMap);
-                    if (newMap.hasMotionPoints())
-                    {
-                        newMesh.movePoints(newMap.preMotionPoints());
-                    }
 
-                    // Relabel the boundary points
-        //            labelList newBoundaryPoints(newMesh.nPoints(), -1);
-        //            forAll(newBoundaryPoints, pI)
-        //            {
-        //                const label newToOldptI= map.pointMap()[pI];
-        //                newBoundaryPoints[pI] = boundaryIOPts[newToOldptI];
-        //            }
-        //            boundaryIOPts = newBoundaryPoints;
-
-
-                    mapOldMeshFaceFieldToNewMesh
-                    (
-                        newMesh,
-                        newMap.faceMap(),
-                        newMeshFaceFilterFactor
-                    );
-
-                    updateOldToNewPointMap
-                    (
-                        newMap.reversePointMap(),
-                        origToCurrentPointMap
-                    );
-                }
-            }
+void Foam::polyMeshFilter::updatePointErrorCount
+(
+    const PackedBoolList& isErrorPoint,
+    const labelList& oldToNewMesh,
+    labelList& pointErrorCount
+) const
+{
+    forAll(mesh_.points(), pI)
+    {
+        if (isErrorPoint[oldToNewMesh[pI]])
+        {
+            pointErrorCount[pI]++;
         }
+    }
+}
 
 
-        scalarField newMeshMinEdgeLen = minEdgeLen_;
+void Foam::polyMeshFilter::checkMeshEdgesAndRelaxEdges
+(
+    const polyMesh& newMesh,
+    const labelList& oldToNewMesh,
+    const PackedBoolList& isErrorPoint,
+    const labelList& pointErrorCount
+)
+{
+    const edgeList& edges = mesh_.edges();
 
-        label nInnerIterations = 0;
-        label nPrevLocalCollapse = labelMax;
+    forAll(edges, edgeI)
+    {
+        const edge& e = edges[edgeI];
+        label newStart = oldToNewMesh[e[0]];
+        label newEnd = oldToNewMesh[e[1]];
 
-        while (true)
+        if
+        (
+            pointErrorCount[e[0]] >= maxPointErrorCount()
+         || pointErrorCount[e[1]] >= maxPointErrorCount()
+        )
         {
-            Info<< nl << indent << "Inner iteration = "
-                << nInnerIterations++ << nl << incrIndent << endl;
-
-            // Per edge collapse status
-            PackedBoolList collapseEdge(newMesh.nEdges());
-
-            Map<point> collapsePointToLocation(newMesh.nPoints());
-
-            // Mark points on boundary
-            const labelList boundaryPoint = findBoundaryPoints
-            (
-                newMesh//,
-//                    boundaryIOPts
-            );
-
-            edgeCollapser collapser(newMesh, collapseFacesCoeffDict_);
+            minEdgeLen_[edgeI] = -1;
+        }
 
-            // Work out which edges to collapse
-            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-            // This is by looking at minEdgeLen (to avoid frozen edges)
-            // and marking in collapseEdge.
-            label nSmallCollapsed = collapser.markSmallEdges
-            (
-                newMeshMinEdgeLen,
-                boundaryPoint,
-                collapseEdge,
-                collapsePointToLocation
-            );
+        if
+        (
+            (newStart >= 0 && isErrorPoint[newStart])
+         || (newEnd >= 0 && isErrorPoint[newEnd])
+        )
+        {
+            minEdgeLen_[edgeI] *= edgeReductionFactor();
+        }
+    }
 
-            reduce(nSmallCollapsed, sumOp<label>());
-            Info<< indent << "Collapsing " << nSmallCollapsed
-                << " small edges" << endl;
+    syncTools::syncEdgeList(mesh_, minEdgeLen_, minEqOp<scalar>(), scalar(0.0));
 
-            // Merge inline edges
-            label nMerged = collapser.markMergeEdges
-            (
-                maxCos_,
-                boundaryPoint,
-                collapseEdge,
-                collapsePointToLocation
-            );
+    for (label smoothIter = 0; smoothIter < maxSmoothIters(); ++smoothIter)
+    {
+        // Smooth minEdgeLen
+        forAll(mesh_.edges(), edgeI)
+        {
+            const edge& e = mesh_.edges()[edgeI];
 
-            reduce(nMerged, sumOp<label>());
-            Info<< indent << "Collapsing " << nMerged << " in line edges"
-                << endl;
+            scalar sumMinEdgeLen = 0;
+            label nEdges = 0;
 
-            if (nMerged + nSmallCollapsed == 0)
+            forAll(e, pointI)
             {
-                Info<< decrIndent;
-                break;
+                const labelList& pEdges = mesh_.pointEdges()[e[pointI]];
+
+                forAll(pEdges, pEdgeI)
+                {
+                    const label pEdge = pEdges[pEdgeI];
+                    sumMinEdgeLen += minEdgeLen_[pEdge];
+                    nEdges++;
+                }
             }
 
-            // Merge edge collapses into consistent collapse-network.
-            // Make sure no cells get collapsed.
-            List<pointEdgeCollapse> allPointInfo;
-            const globalIndex globalPoints(newMesh.nPoints());
-
-            collapser.consistentCollapse
+            minEdgeLen_[edgeI] = min
             (
-                globalPoints,
-                boundaryPoint,
-                collapsePointToLocation,
-                collapseEdge,
-                allPointInfo
+                minEdgeLen_[edgeI],
+                sumMinEdgeLen/nEdges
             );
+        }
 
-            label nLocalCollapse = collapseEdge.count();
-
-            reduce(nLocalCollapse, sumOp<label>());
-            Info<< nl << indent << "Collapsing " << nLocalCollapse
-                << " edges after synchronisation and PointEdgeWave" << endl;
-
-            if (nLocalCollapse >= nPrevLocalCollapse)
-            {
-                Info<< decrIndent;
-                break;
-            }
-            else
-            {
-                nPrevLocalCollapse = nLocalCollapse;
-            }
+        syncTools::syncEdgeList
+        (
+            mesh_,
+            minEdgeLen_,
+            minEqOp<scalar>(),
+            scalar(0.0)
+        );
+    }
+}
 
-            // Apply collapses to current mesh
-            polyTopoChange newMeshMod(newMesh);
 
-            // Insert mesh refinement into polyTopoChange.
-            collapser.setRefinement(allPointInfo, newMeshMod);
+void Foam::polyMeshFilter::checkMeshFacesAndRelaxEdges
+(
+    const polyMesh& newMesh,
+    const labelList& oldToNewMesh,
+    const PackedBoolList& isErrorPoint,
+    const labelList& pointErrorCount
+)
+{
+    const faceList& faces = mesh_.faces();
 
-            Info<< indent << "Apply changes to the current mesh"
-                << decrIndent << endl;
+    forAll(faces, faceI)
+    {
+        const face& f = faces[faceI];
 
-            // Apply changes to current mesh
-            autoPtr<mapPolyMesh> newMapPtr = newMeshMod.changeMesh
-            (
-                newMesh,
-                false
-            );
-            const mapPolyMesh& newMap = newMapPtr();
+        forAll(f, fpI)
+        {
+            const label ptIndex = oldToNewMesh[f[fpI]];
 
-            // Update fields
-            newMesh.updateMesh(newMap);
-            if (newMap.hasMotionPoints())
+            if (pointErrorCount[f[fpI]] >= maxPointErrorCount())
             {
-                newMesh.movePoints(newMap.preMotionPoints());
+                faceFilterFactor_[faceI] = -1;
             }
 
-            // Relabel the boundary points
-//            labelList newBoundaryPoints(newMesh.nPoints(), -1);
-//            forAll(newBoundaryPoints, pI)
-//            {
-//                const label newToOldptI= map.pointMap()[pI];
-//                newBoundaryPoints[pI] = boundaryIOPts[newToOldptI];
-//            }
-//            boundaryIOPts = newBoundaryPoints;
-
-            // Synchronise the factors
-            mapOldMeshEdgeFieldToNewMesh
-            (
-                newMesh,
-                newMap.pointMap(),
-                newMeshMinEdgeLen
-            );
+            if (isErrorPoint[ptIndex])
+            {
+                faceFilterFactor_[faceI] *= faceReductionFactor();
 
-            updateOldToNewPointMap
-            (
-                newMap.reversePointMap(),
-                origToCurrentPointMap
-            );
+                break;
+            }
         }
+    }
 
+    syncTools::syncFaceList(mesh_, faceFilterFactor_, minEqOp<scalar>());
 
-        // Mesh check
-        // ~~~~~~~~~~~~~~~~~~
-        // Do not allow collapses in regions of error.
-        // Updates minEdgeLen, nRelaxedEdges
-
-        if (controlMeshQuality_)
+    for (label smoothIter = 0; smoothIter < maxSmoothIters(); ++smoothIter)
+    {
+        // Smooth faceFilterFactor
+        forAll(faces, faceI)
         {
-            PackedBoolList isErrorPoint(newMesh.nPoints());
-            nBadFaces = edgeCollapser::checkMeshQuality
-            (
-                newMesh,
-                meshQualityCoeffDict_,
-                isErrorPoint
-            );
-
-            Info<< nl << "    Number of bad faces     : " << nBadFaces << nl
-                << "    Number of marked points : "
-                << returnReduce(isErrorPoint.count(), sumOp<unsigned int>())
-                << endl;
-
-            updatePointErrorCount
-            (
-                isErrorPoint,
-                origToCurrentPointMap,
-                pointErrorCount
-            );
+            const labelList& fEdges = mesh_.faceEdges()[faceI];
 
-            checkMeshEdgesAndRelaxEdges
-            (
-                newMesh,
-                origToCurrentPointMap,
-                isErrorPoint,
-                pointErrorCount
-            );
+            scalar sumFaceFilterFactors = 0;
+            label nFaces = 0;
 
-            checkMeshFacesAndRelaxEdges
-            (
-                newMesh,
-                origToCurrentPointMap,
-                isErrorPoint,
-                pointErrorCount
-            );
+            // This is important: Only smooth around faces that share an
+            // edge with a bad face
+            bool skipFace = true;
 
-            newBadFaces = false;
-            forAll(mesh_.points(), pI)
+            forAll(fEdges, fEdgeI)
             {
-                if (isErrorPoint[origToCurrentPointMap[pI]])
+                const labelList& eFaces = mesh_.edgeFaces()[fEdges[fEdgeI]];
+
+                forAll(eFaces, eFaceI)
                 {
-                    if (!newErrorPoint[pI])
+                    const label eFace = eFaces[eFaceI];
+
+                    const face& f = faces[eFace];
+
+                    forAll(f, fpI)
                     {
-                        newBadFaces = true;
-                        break;
+                        const label ptIndex = oldToNewMesh[f[fpI]];
+
+                        if (isErrorPoint[ptIndex])
+                        {
+                            skipFace = false;
+                            break;
+                        }
+                    }
+
+                    if (eFace != faceI)
+                    {
+                        sumFaceFilterFactors += faceFilterFactor_[eFace];
+                        nFaces++;
                     }
                 }
             }
 
-            reduce(newBadFaces, orOp<bool>());
-        }
-        else
-        {
-            return -1;
+            if (skipFace)
+            {
+                continue;
+            }
+
+            faceFilterFactor_[faceI] = min
+            (
+                faceFilterFactor_[faceI],
+                sumFaceFilterFactors/nFaces
+            );
         }
-    }
 
-    return nBadFaces;
+        // Face filter factor needs to be synchronised!
+        syncTools::syncFaceList(mesh_, faceFilterFactor_, minEqOp<scalar>());
+    }
 }
 
 
-Foam::label Foam::polyMeshFilter::filterEdges
+void Foam::polyMeshFilter::updatePointPriorities
 (
-    const label nOriginalBadFaces
+    const polyMesh& newMesh,
+    const labelList& pointMap
 )
 {
-    label nBadFaces = labelMax/2;
-    label nPreviousBadFaces = labelMax;
-    label nOuterIterations = 0;
+    labelList newPointPriority(newMesh.nPoints(), labelMin);
+    const labelList& currPointPriority = pointPriority_();
 
-    minEdgeLen_.resize(mesh_.nEdges(), minLen_);
-    faceFilterFactor_.resize(0);
+    forAll(newPointPriority, ptI)
+    {
+        const label newPointToOldPoint = pointMap[ptI];
+        const label origPointPriority = currPointPriority[newPointToOldPoint];
 
-    labelList pointErrorCount(mesh_.nPoints(), 0);
+        newPointPriority[ptI] = max(origPointPriority, newPointPriority[ptI]);
+    }
 
-    // Main loop
-    // ~~~~~~~~~
-    // It tries and do some collapses, checks the resulting mesh and
-    // 'freezes' some edges (by marking in minEdgeLen) and tries again.
-    // This will iterate ultimately to the situation where every edge is
-    // frozen and nothing gets collapsed.
-    while
+    syncTools::syncPointList
     (
-        nOuterIterations < maxIterations_
-     && nBadFaces > nOriginalBadFaces
-     && nBadFaces < nPreviousBadFaces
-    )
+        newMesh,
+        newPointPriority,
+        maxEqOp<label>(),
+        labelMin
+    );
+
+    pointPriority_.reset(new labelList(newPointPriority));
+}
+
+
+void Foam::polyMeshFilter::printScalarFieldStats
+(
+    const string desc,
+    const scalarField& fld
+) const
+{
+    scalar sum = 0;
+    scalar validElements = 0;
+    scalar min = GREAT;
+    scalar max = -GREAT;
+
+    forAll(fld, i)
     {
-        Info<< nl << "Outer Iteration = " << nOuterIterations++ << nl
-            << endl;
+        const scalar fldElement = fld[i];
 
-        printScalarFieldStats("Edge Filter Factor", minEdgeLen_);
+        if (fldElement >= 0)
+        {
+            sum += fldElement;
 
-        nPreviousBadFaces = nBadFaces;
+            if (fldElement < min)
+            {
+                min = fldElement;
+            }
 
-        // Reset the new mesh to the old mesh
-        newMeshPtr_ = copyMesh(mesh_);
-        fvMesh& newMesh = newMeshPtr_();
+            if (fldElement > max)
+            {
+                max = fldElement;
+            }
 
-        scalarField newMeshMinEdgeLen = minEdgeLen_;
+            validElements++;
+        }
+    }
 
-        labelList origToCurrentPointMap(identity(newMesh.nPoints()));
+    reduce(sum, sumOp<scalar>());
+    reduce(min, minOp<scalar>());
+    reduce(max, maxOp<scalar>());
+    reduce(validElements, sumOp<label>());
+    const label totFieldSize = returnReduce(fld.size(), sumOp<label>());
 
-        label nInnerIterations = 0;
-        label nPrevLocalCollapse = labelMax;
+    Info<< incrIndent << indent << desc
+        << ": min = " << min
+        << " av = " << sum/(validElements + SMALL)
+        << " max = " << max << nl
+        << indent
+        << "    " << validElements << " / " << totFieldSize << " elements used"
+        << decrIndent << endl;
+}
 
-        Info<< incrIndent;
 
-        while (true)
-        {
-            Info<< nl << indent << "Inner iteration = "
-                << nInnerIterations++ << nl << incrIndent << endl;
+void Foam::polyMeshFilter::mapOldMeshEdgeFieldToNewMesh
+(
+    const polyMesh& newMesh,
+    const labelList& pointMap,
+    scalarField& newMeshMinEdgeLen
+) const
+{
+    scalarField tmp(newMesh.nEdges());
 
-            // Per edge collapse status
-            PackedBoolList collapseEdge(newMesh.nEdges());
+    const edgeList& newEdges = newMesh.edges();
+
+    forAll(newEdges, newEdgeI)
+    {
+        const edge& newEdge = newEdges[newEdgeI];
+        const label pStart = newEdge.start();
+        const label pEnd = newEdge.end();
 
-            Map<point> collapsePointToLocation(newMesh.nPoints());
+        tmp[newEdgeI] = min
+        (
+            newMeshMinEdgeLen[pointMap[pStart]],
+            newMeshMinEdgeLen[pointMap[pEnd]]
+        );
+    }
 
-            // Mark points on boundary
-            const labelList boundaryPoint = findBoundaryPoints(newMesh);
+    newMeshMinEdgeLen.transfer(tmp);
 
-            edgeCollapser collapser(newMesh, collapseFacesCoeffDict_);
+    syncTools::syncEdgeList
+    (
+        newMesh,
+        newMeshMinEdgeLen,
+        maxEqOp<scalar>(),
+        scalar(0.0)
+    );
+}
 
-            // Work out which edges to collapse
-            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-            // This is by looking at minEdgeLen (to avoid frozen edges)
-            // and marking in collapseEdge.
-            label nSmallCollapsed = collapser.markSmallEdges
-            (
-                newMeshMinEdgeLen,
-                boundaryPoint,
-                collapseEdge,
-                collapsePointToLocation
-            );
 
-            reduce(nSmallCollapsed, sumOp<label>());
-            Info<< indent << "Collapsing " << nSmallCollapsed
-                << " small edges" << endl;
+void Foam::polyMeshFilter::mapOldMeshFaceFieldToNewMesh
+(
+    const polyMesh& newMesh,
+    const labelList& faceMap,
+    scalarField& newMeshFaceFilterFactor
+) const
+{
+    scalarField tmp(newMesh.nFaces());
 
-            // Merge inline edges
-            label nMerged = collapser.markMergeEdges
-            (
-                maxCos_,
-                boundaryPoint,
-                collapseEdge,
-                collapsePointToLocation
-            );
+    forAll(faceMap, newFaceI)
+    {
+        const label oldFaceI = faceMap[newFaceI];
 
-            reduce(nMerged, sumOp<label>());
-            Info<< indent << "Collapsing " << nMerged << " in line edges"
-                << endl;
+        tmp[newFaceI] = newMeshFaceFilterFactor[oldFaceI];
+    }
 
-            if (nMerged + nSmallCollapsed == 0)
-            {
-                Info<< decrIndent;
-                Info<< decrIndent;
-                break;
-            }
+    newMeshFaceFilterFactor.transfer(tmp);
 
-            // Merge edge collapses into consistent collapse-network.
-            // Make sure no cells get collapsed.
-            List<pointEdgeCollapse> allPointInfo;
-            const globalIndex globalPoints(newMesh.nPoints());
+    syncTools::syncFaceList
+    (
+        newMesh,
+        newMeshFaceFilterFactor,
+        maxEqOp<scalar>()
+    );
+}
 
-            collapser.consistentCollapse
-            (
-                globalPoints,
-                boundaryPoint,
-                collapsePointToLocation,
-                collapseEdge,
-                allPointInfo
-            );
 
-            label nLocalCollapse = collapseEdge.count();
+void Foam::polyMeshFilter::updateOldToNewPointMap
+(
+    const labelList& currToNew,
+    labelList& origToCurrentPointMap
+) const
+{
+    forAll(origToCurrentPointMap, origPointI)
+    {
+        label oldPointI = origToCurrentPointMap[origPointI];
 
-            reduce(nLocalCollapse, sumOp<label>());
-            Info<< nl << indent << "Collapsing " << nLocalCollapse
-                << " edges after synchronisation and PointEdgeWave" << endl;
+        if (oldPointI < currToNew.size())
+        {
+            label newPointI = currToNew[oldPointI];
 
-            if (nLocalCollapse >= nPrevLocalCollapse)
-            {
-                Info<< decrIndent;
-                Info<< decrIndent;
-                break;
-            }
-            else
+            if (newPointI != -1)
             {
-                nPrevLocalCollapse = nLocalCollapse;
+                origToCurrentPointMap[origPointI] = newPointI;
             }
+        }
+    }
+}
 
-            // Apply collapses to current mesh
-            polyTopoChange newMeshMod(newMesh);
-
-            // Insert mesh refinement into polyTopoChange.
-            collapser.setRefinement(allPointInfo, newMeshMod);
 
-            Info<< indent << "Apply changes to the current mesh"
-                << decrIndent << endl;
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-            // Apply changes to current mesh
-            autoPtr<mapPolyMesh> newMapPtr = newMeshMod.changeMesh
+Foam::polyMeshFilter::polyMeshFilter(const fvMesh& mesh)
+:
+    polyMeshFilterSettings
+    (
+        IOdictionary
+        (
+            IOobject
             (
-                newMesh,
-                false
-            );
-            const mapPolyMesh& newMap = newMapPtr();
+                "collapseDict",
+                mesh.time().system(),
+                mesh.time(),
+                IOobject::MUST_READ,
+                IOobject::NO_WRITE
+            )
+        )
+    ),
+    mesh_(mesh),
+    newMeshPtr_(),
+    originalPointPriority_
+    (
+        IOobject
+        (
+            "pointPriority",
+            mesh.time().timeName(),
+            mesh.time(),
+            IOobject::READ_IF_PRESENT,
+            IOobject::AUTO_WRITE
+        ),
+        labelList(mesh.nPoints(), labelMin)
+    ),
+    pointPriority_(),
+    minEdgeLen_(),
+    faceFilterFactor_()
+{
+    writeSettings(Info);
+}
 
-            // Update fields
-            newMesh.updateMesh(newMap);
-            if (newMap.hasMotionPoints())
-            {
-                newMesh.movePoints(newMap.preMotionPoints());
-            }
 
-            // Relabel the boundary points
-//            labelList newBoundaryPoints(newMesh.nPoints(), -1);
-//            forAll(newBoundaryPoints, pI)
-//            {
-//                const label newToOldptI= map.pointMap()[pI];
-//                newBoundaryPoints[pI] = boundaryIOPts[newToOldptI];
-//            }
-//            boundaryIOPts = newBoundaryPoints;
-
-            // Synchronise the factors
-            mapOldMeshEdgeFieldToNewMesh
+Foam::polyMeshFilter::polyMeshFilter
+(
+    const fvMesh& mesh,
+    const labelList& pointPriority
+)
+:
+    polyMeshFilterSettings
+    (
+        IOdictionary
+        (
+            IOobject
             (
-                newMesh,
-                newMap.pointMap(),
-                newMeshMinEdgeLen
-            );
+                "collapseDict",
+                mesh.time().system(),
+                mesh.time(),
+                IOobject::MUST_READ,
+                IOobject::NO_WRITE
+            )
+        )
+    ),
+    mesh_(mesh),
+    newMeshPtr_(),
+    originalPointPriority_(pointPriority),
+    pointPriority_(),
+    minEdgeLen_(),
+    faceFilterFactor_()
+{
+    writeSettings(Info);
+}
 
-            updateOldToNewPointMap
-            (
-                newMap.reversePointMap(),
-                origToCurrentPointMap
-            );
-        }
 
-        // Mesh check
-        // ~~~~~~~~~~~~~~~~~~
-        // Do not allow collapses in regions of error.
-        // Updates minEdgeLen, nRelaxedEdges
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
-        if (controlMeshQuality_)
-        {
-            PackedBoolList isErrorPoint(newMesh.nPoints());
-            nBadFaces = edgeCollapser::checkMeshQuality
-            (
-                newMesh,
-                meshQualityCoeffDict_,
-                isErrorPoint
-            );
+Foam::polyMeshFilter::~polyMeshFilter()
+{}
 
-            Info<< nl << "    Number of bad faces     : " << nBadFaces << nl
-                << "    Number of marked points : "
-                << returnReduce(isErrorPoint.count(), sumOp<unsigned int>())
-                << endl;
 
-            updatePointErrorCount
-            (
-                isErrorPoint,
-                origToCurrentPointMap,
-                pointErrorCount
-            );
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-            checkMeshEdgesAndRelaxEdges
-            (
-                newMesh,
-                origToCurrentPointMap,
-                isErrorPoint,
-                pointErrorCount
-            );
-        }
-        else
+Foam::label Foam::polyMeshFilter::filter(const label nOriginalBadFaces)
+{
+    minEdgeLen_.resize(mesh_.nEdges(), minLen());
+    faceFilterFactor_.resize(mesh_.nFaces(), initialFaceLengthFactor());
+
+    return filterFacesLoop(nOriginalBadFaces);
+}
+
+
+Foam::label Foam::polyMeshFilter::filter(const faceZone& fZone)
+{
+    minEdgeLen_.resize(mesh_.nEdges(), minLen());
+    faceFilterFactor_.resize(mesh_.nFaces(), initialFaceLengthFactor());
+
+    forAll(faceFilterFactor_, fI)
+    {
+        if (fZone.whichFace(fI) == -1)
         {
-            return -1;
+            faceFilterFactor_[fI] = -1;
         }
     }
 
-    return nBadFaces;
+    return filterFacesLoop(0);
 }
 
 
-Foam::label Foam::polyMeshFilter::filterFaceZone(const faceZone& fZone)
+Foam::label Foam::polyMeshFilter::filterEdges
+(
+    const label nOriginalBadFaces
+)
 {
-    const label nOriginalBadFaces = 0;
-
-    label nBadFaces = labelMax;
+    label nBadFaces = labelMax/2;
+    label nPreviousBadFaces = labelMax;
     label nOuterIterations = 0;
 
-    minEdgeLen_.resize(mesh_.nEdges(), minLen_);
-    faceFilterFactor_.resize(mesh_.nFaces(), initialFaceLengthFactor_);
+    minEdgeLen_.resize(mesh_.nEdges(), minLen());
+    faceFilterFactor_.resize(0);
 
-    // Maintain the number of times a point has been part of a bad face
     labelList pointErrorCount(mesh_.nPoints(), 0);
 
     // Main loop
@@ -1182,251 +976,52 @@ Foam::label Foam::polyMeshFilter::filterFaceZone(const faceZone& fZone)
     // frozen and nothing gets collapsed.
     while
     (
-        nOuterIterations < maxIterations_
+        nOuterIterations < maxIterations()
      && nBadFaces > nOriginalBadFaces
+     && nBadFaces < nPreviousBadFaces
     )
     {
         Info<< nl << "Outer Iteration = " << nOuterIterations++ << nl
             << endl;
 
         printScalarFieldStats("Edge Filter Factor", minEdgeLen_);
-        printScalarFieldStats("Face Filter Factor", faceFilterFactor_);
+
+        nPreviousBadFaces = nBadFaces;
 
         // Reset the new mesh to the old mesh
         newMeshPtr_ = copyMesh(mesh_);
         fvMesh& newMesh = newMeshPtr_();
 
-        scalarField newMeshFaceFilterFactor = faceFilterFactor_;
+        scalarField newMeshMinEdgeLen = minEdgeLen_;
+        pointPriority_.reset(new labelList(originalPointPriority_));
 
         labelList origToCurrentPointMap(identity(newMesh.nPoints()));
-        {
-
-            label nInnerIterations = 0;
-            label nPrevLocalCollapse = labelMax;
-
-            Info<< incrIndent;
-
-            while (true)
-            {
-                Info<< nl << indent << "Inner iteration = "
-                    << nInnerIterations++ << nl << incrIndent << endl;
-
-                // Per edge collapse status
-                PackedBoolList collapseEdge(newMesh.nEdges());
-
-                Map<point> collapsePointToLocation(newMesh.nPoints());
-
-                // Mark points on boundary
-                const labelList boundaryPoint = findBoundaryPoints(newMesh);
-
-                edgeCollapser collapser(newMesh, collapseFacesCoeffDict_);
-
-                {
-                    // Collapse faces
-                    labelPair nCollapsedPtEdge = collapser.markFaceZoneEdges
-                    (
-                        fZone,
-                        newMeshFaceFilterFactor,
-                        boundaryPoint,
-                        collapseEdge,
-                        collapsePointToLocation
-                    );
-
-                    label nCollapsed = 0;
-                    forAll(nCollapsedPtEdge, collapseTypeI)
-                    {
-                        nCollapsed += nCollapsedPtEdge[collapseTypeI];
-                    }
-
-                    reduce(nCollapsed, sumOp<label>());
-
-                    Info<< indent
-                        << "Collapsing " << nCollapsed << " faces"
-                        << " (to point = "
-                        << returnReduce
-                           (
-                               nCollapsedPtEdge.first(),
-                               sumOp<label>()
-                           )
-                        << ", to edge = "
-                        << returnReduce
-                           (
-                               nCollapsedPtEdge.second(),
-                               sumOp<label>()
-                           )
-                        << ")" << endl;
-
-                    if (nCollapsed == 0)
-                    {
-                        Info<< decrIndent;
-                        Info<< decrIndent;
-                        break;
-                    }
-                }
-
-                // Merge edge collapses into consistent collapse-network.
-                // Make sure no cells get collapsed.
-                List<pointEdgeCollapse> allPointInfo;
-                const globalIndex globalPoints(newMesh.nPoints());
-
-                collapser.consistentCollapse
-                (
-                    globalPoints,
-                    boundaryPoint,
-                    collapsePointToLocation,
-                    collapseEdge,
-                    allPointInfo
-                );
-
-                label nLocalCollapse = collapseEdge.count();
-
-                reduce(nLocalCollapse, sumOp<label>());
-                Info<< nl << indent << "Collapsing " << nLocalCollapse
-                    << " edges after synchronisation and PointEdgeWave" << endl;
-
-                if (nLocalCollapse >= nPrevLocalCollapse)
-                {
-                    Info<< decrIndent;
-                    Info<< decrIndent;
-                    break;
-                }
-                else
-                {
-                    nPrevLocalCollapse = nLocalCollapse;
-                }
-
-                {
-                    // Apply collapses to current mesh
-                    polyTopoChange newMeshMod(newMesh);
-
-                    // Insert mesh refinement into polyTopoChange.
-                    collapser.setRefinement(allPointInfo, newMeshMod);
-
-                    Info<< indent << "Apply changes to the current mesh"
-                        << decrIndent << endl;
-
-                    // Apply changes to current mesh
-                    autoPtr<mapPolyMesh> newMapPtr = newMeshMod.changeMesh
-                    (
-                        newMesh,
-                        false
-                    );
-                    const mapPolyMesh& newMap = newMapPtr();
-
-                    // Update fields
-                    newMesh.updateMesh(newMap);
-                    if (newMap.hasMotionPoints())
-                    {
-                        newMesh.movePoints(newMap.preMotionPoints());
-                    }
-
-                    // Relabel the boundary points
-        //            labelList newBoundaryPoints(newMesh.nPoints(), -1);
-        //            forAll(newBoundaryPoints, pI)
-        //            {
-        //                const label newToOldptI= map.pointMap()[pI];
-        //                newBoundaryPoints[pI] = boundaryIOPts[newToOldptI];
-        //            }
-        //            boundaryIOPts = newBoundaryPoints;
-
-
-                    mapOldMeshFaceFieldToNewMesh
-                    (
-                        newMesh,
-                        newMap.faceMap(),
-                        newMeshFaceFilterFactor
-                    );
-
-                    updateOldToNewPointMap
-                    (
-                        newMap.reversePointMap(),
-                        origToCurrentPointMap
-                    );
-                }
-            }
-        }
 
-
-        scalarField newMeshMinEdgeLen = minEdgeLen_;
+        Info<< incrIndent;
 
         label nInnerIterations = 0;
         label nPrevLocalCollapse = labelMax;
 
         while (true)
         {
-            Info<< nl << indent << "Inner iteration = "
-                << nInnerIterations++ << nl << incrIndent << endl;
-
-            // Per edge collapse status
-            PackedBoolList collapseEdge(newMesh.nEdges());
-
-            Map<point> collapsePointToLocation(newMesh.nPoints());
-
-            // Mark points on boundary
-            const labelList boundaryPoint = findBoundaryPoints
-            (
-                newMesh//,
-//                    boundaryIOPts
-            );
+            Info<< nl
+                << indent << "Inner iteration = " << nInnerIterations++ << nl
+                << incrIndent << endl;
 
-            edgeCollapser collapser(newMesh, collapseFacesCoeffDict_);
-
-            // Work out which edges to collapse
-            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-            // This is by looking at minEdgeLen (to avoid frozen edges)
-            // and marking in collapseEdge.
-            label nSmallCollapsed = collapser.markSmallEdges
+            label nLocalCollapse = filterEdges
             (
+                newMesh,
                 newMeshMinEdgeLen,
-                boundaryPoint,
-                collapseEdge,
-                collapsePointToLocation
-            );
-
-            reduce(nSmallCollapsed, sumOp<label>());
-            Info<< indent << "Collapsing " << nSmallCollapsed
-                << " small edges" << endl;
-
-            // Merge inline edges
-            label nMerged = collapser.markMergeEdges
-            (
-                maxCos_,
-                boundaryPoint,
-                collapseEdge,
-                collapsePointToLocation
+                origToCurrentPointMap
             );
 
-            reduce(nMerged, sumOp<label>());
-            Info<< indent << "Collapsing " << nMerged << " in line edges"
-                << endl;
-
-            if (nMerged + nSmallCollapsed == 0)
-            {
-                Info<< decrIndent;
-                break;
-            }
-
-            // Merge edge collapses into consistent collapse-network.
-            // Make sure no cells get collapsed.
-            List<pointEdgeCollapse> allPointInfo;
-            const globalIndex globalPoints(newMesh.nPoints());
+            Info<< decrIndent;
 
-            collapser.consistentCollapse
+            if
             (
-                globalPoints,
-                boundaryPoint,
-                collapsePointToLocation,
-                collapseEdge,
-                allPointInfo
-            );
-
-            label nLocalCollapse = collapseEdge.count();
-
-            reduce(nLocalCollapse, sumOp<label>());
-            Info<< nl << indent << "Collapsing " << nLocalCollapse
-                << " edges after synchronisation and PointEdgeWave" << endl;
-
-            if (nLocalCollapse >= nPrevLocalCollapse)
+                nLocalCollapse >= nPrevLocalCollapse
+             || nLocalCollapse == 0
+            )
             {
                 Info<< decrIndent;
                 break;
@@ -1435,68 +1030,20 @@ Foam::label Foam::polyMeshFilter::filterFaceZone(const faceZone& fZone)
             {
                 nPrevLocalCollapse = nLocalCollapse;
             }
-
-            // Apply collapses to current mesh
-            polyTopoChange newMeshMod(newMesh);
-
-            // Insert mesh refinement into polyTopoChange.
-            collapser.setRefinement(allPointInfo, newMeshMod);
-
-            Info<< indent << "Apply changes to the current mesh"
-                << decrIndent << endl;
-
-            // Apply changes to current mesh
-            autoPtr<mapPolyMesh> newMapPtr = newMeshMod.changeMesh
-            (
-                newMesh,
-                false
-            );
-            const mapPolyMesh& newMap = newMapPtr();
-
-            // Update fields
-            newMesh.updateMesh(newMap);
-            if (newMap.hasMotionPoints())
-            {
-                newMesh.movePoints(newMap.preMotionPoints());
-            }
-
-            // Relabel the boundary points
-//            labelList newBoundaryPoints(newMesh.nPoints(), -1);
-//            forAll(newBoundaryPoints, pI)
-//            {
-//                const label newToOldptI= map.pointMap()[pI];
-//                newBoundaryPoints[pI] = boundaryIOPts[newToOldptI];
-//            }
-//            boundaryIOPts = newBoundaryPoints;
-
-            // Synchronise the factors
-            mapOldMeshEdgeFieldToNewMesh
-            (
-                newMesh,
-                newMap.pointMap(),
-                newMeshMinEdgeLen
-            );
-
-            updateOldToNewPointMap
-            (
-                newMap.reversePointMap(),
-                origToCurrentPointMap
-            );
         }
 
-
         // Mesh check
         // ~~~~~~~~~~~~~~~~~~
         // Do not allow collapses in regions of error.
         // Updates minEdgeLen, nRelaxedEdges
 
-        if (controlMeshQuality_)
+        if (controlMeshQuality())
         {
             PackedBoolList isErrorPoint(newMesh.nPoints());
             nBadFaces = edgeCollapser::checkMeshQuality
             (
                 newMesh,
-                meshQualityCoeffDict_,
+                meshQualityCoeffDict(),
                 isErrorPoint
             );
 
@@ -1519,14 +1066,6 @@ Foam::label Foam::polyMeshFilter::filterFaceZone(const faceZone& fZone)
                 isErrorPoint,
                 pointErrorCount
             );
-
-            checkMeshFacesAndRelaxEdges
-            (
-                newMesh,
-                origToCurrentPointMap,
-                isErrorPoint,
-                pointErrorCount
-            );
         }
         else
         {
@@ -1544,4 +1083,11 @@ const Foam::autoPtr<Foam::fvMesh>& Foam::polyMeshFilter::filteredMesh() const
 }
 
 
+const Foam::autoPtr<Foam::labelList>&
+Foam::polyMeshFilter::pointPriority() const
+{
+    return pointPriority_;
+}
+
+
 // ************************************************************************* //
diff --git a/src/dynamicMesh/polyMeshFilter/polyMeshFilter.H b/src/dynamicMesh/polyMeshFilter/polyMeshFilter.H
index 0f26687608f..95cddd0058c 100644
--- a/src/dynamicMesh/polyMeshFilter/polyMeshFilter.H
+++ b/src/dynamicMesh/polyMeshFilter/polyMeshFilter.H
@@ -43,6 +43,7 @@ SourceFiles
 #include "List.H"
 #include "autoPtr.H"
 #include "scalarField.H"
+#include "polyMeshFilterSettings.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -59,6 +60,8 @@ class faceZone;
 \*---------------------------------------------------------------------------*/
 
 class polyMeshFilter
+:
+    private polyMeshFilterSettings
 {
     // Private data
 
@@ -68,52 +71,9 @@ class polyMeshFilter
         //- Copy of the original mesh to perform the filtering on
         autoPtr<fvMesh> newMeshPtr_;
 
-        //- Dictionary containing the coefficient sub-dictionaries
-        const IOdictionary dict_;
-
-        //- After collapsing, check the mesh quality and redo the collapsing
-        //  iteration if there are too many bad faces in the mesh
-        Switch controlMeshQuality_;
-
-        //- Coefficients for collapsing edges
-        const dictionary& collapseEdgesCoeffDict_;
-
-        //- Coefficients for collapsing faces
-        dictionary collapseFacesCoeffDict_;
-
-        //- Coefficients for controlling the mesh quality
-        dictionary meshQualityCoeffDict_;
-
-        //- Remove edges shorter than this length
-        const scalar minLen_;
-
-        //- Merge points that are only attached to two edges and have an angle
-        //  between the edge greater than this value
-        const scalar maxCos_;
-
-        //- The amount that the local minimum edge length will be reduced by if
-        //  the edge is part of a collapse string that generates poor quality
-        //  faces
-        const scalar edgeReductionFactor_;
-
-        //- Maximum number of outer iterations
-        const label maxIterations_;
-
-        //- Maximum number of smoothing iterations of minEdgeLen_ and
-        //  faceFilterFactor_
-        const label maxSmoothIters_;
-
-        //- Initialisation value of faceFilterFactor_
-        const scalar initialFaceLengthFactor_;
-
-        //- The amount that the local face size factor will be reduced by if
-        //  the face is part of a collapse string that generates poor quality
-        //  faces
-        const scalar faceReductionFactor_;
-
-        //- Maximum number of times a deleted point can be associated with the
-        //  creation of a bad face it is forced to be kept.
-        const label maxPointErrorCount_;
+        //-
+        labelList originalPointPriority_;
+        autoPtr<labelList> pointPriority_;
 
         //- The minimum edge length for each edge
         scalarField minEdgeLen_;
@@ -124,6 +84,22 @@ class polyMeshFilter
 
     // Private Member Functions
 
+        label filterFacesLoop(const label nOriginalBadFaces);
+
+        label filterFaces
+        (
+            polyMesh& newMesh,
+            scalarField& newMeshFaceFilterFactor,
+            labelList& origToCurrentPointMap
+        );
+
+        label filterEdges
+        (
+            polyMesh& newMesh,
+            scalarField& newMeshMinEdgeLen,
+            labelList& origToCurrentPointMap
+        );
+
         //- Increment pointErrorCount for points attached to a bad face
         void updatePointErrorCount
         (
@@ -160,7 +136,11 @@ class polyMeshFilter
         // + >0 : point on a processor patch with that ID
         // @todo Need to mark boundaryEdges as well, as an edge may have two
         //       boundary points but not itself lie on a boundary
-        labelList findBoundaryPoints(const polyMesh& mesh) const;
+        void updatePointPriorities
+        (
+            const polyMesh& newMesh,
+            const labelList& pointMap
+        );
 
         //- Print min/mean/max data for a field
         void printScalarFieldStats
@@ -213,6 +193,9 @@ public:
         //- Construct from fvMesh
         explicit polyMeshFilter(const fvMesh& mesh);
 
+        //- Construct from fvMesh and a label list of point priorities
+        polyMeshFilter(const fvMesh& mesh, const labelList& pointPriority);
+
 
     //- Destructor
     ~polyMeshFilter();
@@ -226,6 +209,8 @@ public:
             //  mesh has actually been filtered.
             const autoPtr<fvMesh>& filteredMesh() const;
 
+            const autoPtr<labelList>& pointPriority() const;
+
 
         // Edit
 
@@ -235,11 +220,11 @@ public:
             //- Filter edges and faces
             label filter(const label nOriginalBadFaces);
 
+            //- Filter all faces that are in the face zone indirectPatchFaces
+            label filter(const faceZone& fZone);
+
             //- Filter edges only.
             label filterEdges(const label nOriginalBadFaces);
-
-            //- Filter all faces that are in the face zone indirectPatchFaces
-            label filterFaceZone(const faceZone& fZone);
 };
 
 
diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.C b/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.C
index 6ea1e748b05..cb6334306e3 100644
--- a/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.C
+++ b/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.C
@@ -182,53 +182,46 @@ void Foam::edgeCollapser::collapseToEdge
     Map<point>& collapsePointToLocation
 ) const
 {
-    const face& f = mesh_.faces()[faceI];
-
     // Negative half
 
-    Foam::point collapseToPtA =
-        collapseAxis*(sum(dNeg)/dNeg.size() - dShift) + fC;
+    Foam::point collapseToPtA(GREAT, GREAT, GREAT);
+        //collapseAxis*(sum(dNeg)/dNeg.size() - dShift) + fC;
 
-    DynamicList<label> faceBoundaryPts(f.size());
-    DynamicList<label> faceFeaturePts(f.size());
+    label maxPriority = labelMin;
+    DynamicList<label> maxPriorityPts(max(dNeg.size(), dPos.size()));
 
     forAll(facePtsNeg, fPtI)
     {
-        if (pointPriority[facePtsNeg[fPtI]] == 1)
+        const label facePointI = facePtsNeg[fPtI];
+        const label facePtPriority = pointPriority[facePointI];
+
+        if (facePtPriority > maxPriority)
         {
-            faceFeaturePts.append(facePtsNeg[fPtI]);
+            maxPriority = facePtPriority;
+            maxPriorityPts.clear();
+            maxPriorityPts.append(facePointI);
         }
-        else if (pointPriority[facePtsNeg[fPtI]] == 0)
+        else if (facePtPriority == maxPriority)
         {
-            faceBoundaryPts.append(facePtsNeg[fPtI]);
+            maxPriorityPts.append(facePointI);
         }
     }
 
-    if (!faceBoundaryPts.empty() || !faceFeaturePts.empty())
+    if (!maxPriorityPts.empty())
     {
-        if (!faceFeaturePts.empty())
+        Foam::point averagePt(vector::zero);
+
+        forAll(maxPriorityPts, ptI)
         {
-            collapseToPtA = pts[faceFeaturePts.first()];
+            averagePt += pts[maxPriorityPts[ptI]];
         }
-        else if (faceBoundaryPts.size() == 2)
-        {
-            collapseToPtA =
-                0.5
-               *(
-                    pts[faceBoundaryPts[0]]
-                  + pts[faceBoundaryPts[1]]
-                );
-        }
-        else if (faceBoundaryPts.size() <= f.size())
-        {
-            face bFace(faceBoundaryPts);
 
-            collapseToPtA = bFace.centre(pts);
-        }
+        collapseToPtA = averagePt/maxPriorityPts.size();
+//        collapseToPtA = pts[maxPriorityPts.first()];
     }
 
-    faceFeaturePts.clear();
-    faceBoundaryPts.clear();
+    maxPriority = labelMin;
+    maxPriorityPts.clear();
 
     labelList faceEdgesNeg = edgesFromPoints(faceI, facePtsNeg);
 
@@ -244,47 +237,37 @@ void Foam::edgeCollapser::collapseToEdge
 
 
     // Positive half
-
-    Foam::point collapseToPtB
-        = collapseAxis*(sum(dPos)/dPos.size() - dShift) + fC;
+    Foam::point collapseToPtB(GREAT, GREAT, GREAT);
+//        = collapseAxis*(sum(dPos)/dPos.size() - dShift) + fC;
 
     forAll(facePtsPos, fPtI)
     {
-        if (pointPriority[facePtsPos[fPtI]] == 1)
+        const label facePointI = facePtsPos[fPtI];
+        const label facePtPriority = pointPriority[facePointI];
+
+        if (facePtPriority > maxPriority)
         {
-            faceFeaturePts.append(facePtsPos[fPtI]);
+            maxPriority = facePtPriority;
+            maxPriorityPts.clear();
+            maxPriorityPts.append(facePointI);
         }
-        else if (pointPriority[facePtsPos[fPtI]] == 0)
+        else if (facePtPriority == maxPriority)
         {
-            // If there is a point which is on the boundary,
-            // use it as the point to collapse others to, will
-            // use the first boundary point encountered if
-            // there are multiple boundary points.
-            faceBoundaryPts.append(facePtsPos[fPtI]);
+            maxPriorityPts.append(facePointI);
         }
     }
 
-    if (!faceBoundaryPts.empty() || !faceFeaturePts.empty())
+    if (!maxPriorityPts.empty())
     {
-        if (!faceFeaturePts.empty())
+        Foam::point averagePt(vector::zero);
+
+        forAll(maxPriorityPts, ptI)
         {
-            collapseToPtB = pts[faceFeaturePts.first()];
+            averagePt += pts[maxPriorityPts[ptI]];
         }
-        else if (faceBoundaryPts.size() == 2)
-        {
-            collapseToPtB =
-                0.5
-               *(
-                    pts[faceBoundaryPts[0]]
-                  + pts[faceBoundaryPts[1]]
-                );
-        }
-        else if (faceBoundaryPts.size() <= f.size())
-        {
-            face bFace(faceBoundaryPts);
 
-            collapseToPtB = bFace.centre(pts);
-        }
+        collapseToPtB = averagePt/maxPriorityPts.size();
+//        collapseToPtB = pts[maxPriorityPts.first()];
     }
 
     labelList faceEdgesPos = edgesFromPoints(faceI, facePtsPos);
@@ -316,45 +299,79 @@ void Foam::edgeCollapser::collapseToPoint
 
     Foam::point collapseToPt = fC;
 
-    DynamicList<label> faceBoundaryPts(f.size());
-    DynamicList<label> faceFeaturePts(f.size());
+    label maxPriority = labelMin;
+    DynamicList<label> maxPriorityPts(f.size());
 
     forAll(facePts, fPtI)
     {
-        if (pointPriority[facePts[fPtI]] == 1)
+        const label facePointI = facePts[fPtI];
+        const label facePtPriority = pointPriority[facePointI];
+
+        if (facePtPriority > maxPriority)
         {
-            faceFeaturePts.append(facePts[fPtI]);
+            maxPriority = facePtPriority;
+            maxPriorityPts.clear();
+            maxPriorityPts.append(facePointI);
         }
-        else if (pointPriority[facePts[fPtI]] == 0)
+        else if (facePtPriority == maxPriority)
         {
-            faceBoundaryPts.append(facePts[fPtI]);
+            maxPriorityPts.append(facePointI);
         }
     }
 
-    if (!faceBoundaryPts.empty() || !faceFeaturePts.empty())
+    if (!maxPriorityPts.empty())
     {
-        if (!faceFeaturePts.empty())
+        Foam::point averagePt(vector::zero);
+
+        forAll(maxPriorityPts, ptI)
         {
-            collapseToPt = pts[faceFeaturePts.first()];
+            averagePt += pts[maxPriorityPts[ptI]];
         }
-        else if (faceBoundaryPts.size() == 2)
-        {
-            collapseToPt =
-                0.5
-               *(
-                    pts[faceBoundaryPts[0]]
-                  + pts[faceBoundaryPts[1]]
-                );
-        }
-        else if (faceBoundaryPts.size() <= f.size())
-        {
-            face bFace(faceBoundaryPts);
 
-            collapseToPt = bFace.centre(pts);
-        }
+        collapseToPt = averagePt/maxPriorityPts.size();
+
+//        collapseToPt = pts[maxPriorityPts.first()];
     }
 
-    const labelList faceEdges = mesh_.faceEdges()[faceI];
+//    DynamicList<label> faceBoundaryPts(f.size());
+//    DynamicList<label> faceFeaturePts(f.size());
+//
+//    forAll(facePts, fPtI)
+//    {
+//        if (pointPriority[facePts[fPtI]] == 1)
+//        {
+//            faceFeaturePts.append(facePts[fPtI]);
+//        }
+//        else if (pointPriority[facePts[fPtI]] == 0)
+//        {
+//            faceBoundaryPts.append(facePts[fPtI]);
+//        }
+//    }
+//
+//    if (!faceBoundaryPts.empty() || !faceFeaturePts.empty())
+//    {
+//        if (!faceFeaturePts.empty())
+//        {
+//            collapseToPt = pts[faceFeaturePts.first()];
+//        }
+//        else if (faceBoundaryPts.size() == 2)
+//        {
+//            collapseToPt =
+//                0.5
+//               *(
+//                    pts[faceBoundaryPts[0]]
+//                  + pts[faceBoundaryPts[1]]
+//                );
+//        }
+//        else if (faceBoundaryPts.size() <= f.size())
+//        {
+//            face bFace(faceBoundaryPts);
+//
+//            collapseToPt = bFace.centre(pts);
+//        }
+//    }
+
+    const labelList& faceEdges = mesh_.faceEdges()[faceI];
 
     forAll(faceEdges, eI)
     {
@@ -740,35 +757,51 @@ Foam::label Foam::edgeCollapser::edgeMaster
 {
     label masterPoint = -1;
 
-    label e0 = e.start();
-    label e1 = e.end();
+    const label e0 = e.start();
+    const label e1 = e.end();
 
-    // Collapse edge to point with higher priority.
-    if (pointPriority[e0] >= 0)
+    const label e0Priority = pointPriority[e0];
+    const label e1Priority = pointPriority[e1];
+
+    if (e0Priority > e1Priority)
     {
-        if (pointPriority[e1] >= 0)
-        {
-            // Both points have high priority. Choose one to collapse to.
-            // Note: should look at feature edges/points!
-            masterPoint = e0;
-        }
-        else
-        {
-            masterPoint = e0;
-        }
+        masterPoint = e0;
     }
-    else
+    else if (e0Priority < e1Priority)
     {
-        if (pointPriority[e1] >= 0)
-        {
-            masterPoint = e1;
-        }
-        else
-        {
-            // None on boundary. Neither is a master.
-            return -1;
-        }
+        masterPoint = e1;
     }
+    else if (e0Priority == e1Priority)
+    {
+        masterPoint = e0;
+    }
+
+//    // Collapse edge to point with higher priority.
+//    if (pointPriority[e0] >= 0)
+//    {
+//        if (pointPriority[e1] >= 0)
+//        {
+//            // Both points have high priority. Choose one to collapse to.
+//            // Note: should look at feature edges/points!
+//            masterPoint = e0;
+//        }
+//        else
+//        {
+//            masterPoint = e0;
+//        }
+//    }
+//    else
+//    {
+//        if (pointPriority[e1] >= 0)
+//        {
+//            masterPoint = e1;
+//        }
+//        else
+//        {
+//            // None on boundary. Neither is a master.
+//            return -1;
+//        }
+//    }
 
     return masterPoint;
 }
@@ -784,7 +817,10 @@ void Foam::edgeCollapser::checkBoundaryPointMergeEdges
 {
    const pointField& points = mesh_.points();
 
-   if (pointPriority[pointI] >= 0 && pointPriority[otherPointI] < 0)
+   const label e0Priority = pointPriority[pointI];
+   const label e1Priority = pointPriority[otherPointI];
+
+   if (e0Priority > e1Priority)
    {
        collapsePointToLocation.set
        (
@@ -792,13 +828,29 @@ void Foam::edgeCollapser::checkBoundaryPointMergeEdges
            points[pointI]
        );
    }
-   else
+   else if (e0Priority < e1Priority)
+   {
+       collapsePointToLocation.set
+       (
+           pointI,
+           points[otherPointI]
+       );
+   }
+   else // e0Priority == e1Priority
    {
        collapsePointToLocation.set
        (
            pointI,
            points[otherPointI]
        );
+
+//       Foam::point averagePt
+//       (
+//           0.5*(points[otherPointI] + points[pointI])
+//       );
+//
+//       collapsePointToLocation.set(pointI, averagePt);
+//       collapsePointToLocation.set(otherPointI, averagePt);
    }
 }
 
@@ -1963,7 +2015,7 @@ Foam::labelPair Foam::edgeCollapser::markSmallSliverFaces
     {
         const face& f = faces[fI];
 
-        if (faceFilterFactor[fI] == 0)
+        if (faceFilterFactor[fI] <= 0)
         {
             continue;
         }
@@ -2030,7 +2082,7 @@ Foam::labelPair Foam::edgeCollapser::markFaceZoneEdges
 
         const face& f = faces[fI];
 
-        if (faceFilterFactor[fI] == 0)
+        if (faceFilterFactor[fI] <= 0)
         {
             continue;
         }
-- 
GitLab