diff --git a/applications/utilities/mesh/advanced/collapseEdges/Make/files b/applications/utilities/mesh/advanced/collapseEdges/Make/files
index d89ca6e737c6c84ce878bd4e57566fbd070333a4..a15838abe84da087d0c63693617ed5b410e56b22 100644
--- a/applications/utilities/mesh/advanced/collapseEdges/Make/files
+++ b/applications/utilities/mesh/advanced/collapseEdges/Make/files
@@ -1,3 +1,4 @@
 collapseEdges.C
+pointEdgeCollapse/pointEdgeCollapse.C
 
 EXE = $(FOAM_APPBIN)/collapseEdges
diff --git a/applications/utilities/mesh/advanced/collapseEdges/Make/options b/applications/utilities/mesh/advanced/collapseEdges/Make/options
index 21b17b14c9d7dd8ae8c0c55fdcf698ce54019fcb..d1efa61fd56aef52623d7e352c300f8948503fd2 100644
--- a/applications/utilities/mesh/advanced/collapseEdges/Make/options
+++ b/applications/utilities/mesh/advanced/collapseEdges/Make/options
@@ -1,6 +1,10 @@
 EXE_INC = \
-    -I$(LIB_SRC)/dynamicMesh/lnInclude
+    -I$(LIB_SRC)/dynamicMesh/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -IpointEdgeCollapse
 
 EXE_LIBS = \
     -ldynamicMesh \
-    -lmeshTools
+    -lmeshTools \
+    -lfiniteVolume
diff --git a/applications/utilities/mesh/advanced/collapseEdges/collapseEdges.C b/applications/utilities/mesh/advanced/collapseEdges/collapseEdges.C
index f1eb28e5947759fe22aee59bf0c28a3ed3a2c0f0..899159b2a29ba4005f6fdd740260f1fee794674b 100644
--- a/applications/utilities/mesh/advanced/collapseEdges/collapseEdges.C
+++ b/applications/utilities/mesh/advanced/collapseEdges/collapseEdges.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -41,170 +41,634 @@ Description
 
 #include "argList.H"
 #include "Time.H"
-#include "edgeCollapser.H"
 #include "polyTopoChange.H"
 #include "polyTopoChanger.H"
 #include "polyMesh.H"
+#include "fvMesh.H"
 #include "mapPolyMesh.H"
 #include "mathematicalConstants.H"
 #include "PackedBoolList.H"
 #include "SortableList.H"
 #include "unitConversion.H"
+#include "globalMeshData.H"
+#include "globalIndex.H"
+#include "PointEdgeWave.H"
+#include "pointEdgeCollapse.H"
+#include "motionSmoother.H"
+
+#include "OFstream.H"
+#include "meshTools.H"
 
 using namespace Foam;
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-// Get faceEdges in order of face points, i.e. faceEdges[0] is between
-// f[0] and f[1]
-labelList getSortedEdges
+label findIndex
 (
-    const edgeList& edges,
-    const labelList& f,
-    const labelList& edgeLabels
+    const labelList& elems,
+    const label start,
+    const label size,
+    const label val
 )
 {
-    labelList faceEdges(edgeLabels.size(), -1);
+    for (label i = start; i < size; i++)
+    {
+        if (elems[i] == val)
+        {
+            return i;
+        }
+    }
+    return -1;
+}
 
-    // Find starting pos in f for every edgeLabels
-    forAll(edgeLabels, i)
+
+void filterFace
+(
+    const label faceI,
+    face& f,
+    const List<pointEdgeCollapse>& allPointInfo,
+    const Map<DynamicList<label> >& collapseStrings
+)
+{
+    label newFp = 0;
+
+    face oldFace = f;
+
+    forAll(f, fp)
     {
-        label edgeI = edgeLabels[i];
+        label pointI = f[fp];
 
-        const edge& e = edges[edgeI];
+        label collapsePoint = allPointInfo[pointI].collapseIndex();
 
-        label fp = findIndex(f, e[0]);
-        label fp1 = f.fcIndex(fp);
+        if (collapseStrings.found(collapsePoint))
+        {
+            collapsePoint = collapseStrings[collapsePoint][0];
+        }
 
-        if (f[fp1] == e[1])
+        if (collapsePoint == -1)
         {
-            // EdgeI between fp -> fp1
-            faceEdges[fp] = edgeI;
+            WarningIn
+                (
+                    "filterFace"
+                    "(const label, face&, const List<pointEdgeCollapse>&)"
+                )
+                << "Point " << pointI << " was not visited by PointEdgeWave"
+                << endl;
+        }
+        else if (collapsePoint == -2)
+        {
+            f[newFp++] = pointI;
         }
         else
         {
-            // EdgeI between fp-1 -> fp
-            faceEdges[f.rcIndex(fp)] = edgeI;
+            if (findIndex(f, 0, newFp, collapsePoint) == -1)
+            {
+                f[newFp++] = collapsePoint;
+            }
         }
     }
 
-    return faceEdges;
+
+    // Check for pinched face. Tries to correct
+    // - consecutive duplicate vertex. Removes duplicate vertex.
+    // - duplicate vertex with one other vertex in between (spike).
+    // Both of these should not really occur! and should be checked before
+    // collapsing edges.
+
+    const label size = newFp;
+
+    newFp = 2;
+
+    for (label fp = 2; fp < size; fp++)
+    {
+        label fp1 = fp-1;
+        label fp2 = fp-2;
+
+        label pointI = f[fp];
+
+        // Search for previous occurrence.
+        label index = findIndex(f, 0, fp, pointI);
+
+        if (index == fp1)
+        {
+            WarningIn
+            (
+                "Foam::edgeCollapser::filterFace(const label faceI, "
+                "face& f) const"
+            )   << "Removing consecutive duplicate vertex in face "
+                << f << endl;
+            // Don't store current pointI
+        }
+        else if (index == fp2)
+        {
+            WarningIn
+            (
+                "Foam::edgeCollapser::filterFace(const label faceI, "
+                "face& f) const"
+            )   << "Removing non-consecutive duplicate vertex in face "
+                << f << endl;
+            // Don't store current pointI and remove previous
+            newFp--;
+        }
+        else if (index != -1)
+        {
+            WarningIn
+            (
+                "Foam::edgeCollapser::filterFace(const label faceI, "
+                "face& f) const"
+            )   << "Pinched face " << f << endl;
+            f[newFp++] = pointI;
+        }
+        else
+        {
+            f[newFp++] = pointI;
+        }
+    }
+
+    f.setSize(newFp);
 }
 
 
-// Merges edges which are in straight line. I.e. edge split by point.
-label mergeEdges
+bool setRefinement
 (
     const polyMesh& mesh,
-    const scalar maxCos,
-    edgeCollapser& collapser
+    polyTopoChange& meshMod,
+    const List<pointEdgeCollapse>& allPointInfo
 )
 {
-    const pointField& points = mesh.points();
-    const edgeList& edges = mesh.edges();
-    const labelListList& pointEdges = mesh.pointEdges();
-    const labelList& region = collapser.pointRegion();
-    const labelList& master = collapser.pointRegionMaster();
+    const cellList& cells = mesh.cells();
+    const labelList& faceOwner = mesh.faceOwner();
+    const labelList& faceNeighbour = mesh.faceNeighbour();
+    const labelListList& pointFaces = mesh.pointFaces();
+    const pointZoneMesh& pointZones = mesh.pointZones();
 
+    globalIndex globalStrings(mesh.nPoints());
+
+    boolList removedPoints(mesh.nPoints(), false);
+
+    // Create strings of edges
+    Map<DynamicList<label> > collapseStrings;
+
+    forAll(allPointInfo, pointI)
+    {
+        const label collapseIndex = allPointInfo[pointI].collapseIndex();
+
+        if (collapseIndex != -1 && collapseIndex != -2)
+        {
+            collapseStrings(collapseIndex).append(pointI);
+        }
+    }
+
+    bool meshChanged = false;
+
+    // Current faces (is also collapseStatus: f.size() < 3)
+    faceList newFaces(mesh.faces());
+
+    // Current cellCollapse status
+    boolList cellRemoved(mesh.nCells(), false);
+
+    label nUnvisited = 0;
+    label nUncollapsed = 0;
     label nCollapsed = 0;
 
-    forAll(pointEdges, pointI)
+    forAll(allPointInfo, pI)
     {
-        const labelList& pEdges = pointEdges[pointI];
+        const pointEdgeCollapse& pec = allPointInfo[pI];
 
-        if (pEdges.size() == 2)
+        if (pec.collapseIndex() == -1)
+        {
+            nUnvisited++;
+        }
+        else if (pec.collapseIndex() == -2)
         {
-            const edge& leftE = edges[pEdges[0]];
-            const edge& rightE = edges[pEdges[1]];
+            nUncollapsed++;
+        }
+        else if (pec.collapseIndex() >= 0)
+        {
+            nCollapsed++;
+        }
+    }
+
+    label nPoints = allPointInfo.size();
+
+    reduce(nPoints, sumOp<label>());
+    reduce(nUnvisited, sumOp<label>());
+    reduce(nUncollapsed, sumOp<label>());
+    reduce(nCollapsed, sumOp<label>());
 
-            // Get the two vertices on both sides of the point
-            label leftV = leftE.otherVertex(pointI);
-            label rightV = rightE.otherVertex(pointI);
+    Info<< incrIndent;
+    Info<< indent << "Number of points : " << nPoints << nl
+        << indent << "Not visited      : " << nUnvisited << nl
+        << indent << "Not collapsed    : " << nUncollapsed << nl
+        << indent << "Collapsed        : " << nCollapsed << nl
+        << endl;
+    Info<< decrIndent;
 
-            // Collapse only if none of the points part of merge network
-            // or all of networks with different masters.
-            label midMaster = -1;
-            if (region[pointI] != -1)
+    do
+    {
+        // Update face collapse from edge collapses
+        forAll(newFaces, faceI)
+        {
+            filterFace(faceI, newFaces[faceI], allPointInfo, collapseStrings);
+        }
+
+        // Check if faces to be collapsed cause cells to become collapsed.
+        label nCellCollapsed = 0;
+
+        forAll(cells, cellI)
+        {
+            if (!cellRemoved[cellI])
             {
-                midMaster = master[region[pointI]];
+                const cell& cFaces = cells[cellI];
+
+                label nFaces = cFaces.size();
+
+                forAll(cFaces, i)
+                {
+                    label faceI = cFaces[i];
+
+                    if (newFaces[faceI].size() < 3)
+                    {
+                        --nFaces;
+
+                        if (nFaces < 4)
+                        {
+                            Info<< "Cell:" << cellI
+                                << " uses faces:" << cFaces
+                                << " of which too many are marked for removal:"
+                                << endl
+                                << "   ";
+                            forAll(cFaces, j)
+                            {
+                                if (newFaces[cFaces[j]].size() < 3)
+                                {
+                                    Info<< ' '<< cFaces[j];
+                                }
+                            }
+                            Info<< endl;
+
+                            cellRemoved[cellI] = true;
+
+                            // Collapse all edges of cell to nothing
+                            //collapseEdges(cellEdges[cellI]);
+
+                            nCellCollapsed++;
+
+                            break;
+                        }
+                    }
+                }
             }
+        }
+
+        if (nCellCollapsed == 0)
+        {
+            break;
+        }
+    } while (true);
+
+
+    // Keep track of faces that have been done already.
+    boolList doneFace(mesh.nFaces(), false);
+
+    {
+        // Mark points used.
+        boolList usedPoint(mesh.nPoints(), false);
 
-            label leftMaster = -2;
-            if (region[leftV] != -1)
+        forAll(cellRemoved, cellI)
+        {
+            if (cellRemoved[cellI])
             {
-                leftMaster = master[region[leftV]];
+                meshMod.removeCell(cellI, -1);
             }
+        }
+
+        // Remove faces
+        forAll(newFaces, faceI)
+        {
+            const face& f = newFaces[faceI];
+
+            if (f.size() < 3)
+            {
+                meshMod.removeFace(faceI, -1);
+                meshChanged = true;
 
-            label rightMaster = -3;
-            if (region[rightV] != -1)
+                // Mark face as been done.
+                doneFace[faceI] = true;
+            }
+            else
             {
-                rightMaster = master[region[rightV]];
+                // Kept face. Mark vertices
+                forAll(f, fp)
+                {
+                    usedPoint[f[fp]] = true;
+                }
             }
+        }
 
-            if
-            (
-                midMaster != leftMaster
-             && midMaster != rightMaster
-             && leftMaster != rightMaster
-            )
+        // Remove unused vertices that have not been marked for removal already
+        forAll(usedPoint, pointI)
+        {
+            if (!usedPoint[pointI])
             {
-                // Check if the two edge are in line
-                vector leftVec = points[pointI] - points[leftV];
-                leftVec /= mag(leftVec) + VSMALL;
+                removedPoints[pointI] = true;
+                meshMod.removePoint(pointI, -1);
+                meshChanged = true;
+            }
+        }
+    }
+
+    // Modify the point location of the remaining points
+    forAll(allPointInfo, pointI)
+    {
+        const label collapseIndex = allPointInfo[pointI].collapseIndex();
+        const point& collapsePoint = allPointInfo[pointI].collapsePoint();
+
+        if
+        (
+            removedPoints[pointI] == false
+         && collapseIndex != -1
+         && collapseIndex != -2
+        )
+        {
+            meshMod.modifyPoint
+            (
+                pointI,
+                collapsePoint,
+                pointZones.whichZone(pointI),
+                false
+            );
+        }
+    }
+
+
+    const polyBoundaryMesh& boundaryMesh = mesh.boundaryMesh();
+    const faceZoneMesh& faceZones = mesh.faceZones();
+
+    // Renumber faces that use points
+    forAll(allPointInfo, pointI)
+    {
+        if (removedPoints[pointI] == true)
+        {
+            const labelList& changedFaces = pointFaces[pointI];
 
-                vector rightVec = points[rightV] - points[pointI];
-                rightVec /= mag(rightVec) + VSMALL;
+            forAll(changedFaces, changedFaceI)
+            {
+                label faceI = changedFaces[changedFaceI];
 
-                if ((leftVec & rightVec) > maxCos)
+                if (!doneFace[faceI])
                 {
-                    // Collapse one (left) side of the edge. Make left vertex
-                    // the master.
-                    //if (collapser.unaffectedEdge(pEdges[0]))
+                    doneFace[faceI] = true;
+
+                    // Get current zone info
+                    label zoneID = faceZones.whichZone(faceI);
+
+                    bool zoneFlip = false;
+
+                    if (zoneID >= 0)
                     {
-                        collapser.collapseEdge(pEdges[0], leftV);
-                        nCollapsed++;
+                        const faceZone& fZone = faceZones[zoneID];
+
+                        zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
+                    }
+
+                    // Get current connectivity
+                    label own = faceOwner[faceI];
+                    label nei = -1;
+                    label patchID = -1;
+
+                    if (mesh.isInternalFace(faceI))
+                    {
+                        nei = faceNeighbour[faceI];
+                    }
+                    else
+                    {
+                        patchID = boundaryMesh.whichPatch(faceI);
                     }
+
+                    meshMod.modifyFace
+                    (
+                        newFaces[faceI],            // face
+                        faceI,                      // faceI to change
+                        own,                        // owner
+                        nei,                        // neighbour
+                        false,                      // flipFaceFlux
+                        patchID,                    // patch
+                        zoneID,
+                        zoneFlip
+                    );
+                    meshChanged = true;
                 }
             }
         }
     }
 
-    return nCollapsed;
+    // Print regions:
+//    printRegions();
+
+    return meshChanged;
+}
+
+
+// Get faceEdges in order of face points, i.e. faceEdges[0] is between
+// f[0] and f[1]
+labelList getSortedEdges
+(
+    const edgeList& edges,
+    const labelList& f,
+    const labelList& edgeLabels
+)
+{
+    labelList faceEdges(edgeLabels.size(), -1);
+
+    // Find starting pos in f for every edgeLabels
+    forAll(edgeLabels, i)
+    {
+        label edgeI = edgeLabels[i];
+
+        const edge& e = edges[edgeI];
+
+        label fp = findIndex(f, e[0]);
+        label fp1 = f.fcIndex(fp);
+
+        if (f[fp1] == e[1])
+        {
+            // EdgeI between fp -> fp1
+            faceEdges[fp] = edgeI;
+        }
+        else
+        {
+            // EdgeI between fp-1 -> fp
+            faceEdges[f.rcIndex(fp)] = edgeI;
+        }
+    }
+
+    return faceEdges;
 }
 
 
+// Merges edges which are in straight line. I.e. edge split by point.
+//label mergeEdges
+//(
+//    const polyMesh& mesh,
+//    const scalar maxCos,
+//    List<pointEdgeCollapse>& allPointInfo
+//)
+//{
+//    const pointField& points = mesh.points();
+//    const edgeList& edges = mesh.edges();
+//    const labelListList& pointEdges = mesh.pointEdges();
+//    const labelList& region = collapser.pointRegion();
+//    const labelList& master = collapser.pointRegionMaster();
+//
+//    label nCollapsed = 0;
+//
+//    forAll(pointEdges, pointI)
+//    {
+//        const labelList& pEdges = pointEdges[pointI];
+//
+//        if (pEdges.size() == 2)
+//        {
+//            const edge& leftE = edges[pEdges[0]];
+//            const edge& rightE = edges[pEdges[1]];
+//
+//            // Get the two vertices on both sides of the point
+//            label leftV = leftE.otherVertex(pointI);
+//            label rightV = rightE.otherVertex(pointI);
+//
+//            // Collapse only if none of the points part of merge network
+//            // or all of networks with different masters.
+//            label midMaster = -1;
+//            if (region[pointI] != -1)
+//            {
+//                midMaster = master[region[pointI]];
+//            }
+//
+//            label leftMaster = -2;
+//            if (region[leftV] != -1)
+//            {
+//                leftMaster = master[region[leftV]];
+//            }
+//
+//            label rightMaster = -3;
+//            if (region[rightV] != -1)
+//            {
+//                rightMaster = master[region[rightV]];
+//            }
+//
+//            if
+//            (
+//                midMaster != leftMaster
+//             && midMaster != rightMaster
+//             && leftMaster != rightMaster
+//            )
+//            {
+//                // Check if the two edge are in line
+//                vector leftVec = points[pointI] - points[leftV];
+//                leftVec /= mag(leftVec) + VSMALL;
+//
+//                vector rightVec = points[rightV] - points[pointI];
+//                rightVec /= mag(rightVec) + VSMALL;
+//
+//                if ((leftVec & rightVec) > maxCos)
+//                {
+//                    // Collapse one (left) side of the edge. Make left vertex
+//                    // the master.
+//                    //if (collapser.unaffectedEdge(pEdges[0]))
+//                    const edge& e = mesh.edges()[pEdges[0]];
+//
+//                    if
+//                    (
+//                        allPointInfo[e[0]].collapseIndex() < 0
+//                     && allPointInfo[e[1]].collapseIndex() < 0
+//                    )
+//                    {
+//                        //pointEdgeCollapse pec(mesh.points()[leftV], leftV);
+//
+//                        allPointInfo[e[0]] = pec;
+//                        allPointInfo[e[1]] = pec;
+//
+//                        //collapser.collapseEdge(pEdges[0], leftV);
+//                        nCollapsed++;
+//                    }
+//                }
+//            }
+//        }
+//    }
+//
+//    return nCollapsed;
+//}
+
+
 // Return master point edge needs to be collapsed to (or -1)
-label edgeMaster(const PackedBoolList& boundaryPoint, const edge& e)
+label edgeMaster
+(
+    const labelList& boundaryPoint,
+    const bool flipEdge,
+    const edge& e
+)
 {
     label masterPoint = -1;
 
+    label e0 = e[0];
+    label e1 = e[1];
+
+    if (flipEdge)
+    {
+        e0 = e[1];
+        e1 = e[0];
+    }
+
+    // Check if one of the points is on a processor
+//    if
+//    (
+//        boundaryPoint[e0] > 0
+//     && boundaryPoint[e1] > 0
+//    )
+//    {
+//        if (boundaryPoint[e0] != boundaryPoint[e1])
+//        {
+//            return -1;
+//        }
+//    }
+//
+//    if (boundaryPoint[e0] > 0)
+//    {
+//        return e0;
+//    }
+//    else if (boundaryPoint[e1] > 0)
+//    {
+//        return e1;
+//    }
+
     // Collapse edge to boundary point.
-    if (boundaryPoint.get(e[0]))
+    if (boundaryPoint[e0] == 0)
     {
-        if (boundaryPoint.get(e[1]))
+        if (boundaryPoint[e1] == 0)
         {
             // Both points on boundary. Choose one to collapse to.
             // Note: should look at feature edges/points!
-            masterPoint = e[0];
+            masterPoint = e0;
         }
         else
         {
-            masterPoint = e[0];
+            masterPoint = e0;
         }
     }
     else
     {
-        if (boundaryPoint.get(e[1]))
+        if (boundaryPoint[e1] == 0)
         {
-            masterPoint = e[1];
+            masterPoint = e1;
         }
         else
         {
             // None on boundary. Choose arbitrary.
             // Note: should look at geometry?
-            masterPoint = e[0];
+            masterPoint = e0;
         }
     }
+
     return masterPoint;
 }
 
@@ -212,124 +676,266 @@ label edgeMaster(const PackedBoolList& boundaryPoint, const edge& e)
 label collapseSmallEdges
 (
     const polyMesh& mesh,
-    const PackedBoolList& boundaryPoint,
+    const scalarList& freezeEdges,
+    const labelList& boundaryPoint,
     const scalar minLen,
-    edgeCollapser& collapser
+    List<pointEdgeCollapse>& allPointInfo
 )
 {
     const pointField& points = mesh.points();
     const edgeList& edges = mesh.edges();
 
-    // Collapse all edges that are too small. Choose intelligently which
-    // point to collapse edge to.
-
-    label nCollapsed = 0;
+    // Store collapse direction in collapseEdge
+    //   -1 -> Do not collapse
+    //    0 -> Collapse to start point
+    //    1 -> Collapse to end point
+    labelList collapseEdge(edges.size(), -1);
 
     forAll(edges, edgeI)
     {
         const edge& e = edges[edgeI];
 
-        if (e.mag(points) < minLen)
+        if (e.mag(points) < minLen*freezeEdges[edgeI])
         {
-            label master = edgeMaster(boundaryPoint, e);
-
-            if (master != -1) // && collapser.unaffectedEdge(edgeI))
-            {
-                collapser.collapseEdge(edgeI, master);
-                nCollapsed++;
-            }
+            collapseEdge[edgeI] = 0;
         }
     }
-    return nCollapsed;
-}
-
-
-// Faces which have edges just larger than collapse length but faces which
-// are very small. This one tries to collapse them if it can be done with
-// edge collapse. For faces where a face gets replace by two edges use
-// collapseFaces
-label collapseHighAspectFaces
-(
-    const polyMesh& mesh,
-    const PackedBoolList& boundaryPoint,
-    const scalar areaFac,
-    const scalar edgeRatio,
-    edgeCollapser& collapser
-)
-{
-    const pointField& points = mesh.points();
-    const edgeList& edges = mesh.edges();
-    const faceList& faces = mesh.faces();
-    const labelListList& faceEdges = mesh.faceEdges();
 
-    scalarField magArea(mag(mesh.faceAreas()));
+    // Check whether edge point order is reversed from mesh to coupledPatch
+//    const globalMeshData& globalData = mesh.globalData();
+//    const mapDistribute& map = globalData.globalEdgeSlavesMap();
+//    const labelList& coupledMeshEdges = globalData.coupledPatchMeshEdges();
+//    const indirectPrimitivePatch& coupledPatch = globalData.coupledPatch();
+//    const PackedBoolList& cppOrientation = globalData.globalEdgeOrientation();
+//    PackedBoolList meshToPatchSameOrientation(coupledMeshEdges.size(), true);
+//
+//    forAll(coupledMeshEdges, eI)
+//    {
+//        const label meshEdgeIndex = coupledMeshEdges[eI];
+//
+//        if (collapseEdge[meshEdgeIndex] != -1)
+//        {
+//            const edge& meshEdge = edges[meshEdgeIndex];
+//            const edge& coupledPatchEdge = coupledPatch.edges()[eI];
+//
+//            if
+//            (
+//                meshEdge[0] == coupledPatch.meshPoints()[coupledPatchEdge[1]]
+//             && meshEdge[1] == coupledPatch.meshPoints()[coupledPatchEdge[0]]
+//            )
+//            {
+//                meshToPatchSameOrientation[eI] = false;
+//            }
+//        }
+//    }
+//
+//
+//    labelList cppEdgeData(coupledMeshEdges.size(), -1);
+//
+//    forAll(coupledMeshEdges, eI)
+//    {
+//        const label meshEdgeIndex = coupledMeshEdges[eI];
+//
+//        if (collapseEdge[meshEdgeIndex] != -1)
+//        {
+//            if (meshToPatchSameOrientation[eI] == cppOrientation[eI])
+//            {
+//                cppEdgeData[eI] = 0;
+//            }
+//            else
+//            {
+//                cppEdgeData[eI] = 1;
+//            }
+//        }
+//    }
+//
+//
+//    // Synchronise cppEdgeData
+//    // Use minEqOp reduction, so that edge will only be collapsed on processor
+//    // boundary if both processors agree to collapse it
+//    globalData.syncData
+//    (
+//        cppEdgeData,
+//        globalData.globalEdgeSlaves(),
+//        globalData.globalEdgeTransformedSlaves(),
+//        map,
+//        minEqOp<label>()
+//    );
+//
+//
+//    forAll(coupledMeshEdges, eI)
+//    {
+//        const label meshEdgeIndex = coupledMeshEdges[eI];
+//
+//        if (collapseEdge[meshEdgeIndex] != -1)
+//        {
+//            if (meshToPatchSameOrientation[eI] == cppOrientation[eI])
+//            {
+//                collapseEdge[meshEdgeIndex] = 0;
+//            }
+//            else
+//            {
+//                collapseEdge[meshEdgeIndex] = 1;
+//            }
+//        }
+//    }
 
-    label maxIndex = findMax(magArea);
+    label nCollapsed = 0;
 
-    scalar minArea = areaFac * magArea[maxIndex];
+    DynamicList<label> initPoints(mesh.nPoints());
+    DynamicList<pointEdgeCollapse> initPointInfo(mesh.nPoints());
+    allPointInfo.resize(mesh.nPoints());
 
-    Info<< "Max face area:" << magArea[maxIndex] << endl
-        << "Collapse area factor:" << areaFac << endl
-        << "Collapse area:" << minArea << endl;
+    globalIndex globalStrings(mesh.nPoints());
 
-    label nCollapsed = 0;
+    List<pointEdgeCollapse> allEdgeInfo(mesh.nEdges());
+    forAll(allEdgeInfo, edgeI)
+    {
+        allEdgeInfo[edgeI] = pointEdgeCollapse(vector::zero, -1);
+    }
 
-    forAll(faces, faceI)
+    forAll(edges, edgeI)
     {
-        if (magArea[faceI] < minArea)
-        {
-            const face& f = faces[faceI];
+        const edge& e = edges[edgeI];
 
-            // Get the edges in face point order
-            labelList fEdges(getSortedEdges(edges, f, faceEdges[faceI]));
+        if (collapseEdge[edgeI] != -1)
+        {
+            const label master =
+                edgeMaster
+                (
+                    boundaryPoint,
+                    collapseEdge[edgeI],
+                    e
+                );
 
-            SortableList<scalar> lengths(fEdges.size());
-            forAll(fEdges, i)
+//            if (master != -1)
             {
-                lengths[i] = edges[fEdges[i]].mag(points);
-            }
-            lengths.sort();
-
-
-            label edgeI = -1;
+                pointEdgeCollapse pec
+                (
+                    points[master],
+                    globalStrings.toGlobal(master)
+                );
 
-            if (f.size() == 4)
-            {
-                // Compare second largest to smallest
-                if (lengths[2] > edgeRatio*lengths[0])
-                {
-                    // Collapse smallest only. Triangle should be cleared
-                    // next time around.
-                    edgeI = fEdges[lengths.indices()[0]];
-                }
-            }
-            else if (f.size() == 3)
-            {
-                // Compare second largest to smallest
-                if (lengths[1] > edgeRatio*lengths[0])
-                {
-                    edgeI = fEdges[lengths.indices()[0]];
-                }
-            }
+                allEdgeInfo[edgeI] = pec;
 
+                initPointInfo.append(pec);
+                initPoints.append(e.start());
 
-            if (edgeI != -1)
-            {
-                label master = edgeMaster(boundaryPoint, edges[edgeI]);
+                initPointInfo.append(pec);
+                initPoints.append(e.end());
 
-                if (master != -1)// && collapser.unaffectedEdge(edgeI))
-                {
-                    collapser.collapseEdge(edgeI, master);
-                    nCollapsed++;
-                }
+                nCollapsed++;
             }
         }
     }
 
+    PointEdgeWave<pointEdgeCollapse> collapsePropagator
+    (
+        mesh,
+        initPoints,
+        initPointInfo,
+        allPointInfo,
+        allEdgeInfo,
+        mesh.globalData().nTotalPoints()  // Maximum number of iterations
+    );
+
     return nCollapsed;
 }
 
 
+// Faces which have edges just larger than collapse length but faces which
+// are very small. This one tries to collapse them if it can be done with
+// edge collapse. For faces where a face gets replace by two edges use
+// collapseFaces
+//label collapseHighAspectFaces
+//(
+//    const polyMesh& mesh,
+//    const PackedBoolList& boundaryPoint,
+//    const Map<label>& processorPoints,
+//    const scalar areaFac,
+//    const scalar edgeRatio,
+//    edgeCollapser& collapser
+//)
+//{
+//    const pointField& points = mesh.points();
+//    const edgeList& edges = mesh.edges();
+//    const faceList& faces = mesh.faces();
+//    const labelListList& faceEdges = mesh.faceEdges();
+//
+//    scalarField magArea(mag(mesh.faceAreas()));
+//
+//    label maxIndex = findMax(magArea);
+//
+//    scalar minArea = areaFac * magArea[maxIndex];
+//
+//    Info<< "Max face area:" << magArea[maxIndex] << endl
+//        << "Collapse area factor:" << areaFac << endl
+//        << "Collapse area:" << minArea << endl;
+//
+//    label nCollapsed = 0;
+//
+//    forAll(faces, faceI)
+//    {
+//        if (magArea[faceI] < minArea)
+//        {
+//            const face& f = faces[faceI];
+//
+//            // Get the edges in face point order
+//            labelList fEdges(getSortedEdges(edges, f, faceEdges[faceI]));
+//
+//            SortableList<scalar> lengths(fEdges.size());
+//            forAll(fEdges, i)
+//            {
+//                lengths[i] = edges[fEdges[i]].mag(points);
+//            }
+//            lengths.sort();
+//
+//
+//            label edgeI = -1;
+//
+//            if (f.size() == 4)
+//            {
+//                // Compare second largest to smallest
+//                if (lengths[2] > edgeRatio*lengths[0])
+//                {
+//                    // Collapse smallest only. Triangle should be cleared
+//                    // next time around.
+//                    edgeI = fEdges[lengths.indices()[0]];
+//                }
+//            }
+//            else if (f.size() == 3)
+//            {
+//                // Compare second largest to smallest
+//                if (lengths[1] > edgeRatio*lengths[0])
+//                {
+//                    edgeI = fEdges[lengths.indices()[0]];
+//                }
+//            }
+//
+//
+//            if (edgeI != -1)
+//            {
+//                label master = edgeMaster
+//                    (
+//                        boundaryPoint,
+//                        processorPoints,
+//                        false,
+//                        edges[edgeI]
+//                    );
+//
+//                if (master != -1)// && collapser.unaffectedEdge(edgeI))
+//                {
+//                    collapser.collapseEdge(edgeI, master);
+//                    nCollapsed++;
+//                }
+//            }
+//        }
+//    }
+//
+//    return nCollapsed;
+//}
+
+
 void set(const labelList& elems, const bool val, boolList& status)
 {
     forAll(elems, i)
@@ -340,122 +946,254 @@ void set(const labelList& elems, const bool val, boolList& status)
 
 
 // Tries to simplify polygons to face of minSize (4=quad, 3=triangle)
-label simplifyFaces
-(
-    const polyMesh& mesh,
-    const PackedBoolList& boundaryPoint,
-    const label minSize,
-    const scalar lenGap,
-    edgeCollapser& collapser
-)
+//label simplifyFaces
+//(
+//    const polyMesh& mesh,
+//    const PackedBoolList& boundaryPoint,
+//    const Map<label>& processorPoints,
+//    const label minSize,
+//    const scalar lenGap,
+//    edgeCollapser& collapser
+//)
+//{
+//    const pointField& points = mesh.points();
+//    const edgeList& edges = mesh.edges();
+//    const faceList& faces = mesh.faces();
+//    const cellList& cells = mesh.cells();
+//    const labelListList& faceEdges = mesh.faceEdges();
+//    const labelList& faceOwner = mesh.faceOwner();
+//    const labelList& faceNeighbour = mesh.faceNeighbour();
+//    const labelListList& pointCells = mesh.pointCells();
+//    const labelListList& cellEdges = mesh.cellEdges();
+//
+//    label nCollapsed = 0;
+//
+//    boolList protectedEdge(mesh.nEdges(), false);
+//
+//    forAll(faces, faceI)
+//    {
+//        const face& f = faces[faceI];
+//
+//        if
+//        (
+//            f.size() > minSize
+//         && cells[faceOwner[faceI]].size() >= 6
+//         && (
+//                mesh.isInternalFace(faceI)
+//             && cells[faceNeighbour[faceI]].size() >= 6
+//            )
+//        )
+//        {
+//            // Get the edges in face point order
+//            labelList fEdges(getSortedEdges(edges, f, faceEdges[faceI]));
+//
+//            SortableList<scalar> lengths(fEdges.size());
+//            forAll(fEdges, i)
+//            {
+//                lengths[i] = edges[fEdges[i]].mag(points);
+//            }
+//            lengths.sort();
+//
+//
+//            // Now find a gap in length between consecutive elements greater
+//            // than lenGap.
+//
+//            label gapPos = -1;
+//
+//            for (label i = f.size()-1-minSize; i >= 0; --i)
+//            {
+//                if (lengths[i+1] > lenGap*lengths[i])
+//                {
+//                    gapPos = i;
+//
+//                    break;
+//                }
+//            }
+//
+//            if (gapPos != -1)
+//            {
+//                //for (label i = gapPos; i >= 0; --i)
+//                label i = 0;  // Hack: collapse smallest edge only.
+//                {
+//                    label edgeI = fEdges[lengths.indices()[i]];
+//
+//                    if (!protectedEdge[edgeI])
+//                    {
+//                        const edge& e = edges[edgeI];
+//
+//                        label master
+//                       = edgeMaster(boundaryPoint, processorPoints, false, e);
+//
+//                        if (master != -1)
+//                        {
+//                            collapser.collapseEdge(edgeI, master);
+//
+//                            // Protect all other edges on all cells using edge
+//                            // points.
+//
+//                            const labelList& pCells0 = pointCells[e[0]];
+//
+//                            forAll(pCells0, i)
+//                            {
+//                              set(cellEdges[pCells0[i]], true, protectedEdge);
+//                            }
+//                            const labelList& pCells1 = pointCells[e[1]];
+//
+//                            forAll(pCells1, i)
+//                            {
+//                              set(cellEdges[pCells1[i]], true, protectedEdge);
+//                            }
+//
+//                            nCollapsed++;
+//                        }
+//                    }
+//                }
+//            }
+//        }
+//    }
+//
+//    return nCollapsed;
+//}
+
+
+labelHashSet checkMeshQuality(const polyMesh& mesh)
 {
-    const pointField& points = mesh.points();
-    const edgeList& edges = mesh.edges();
-    const faceList& faces = mesh.faces();
-    const cellList& cells = mesh.cells();
-    const labelListList& faceEdges = mesh.faceEdges();
-    const labelList& faceOwner = mesh.faceOwner();
-    const labelList& faceNeighbour = mesh.faceNeighbour();
-    const labelListList& pointCells = mesh.pointCells();
-    const labelListList& cellEdges = mesh.cellEdges();
+    //mesh.checkMesh(true);
+    labelHashSet freezePoints;
 
-    label nCollapsed = 0;
+    IOdictionary meshQualityDict
+    (
+        IOobject
+        (
+            "meshQualityControls",
+            mesh.time().system(),
+            mesh.time(),
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE
+        )
+    );
 
-    boolList protectedEdge(mesh.nEdges(), false);
+    labelHashSet badFaces(mesh.nFaces()/100);
+    DynamicList<label> checkFaces(mesh.nFaces());
 
-    forAll(faces, faceI)
-    {
-        const face& f = faces[faceI];
+    const vectorField& fAreas = mesh.faceAreas();
 
-        if
-        (
-            f.size() > minSize
-         && cells[faceOwner[faceI]].size() >= 6
-         && (
-                mesh.isInternalFace(faceI)
-             && cells[faceNeighbour[faceI]].size() >= 6
-            )
-        )
+    scalar faceAreaLimit = SMALL;
+
+    forAll(fAreas, fI)
+    {
+        if (mag(fAreas[fI]) > faceAreaLimit)
         {
-            // Get the edges in face point order
-            labelList fEdges(getSortedEdges(edges, f, faceEdges[faceI]));
+            checkFaces.append(fI);
+        }
+    }
 
-            SortableList<scalar> lengths(fEdges.size());
-            forAll(fEdges, i)
-            {
-                lengths[i] = edges[fEdges[i]].mag(points);
-            }
-            lengths.sort();
+    motionSmoother::checkMesh
+    (
+        false,
+        mesh,
+        meshQualityDict,
+        checkFaces,
+        badFaces
+    );
 
+    label nBadFaces = badFaces.size();
+    reduce(nBadFaces, sumOp<label>());
 
-            // Now find a gap in length between consecutive elements greater
-            // than lenGap.
+    Info<< nl << "Number of bad faces          : " << nBadFaces << endl;
 
-            label gapPos = -1;
+    forAllConstIter(labelHashSet, badFaces, iter)
+    {
+        const face& f = mesh.faces()[iter.key()];
 
-            for (label i = f.size()-1-minSize; i >= 0; --i)
-            {
-                if (lengths[i+1] > lenGap*lengths[i])
-                {
-                    gapPos = i;
+        forAll(f, pI)
+        {
+            freezePoints.insert(f[pI]);
+        }
+    }
 
-                    break;
-                }
-            }
+//    const edgeList& edges = mesh.edges();
+//
+//    label nFrozenEdges = 0;
+//
+//    OFstream str("frozenEdges.obj");
+//
+//    label count = 0;
+//    forAll(edges, eI)
+//    {
+//        const edge& e = edges[eI];
+//
+//        if (freezePoints.found(e[0]) && freezePoints.found(e[1]))
+//        {
+//            freezeEdges[eI] = true;
+//            nFrozenEdges++;
+//        }
+//    }
+
+    return freezePoints;
+}
 
-            if (gapPos != -1)
-            {
-                //for (label i = gapPos; i >= 0; --i)
-                label i = 0;  // Hack: collapse smallest edge only.
-                {
-                    label edgeI = fEdges[lengths.indices()[i]];
 
-                    if (!protectedEdge[edgeI])
-                    {
-                        const edge& e = edges[edgeI];
+// Mark boundary points
+// boundaryPoint:
+// + -1 : point not on boundary
+// +  0 : point on a real boundary
+// + >0 : point on a processor patch with that ID
+labelList findBoundaryPoints(const polyMesh& mesh)
+{
+    const faceList& faces = mesh.faces();
+    const polyBoundaryMesh& bMesh = mesh.boundaryMesh();
 
-                        label master = edgeMaster(boundaryPoint, e);
 
-                        if (master != -1)
-                        {
-                            collapser.collapseEdge(edgeI, master);
+    labelList boundaryPoint(mesh.nPoints(), -1);
 
-                            // Protect all other edges on all cells using edge
-                            // points.
+    // Get all points on a boundary
+    label nIntFaces = mesh.nInternalFaces();
+    for (label faceI = nIntFaces; faceI < mesh.nFaces(); faceI++)
+    {
+        const face& f = faces[faceI];
 
-                            const labelList& pCells0 = pointCells[e[0]];
+        forAll(f, fp)
+        {
+           boundaryPoint[f[fp]] = 0;
+        }
+    }
 
-                            forAll(pCells0, i)
-                            {
-                                set(cellEdges[pCells0[i]], true, protectedEdge);
-                            }
-                            const labelList& pCells1 = pointCells[e[1]];
+    // Get all processor boundary points and the processor patch label
+    // that they are on.
+    forAll(bMesh, patchI)
+    {
+        const polyPatch& patch = bMesh[patchI];
 
-                            forAll(pCells1, i)
-                            {
-                                set(cellEdges[pCells1[i]], true, protectedEdge);
-                            }
+        if (isA<processorPolyPatch>(patch))
+        {
+            const processorPolyPatch& pPatch =
+                refCast<const processorPolyPatch>(patch);
 
-                            nCollapsed++;
-                        }
-                    }
+            forAll(pPatch, fI)
+            {
+                const face& f = pPatch[fI];
+
+                forAll(f, fp)
+                {
+                    boundaryPoint[f[fp]] = patchI;
                 }
             }
         }
     }
 
-    return nCollapsed;
+    return boundaryPoint;
 }
 
 
 // Main program:
-
 int main(int argc, char *argv[])
 {
 #   include "addOverwriteOption.H"
-    argList::noParallel();
+
     argList::validArgs.append("edge length [m]");
     argList::validArgs.append("merge angle (degrees)");
+    argList::addOption("minLenFactor", "scalar", "edge length factor");
 
 #   include "setRootCase.H"
 #   include "createTime.H"
@@ -463,8 +1201,11 @@ int main(int argc, char *argv[])
 #   include "createPolyMesh.H"
     const word oldInstance = mesh.pointsInstance();
 
-    const scalar minLen  = args.argRead<scalar>(1);
+    scalar minLen  = args.argRead<scalar>(1);
     const scalar angle   = args.argRead<scalar>(2);
+    const scalar minLenFactor
+        = args.optionLookupOrDefault<scalar>("minLenFactor", 0.5);
+
     const bool overwrite = args.optionFound("overwrite");
 
     scalar maxCos = Foam::cos(degToRad(angle));
@@ -475,108 +1216,196 @@ int main(int argc, char *argv[])
         << " degrees" << nl
         << endl;
 
+    Info<< "If an invalid mesh is generated then the edge length will be " << nl
+        << "multiplied by a factor of " << minLenFactor << " and collapsing "
+        << "will be reattempted" << nl << endl;
 
     bool meshChanged = false;
 
-    while (true)
-    {
-        const faceList& faces = mesh.faces();
+    checkMeshQuality(mesh);
 
-        // Get all points on the boundary
-        PackedBoolList boundaryPoint(mesh.nPoints());
+    autoPtr<fvMesh> fvMeshPtr;
 
-        label nIntFaces = mesh.nInternalFaces();
-        for (label faceI = nIntFaces; faceI < mesh.nFaces(); faceI++)
-        {
-            const face& f = faces[faceI];
+    scalarList freezeEdges(mesh.nEdges(), 1.0);
 
-            forAll(f, fp)
-            {
-                boundaryPoint.set(f[fp], 1);
-            }
-        }
+    do
+    {
+        label nIterations = 0;
+        label nFrozenEdges = 0;
 
-        // Edge collapsing engine
-        edgeCollapser collapser(mesh);
+        fvMeshPtr.reset(new fvMesh(mesh));
+        fvMesh& fvMeshRef = fvMeshPtr();
 
+        // Contains new point label for original points
+        labelList pointMap(identity(mesh.nPoints()));
 
-        // Collapse all edges that are too small.
-        label nCollapsed =
-            collapseSmallEdges
-            (
-                mesh,
-                boundaryPoint,
-                minLen,
-                collapser
-            );
-        Info<< "Collapsing " << nCollapsed << " small edges" << endl;
+        scalarList tmpFreezeEdges = freezeEdges;
 
+        autoPtr<mapPolyMesh> morphMap;
 
-        // Remove midpoints on straight edges.
-        if (nCollapsed == 0)
+        while (true)
         {
-            nCollapsed = mergeEdges(mesh, maxCos, collapser);
-            Info<< "Collapsing " << nCollapsed << " in line edges" << endl;
-        }
+            Info<< "Iteration " << nIterations << incrIndent << endl;
 
+            labelList boundaryPoint = findBoundaryPoints(fvMeshRef);
 
-        // Remove small sliver faces that can be collapsed to single edge
-        if (nCollapsed == 0)
-        {
-            nCollapsed =
-                collapseHighAspectFaces
+            List<pointEdgeCollapse> allPointInfo;
+
+            // Collapse all edges that are too small.
+            label nSmallCollapsed =
+                collapseSmallEdges
                 (
-                    mesh,
+                    fvMeshRef,
+                    tmpFreezeEdges,
                     boundaryPoint,
-                    1e-9,       // factor of largest face area
-                    5,          // factor between smallest and largest edge on
-                                // face
-                    collapser
+                    minLen,
+                    allPointInfo
                 );
-            Info<< "Collapsing " << nCollapsed
+
+            reduce(nSmallCollapsed, sumOp<label>());
+
+            Info<< indent << "Collapsing " << nSmallCollapsed
+                << " small edges" << endl;
+
+
+
+
+
+            label nMerged = 0;
+
+            // Remove midpoints on straight edges.
+            if (nSmallCollapsed == 0)
+            {
+                //nMerged = mergeEdges(fvMeshRef, maxCos, allPointInfo);
+            }
+
+            reduce(nMerged, sumOp<label>());
+
+            Info<< indent << "Collapsing " << nMerged << " in line edges"
+                << endl;
+
+
+
+
+
+
+            label nSliversCollapsed = 0;
+
+            // Remove small sliver faces that can be collapsed to single edge
+//            if (nSmallCollapsed == 0 && nMerged == 0)
+//            {
+//                nSliversCollapsed =
+//                    collapseHighAspectFaces
+//                    (
+//                        mesh,
+//                        boundaryPoint,
+//                        processorPoints,
+//                        1E-9,
+//                        5,
+//                        collapser
+//                    );
+//            }
+
+            reduce(nSliversCollapsed, sumOp<label>());
+
+            Info<< indent << "Collapsing " << nSliversCollapsed
                 << " small high aspect ratio faces" << endl;
-        }
 
-        // Simplify faces to quads wherever possible
-        //if (nCollapsed == 0)
-        //{
-        //    nCollapsed =
-        //        simplifyFaces
-        //        (
-        //            mesh,
-        //            boundaryPoint,
-        //            4,              // minimum size of face
-        //            0.2,            // gap in edge lengths on face
-        //            collapser
-        //        );
-        //    Info<< "Collapsing " << nCollapsed << " polygonal faces" << endl;
-        //}
 
+            // Simplify faces to quads wherever possible
+            //if (nCollapsed == 0)
+            //{
+            //    nCollapsed =
+            //        simplifyFaces
+            //        (
+            //            mesh,
+            //            boundaryPoint,
+            //            4,              // minimum size of face
+            //            0.2,            // gap in edge lengths on face
+            //            collapser
+            //        );
+            //    Info<< "Collapsing " << nCollapsed << " polygonal faces"
+            //        << endl;
+            //}
+
+
+            label totalCollapsed =
+                nSmallCollapsed
+              + nMerged
+              + nSliversCollapsed;
+
+            polyTopoChange meshMod(fvMeshRef);
+
+            // Insert mesh refinement into polyTopoChange.
+            setRefinement(fvMeshRef, meshMod, allPointInfo);
+
+            // Do all changes
+            Info<< indent << "Applying changes to the mesh" << nl
+                << decrIndent << endl;
+
+            morphMap = meshMod.changeMesh(fvMeshRef, false);
+
+//            // Contains new point label for old points
+//            const labelList& reversePointMap = morphMap().reversePointMap();
+//
+//            forAll(pointMap, pI)
+//            {
+//                const label originalPoint = pI;
+//                const label currentPoint = pointMap[pI];
+//
+//                if (currentPoint < reversePointMap.size())
+//                {
+//                    const label newPoint = reversePointMap[currentPoint];
+//
+//                    if (newPoint != -1)
+//                    {
+//                        pointMap[originalPoint] = newPoint;
+//                    }
+//                }
+//            }
+
+            if (totalCollapsed == 0)
+            {
+                labelHashSet freezePoints = checkMeshQuality(fvMeshRef);
 
-        if (nCollapsed == 0)
-        {
-            break;
-        }
+                label nFreezePoints = freezePoints.size();
+                reduce(nFreezePoints, sumOp<label>());
 
-        polyTopoChange meshMod(mesh);
+                nFrozenEdges = nFreezePoints;
 
-        // Insert mesh refinement into polyTopoChange.
-        collapser.setRefinement(meshMod);
+                Info<< "Number of frozen points      : " << nFreezePoints
+                    << endl;
 
-        // Do all changes
-        Info<< "Morphing ..." << endl;
+                break;
+            }
 
-        autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
+            if (morphMap().hasMotionPoints())
+            {
+                fvMeshRef.movePoints(morphMap().preMotionPoints());
+            }
 
-        collapser.updateMesh(morphMap());
+            meshChanged = true;
 
-        if (morphMap().hasMotionPoints())
+            nIterations++;
+        }
+
+        if (nFrozenEdges > 0)
         {
-            mesh.movePoints(morphMap().preMotionPoints());
+            minLen *= minLenFactor;
         }
 
-        meshChanged = true;
-    }
+        reduce(nFrozenEdges, sumOp<label>());
+
+        Info<< "Number of frozen edges       : " << nFrozenEdges << nl
+            << endl;
+
+        if (nFrozenEdges == 0)
+        {
+            break;
+        }
+
+    } while (true);
+
 
     if (meshChanged)
     {
@@ -587,14 +1416,21 @@ int main(int argc, char *argv[])
         }
         else
         {
-            mesh.setInstance(oldInstance);
+            fvMeshPtr().setInstance(oldInstance);
         }
 
-        Info<< "Writing collapsed mesh to time " << runTime.timeName() << endl;
+        Info<< nl << "Writing collapsed mesh to time "
+            << runTime.timeName() << nl << endl;
 
-        mesh.write();
+        fvMeshPtr().write();
     }
 
+    Info<< "Final minimum length : " << minLen << " m" << nl << endl;
+
+    Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
+        << "  ClockTime = " << runTime.elapsedClockTime() << " s"
+        << nl << endl;
+
     Info<< "End\n" << endl;
 
     return 0;
diff --git a/applications/utilities/mesh/advanced/collapseEdges/pointEdgeCollapse/pointEdgeCollapse.C b/applications/utilities/mesh/advanced/collapseEdges/pointEdgeCollapse/pointEdgeCollapse.C
new file mode 100644
index 0000000000000000000000000000000000000000..6830e1c8f56ed18c006241ffb16388012da4b042
--- /dev/null
+++ b/applications/utilities/mesh/advanced/collapseEdges/pointEdgeCollapse/pointEdgeCollapse.C
@@ -0,0 +1,51 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2012 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "pointEdgeCollapse.H"
+
+// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
+
+Foam::Ostream& Foam::operator<<
+(
+    Foam::Ostream& os,
+    const Foam::pointEdgeCollapse& wDist
+)
+{
+    return os
+        << wDist.collapsePoint_ << wDist.collapseIndex_;
+}
+
+Foam::Istream& Foam::operator>>
+(
+    Foam::Istream& is,
+    Foam::pointEdgeCollapse& wDist
+)
+{
+    return is
+        >> wDist.collapsePoint_ >> wDist.collapseIndex_;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/advanced/collapseEdges/pointEdgeCollapse/pointEdgeCollapse.H b/applications/utilities/mesh/advanced/collapseEdges/pointEdgeCollapse/pointEdgeCollapse.H
new file mode 100644
index 0000000000000000000000000000000000000000..cd8383b8b33b6ed6ddb0b03a172aa632205f3cee
--- /dev/null
+++ b/applications/utilities/mesh/advanced/collapseEdges/pointEdgeCollapse/pointEdgeCollapse.H
@@ -0,0 +1,227 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2012 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::pointEdgeCollapse
+
+Description
+    Determines length of string of edges walked to point.
+
+SourceFiles
+    pointEdgeCollapseI.H
+    pointEdgeCollapse.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef pointEdgeCollapse_H
+#define pointEdgeCollapse_H
+
+#include "point.H"
+#include "tensor.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class polyPatch;
+class polyMesh;
+
+/*---------------------------------------------------------------------------*\
+                           Class pointEdgeCollapse Declaration
+\*---------------------------------------------------------------------------*/
+
+class pointEdgeCollapse
+{
+    // Private data
+
+        //- Collapse location
+        point collapsePoint_;
+
+        //- Collapse string index
+        label collapseIndex_;
+
+
+    // Private Member Functions
+
+        //- Evaluate distance to point.
+        template<class TrackingData>
+        inline bool update
+        (
+            const pointEdgeCollapse& w2,
+            const scalar tol,
+            TrackingData& td
+        );
+
+
+        //- Check for same coordinate
+        inline bool samePoint(const point& pt) const;
+
+public:
+
+    // Constructors
+
+        //- Construct null
+        inline pointEdgeCollapse();
+
+        //- Construct from components
+        inline pointEdgeCollapse
+        (
+            const point& collapsePoint,
+            const label collapseIndex
+        );
+
+
+    // Member Functions
+
+        // Access
+
+            inline const point& collapsePoint() const;
+
+            inline label collapseIndex() const;
+
+
+        // Needed by meshWave
+
+            //- Check whether origin has been changed at all or
+            //  still contains original (invalid) value.
+            template<class TrackingData>
+            inline bool valid(TrackingData& td) const;
+
+            //- Convert origin to relative vector to leaving point
+            //  (= point coordinate)
+            template<class TrackingData>
+            inline void leaveDomain
+            (
+                const polyPatch& patch,
+                const label patchPointI,
+                const point& pos,
+                TrackingData& td
+            );
+
+            //- Convert relative origin to absolute by adding entering point
+            template<class TrackingData>
+            inline void enterDomain
+            (
+                const polyPatch& patch,
+                const label patchPointI,
+                const point& pos,
+                TrackingData& td
+            );
+
+            //- Apply rotation matrix to origin
+            template<class TrackingData>
+            inline void transform
+            (
+                const tensor& rotTensor,
+                TrackingData& td
+            );
+
+            //- Influence of edge on point
+            template<class TrackingData>
+            inline bool updatePoint
+            (
+                const polyMesh& mesh,
+                const label pointI,
+                const label edgeI,
+                const pointEdgeCollapse& edgeInfo,
+                const scalar tol,
+                TrackingData& td
+            );
+
+            //- Influence of different value on same point.
+            //  Merge new and old info.
+            template<class TrackingData>
+            inline bool updatePoint
+            (
+                const polyMesh& mesh,
+                const label pointI,
+                const pointEdgeCollapse& newPointInfo,
+                const scalar tol,
+                TrackingData& td
+            );
+
+            //- Influence of different value on same point.
+            //  No information about current position whatsoever.
+            template<class TrackingData>
+            inline bool updatePoint
+            (
+                const pointEdgeCollapse& newPointInfo,
+                const scalar tol,
+                TrackingData& td
+            );
+
+            //- Influence of point on edge.
+            template<class TrackingData>
+            inline bool updateEdge
+            (
+                const polyMesh& mesh,
+                const label edgeI,
+                const label pointI,
+                const pointEdgeCollapse& pointInfo,
+                const scalar tol,
+                TrackingData& td
+            );
+
+            //- Same (like operator==)
+            template<class TrackingData>
+            inline bool equal(const pointEdgeCollapse&, TrackingData&)
+            const;
+
+
+    // Member Operators
+
+        //Note: Used to determine whether to call update.
+        inline bool operator==(const pointEdgeCollapse&) const;
+        inline bool operator!=(const pointEdgeCollapse&) const;
+
+
+    // IOstream Operators
+
+        friend Ostream& operator<<(Ostream&, const pointEdgeCollapse&);
+        friend Istream& operator>>(Istream&, pointEdgeCollapse&);
+};
+
+
+//- Data associated with pointEdgeCollapse type are contiguous
+template<>
+inline bool contiguous<pointEdgeCollapse>()
+{
+    return true;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "pointEdgeCollapseI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/advanced/collapseEdges/pointEdgeCollapse/pointEdgeCollapseI.H b/applications/utilities/mesh/advanced/collapseEdges/pointEdgeCollapse/pointEdgeCollapseI.H
new file mode 100644
index 0000000000000000000000000000000000000000..3fb1468a88f799f92c872f0ecc9fe0b60bf23747
--- /dev/null
+++ b/applications/utilities/mesh/advanced/collapseEdges/pointEdgeCollapse/pointEdgeCollapseI.H
@@ -0,0 +1,313 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2012 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "polyMesh.H"
+#include "transform.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+// Update this with w2.
+template<class TrackingData>
+inline bool Foam::pointEdgeCollapse::update
+(
+    const pointEdgeCollapse& w2,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    if (!w2.valid(td))
+    {
+        FatalErrorIn("pointEdgeCollapse::update(..)")
+            << "problem." << abort(FatalError);
+    }
+
+    if (w2.collapseIndex_ == -1)
+    {
+        // Not marked for collapse; only happens on edges.
+        return false;
+    }
+
+    if (!valid(td))
+    {
+        operator=(w2);
+        return true;
+    }
+    else
+    {
+        // Same coordinate. Same string?
+        if (w2.collapseIndex_ < collapseIndex_)
+        {
+            // Take over string index from w2 (and also coordinate but this
+            // was same)
+            operator=(w2);
+            return true;
+        }
+        else if (w2.collapseIndex_ == collapseIndex_)
+        {
+            bool identicalPoint = samePoint(w2.collapsePoint_);
+            bool nearer = magSqr(w2.collapsePoint_) < magSqr(collapsePoint_);
+            if (nearer)
+            {
+                operator=(w2);
+            }
+            if (identicalPoint)
+            {
+                return false;
+            }
+            else
+            {
+                return nearer;
+            }
+        }
+        else
+        {
+            return false;
+        }
+
+//        if (samePoint(w2.collapsePoint_))
+//        {
+//            // Same coordinate. Same string?
+//            if (w2.collapseIndex_ < collapseIndex_)
+//            {
+//                // Take over string index from w2 (and also coordinate but this
+//                // was same)
+//                operator=(w2);
+//                return true;
+//            }
+//            else
+//            {
+//                return false;
+//            }
+//        }
+//        else
+//        {
+//            // Find nearest coordinate
+//            if (magSqr(w2.collapsePoint_) < magSqr(collapsePoint_))
+//            {
+//                operator=(w2);
+//                return true;
+//            }
+//            else
+//            {
+//                return false;
+//            }
+//        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Null constructor
+inline Foam::pointEdgeCollapse::pointEdgeCollapse()
+:
+    collapsePoint_(GREAT, GREAT, GREAT),
+    collapseIndex_(-2)
+{}
+
+
+// Construct from origin, distance
+inline Foam::pointEdgeCollapse::pointEdgeCollapse
+(
+    const point& collapsePoint,
+    const label collapseIndex
+)
+:
+    collapsePoint_(collapsePoint),
+    collapseIndex_(collapseIndex)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+inline const Foam::point& Foam::pointEdgeCollapse::collapsePoint() const
+{
+    return collapsePoint_;
+}
+
+
+inline Foam::label Foam::pointEdgeCollapse::collapseIndex() const
+{
+    return collapseIndex_;
+}
+
+
+inline bool Foam::pointEdgeCollapse::samePoint(const point& pt) const
+{
+    bool isLegal1 = (cmptMin(collapsePoint_) < 0.5*GREAT);
+    bool isLegal2 = (cmptMin(pt) < 0.5*GREAT);
+
+    if (isLegal1 && isLegal2)
+    {
+        return mag(collapsePoint_ - pt) < 1e-9;//SMALL;
+    }
+    else
+    {
+        return isLegal1 == isLegal2;
+    }
+}
+
+
+template<class TrackingData>
+inline bool Foam::pointEdgeCollapse::valid(TrackingData& td) const
+{
+    return collapseIndex_ != -2;
+}
+
+
+template<class TrackingData>
+inline void Foam::pointEdgeCollapse::leaveDomain
+(
+    const polyPatch& patch,
+    const label patchPointI,
+    const point& coord,
+    TrackingData& td
+)
+{
+    collapsePoint_ -= coord;
+}
+
+
+template<class TrackingData>
+inline void Foam::pointEdgeCollapse::transform
+(
+    const tensor& rotTensor,
+    TrackingData& td
+)
+{
+    collapsePoint_ = Foam::transform(rotTensor, collapsePoint_);
+}
+
+
+// Update absolute geometric quantities. Note that distance (dist_)
+// is not affected by leaving/entering domain.
+template<class TrackingData>
+inline void Foam::pointEdgeCollapse::enterDomain
+(
+    const polyPatch& patch,
+    const label patchPointI,
+    const point& coord,
+    TrackingData& td
+)
+{
+    // back to absolute form
+    collapsePoint_ += coord;
+}
+
+
+// Update this with information from connected edge
+template<class TrackingData>
+inline bool Foam::pointEdgeCollapse::updatePoint
+(
+    const polyMesh& mesh,
+    const label pointI,
+    const label edgeI,
+    const pointEdgeCollapse& edgeInfo,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    return update(edgeInfo, tol, td);
+}
+
+
+// Update this with new information on same point
+template<class TrackingData>
+inline bool Foam::pointEdgeCollapse::updatePoint
+(
+    const polyMesh& mesh,
+    const label pointI,
+    const pointEdgeCollapse& newPointInfo,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    return update(newPointInfo, tol, td);
+}
+
+
+// Update this with new information on same point. No extra information.
+template<class TrackingData>
+inline bool Foam::pointEdgeCollapse::updatePoint
+(
+    const pointEdgeCollapse& newPointInfo,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    return update(newPointInfo, tol, td);
+}
+
+
+// Update this with information from connected point
+template<class TrackingData>
+inline bool Foam::pointEdgeCollapse::updateEdge
+(
+    const polyMesh& mesh,
+    const label edgeI,
+    const label pointI,
+    const pointEdgeCollapse& pointInfo,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    return update(pointInfo, tol, td);
+}
+
+
+template <class TrackingData>
+inline bool Foam::pointEdgeCollapse::equal
+(
+    const pointEdgeCollapse& rhs,
+    TrackingData& td
+) const
+{
+    return operator==(rhs);
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+inline bool Foam::pointEdgeCollapse::operator==
+(
+    const Foam::pointEdgeCollapse& rhs
+) const
+{
+    return
+        collapseIndex_ == rhs.collapseIndex_
+     && samePoint(rhs.collapsePoint_);
+}
+
+
+inline bool Foam::pointEdgeCollapse::operator!=
+(
+    const Foam::pointEdgeCollapse& rhs
+) const
+{
+    return !(*this == rhs);
+}
+
+
+// ************************************************************************* //
diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.C b/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.C
index 415c6facdca40204dfe3e097e10452ec756a9933..22872abf47d6b1c5f87150831ef4ce1d22a82b3a 100644
--- a/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.C
+++ b/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.C
@@ -27,6 +27,10 @@ License
 #include "polyMesh.H"
 #include "polyTopoChange.H"
 #include "ListOps.H"
+#include "globalMeshData.H"
+#include "OFstream.H"
+#include "meshTools.H"
+#include "syncTools.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -121,6 +125,7 @@ void Foam::edgeCollapser::filterFace(const label faceI, face& f) const
         }
     }
 
+
     // Check for pinched face. Tries to correct
     // - consecutive duplicate vertex. Removes duplicate vertex.
     // - duplicate vertex with one other vertex in between (spike).
@@ -190,15 +195,15 @@ void Foam::edgeCollapser::printRegions() const
 
         if (master != -1)
         {
-            Info<< "Region:" << regionI << nl
+            Pout<< "Region:" << regionI << nl
                 << "    master:" << master
-                << ' ' << mesh_.points()[master] << nl;
+                << ' ' << pointRegionMasterLocation_[regionI] << nl;
 
             forAll(pointRegion_, pointI)
             {
                 if (pointRegion_[pointI] == regionI && pointI != master)
                 {
-                    Info<< "    slave:" << pointI
+                    Pout<< "    slave:" << pointI
                         << ' ' <<  mesh_.points()[pointI] << nl;
                 }
             }
@@ -272,6 +277,7 @@ Foam::edgeCollapser::edgeCollapser(const polyMesh& mesh)
 :
     mesh_(mesh),
     pointRegion_(mesh.nPoints(), -1),
+    pointRegionMasterLocation_(mesh.nPoints() / 100),
     pointRegionMaster_(mesh.nPoints() / 100),
     freeRegions_()
 {}
@@ -289,6 +295,8 @@ bool Foam::edgeCollapser::unaffectedEdge(const label edgeI) const
 
 bool Foam::edgeCollapser::collapseEdge(const label edgeI, const label master)
 {
+    const pointField& points = mesh_.points();
+
     const edge& e = mesh_.edges()[edgeI];
 
     label pointRegion0 = pointRegion_[e[0]];
@@ -310,7 +318,7 @@ bool Foam::edgeCollapser::collapseEdge(const label edgeI, const label master)
                 {
                     FatalErrorIn
                     ("edgeCollapser::collapseEdge(const label, const label)")
-                        << "Problem : freeed region :" << freeRegion
+                        << "Problem : freed region :" << freeRegion
                         << " has already master "
                         << pointRegionMaster_[freeRegion]
                         << abort(FatalError);
@@ -327,13 +335,22 @@ bool Foam::edgeCollapser::collapseEdge(const label edgeI, const label master)
             pointRegion_[e[1]] = freeRegion;
 
             pointRegionMaster_(freeRegion) = master;
+            pointRegionMasterLocation_(freeRegion) = points[master];
         }
         else
         {
             // e[1] is part of collapse network, e[0] not. Add e0 to e1 region.
             pointRegion_[e[0]] = pointRegion1;
 
-            pointRegionMaster_[pointRegion1] = master;
+            if
+            (
+                pointRegionMaster_[pointRegion1] == e[0]
+             || pointRegionMaster_[pointRegion1] == e[1]
+            )
+            {
+                pointRegionMaster_[pointRegion1] = master;
+                pointRegionMasterLocation_[pointRegion1] = points[master];
+            }
         }
     }
     else
@@ -343,7 +360,15 @@ bool Foam::edgeCollapser::collapseEdge(const label edgeI, const label master)
             // e[0] is part of collapse network. Add e1 to e0 region
             pointRegion_[e[1]] = pointRegion0;
 
-            pointRegionMaster_[pointRegion0] = master;
+            if
+            (
+                pointRegionMaster_[pointRegion0] == e[0]
+             || pointRegionMaster_[pointRegion0] == e[1]
+            )
+            {
+                pointRegionMaster_[pointRegion0] = master;
+                pointRegionMasterLocation_[pointRegion0] = points[master];
+            }
         }
         else if (pointRegion0 != pointRegion1)
         {
@@ -356,6 +381,9 @@ bool Foam::edgeCollapser::collapseEdge(const label edgeI, const label master)
             // Use minRegion as region for combined net, free maxRegion.
             pointRegionMaster_[minRegion] = master;
             pointRegionMaster_[maxRegion] = -1;
+            pointRegionMasterLocation_[minRegion] = points[master];
+            pointRegionMasterLocation_[maxRegion] = point(0, 0, 0);
+
             freeRegions_.insert(maxRegion);
 
             if (minRegion != pointRegion0)
@@ -380,12 +408,61 @@ bool Foam::edgeCollapser::setRefinement(polyTopoChange& meshMod)
     const labelList& faceNeighbour = mesh_.faceNeighbour();
     const labelListList& pointFaces = mesh_.pointFaces();
     const labelListList& cellEdges = mesh_.cellEdges();
+    const pointZoneMesh& pointZones = mesh_.pointZones();
+
 
-    // Print regions:
-    //printRegions()
 
     bool meshChanged = false;
 
+    // Synchronise pointRegionMasterLocation_
+    const globalMeshData& globalData = mesh_.globalData();
+    const mapDistribute& map = globalData.globalPointSlavesMap();
+    const indirectPrimitivePatch& coupledPatch = globalData.coupledPatch();
+    const labelList& meshPoints = coupledPatch.meshPoints();
+    const Map<label>& meshPointMap = coupledPatch.meshPointMap();
+
+
+    List<point> newPoints = coupledPatch.localPoints();
+
+    for (label pI = 0; pI < coupledPatch.nPoints(); ++pI)
+    {
+        const label pointRegionMaster = pointRegion_[meshPoints[pI]];
+
+        if (pointRegionMaster != -1)
+        {
+            newPoints[pI]
+                = pointRegionMasterLocation_[pointRegionMaster];
+        }
+    }
+
+    globalData.syncData
+    (
+        newPoints,
+        globalData.globalPointSlaves(),
+        globalData.globalPointTransformedSlaves(),
+        map,
+        minMagSqrEqOp<point>()
+    );
+
+        OFstream str1("newPoints_" + name(Pstream::myProcNo()) + ".obj");
+        forAll(pointRegion_, pI)
+        {
+            if (meshPointMap.found(pI))
+            {
+                meshTools::writeOBJ(str1, newPoints[meshPointMap[pI]]);
+            }
+        }
+
+    for (label pI = 0; pI < coupledPatch.nPoints(); ++pI)
+    {
+        const label pointRegionMaster = pointRegion_[meshPoints[pI]];
+
+        if (pointRegionMaster != -1)
+        {
+            pointRegionMasterLocation_[pointRegionMaster]
+                = newPoints[pI];
+        }
+    }
 
     // Current faces (is also collapseStatus: f.size() < 3)
     faceList newFaces(mesh_.faces());
@@ -393,7 +470,6 @@ bool Foam::edgeCollapser::setRefinement(polyTopoChange& meshMod)
     // Current cellCollapse status
     boolList cellRemoved(mesh_.nCells(), false);
 
-
     do
     {
         // Update face collapse from edge collapses
@@ -521,12 +597,49 @@ bool Foam::edgeCollapser::setRefinement(polyTopoChange& meshMod)
         }
     }
 
+    // Modify the point location of the remaining points
+    forAll(pointRegion_, pointI)
+    {
+        const label pointRegion = pointRegion_[pointI];
+
+        if
+        (
+            !pointRemoved(pointI)
+         && meshPointMap.found(pointI)
+        )
+        {
+            meshMod.modifyPoint
+            (
+                pointI,
+                newPoints[meshPointMap[pointI]],
+                pointZones.whichZone(pointI),
+                false
+            );
+        }
+        else if
+        (
+            pointRegion != -1
+         && !pointRemoved(pointI)
+         && !meshPointMap.found(pointI)
+        )
+        {
+            const point& collapsePoint
+                = pointRegionMasterLocation_[pointRegion];
+
+            meshMod.modifyPoint
+            (
+                pointI,
+                collapsePoint,
+                pointZones.whichZone(pointI),
+                false
+            );
+        }
+    }
 
 
     const polyBoundaryMesh& boundaryMesh = mesh_.boundaryMesh();
     const faceZoneMesh& faceZones = mesh_.faceZones();
 
-
     // Renumber faces that use points
     forAll(pointRegion_, pointI)
     {
@@ -585,6 +698,9 @@ bool Foam::edgeCollapser::setRefinement(polyTopoChange& meshMod)
         }
     }
 
+    // Print regions:
+//    printRegions();
+
     return meshChanged;
 }
 
@@ -593,8 +709,10 @@ void Foam::edgeCollapser::updateMesh(const mapPolyMesh& map)
 {
     pointRegion_.setSize(mesh_.nPoints());
     pointRegion_ = -1;
+
     // Reset count, do not remove underlying storage
     pointRegionMaster_.clear();
+    pointRegionMasterLocation_.clear();
     freeRegions_.clear();
 }
 
diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.H b/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.H
index 98d8ef30d5bce148647499c65cbcbde299df9fc1..3a10a9319749081af5960967cb6eaf09ec3e17d4 100644
--- a/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.H
+++ b/src/dynamicMesh/polyTopoChange/polyTopoChange/edgeCollapser.H
@@ -39,6 +39,7 @@ SourceFiles
 
 #include "labelList.H"
 #include "DynamicList.H"
+#include "point.H"
 #include "typeInfo.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -66,6 +67,10 @@ class edgeCollapser
         //- For every point -1 or region number
         labelList pointRegion_;
 
+        //- Actual location of the point to collapse to for every region master
+        //  point. This will be forced to be consistent across processors
+        DynamicList<point> pointRegionMasterLocation_;
+
         //- -1 or master vertex for region number
         DynamicList<label> pointRegionMaster_;