From 3eb95ac527badd0c75753c6bc9772b4e2aa6aa81 Mon Sep 17 00:00:00 2001
From: mattijs <mattijs>
Date: Mon, 8 Feb 2010 11:38:51 +0000
Subject: [PATCH] ENH: New shared point addressing.

Now mapDistribute structure to pull data from slaves to master and vice versa.
---
 .../polyMesh/globalMeshData/globalMeshData.C  | 488 ++++++++-
 .../polyMesh/globalMeshData/globalMeshData.H  | 106 +-
 .../polyMesh/globalMeshData/globalPoints.C    | 965 ++++++++++++++----
 .../polyMesh/globalMeshData/globalPoints.H    | 111 +-
 4 files changed, 1371 insertions(+), 299 deletions(-)

diff --git a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C
index 1b3bb264a21..2ede6a88e34 100644
--- a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C
+++ b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C
@@ -410,33 +410,30 @@ Foam::label Foam::globalMeshData::countCoincidentFaces
 }
 
 
-void Foam::globalMeshData::calcGlobalPointSlaves() const
+void Foam::globalMeshData::calcGlobalPointSlaves
+(
+    const globalPoints& globalData,
+    autoPtr<globalIndex>& globalIndicesPtr,
+    autoPtr<labelListList>& globalPointSlavesPtr,
+    autoPtr<mapDistribute>& globalPointSlavesMapPtr
+) const
 {
-    if (debug)
-    {
-        Pout<< "globalMeshData::calcGlobalPointSlaves() :"
-            << " calculating coupled master to slave point addressing."
-            << endl;
-    }
-
-    // Calculate connected points for master points
-    globalPoints globalData(mesh_, coupledPatch(), true);
-
-    const Map<label>& meshToProcPoint = globalData.meshToProcPoint();
-
     // Create global numbering for coupled points
-    globalPointNumberingPtr_.reset
+    globalIndicesPtr.reset
     (
         new globalIndex(globalData.globalIndices())
     );
-    const globalIndex& globalIndices = globalPointNumberingPtr_();
+    const globalIndex& globalIndices = globalIndicesPtr();
 
     // Create master to slave addressing. Empty for slave points.
-    globalPointSlavesPtr_.reset
+    globalPointSlavesPtr.reset
     (
         new labelListList(coupledPatch().nPoints())
     );
-    labelListList& globalPointSlaves = globalPointSlavesPtr_();
+    labelListList& globalPointSlaves = globalPointSlavesPtr();
+
+
+    const Map<label>& meshToProcPoint = globalData.meshToProcPoint();
 
     forAllConstIter(Map<label>, meshToProcPoint, iter)
     {
@@ -465,7 +462,7 @@ void Foam::globalMeshData::calcGlobalPointSlaves() const
     // Changes globalPointSlaves to be indices into compact data
 
     List<Map<label> > compactMap(Pstream::nProcs());
-    globalPointSlavesMapPtr_.reset
+    globalPointSlavesMapPtr.reset
     (
         new mapDistribute
         (
@@ -477,41 +474,50 @@ void Foam::globalMeshData::calcGlobalPointSlaves() const
 
     if (debug)
     {
-        Pout<< "globalMeshData::calcGlobalPointSlaves() :"
+        Pout<< "globalMeshData::calcGlobalPointSlaves(..) :"
             << " coupled points:" << coupledPatch().nPoints()
             << " additional remote points:"
-            <<  globalPointSlavesMapPtr_().constructSize()
+            <<  globalPointSlavesMapPtr().constructSize()
               - coupledPatch().nPoints()
             << endl;
     }
 }
 
 
-void Foam::globalMeshData::calcGlobalEdgeSlaves() const
+void Foam::globalMeshData::calcGlobalPointSlaves() const
 {
     if (debug)
     {
-        Pout<< "globalMeshData::calcGlobalEdgeSlaves() :"
-            << " calculating coupled master to slave edge addressing."
+        Pout<< "globalMeshData::calcGlobalPointSlaves() :"
+            << " calculating coupled master to collocated"
+            << " slave point addressing."
             << endl;
     }
 
-    const labelListList& globalPointSlaves = this->globalPointSlaves();
-    const mapDistribute& globalPointSlavesMap = this->globalPointSlavesMap();
+    // Calculate collocated connected points for master points.
+    globalPoints collocatedGlobalData(mesh_, coupledPatch(), true, false);
 
-    // - Send across connected edges (in global edge addressing)
-    // - Check on receiving side whether edge has same slave edge
-    //   on both endpoints.
-
-    // Create global numbering for coupled edges
-    globalEdgeNumberingPtr_.reset
+    calcGlobalPointSlaves
     (
-        new globalIndex(coupledPatch().nEdges())
+        collocatedGlobalData,
+        globalPointNumberingPtr_,
+        globalPointSlavesPtr_,
+        globalPointSlavesMapPtr_
     );
-    const globalIndex& globalIndices = globalEdgeNumberingPtr_();
+}
 
+
+void Foam::globalMeshData::calcGlobalEdgeSlaves
+(
+    const labelListList& pointSlaves,
+    const mapDistribute& pointSlavesMap,
+    const globalIndex& globalEdgeIndices,
+    autoPtr<labelListList>& globalEdgeSlavesPtr,
+    autoPtr<mapDistribute>& globalEdgeSlavesMapPtr
+) const
+{
     // Coupled point to global coupled edges.
-    labelListList globalPointEdges(globalPointSlavesMap.constructSize());
+    labelListList globalPointEdges(pointSlavesMap.constructSize());
 
     // Create local version
     const labelListList& pointEdges = coupledPatch().pointEdges();
@@ -522,12 +528,12 @@ void Foam::globalMeshData::calcGlobalEdgeSlaves() const
         globalPEdges.setSize(pEdges.size());
         forAll(pEdges, i)
         {
-            globalPEdges[i] = globalIndices.toGlobal(pEdges[i]);
+            globalPEdges[i] = globalEdgeIndices.toGlobal(pEdges[i]);
         }
     }
 
     // Pull slave data to master
-    globalPointSlavesMap.distribute(globalPointEdges);
+    pointSlavesMap.distribute(globalPointEdges);
 
     // Now check on master if any of my edges are also on slave.
     // This assumes that if slaves have a coupled edge it is also on
@@ -538,14 +544,14 @@ void Foam::globalMeshData::calcGlobalEdgeSlaves() const
     const edgeList& edges = coupledPatch().edges();
 
     // Create master to slave addressing. Empty for slave edges.
-    globalEdgeSlavesPtr_.reset(new labelListList(edges.size()));
-    labelListList& globalEdgeSlaves = globalEdgeSlavesPtr_();
+    globalEdgeSlavesPtr.reset(new labelListList(edges.size()));
+    labelListList& globalEdgeSlaves = globalEdgeSlavesPtr();
 
     forAll(edges, edgeI)
     {
         const edge& e = edges[edgeI];
-        const labelList& slaves0 = globalPointSlaves[e[0]];
-        const labelList& slaves1 = globalPointSlaves[e[1]];
+        const labelList& slaves0 = pointSlaves[e[0]];
+        const labelList& slaves1 = pointSlaves[e[1]];
 
         // Check for edges that are in both slaves0 and slaves1.
         pointEdgeSet.clear();
@@ -576,11 +582,11 @@ void Foam::globalMeshData::calcGlobalEdgeSlaves() const
 
     // Construct map
     List<Map<label> > compactMap(Pstream::nProcs());
-    globalEdgeSlavesMapPtr_.reset
+    globalEdgeSlavesMapPtr.reset
     (
         new mapDistribute
         (
-            globalIndices,
+            globalEdgeIndices,
             globalEdgeSlaves,
             compactMap
         )
@@ -591,12 +597,39 @@ void Foam::globalMeshData::calcGlobalEdgeSlaves() const
         Pout<< "globalMeshData::calcGlobalEdgeSlaves() :"
             << " coupled edge:" << edges.size()
             << " additional remote edges:"
-            << globalEdgeSlavesMapPtr_().constructSize() - edges.size()
+            << globalEdgeSlavesMapPtr().constructSize() - edges.size()
             << endl;
     }
 }
 
 
+void Foam::globalMeshData::calcGlobalEdgeSlaves() const
+{
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalEdgeSlaves() :"
+            << " calculating coupled master to collocated slave"
+            << " edge addressing." << endl;
+    }
+
+    // - Send across connected edges (in global edge addressing)
+    // - Check on receiving side whether edge has same slave edge
+    //   on both endpoints.
+
+    // Create global numbering for coupled edges
+    const globalIndex& globalIndices = globalEdgeNumbering();
+
+    calcGlobalEdgeSlaves
+    (
+        globalPointSlaves(),
+        globalPointSlavesMap(),
+        globalIndices,
+        globalEdgeSlavesPtr_,
+        globalEdgeSlavesMapPtr_
+    );
+}
+
+
 // Calculate uncoupled boundary faces (without calculating
 // primitiveMesh::pointFaces())
 void Foam::globalMeshData::calcPointBoundaryFaces
@@ -961,6 +994,55 @@ void Foam::globalMeshData::calcGlobalPointBoundaryCells() const
 }
 
 
+void Foam::globalMeshData::calcGlobalPointAllSlaves() const
+{
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalPointAllSlaves() :"
+            << " calculating coupled master to slave point addressing."
+            << endl;
+    }
+
+    // Calculate collocated&non-collocated connected points for master points.
+    globalPoints allGlobalData(mesh_, coupledPatch(), true, true);
+
+    calcGlobalPointSlaves
+    (
+        allGlobalData,
+        globalPointAllNumberingPtr_,
+        globalPointAllSlavesPtr_,
+        globalPointAllSlavesMapPtr_
+    );
+}
+
+
+void Foam::globalMeshData::calcGlobalEdgeAllSlaves() const
+{
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalEdgeAllSlaves() :"
+            << " calculating coupled master to slave edge addressing."
+            << endl;
+    }
+
+    // - Send across connected edges (in global edge addressing)
+    // - Check on receiving side whether edge has same slave edge
+    //   on both endpoints.
+
+    // Create global numbering for coupled edges
+    const globalIndex& globalIndices = globalEdgeNumbering();
+
+    calcGlobalEdgeSlaves
+    (
+        globalPointAllSlaves(),
+        globalPointAllSlavesMap(),
+        globalIndices,
+        globalEdgeAllSlavesPtr_,
+        globalEdgeAllSlavesMapPtr_
+    );
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 // Construct from polyMesh
@@ -1057,6 +1139,17 @@ void Foam::globalMeshData::clearOut()
     globalBoundaryCellNumberingPtr_.clear();
     globalPointBoundaryCellsPtr_.clear();
     globalPointBoundaryCellsMapPtr_.clear();
+
+    //- Non-collocated
+
+    // Point
+    globalPointAllNumberingPtr_.clear();
+    globalPointAllSlavesPtr_.clear();
+    globalPointAllSlavesMapPtr_.clear();
+    // Edge
+    globalEdgeAllSlavesPtr_.clear();
+    globalEdgeAllSlavesMapPtr_.clear();
+
 }
 
 
@@ -1212,7 +1305,7 @@ Foam::pointField Foam::globalMeshData::geometricSharedPoints() const
     labelList pMap;
     pointField mergedPoints;
 
-    mergePoints
+    Foam::mergePoints
     (
         sharedPoints,   // coordinates to merge
         tolDim,         // tolerance
@@ -1350,7 +1443,10 @@ const Foam::globalIndex& Foam::globalMeshData::globalEdgeNumbering() const
 {
     if (!globalEdgeNumberingPtr_.valid())
     {
-        calcGlobalEdgeSlaves();
+        globalEdgeNumberingPtr_.reset
+        (
+            new globalIndex(coupledPatch().nEdges())
+        );
     }
     return globalEdgeNumberingPtr_();
 }
@@ -1452,6 +1548,293 @@ const
 }
 
 
+
+// Non-collocated coupled point/edge addressing
+
+const Foam::globalIndex& Foam::globalMeshData::globalPointAllNumbering() const
+{
+    if (!globalPointAllNumberingPtr_.valid())
+    {
+        calcGlobalPointAllSlaves();
+    }
+    return globalPointAllNumberingPtr_();
+}
+
+
+const Foam::labelListList& Foam::globalMeshData::globalPointAllSlaves() const
+{
+    if (!globalPointAllSlavesPtr_.valid())
+    {
+        calcGlobalPointAllSlaves();
+    }
+    return globalPointAllSlavesPtr_();
+}
+
+
+const Foam::mapDistribute& Foam::globalMeshData::globalPointAllSlavesMap() const
+{
+    if (!globalPointAllSlavesMapPtr_.valid())
+    {
+        calcGlobalPointAllSlaves();
+    }
+    return globalPointAllSlavesMapPtr_();
+}
+
+
+const Foam::labelListList& Foam::globalMeshData::globalEdgeAllSlaves() const
+{
+    if (!globalEdgeAllSlavesPtr_.valid())
+    {
+        calcGlobalEdgeAllSlaves();
+    }
+    return globalEdgeAllSlavesPtr_();
+}
+
+
+const Foam::mapDistribute& Foam::globalMeshData::globalEdgeAllSlavesMap() const
+{
+    if (!globalEdgeAllSlavesMapPtr_.valid())
+    {
+        calcGlobalEdgeAllSlaves();
+    }
+    return globalEdgeAllSlavesMapPtr_();
+}
+
+
+Foam::autoPtr<Foam::globalIndex> Foam::globalMeshData::mergePoints
+(
+    labelList& pointToGlobal,
+    labelList& uniquePoints
+) const
+{
+    const indirectPrimitivePatch& cpp = coupledPatch();
+    const labelListList& pointSlaves = globalPointSlaves();
+    const mapDistribute& pointSlavesMap = globalPointSlavesMap();
+
+
+    // 1. Count number of masters on my processor.
+    label nCoupledMaster = 0;
+    PackedBoolList isMaster(mesh_.nPoints(), 1);
+    forAll(pointSlaves, pointI)
+    {
+        const labelList& slavePoints = pointSlaves[pointI];
+
+        if (slavePoints.size() > 0)
+        {
+            nCoupledMaster++;
+        }
+        else
+        {
+            isMaster[cpp.meshPoints()[pointI]] = 0;
+        }
+    }
+
+    label myUniquePoints = mesh_.nPoints() - cpp.nPoints() + nCoupledMaster;
+
+    //Pout<< "Points :" << nl
+    //    << "    mesh             : " << mesh_.nPoints() << nl
+    //    << "    of which coupled : " << cpp.nPoints() << nl
+    //    << "    of which master  : " << nCoupledMaster << nl
+    //    << endl;
+
+
+    // 2. Create global indexing for unique points.
+    autoPtr<globalIndex> globalPointsPtr(new globalIndex(myUniquePoints));
+
+
+    // 3. Assign global point numbers. Keep slaves unset.
+    pointToGlobal.setSize(mesh_.nPoints());
+    pointToGlobal = -1;
+    uniquePoints.setSize(myUniquePoints);
+    label nMaster = 0;
+
+    forAll(isMaster, meshPointI)
+    {
+        if (isMaster[meshPointI])
+        {
+            pointToGlobal[meshPointI] = globalPointsPtr().toGlobal(nMaster);
+            uniquePoints[nMaster] = meshPointI;
+            nMaster++;
+        }
+    }
+
+
+    // 4. Push global index for coupled points to slaves.
+    {
+        labelList masterToGlobal(pointSlavesMap.constructSize(), -1);
+
+        forAll(pointSlaves, pointI)
+        {
+            const labelList& slaves = pointSlaves[pointI];
+
+            if (slaves.size() > 0)
+            {
+                // Duplicate master globalpoint into slave slots
+                label meshPointI = cpp.meshPoints()[pointI];
+                masterToGlobal[pointI] = pointToGlobal[meshPointI];
+                forAll(slaves, i)
+                {
+                    masterToGlobal[slaves[i]] = masterToGlobal[pointI];
+                }
+            }
+        }
+
+        // Send back
+        pointSlavesMap.reverseDistribute(cpp.nPoints(), masterToGlobal);
+
+        // On slave copy master index into overal map.
+        forAll(pointSlaves, pointI)
+        {
+            const labelList& slaves = pointSlaves[pointI];
+
+            if (slaves.size() == 0)
+            {
+                label meshPointI = cpp.meshPoints()[pointI];
+                pointToGlobal[meshPointI] = masterToGlobal[pointI];
+            }
+        }
+    }
+
+    return globalPointsPtr;
+}
+
+
+Foam::autoPtr<Foam::globalIndex> Foam::globalMeshData::mergePoints
+(
+    const labelList& meshPoints,
+    const Map<label>& meshPointMap,
+    labelList& pointToGlobal,
+    labelList& uniquePoints
+) const
+{
+    const indirectPrimitivePatch& cpp = coupledPatch();
+    const labelListList& pointSlaves = globalPointSlaves();
+    const mapDistribute& pointSlavesMap = globalPointSlavesMap();
+
+
+    // 1. Count number of masters on my processor.
+    label nCoupledMaster = 0;
+    label nCoupledSlave = 0;
+    PackedBoolList isMaster(meshPoints.size(), 1);
+
+    forAll(meshPoints, localPointI)
+    {
+        label meshPointI = meshPoints[localPointI];
+
+        Map<label>::const_iterator iter = cpp.meshPointMap().find(meshPointI);
+
+        if (iter != cpp.meshPointMap().end())
+        {
+            // My localPointI is a coupled point.
+
+            label coupledPointI = iter();
+
+            if (pointSlaves[coupledPointI].size() > 0)
+            {
+                nCoupledMaster++;
+            }
+            else
+            {
+                isMaster[localPointI] = 0;
+                nCoupledSlave++;
+            }
+        }
+    }
+
+    label myUniquePoints = meshPoints.size() + nCoupledMaster - nCoupledSlave;
+
+Pout<< "Points :" << nl
+    << "    patch            : " << meshPoints.size() << nl
+    << "    of which coupled : " << nCoupledMaster+nCoupledSlave << nl
+    << "    of which master  : " << nCoupledMaster << nl
+    << "    of which slave   : " << nCoupledSlave << nl
+    << endl;
+
+
+    // 2. Create global indexing for unique points.
+    autoPtr<globalIndex> globalPointsPtr(new globalIndex(myUniquePoints));
+
+
+    // 3. Assign global point numbers. Keep slaves unset.
+    pointToGlobal.setSize(meshPoints.size());
+    pointToGlobal = -1;
+    uniquePoints.setSize(myUniquePoints);
+    label nMaster = 0;
+
+    forAll(isMaster, localPointI)
+    {
+        if (isMaster[localPointI])
+        {
+            pointToGlobal[localPointI] = globalPointsPtr().toGlobal(nMaster);
+            uniquePoints[nMaster] = localPointI;
+            nMaster++;
+        }
+    }
+
+
+    // 4. Push global index for coupled points to slaves.
+    {
+        labelList masterToGlobal(pointSlavesMap.constructSize(), -1);
+
+        forAll(meshPoints, localPointI)
+        {
+            label meshPointI = meshPoints[localPointI];
+
+            Map<label>::const_iterator iter = cpp.meshPointMap().find
+            (
+                meshPointI
+            );
+
+            if (iter != cpp.meshPointMap().end())
+            {
+                // My localPointI is a coupled point.
+                label coupledPointI = iter();
+
+                const labelList& slaves = pointSlaves[coupledPointI];
+
+                if (slaves.size() > 0)
+                {
+                    // Duplicate master globalpoint into slave slots
+                    masterToGlobal[coupledPointI] = pointToGlobal[meshPointI];
+                    forAll(slaves, i)
+                    {
+                        masterToGlobal[slaves[i]] = pointToGlobal[meshPointI];
+                    }
+                }
+            }
+        }
+
+        // Send back
+        pointSlavesMap.reverseDistribute(cpp.nPoints(), masterToGlobal);
+
+        // On slave copy master index into overal map.
+        forAll(meshPoints, localPointI)
+        {
+            label meshPointI = meshPoints[localPointI];
+
+            Map<label>::const_iterator iter = cpp.meshPointMap().find
+            (
+                meshPointI
+            );
+
+            if (iter != cpp.meshPointMap().end())
+            {
+                // My localPointI is a coupled point.
+                label coupledPointI = iter();
+                const labelList& slaves = pointSlaves[coupledPointI];
+
+                if (slaves.size() == 0)
+                {
+                    pointToGlobal[meshPointI] = masterToGlobal[coupledPointI];
+                }
+            }
+        }
+    }
+
+    return globalPointsPtr;
+}
+
+
 void Foam::globalMeshData::movePoints(const pointField& newPoints)
 {
     // Topology does not change and we don't store any geometry so nothing
@@ -1482,8 +1865,9 @@ void Foam::globalMeshData::updateMesh()
 
     // Option 1. Topological
     {
-        // Calculate all shared points. This does all the hard work.
-        globalPoints parallelPoints(mesh_, false);
+        // Calculate all shared points (excluded points that are only
+        // on two coupled patches). This does all the hard work.
+        globalPoints parallelPoints(mesh_, false, true);
 
         // Copy data out.
         nGlobalPoints_ = parallelPoints.nGlobalPoints();
@@ -1505,6 +1889,16 @@ void Foam::globalMeshData::updateMesh()
     //    sharedEdgeAddr_ = parallelPoints.sharedEdgeAddr();
     //}
 
+    if (debug)
+    {
+        Pout<< "globalMeshData : nGlobalPoints_:" << nGlobalPoints_ << nl
+            << "globalMeshData : sharedPointLabels_:"
+            << sharedPointLabels_.size() << nl
+            << "globalMeshData : sharedPointAddr_:"
+            << sharedPointAddr_.size() << endl;
+    }
+
+
     // Total number of faces. Start off from all faces. Remove coincident
     // processor faces (on highest numbered processor) before summing.
     nTotalFaces_ = mesh_.nFaces();
diff --git a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H
index a6e03baf957..f397d69ae14 100644
--- a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H
+++ b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H
@@ -31,7 +31,7 @@ Description
 
     Requires:
     - all processor patches to have correct ordering.
-    - all processorPatches to have their transforms set ('makeTransforms')
+    - all processorPatches to have their transforms set.
 
     The shared point addressing is quite interesting. It gives on each processor
     the vertices that cannot be set using a normal swap on processor patches.
@@ -67,14 +67,12 @@ Description
 
 SourceFiles
     globalMeshData.C
-    globalMeshDataMorph.C
 
 \*---------------------------------------------------------------------------*/
 
 #ifndef globalMeshData_H
 #define globalMeshData_H
 
-//#include "polyMesh.H"
 #include "Switch.H"
 #include "processorTopology.H"
 #include "labelPair.H"
@@ -95,6 +93,7 @@ class globalIndex;
 class polyMesh;
 class mapDistribute;
 template<class T> class EdgeMap;
+class globalPoints;
 
 /*---------------------------------------------------------------------------*\
                            Class globalMeshData Declaration
@@ -201,31 +200,36 @@ class globalMeshData
 
 
         // Coupled point addressing
-        // This is addressing from coupled point to coupled points,faces,cells
+        // This is addressing from coupled point to coupled points/faces/cells.
+        // Two variants:
+        //  - collocated (so not physically separated)
+        //  - also separated
         // This is a full schedule so includes points only used by two
         // coupled patches.
 
             mutable autoPtr<indirectPrimitivePatch> coupledPatchPtr_;
 
-            // Coupled point to coupled points
+            // Collocated
+
+                // Coupled point to collocated coupled points
 
                 mutable autoPtr<globalIndex> globalPointNumberingPtr_;
                 mutable autoPtr<labelListList> globalPointSlavesPtr_;
                 mutable autoPtr<mapDistribute> globalPointSlavesMapPtr_;
 
-            // Coupled edge to coupled edges
+                // Coupled edge to collocated coupled edges
 
                 mutable autoPtr<globalIndex> globalEdgeNumberingPtr_;
                 mutable autoPtr<labelListList> globalEdgeSlavesPtr_;
                 mutable autoPtr<mapDistribute> globalEdgeSlavesMapPtr_;
 
-            // Coupled point to boundary faces
+                // Coupled point to collocated boundary faces
 
                 mutable autoPtr<globalIndex> globalBoundaryFaceNumberingPtr_;
                 mutable autoPtr<labelListList> globalPointBoundaryFacesPtr_;
                 mutable autoPtr<mapDistribute> globalPointBoundaryFacesMapPtr_;
 
-            // Coupled point to boundary cells
+                // Coupled point to collocated boundary cells
 
                 mutable autoPtr<labelList> boundaryCellsPtr_;
                 mutable autoPtr<globalIndex> globalBoundaryCellNumberingPtr_;
@@ -233,6 +237,21 @@ class globalMeshData
                 mutable autoPtr<mapDistribute> globalPointBoundaryCellsMapPtr_;
 
 
+            // Non-collocated as well
+
+                // Coupled point to all coupled points
+
+                mutable autoPtr<globalIndex> globalPointAllNumberingPtr_;
+                mutable autoPtr<labelListList> globalPointAllSlavesPtr_;
+                mutable autoPtr<mapDistribute> globalPointAllSlavesMapPtr_;
+
+                // Coupled edge to all coupled edges (same numbering as
+                // collocated coupled edges)
+
+                mutable autoPtr<labelListList> globalEdgeAllSlavesPtr_;
+                mutable autoPtr<mapDistribute> globalEdgeAllSlavesMapPtr_;
+
+
     // Private Member Functions
 
         //- Set up processor patch addressing
@@ -256,9 +275,28 @@ class globalMeshData
             const vectorField& separationDist
         );
 
+        //- Calculate global point addressing.
+        void calcGlobalPointSlaves
+        (
+            const globalPoints&,
+            autoPtr<globalIndex>&,
+            autoPtr<labelListList>&,
+            autoPtr<mapDistribute>&
+        ) const;
+
         //- Calculate global point addressing.
         void calcGlobalPointSlaves() const;
 
+        //- Calculate global edge addressing.
+        void calcGlobalEdgeSlaves
+        (
+            const labelListList&,
+            const mapDistribute&,
+            const globalIndex&,
+            autoPtr<labelListList>&,
+            autoPtr<mapDistribute>&
+        ) const;
+
         //- Calculate global edge addressing.
         void calcGlobalEdgeSlaves() const;
 
@@ -272,6 +310,15 @@ class globalMeshData
         void calcGlobalPointBoundaryCells() const;
 
 
+        // Non-collocated
+
+            //- Calculate global point addressing.
+            void calcGlobalPointAllSlaves() const;
+
+            //- Calculate global edge addressing.
+            void calcGlobalEdgeAllSlaves() const;
+
+
         //- Disallow default bitwise copy construct
         globalMeshData(const globalMeshData&);
 
@@ -449,8 +496,8 @@ public:
             //- Return patch of all coupled faces
             const indirectPrimitivePatch& coupledPatch() const;
 
-            // Coupled point to coupled points. Coupled points are points on
-            // any coupled patch.
+            // Coupled point to collocated coupled points. Coupled points are
+            // points on any coupled patch.
 
                 //- Numbering of coupled points is according to coupledPatch.
                 const globalIndex& globalPointNumbering() const;
@@ -484,6 +531,45 @@ public:
                 const mapDistribute& globalPointBoundaryCellsMap() const;
 
 
+            // Collocated & non-collocated
+
+                // Coupled point to all coupled points (collocated and
+                // non-collocated).
+
+                    const globalIndex& globalPointAllNumbering()const;
+                    const labelListList& globalPointAllSlaves() const;
+                    const mapDistribute& globalPointAllSlavesMap() const;
+
+                // Coupled edge to all coupled edges (same numbering as
+                // collocated)
+
+                    const labelListList& globalEdgeAllSlaves() const;
+                    const mapDistribute& globalEdgeAllSlavesMap() const;
+
+            // Other
+
+                //- Helper for merging mesh point data. Determines
+                //  - my unique indices
+                //  - global numbering over all unique indices
+                //  - the global number for all local points (so this will
+                //    be local for my unique points)
+                autoPtr<globalIndex> mergePoints
+                (
+                    labelList& pointToGlobal,
+                    labelList& uniquePoints
+                ) const;
+
+                //- Helper for merging patch point data. Takes maps from
+                //  local points to/from mesh
+                autoPtr<globalIndex> mergePoints
+                (
+                    const labelList& meshPoints,
+                    const Map<label>& meshPointMap,
+                    labelList& pointToGlobal,
+                    labelList& uniquePoints
+                ) const;
+
+
         // Edit
 
             //- Update for moving points.
diff --git a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.C b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.C
index 6dfc702fdd6..f62527b2722 100644
--- a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.C
+++ b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.C
@@ -33,9 +33,212 @@ License
 
 defineTypeNameAndDebug(Foam::globalPoints, 0);
 
+const Foam::label Foam::globalPoints::fromCollocated = labelMax/2;
+
+const Foam::scalar Foam::globalPoints::mergeDist = ROOTVSMALL;
+
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
+// Routines to handle global indices
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+bool Foam::globalPoints::noTransform(const tensor& tt, const scalar mergeDist)
+{
+    return
+        (mag(tt.xx()-1) < mergeDist)
+     && (mag(tt.yy()-1) < mergeDist)
+     && (mag(tt.zz()-1) < mergeDist)
+     && (mag(tt.xy()) < mergeDist)
+     && (mag(tt.xz()) < mergeDist)
+     && (mag(tt.yx()) < mergeDist)
+     && (mag(tt.yz()) < mergeDist)
+     && (mag(tt.zx()) < mergeDist)
+     && (mag(tt.zy()) < mergeDist);
+}
+
+
+// Calculates per face whether couple is collocated.
+Foam::PackedBoolList Foam::globalPoints::collocatedFaces
+(
+    const coupledPolyPatch& pp,
+    const scalar mergeDist
+)
+{
+    // Initialise to false
+    PackedBoolList collocated(pp.size());
+
+    const vectorField& separation = pp.separation();
+    const tensorField& forwardT = pp.forwardT();
+
+    if (forwardT.size() == 0)
+    {
+        // Parallel.
+        if (separation.size() == 0)
+        {
+            collocated = 1u;
+        }
+        else if (separation.size() == 1)
+        {
+            // Fully separate. Do not synchronise.
+        }
+        else
+        {
+            // Per face separation.
+            forAll(pp, faceI)
+            {
+                if (mag(separation[faceI]) < mergeDist)
+                {
+                    collocated[faceI] = 1u;
+                }
+            }
+        }
+    }
+    else if (forwardT.size() == 1)
+    {
+        // Fully transformed.
+    }
+    else
+    {
+        // Per face transformation.
+        forAll(pp, faceI)
+        {
+            if (noTransform(forwardT[faceI], mergeDist))
+            {
+                collocated[faceI] = 1u;
+            }
+        }
+    }
+    return collocated;
+}
+
+
+Foam::PackedBoolList Foam::globalPoints::collocatedPoints
+(
+    const coupledPolyPatch& pp,
+    const scalar mergeDist
+)
+{
+    // Initialise to false
+    PackedBoolList collocated(pp.nPoints());
+
+    const vectorField& separation = pp.separation();
+    const tensorField& forwardT = pp.forwardT();
+
+    if (forwardT.size() == 0)
+    {
+        // Parallel.
+        if (separation.size() == 0)
+        {
+            collocated = 1u;
+        }
+        else if (separation.size() == 1)
+        {
+            // Fully separate.
+        }
+        else
+        {
+            // Per face separation.
+            for (label pointI = 0; pointI < pp.nPoints(); pointI++)
+            {
+                label faceI = pp.pointFaces()[pointI][0];
+
+                if (mag(separation[faceI]) < mergeDist)
+                {
+                    collocated[pointI] = 1u;
+                }
+            }
+        }
+    }
+    else if (forwardT.size() == 1)
+    {
+        // Fully transformed.
+    }
+    else
+    {
+        // Per face transformation.
+        for (label pointI = 0; pointI < pp.nPoints(); pointI++)
+        {
+            label faceI = pp.pointFaces()[pointI][0];
+
+            if (noTransform(forwardT[faceI], mergeDist))
+            {
+                collocated[pointI] = 1u;
+            }
+        }
+    }
+    return collocated;
+}
+
+
+Foam::label Foam::globalPoints::toGlobal
+(
+    const label localPointI,
+    const bool isCollocated
+) const
+{
+    label globalPointI = globalIndices_.toGlobal(localPointI);
+
+    if (isCollocated)
+    {
+        return globalPointI + fromCollocated;
+    }
+    else
+    {
+        return globalPointI;
+    }
+}
+
+
+bool Foam::globalPoints::isCollocated(const label globalI) const
+{
+    return globalI >= fromCollocated;
+}
+
+
+Foam::label Foam::globalPoints::removeCollocated(const label globalI) const
+{
+    if (globalI >= fromCollocated)
+    {
+        return globalI - fromCollocated;
+    }
+    else
+    {
+        return globalI;
+    }
+}
+
+
+bool Foam::globalPoints::isLocal(const label globalI) const
+{
+    return globalIndices_.isLocal(removeCollocated(globalI));
+}
+
+
+Foam::label Foam::globalPoints::whichProcID(const label globalI) const
+{
+    return globalIndices_.whichProcID(removeCollocated(globalI));
+}
+
+
+Foam::label Foam::globalPoints::toLocal
+(
+    const label procI,
+    const label globalI
+) const
+{
+    return globalIndices_.toLocal(procI, removeCollocated(globalI));
+}
+
+
+Foam::label Foam::globalPoints::toLocal(const label globalI) const
+{
+    return toLocal(Pstream::myProcNo(), globalI);
+}
+
+
+// Collect all topological information about a point on a patch.
+
 // Total number of points on processor patches. Is upper limit for number
 // of shared points
 Foam::label Foam::globalPoints::countPatchPoints
@@ -164,7 +367,8 @@ Foam::label Foam::globalPoints::localToMeshPoint
 bool Foam::globalPoints::storeInfo
 (
     const labelList& nbrInfo,
-    const label localPointI
+    const label localPointI,
+    const bool isCollocated
 )
 {
     label infoChanged = false;
@@ -181,7 +385,7 @@ bool Foam::globalPoints::storeInfo
     }
     else
     {
-        labelList knownInfo(1, globalIndices_.toGlobal(localPointI));
+        labelList knownInfo(1, toGlobal(localPointI, isCollocated));
 
         if (mergeInfo(nbrInfo, knownInfo))
         {
@@ -197,6 +401,46 @@ bool Foam::globalPoints::storeInfo
 }
 
 
+void Foam::globalPoints::printProcPoints
+(
+    const labelList& patchToMeshPoint,
+    const labelList& pointInfo,
+    Ostream& os
+) const
+{
+    forAll(pointInfo, i)
+    {
+        label globalI = pointInfo[i];
+
+        label procI = whichProcID(globalI);
+        os  << "    connected to proc " << procI;
+
+        if (isCollocated(globalI))
+        {
+            os  << " collocated localpoint:";
+        }
+        else
+        {
+            os  << " separated localpoint:";
+        }
+
+        os  << toLocal(procI, globalI);
+
+        if (isLocal(globalI))
+        {
+            label meshPointI = localToMeshPoint
+            (
+                patchToMeshPoint,
+                toLocal(globalI)
+            );
+            os  << " at:" <<  mesh_.points()[meshPointI];
+        }
+
+        os  << endl;
+    }
+}
+
+
 // Insert my own points into structure and mark as changed.
 void Foam::globalPoints::initOwnPoints
 (
@@ -217,14 +461,26 @@ void Foam::globalPoints::initOwnPoints
          || isA<cyclicPolyPatch>(pp)
         )
         {
+            // Find points with transforms
+
+            PackedBoolList isCollocatedPoint
+            (
+                collocatedPoints
+                (
+                    refCast<const coupledPolyPatch>(pp),
+                    mergeDist
+                )
+            );
+
+
             const labelList& meshPoints = pp.meshPoints();
 
             if (allPoints)
             {
                 // All points on patch
-                forAll(meshPoints, i)
+                forAll(meshPoints, patchPointI)
                 {
-                    label meshPointI = meshPoints[i];
+                    label meshPointI = meshPoints[patchPointI];
                     label localPointI = meshToLocalPoint
                     (
                         meshToPatchPoint,
@@ -233,7 +489,7 @@ void Foam::globalPoints::initOwnPoints
                     labelList knownInfo
                     (
                         1,
-                        globalIndices_.toGlobal(localPointI)
+                        toGlobal(localPointI, isCollocatedPoint[patchPointI])
                     );
 
                     // Update addressing from point to index in procPoints
@@ -262,7 +518,11 @@ void Foam::globalPoints::initOwnPoints
                     labelList knownInfo
                     (
                         1,
-                        globalIndices_.toGlobal(localPointI)
+                        toGlobal
+                        (
+                            localPointI,
+                            isCollocatedPoint[boundaryPoints[i]]
+                        )
                     );
 
                     // Update addressing from point to index in procPoints
@@ -282,6 +542,7 @@ void Foam::globalPoints::initOwnPoints
 // Send all my info on changedPoints_ to my neighbours.
 void Foam::globalPoints::sendPatchPoints
 (
+    const bool mergeSeparated,
     const Map<label>& meshToPatchPoint,
     PstreamBuffers& pBufs,
     const labelHashSet& changedPoints
@@ -295,6 +556,19 @@ void Foam::globalPoints::sendPatchPoints
 
         if (Pstream::parRun() && isA<processorPolyPatch>(pp))
         {
+            const processorPolyPatch& procPatch =
+                refCast<const processorPolyPatch>(pp);
+
+            PackedBoolList isCollocatedPoint
+            (
+                collocatedPoints
+                (
+                    procPatch,
+                    mergeDist
+                )
+            );
+
+
             // Information to send:
             // patch face
             DynamicList<label> patchFaces(pp.nPoints());
@@ -312,48 +586,47 @@ void Foam::globalPoints::sendPatchPoints
 
             forAll(meshPoints, patchPointI)
             {
-                label meshPointI = meshPoints[patchPointI];
-                label localPointI = meshToLocalPoint
-                (
-                    meshToPatchPoint,
-                    meshPointI
-                );
-
-                if (changedPoints.found(localPointI))
+                if (mergeSeparated || isCollocatedPoint[patchPointI])
                 {
-                    label index = meshToProcPoint_[localPointI];
+                    label meshPointI = meshPoints[patchPointI];
+                    label localPointI = meshToLocalPoint
+                    (
+                        meshToPatchPoint,
+                        meshPointI
+                    );
 
-                    const labelList& knownInfo = procPoints_[index];
+                    if (changedPoints.found(localPointI))
+                    {
+                        label index = meshToProcPoint_[localPointI];
 
-                    // Add my information about localPointI to the send buffers
-                    addToSend
-                    (
-                        pp,
-                        patchPointI,
-                        knownInfo,
+                        const labelList& knownInfo = procPoints_[index];
 
-                        patchFaces,
-                        indexInFace,
-                        allInfo
-                    );
+                        // Add my information about localPointI to the
+                        // send buffers
+                        addToSend
+                        (
+                            pp,
+                            patchPointI,
+                            knownInfo,
+
+                            patchFaces,
+                            indexInFace,
+                            allInfo
+                        );
+                    }
                 }
             }
 
             // Send to neighbour
+            if (debug)
             {
-                const processorPolyPatch& procPatch =
-                    refCast<const processorPolyPatch>(pp);
-
-                if (debug)
-                {
-                    Pout<< " Sending to "
-                        << procPatch.neighbProcNo() << "   point information:"
-                        << patchFaces.size() << endl;
-                }
-
-                UOPstream toNeighbour(procPatch.neighbProcNo(), pBufs);
-                toNeighbour << patchFaces << indexInFace << allInfo;
+                Pout<< " Sending to "
+                    << procPatch.neighbProcNo() << "   point information:"
+                    << patchFaces.size() << endl;
             }
+
+            UOPstream toNeighbour(procPatch.neighbProcNo(), pBufs);
+            toNeighbour << patchFaces << indexInFace << allInfo;
         }
     }
 }
@@ -366,6 +639,7 @@ void Foam::globalPoints::sendPatchPoints
 // - changedPoints: all points for which something changed.
 void Foam::globalPoints::receivePatchPoints
 (
+    const bool mergeSeparated,
     const Map<label>& meshToPatchPoint,
     PstreamBuffers& pBufs,
     labelHashSet& changedPoints
@@ -385,6 +659,15 @@ void Foam::globalPoints::receivePatchPoints
             const processorPolyPatch& procPatch =
                 refCast<const processorPolyPatch>(pp);
 
+            PackedBoolList isCollocatedPoint
+            (
+                collocatedPoints
+                (
+                    procPatch,
+                    mergeDist
+                )
+            );
+
             labelList patchFaces;
             labelList indexInFace;
             List<labelList> nbrInfo;
@@ -417,7 +700,15 @@ void Foam::globalPoints::receivePatchPoints
                     meshPointI
                 );
 
-                if (storeInfo(nbrInfo[i], localPointI))
+                if
+                (
+                    storeInfo
+                    (
+                        nbrInfo[i],
+                        localPointI,
+                        isCollocatedPoint[pp.meshPointMap()[meshPointI]]
+                    )
+                )
                 {
                     changedPoints.insert(localPointI);
                 }
@@ -431,6 +722,15 @@ void Foam::globalPoints::receivePatchPoints
             const cyclicPolyPatch& cycPatch =
                 refCast<const cyclicPolyPatch>(pp);
 
+            PackedBoolList isCollocatedPoint
+            (
+                collocatedPoints
+                (
+                    cycPatch,
+                    mergeDist
+                )
+            );
+
             const labelList& meshPoints = pp.meshPoints();
 
             //const edgeList& connections = cycPatch.coupledPoints();
@@ -440,44 +740,63 @@ void Foam::globalPoints::receivePatchPoints
             {
                 const edge& e = connections[i];
 
-                label meshPointA = meshPoints[e[0]];
-                label meshPointB = meshPoints[e[1]];
+                if (mergeSeparated || isCollocatedPoint[e[0]])
+                {
+                    label meshPointA = meshPoints[e[0]];
+                    label meshPointB = meshPoints[e[1]];
 
-                label localA = meshToLocalPoint
-                (
-                    meshToPatchPoint,
-                    meshPointA
-                );
-                label localB = meshToLocalPoint
-                (
-                    meshToPatchPoint,
-                    meshPointB
-                );
+                    label localA = meshToLocalPoint
+                    (
+                        meshToPatchPoint,
+                        meshPointA
+                    );
+                    label localB = meshToLocalPoint
+                    (
+                        meshToPatchPoint,
+                        meshPointB
+                    );
 
 
-                // Do we have information on pointA?
-                Map<label>::iterator procPointA =
-                    meshToProcPoint_.find(localA);
+                    // Do we have information on pointA?
+                    Map<label>::iterator procPointA =
+                        meshToProcPoint_.find(localA);
 
-                if (procPointA != meshToProcPoint_.end())
-                {
-                    // Store A info onto pointB
-                    if (storeInfo(procPoints_[procPointA()], localB))
+                    if (procPointA != meshToProcPoint_.end())
                     {
-                        changedPoints.insert(localB);
+                        // Store A info onto pointB
+                        if
+                        (
+                            storeInfo
+                            (
+                                procPoints_[procPointA()],
+                                localB,
+                                isCollocatedPoint[e[1]]
+                            )
+                        )
+                        {
+                            changedPoints.insert(localB);
+                        }
                     }
-                }
 
-                // Same for info on pointB
-                Map<label>::iterator procPointB =
-                    meshToProcPoint_.find(localB);
+                    // Same for info on pointB
+                    Map<label>::iterator procPointB =
+                        meshToProcPoint_.find(localB);
 
-                if (procPointB != meshToProcPoint_.end())
-                {
-                    // Store B info onto pointA
-                    if (storeInfo(procPoints_[procPointB()], localA))
+                    if (procPointB != meshToProcPoint_.end())
                     {
-                        changedPoints.insert(localA);
+                        // Store B info onto pointA
+                        if
+                        (
+                            storeInfo
+                            (
+                                procPoints_[procPointB()],
+                                localA,
+                                isCollocatedPoint[e[0]]
+                            )
+                        )
+                        {
+                            changedPoints.insert(localA);
+                        }
                     }
                 }
             }
@@ -520,23 +839,23 @@ void Foam::globalPoints::remove
             if
             (
                 (
-                    globalIndices_.isLocal(a)
-                 && directNeighbours.found(globalIndices_.toLocal(a))
+                    isLocal(a)
+                 && directNeighbours.found(toLocal(a))
                 )
              || (
-                    globalIndices_.isLocal(b)
-                 && directNeighbours.found(globalIndices_.toLocal(b))
+                    isLocal(b)
+                 && directNeighbours.found(toLocal(b))
                 )
             )
             {
                 // Normal faceNeighbours
-                if (globalIndices_.isLocal(a))
+                if (isLocal(a))
                 {
                     //Pout<< "Removing direct neighbour:"
                     //    << mesh_.points()[a[1]]
                     //    << endl;
                 }
-                else if (globalIndices_.isLocal(b))
+                else if (isLocal(b))
                 {
                     //Pout<< "Removing direct neighbour:"
                     //    << mesh_.points()[b[1]]
@@ -568,8 +887,8 @@ void Foam::globalPoints::remove
             // So this meshPoint will have info of size one only.
             if
             (
-                !globalIndices_.isLocal(pointInfo[0])
-             || !directNeighbours.found(globalIndices_.toLocal(pointInfo[0]))
+                !isLocal(pointInfo[0])
+             || !directNeighbours.found(toLocal(pointInfo[0]))
             )
             {
                 meshToProcPoint_.insert(localPointI, procPoints_.size());
@@ -588,33 +907,86 @@ void Foam::globalPoints::remove
 
 
 // Compact indices
-void Foam::globalPoints::compact()
+void Foam::globalPoints::compact(const labelList& patchToMeshPoint)
 {
-    // TBD: find same procPoints entries. Or rather check if
-    // in a procPoints there are points with indices < my index.
-    // This will just merge identical entries so lower storage, but will
-    // not affect anything else. Note: only relevant with cyclics.
-
     labelList oldToNew(procPoints_.size(), -1);
     labelList newToOld(meshToProcPoint_.size());
 
     label newIndex = 0;
-    forAllIter(Map<label>, meshToProcPoint_, iter)
+    forAllConstIter(Map<label>, meshToProcPoint_, iter)
     {
         label oldIndex = iter();
 
         if (oldToNew[oldIndex] == -1)
         {
-            iter() = newIndex;
-            oldToNew[oldIndex] = newIndex;
-            newToOld[newIndex] = oldIndex;
-            newIndex++;
+            // Check if one of the procPoints already is merged.
+            const labelList& pointInfo = procPoints_[oldIndex];
+
+            if (pointInfo.size() >= 2)
+            {
+                // Merge out single entries
+
+                label minIndex = labelMax;
+
+                forAll(pointInfo, i)
+                {
+                    if (isLocal(pointInfo[i]))
+                    {
+                        label localI = toLocal(pointInfo[i]);
+
+                        // Is localPoint itself already merged?
+                        label index = meshToProcPoint_[localI];
+
+                        //Pout<< "        found point:" << localI
+                        //    << " with current index " << index << endl;
+
+                        if (oldToNew[index] != -1)
+                        {
+                            minIndex = min(minIndex, oldToNew[index]);
+                        }
+                    }
+                }
+
+                if (minIndex < labelMax && minIndex != oldIndex)
+                {
+                    // Make my index point to minIndex
+                    oldToNew[oldIndex] = minIndex;
+                }
+                else
+                {
+                    // Nothing compacted yet. Allocate new index.
+                    oldToNew[oldIndex] = newIndex;
+                    newToOld[newIndex] = oldIndex;
+                    newIndex++;
+                }
+            }
+            else
+            {
+                //Pout<< "Removed singlepoint pointI:" << iter.key()
+                //    << " currentindex:" << iter()
+                //    << endl;
+            }
         }
     }
+
+    // Redo indices
+    Map<label> oldMeshToProcPoint(meshToProcPoint_.xfer());
+    forAllConstIter(Map<label>, oldMeshToProcPoint, iter)
+    {
+        label newIndex = oldToNew[iter()];
+        if (newIndex != -1)
+        {
+            meshToProcPoint_.insert(iter.key(), newIndex);
+        }
+    }
+
     List<labelList> oldProcPoints;
     oldProcPoints.transfer(procPoints_);
 
-    procPoints_.setSize(meshToProcPoint_.size());
+    newToOld.setSize(newIndex);
+
+    procPoints_.setSize(newIndex);
+
     forAll(procPoints_, i)
     {
         // Transfer
@@ -631,8 +1003,11 @@ Foam::labelList Foam::globalPoints::getMasterPoints
     const labelList& patchToMeshPoint
 ) const
 {
-    labelList masterPoints(nPatchPoints_);
-    label nMaster = 0;
+    //labelList masterPoints(nPatchPoints_);
+    //label nMaster = 0;
+
+    labelHashSet masterPointSet(nPatchPoints_);
+
 
     // Go through all equivalences and determine points where I am master.
     forAllConstIter(Map<label>, meshToProcPoint_, iter)
@@ -661,27 +1036,28 @@ Foam::labelList Foam::globalPoints::getMasterPoints
 
             if
             (
-                globalIndices_.isLocal(pointInfo[0])
-             && globalIndices_.toLocal(pointInfo[0]) == localPointI
+                isLocal(pointInfo[0])
+             && toLocal(pointInfo[0]) == localPointI
             )
             {
                 // I am lowest numbered processor and point. Add to my list.
-                masterPoints[nMaster++] = localPointI;
+                //masterPoints[nMaster++] = localPointI;
+                masterPointSet.insert(localPointI);
             }
         }
     }
 
-    masterPoints.setSize(nMaster);
-
-    return masterPoints;
+    return masterPointSet.toc();
 }
 
 
-// Send subset of lists
+// Send subset of lists.
+// Note: might not be used if separated
 void Foam::globalPoints::sendSharedPoints
 (
+    const bool mergeSeparated,
     PstreamBuffers& pBufs,
-    const labelList& changedIndices
+    const DynamicList<label>& changedIndices
 ) const
 {
     const polyBoundaryMesh& patches = mesh_.boundaryMesh();
@@ -713,19 +1089,62 @@ void Foam::globalPoints::sendSharedPoints
 }
 
 
+// Check if any connected local points already have a sharedPoint. This handles
+// locally connected points.
+void Foam::globalPoints::extendSharedPoints
+(
+    const Map<label>& meshToShared,
+    DynamicList<label>& changedIndices
+)
+{
+    forAllConstIter(Map<label>, meshToProcPoint_, iter)
+    {
+        label localI = iter.key();
+        label sharedI = meshToShared[localI];
+
+        if (sharedPointLabels_[sharedI] == -1)
+        {
+            // No sharedpoint yet for me. Check if any of my connected
+            // points have.
+
+            const labelList& pointInfo = procPoints_[iter()];
+            forAll(pointInfo, i)
+            {
+                if (isLocal(pointInfo[i]))
+                {
+                    label nbrLocalI = toLocal(pointInfo[i]);
+                    label nbrSharedI = meshToShared[nbrLocalI];
+
+                    if (sharedPointAddr_[nbrSharedI] != -1)
+                    {
+                        // I do have a sharedpoint for nbrSharedI. Reuse it.
+                        sharedPointLabels_[sharedI] = localI;
+                        sharedPointAddr_[sharedI] =
+                            sharedPointAddr_[nbrSharedI];
+                        changedIndices.append(sharedI);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
+
+
 // Receive shared point indices for all my shared points. Note that since
 // there are only a few here we can build a reverse map using the point label
 // instead of doing all this relative point indexing (patch face + index in
 // face) as in send/receivePatchPoints
 void Foam::globalPoints::receiveSharedPoints
 (
+    const bool mergeSeparated,
     const Map<label>& meshToPatchPoint,
+    const Map<label>& meshToShared,
     PstreamBuffers& pBufs,
-    labelList& changedIndices
+    DynamicList<label>& changedIndices
 )
 {
-    changedIndices.setSize(sharedPointAddr_.size());
-    label nChanged = 0;
+    changedIndices.clear();
 
     const polyBoundaryMesh& patches = mesh_.boundaryMesh();
 
@@ -770,21 +1189,21 @@ void Foam::globalPoints::receiveSharedPoints
             forAllConstIter(Map<label>, meshToProcPoint_, iter)
             {
                 label localPointI = iter.key();
-                label index = iter();
+                label sharedI = meshToShared[localPointI];
 
-                if (sharedPointAddr_[index] == -1)
+                if (sharedPointAddr_[sharedI] == -1)
                 {
                     // No shared point known yet for this point.
                     // See if was received from neighbour.
-                    const labelList& knownInfo = procPoints_[index];
+                    const labelList& knownInfo = procPoints_[iter()];
 
                     // Check through the whole equivalence list for any
                     // point from the neighbour.
                     forAll(knownInfo, j)
                     {
                         const label info = knownInfo[j];
-                        label procI = globalIndices_.whichProcID(info);
-                        label pointI = globalIndices_.toLocal(procI, info);
+                        label procI = whichProcID(info);
+                        label pointI = toLocal(procI, info);
 
                         if
                         (
@@ -795,9 +1214,9 @@ void Foam::globalPoints::receiveSharedPoints
                             // So this knownInfo contains the neighbour point
                             label sharedPointI = nbrSharedPoints[pointI];
 
-                            sharedPointAddr_[index] = sharedPointI;
-                            sharedPointLabels_[index] = localPointI;
-                            changedIndices[nChanged++] = index;
+                            sharedPointAddr_[sharedI] = sharedPointI;
+                            sharedPointLabels_[sharedI] = localPointI;
+                            changedIndices.append(sharedI);
 
                             break;
                         }
@@ -810,15 +1229,27 @@ void Foam::globalPoints::receiveSharedPoints
             const cyclicPolyPatch& cycPatch =
                 refCast<const cyclicPolyPatch>(pp);
 
-            // Build map from mesh or patch point to sharedPoint
+            PackedBoolList isCollocatedPoint
+            (
+                collocatedPoints
+                (
+                    cycPatch,
+                    mergeDist
+                )
+            );
+
+            // Build map from mesh or patch point to sharedPoint.
             Map<label> localToSharedPoint(sharedPointAddr_.size());
             forAll(sharedPointLabels_, i)
             {
-                localToSharedPoint.insert
-                (
-                    sharedPointLabels_[i],
-                    sharedPointAddr_[i]
-                );
+                if (sharedPointLabels_[i] != -1)
+                {
+                    localToSharedPoint.insert
+                    (
+                        sharedPointLabels_[i],
+                        sharedPointAddr_[i]
+                    );
+                }
             }
 
             // Sync all info.
@@ -828,77 +1259,82 @@ void Foam::globalPoints::receiveSharedPoints
             forAll(connections, i)
             {
                 const edge& e = connections[i];
-                label meshPointA = pp.meshPoints()[e[0]];
-                label meshPointB = pp.meshPoints()[e[1]];
 
-                label localA = meshToLocalPoint
-                (
-                    meshToPatchPoint,
-                    meshPointA
-                );
-                label localB = meshToLocalPoint
-                (
-                    meshToPatchPoint,
-                    meshPointB
-                );
+                if (mergeSeparated || isCollocatedPoint[e[0]])
+                {
+                    label meshPointA = pp.meshPoints()[e[0]];
+                    label meshPointB = pp.meshPoints()[e[1]];
+
+                    label localA = meshToLocalPoint
+                    (
+                        meshToPatchPoint,
+                        meshPointA
+                    );
+                    label localB = meshToLocalPoint
+                    (
+                        meshToPatchPoint,
+                        meshPointB
+                    );
 
-                // Do we already have shared point for pointA?
-                Map<label>::iterator fndA = localToSharedPoint.find(localA);
-                Map<label>::iterator fndB = localToSharedPoint.find(localB);
+                    // Do we already have shared point for pointA?
+                    Map<label>::iterator fndA = localToSharedPoint.find(localA);
+                    Map<label>::iterator fndB = localToSharedPoint.find(localB);
 
-                if (fndA != localToSharedPoint.end())
-                {
-                    if (fndB != localToSharedPoint.end())
+                    if (fndA != localToSharedPoint.end())
                     {
-                        if (fndA() != fndB())
+                        if (fndB != localToSharedPoint.end())
                         {
-                            FatalErrorIn
-                            (
-                                "globalPoints::receiveSharedPoints"
-                                "(labelList&)"
-                            )   << "On patch " << pp.name()
-                                << " connected points " << meshPointA
-                                << ' ' << mesh_.points()[meshPointA]
-                                << " and " << meshPointB
-                                << ' ' << mesh_.points()[meshPointB]
-                                << " are mapped to different shared points: "
-                                << fndA() << " and " << fndB()
-                                << abort(FatalError);
+                            if (fndA() != fndB())
+                            {
+                                FatalErrorIn
+                                (
+                                    "globalPoints::receiveSharedPoints(..)"
+                                )   << "On patch " << pp.name()
+                                    << " connected points " << meshPointA
+                                    << ' ' << mesh_.points()[meshPointA]
+                                    << " and " << meshPointB
+                                    << ' ' << mesh_.points()[meshPointB]
+                                    << " are mapped to different shared"
+                                    << " points: "
+                                    << fndA() << " and " << fndB()
+                                    << abort(FatalError);
+                            }
                         }
-                    }
-                    else
-                    {
-                        // No shared point yet for B.
-                        label sharedPointI = fndA();
+                        else
+                        {
+                            // No shared point yet for B.
+                            label sharedPointI = fndA();
 
-                        // Store shared point for pointB
-                        label index = meshToProcPoint_[localB];
+                            // Store shared point for pointB
+                            label sharedI = meshToShared[localB];
 
-                        sharedPointAddr_[index] = sharedPointI;
-                        sharedPointLabels_[index] = localB;
-                        changedIndices[nChanged++] = index;
+                            sharedPointAddr_[sharedI] = sharedPointI;
+                            sharedPointLabels_[sharedI] = localB;
+                            changedIndices.append(sharedI);
+                        }
                     }
-                }
-                else
-                {
-                    // No shared point yet for A.
-                    if (fndB != localToSharedPoint.end())
+                    else
                     {
-                        label sharedPointI = fndB();
+                        // No shared point yet for A.
+                        if (fndB != localToSharedPoint.end())
+                        {
+                            label sharedPointI = fndB();
 
-                        // Store shared point for pointA
-                        label index = meshToProcPoint_[localA];
+                            // Store shared point for pointA
+                            label sharedI = meshToShared[localA];
 
-                        sharedPointAddr_[index] = sharedPointI;
-                        sharedPointLabels_[index] = localA;
-                        changedIndices[nChanged++] = index;
+                            sharedPointAddr_[sharedI] = sharedPointI;
+                            sharedPointLabels_[sharedI] = localA;
+                            changedIndices.append(sharedI);
+                        }
                     }
                 }
             }
         }
     }
 
-    changedIndices.setSize(nChanged);
+    // Extend shared points from local connections.
+    extendSharedPoints(meshToShared, changedIndices);
 }
 
 
@@ -954,16 +1390,27 @@ void Foam::globalPoints::calculateSharedPoints
 (
     const Map<label>& meshToPatchPoint, // from mesh point to local numbering
     const labelList& patchToMeshPoint,  // from local numbering to mesh point
-    const bool keepAllPoints
+    const bool keepAllPoints,
+    const bool mergeSeparated
 )
 {
     if (debug)
     {
-        Pout<< "globalPoints::globalPoints(const polyMesh&) : "
+        Pout<< "globalPoints::calculateSharedPoints(..) : "
             << "doing processor to processor communication to get sharedPoints"
             << endl;
     }
 
+    if (globalIndices_.size() >= fromCollocated)
+    {
+        FatalErrorIn("globalPoints::calculateSharedPoints(..)")
+            << "Integer overflow. Total number of points "
+            << globalIndices_.size()
+            << " is too large to be represented." << exit(FatalError);
+    }
+
+
+
     labelHashSet changedPoints(nPatchPoints_);
 
     // Initialize procPoints with my patch points. Keep track of points
@@ -983,9 +1430,21 @@ void Foam::globalPoints::calculateSharedPoints
     // Do one exchange iteration to get neighbour points.
     {
         PstreamBuffers pBufs(Pstream::defaultCommsType);
-        sendPatchPoints(meshToPatchPoint, pBufs, changedPoints);
+        sendPatchPoints
+        (
+            mergeSeparated,
+            meshToPatchPoint,
+            pBufs,
+            changedPoints
+        );
         pBufs.finishedSends();
-        receivePatchPoints(meshToPatchPoint, pBufs, changedPoints);
+        receivePatchPoints
+        (
+            mergeSeparated,
+            meshToPatchPoint,
+            pBufs,
+            changedPoints
+        );
     }
 
 
@@ -1002,9 +1461,21 @@ void Foam::globalPoints::calculateSharedPoints
     do
     {
         PstreamBuffers pBufs(Pstream::defaultCommsType);
-        sendPatchPoints(meshToPatchPoint, pBufs, changedPoints);
+        sendPatchPoints
+        (
+            mergeSeparated,
+            meshToPatchPoint,
+            pBufs,
+            changedPoints
+        );
         pBufs.finishedSends();
-        receivePatchPoints(meshToPatchPoint, pBufs, changedPoints);
+        receivePatchPoints
+        (
+            mergeSeparated,
+            meshToPatchPoint,
+            pBufs,
+            changedPoints
+        );
 
         changed = changedPoints.size() > 0;
         reduce(changed, orOp<bool>());
@@ -1015,13 +1486,23 @@ void Foam::globalPoints::calculateSharedPoints
     // Remove direct neighbours from point equivalences.
     if (!keepAllPoints)
     {
+        //Pout<< "**Removing direct neighbours:" << endl;
+        //forAllConstIter(Map<label>, neighbourList, iter)
+        //{
+        //    label localI = iter.key();
+        //    Pout<< "pointI:" << localI << " index:" << iter()
+        //        << " coord:"
+        //        << mesh_.points()[localToMeshPoint(patchToMeshPoint, localI)]
+        //        << endl;
+        //}
         remove(patchToMeshPoint, neighbourList);
     }
-    else
-    {
-        // Compact out unused elements
-        compact();
-    }
+
+
+    // Compact out unused elements
+    compact(patchToMeshPoint);
+
+
 
     procPoints_.shrink();
 
@@ -1031,39 +1512,31 @@ void Foam::globalPoints::calculateSharedPoints
     {
         sort(procPoints_[iter()]);
     }
+    // We can now remove the collocated bit
+    forAll(procPoints_, index)
+    {
+        labelList& pointInfo = procPoints_[index];
+
+        forAll(pointInfo, i)
+        {
+            pointInfo[i] = removeCollocated(pointInfo[i]);
+        }
+    }
 
 
-    // Pout<< "Now connected points:" << endl;
-    // forAllConstIter(Map<label>, meshToProcPoint_, iter)
-    // {
-    //     label localI = iter.key();
-    //     const labelList& pointInfo = procPoints_[iter()];
-    // 
-    //     Pout<< "pointI:" << localI << " index:" << iter()
-    //         << " coord:"
-    //         << mesh_.points()[localToMeshPoint(patchToMeshPoint, localI)]
-    //         << endl;
-    // 
-    //     forAll(pointInfo, i)
-    //     {
-    //         label procI = globalIndices_.whichProcID(pointInfo[i]);
-    //         Pout<< "    connected to proc " << procI
-    //             << " localpoint:"
-    //             << globalIndices_.toLocal(procI, pointInfo[i]);
-    // 
-    //         if (globalIndices_.isLocal(pointInfo[i]))
-    //         {
-    //             label meshPointI = localToMeshPoint
-    //             (
-    //                 patchToMeshPoint,
-    //                 globalIndices_.toLocal(pointInfo[i])
-    //             );
-    //             Pout<< " at:" <<  mesh_.points()[meshPointI];
-    //         }
-    // 
-    //         Pout<< endl;
-    //     }
-    // }
+//Pout<< "Now connected points:" << endl;
+//forAllConstIter(Map<label>, meshToProcPoint_, iter)
+//{
+//    label localI = iter.key();
+//    const labelList& pointInfo = procPoints_[iter()];
+//
+//    Pout<< "pointI:" << localI << " index:" << iter()
+//        << " coord:"
+//        << mesh_.points()[localToMeshPoint(patchToMeshPoint, localI)]
+//        << endl;
+//
+//    printProcPoints(patchToMeshPoint, pointInfo, Pout);
+//}
 
 
     // We now have - in procPoints_ - a list of points which are shared between
@@ -1081,22 +1554,31 @@ void Foam::globalPoints::calculateSharedPoints
     sharedPointLabels_.setSize(meshToProcPoint_.size());
     sharedPointLabels_ = -1;
 
-
     // Get point labels of points for which I am master (lowest
     // numbered proc)
     labelList masterPoints(getMasterPoints(patchToMeshPoint));
 
+
     // Get global numbering for master points
     globalIndex globalMasterPoints(masterPoints.size());
     nGlobalPoints_ = globalMasterPoints.size();
 
+    // Number meshToProcPoint
+    label sharedI = 0;
+    Map<label> meshToShared(meshToProcPoint_.size());
+    forAllConstIter(Map<label>, meshToProcPoint_, iter)
+    {
+        meshToShared.insert(iter.key(), sharedI++);
+    }
+
+    // Assign the entries for the masters
     forAll(masterPoints, i)
     {
         label localPointI = masterPoints[i];
-        label index = meshToProcPoint_[localPointI];
+        label sharedI = meshToShared[localPointI];
 
-        sharedPointLabels_[index] = localPointI;
-        sharedPointAddr_[index] = globalMasterPoints.toGlobal(i);
+        sharedPointLabels_[sharedI] = localPointI;
+        sharedPointAddr_[sharedI] = globalMasterPoints.toGlobal(i);
     }
 
 
@@ -1105,17 +1587,18 @@ void Foam::globalPoints::calculateSharedPoints
     // Loop until nothing changes.
 
     // Initial subset to send is points for which I have sharedPoints
-    labelList changedIndices(sharedPointAddr_.size());
-    label nChanged = 0;
-
+    DynamicList<label> changedIndices(sharedPointAddr_.size());
     forAll(sharedPointAddr_, i)
     {
         if (sharedPointAddr_[i] != -1)
         {
-            changedIndices[nChanged++] = i;
+            changedIndices.append(i);
         }
     }
-    changedIndices.setSize(nChanged);
+
+    // Assign local slaves from local master
+    extendSharedPoints(meshToShared, changedIndices);
+
 
     changed = false;
 
@@ -1127,9 +1610,16 @@ void Foam::globalPoints::calculateSharedPoints
                 << " Exchanging them" << endl;
         }
         PstreamBuffers pBufs(Pstream::defaultCommsType);
-        sendSharedPoints(pBufs, changedIndices);
+        sendSharedPoints(mergeSeparated, pBufs, changedIndices);
         pBufs.finishedSends();
-        receiveSharedPoints(meshToPatchPoint, pBufs, changedIndices);
+        receiveSharedPoints
+        (
+            mergeSeparated,
+            meshToPatchPoint,
+            meshToShared,
+            pBufs,
+            changedIndices
+        );
 
         changed = changedIndices.size() > 0;
         reduce(changed, orOp<bool>());
@@ -1137,11 +1627,23 @@ void Foam::globalPoints::calculateSharedPoints
     } while (changed);
 
 
+//    forAll(sharedPointLabels_, sharedI)
+//    {
+//        label localI = sharedPointLabels_[sharedI];
+//
+//        Pout<< "point:" << localI
+//            << " coord:"
+//            << mesh_.points()[localToMeshPoint(patchToMeshPoint, localI)]
+//            << " ON TO GLOBAL:" << sharedPointAddr_[sharedI]
+//            << endl;
+//    }
+
+
     forAll(sharedPointLabels_, i)
     {
         if (sharedPointLabels_[i] == -1)
         {
-            FatalErrorIn("globalPoints::globalPoints(const polyMesh&)")
+            FatalErrorIn("globalPoints::calculateSharedPoints(..)")
                 << "Problem: shared point on processor " << Pstream::myProcNo()
                 << " not set at index " << sharedPointLabels_[i] << endl
                 << "This might mean the individual processor domains are not"
@@ -1153,7 +1655,7 @@ void Foam::globalPoints::calculateSharedPoints
 
     if (debug)
     {
-        Pout<< "globalPoints::globalPoints(const polyMesh&) : "
+        Pout<< "globalPoints::calculateSharedPoints(..) : "
             << "Finished global points" << endl;
     }
 }
@@ -1165,7 +1667,8 @@ void Foam::globalPoints::calculateSharedPoints
 Foam::globalPoints::globalPoints
 (
     const polyMesh& mesh,
-    const bool keepAllPoints
+    const bool keepAllPoints,
+    const bool mergeSeparated
 )
 :
     mesh_(mesh),
@@ -1181,7 +1684,13 @@ Foam::globalPoints::globalPoints
     Map<label> meshToPatchPoint(0);
     labelList patchToMeshPoint(0);
 
-    calculateSharedPoints(meshToPatchPoint, patchToMeshPoint, keepAllPoints);
+    calculateSharedPoints
+    (
+        meshToPatchPoint,
+        patchToMeshPoint,
+        keepAllPoints,
+        mergeSeparated
+    );
 }
 
 
@@ -1190,7 +1699,8 @@ Foam::globalPoints::globalPoints
 (
     const polyMesh& mesh,
     const indirectPrimitivePatch& coupledPatch,
-    const bool keepAllPoints
+    const bool keepAllPoints,
+    const bool mergeSeparated
 )
 :
     mesh_(mesh),
@@ -1206,7 +1716,8 @@ Foam::globalPoints::globalPoints
     (
         coupledPatch.meshPointMap(),
         coupledPatch.meshPoints(),
-        keepAllPoints
+        keepAllPoints,
+        mergeSeparated
     );
 }
 
diff --git a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.H b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.H
index 41d010ec9f2..246842632ab 100644
--- a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.H
+++ b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.H
@@ -67,8 +67,8 @@ Description
     At this point one will have complete point-point connectivity for all
     points on processor patches. Now
 
-        - remove point equivalences of size 2. These are just normal points
-          shared between two neighbouring procPatches.
+        - (optional)remove point equivalences of size 2. These are
+          just normal points shared between two neighbouring procPatches.
         - collect on each processor points for which it is the master
         - request number of sharedPointLabels from the Pstream::master.
 
@@ -98,10 +98,10 @@ SourceFiles
 #include "DynamicList.H"
 #include "Map.H"
 #include "primitivePatch.H"
-#include "className.H"
 #include "edgeList.H"
 #include "globalIndex.H"
 #include "indirectPrimitivePatch.H"
+#include "PackedBoolList.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -112,6 +112,8 @@ namespace Foam
 class polyMesh;
 class polyBoundaryMesh;
 class cyclicPolyPatch;
+class polyPatch;
+class coupledPolyPatch;
 
 /*---------------------------------------------------------------------------*\
                            Class globalPoints Declaration
@@ -119,7 +121,15 @@ class cyclicPolyPatch;
 
 class globalPoints
 {
-    // Private classes
+    // Static data members
+
+        //- Offset to add to points (in globalIndices) originating from
+        //  collocated coupled points.
+        static const label fromCollocated;
+
+        //- Distance to check whether points/faces are collocated.
+        static const scalar mergeDist;
+
 
     // Private data
 
@@ -152,13 +162,53 @@ class globalPoints
 
     // Private Member Functions
 
+        //- Is identity transform?
+        static bool noTransform(const tensor&, const scalar mergeDist);
+
+        //- Return per face collocated status
+        static PackedBoolList collocatedFaces
+        (
+            const coupledPolyPatch&,
+            const scalar mergeDist
+        );
+
+        //- Return per point collocated status
+        static PackedBoolList collocatedPoints
+        (
+            const coupledPolyPatch&,
+            const scalar mergeDist
+        );
+
+        // Wrappers around global point numbering to add collocated bit
+
+            //- Convert into globalIndices and add collocated bit
+            label toGlobal(const label, const bool isCollocated) const;
+
+            //- Is collocated bit set
+            bool isCollocated(const label globalI) const;
+
+            //- Remove collocated bit
+            label removeCollocated(const label globalI) const;
+
+            //- (remove collocated bit and) check if originates from local proc
+            bool isLocal(const label globalI) const;
+
+            //- (remove collocated bit and) get originating processor
+            label whichProcID(const label globalI) const;
+
+            //- (remove collocated bit and) convert to local number on processor
+            label toLocal(const label procI, const label globalI) const;
+
+            //- (remove collocated bit and) convert to local number on
+            //  Pstream::myProcNo
+            label toLocal(const label globalI) const;
+
+
+
         //- Count all points on processorPatches. Is all points for which
         //  information is collected.
         static label countPatchPoints(const polyBoundaryMesh&);
 
-        ////- Get all faces on coupled patches
-        //static labelListl coupledFaces(const polyBoundaryMesh&);
-
         //- Add information about patchPointI in relative indices to send
         //  buffers (patchFaces, indexInFace etc.)
         static void addToSend
@@ -197,9 +247,17 @@ class globalPoints
         bool storeInfo
         (
             const labelList& nbrInfo,
-            const label localPointI
+            const label localPointI,
+            const bool isCollocated
         );
 
+        void printProcPoints
+        (
+            const labelList& patchToMeshPoint,
+            const labelList& pointInfo,
+            Ostream& os
+        ) const;
+
         //- Initialize procPoints_ to my patch points. allPoints = true:
         //  seed with all patch points, = false: only boundaryPoints().
         void initOwnPoints
@@ -212,6 +270,7 @@ class globalPoints
         //- Send subset of procPoints to neighbours
         void sendPatchPoints
         (
+            const bool mergeSeparated,
             const Map<label>&,
             PstreamBuffers&,
             const labelHashSet&
@@ -220,6 +279,7 @@ class globalPoints
         //- Receive neighbour points and merge into my procPoints.
         void receivePatchPoints
         (
+            const bool mergeSeparated,
             const Map<label>&,
             PstreamBuffers&,
             labelHashSet&
@@ -230,20 +290,31 @@ class globalPoints
         void remove(const labelList& patchToMeshPoint, const Map<label>&);
 
         //- Compact out unused elements of procPoints.
-        void compact();
+        void compact(const labelList& patchToMeshPoint);
 
         //- Get indices of point for which I am master (lowest numbered proc)
         labelList getMasterPoints(const labelList& patchToMeshPoint) const;
 
+
         //- Send subset of shared points to neighbours
-        void sendSharedPoints(PstreamBuffers&, const labelList&) const;
+        void sendSharedPoints
+        (
+            const bool mergeSeparated,
+            PstreamBuffers&,
+            const DynamicList<label>&
+        ) const;
+
+        //- Take over any local shared points
+        void extendSharedPoints(const Map<label>&, DynamicList<label>&);
 
         //- Receive shared points and update subset.
         void receiveSharedPoints
         (
-            const Map<label>&,
+            const bool mergeSeparated,
+            const Map<label>& meshToPatchPoint,
+            const Map<label>& meshToShared,
             PstreamBuffers&,
-            labelList&
+            DynamicList<label>&
         );
 
         //- Should move into cyclicPolyPatch ordering problem
@@ -255,7 +326,8 @@ class globalPoints
         (
             const Map<label>&,
             const labelList&,
-            const bool keepAllPoints
+            const bool keepAllPoints,
+            const bool mergeSeparated
         );
 
         //- Disallow default bitwise copy construct
@@ -276,7 +348,15 @@ public:
         //- Construct from mesh.
         //  keepAllPoints = false : filter out points that are on two
         //  neighbouring coupled patches (so can be swapped)
-        globalPoints(const polyMesh& mesh, const bool keepAllPoints);
+        //  mergeSeparated:
+        //      true  : merge coupled points across separated patches.
+        //      false : do not merge across coupled separated patches.
+        globalPoints
+        (
+            const polyMesh& mesh,
+            const bool keepAllPoints,
+            const bool mergeSeparated
+        );
 
         //- Construct from mesh and patch of coupled faces. Difference with
         //  construct from mesh only is that this stores the meshToProcPoint,
@@ -286,7 +366,8 @@ public:
         (
             const polyMesh& mesh,
             const indirectPrimitivePatch& coupledPatch,
-            const bool keepAllPoints
+            const bool keepAllPoints,
+            const bool mergeSeparated
         );
 
 
-- 
GitLab