Newer
Older
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "globalMeshData.H"
#include "Time.H"
#include "Pstream.H"
#include "PstreamCombineReduceOps.H"
#include "processorPolyPatch.H"
#include "demandDrivenData.H"
#include "globalPoints.H"
#include "polyMesh.H"
#include "mapDistribute.H"
#include "labelIOList.H"
#include "PackedList.H"
#include "mergePoints.H"
#include "matchPoints.H"
#include "OFstream.H"
#include "globalIndexAndTransform.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(globalMeshData, 0);
// Geometric matching tolerance. Factor of mesh bounding box.
const scalar globalMeshData::matchTol_ = 1e-8;
template<>
class minEqOp<labelPair>
{
public:
void operator()(labelPair& x, const labelPair& y) const
{
x[0] = min(x[0], y[0]);
x[1] = min(x[1], y[1]);
}
};
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// Collect processor patch addressing.
void Foam::globalMeshData::initProcAddr()
{
processorPatchIndices_.setSize(mesh_.boundaryMesh().size());
processorPatchIndices_ = -1;
processorPatchNeighbours_.setSize(mesh_.boundaryMesh().size());
processorPatchNeighbours_ = -1;
// Construct processor patch indexing. processorPatchNeighbours_ only
// set if running in parallel!
processorPatches_.setSize(mesh_.boundaryMesh().size());
label nNeighbours = 0;
forAll(mesh_.boundaryMesh(), patchi)
{
if (isA<processorPolyPatch>(mesh_.boundaryMesh()[patchi]))
{
processorPatches_[nNeighbours] = patchi;
processorPatchIndices_[patchi] = nNeighbours++;
}
}
processorPatches_.setSize(nNeighbours);
if (Pstream::parRun())
{
PstreamBuffers pBufs(Pstream::nonBlocking);
// Send indices of my processor patches to my neighbours
forAll(processorPatches_, i)
{
label patchi = processorPatches_[i];
(
refCast<const processorPolyPatch>
(
mesh_.boundaryMesh()[patchi]
);
toNeighbour << processorPatchIndices_[patchi];
}
forAll(processorPatches_, i)
{
label patchi = processorPatches_[i];
(
refCast<const processorPolyPatch>
(
mesh_.boundaryMesh()[patchi]
fromNeighbour >> processorPatchNeighbours_[patchi];
}
}
}
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
void Foam::globalMeshData::calcSharedPoints() const
{
if
(
nGlobalPoints_ != -1
|| sharedPointLabelsPtr_.valid()
|| sharedPointAddrPtr_.valid()
)
{
FatalErrorIn("globalMeshData::calcSharedPoints()")
<< "Shared point addressing already done" << abort(FatalError);
}
// Calculate all shared points (exclude points that are only
// on two coupled patches). This does all the hard work.
globalPoints parallelPoints(mesh_, false, true);
// Count the number of master points
label nMaster = 0;
forAll(parallelPoints.pointPoints(), i)
{
const labelList& pPoints = parallelPoints.pointPoints()[i];
const labelList& transPPoints =
parallelPoints.transformedPointPoints()[i];
if (pPoints.size()+transPPoints.size() > 0)
{
nMaster++;
}
}
// Allocate global numbers
globalIndex masterNumbering(nMaster);
nGlobalPoints_ = masterNumbering.size();
// Push master number to slaves
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 1. Fill master and slave slots
nMaster = 0;
labelList master(parallelPoints.map().constructSize(), -1);
forAll(parallelPoints.pointPoints(), i)
{
const labelList& pPoints = parallelPoints.pointPoints()[i];
const labelList& transPPoints =
parallelPoints.transformedPointPoints()[i];
if (pPoints.size()+transPPoints.size() > 0)
{
master[i] = masterNumbering.toGlobal(nMaster);
forAll(pPoints, j)
{
master[pPoints[j]] = master[i];
}
forAll(transPPoints, j)
{
master[transPPoints[j]] = master[i];
}
nMaster++;
}
}
// 2. Push slave slots back to local storage on originating processor
// For all the four types of points:
// - local master : already set
// - local transformed slave point : the reverse transform at
// reverseDistribute will have copied it back to its originating local
// point
// - remote untransformed slave point : sent back to originating processor
// - remote transformed slave point : the reverse transform will
// copy it back into the remote slot which then gets sent back to
// originating processor
parallelPoints.map().reverseDistribute
(
parallelPoints.map().constructSize(),
master
);
// Collect all points that are a master or refer to a master.
nMaster = 0;
forAll(parallelPoints.pointPoints(), i)
{
if (master[i] != -1)
{
nMaster++;
}
}
sharedPointLabelsPtr_.reset(new labelList(nMaster));
labelList& sharedPointLabels = sharedPointLabelsPtr_();
sharedPointAddrPtr_.reset(new labelList(nMaster));
labelList& sharedPointAddr = sharedPointAddrPtr_();
nMaster = 0;
forAll(parallelPoints.pointPoints(), i)
{
if (master[i] != -1)
{
// I am master or slave
sharedPointLabels[nMaster] = i;
sharedPointAddr[nMaster] = master[i];
nMaster++;
}
}
if (debug)
{
Pout<< "globalMeshData : nGlobalPoints_:" << nGlobalPoints_ << nl
<< "globalMeshData : sharedPointLabels_:"
<< sharedPointLabelsPtr_().size() << nl
<< "globalMeshData : sharedPointAddr_:"
<< sharedPointAddrPtr_().size() << endl;
}
}
// Given information about locally used edges allocate global shared edges.
void Foam::globalMeshData::countSharedEdges
(
const EdgeMap<labelList>& procSharedEdges,
EdgeMap<label>& globalShared,
label& sharedEdgeI
)
{
// Count occurrences of procSharedEdges in global shared edges table.
forAllConstIter(EdgeMap<labelList>, procSharedEdges, iter)
{
const edge& e = iter.key();
EdgeMap<label>::iterator globalFnd = globalShared.find(e);
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
if (globalFnd == globalShared.end())
{
// First time occurrence of this edge. Check how many we are adding.
if (iter().size() == 1)
{
// Only one edge. Mark with special value.
globalShared.insert(e, -1);
}
else
{
// Edge used more than once (even by local shared edges alone)
// so allocate proper shared edge label.
globalShared.insert(e, sharedEdgeI++);
}
}
else
{
if (globalFnd() == -1)
{
// Second time occurence of this edge. Assign proper
// edge label.
globalFnd() = sharedEdgeI++;
}
}
}
}
// Shared edges are shared between multiple processors. By their nature both
// of their endpoints are shared points. (but not all edges using two shared
// points are shared edges! There might e.g. be an edge between two unrelated
// clusters of shared points)
void Foam::globalMeshData::calcSharedEdges() const
{
if
(
nGlobalEdges_ != -1
|| sharedEdgeLabelsPtr_.valid()
|| sharedEdgeAddrPtr_.valid()
)
{
FatalErrorIn("globalMeshData::calcSharedEdges()")
<< "Shared edge addressing already done" << abort(FatalError);
}
const labelList& sharedPtAddr = sharedPointAddr();
const labelList& sharedPtLabels = sharedPointLabels();
// Since don't want to construct pointEdges for whole mesh create
// Map for all shared points.
Map<label> meshToShared(2*sharedPtLabels.size());
forAll(sharedPtLabels, i)
{
meshToShared.insert(sharedPtLabels[i], i);
}
// 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)
EdgeMap<labelList> localShared(2*sharedPtAddr.size());
const edgeList& edges = mesh_.edges();
forAll(edges, edgeI)
{
const edge& e = edges[edgeI];
Map<label>::const_iterator e0Fnd = meshToShared.find(e[0]);
if (e0Fnd != meshToShared.end())
{
Map<label>::const_iterator e1Fnd = meshToShared.find(e[1]);
if (e1Fnd != meshToShared.end())
{
// Found edge which uses shared points. Probably shared.
// Construct the edge in shared points (or rather global indices
// of the shared points)
edge sharedEdge
(
sharedPtAddr[e0Fnd()],
sharedPtAddr[e1Fnd()]
);
EdgeMap<labelList>::iterator iter =
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
localShared.find(sharedEdge);
if (iter == localShared.end())
{
// First occurrence of this point combination. Store.
localShared.insert(sharedEdge, labelList(1, edgeI));
}
else
{
// Add this edge to list of edge labels.
labelList& edgeLabels = iter();
label sz = edgeLabels.size();
edgeLabels.setSize(sz+1);
edgeLabels[sz] = edgeI;
}
}
}
}
// Now we have a table on every processors which gives its edges which use
// shared points. Send this all to the master and have it allocate
// global edge numbers for it. But only allocate a global edge number for
// edge if it is used more than once!
// Note that we are now sending the whole localShared to the master whereas
// we only need the local count (i.e. the number of times a global edge is
// used). But then this only gets done once so not too bothered about the
// extra global communication.
EdgeMap<label> globalShared(nGlobalPoints());
if (Pstream::master())
{
label sharedEdgeI = 0;
// Merge my shared edges into the global list
if (debug)
{
Pout<< "globalMeshData::calcSharedEdges : Merging in from proc0 : "
<< localShared.size() << endl;
}
countSharedEdges(localShared, globalShared, sharedEdgeI);
// Receive data from slaves and insert
if (Pstream::parRun())
{
for
(
int slave=Pstream::firstSlave();
slave<=Pstream::lastSlave();
slave++
)
{
// Receive the edges using shared points from the slave.
IPstream fromSlave(Pstream::blocking, slave);
EdgeMap<labelList> procSharedEdges(fromSlave);
if (debug)
{
Pout<< "globalMeshData::calcSharedEdges : "
<< "Merging in from proc"
<< Foam::name(slave) << " : " << procSharedEdges.size()
<< endl;
}
countSharedEdges(procSharedEdges, globalShared, sharedEdgeI);
}
}
// Now our globalShared should have some edges with -1 as edge label
// These were only used once so are not proper shared edges.
// Remove them.
{
EdgeMap<label> oldSharedEdges(globalShared);
globalShared.clear();
forAllConstIter(EdgeMap<label>, oldSharedEdges, iter)
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
{
if (iter() != -1)
{
globalShared.insert(iter.key(), iter());
}
}
if (debug)
{
Pout<< "globalMeshData::calcSharedEdges : Filtered "
<< oldSharedEdges.size()
<< " down to " << globalShared.size() << endl;
}
}
// Send back to slaves.
if (Pstream::parRun())
{
for
(
int slave=Pstream::firstSlave();
slave<=Pstream::lastSlave();
slave++
)
{
// Receive the edges using shared points from the slave.
OPstream toSlave(Pstream::blocking, slave);
toSlave << globalShared;
}
}
}
else
{
// Send local edges to master
{
OPstream toMaster(Pstream::blocking, Pstream::masterNo());
toMaster << localShared;
}
// Receive merged edges from master.
{
IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
fromMaster >> globalShared;
}
}
// Now use the global shared edges list (globalShared) to classify my local
// ones (localShared)
nGlobalEdges_ = globalShared.size();
DynamicList<label> dynSharedEdgeLabels(globalShared.size());
DynamicList<label> dynSharedEdgeAddr(globalShared.size());
forAllConstIter(EdgeMap<labelList>, localShared, iter)
{
const edge& e = iter.key();
EdgeMap<label>::const_iterator edgeFnd = globalShared.find(e);
if (edgeFnd != globalShared.end())
{
// My local edge is indeed a shared one. Go through all local edge
// labels with this point combination.
const labelList& edgeLabels = iter();
forAll(edgeLabels, i)
{
// Store label of local mesh edge
dynSharedEdgeLabels.append(edgeLabels[i]);
// Store label of shared edge
dynSharedEdgeAddr.append(edgeFnd());
}
}
}
sharedEdgeLabelsPtr_.reset(new labelList());
labelList& sharedEdgeLabels = sharedEdgeLabelsPtr_();
sharedEdgeLabels.transfer(dynSharedEdgeLabels);
sharedEdgeAddrPtr_.reset(new labelList());
labelList& sharedEdgeAddr = sharedEdgeAddrPtr_();
sharedEdgeAddr.transfer(dynSharedEdgeAddr);
if (debug)
{
Pout<< "globalMeshData : nGlobalEdges_:" << nGlobalEdges_ << nl
<< "globalMeshData : sharedEdgeLabels:" << sharedEdgeLabels.size()
<< nl
<< "globalMeshData : sharedEdgeAddr:" << sharedEdgeAddr.size()
<< endl;
}
}
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, true);
globalPointSlavesPtr_.reset
new labelListList
(
globalData.pointPoints().xfer()
)
globalPointTransformedSlavesPtr_.reset
new labelListList
globalData.transformedPointPoints().xfer()
);
globalPointSlavesMapPtr_.reset
(
new mapDistribute
(
globalData.map().xfer()
void Foam::globalMeshData::calcPointConnectivity
(
List<labelPairList>& allPointConnectivity
) const
const globalIndexAndTransform& transforms = globalTransforms();
const labelListList& slaves = globalPointSlaves();
const labelListList& transformedSlaves = globalPointTransformedSlaves();
// Create field with my local data
labelPairList myData(globalPointSlavesMap().constructSize());
forAll(slaves, pointI)
myData[pointI] = globalIndexAndTransform::encode
(
Pstream::myProcNo(),
pointI,
transforms.nullTransformIndex()
);
// Send over.
globalPointSlavesMap().distribute(myData);
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
// String of connected points with their transform
allPointConnectivity.setSize(globalPointSlavesMap().constructSize());
forAll(slaves, pointI)
{
// Reconstruct string of connected points
const labelList& pSlaves = slaves[pointI];
const labelList& pTransformSlaves = transformedSlaves[pointI];
labelPairList& pConnectivity = allPointConnectivity[pointI];
pConnectivity.setSize(1+pSlaves.size()+pTransformSlaves.size());
label connI = 0;
// Add myself
pConnectivity[connI++] = myData[pointI];
// Add untransformed points
forAll(pSlaves, i)
{
pConnectivity[connI++] = myData[pSlaves[i]];
}
// Add transformed points.
forAll(pTransformSlaves, i)
{
// Get transform from index
label transformI = globalPointSlavesMap().whichTransform
(
pTransformSlaves[i]
);
// Add transform to connectivity
const labelPair& n = myData[pTransformSlaves[i]];
label procI = globalIndexAndTransform::processor(n);
label index = globalIndexAndTransform::index(n);
pConnectivity[connI++] = globalIndexAndTransform::encode
(
procI,
index,
transformI
);
}
// Put back in slots
forAll(pSlaves, i)
{
allPointConnectivity[pSlaves[i]] = pConnectivity;
}
forAll(pTransformSlaves, i)
{
allPointConnectivity[pTransformSlaves[i]] = pConnectivity;
}
}
globalPointSlavesMap().reverseDistribute
(
allPointConnectivity.size(),
allPointConnectivity
);
}
void Foam::globalMeshData::calcGlobalPointEdges
(
labelListList& globalPointEdges,
List<labelPairList>& globalPointPoints
) const
{
const edgeList& edges = coupledPatch().edges();
const labelListList& pointEdges = coupledPatch().pointEdges();
const globalIndex& globalEdgeNumbers = globalEdgeNumbering();
const labelListList& slaves = globalPointSlaves();
const labelListList& transformedSlaves = globalPointTransformedSlaves();
// Create local version
globalPointEdges.setSize(globalPointSlavesMap().constructSize());
globalPointPoints.setSize(globalPointSlavesMap().constructSize());
forAll(pointEdges, pointI)
{
const labelList& pEdges = pointEdges[pointI];
labelList& globalPEdges = globalPointEdges[pointI];
globalPEdges.setSize(pEdges.size());
forAll(pEdges, i)
{
globalPEdges[i] = globalEdgeNumbers.toGlobal(pEdges[i]);
labelPairList& globalPPoints = globalPointPoints[pointI];
globalPPoints.setSize(pEdges.size());
forAll(pEdges, i)
{
label otherPointI = edges[pEdges[i]].otherVertex(pointI);
globalPPoints[i] = globalIndexAndTransform::encode
(
Pstream::myProcNo(),
otherPointI,
globalTransforms().nullTransformIndex()
);
}
// Pull slave data to master. Dummy transform.
globalPointSlavesMap().distribute(globalPointEdges);
globalPointSlavesMap().distribute(globalPointPoints);
// Add all pointEdges
forAll(slaves, pointI)
{
const labelList& pSlaves = slaves[pointI];
const labelList& pTransformSlaves = transformedSlaves[pointI];
label n = 0;
forAll(pSlaves, i)
{
n += globalPointEdges[pSlaves[i]].size();
}
forAll(pTransformSlaves, i)
{
n += globalPointEdges[pTransformSlaves[i]].size();
}
// Add all the point edges of the slaves to those of the (master) point
{
labelList& globalPEdges = globalPointEdges[pointI];
label sz = globalPEdges.size();
globalPEdges.setSize(sz+n);
forAll(pSlaves, i)
{
const labelList& otherData = globalPointEdges[pSlaves[i]];
forAll(otherData, j)
{
globalPEdges[sz++] = otherData[j];
}
}
forAll(pTransformSlaves, i)
{
const labelList& otherData =
globalPointEdges[pTransformSlaves[i]];
forAll(otherData, j)
{
globalPEdges[sz++] = otherData[j];
}
}
// Put back in slots
forAll(pSlaves, i)
{
globalPointEdges[pSlaves[i]] = globalPEdges;
}
forAll(pTransformSlaves, i)
{
globalPointEdges[pTransformSlaves[i]] = globalPEdges;
}
}
// Same for corresponding pointPoints
labelPairList& globalPPoints = globalPointPoints[pointI];
label sz = globalPPoints.size();
globalPPoints.setSize(sz + n);
// Add untransformed points
forAll(pSlaves, i)
const labelPairList& otherData = globalPointPoints[pSlaves[i]];
forAll(otherData, j)
globalPPoints[sz++] = otherData[j];
// Add transformed points.
forAll(pTransformSlaves, i)
// Get transform from index
label transformI = globalPointSlavesMap().whichTransform
(
pTransformSlaves[i]
);
const labelPairList& otherData =
globalPointPoints[pTransformSlaves[i]];
forAll(otherData, j)
{
// Add transform to connectivity
const labelPair& n = otherData[j];
label procI = globalIndexAndTransform::processor(n);
label index = globalIndexAndTransform::index(n);
globalPPoints[sz++] = globalIndexAndTransform::encode
(
procI,
index,
transformI
);
// Put back in slots
forAll(pSlaves, i)
{
globalPointPoints[pSlaves[i]] = globalPPoints;
}
forAll(pTransformSlaves, i)
{
globalPointPoints[pTransformSlaves[i]] = globalPPoints;
}
}
// Push back
globalPointSlavesMap().reverseDistribute
(
globalPointEdges.size(),
globalPointEdges
);
// Push back
globalPointSlavesMap().reverseDistribute
(
globalPointPoints.size(),
globalPointPoints
);
}
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
// Find transformation to take remotePoint to localPoint. Use info to find
// the transforms.
Foam::label Foam::globalMeshData::findTransform
(
const labelPairList& info,
const labelPair& remotePoint,
const label localPoint
) const
{
const label remoteProcI = globalIndexAndTransform::processor(remotePoint);
const label remoteIndex = globalIndexAndTransform::index(remotePoint);
label remoteTransformI = -1;
label localTransformI = -1;
forAll(info, i)
{
label procI = globalIndexAndTransform::processor(info[i]);
label pointI = globalIndexAndTransform::index(info[i]);
label transformI = globalIndexAndTransform::transformIndex(info[i]);
if (procI == Pstream::myProcNo() && pointI == localPoint)
{
localTransformI = transformI;
//Pout<< "For local :" << localPoint
// << " found transform:" << localTransformI
// << endl;
}
if (procI == remoteProcI && pointI == remoteIndex)
remoteTransformI = transformI;
//Pout<< "For remote:" << remotePoint
// << " found transform:" << remoteTransformI
// << " at index:" << i
// << endl;
}
}
if (remoteTransformI == -1 || localTransformI == -1)
{
FatalErrorIn("globalMeshData::findTransform(..)")
<< "Problem. Cannot find " << remotePoint
<< " or " << localPoint << " "
<< coupledPatch().localPoints()[localPoint]
<< " in " << info
<< endl
<< "remoteTransformI:" << remoteTransformI << endl
<< "localTransformI:" << localTransformI
<< abort(FatalError);
}
return globalTransforms().subtractTransformIndex
(
remoteTransformI,
localTransformI
);
}
void Foam::globalMeshData::calcGlobalEdgeSlaves() const
{
if (debug)
{
Pout<< "globalMeshData::calcGlobalEdgeSlaves() :"
<< " calculating coupled master to slave edge addressing." << endl;
}
const edgeList& edges = coupledPatch().edges();
const globalIndex& globalEdgeNumbers = globalEdgeNumbering();
// The whole problem with deducting edge-connectivity from
// point-connectivity is that one of the the endpoints might be
// a local master but the other endpoint might not. So we first
// need to make sure that all points know about connectivity and
// the transformations.
// 1. collect point connectivity - basically recreating globalPoints output.
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
// All points will now have a string of points. The transforms are
// in respect to the master.
List<labelPairList> allPointConnectivity;
calcPointConnectivity(allPointConnectivity);
// 2. Get all pointEdges and pointPoints
// Coupled point to global coupled edges and corresponding endpoint.
labelListList globalPointEdges;
List<labelPairList> globalPointPoints;
calcGlobalPointEdges(globalPointEdges, globalPointPoints);
// 3. Now all points have
// - all the connected points with original transform
// - all the connected global edges
// Now all we need to do is go through all the edges and check
// both endpoints. If there is a edge between the two which is
// produced by transforming both points in the same way it is a shared
// edge.
// Collect strings of connected edges.
List<labelPairList> allEdgeConnectivity(edges.size());
forAll(edges, edgeI)
{
const edge& e = edges[edgeI];
const labelList& pEdges0 = globalPointEdges[e[0]];
const labelPairList& pPoints0 = globalPointPoints[e[0]];
const labelList& pEdges1 = globalPointEdges[e[1]];
const labelPairList& pPoints1 = globalPointPoints[e[1]];
// Most edges will be size 2
DynamicList<labelPair> eEdges(2);
// Append myself.
eEdges.append
(
globalIndexAndTransform::encode
(
Pstream::myProcNo(),
edgeI,
globalTransforms().nullTransformIndex()
)
);
forAll(pEdges0, i)
{
forAll(pEdges1, j)
if
(
pEdges0[i] == pEdges1[j]
&& pEdges0[i] != globalEdgeNumbers.toGlobal(edgeI)
)
// Found a shared edge. Now check if the endpoints
// go through the same transformation.
// Local: e[0] remote:pPoints1[j]
// Local: e[1] remote:pPoints0[i]
// Find difference in transforms to go from point on remote
// edge (pPoints1[j]) to this point.
label transform0 = findTransform
(
allPointConnectivity[e[0]],
pPoints1[j],
e[0]
);
label transform1 = findTransform
(
allPointConnectivity[e[1]],
pPoints0[i],
e[1]
);
if (transform0 == transform1)
{
label procI = globalEdgeNumbers.whichProcID(pEdges0[i]);
eEdges.append
(
globalIndexAndTransform::encode
(
procI,
globalEdgeNumbers.toLocal(procI, pEdges0[i]),
transform0
)
);
}
}
}
}
allEdgeConnectivity[edgeI].transfer(eEdges);
sort(allEdgeConnectivity[edgeI], globalIndexAndTransform::less());
}
// We now have - in allEdgeConnectivity - a list of edges which are shared
// between multiple processors. Filter into non-transformed and transformed
// connections.
globalEdgeSlavesPtr_.reset(new labelListList(edges.size()));
labelListList& globalEdgeSlaves = globalEdgeSlavesPtr_();
List<labelPairList> transformedEdges(edges.size());
forAll(allEdgeConnectivity, edgeI)
{
const labelPairList& edgeInfo = allEdgeConnectivity[edgeI];
if (edgeInfo.size() >= 2)
{
const labelPair& masterInfo = edgeInfo[0];
// Check if master edge (= first element (since sorted)) is me.