From c6d4035ced915c4e95587a25201920d93e1acaa3 Mon Sep 17 00:00:00 2001
From: mattijs <mattijs>
Date: Mon, 4 Jan 2010 13:25:30 +0000
Subject: [PATCH] Added master-slave addressing for coupled points.

- Rewrote globalPoints to use globalIndex class so now only transfers
single label instead of labelPair
- Added addressing in globalMeshData
    - from coupled master points to slave points
    -         ,,          edges     ,,    edges
    - from coupled points (master or slave) to uncoupled boundary faces
    -               ,,                    ,,                      cells
- See test/globalMeshData for simple test
---
 applications/test/globalMeshData/Make/files   |   3 +
 applications/test/globalMeshData/Make/options |   3 +
 .../test/globalMeshData/globalMeshDataTest.C  | 221 +++++
 .../polyMesh/globalMeshData/globalMeshData.C  | 821 +++++++++++++++++-
 .../polyMesh/globalMeshData/globalMeshData.H  | 104 ++-
 .../polyMesh/globalMeshData/globalPoints.C    | 694 +++++++++------
 .../polyMesh/globalMeshData/globalPoints.H    | 146 +++-
 7 files changed, 1627 insertions(+), 365 deletions(-)
 create mode 100644 applications/test/globalMeshData/Make/files
 create mode 100644 applications/test/globalMeshData/Make/options
 create mode 100644 applications/test/globalMeshData/globalMeshDataTest.C

diff --git a/applications/test/globalMeshData/Make/files b/applications/test/globalMeshData/Make/files
new file mode 100644
index 00000000000..dc5877e3835
--- /dev/null
+++ b/applications/test/globalMeshData/Make/files
@@ -0,0 +1,3 @@
+globalMeshDataTest.C
+
+EXE = $(FOAM_USER_APPBIN)/globalMeshDataTest
diff --git a/applications/test/globalMeshData/Make/options b/applications/test/globalMeshData/Make/options
new file mode 100644
index 00000000000..4c3dd783cb4
--- /dev/null
+++ b/applications/test/globalMeshData/Make/options
@@ -0,0 +1,3 @@
+EXE_INC =
+
+EXE_LIBS =
diff --git a/applications/test/globalMeshData/globalMeshDataTest.C b/applications/test/globalMeshData/globalMeshDataTest.C
new file mode 100644
index 00000000000..75f98b1b9ce
--- /dev/null
+++ b/applications/test/globalMeshData/globalMeshDataTest.C
@@ -0,0 +1,221 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2009 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 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, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Application
+    globalMeshDataTest
+
+Description
+    Test global point communication
+
+\*---------------------------------------------------------------------------*/
+
+#include "globalMeshData.H"
+#include "argList.H"
+#include "polyMesh.H"
+#include "Time.H"
+#include "mapDistribute.H"
+
+using namespace Foam;
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Main program:
+
+int main(int argc, char *argv[])
+{
+#   include "setRootCase.H"
+#   include "createTime.H"
+#   include "createPolyMesh.H"
+
+    const globalMeshData& globalData = mesh.globalData();
+    const indirectPrimitivePatch& coupledPatch = globalData.coupledPatch();
+
+
+    // Test:print shared points
+    {
+        const labelListList& globalPointSlaves =
+            globalData.globalPointSlaves();
+        const mapDistribute& globalPointSlavesMap =
+            globalData.globalPointSlavesMap();
+
+        pointField coords(globalPointSlavesMap.constructSize());
+        SubList<point>(coords, coupledPatch.nPoints()).assign
+        (
+            coupledPatch.localPoints()
+        );
+
+        // Exchange data
+        globalPointSlavesMap.distribute(coords);
+
+        // Print
+        forAll(globalPointSlaves, pointI)
+        {
+            const labelList& slavePoints = globalPointSlaves[pointI];
+
+            if (slavePoints.size() > 0)
+            {
+                Pout<< "Master point:" << pointI
+                    << " coord:" << coords[pointI]
+                    << " connected to slave points:" << endl;
+
+                forAll(slavePoints, i)
+                {
+                    Pout<< "    " << coords[slavePoints[i]] << endl;
+                }
+            }
+        }
+    }
+
+
+
+    // Test: point to faces addressing
+    {
+        const labelListList& globalPointBoundaryFaces =
+            globalData.globalPointBoundaryFaces();
+        const mapDistribute& globalPointBoundaryFacesMap =
+            globalData.globalPointBoundaryFacesMap();
+
+        label nBnd = mesh.nFaces()-mesh.nInternalFaces();
+
+        pointField fc(globalPointBoundaryFacesMap.constructSize());
+        SubList<point>(fc, nBnd).assign
+        (
+            primitivePatch
+            (
+                SubList<face>
+                (
+                    mesh.faces(),
+                    nBnd,
+                    mesh.nInternalFaces()
+                ),
+                mesh.points()
+            ).faceCentres()
+        );
+
+        // Exchange data
+        globalPointBoundaryFacesMap.distribute(fc);
+
+        // Print
+        forAll(globalPointBoundaryFaces, pointI)
+        {
+            const labelList& bFaces = globalPointBoundaryFaces[pointI];
+
+            Pout<< "Point:" << pointI
+                << " at:" << coupledPatch.localPoints()[pointI]
+                << " connected to faces:" << endl;
+
+            forAll(bFaces, i)
+            {
+                Pout<< "    " << fc[bFaces[i]] << endl;
+            }
+        }
+    }
+
+
+
+
+
+    // Test:point to cells addressing
+    {
+        const labelList& boundaryCells = globalData.boundaryCells();
+        const labelListList& globalPointBoundaryCells =
+            globalData.globalPointBoundaryCells();
+        const mapDistribute& globalPointBoundaryCellsMap =
+            globalData.globalPointBoundaryCellsMap();
+
+        pointField cc(globalPointBoundaryCellsMap.constructSize());
+        forAll(boundaryCells, i)
+        {
+            cc[i] = mesh.cellCentres()[boundaryCells[i]];
+        }
+
+        // Exchange data
+        globalPointBoundaryCellsMap.distribute(cc);
+
+        // Print
+        forAll(globalPointBoundaryCells, pointI)
+        {
+            const labelList& bCells = globalPointBoundaryCells[pointI];
+
+            Pout<< "Point:" << pointI
+                << " at:" << coupledPatch.localPoints()[pointI]
+                << " connected to cells:" << endl;
+
+            forAll(bCells, i)
+            {
+                Pout<< "    " << cc[bCells[i]] << endl;
+            }
+        }
+    }
+
+
+
+    // Test:print shared edges
+    {
+        const labelListList& globalEdgeSlaves =
+            globalData.globalEdgeSlaves();
+        const mapDistribute& globalEdgeSlavesMap =
+            globalData.globalEdgeSlavesMap();
+
+        // Test: distribute edge centres
+        pointField ec(globalEdgeSlavesMap.constructSize());
+        forAll(coupledPatch.edges(), edgeI)
+        {
+            ec[edgeI] = coupledPatch.edges()[edgeI].centre
+            (
+                coupledPatch.localPoints()
+            );
+        }
+
+        // Exchange data
+        globalEdgeSlavesMap.distribute(ec);
+
+        // Print
+        forAll(globalEdgeSlaves, edgeI)
+        {
+            const labelList& slaveEdges = globalEdgeSlaves[edgeI];
+
+            if (slaveEdges.size() > 0)
+            {
+                Pout<< "Master edge:" << edgeI
+                    << " centre:" << ec[edgeI]
+                    << " connected to slave edges:" << endl;
+
+                forAll(slaveEdges, i)
+                {
+                    Pout<< "    " << ec[slaveEdges[i]] << endl;
+                }
+            }
+        }
+    }
+
+
+    Info<< "End\n" << endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C
index 147b370d1a2..1b3bb264a21 100644
--- a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C
+++ b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.C
@@ -32,6 +32,8 @@ License
 #include "demandDrivenData.H"
 #include "globalPoints.H"
 //#include "geomGlobalPoints.H"
+#include "polyMesh.H"
+#include "mapDistribute.H"
 #include "labelIOList.H"
 #include "PackedList.H"
 #include "mergePoints.H"
@@ -115,24 +117,17 @@ void Foam::globalMeshData::initProcAddr()
 // Given information about locally used edges allocate global shared edges.
 void Foam::globalMeshData::countSharedEdges
 (
-    const HashTable<labelList, edge, Hash<edge> >& procSharedEdges,
-    HashTable<label, edge, Hash<edge> >& globalShared,
+    const EdgeMap<labelList>& procSharedEdges,
+    EdgeMap<label>& globalShared,
     label& sharedEdgeI
 )
 {
     // Count occurrences of procSharedEdges in global shared edges table.
-    for
-    (
-        HashTable<labelList, edge, Hash<edge> >::const_iterator iter =
-            procSharedEdges.begin();
-        iter != procSharedEdges.end();
-        ++iter
-    )
+    forAllConstIter(EdgeMap<labelList>, procSharedEdges, iter)
     {
         const edge& e = iter.key();
 
-        HashTable<label, edge, Hash<edge> >::iterator globalFnd =
-            globalShared.find(e);
+        EdgeMap<label>::iterator globalFnd = globalShared.find(e);
 
         if (globalFnd == globalShared.end())
         {
@@ -189,10 +184,7 @@ void Foam::globalMeshData::calcSharedEdges() const
     // Find edges using shared points. Store correspondence to local edge
     // numbering. Note that multiple local edges can have the same shared
     // points! (for cyclics or separated processor patches)
-    HashTable<labelList, edge, Hash<edge> > localShared
-    (
-        2*sharedPtAddr.size()
-    );
+    EdgeMap<labelList> localShared(2*sharedPtAddr.size());
 
     const edgeList& edges = mesh_.edges();
 
@@ -218,7 +210,7 @@ void Foam::globalMeshData::calcSharedEdges() const
                     sharedPtAddr[e1Fnd()]
                 );
 
-                HashTable<labelList, edge, Hash<edge> >::iterator iter =
+                EdgeMap<labelList>::iterator iter =
                     localShared.find(sharedEdge);
 
                 if (iter == localShared.end())
@@ -249,7 +241,7 @@ void Foam::globalMeshData::calcSharedEdges() const
     // used). But then this only gets done once so not too bothered about the
     // extra global communication.
 
-    HashTable<label, edge, Hash<edge> > globalShared(nGlobalPoints());
+    EdgeMap<label> globalShared(nGlobalPoints());
 
     if (Pstream::master())
     {
@@ -275,10 +267,7 @@ void Foam::globalMeshData::calcSharedEdges() const
             {
                 // Receive the edges using shared points from the slave.
                 IPstream fromSlave(Pstream::blocking, slave);
-                HashTable<labelList, edge, Hash<edge> > procSharedEdges
-                (
-                    fromSlave
-                );
+                EdgeMap<labelList> procSharedEdges(fromSlave);
 
                 if (debug)
                 {
@@ -295,17 +284,11 @@ void Foam::globalMeshData::calcSharedEdges() const
         // These were only used once so are not proper shared edges.
         // Remove them.
         {
-            HashTable<label, edge, Hash<edge> > oldSharedEdges(globalShared);
+            EdgeMap<label> oldSharedEdges(globalShared);
 
             globalShared.clear();
 
-            for
-            (
-                HashTable<label, edge, Hash<edge> >::const_iterator iter =
-                    oldSharedEdges.begin();
-                iter != oldSharedEdges.end();
-                ++iter
-            )
+            forAllConstIter(EdgeMap<label>, oldSharedEdges, iter)
             {
                 if (iter() != -1)
                 {
@@ -361,18 +344,11 @@ void Foam::globalMeshData::calcSharedEdges() const
     DynamicList<label> dynSharedEdgeLabels(globalShared.size());
     DynamicList<label> dynSharedEdgeAddr(globalShared.size());
 
-    for
-    (
-        HashTable<labelList, edge, Hash<edge> >::const_iterator iter =
-            localShared.begin();
-        iter != localShared.end();
-        ++iter
-    )
+    forAllConstIter(EdgeMap<labelList>, localShared, iter)
     {
         const edge& e = iter.key();
 
-        HashTable<label, edge, Hash<edge> >::const_iterator edgeFnd =
-            globalShared.find(e);
+        EdgeMap<label>::const_iterator edgeFnd = globalShared.find(e);
 
         if (edgeFnd != globalShared.end())
         {
@@ -434,6 +410,557 @@ Foam::label Foam::globalMeshData::countCoincidentFaces
 }
 
 
+void Foam::globalMeshData::calcGlobalPointSlaves() 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
+    (
+        new globalIndex(globalData.globalIndices())
+    );
+    const globalIndex& globalIndices = globalPointNumberingPtr_();
+
+    // Create master to slave addressing. Empty for slave points.
+    globalPointSlavesPtr_.reset
+    (
+        new labelListList(coupledPatch().nPoints())
+    );
+    labelListList& globalPointSlaves = globalPointSlavesPtr_();
+
+    forAllConstIter(Map<label>, meshToProcPoint, iter)
+    {
+        label localPointI = iter.key();
+        const labelList& pPoints = globalData.procPoints()[iter()];
+
+        // Am I master?
+        if
+        (
+            globalIndices.isLocal(pPoints[0])
+         && globalIndices.toLocal(pPoints[0]) == localPointI
+        )
+        {
+            labelList& slaves = globalPointSlaves[localPointI];
+            slaves.setSize(pPoints.size()-1);
+            for (label i = 1; i < pPoints.size(); i++)
+            {
+                slaves[i-1] = pPoints[i];
+            }
+        }
+    }
+
+    // Create schedule to get information from slaves onto master
+
+    // Construct compact numbering and distribution map.
+    // Changes globalPointSlaves to be indices into compact data
+
+    List<Map<label> > compactMap(Pstream::nProcs());
+    globalPointSlavesMapPtr_.reset
+    (
+        new mapDistribute
+        (
+            globalIndices,
+            globalPointSlaves,
+            compactMap
+        )
+    );
+
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalPointSlaves() :"
+            << " coupled points:" << coupledPatch().nPoints()
+            << " additional remote points:"
+            <<  globalPointSlavesMapPtr_().constructSize()
+              - coupledPatch().nPoints()
+            << endl;
+    }
+}
+
+
+void Foam::globalMeshData::calcGlobalEdgeSlaves() const
+{
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalEdgeSlaves() :"
+            << " calculating coupled master to slave edge addressing."
+            << endl;
+    }
+
+    const labelListList& globalPointSlaves = this->globalPointSlaves();
+    const mapDistribute& globalPointSlavesMap = this->globalPointSlavesMap();
+
+    // - 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
+    (
+        new globalIndex(coupledPatch().nEdges())
+    );
+    const globalIndex& globalIndices = globalEdgeNumberingPtr_();
+
+    // Coupled point to global coupled edges.
+    labelListList globalPointEdges(globalPointSlavesMap.constructSize());
+
+    // Create local version
+    const labelListList& pointEdges = coupledPatch().pointEdges();
+    forAll(pointEdges, pointI)
+    {
+        const labelList& pEdges = pointEdges[pointI];
+        labelList& globalPEdges = globalPointEdges[pointI];
+        globalPEdges.setSize(pEdges.size());
+        forAll(pEdges, i)
+        {
+            globalPEdges[i] = globalIndices.toGlobal(pEdges[i]);
+        }
+    }
+
+    // Pull slave data to master
+    globalPointSlavesMap.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
+    // the master (otherwise the mesh would be illegal anyway)
+
+    labelHashSet pointEdgeSet;
+
+    const edgeList& edges = coupledPatch().edges();
+
+    // Create master to slave addressing. Empty for slave edges.
+    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]];
+
+        // Check for edges that are in both slaves0 and slaves1.
+        pointEdgeSet.clear();
+        forAll(slaves0, i)
+        {
+            const labelList& connectedEdges = globalPointEdges[slaves0[i]];
+            pointEdgeSet.insert(connectedEdges);
+        }
+        forAll(slaves1, i)
+        {
+            const labelList& connectedEdges = globalPointEdges[slaves1[i]];
+
+            forAll(connectedEdges, j)
+            {
+                label globalEdgeI = connectedEdges[j];
+
+                if (pointEdgeSet.found(globalEdgeI))
+                {
+                    // Found slave edge.
+                    label sz = globalEdgeSlaves[edgeI].size();
+                    globalEdgeSlaves[edgeI].setSize(sz+1);
+                    globalEdgeSlaves[edgeI][sz] = globalEdgeI;
+                }
+            }
+        }
+    }
+
+
+    // Construct map
+    List<Map<label> > compactMap(Pstream::nProcs());
+    globalEdgeSlavesMapPtr_.reset
+    (
+        new mapDistribute
+        (
+            globalIndices,
+            globalEdgeSlaves,
+            compactMap
+        )
+    );
+
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalEdgeSlaves() :"
+            << " coupled edge:" << edges.size()
+            << " additional remote edges:"
+            << globalEdgeSlavesMapPtr_().constructSize() - edges.size()
+            << endl;
+    }
+}
+
+
+// Calculate uncoupled boundary faces (without calculating
+// primitiveMesh::pointFaces())
+void Foam::globalMeshData::calcPointBoundaryFaces
+(
+    labelListList& pointBoundaryFaces
+) const
+{
+    const polyBoundaryMesh& bMesh = mesh_.boundaryMesh();
+    const Map<label>& meshPointMap = coupledPatch().meshPointMap();
+
+    // 1. Count
+
+    labelList nPointFaces(coupledPatch().nPoints(), 0);
+
+    forAll(bMesh, patchI)
+    {
+        const polyPatch& pp = bMesh[patchI];
+
+        if (!pp.coupled())
+        {
+            forAll(pp, i)
+            {
+                const face& f = pp[i];
+
+                forAll(f, fp)
+                {
+                    Map<label>::const_iterator iter = meshPointMap.find(f[fp]);
+                    if (iter != meshPointMap.end())
+                    {
+                        nPointFaces[iter()]++;
+                    }
+                }
+            }
+        }
+    }
+
+
+    // 2. Size
+
+    pointBoundaryFaces.setSize(coupledPatch().nPoints());
+    forAll(nPointFaces, pointI)
+    {
+        pointBoundaryFaces[pointI].setSize(nPointFaces[pointI]);
+    }
+    nPointFaces = 0;
+
+
+    // 3. Fill
+
+    forAll(bMesh, patchI)
+    {
+        const polyPatch& pp = bMesh[patchI];
+
+        if (!pp.coupled())
+        {
+            forAll(pp, i)
+            {
+                const face& f = pp[i];
+                forAll(f, fp)
+                {
+                    Map<label>::const_iterator iter = meshPointMap.find(f[fp]);
+                    if (iter != meshPointMap.end())
+                    {
+                        label bFaceI = pp.start() + i - mesh_.nInternalFaces();
+                        pointBoundaryFaces[iter()][nPointFaces[iter()]++] =
+                            bFaceI;
+                    }
+                }
+            }
+        }
+    }
+}
+
+void Foam::globalMeshData::calcGlobalPointBoundaryFaces() const
+{
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalPointBoundaryFaces() :"
+            << " calculating coupled point to boundary face addressing."
+            << endl;
+    }
+
+    // Construct local point to (uncoupled)boundaryfaces.
+    labelListList pointBoundaryFaces;
+    calcPointBoundaryFaces(pointBoundaryFaces);
+
+
+    // Global indices for boundary faces
+    globalBoundaryFaceNumberingPtr_.reset
+    (
+        new globalIndex(mesh_.nFaces()-mesh_.nInternalFaces())
+    );
+    globalIndex& globalIndices = globalBoundaryFaceNumberingPtr_();
+
+
+    // Convert local boundary faces to global numbering
+    globalPointBoundaryFacesPtr_.reset
+    (
+        new labelListList(globalPointSlavesMap().constructSize())
+    );
+    labelListList& globalPointBoundaryFaces = globalPointBoundaryFacesPtr_();
+
+    forAll(pointBoundaryFaces, pointI)
+    {
+        const labelList& bFaces = pointBoundaryFaces[pointI];
+        labelList& globalFaces = globalPointBoundaryFaces[pointI];
+        globalFaces.setSize(bFaces.size());
+        forAll(bFaces, i)
+        {
+            globalFaces[i] = globalIndices.toGlobal(bFaces[i]);
+        }
+    }
+
+
+    // Pull slave pointBoundaryFaces to master
+    globalPointSlavesMap().distribute(globalPointBoundaryFaces);
+
+
+    // Merge slave labels into master globalPointBoundaryFaces
+    const labelListList& pointSlaves = globalPointSlaves();
+
+    forAll(pointSlaves, pointI)
+    {
+        const labelList& slaves = pointSlaves[pointI];
+
+        if (slaves.size() > 0)
+        {
+            labelList& myBFaces = globalPointBoundaryFaces[pointI];
+
+            forAll(slaves, i)
+            {
+                const labelList& slaveBFaces =
+                    globalPointBoundaryFaces[slaves[i]];
+
+                // Add all slaveBFaces. Note that need to check for
+                // uniqueness only in case of cyclics.
+
+                label sz = myBFaces.size();
+                myBFaces.setSize(sz+slaveBFaces.size());
+                forAll(slaveBFaces, j)
+                {
+                    label slave = slaveBFaces[j];
+                    if (findIndex(SubList<label>(myBFaces, sz), slave) == -1)
+                    {
+                        myBFaces[sz++] = slave;
+                    }
+                }
+                myBFaces.setSize(sz);
+            }
+        }
+    }
+
+
+    // Copy merged boundaryFaces back from master into slave slot
+    forAll(pointSlaves, pointI)
+    {
+        const labelList& bFaces = globalPointBoundaryFaces[pointI];
+        const labelList& slaves = pointSlaves[pointI];
+
+        forAll(slaves, i)
+        {
+            globalPointBoundaryFaces[slaves[i]] = bFaces;
+        }
+    }
+
+
+    // Sync back to slaves.
+    globalPointSlavesMap().reverseDistribute
+    (
+        coupledPatch().nPoints(),
+        globalPointBoundaryFaces
+    );
+
+
+    // Construct a map to get the face data directly
+    List<Map<label> > compactMap(Pstream::nProcs());
+    globalPointBoundaryFacesMapPtr_.reset
+    (
+        new mapDistribute
+        (
+            globalIndices,
+            globalPointBoundaryFaces,
+            compactMap
+        )
+    );
+
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalPointBoundaryFaces() :"
+            << " coupled points:" << coupledPatch().nPoints()
+            << " local boundary faces:" <<  globalIndices.localSize()
+            << " additional remote faces:"
+            <<  globalPointBoundaryFacesMapPtr_().constructSize()
+              - globalIndices.localSize()
+            << endl;
+    }
+}
+
+
+void Foam::globalMeshData::calcGlobalPointBoundaryCells() const
+{
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalPointBoundaryCells() :"
+            << " calculating coupled point to boundary cell addressing."
+            << endl;
+    }
+
+    // Create map of boundary cells and point-cell addressing
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    label bCellI = 0;
+    Map<label> meshCellMap(4*coupledPatch().nPoints());
+    DynamicList<label> cellMap(meshCellMap.size());
+
+    // Create addressing for point to boundary cells (local)
+    labelListList pointBoundaryCells(coupledPatch().nPoints());
+
+    forAll(coupledPatch().meshPoints(), pointI)
+    {
+        label meshPointI = coupledPatch().meshPoints()[pointI];
+        const labelList& pCells = mesh_.pointCells(meshPointI);
+
+        labelList& bCells = pointBoundaryCells[pointI];
+        bCells.setSize(pCells.size());
+
+        forAll(pCells, i)
+        {
+            label cellI = pCells[i];
+            Map<label>::iterator fnd = meshCellMap.find(cellI);
+
+            if (fnd != meshCellMap.end())
+            {
+                bCells[i] = fnd();
+            }
+            else
+            {
+                meshCellMap.insert(cellI, bCellI);
+                cellMap.append(cellI);
+                bCells[i] = bCellI;
+                bCellI++;
+            }
+        }
+    }
+
+
+    boundaryCellsPtr_.reset(new labelList());
+    labelList& boundaryCells = boundaryCellsPtr_();
+    boundaryCells.transfer(cellMap.shrink());
+
+
+    // Convert point-cells to global point numbers
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    globalBoundaryCellNumberingPtr_.reset
+    (
+        new globalIndex(boundaryCells.size())
+    );
+    globalIndex& globalIndices = globalBoundaryCellNumberingPtr_();
+
+
+    globalPointBoundaryCellsPtr_.reset
+    (
+        new labelListList(globalPointSlavesMap().constructSize())
+    );
+    labelListList& globalPointBoundaryCells = globalPointBoundaryCellsPtr_();
+
+    forAll(pointBoundaryCells, pointI)
+    {
+        const labelList& pCells = pointBoundaryCells[pointI];
+        labelList& globalCells = globalPointBoundaryCells[pointI];
+        globalCells.setSize(pCells.size());
+        forAll(pCells, i)
+        {
+            globalCells[i] = globalIndices.toGlobal(pCells[i]);
+        }
+    }
+
+
+    // Pull slave pointBoundaryCells to master
+    globalPointSlavesMap().distribute(globalPointBoundaryCells);
+
+
+    // Merge slave labels into master globalPointBoundaryCells
+    const labelListList& pointSlaves = globalPointSlaves();
+
+    forAll(pointSlaves, pointI)
+    {
+        const labelList& slaves = pointSlaves[pointI];
+
+        if (slaves.size() > 0)
+        {
+            labelList& myBCells = globalPointBoundaryCells[pointI];
+
+            forAll(slaves, i)
+            {
+                const labelList& slaveBCells =
+                    globalPointBoundaryCells[slaves[i]];
+
+                // Add all slaveBCells. Note that need to check for
+                // uniqueness only in case of cyclics.
+
+                label sz = myBCells.size();
+                myBCells.setSize(sz+slaveBCells.size());
+                forAll(slaveBCells, j)
+                {
+                    label slave = slaveBCells[j];
+                    if (findIndex(SubList<label>(myBCells, sz), slave) == -1)
+                    {
+                        myBCells[sz++] = slave;
+                    }
+                }
+                myBCells.setSize(sz);
+            }
+        }
+    }
+
+
+    // Copy merged boundaryCells back from master into slave slot
+    forAll(pointSlaves, pointI)
+    {
+        const labelList& bCells = globalPointBoundaryCells[pointI];
+        const labelList& slaves = pointSlaves[pointI];
+
+        forAll(slaves, i)
+        {
+            globalPointBoundaryCells[slaves[i]] = bCells;
+        }
+    }
+
+
+    // Sync back to slaves.
+    globalPointSlavesMap().reverseDistribute
+    (
+        coupledPatch().nPoints(),
+        globalPointBoundaryCells
+    );
+
+
+    // Construct a map to get the cell data directly
+    List<Map<label> > compactMap(Pstream::nProcs());
+    globalPointBoundaryCellsMapPtr_.reset
+    (
+        new mapDistribute
+        (
+            globalIndices,
+            globalPointBoundaryCells,
+            compactMap
+        )
+    );
+
+    if (debug)
+    {
+        Pout<< "globalMeshData::calcGlobalPointBoundaryCells() :"
+            << " coupled points:" << coupledPatch().nPoints()
+            << " local boundary cells:" <<  globalIndices.localSize()
+            << " additional remote cells:"
+            <<  globalPointBoundaryCellsMapPtr_().constructSize()
+              - globalIndices.localSize()
+            << endl;
+    }
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 // Construct from polyMesh
@@ -511,6 +1038,25 @@ void Foam::globalMeshData::clearOut()
     nGlobalPoints_ = -1;
     deleteDemandDrivenData(sharedEdgeLabelsPtr_);
     deleteDemandDrivenData(sharedEdgeAddrPtr_);
+
+    coupledPatchPtr_.clear();
+    // Point
+    globalPointNumberingPtr_.clear();
+    globalPointSlavesPtr_.clear();
+    globalPointSlavesMapPtr_.clear();
+    // Edge
+    globalEdgeNumberingPtr_.clear();
+    globalEdgeSlavesPtr_.clear();
+    globalEdgeSlavesMapPtr_.clear();
+    // Face
+    globalBoundaryFaceNumberingPtr_.clear();
+    globalPointBoundaryFacesPtr_.clear();
+    globalPointBoundaryFacesMapPtr_.clear();
+    // Cell
+    boundaryCellsPtr_.clear();
+    globalBoundaryCellNumberingPtr_.clear();
+    globalPointBoundaryCellsPtr_.clear();
+    globalPointBoundaryCellsMapPtr_.clear();
 }
 
 
@@ -709,6 +1255,203 @@ const Foam::labelList& Foam::globalMeshData::sharedEdgeAddr() const
 }
 
 
+const Foam::indirectPrimitivePatch& Foam::globalMeshData::coupledPatch() const
+{
+    if (!coupledPatchPtr_.valid())
+    {
+        const polyBoundaryMesh& bMesh = mesh_.boundaryMesh();
+
+        label nCoupled = 0;
+
+        forAll(bMesh, patchI)
+        {
+            const polyPatch& pp = bMesh[patchI];
+
+            if (pp.coupled())
+            {
+                nCoupled += pp.size();
+            }
+        }
+        labelList coupledFaces(nCoupled);
+        nCoupled = 0;
+
+        forAll(bMesh, patchI)
+        {
+            const polyPatch& pp = bMesh[patchI];
+
+            if (pp.coupled())
+            {
+                label faceI = pp.start();
+
+                forAll(pp, i)
+                {
+                    coupledFaces[nCoupled++] = faceI++;
+                }
+            }
+        }
+
+        coupledPatchPtr_.reset
+        (
+            new indirectPrimitivePatch
+            (
+                IndirectList<face>
+                (
+                    mesh_.faces(),
+                    coupledFaces
+                ),
+                mesh_.points()
+            )
+        );
+
+        if (debug)
+        {
+            Pout<< "globalMeshData::coupledPatch() :"
+                << " constructed  coupled faces patch:"
+                << "  faces:" << coupledPatchPtr_().size()
+                << "  points:" << coupledPatchPtr_().nPoints()
+                << endl;
+        }
+    }
+    return coupledPatchPtr_();
+}
+
+
+const Foam::globalIndex& Foam::globalMeshData::globalPointNumbering() const
+{
+    if (!globalPointNumberingPtr_.valid())
+    {
+        calcGlobalPointSlaves();
+    }
+    return globalPointNumberingPtr_();
+}
+
+
+const Foam::labelListList& Foam::globalMeshData::globalPointSlaves() const
+{
+    if (!globalPointSlavesPtr_.valid())
+    {
+        calcGlobalPointSlaves();
+    }
+    return globalPointSlavesPtr_();
+}
+
+
+const Foam::mapDistribute& Foam::globalMeshData::globalPointSlavesMap() const
+{
+    if (!globalPointSlavesMapPtr_.valid())
+    {
+        calcGlobalPointSlaves();
+    }
+    return globalPointSlavesMapPtr_();
+}
+
+
+const Foam::globalIndex& Foam::globalMeshData::globalEdgeNumbering() const
+{
+    if (!globalEdgeNumberingPtr_.valid())
+    {
+        calcGlobalEdgeSlaves();
+    }
+    return globalEdgeNumberingPtr_();
+}
+
+
+const Foam::labelListList& Foam::globalMeshData::globalEdgeSlaves() const
+{
+    if (!globalEdgeSlavesPtr_.valid())
+    {
+        calcGlobalEdgeSlaves();
+    }
+    return globalEdgeSlavesPtr_();
+}
+
+
+const Foam::mapDistribute& Foam::globalMeshData::globalEdgeSlavesMap() const
+{
+    if (!globalEdgeSlavesMapPtr_.valid())
+    {
+        calcGlobalEdgeSlaves();
+    }
+    return globalEdgeSlavesMapPtr_();
+}
+
+
+const Foam::globalIndex& Foam::globalMeshData::globalBoundaryFaceNumbering()
+const
+{
+    if (!globalBoundaryFaceNumberingPtr_.valid())
+    {
+        calcGlobalPointBoundaryFaces();
+    }
+    return globalBoundaryFaceNumberingPtr_();
+}
+
+
+const Foam::labelListList& Foam::globalMeshData::globalPointBoundaryFaces()
+const
+{
+    if (!globalPointBoundaryFacesPtr_.valid())
+    {
+        calcGlobalPointBoundaryFaces();
+    }
+    return globalPointBoundaryFacesPtr_();
+}
+
+
+const Foam::mapDistribute& Foam::globalMeshData::globalPointBoundaryFacesMap()
+const
+{
+    if (!globalPointBoundaryFacesMapPtr_.valid())
+    {
+        calcGlobalPointBoundaryFaces();
+    }
+    return globalPointBoundaryFacesMapPtr_();
+}
+
+
+const Foam::labelList& Foam::globalMeshData::boundaryCells() const
+{
+    if (!boundaryCellsPtr_.valid())
+    {
+        calcGlobalPointBoundaryCells();
+    }
+    return boundaryCellsPtr_();
+}
+
+
+const Foam::globalIndex& Foam::globalMeshData::globalBoundaryCellNumbering()
+const
+{
+    if (!globalBoundaryCellNumberingPtr_.valid())
+    {
+        calcGlobalPointBoundaryCells();
+    }
+    return globalBoundaryCellNumberingPtr_();
+}
+
+
+const Foam::labelListList& Foam::globalMeshData::globalPointBoundaryCells()
+const
+{
+    if (!globalPointBoundaryCellsPtr_.valid())
+    {
+        calcGlobalPointBoundaryCells();
+    }
+    return globalPointBoundaryCellsPtr_();
+}
+
+
+const Foam::mapDistribute& Foam::globalMeshData::globalPointBoundaryCellsMap()
+const
+{
+    if (!globalPointBoundaryCellsMapPtr_.valid())
+    {
+        calcGlobalPointBoundaryCells();
+    }
+    return globalPointBoundaryCellsMapPtr_();
+}
+
+
 void Foam::globalMeshData::movePoints(const pointField& newPoints)
 {
     // Topology does not change and we don't store any geometry so nothing
@@ -740,7 +1483,7 @@ void Foam::globalMeshData::updateMesh()
     // Option 1. Topological
     {
         // Calculate all shared points. This does all the hard work.
-        globalPoints parallelPoints(mesh_);
+        globalPoints parallelPoints(mesh_, false);
 
         // Copy data out.
         nGlobalPoints_ = parallelPoints.nGlobalPoints();
diff --git a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H
index 7c4893126d7..a6e03baf957 100644
--- a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H
+++ b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalMeshData.H
@@ -74,10 +74,13 @@ SourceFiles
 #ifndef globalMeshData_H
 #define globalMeshData_H
 
-#include "polyMesh.H"
+//#include "polyMesh.H"
 #include "Switch.H"
 #include "processorTopology.H"
 #include "labelPair.H"
+#include "indirectPrimitivePatch.H"
+#include "boundBox.H"
+#include "IOobject.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -88,7 +91,10 @@ namespace Foam
 
 class globalMeshData;
 Ostream& operator<<(Ostream&, const globalMeshData&);
-
+class globalIndex;
+class polyMesh;
+class mapDistribute;
+template<class T> class EdgeMap;
 
 /*---------------------------------------------------------------------------*\
                            Class globalMeshData Declaration
@@ -194,6 +200,39 @@ class globalMeshData
             mutable labelList* sharedEdgeAddrPtr_;
 
 
+        // Coupled point addressing
+        // This is addressing from coupled point to coupled points,faces,cells
+        // This is a full schedule so includes points only used by two
+        // coupled patches.
+
+            mutable autoPtr<indirectPrimitivePatch> coupledPatchPtr_;
+
+            // Coupled point to coupled points
+
+                mutable autoPtr<globalIndex> globalPointNumberingPtr_;
+                mutable autoPtr<labelListList> globalPointSlavesPtr_;
+                mutable autoPtr<mapDistribute> globalPointSlavesMapPtr_;
+
+            // Coupled edge to coupled edges
+
+                mutable autoPtr<globalIndex> globalEdgeNumberingPtr_;
+                mutable autoPtr<labelListList> globalEdgeSlavesPtr_;
+                mutable autoPtr<mapDistribute> globalEdgeSlavesMapPtr_;
+
+            // Coupled point to boundary faces
+
+                mutable autoPtr<globalIndex> globalBoundaryFaceNumberingPtr_;
+                mutable autoPtr<labelListList> globalPointBoundaryFacesPtr_;
+                mutable autoPtr<mapDistribute> globalPointBoundaryFacesMapPtr_;
+
+            // Coupled point to boundary cells
+
+                mutable autoPtr<labelList> boundaryCellsPtr_;
+                mutable autoPtr<globalIndex> globalBoundaryCellNumberingPtr_;
+                mutable autoPtr<labelListList> globalPointBoundaryCellsPtr_;
+                mutable autoPtr<mapDistribute> globalPointBoundaryCellsMapPtr_;
+
+
     // Private Member Functions
 
         //- Set up processor patch addressing
@@ -202,8 +241,8 @@ class globalMeshData
         //- Helper function for shared edge addressing
         static void countSharedEdges
         (
-            const HashTable<labelList, edge, Hash<edge> >& procSharedEdges,
-            HashTable<label, edge, Hash<edge> >&,
+            const EdgeMap<labelList>&,
+            EdgeMap<label>&,
             label&
         );
 
@@ -217,6 +256,22 @@ class globalMeshData
             const vectorField& separationDist
         );
 
+        //- Calculate global point addressing.
+        void calcGlobalPointSlaves() const;
+
+        //- Calculate global edge addressing.
+        void calcGlobalEdgeSlaves() const;
+
+        //- Calculate coupled point to uncoupled boundary faces. Local only.
+        void calcPointBoundaryFaces(labelListList& pointBoundaryFaces) const;
+
+        //- Calculate global point to global boundary face addressing.
+        void calcGlobalPointBoundaryFaces() const;
+
+        //- Calculate global point to global boundary cell addressing.
+        void calcGlobalPointBoundaryCells() const;
+
+
         //- Disallow default bitwise copy construct
         globalMeshData(const globalMeshData&);
 
@@ -388,6 +443,47 @@ public:
             const labelList& sharedEdgeAddr() const;
 
 
+
+        // Global master - slave point communication
+
+            //- Return patch of all coupled faces
+            const indirectPrimitivePatch& coupledPatch() const;
+
+            // Coupled point to coupled points. Coupled points are points on
+            // any coupled patch.
+
+                //- Numbering of coupled points is according to coupledPatch.
+                const globalIndex& globalPointNumbering() const;
+                //- For every coupled point the indices into the field
+                //  distributed by below map.
+                const labelListList& globalPointSlaves() const;
+                const mapDistribute& globalPointSlavesMap() const;
+
+            // Coupled edge to coupled edges.
+
+                const globalIndex& globalEdgeNumbering() const;
+                const labelListList& globalEdgeSlaves() const;
+                const mapDistribute& globalEdgeSlavesMap() const;
+
+            // Coupled point to boundary faces. These are uncoupled boundary
+            // faces only but include empty patches.
+
+                //- Numbering of boundary faces is face-mesh.nInternalFaces()
+                const globalIndex& globalBoundaryFaceNumbering() const;
+                const labelListList& globalPointBoundaryFaces() const;
+                const mapDistribute& globalPointBoundaryFacesMap() const;
+
+            // Coupled point to boundary cell
+
+                //- From boundary cell to mesh cell
+                const labelList& boundaryCells() const;
+
+                //- Numbering of boundary cells is according to boundaryCells()
+                const globalIndex& globalBoundaryCellNumbering() const;
+                const labelListList& globalPointBoundaryCells() const;
+                const mapDistribute& globalPointBoundaryCellsMap() 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 bd94a301420..6dfc702fdd6 100644
--- a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.C
+++ b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.C
@@ -70,11 +70,11 @@ void Foam::globalPoints::addToSend
 (
     const primitivePatch& pp,
     const label patchPointI,
-    const procPointList& knownInfo,
+    const labelList& knownInfo,
 
     DynamicList<label>& patchFaces,
     DynamicList<label>& indexInFace,
-    DynamicList<procPointList>& allInfo
+    DynamicList<labelList>& allInfo
 )
 {
     label meshPointI = pp.meshPoints()[patchPointI];
@@ -97,58 +97,65 @@ void Foam::globalPoints::addToSend
 
 
 // Add nbrInfo to myInfo. Return true if anything changed.
-// nbrInfo is for a point a list of all the processors using it (and the
-// meshPoint label on that processor)
+// nbrInfo is for a point a list of all the global points using it
 bool Foam::globalPoints::mergeInfo
 (
-    const procPointList& nbrInfo,
-    procPointList& myInfo
+    const labelList& nbrInfo,
+    labelList& myInfo
 )
 {
-    // Indices of entries in nbrInfo not yet in myInfo.
-    DynamicList<label> newInfo(nbrInfo.size());
+    labelList newInfo(myInfo);
+    label newI = newInfo.size();
+    newInfo.setSize(newI + nbrInfo.size());
 
     forAll(nbrInfo, i)
     {
-        const procPoint& info = nbrInfo[i];
-
-        // Check if info already in myInfo.
-        label index = -1;
-
-        forAll(myInfo, j)
-        {
-            if (myInfo[j] == info)
-            {
-                // Already have information for processor/point combination
-                // in my list so skip.
-                index = j;
-
-                break;
-            }
-        }
+        label index = findIndex(myInfo, nbrInfo[i]);
 
         if (index == -1)
         {
-            // Mark this information as being not yet in myInfo
-            newInfo.append(i);
+            newInfo[newI++] = nbrInfo[i];
         }
     }
 
-    newInfo.shrink();
+    newInfo.setSize(newI);
 
-    // Append all nbrInfos referenced in newInfo to myInfo.
+    // Did anything change?
+    bool anyChanged = (newI > myInfo.size());
 
-    label index = myInfo.size();
+    myInfo.transfer(newInfo);
 
-    myInfo.setSize(index + newInfo.size());
+    return anyChanged;
+}
 
-    forAll(newInfo, i)
-    {
-        myInfo[index++] = nbrInfo[newInfo[i]];
-    }
 
-    // Did anything change?
-    return newInfo.size() > 0;
+Foam::label Foam::globalPoints::meshToLocalPoint
+(
+    const Map<label>& meshToPatchPoint, // from mesh point to local numbering
+    const label meshPointI
+)
+{
+    return
+    (
+        meshToPatchPoint.size() == 0
+      ? meshPointI
+      : meshToPatchPoint[meshPointI]
+    );
+}
+
+
+Foam::label Foam::globalPoints::localToMeshPoint
+(
+    const labelList& patchToMeshPoint,
+    const label localPointI
+)
+{
+    return
+    (
+        patchToMeshPoint.size() == 0
+      ? localPointI
+      : patchToMeshPoint[localPointI]
+    );
 }
 
 
@@ -156,34 +163,30 @@ bool Foam::globalPoints::mergeInfo
 // Uses mergeInfo above. Returns true if data kept for meshPointI changed.
 bool Foam::globalPoints::storeInfo
 (
-    const procPointList& nbrInfo,
-    const label meshPointI
+    const labelList& nbrInfo,
+    const label localPointI
 )
 {
     label infoChanged = false;
 
     // Get the index into the procPoints list.
-    Map<label>::iterator iter = meshToProcPoint_.find(meshPointI);
+    Map<label>::iterator iter = meshToProcPoint_.find(localPointI);
 
     if (iter != meshToProcPoint_.end())
     {
-        procPointList& knownInfo = procPoints_[iter()];
-
-        if (mergeInfo(nbrInfo, knownInfo))
+        if (mergeInfo(nbrInfo, procPoints_[iter()]))
         {
             infoChanged = true;
         }
     }
     else
     {
-        procPointList knownInfo(1);
-        knownInfo[0][0] = Pstream::myProcNo();
-        knownInfo[0][1] = meshPointI;
+        labelList knownInfo(1, globalIndices_.toGlobal(localPointI));
 
         if (mergeInfo(nbrInfo, knownInfo))
         {
             // Update addressing from into procPoints
-            meshToProcPoint_.insert(meshPointI, procPoints_.size());
+            meshToProcPoint_.insert(localPointI, procPoints_.size());
             // Insert into list of equivalences.
             procPoints_.append(knownInfo);
 
@@ -197,6 +200,7 @@ bool Foam::globalPoints::storeInfo
 // Insert my own points into structure and mark as changed.
 void Foam::globalPoints::initOwnPoints
 (
+    const Map<label>& meshToPatchPoint,
     const bool allPoints,
     labelHashSet& changedPoints
 )
@@ -221,18 +225,24 @@ void Foam::globalPoints::initOwnPoints
                 forAll(meshPoints, i)
                 {
                     label meshPointI = meshPoints[i];
+                    label localPointI = meshToLocalPoint
+                    (
+                        meshToPatchPoint,
+                        meshPointI
+                    );
+                    labelList knownInfo
+                    (
+                        1,
+                        globalIndices_.toGlobal(localPointI)
+                    );
 
-                    procPointList knownInfo(1);
-                    knownInfo[0][0] = Pstream::myProcNo();
-                    knownInfo[0][1] = meshPointI;
-
-                    // Update addressing from meshpoint to index in procPoints
-                    meshToProcPoint_.insert(meshPointI, procPoints_.size());
+                    // Update addressing from point to index in procPoints
+                    meshToProcPoint_.insert(localPointI, procPoints_.size());
                     // Insert into list of equivalences.
                     procPoints_.append(knownInfo);
 
                     // Update changedpoints info.
-                    changedPoints.insert(meshPointI);
+                    changedPoints.insert(localPointI);
                 }
             }
             else
@@ -243,18 +253,25 @@ void Foam::globalPoints::initOwnPoints
                 forAll(boundaryPoints, i)
                 {
                     label meshPointI = meshPoints[boundaryPoints[i]];
+                    label localPointI = meshToLocalPoint
+                    (
+                        meshToPatchPoint,
+                        meshPointI
+                    );
 
-                    procPointList knownInfo(1);
-                    knownInfo[0][0] = Pstream::myProcNo();
-                    knownInfo[0][1] = meshPointI;
+                    labelList knownInfo
+                    (
+                        1,
+                        globalIndices_.toGlobal(localPointI)
+                    );
 
-                    // Update addressing from meshpoint to index in procPoints
-                    meshToProcPoint_.insert(meshPointI, procPoints_.size());
+                    // Update addressing from point to index in procPoints
+                    meshToProcPoint_.insert(localPointI, procPoints_.size());
                     // Insert into list of equivalences.
                     procPoints_.append(knownInfo);
 
                     // Update changedpoints info.
-                    changedPoints.insert(meshPointI);
+                    changedPoints.insert(localPointI);
                 }
             }
         }
@@ -263,8 +280,12 @@ void Foam::globalPoints::initOwnPoints
 
 
 // Send all my info on changedPoints_ to my neighbours.
-void Foam::globalPoints::sendPatchPoints(const labelHashSet& changedPoints)
- const
+void Foam::globalPoints::sendPatchPoints
+(
+    const Map<label>& meshToPatchPoint,
+    PstreamBuffers& pBufs,
+    const labelHashSet& changedPoints
+) const
 {
     const polyBoundaryMesh& patches = mesh_.boundaryMesh();
 
@@ -280,10 +301,10 @@ void Foam::globalPoints::sendPatchPoints(const labelHashSet& changedPoints)
             // index in patch face
             DynamicList<label> indexInFace(pp.nPoints());
             // all information I currently hold about this patchPoint
-            DynamicList<procPointList> allInfo(pp.nPoints());
+            DynamicList<labelList> allInfo(pp.nPoints());
 
 
-            // Now collect information on all mesh points mentioned in
+            // Now collect information on all points mentioned in
             // changedPoints. Note that these points only should occur on
             // processorPatches (or rather this is a limitation!).
 
@@ -292,14 +313,19 @@ void Foam::globalPoints::sendPatchPoints(const labelHashSet& changedPoints)
             forAll(meshPoints, patchPointI)
             {
                 label meshPointI = meshPoints[patchPointI];
+                label localPointI = meshToLocalPoint
+                (
+                    meshToPatchPoint,
+                    meshPointI
+                );
 
-                if (changedPoints.found(meshPointI))
+                if (changedPoints.found(localPointI))
                 {
-                    label index = meshToProcPoint_[meshPointI];
+                    label index = meshToProcPoint_[localPointI];
 
-                    const procPointList& knownInfo = procPoints_[index];
+                    const labelList& knownInfo = procPoints_[index];
 
-                    // Add my information about meshPointI to the send buffers
+                    // Add my information about localPointI to the send buffers
                     addToSend
                     (
                         pp,
@@ -312,9 +338,6 @@ void Foam::globalPoints::sendPatchPoints(const labelHashSet& changedPoints)
                     );
                 }
             }
-            patchFaces.shrink();
-            indexInFace.shrink();
-            allInfo.shrink();
 
             // Send to neighbour
             {
@@ -328,12 +351,7 @@ void Foam::globalPoints::sendPatchPoints(const labelHashSet& changedPoints)
                         << patchFaces.size() << endl;
                 }
 
-                OPstream toNeighbour
-                (
-                    Pstream::blocking,
-                    procPatch.neighbProcNo()
-                );
-
+                UOPstream toNeighbour(procPatch.neighbProcNo(), pBufs);
                 toNeighbour << patchFaces << indexInFace << allInfo;
             }
         }
@@ -345,8 +363,13 @@ void Foam::globalPoints::sendPatchPoints(const labelHashSet& changedPoints)
 // After finishing will have updated
 // - procPoints_ : all neighbour information merged in.
 // - meshToProcPoint_
-// - changedPoints: all meshPoints for which something changed.
-void Foam::globalPoints::receivePatchPoints(labelHashSet& changedPoints)
+// - changedPoints: all points for which something changed.
+void Foam::globalPoints::receivePatchPoints
+(
+    const Map<label>& meshToPatchPoint,
+    PstreamBuffers& pBufs,
+    labelHashSet& changedPoints
+)
 {
     const polyBoundaryMesh& patches = mesh_.boundaryMesh();
 
@@ -364,14 +387,10 @@ void Foam::globalPoints::receivePatchPoints(labelHashSet& changedPoints)
 
             labelList patchFaces;
             labelList indexInFace;
-            List<procPointList> nbrInfo;
+            List<labelList> nbrInfo;
 
             {
-                IPstream fromNeighbour
-                (
-                    Pstream::blocking,
-                    procPatch.neighbProcNo()
-                );
+                UIPstream fromNeighbour(procPatch.neighbProcNo(), pBufs);
                 fromNeighbour >> patchFaces >> indexInFace >> nbrInfo;
             }
 
@@ -392,19 +411,15 @@ void Foam::globalPoints::receivePatchPoints(labelHashSet& changedPoints)
                 // Get the meshpoint on my side
                 label meshPointI = f[index];
 
-                //const procPointList& info = nbrInfo[i];
-                //Pout << "Received for my coord "
-                //    << mesh_.points()[meshPointI];
-                //
-                //forAll(info, j)
-                //{
-                //    Pout<< ' ' <<info[j];
-                //}
-                //Pout<< endl;
-
-                if (storeInfo(nbrInfo[i], meshPointI))
+                label localPointI = meshToLocalPoint
+                (
+                    meshToPatchPoint,
+                    meshPointI
+                );
+
+                if (storeInfo(nbrInfo[i], localPointI))
                 {
-                    changedPoints.insert(meshPointI);
+                    changedPoints.insert(localPointI);
                 }
             }
         }
@@ -428,29 +443,41 @@ void Foam::globalPoints::receivePatchPoints(labelHashSet& changedPoints)
                 label meshPointA = meshPoints[e[0]];
                 label meshPointB = meshPoints[e[1]];
 
-                // Do we have information on meshPointA?
+                label localA = meshToLocalPoint
+                (
+                    meshToPatchPoint,
+                    meshPointA
+                );
+                label localB = meshToLocalPoint
+                (
+                    meshToPatchPoint,
+                    meshPointB
+                );
+
+
+                // Do we have information on pointA?
                 Map<label>::iterator procPointA =
-                    meshToProcPoint_.find(meshPointA);
+                    meshToProcPoint_.find(localA);
 
                 if (procPointA != meshToProcPoint_.end())
                 {
                     // Store A info onto pointB
-                    if (storeInfo(procPoints_[procPointA()], meshPointB))
+                    if (storeInfo(procPoints_[procPointA()], localB))
                     {
-                        changedPoints.insert(meshPointB);
+                        changedPoints.insert(localB);
                     }
                 }
 
                 // Same for info on pointB
                 Map<label>::iterator procPointB =
-                    meshToProcPoint_.find(meshPointB);
+                    meshToProcPoint_.find(localB);
 
                 if (procPointB != meshToProcPoint_.end())
                 {
                     // Store B info onto pointA
-                    if (storeInfo(procPoints_[procPointB()], meshPointA))
+                    if (storeInfo(procPoints_[procPointB()], localA))
                     {
-                        changedPoints.insert(meshPointA);
+                        changedPoints.insert(localA);
                     }
                 }
             }
@@ -461,25 +488,24 @@ void Foam::globalPoints::receivePatchPoints(labelHashSet& changedPoints)
 
 // Remove entries which are handled by normal face-face communication. I.e.
 // those points where the equivalence list is only me and my (face)neighbour
-void Foam::globalPoints::remove(const Map<label>& directNeighbours)
+void Foam::globalPoints::remove
+(
+    const labelList& patchToMeshPoint,
+    const Map<label>& directNeighbours
+)
 {
     // Save old ones.
     Map<label> oldMeshToProcPoint(meshToProcPoint_);
     meshToProcPoint_.clear();
 
-    List<procPointList> oldProcPoints;
+    List<labelList> oldProcPoints;
     oldProcPoints.transfer(procPoints_);
 
     // Go through all equivalences
-    for
-    (
-        Map<label>::const_iterator iter = oldMeshToProcPoint.begin();
-        iter != oldMeshToProcPoint.end();
-        ++iter
-    )
+    forAllConstIter(Map<label>, oldMeshToProcPoint, iter)
     {
-        label meshPointI = iter.key();
-        const procPointList& pointInfo = oldProcPoints[iter()];
+        label localPointI = iter.key();
+        const labelList& pointInfo = oldProcPoints[iter()];
 
         if (pointInfo.size() == 2)
         {
@@ -488,23 +514,29 @@ void Foam::globalPoints::remove(const Map<label>& directNeighbours)
             // is in it. This would be an ordinary connection and can be
             // handled by normal face-face connectivity.
 
-            const procPoint& a = pointInfo[0];
-            const procPoint& b = pointInfo[1];
+            const label a = pointInfo[0];
+            const label b = pointInfo[1];
 
             if
             (
-                (a[0] == Pstream::myProcNo() && directNeighbours.found(a[1]))
-             || (b[0] == Pstream::myProcNo() && directNeighbours.found(b[1]))
+                (
+                    globalIndices_.isLocal(a)
+                 && directNeighbours.found(globalIndices_.toLocal(a))
+                )
+             || (
+                    globalIndices_.isLocal(b)
+                 && directNeighbours.found(globalIndices_.toLocal(b))
+                )
             )
             {
                 // Normal faceNeighbours
-                if (a[0] == Pstream::myProcNo())
+                if (globalIndices_.isLocal(a))
                 {
                     //Pout<< "Removing direct neighbour:"
                     //    << mesh_.points()[a[1]]
                     //    << endl;
                 }
-                else if (b[0] == Pstream::myProcNo())
+                else if (globalIndices_.isLocal(b))
                 {
                     //Pout<< "Removing direct neighbour:"
                     //    << mesh_.points()[b[1]]
@@ -525,7 +557,7 @@ void Foam::globalPoints::remove(const Map<label>& directNeighbours)
                 // be found if the two domains are face connected at all
                 // (not shown in the picture)
 
-                meshToProcPoint_.insert(meshPointI, procPoints_.size());
+                meshToProcPoint_.insert(localPointI, procPoints_.size());
                 procPoints_.append(pointInfo);
             }
         }
@@ -536,17 +568,17 @@ void Foam::globalPoints::remove(const Map<label>& directNeighbours)
             // So this meshPoint will have info of size one only.
             if
             (
-                pointInfo[0][0] != Pstream::myProcNo()
-             || !directNeighbours.found(pointInfo[0][1])
+                !globalIndices_.isLocal(pointInfo[0])
+             || !directNeighbours.found(globalIndices_.toLocal(pointInfo[0]))
             )
             {
-                meshToProcPoint_.insert(meshPointI, procPoints_.size());
+                meshToProcPoint_.insert(localPointI, procPoints_.size());
                 procPoints_.append(pointInfo);
             }
         }
         else
         {
-            meshToProcPoint_.insert(meshPointI, procPoints_.size());
+            meshToProcPoint_.insert(localPointI, procPoints_.size());
             procPoints_.append(pointInfo);
         }
     }
@@ -555,35 +587,67 @@ void Foam::globalPoints::remove(const Map<label>& directNeighbours)
 }
 
 
+// Compact indices
+void Foam::globalPoints::compact()
+{
+    // 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)
+    {
+        label oldIndex = iter();
+
+        if (oldToNew[oldIndex] == -1)
+        {
+            iter() = newIndex;
+            oldToNew[oldIndex] = newIndex;
+            newToOld[newIndex] = oldIndex;
+            newIndex++;
+        }
+    }
+    List<labelList> oldProcPoints;
+    oldProcPoints.transfer(procPoints_);
+
+    procPoints_.setSize(meshToProcPoint_.size());
+    forAll(procPoints_, i)
+    {
+        // Transfer
+        procPoints_[i].transfer(oldProcPoints[newToOld[i]]);
+    }
+}
+
+
 // Get (indices of) points for which I am master (= lowest numbered point on
 // lowest numbered processor).
 // (equivalence lists should be complete by now)
-Foam::labelList Foam::globalPoints::getMasterPoints() const
+Foam::labelList Foam::globalPoints::getMasterPoints
+(
+    const labelList& patchToMeshPoint
+) const
 {
     labelList masterPoints(nPatchPoints_);
     label nMaster = 0;
 
-    // Go through all equivalences and determine meshPoints where I am master.
-    for
-    (
-        Map<label>::const_iterator iter = meshToProcPoint_.begin();
-        iter != meshToProcPoint_.end();
-        ++iter
-    )
+    // Go through all equivalences and determine points where I am master.
+    forAllConstIter(Map<label>, meshToProcPoint_, iter)
     {
-        label meshPointI = iter.key();
-        const procPointList& pointInfo = procPoints_[iter()];
+        label localPointI = iter.key();
+        const labelList& pointInfo = procPoints_[iter()];
 
         if (pointInfo.size() < 2)
         {
             // Points should have an equivalence list >= 2 since otherwise
             // they would be direct neighbours and have been removed in the
             // call to 'remove'.
-            Pout<< "MeshPoint:" << meshPointI
-                << " coord:" << mesh_.points()[meshPointI]
-                << " has no corresponding point on a neighbouring processor"
-                << endl;
-            FatalErrorIn("globalPoints::getMasterPoints()")
+            label meshPointI = localToMeshPoint(patchToMeshPoint, localPointI);
+
+            FatalErrorIn("globalPoints::getMasterPoints(..)")
                 << '[' << Pstream::myProcNo() << ']'
                 << " MeshPoint:" << meshPointI
                 << " coord:" << mesh_.points()[meshPointI]
@@ -592,33 +656,17 @@ Foam::labelList Foam::globalPoints::getMasterPoints() const
         }
         else
         {
-            // Find lowest processor and lowest mesh point on this processor.
-            label lowestProcI = labelMax;
-            label lowestPointI = labelMax;
-
-            forAll(pointInfo, i)
-            {
-                label proc = pointInfo[i][0];
-
-                if (proc < lowestProcI)
-                {
-                    lowestProcI = proc;
-                    lowestPointI = pointInfo[i][1];
-                }
-                else if (proc == lowestProcI)
-                {
-                    lowestPointI = min(lowestPointI, pointInfo[i][1]);
-                }
-            }
+            // Check if lowest numbered processor and point is
+            // on this processor. Since already sorted is first element.
 
             if
             (
-                lowestProcI == Pstream::myProcNo()
-             && lowestPointI == meshPointI
+                globalIndices_.isLocal(pointInfo[0])
+             && globalIndices_.toLocal(pointInfo[0]) == localPointI
             )
             {
                 // I am lowest numbered processor and point. Add to my list.
-                masterPoints[nMaster++] = meshPointI;
+                masterPoints[nMaster++] = localPointI;
             }
         }
     }
@@ -630,7 +678,11 @@ Foam::labelList Foam::globalPoints::getMasterPoints() const
 
 
 // Send subset of lists
-void Foam::globalPoints::sendSharedPoints(const labelList& changedIndices) const
+void Foam::globalPoints::sendSharedPoints
+(
+    PstreamBuffers& pBufs,
+    const labelList& changedIndices
+) const
 {
     const polyBoundaryMesh& patches = mesh_.boundaryMesh();
 
@@ -643,7 +695,7 @@ void Foam::globalPoints::sendSharedPoints(const labelList& changedIndices) const
             const processorPolyPatch& procPatch =
                 refCast<const processorPolyPatch>(pp);
 
-            OPstream toNeighbour(Pstream::blocking, procPatch.neighbProcNo());
+            UOPstream toNeighbour(procPatch.neighbProcNo(), pBufs);
 
             if (debug)
             {
@@ -652,6 +704,7 @@ void Foam::globalPoints::sendSharedPoints(const labelList& changedIndices) const
                     << changedIndices.size() << endl;
             }
 
+            // Send over changed elements
             toNeighbour
                 << UIndirectList<label>(sharedPointAddr_, changedIndices)()
                 << UIndirectList<label>(sharedPointLabels_, changedIndices)();
@@ -661,10 +714,15 @@ void Foam::globalPoints::sendSharedPoints(const labelList& changedIndices) const
 
 
 // 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 meshpoint
+// 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(labelList& changedIndices)
+void Foam::globalPoints::receiveSharedPoints
+(
+    const Map<label>& meshToPatchPoint,
+    PstreamBuffers& pBufs,
+    labelList& changedIndices
+)
 {
     changedIndices.setSize(sharedPointAddr_.size());
     label nChanged = 0;
@@ -681,22 +739,18 @@ void Foam::globalPoints::receiveSharedPoints(labelList& changedIndices)
             const processorPolyPatch& procPatch =
                 refCast<const processorPolyPatch>(pp);
 
-            // Map from neighbouring meshPoint to sharedPoint)
+            // Map from neighbouring mesh or patch point to sharedPoint)
             Map<label> nbrSharedPoints(sharedPointAddr_.size());
 
             {
-                // Receive meshPoints on neighbour and sharedPoints and build
+                // Receive points on neighbour and sharedPoints and build
                 // map from it. Note that we could have built the map on the
                 // neighbour and sent it over.
                 labelList nbrSharedPointAddr;
                 labelList nbrSharedPointLabels;
 
                 {
-                    IPstream fromNeighbour
-                    (
-                        Pstream::blocking,
-                        procPatch.neighbProcNo()
-                    );
+                    UIPstream fromNeighbour(procPatch.neighbProcNo(), pBufs);
                     fromNeighbour >> nbrSharedPointAddr >> nbrSharedPointLabels;
                 }
 
@@ -705,7 +759,7 @@ void Foam::globalPoints::receiveSharedPoints(labelList& changedIndices)
                 {
                     nbrSharedPoints.insert
                     (
-                        nbrSharedPointLabels[i], // meshpoint on neighbour
+                        nbrSharedPointLabels[i], // mesh/patchpoint on neighbour
                         nbrSharedPointAddr[i]    // sharedPoint label
                     );
                 }
@@ -713,39 +767,36 @@ void Foam::globalPoints::receiveSharedPoints(labelList& changedIndices)
 
 
             // Merge into whatever information I hold.
-            for
-            (
-                Map<label>::const_iterator iter = meshToProcPoint_.begin();
-                iter != meshToProcPoint_.end();
-                ++iter
-            )
+            forAllConstIter(Map<label>, meshToProcPoint_, iter)
             {
-                label meshPointI = iter.key();
+                label localPointI = iter.key();
                 label index = iter();
 
                 if (sharedPointAddr_[index] == -1)
                 {
-                    // No shared point known yet for this meshPoint.
+                    // No shared point known yet for this point.
                     // See if was received from neighbour.
-                    const procPointList& knownInfo = procPoints_[index];
+                    const labelList& knownInfo = procPoints_[index];
 
                     // Check through the whole equivalence list for any
                     // point from the neighbour.
                     forAll(knownInfo, j)
                     {
-                        const procPoint& info = knownInfo[j];
+                        const label info = knownInfo[j];
+                        label procI = globalIndices_.whichProcID(info);
+                        label pointI = globalIndices_.toLocal(procI, info);
 
                         if
                         (
-                            (info[0] == procPatch.neighbProcNo())
-                         && nbrSharedPoints.found(info[1])
+                            procI == procPatch.neighbProcNo()
+                         && nbrSharedPoints.found(pointI)
                         )
                         {
                             // So this knownInfo contains the neighbour point
-                            label sharedPointI = nbrSharedPoints[info[1]];
+                            label sharedPointI = nbrSharedPoints[pointI];
 
                             sharedPointAddr_[index] = sharedPointI;
-                            sharedPointLabels_[index] = meshPointI;
+                            sharedPointLabels_[index] = localPointI;
                             changedIndices[nChanged++] = index;
 
                             break;
@@ -759,13 +810,15 @@ void Foam::globalPoints::receiveSharedPoints(labelList& changedIndices)
             const cyclicPolyPatch& cycPatch =
                 refCast<const cyclicPolyPatch>(pp);
 
-            // Build map from meshPoint to sharedPoint
-            Map<label> meshToSharedPoint(sharedPointAddr_.size());
+            // Build map from mesh or patch point to sharedPoint
+            Map<label> localToSharedPoint(sharedPointAddr_.size());
             forAll(sharedPointLabels_, i)
             {
-                label meshPointI = sharedPointLabels_[i];
-
-                meshToSharedPoint.insert(meshPointI, sharedPointAddr_[i]);
+                localToSharedPoint.insert
+                (
+                    sharedPointLabels_[i],
+                    sharedPointAddr_[i]
+                );
             }
 
             // Sync all info.
@@ -775,17 +828,27 @@ void Foam::globalPoints::receiveSharedPoints(labelList& changedIndices)
             forAll(connections, i)
             {
                 const edge& e = connections[i];
-
                 label meshPointA = pp.meshPoints()[e[0]];
                 label meshPointB = pp.meshPoints()[e[1]];
 
-                // Do we already have shared point for meshPointA?
-                Map<label>::iterator fndA = meshToSharedPoint.find(meshPointA);
-                Map<label>::iterator fndB = meshToSharedPoint.find(meshPointB);
+                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);
 
-                if (fndA != meshToSharedPoint.end())
+                if (fndA != localToSharedPoint.end())
                 {
-                    if (fndB != meshToSharedPoint.end())
+                    if (fndB != localToSharedPoint.end())
                     {
                         if (fndA() != fndB())
                         {
@@ -808,26 +871,26 @@ void Foam::globalPoints::receiveSharedPoints(labelList& changedIndices)
                         // No shared point yet for B.
                         label sharedPointI = fndA();
 
-                        // Store shared point for meshPointB
-                        label index = meshToProcPoint_[meshPointB];
+                        // Store shared point for pointB
+                        label index = meshToProcPoint_[localB];
 
                         sharedPointAddr_[index] = sharedPointI;
-                        sharedPointLabels_[index] = meshPointB;
+                        sharedPointLabels_[index] = localB;
                         changedIndices[nChanged++] = index;
                     }
                 }
                 else
                 {
                     // No shared point yet for A.
-                    if (fndB != meshToSharedPoint.end())
+                    if (fndB != localToSharedPoint.end())
                     {
                         label sharedPointI = fndB();
 
-                        // Store shared point for meshPointA
-                        label index = meshToProcPoint_[meshPointA];
+                        // Store shared point for pointA
+                        label index = meshToProcPoint_[localA];
 
                         sharedPointAddr_[index] = sharedPointI;
-                        sharedPointLabels_[index] = meshPointA;
+                        sharedPointLabels_[index] = localA;
                         changedIndices[nChanged++] = index;
                     }
                 }
@@ -887,18 +950,12 @@ Foam::edgeList Foam::globalPoints::coupledPoints(const cyclicPolyPatch& pp)
 }
 
 
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-// Construct from components
-Foam::globalPoints::globalPoints(const polyMesh& mesh)
-:
-    mesh_(mesh),
-    nPatchPoints_(countPatchPoints(mesh.boundaryMesh())),
-    procPoints_(nPatchPoints_),
-    meshToProcPoint_(nPatchPoints_),
-    sharedPointAddr_(0),
-    sharedPointLabels_(0),
-    nGlobalPoints_(0)
+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
+)
 {
     if (debug)
     {
@@ -921,24 +978,33 @@ Foam::globalPoints::globalPoints(const polyMesh& mesh)
     //   shared point is not on the boundary of any processor patches using it.
     //   This would happen if a domain was pinched such that two patches share
     //   a point or edge.
-    initOwnPoints(true, changedPoints);
+    initOwnPoints(meshToPatchPoint, true, changedPoints);
 
     // Do one exchange iteration to get neighbour points.
-    sendPatchPoints(changedPoints);
-    receivePatchPoints(changedPoints);
+    {
+        PstreamBuffers pBufs(Pstream::defaultCommsType);
+        sendPatchPoints(meshToPatchPoint, pBufs, changedPoints);
+        pBufs.finishedSends();
+        receivePatchPoints(meshToPatchPoint, pBufs, changedPoints);
+    }
 
 
     // Save neighbours reachable through face-face communication.
-    Map<label> neighbourList(meshToProcPoint_);
-
+    Map<label> neighbourList;
+    if (!keepAllPoints)
+    {
+        neighbourList = meshToProcPoint_;
+    }
 
     // Exchange until nothing changes on all processors.
     bool changed = false;
 
     do
     {
-        sendPatchPoints(changedPoints);
-        receivePatchPoints(changedPoints);
+        PstreamBuffers pBufs(Pstream::defaultCommsType);
+        sendPatchPoints(meshToPatchPoint, pBufs, changedPoints);
+        pBufs.finishedSends();
+        receivePatchPoints(meshToPatchPoint, pBufs, changedPoints);
 
         changed = changedPoints.size() > 0;
         reduce(changed, orOp<bool>());
@@ -947,29 +1013,57 @@ Foam::globalPoints::globalPoints(const polyMesh& mesh)
 
 
     // Remove direct neighbours from point equivalences.
-    remove(neighbourList);
-
-
-    //Pout<< "After removing locally connected points:" << endl;
-    //for
-    //(
-    //    Map<label>::const_iterator iter = meshToProcPoint_.begin();
-    //    iter != meshToProcPoint_.end();
-    //    ++iter
-    //)
-    //{
-    //    label meshPointI = iter.key();
-    //    const procPointList& pointInfo = procPoints_[iter()];
-    //
-    //    forAll(pointInfo, i)
-    //    {
-    //        Pout<< "    pointI:" << meshPointI << ' '
-    //            << mesh.points()[meshPointI]
-    //            << " connected to proc " << pointInfo[i][0]
-    //            << " point:" << pointInfo[i][1]
-    //        << endl;
-    //    }
-    //}
+    if (!keepAllPoints)
+    {
+        remove(patchToMeshPoint, neighbourList);
+    }
+    else
+    {
+        // Compact out unused elements
+        compact();
+    }
+
+    procPoints_.shrink();
+
+    // Sort procPoints in incremental order. This will make the master the
+    // first element.
+    forAllIter(Map<label>, meshToProcPoint_, iter)
+    {
+        sort(procPoints_[iter()]);
+    }
+
+
+    // 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;
+    //     }
+    // }
 
 
     // We now have - in procPoints_ - a list of points which are shared between
@@ -988,49 +1082,21 @@ Foam::globalPoints::globalPoints(const polyMesh& mesh)
     sharedPointLabels_ = -1;
 
 
-    // Get points for which I am master (lowest numbered proc)
-    labelList masterPoints(getMasterPoints());
-
+    // Get point labels of points for which I am master (lowest
+    // numbered proc)
+    labelList masterPoints(getMasterPoints(patchToMeshPoint));
 
-    // Determine number of master points on all processors.
-    labelList sharedPointSizes(Pstream::nProcs());
-    sharedPointSizes[Pstream::myProcNo()] = masterPoints.size();
-
-    Pstream::gatherList(sharedPointSizes);
-    Pstream::scatterList(sharedPointSizes);
-
-    if (debug)
-    {
-        Pout<< "sharedPointSizes:" << sharedPointSizes << endl;
-    }
-
-    // Get total number of shared points
-    nGlobalPoints_ = 0;
-    forAll(sharedPointSizes, procI)
-    {
-        nGlobalPoints_ += sharedPointSizes[procI];
-    }
-
-    // Assign sharedPoint labels. Every processor gets assigned consecutive
-    // numbers for its master points.
-    // These are assigned in processor order so processor0 gets
-    // 0..masterPoints.size()-1 etc.
-
-    // My point labels start after those of lower numbered processors
-    label sharedPointI = 0;
-    for (label procI = 0; procI < Pstream::myProcNo(); procI++)
-    {
-        sharedPointI += sharedPointSizes[procI];
-    }
+    // Get global numbering for master points
+    globalIndex globalMasterPoints(masterPoints.size());
+    nGlobalPoints_ = globalMasterPoints.size();
 
     forAll(masterPoints, i)
     {
-        label meshPointI = masterPoints[i];
-
-        label index = meshToProcPoint_[meshPointI];
+        label localPointI = masterPoints[i];
+        label index = meshToProcPoint_[localPointI];
 
-        sharedPointLabels_[index] = meshPointI;
-        sharedPointAddr_[index] = sharedPointI++;
+        sharedPointLabels_[index] = localPointI;
+        sharedPointAddr_[index] = globalMasterPoints.toGlobal(i);
     }
 
 
@@ -1060,8 +1126,10 @@ Foam::globalPoints::globalPoints(const polyMesh& mesh)
             Pout<< "Determined " << changedIndices.size() << " shared points."
                 << " Exchanging them" << endl;
         }
-        sendSharedPoints(changedIndices);
-        receiveSharedPoints(changedIndices);
+        PstreamBuffers pBufs(Pstream::defaultCommsType);
+        sendSharedPoints(pBufs, changedIndices);
+        pBufs.finishedSends();
+        receiveSharedPoints(meshToPatchPoint, pBufs, changedIndices);
 
         changed = changedIndices.size() > 0;
         reduce(changed, orOp<bool>());
@@ -1073,7 +1141,7 @@ Foam::globalPoints::globalPoints(const polyMesh& mesh)
     {
         if (sharedPointLabels_[i] == -1)
         {
-            FatalErrorIn("globalPoints::globalPoints(const polyMesh& mesh)")
+            FatalErrorIn("globalPoints::globalPoints(const polyMesh&)")
                 << "Problem: shared point on processor " << Pstream::myProcNo()
                 << " not set at index " << sharedPointLabels_[i] << endl
                 << "This might mean the individual processor domains are not"
@@ -1091,4 +1159,56 @@ Foam::globalPoints::globalPoints(const polyMesh& mesh)
 }
 
 
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Construct from mesh
+Foam::globalPoints::globalPoints
+(
+    const polyMesh& mesh,
+    const bool keepAllPoints
+)
+:
+    mesh_(mesh),
+    globalIndices_(mesh_.nPoints()),
+    nPatchPoints_(countPatchPoints(mesh.boundaryMesh())),
+    procPoints_(nPatchPoints_),
+    meshToProcPoint_(nPatchPoints_),
+    sharedPointAddr_(0),
+    sharedPointLabels_(0),
+    nGlobalPoints_(0)
+{
+    // Empty patch maps to signal storing mesh point labels
+    Map<label> meshToPatchPoint(0);
+    labelList patchToMeshPoint(0);
+
+    calculateSharedPoints(meshToPatchPoint, patchToMeshPoint, keepAllPoints);
+}
+
+
+// Construct from mesh and patch of coupled faces
+Foam::globalPoints::globalPoints
+(
+    const polyMesh& mesh,
+    const indirectPrimitivePatch& coupledPatch,
+    const bool keepAllPoints
+)
+:
+    mesh_(mesh),
+    globalIndices_(coupledPatch.nPoints()),
+    nPatchPoints_(coupledPatch.nPoints()),
+    procPoints_(nPatchPoints_),
+    meshToProcPoint_(nPatchPoints_),
+    sharedPointAddr_(0),
+    sharedPointLabels_(0),
+    nGlobalPoints_(0)
+{
+    calculateSharedPoints
+    (
+        coupledPatch.meshPointMap(),
+        coupledPatch.meshPoints(),
+        keepAllPoints
+    );
+}
+
+
 // ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.H b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.H
index c2361da2baa..41d010ec9f2 100644
--- a/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.H
+++ b/src/OpenFOAM/meshes/polyMesh/globalMeshData/globalPoints.H
@@ -29,9 +29,8 @@ Description
     Calculates points shared by more than two processor patches or cyclic
     patches.
 
-    Is used in globalMeshData. (this info is needed for point-edge
-    communication where you do all but these shared points with patch to
-    patch communication but need to do a reduce on these shared points)
+    Is used in globalMeshData. (this info is needed for point/edge
+    communication where processor swaps are not enough to exchange data)
 
     Works purely topological and using local communication only.
     Needs:
@@ -41,8 +40,8 @@ Description
       - f[0] ordering on patch faces to be ok.
 
     Works by constructing equivalence lists for all the points on processor
-    patches. These list are procPointList and give processor and meshPoint
-    label on that processor.
+    patches. These list are in globalIndex numbering (so consecutively numbered
+    per processor)
     E.g.
     @verbatim
           ((7 93)(4 731)(3 114))
@@ -85,6 +84,9 @@ Description
      endloop until nothing changes.
 
 
+    Note: the data held is either mesh point labels (construct from mesh only)
+    or patch point labels (construct from mesh and patch).
+
 SourceFiles
     globalPoints.C
 
@@ -95,11 +97,11 @@ SourceFiles
 
 #include "DynamicList.H"
 #include "Map.H"
-#include "labelList.H"
-#include "FixedList.H"
 #include "primitivePatch.H"
 #include "className.H"
 #include "edgeList.H"
+#include "globalIndex.H"
+#include "indirectPrimitivePatch.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -119,30 +121,29 @@ class globalPoints
 {
     // Private classes
 
-        //- Define procPointList as holding a list of meshPoint/processor labels
-        typedef FixedList<label, 2> procPoint;
-        typedef List<procPoint> procPointList;
-
     // Private data
 
         //- Mesh reference
         const polyMesh& mesh_;
 
+        //- Global numbering of points
+        globalIndex globalIndices_;
+
         //- Sum of points on processor patches (unfiltered, point on 2 patches
         //  counts as 2)
         const label nPatchPoints_;
 
         //- All points on boundaries and their corresponding connected points
         //  on other processors.
-        DynamicList<procPointList> procPoints_;
+        DynamicList<labelList> procPoints_;
 
-        //- Map from mesh point to index in procPoints
+        //- Map from mesh (or patch) point to index in procPoints
         Map<label> meshToProcPoint_;
 
         //- Shared points used by this processor (= global point number)
         labelList sharedPointAddr_;
 
-        //- My meshpoints corresponding to the shared points
+        //- My mesh(or patch) points corresponding to the shared points
         labelList sharedPointLabels_;
 
         //- Total number of shared points.
@@ -155,56 +156,108 @@ class globalPoints
         //  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
         (
             const primitivePatch&,
             const label patchPointI,
-            const procPointList&,
+            const labelList&,
             DynamicList<label>& patchFaces,
             DynamicList<label>& indexInFace,
-            DynamicList<procPointList>& allInfo
+            DynamicList<labelList>& allInfo
         );
 
         //- Merge info from neighbour into my data
         static bool mergeInfo
         (
-            const procPointList& nbrInfo,
-            procPointList& myInfo
+            const labelList& nbrInfo,
+            labelList& myInfo
+        );
+
+        //- From mesh point to 'local point'. Is the mesh point itself
+        //  if meshToPatchPoint is empty.
+        static label meshToLocalPoint
+        (
+            const Map<label>& meshToPatchPoint,
+            const label meshPointI
+        );
+
+        //- Opposite of meshToLocalPoint.
+        static label localToMeshPoint
+        (
+            const labelList& patchToMeshPoint,
+            const label localPointI
         );
 
         //- Store (and merge) info for meshPointI
-        bool storeInfo(const procPointList& nbrInfo, const label meshPointI);
+        bool storeInfo
+        (
+            const labelList& nbrInfo,
+            const label localPointI
+        );
 
         //- Initialize procPoints_ to my patch points. allPoints = true:
         //  seed with all patch points, = false: only boundaryPoints().
-        void initOwnPoints(const bool allPoints, labelHashSet& changedPoints);
+        void initOwnPoints
+        (
+            const Map<label>& meshToPatchPoint,
+            const bool allPoints,
+            labelHashSet& changedPoints
+        );
 
         //- Send subset of procPoints to neighbours
-        void sendPatchPoints(const labelHashSet& changedPoints) const;
+        void sendPatchPoints
+        (
+            const Map<label>&,
+            PstreamBuffers&,
+            const labelHashSet&
+        ) const;
 
         //- Receive neighbour points and merge into my procPoints.
-        void receivePatchPoints(labelHashSet& changedPoints);
+        void receivePatchPoints
+        (
+            const Map<label>&,
+            PstreamBuffers&,
+            labelHashSet&
+        );
 
         //- Remove entries of size 2 where meshPoint is in provided Map.
         //  Used to remove normal face-face connected points.
-        void remove(const Map<label>&);
+        void remove(const labelList& patchToMeshPoint, const Map<label>&);
+
+        //- Compact out unused elements of procPoints.
+        void compact();
 
         //- Get indices of point for which I am master (lowest numbered proc)
-        labelList getMasterPoints() const;
+        labelList getMasterPoints(const labelList& patchToMeshPoint) const;
 
         //- Send subset of shared points to neighbours
-        void sendSharedPoints(const labelList& changedIndices) const;
+        void sendSharedPoints(PstreamBuffers&, const labelList&) const;
 
         //- Receive shared points and update subset.
-        void receiveSharedPoints(labelList& changedIndices);
-
+        void receiveSharedPoints
+        (
+            const Map<label>&,
+            PstreamBuffers&,
+            labelList&
+        );
 
-        //- Should move into cyclicPolyPatch but some ordering problem
+        //- Should move into cyclicPolyPatch ordering problem
         //  keeps on giving problems.
         static edgeList coupledPoints(const cyclicPolyPatch&);
 
+        //- Do all calculations.
+        void calculateSharedPoints
+        (
+            const Map<label>&,
+            const labelList&,
+            const bool keepAllPoints
+        );
+
         //- Disallow default bitwise copy construct
         globalPoints(const globalPoints&);
 
@@ -220,22 +273,44 @@ public:
 
     // Constructors
 
-        //- Construct from mesh
-        globalPoints(const polyMesh& mesh);
+        //- 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);
+
+        //- Construct from mesh and patch of coupled faces. Difference with
+        //  construct from mesh only is that this stores the meshToProcPoint,
+        //  procPoints and sharedPointLabels as patch local point labels
+        //  instead of mesh point labels.
+        globalPoints
+        (
+            const polyMesh& mesh,
+            const indirectPrimitivePatch& coupledPatch,
+            const bool keepAllPoints
+        );
 
 
     // Member Functions
 
         // Access
 
-            label nPatchPoints() const
+            //- From (mesh or patch) point to index in procPoints
+            const Map<label>& meshToProcPoint() const
             {
-                return nPatchPoints_;
+                return meshToProcPoint_;
             }
 
-            const Map<label>& meshToProcPoint() const
+            //- procPoints is per point the connected points (in global
+            //  point numbers)
+            const DynamicList<labelList>& procPoints() const
             {
-                return meshToProcPoint_;
+                return procPoints_;
+            }
+
+            //- Global numbering of (mesh or patch) points
+            const globalIndex& globalIndices() const
+            {
+                return globalIndices_;
             }
 
             //- shared points used by this processor (= global point number)
@@ -244,12 +319,13 @@ public:
                 return sharedPointAddr_;
             }
 
-            //- my meshpoints corresponding to the shared points
+            //- my (mesh or patch)points corresponding to the shared points
             const labelList& sharedPointLabels() const
             {
                 return sharedPointLabels_;
             }
 
+            //- total number of shared points
             label nGlobalPoints() const
             {
                 return nGlobalPoints_;
-- 
GitLab