globalMeshData.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2024 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "globalMeshData.H"
30 #include "globalPoints.H"
31 #include "polyMesh.H"
32 #include "mapDistribute.H"
33 #include "labelIOList.H"
34 #include "mergePoints.H"
35 #include "processorPolyPatch.H"
36 #include "processorTopologyNew.H"
38 #include "ListOps.H"
39 #include "Pstream.H"
40 
41 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42 
43 namespace Foam
44 {
45 defineTypeNameAndDebug(globalMeshData, 0);
46 
47 const scalar globalMeshData::matchTol_ = 1e-8;
48 
49 template<>
50 class minEqOp<labelPair>
51 {
52 public:
53  void operator()(labelPair& x, const labelPair& y) const
54  {
55  x[0] = min(x[0], y[0]);
56  x[1] = min(x[1], y[1]);
57  }
58 };
59 }
60 
61 
62 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
63 
64 void Foam::globalMeshData::initProcAddr()
65 {
66  processorPatchIndices_.resize_nocopy(mesh_.boundaryMesh().size());
67  processorPatchIndices_ = -1;
68 
69  processorPatchNeighbours_.resize_nocopy(mesh_.boundaryMesh().size());
70  processorPatchNeighbours_ = -1;
71 
72  // Construct processor patch indexing. processorPatchNeighbours_ only
73  // set if running in parallel!
74  processorPatches_.resize_nocopy(mesh_.boundaryMesh().size());
75 
76  label nNeighbours = 0;
77 
78  forAll(mesh_.boundaryMesh(), patchi)
79  {
80  if (isA<processorPolyPatch>(mesh_.boundaryMesh()[patchi]))
81  {
82  processorPatches_[nNeighbours] = patchi;
83  processorPatchIndices_[patchi] = nNeighbours++;
84  }
85  }
86  processorPatches_.resize(nNeighbours);
87 
88 
89  if (UPstream::parRun())
90  {
91  // Allocate unique tag for all comms
92  const int oldTag = UPstream::incrMsgType();
93 
94  PstreamBuffers pBufs(mesh_.comm());
95 
96  // Send indices of my processor patches to my neighbours
97  for (const label patchi : processorPatches_)
98  {
99  UOPstream toNeighbour
100  (
101  refCast<const processorPolyPatch>
102  (
103  mesh_.boundaryMesh()[patchi]
104  ).neighbProcNo(),
105  pBufs
106  );
107 
108  toNeighbour << processorPatchIndices_[patchi];
109  }
110 
111  pBufs.finishedSends();
112 
113  for (const label patchi : processorPatches_)
114  {
115  UIPstream fromNeighbour
116  (
117  refCast<const processorPolyPatch>
118  (
119  mesh_.boundaryMesh()[patchi]
120  ).neighbProcNo(),
121  pBufs
122  );
123 
124  fromNeighbour >> processorPatchNeighbours_[patchi];
125  }
126 
127  // Reset tag
128  UPstream::msgType(oldTag);
129  }
130 }
131 
132 
133 void Foam::globalMeshData::calcSharedPoints() const
134 {
135  if
136  (
137  nGlobalPoints_ != -1
138  || sharedPointLabelsPtr_
139  || sharedPointAddrPtr_
140  )
141  {
143  << "Shared point addressing already done" << abort(FatalError);
144  }
145 
146  // Allocate unique tag for all comms
147  const int oldTag = UPstream::incrMsgType();
148 
149  // Calculate all shared points (exclude points that are only
150  // on two coupled patches). This does all the hard work.
151  const globalPoints parallelPoints(mesh_, false, true);
152 
153  // Count the number of master points
154  label nMaster = 0;
155  forAll(parallelPoints.pointPoints(), i)
156  {
157  const labelList& pPoints = parallelPoints.pointPoints()[i];
158  const labelList& transPPoints =
159  parallelPoints.transformedPointPoints()[i];
160 
161  if (pPoints.size()+transPPoints.size() > 0)
162  {
163  nMaster++;
164  }
165  }
166 
167  // Allocate global numbers
168  const globalIndex masterNumbering(nMaster);
169 
170  nGlobalPoints_ = masterNumbering.totalSize();
171 
172 
173  // Push master number to slaves
174  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
175  // 1. Fill master and slave slots
176  nMaster = 0;
177  labelList master(parallelPoints.map().constructSize(), -1);
178  forAll(parallelPoints.pointPoints(), i)
179  {
180  const labelList& pPoints = parallelPoints.pointPoints()[i];
181  const labelList& transPPoints =
182  parallelPoints.transformedPointPoints()[i];
183 
184  if (pPoints.size()+transPPoints.size() > 0)
185  {
186  master[i] = masterNumbering.toGlobal(nMaster);
187 
188  labelUIndList(master, pPoints) = master[i];
189  labelUIndList(master, transPPoints) = master[i];
190 
191  ++nMaster;
192  }
193  }
194 
195 
196  // 2. Push slave slots back to local storage on originating processor
197  // For all the four types of points:
198  // - local master : already set
199  // - local transformed slave point : the reverse transform at
200  // reverseDistribute will have copied it back to its originating local
201  // point
202  // - remote untransformed slave point : sent back to originating processor
203  // - remote transformed slave point : the reverse transform will
204  // copy it back into the remote slot which then gets sent back to
205  // originating processor
206 
207  parallelPoints.map().reverseDistribute
208  (
209  parallelPoints.map().constructSize(),
210  master
211  );
212 
213 
214  // Collect all points that are a master or refer to a master.
215  nMaster = 0;
216  forAll(parallelPoints.pointPoints(), i)
217  {
218  if (master[i] != -1)
219  {
220  nMaster++;
221  }
222  }
223 
224  sharedPointLabelsPtr_.reset(new labelList(nMaster));
225  labelList& sharedPointLabels = sharedPointLabelsPtr_();
226  sharedPointAddrPtr_.reset(new labelList(nMaster));
227  labelList& sharedPointAddr = sharedPointAddrPtr_();
228  nMaster = 0;
229 
230  forAll(parallelPoints.pointPoints(), i)
231  {
232  if (master[i] != -1)
233  {
234  // I am master or slave
235  sharedPointLabels[nMaster] = i;
236  sharedPointAddr[nMaster] = master[i];
237  nMaster++;
238  }
239  }
240 
241  // Reset tag
242  UPstream::msgType(oldTag);
243 
244  if (debug)
245  {
246  Pout<< "globalMeshData : nGlobalPoints_:" << nGlobalPoints_ << nl
247  << "globalMeshData : sharedPointLabels_:"
248  << sharedPointLabelsPtr_().size() << nl
249  << "globalMeshData : sharedPointAddr_:"
250  << sharedPointAddrPtr_().size() << endl;
251  }
252 }
253 
254 
255 void Foam::globalMeshData::countSharedEdges
256 (
257  const EdgeMap<labelList>& procSharedEdges,
258  EdgeMap<label>& globalShared,
259  label& sharedEdgeI
260 )
261 {
262  // Count occurrences of procSharedEdges in global shared edges table.
263  forAllConstIters(procSharedEdges, iter)
264  {
265  const edge& e = iter.key();
266 
267  auto globalFnd = globalShared.find(e);
268 
269  if (globalFnd.good())
270  {
271  if (globalFnd() == -1)
272  {
273  // Second time occurrence of this edge.
274  // Assign proper edge label.
275  globalFnd() = sharedEdgeI++;
276  }
277  }
278  else
279  {
280  // First time occurrence of this edge. Check how many we are adding.
281  if (iter().size() == 1)
282  {
283  // Only one edge. Mark with special value.
284  globalShared.insert(e, -1);
285  }
286  else
287  {
288  // Edge used more than once (even by local shared edges alone)
289  // so allocate proper shared edge label.
290  globalShared.insert(e, sharedEdgeI++);
291  }
292  }
293  }
294 }
295 
296 
297 void Foam::globalMeshData::calcSharedEdges() const
298 {
299  // Shared edges are shared between multiple processors. By their nature both
300  // of their endpoints are shared points. (but not all edges using two shared
301  // points are shared edges! There might e.g. be an edge between two
302  // unrelated clusters of shared points)
303 
304  if
305  (
306  nGlobalEdges_ != -1
307  || sharedEdgeLabelsPtr_
308  || sharedEdgeAddrPtr_
309  )
310  {
312  << "Shared edge addressing already done" << abort(FatalError);
313  }
314 
315 
316  const labelList& sharedPtAddr = sharedPointAddr();
317  const labelList& sharedPtLabels = sharedPointLabels();
318 
319  // Since don't want to construct pointEdges for whole mesh create
320  // Map for all shared points.
321  Map<label> meshToShared(invertToMap(sharedPtLabels));
322 
323 
324  // Find edges using shared points. Store correspondence to local edge
325  // numbering. Note that multiple local edges can have the same shared
326  // points! (for cyclics or separated processor patches)
327  EdgeMap<labelList> localShared(2*sharedPtAddr.size());
328 
329  const edgeList& edges = mesh_.edges();
330 
331  forAll(edges, edgei)
332  {
333  const edge& e = edges[edgei];
334 
335  const auto e0Fnd = meshToShared.cfind(e[0]);
336 
337  if (e0Fnd.good())
338  {
339  const auto e1Fnd = meshToShared.cfind(e[1]);
340 
341  if (e1Fnd.good())
342  {
343  // Found edge which uses shared points. Probably shared.
344 
345  // Construct the edge in shared points (or rather global indices
346  // of the shared points)
347  edge sharedEdge
348  (
349  sharedPtAddr[e0Fnd.val()],
350  sharedPtAddr[e1Fnd.val()]
351  );
352 
353  // Add this edge to list of edge labels
354  localShared(sharedEdge).push_back(edgei);
355  }
356  }
357  }
358 
359 
360  // Now we have a table on every processors which gives its edges which use
361  // shared points. Send this all to the master and have it allocate
362  // global edge numbers for it. But only allocate a global edge number for
363  // edge if it is used more than once!
364  // Note that we are now sending the whole localShared to the master whereas
365  // we only need the local count (i.e. the number of times a global edge is
366  // used). But then this only gets done once so not too bothered about the
367  // extra global communication.
368 
369  EdgeMap<label> globalShared(2*nGlobalPoints());
370 
371  // Allocate unique tag for all comms
372  const int oldTag = UPstream::incrMsgType();
373 
374  if (UPstream::master())
375  {
376  label sharedEdgeI = 0;
377 
378  // Merge my shared edges into the global list
379  if (debug)
380  {
381  Pout<< "globalMeshData::calcSharedEdges : Merging in from proc0 : "
382  << localShared.size() << endl;
383  }
384  countSharedEdges(localShared, globalShared, sharedEdgeI);
385 
386  // Receive data and insert
387  if (UPstream::parRun())
388  {
389  for (const int proci : UPstream::subProcs())
390  {
391  // Receive the edges using shared points from the slave.
392  EdgeMap<labelList> procSharedEdges;
393  IPstream::recv(procSharedEdges, proci);
394 
395  if (debug)
396  {
397  Pout<< "globalMeshData::calcSharedEdges : "
398  << "Merging in from proc"
399  << proci << " : " << procSharedEdges.size()
400  << endl;
401  }
402  countSharedEdges(procSharedEdges, globalShared, sharedEdgeI);
403  }
404  }
405 
406  // Now our globalShared should have some edges with -1 as edge label
407  // These were only used once so are not proper shared edges.
408  // Remove them.
409  {
410  EdgeMap<label> oldSharedEdges(std::move(globalShared));
411  globalShared.clear();
412 
413  forAllConstIters(oldSharedEdges, iter)
414  {
415  if (iter.val() != -1)
416  {
417  globalShared.insert(iter.key(), iter.val());
418  }
419  }
420 
421  if (debug)
422  {
423  Pout<< "globalMeshData::calcSharedEdges : Filtered "
424  << oldSharedEdges.size()
425  << " down to " << globalShared.size() << endl;
426  }
427  }
428  }
429  else
430  {
431  if (UPstream::parRun())
432  {
433  // send local edges to master
434  OPstream::send(localShared, UPstream::masterNo());
435  }
436  }
437 
438  // Broadcast: merged edges to all
439  Pstream::broadcast(globalShared); // == worldComm;
440 
441 
442  // Now use the global shared edges list (globalShared) to classify my local
443  // ones (localShared)
444 
445  nGlobalEdges_ = globalShared.size();
446 
447  DynamicList<label> dynSharedEdgeLabels(globalShared.size());
448  DynamicList<label> dynSharedEdgeAddr(globalShared.size());
449 
450  forAllConstIters(localShared, iter)
451  {
452  const edge& e = iter.key();
453 
454  const auto edgeFnd = globalShared.cfind(e);
455 
456  if (edgeFnd.good())
457  {
458  // My local edge is indeed a shared one. Go through all local edge
459  // labels with this point combination.
460  const labelList& edgeLabels = iter.val();
461 
462  for (const label edgei : edgeLabels)
463  {
464  // Store label of local mesh edge
465  dynSharedEdgeLabels.append(edgei);
466 
467  // Store label of shared edge
468  dynSharedEdgeAddr.append(edgeFnd());
469  }
470  }
471  }
472 
473 
474  sharedEdgeLabelsPtr_.reset
475  (
476  new labelList(std::move(dynSharedEdgeLabels))
477  );
478 
479  sharedEdgeAddrPtr_.reset
480  (
481  new labelList(std::move(dynSharedEdgeAddr))
482  );
483 
484  // Reset tag
485  UPstream::msgType(oldTag);
486 
487  if (debug)
488  {
489  Pout<< "globalMeshData : nGlobalEdges_:" << nGlobalEdges_ << nl
490  << "globalMeshData : sharedEdgeLabels:"
491  << sharedEdgeLabelsPtr_().size() << nl
492  << "globalMeshData : sharedEdgeAddr:"
493  << sharedEdgeAddrPtr_().size() << endl;
494  }
495 }
496 
497 
498 void Foam::globalMeshData::calcGlobalPointSlaves() const
499 {
500  if (debug)
501  {
502  Pout<< "globalMeshData::calcGlobalPointSlaves() :"
503  << " calculating coupled master to slave point addressing."
504  << endl;
505  }
506 
507  // Allocate unique tag for all comms
508  const int oldTag = UPstream::incrMsgType();
509 
510  // Calculate connected points for master points.
511  globalPoints globalData(mesh_, coupledPatch(), true, true);
512 
513  globalPointSlavesPtr_.reset
514  (
515  new labelListList
516  (
517  std::move(globalData.pointPoints())
518  )
519  );
520  globalPointTransformedSlavesPtr_.reset
521  (
522  new labelListList
523  (
524  std::move(globalData.transformedPointPoints())
525  )
526  );
527 
528  globalPointSlavesMapPtr_.reset
529  (
530  new mapDistribute
531  (
532  std::move(globalData.map())
533  )
534  );
535 
536  // Reset tag
537  UPstream::msgType(oldTag);
538 }
539 
540 
541 void Foam::globalMeshData::calcPointConnectivity
542 (
543  List<labelPairList>& allPointConnectivity
544 ) const
545 {
546  const globalIndexAndTransform& transforms = globalTransforms();
547  const labelListList& slaves = globalPointSlaves();
548  const labelListList& transformedSlaves = globalPointTransformedSlaves();
549  const auto& slavesMap = globalPointSlavesMap();
550 
551 
552  // Allocate unique tag for all comms
553  const int oldTag = UPstream::incrMsgType();
554 
555  // Create field with my local data
556  labelPairList myData(slavesMap.constructSize());
557  forAll(slaves, pointi)
558  {
559  myData[pointi] = transforms.encode
560  (
562  pointi,
563  transforms.nullTransformIndex()
564  );
565  }
566  // Send to master
567  slavesMap.distribute(myData, true, UPstream::msgType());
568 
569 
570  // String of connected points with their transform
571  allPointConnectivity.setSize(slavesMap.constructSize());
572  allPointConnectivity = labelPairList(0);
573 
574  // Pass1: do the master points since these also update local slaves
575  // (e.g. from local cyclics)
576  forAll(slaves, pointi)
577  {
578  // Reconstruct string of connected points
579  const labelList& pSlaves = slaves[pointi];
580  const labelList& pTransformSlaves = transformedSlaves[pointi];
581 
582  if (pSlaves.size()+pTransformSlaves.size())
583  {
584  labelPairList& pConnectivity = allPointConnectivity[pointi];
585 
586  pConnectivity.setSize(1+pSlaves.size()+pTransformSlaves.size());
587  label connI = 0;
588 
589  // Add myself
590  pConnectivity[connI++] = myData[pointi];
591  // Add untransformed points
592  forAll(pSlaves, i)
593  {
594  pConnectivity[connI++] = myData[pSlaves[i]];
595  }
596  // Add transformed points.
597  forAll(pTransformSlaves, i)
598  {
599  // Get transform from index
600  label transformI = slavesMap.whichTransform
601  (
602  pTransformSlaves[i]
603  );
604  // Add transform to connectivity
605  const labelPair& n = myData[pTransformSlaves[i]];
606  label proci = transforms.processor(n);
607  label index = transforms.index(n);
608  pConnectivity[connI++] = transforms.encode
609  (
610  proci,
611  index,
612  transformI
613  );
614  }
615 
616  // Put back in slots
617  forAll(pSlaves, i)
618  {
619  allPointConnectivity[pSlaves[i]] = pConnectivity;
620  }
621  forAll(pTransformSlaves, i)
622  {
623  allPointConnectivity[pTransformSlaves[i]] = pConnectivity;
624  }
625  }
626  }
627 
628 
629  // Pass2: see if anything is still unset (should not be the case)
630  forAll(slaves, pointi)
631  {
632  labelPairList& pConnectivity = allPointConnectivity[pointi];
633 
634  if (pConnectivity.size() == 0)
635  {
636  pConnectivity.setSize(1, myData[pointi]);
637  }
638  }
639 
640 
641  slavesMap.reverseDistribute
642  (
643  slaves.size(),
644  allPointConnectivity,
645  true,
647  );
648 
649  // Reset tag
650  UPstream::msgType(oldTag);
651 }
652 
653 
654 void Foam::globalMeshData::calcGlobalPointEdges
655 (
656  labelListList& globalPointEdges,
657  List<labelPairList>& globalPointPoints
658 ) const
659 {
660  const edgeList& edges = coupledPatch().edges();
661  const labelListList& pointEdges = coupledPatch().pointEdges();
662  const globalIndex& globalEdgeNumbers = globalEdgeNumbering();
663  const labelListList& slaves = globalPointSlaves();
664  const labelListList& transformedSlaves = globalPointTransformedSlaves();
665  const globalIndexAndTransform& transforms = globalTransforms();
666 
667 
668  // Create local version
669  globalPointEdges.setSize(globalPointSlavesMap().constructSize());
670  globalPointPoints.setSize(globalPointSlavesMap().constructSize());
671  forAll(pointEdges, pointi)
672  {
673  const labelList& pEdges = pointEdges[pointi];
674  globalPointEdges[pointi] = globalEdgeNumbers.toGlobal(pEdges);
675 
676  labelPairList& globalPPoints = globalPointPoints[pointi];
677  globalPPoints.setSize(pEdges.size());
678  forAll(pEdges, i)
679  {
680  label otherPointi = edges[pEdges[i]].otherVertex(pointi);
681  globalPPoints[i] = transforms.encode
682  (
684  otherPointi,
685  transforms.nullTransformIndex()
686  );
687  }
688  }
689 
690  // Pull slave data to master. Dummy transform.
691 
692  // Allocate unique tag for all comms
693  const int oldTag = UPstream::incrMsgType();
694 
695  globalPointSlavesMap().distribute
696  (
697  globalPointEdges,
698  true,
700  );
701  // Make sure second send uses 'far' away tags in case of NBX deciding on
702  // multi-pass spraying of messages with consecutive tags
703  globalPointSlavesMap().distribute
704  (
705  globalPointPoints,
706  true,
707  UPstream::msgType()+23456 // Unique, far enough away tag
708  );
709 
710  // Add all pointEdges
711  forAll(slaves, pointi)
712  {
713  const labelList& pSlaves = slaves[pointi];
714  const labelList& pTransformSlaves = transformedSlaves[pointi];
715 
716  label n = 0;
717  forAll(pSlaves, i)
718  {
719  n += globalPointEdges[pSlaves[i]].size();
720  }
721  forAll(pTransformSlaves, i)
722  {
723  n += globalPointEdges[pTransformSlaves[i]].size();
724  }
725 
726  // Add all the point edges of the slaves to those of the (master) point
727  {
728  labelList& globalPEdges = globalPointEdges[pointi];
729  label sz = globalPEdges.size();
730  globalPEdges.setSize(sz+n);
731  forAll(pSlaves, i)
732  {
733  const labelList& otherData = globalPointEdges[pSlaves[i]];
734  forAll(otherData, j)
735  {
736  globalPEdges[sz++] = otherData[j];
737  }
738  }
739  forAll(pTransformSlaves, i)
740  {
741  const labelList& otherData =
742  globalPointEdges[pTransformSlaves[i]];
743  forAll(otherData, j)
744  {
745  globalPEdges[sz++] = otherData[j];
746  }
747  }
748 
749  // Put back in slots
750  forAll(pSlaves, i)
751  {
752  globalPointEdges[pSlaves[i]] = globalPEdges;
753  }
754  forAll(pTransformSlaves, i)
755  {
756  globalPointEdges[pTransformSlaves[i]] = globalPEdges;
757  }
758  }
759 
760 
761  // Same for corresponding pointPoints
762  {
763  labelPairList& globalPPoints = globalPointPoints[pointi];
764  label sz = globalPPoints.size();
765  globalPPoints.setSize(sz + n);
766 
767  // Add untransformed points
768  forAll(pSlaves, i)
769  {
770  const labelPairList& otherData = globalPointPoints[pSlaves[i]];
771  forAll(otherData, j)
772  {
773  globalPPoints[sz++] = otherData[j];
774  }
775  }
776  // Add transformed points.
777  forAll(pTransformSlaves, i)
778  {
779  // Get transform from index
780  label transformI = globalPointSlavesMap().whichTransform
781  (
782  pTransformSlaves[i]
783  );
784 
785  const labelPairList& otherData =
786  globalPointPoints[pTransformSlaves[i]];
787  forAll(otherData, j)
788  {
789  // Add transform to connectivity
790  const labelPair& n = otherData[j];
791  label proci = transforms.processor(n);
792  label index = transforms.index(n);
793  globalPPoints[sz++] = transforms.encode
794  (
795  proci,
796  index,
797  transformI
798  );
799  }
800  }
801 
802  // Put back in slots
803  forAll(pSlaves, i)
804  {
805  globalPointPoints[pSlaves[i]] = globalPPoints;
806  }
807  forAll(pTransformSlaves, i)
808  {
809  globalPointPoints[pTransformSlaves[i]] = globalPPoints;
810  }
811  }
812  }
813  // Push back
814  globalPointSlavesMap().reverseDistribute
815  (
816  slaves.size(),
817  globalPointEdges,
818  true,
820  );
821  // Push back
822  globalPointSlavesMap().reverseDistribute
823  (
824  slaves.size(),
825  globalPointPoints,
826  true,
827  UPstream::msgType()+65432 // Unique, far enough away tag
828  );
829 
830  // Reset tag
831  UPstream::msgType(oldTag);
832 }
833 
834 
835 Foam::label Foam::globalMeshData::findTransform
836 (
837  const labelPairList& info,
838  const labelPair& remotePoint,
839  const label localPoint
840 ) const
841 {
842  const globalIndexAndTransform& transforms = globalTransforms();
843 
844  const label remoteProci = transforms.processor(remotePoint);
845  const label remoteIndex = transforms.index(remotePoint);
846 
847  label remoteTransformI = -1;
848  label localTransformI = -1;
849  forAll(info, i)
850  {
851  label proci = transforms.processor(info[i]);
852  label pointi = transforms.index(info[i]);
853  label transformI = transforms.transformIndex(info[i]);
854 
855  if (proci == Pstream::myProcNo() && pointi == localPoint)
856  {
857  localTransformI = transformI;
858  //Pout<< "For local :" << localPoint
859  // << " found transform:" << localTransformI
860  // << endl;
861  }
862  if (proci == remoteProci && pointi == remoteIndex)
863  {
864  remoteTransformI = transformI;
865  //Pout<< "For remote:" << remotePoint
866  // << " found transform:" << remoteTransformI
867  // << " at index:" << i
868  // << endl;
869  }
870  }
871 
872  if (remoteTransformI == -1 || localTransformI == -1)
873  {
875  << "Problem. Cannot find " << remotePoint
876  << " or " << localPoint << " "
877  << coupledPatch().localPoints()[localPoint]
878  << " in " << info
879  << endl
880  << "remoteTransformI:" << remoteTransformI << endl
881  << "localTransformI:" << localTransformI
882  << abort(FatalError);
883  }
884 
885  return transforms.subtractTransformIndex
886  (
887  remoteTransformI,
888  localTransformI
889  );
890 }
891 
892 
893 void Foam::globalMeshData::calcGlobalEdgeSlaves() const
894 {
895  if (debug)
896  {
897  Pout<< "globalMeshData::calcGlobalEdgeSlaves() :"
898  << " calculating coupled master to slave edge addressing." << endl;
899  }
900 
901  const edgeList& edges = coupledPatch().edges();
902  const globalIndex& globalEdgeNumbers = globalEdgeNumbering();
903  const globalIndexAndTransform& transforms = globalTransforms();
904 
905 
906  // The whole problem with deducting edge-connectivity from
907  // point-connectivity is that one of the endpoints might be
908  // a local master but the other endpoint might not. So we first
909  // need to make sure that all points know about connectivity and
910  // the transformations.
911 
912  // Allocate unique tag for all comms
913  const int oldTag = UPstream::incrMsgType();
914 
915  // 1. collect point connectivity - basically recreating globalPoints output.
916  // All points will now have a string of coupled points. The transforms are
917  // in respect to the master.
918  List<labelPairList> allPointConnectivity;
919  calcPointConnectivity(allPointConnectivity);
920 
921 
922  // 2. Get all pointEdges and pointPoints
923  // Coupled point to global coupled edges and corresponding endpoint.
924  labelListList globalPointEdges;
925  List<labelPairList> globalPointPoints;
926  calcGlobalPointEdges(globalPointEdges, globalPointPoints);
927 
928 
929  // 3. Now all points have
930  // - all the connected points with original transform
931  // - all the connected global edges
932 
933  // Now all we need to do is go through all the edges and check
934  // both endpoints. If there is a edge between the two which is
935  // produced by transforming both points in the same way it is a shared
936  // edge.
937 
938  // Collect strings of connected edges.
939  List<labelPairList> allEdgeConnectivity(edges.size());
940 
941  forAll(edges, edgeI)
942  {
943  const edge& e = edges[edgeI];
944  const labelList& pEdges0 = globalPointEdges[e[0]];
945  const labelPairList& pPoints0 = globalPointPoints[e[0]];
946  const labelList& pEdges1 = globalPointEdges[e[1]];
947  const labelPairList& pPoints1 = globalPointPoints[e[1]];
948 
949  // Most edges will be size 2
950  DynamicList<labelPair> eEdges(2);
951  // Append myself.
952  eEdges.append
953  (
954  transforms.encode
955  (
957  edgeI,
958  transforms.nullTransformIndex()
959  )
960  );
961 
962  forAll(pEdges0, i)
963  {
964  forAll(pEdges1, j)
965  {
966  if
967  (
968  pEdges0[i] == pEdges1[j]
969  && pEdges0[i] != globalEdgeNumbers.toGlobal(edgeI)
970  )
971  {
972  // Found a shared edge. Now check if the endpoints
973  // go through the same transformation.
974  // Local: e[0] remote:pPoints1[j]
975  // Local: e[1] remote:pPoints0[i]
976 
977 
978  // Find difference in transforms to go from point on remote
979  // edge (pPoints1[j]) to this point.
980 
981  label transform0 = findTransform
982  (
983  allPointConnectivity[e[0]],
984  pPoints1[j],
985  e[0]
986  );
987  label transform1 = findTransform
988  (
989  allPointConnectivity[e[1]],
990  pPoints0[i],
991  e[1]
992  );
993 
994  if (transform0 == transform1)
995  {
996  label proci = globalEdgeNumbers.whichProcID(pEdges0[i]);
997  eEdges.append
998  (
999  transforms.encode
1000  (
1001  proci,
1002  globalEdgeNumbers.toLocal(proci, pEdges0[i]),
1003  transform0
1004  )
1005  );
1006  }
1007  }
1008  }
1009  }
1010 
1011  allEdgeConnectivity[edgeI].transfer(eEdges);
1012  Foam::sort
1013  (
1014  allEdgeConnectivity[edgeI],
1015  globalIndexAndTransform::less(transforms)
1016  );
1017  }
1018 
1019  // We now have - in allEdgeConnectivity - a list of edges which are shared
1020  // between multiple processors. Filter into non-transformed and transformed
1021  // connections.
1022 
1023  globalEdgeSlavesPtr_.reset(new labelListList(edges.size()));
1024  labelListList& globalEdgeSlaves = globalEdgeSlavesPtr_();
1025  List<labelPairList> transformedEdges(edges.size());
1026  forAll(allEdgeConnectivity, edgeI)
1027  {
1028  const labelPairList& edgeInfo = allEdgeConnectivity[edgeI];
1029  if (edgeInfo.size() >= 2)
1030  {
1031  const labelPair& masterInfo = edgeInfo[0];
1032 
1033  // Check if master edge (= first element (since sorted)) is me.
1034  if
1035  (
1036  (
1037  transforms.processor(masterInfo)
1038  == Pstream::myProcNo()
1039  )
1040  && (transforms.index(masterInfo) == edgeI)
1041  )
1042  {
1043  // Sort into transformed and untransformed
1044  labelList& eEdges = globalEdgeSlaves[edgeI];
1045  eEdges.setSize(edgeInfo.size()-1);
1046 
1047  labelPairList& trafoEEdges = transformedEdges[edgeI];
1048  trafoEEdges.setSize(edgeInfo.size()-1);
1049 
1050  label nonTransformI = 0;
1051  label transformI = 0;
1052 
1053  for (label i = 1; i < edgeInfo.size(); i++)
1054  {
1055  const labelPair& info = edgeInfo[i];
1056  label proci = transforms.processor(info);
1057  label index = transforms.index(info);
1058  label transform = transforms.transformIndex
1059  (
1060  info
1061  );
1062 
1063  if (transform == transforms.nullTransformIndex())
1064  {
1065  eEdges[nonTransformI++] = globalEdgeNumbers.toGlobal
1066  (
1067  proci,
1068  index
1069  );
1070  }
1071  else
1072  {
1073  trafoEEdges[transformI++] = info;
1074  }
1075  }
1076 
1077  eEdges.setSize(nonTransformI);
1078  trafoEEdges.setSize(transformI);
1079  }
1080  }
1081  }
1082 
1083 
1084  // Construct map
1085  globalEdgeTransformedSlavesPtr_.reset(new labelListList());
1086 
1087  List<Map<label>> compactMap(Pstream::nProcs());
1088  globalEdgeSlavesMapPtr_.reset
1089  (
1090  new mapDistribute
1091  (
1092  globalEdgeNumbers,
1093  globalEdgeSlaves,
1094 
1095  transforms,
1096  transformedEdges,
1097  globalEdgeTransformedSlavesPtr_(),
1098 
1099  compactMap,
1101  )
1102  );
1103 
1104  // Reset tag
1105  UPstream::msgType(oldTag);
1106 
1107  if (debug)
1108  {
1109  Pout<< "globalMeshData::calcGlobalEdgeSlaves() :"
1110  << " coupled edges:" << edges.size()
1111  << " additional coupled edges:"
1112  << globalEdgeSlavesMapPtr_().constructSize() - edges.size()
1113  << endl;
1114  }
1115 }
1116 
1117 
1118 void Foam::globalMeshData::calcGlobalEdgeOrientation() const
1119 {
1120  if (debug)
1121  {
1122  Pout<< "globalMeshData::calcGlobalEdgeOrientation() :"
1123  << " calculating edge orientation w.r.t. master edge." << endl;
1124  }
1125 
1126  // Allocate unique tag for all comms
1127  const int oldTag = UPstream::incrMsgType();
1128 
1129  const globalIndex& globalPoints = globalPointNumbering();
1130 
1131  // 1. Determine master point
1132  labelList masterPoint;
1133  {
1134  const mapDistribute& map = globalPointSlavesMap();
1135 
1136  masterPoint.setSize(map.constructSize());
1137  masterPoint = labelMax;
1138 
1139  for (label pointi = 0; pointi < coupledPatch().nPoints(); pointi++)
1140  {
1141  masterPoint[pointi] = globalPoints.toGlobal(pointi);
1142  }
1143  syncData
1144  (
1145  masterPoint,
1146  globalPointSlaves(),
1147  globalPointTransformedSlaves(),
1148  map,
1149  minEqOp<label>()
1150  );
1151  }
1152 
1153  // Now all points should know who is master by comparing their global
1154  // pointID with the masterPointID. We now can use this information
1155  // to find the orientation of the master edge.
1156 
1157  {
1158  const mapDistribute& map = globalEdgeSlavesMap();
1159  const labelListList& slaves = globalEdgeSlaves();
1160  const labelListList& transformedSlaves = globalEdgeTransformedSlaves();
1161 
1162  // Distribute orientation of master edge (in masterPoint numbering)
1163  labelPairList masterEdgeVerts(map.constructSize());
1164  masterEdgeVerts = labelPair(labelMax, labelMax);
1165 
1166  for (label edgeI = 0; edgeI < coupledPatch().nEdges(); edgeI++)
1167  {
1168  if
1169  (
1170  (
1171  slaves[edgeI].size()
1172  + transformedSlaves[edgeI].size()
1173  )
1174  > 0
1175  )
1176  {
1177  // I am master. Fill in my masterPoint equivalent.
1178 
1179  const edge& e = coupledPatch().edges()[edgeI];
1180  masterEdgeVerts[edgeI] = labelPair
1181  (
1182  masterPoint[e[0]],
1183  masterPoint[e[1]]
1184  );
1185  }
1186  }
1187  syncData
1188  (
1189  masterEdgeVerts,
1190  slaves,
1191  transformedSlaves,
1192  map,
1193  minEqOp<labelPair>()
1194  );
1195 
1196  // Now check my edges on how they relate to the master's edgeVerts
1197  globalEdgeOrientationPtr_.reset
1198  (
1199  new bitSet(coupledPatch().nEdges())
1200  );
1201  bitSet& globalEdgeOrientation = globalEdgeOrientationPtr_();
1202 
1203  forAll(coupledPatch().edges(), edgeI)
1204  {
1205  // Test that edge is not single edge on cyclic baffle
1206  if (masterEdgeVerts[edgeI] != labelPair(labelMax, labelMax))
1207  {
1208  const edge& e = coupledPatch().edges()[edgeI];
1209  const labelPair masterE
1210  (
1211  masterPoint[e[0]],
1212  masterPoint[e[1]]
1213  );
1214 
1215  const int stat = labelPair::compare
1216  (
1217  masterE,
1218  masterEdgeVerts[edgeI]
1219  );
1220  if (stat == 0)
1221  {
1223  << "problem : my edge:" << e
1224  << " in master points:" << masterE
1225  << " v.s. masterEdgeVerts:" << masterEdgeVerts[edgeI]
1226  << exit(FatalError);
1227  }
1228  else
1229  {
1230  globalEdgeOrientation.set(edgeI, (stat == 1));
1231  }
1232  }
1233  else
1234  {
1235  globalEdgeOrientation.set(edgeI, true);
1236  }
1237  }
1238  }
1239 
1240  // Reset tag
1241  UPstream::msgType(oldTag);
1242 
1243  if (debug)
1244  {
1245  Pout<< "globalMeshData::calcGlobalEdgeOrientation() :"
1246  << " finished calculating edge orientation."
1247  << endl;
1248  }
1249 }
1250 
1251 
1252 void Foam::globalMeshData::calcPointBoundaryFaces
1253 (
1254  labelListList& pointBoundaryFaces
1255 ) const
1256 {
1257  const polyBoundaryMesh& bMesh = mesh_.boundaryMesh();
1258  const Map<label>& meshPointMap = coupledPatch().meshPointMap();
1259 
1260  // 1. Count
1261 
1262  labelList nPointFaces(coupledPatch().nPoints(), Zero);
1263 
1264  for (const polyPatch& pp : bMesh)
1265  {
1266  if (!pp.coupled())
1267  {
1268  for (const face& f : pp)
1269  {
1270  forAll(f, fp)
1271  {
1272  const auto iter = meshPointMap.cfind(f[fp]);
1273  if (iter.good())
1274  {
1275  nPointFaces[iter.val()]++;
1276  }
1277  }
1278  }
1279  }
1280  }
1281 
1282 
1283  // 2. Size
1284 
1285  pointBoundaryFaces.setSize(coupledPatch().nPoints());
1286  forAll(nPointFaces, pointi)
1287  {
1288  pointBoundaryFaces[pointi].setSize(nPointFaces[pointi]);
1289  }
1290  nPointFaces = 0;
1291 
1292 
1293  // 3. Fill
1294 
1295  forAll(bMesh, patchi)
1296  {
1297  const polyPatch& pp = bMesh[patchi];
1298 
1299  if (!pp.coupled())
1300  {
1301  forAll(pp, i)
1302  {
1303  const face& f = pp[i];
1304  forAll(f, fp)
1305  {
1306  const auto iter = meshPointMap.cfind(f[fp]);
1307 
1308  if (iter.good())
1309  {
1310  label bFacei =
1311  pp.start() + i - mesh_.nInternalFaces();
1312  pointBoundaryFaces[iter()][nPointFaces[iter()]++] =
1313  bFacei;
1314  }
1315  }
1316  }
1317  }
1318  }
1319 }
1320 
1321 
1322 void Foam::globalMeshData::calcGlobalPointBoundaryFaces() const
1323 {
1324  if (debug)
1325  {
1326  Pout<< "globalMeshData::calcGlobalPointBoundaryFaces() :"
1327  << " calculating coupled point to boundary face addressing."
1328  << endl;
1329  }
1330 
1331  const label myProci = UPstream::myProcNo();
1332 
1333  // Allocate unique tag for all comms
1334  const int oldTag = UPstream::incrMsgType();
1335 
1336  // Construct local point to (uncoupled)boundaryfaces.
1337  labelListList pointBoundaryFaces;
1338  calcPointBoundaryFaces(pointBoundaryFaces);
1339 
1340 
1341  // Global indices for boundary faces
1342  globalBoundaryFaceNumberingPtr_.reset
1343  (
1344  new globalIndex(mesh_.nBoundaryFaces())
1345  );
1346  const auto& globalIndices = *globalBoundaryFaceNumberingPtr_;
1347 
1348 
1349  // Convert local boundary faces to global numbering
1350  globalPointBoundaryFacesPtr_.reset
1351  (
1352  new labelListList(globalPointSlavesMap().constructSize())
1353  );
1354  auto& globalPointBoundaryFaces = *globalPointBoundaryFacesPtr_;
1355 
1356  forAll(pointBoundaryFaces, pointi)
1357  {
1358  globalPointBoundaryFaces[pointi] = globalIndices.toGlobal
1359  (
1360  myProci,
1361  pointBoundaryFaces[pointi]
1362  );
1363  }
1364 
1365 
1366  // Pull slave pointBoundaryFaces to master
1367  globalPointSlavesMap().distribute
1368  (
1369  globalPointBoundaryFaces,
1370  true // put data on transformed points into correct slots
1371  );
1372 
1373 
1374  // Merge slave labels into master globalPointBoundaryFaces.
1375  // Split into untransformed and transformed values.
1376  const labelListList& pointSlaves = globalPointSlaves();
1377  const labelListList& pointTransformSlaves =
1378  globalPointTransformedSlaves();
1379  const globalIndexAndTransform& transforms = globalTransforms();
1380 
1381 
1382  // Any faces coming in through transformation
1383  List<labelPairList> transformedFaces(pointSlaves.size());
1384 
1385 
1386  forAll(pointSlaves, pointi)
1387  {
1388  const labelList& slaves = pointSlaves[pointi];
1389  const labelList& transformedSlaves = pointTransformSlaves[pointi];
1390 
1391  if (slaves.size() > 0)
1392  {
1393  labelList& myBFaces = globalPointBoundaryFaces[pointi];
1394  label sz = myBFaces.size();
1395 
1396  // Count
1397  label n = 0;
1398  forAll(slaves, i)
1399  {
1400  n += globalPointBoundaryFaces[slaves[i]].size();
1401  }
1402  // Fill
1403  myBFaces.setSize(sz+n);
1404  n = sz;
1405  forAll(slaves, i)
1406  {
1407  const labelList& slaveBFaces =
1408  globalPointBoundaryFaces[slaves[i]];
1409 
1410  // Add all slaveBFaces. Note that need to check for
1411  // uniqueness only in case of cyclics.
1412 
1413  for (const label slave : slaveBFaces)
1414  {
1415  if (!SubList<label>(myBFaces, sz).found(slave))
1416  {
1417  myBFaces[n++] = slave;
1418  }
1419  }
1420  }
1421  myBFaces.setSize(n);
1422  }
1423 
1424 
1425  if (transformedSlaves.size() > 0)
1426  {
1427  const labelList& untrafoFaces = globalPointBoundaryFaces[pointi];
1428 
1429  labelPairList& myBFaces = transformedFaces[pointi];
1430  label sz = myBFaces.size();
1431 
1432  // Count
1433  label n = 0;
1434  forAll(transformedSlaves, i)
1435  {
1436  n += globalPointBoundaryFaces[transformedSlaves[i]].size();
1437  }
1438  // Fill
1439  myBFaces.setSize(sz+n);
1440  n = sz;
1441  forAll(transformedSlaves, i)
1442  {
1443  label transformI = globalPointSlavesMap().whichTransform
1444  (
1445  transformedSlaves[i]
1446  );
1447 
1448  const labelList& slaveBFaces =
1449  globalPointBoundaryFaces[transformedSlaves[i]];
1450 
1451  for (const label slave : slaveBFaces)
1452  {
1453  // Check that same face not already present untransformed
1454  if (!untrafoFaces.found(slave))
1455  {
1456  label proci = globalIndices.whichProcID(slave);
1457  label facei = globalIndices.toLocal(proci, slave);
1458 
1459  myBFaces[n++] = transforms.encode
1460  (
1461  proci,
1462  facei,
1463  transformI
1464  );
1465  }
1466  }
1467  }
1468  myBFaces.setSize(n);
1469  }
1470 
1471 
1472  if (slaves.size() + transformedSlaves.size() == 0)
1473  {
1474  globalPointBoundaryFaces[pointi].clear();
1475  }
1476  }
1477 
1478  // Construct a map to get the face data directly
1479  List<Map<label>> compactMap(Pstream::nProcs());
1480 
1481  globalPointTransformedBoundaryFacesPtr_.reset
1482  (
1483  new labelListList(transformedFaces.size())
1484  );
1485 
1486  globalPointBoundaryFacesMapPtr_.reset
1487  (
1488  new mapDistribute
1489  (
1490  globalIndices,
1491  globalPointBoundaryFaces,
1492 
1493  transforms,
1494  transformedFaces,
1495  globalPointTransformedBoundaryFacesPtr_(),
1496 
1497  compactMap
1498  )
1499  );
1500  globalPointBoundaryFaces.setSize(coupledPatch().nPoints());
1501  globalPointTransformedBoundaryFacesPtr_().setSize(coupledPatch().nPoints());
1502 
1503  // Reset tag
1504  UPstream::msgType(oldTag);
1505 
1506  if (debug)
1507  {
1508  Pout<< "globalMeshData::calcGlobalPointBoundaryFaces() :"
1509  << " coupled points:" << coupledPatch().nPoints()
1510  << " local boundary faces:" << globalIndices.localSize()
1511  << " additional coupled faces:"
1512  << globalPointBoundaryFacesMapPtr_().constructSize()
1513  - globalIndices.localSize()
1514  << endl;
1515  }
1516 }
1517 
1518 
1519 void Foam::globalMeshData::calcGlobalPointBoundaryCells() const
1520 {
1521  if (debug)
1522  {
1523  Pout<< "globalMeshData::calcGlobalPointBoundaryCells() :"
1524  << " calculating coupled point to boundary cell addressing."
1525  << endl;
1526  }
1527 
1528  const label myProci = UPstream::myProcNo();
1529 
1530  // Create map of boundary cells and point-cell addressing
1531  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1532 
1533  label bCelli = 0;
1534  Map<label> meshCellMap(4*coupledPatch().nPoints());
1535  DynamicList<label> cellMap(meshCellMap.size());
1536 
1537  // Create addressing for point to boundary cells (local)
1538  labelListList pointBoundaryCells(coupledPatch().nPoints());
1539 
1540  forAll(coupledPatch().meshPoints(), pointi)
1541  {
1542  label meshPointi = coupledPatch().meshPoints()[pointi];
1543  const labelList& pCells = mesh_.pointCells(meshPointi);
1544 
1545  labelList& bCells = pointBoundaryCells[pointi];
1546  bCells.setSize(pCells.size());
1547 
1548  forAll(pCells, i)
1549  {
1550  const label celli = pCells[i];
1551  const auto fnd = meshCellMap.cfind(celli);
1552 
1553  if (fnd.good())
1554  {
1555  bCells[i] = fnd();
1556  }
1557  else
1558  {
1559  meshCellMap.insert(celli, bCelli);
1560  cellMap.append(celli);
1561  bCells[i] = bCelli;
1562  bCelli++;
1563  }
1564  }
1565  }
1566 
1567 
1568  boundaryCellsPtr_.reset(new labelList(std::move(cellMap)));
1569  labelList& boundaryCells = boundaryCellsPtr_();
1570 
1571 
1572  // Convert point-cells to global (boundary)cell numbers
1573  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1574 
1575 
1576  // Allocate unique tag for all comms
1577  const int oldTag = UPstream::incrMsgType();
1578 
1579  globalBoundaryCellNumberingPtr_.reset
1580  (
1581  new globalIndex(boundaryCells.size())
1582  );
1583  const auto& globalIndices = *globalBoundaryCellNumberingPtr_;
1584 
1585 
1586  // Convert local boundary cells to global numbering
1587  globalPointBoundaryCellsPtr_.reset
1588  (
1589  new labelListList(globalPointSlavesMap().constructSize())
1590  );
1591  auto& globalPointBoundaryCells = *globalPointBoundaryCellsPtr_;
1592 
1593  forAll(pointBoundaryCells, pointi)
1594  {
1595  globalPointBoundaryCells[pointi] = globalIndices.toGlobal
1596  (
1597  myProci,
1598  pointBoundaryCells[pointi]
1599  );
1600  }
1601 
1602 
1603  // Pull slave pointBoundaryCells to master
1604  globalPointSlavesMap().distribute
1605  (
1606  globalPointBoundaryCells,
1607  true // put data on transformed points into correct slots
1608  );
1609 
1610 
1611  // Merge slave labels into master globalPointBoundaryCells
1612  const labelListList& pointSlaves = globalPointSlaves();
1613  const labelListList& pointTransformSlaves =
1614  globalPointTransformedSlaves();
1615  const globalIndexAndTransform& transforms = globalTransforms();
1616 
1617  List<labelPairList> transformedCells(pointSlaves.size());
1618 
1619 
1620  forAll(pointSlaves, pointi)
1621  {
1622  const labelList& slaves = pointSlaves[pointi];
1623  const labelList& transformedSlaves = pointTransformSlaves[pointi];
1624 
1625  if (slaves.size() > 0)
1626  {
1627  labelList& myBCells = globalPointBoundaryCells[pointi];
1628  label sz = myBCells.size();
1629 
1630  // Count
1631  label n = 0;
1632  forAll(slaves, i)
1633  {
1634  n += globalPointBoundaryCells[slaves[i]].size();
1635  }
1636  // Fill
1637  myBCells.setSize(sz+n);
1638  n = sz;
1639  forAll(slaves, i)
1640  {
1641  const labelList& slaveBCells =
1642  globalPointBoundaryCells[slaves[i]];
1643 
1644  // Add all slaveBCells. Note that need to check for
1645  // uniqueness only in case of cyclics.
1646 
1647  for (const label slave : slaveBCells)
1648  {
1649  if (!SubList<label>(myBCells, sz).found(slave))
1650  {
1651  myBCells[n++] = slave;
1652  }
1653  }
1654  }
1655  myBCells.setSize(n);
1656  }
1657 
1658 
1659  if (transformedSlaves.size() > 0)
1660  {
1661  const labelList& untrafoCells = globalPointBoundaryCells[pointi];
1662 
1663  labelPairList& myBCells = transformedCells[pointi];
1664  label sz = myBCells.size();
1665 
1666  // Count
1667  label n = 0;
1668  forAll(transformedSlaves, i)
1669  {
1670  n += globalPointBoundaryCells[transformedSlaves[i]].size();
1671  }
1672  // Fill
1673  myBCells.setSize(sz+n);
1674  n = sz;
1675  forAll(transformedSlaves, i)
1676  {
1677  label transformI = globalPointSlavesMap().whichTransform
1678  (
1679  transformedSlaves[i]
1680  );
1681 
1682  const labelList& slaveBCells =
1683  globalPointBoundaryCells[transformedSlaves[i]];
1684 
1685  for (const label slave : slaveBCells)
1686  {
1687  // Check that same cell not already present untransformed
1688  if (!untrafoCells.found(slave))
1689  {
1690  label proci = globalIndices.whichProcID(slave);
1691  label celli = globalIndices.toLocal(proci, slave);
1692  myBCells[n++] = transforms.encode
1693  (
1694  proci,
1695  celli,
1696  transformI
1697  );
1698  }
1699  }
1700  }
1701  myBCells.setSize(n);
1702  }
1703 
1704  if (slaves.size() + transformedSlaves.size() == 0)
1705  {
1706  globalPointBoundaryCells[pointi].clear();
1707  }
1708  }
1709 
1710  // Construct a map to get the cell data directly
1711  List<Map<label>> compactMap(Pstream::nProcs());
1712 
1713  globalPointTransformedBoundaryCellsPtr_.reset
1714  (
1715  new labelListList(transformedCells.size())
1716  );
1717 
1718  globalPointBoundaryCellsMapPtr_.reset
1719  (
1720  new mapDistribute
1721  (
1722  globalIndices,
1723  globalPointBoundaryCells,
1724 
1725  transforms,
1726  transformedCells,
1727  globalPointTransformedBoundaryCellsPtr_(),
1728 
1729  compactMap
1730  )
1731  );
1732  globalPointBoundaryCells.setSize(coupledPatch().nPoints());
1733  globalPointTransformedBoundaryCellsPtr_().setSize(coupledPatch().nPoints());
1734 
1735  // Reset tag
1736  UPstream::msgType(oldTag);
1737 
1738  if (debug)
1739  {
1740  Pout<< "globalMeshData::calcGlobalPointBoundaryCells() :"
1741  << " coupled points:" << coupledPatch().nPoints()
1742  << " local boundary cells:" << globalIndices.localSize()
1743  << " additional coupled cells:"
1744  << globalPointBoundaryCellsMapPtr_().constructSize()
1745  - globalIndices.localSize()
1746  << endl;
1747  }
1748 }
1749 
1750 
1751 void Foam::globalMeshData::calcGlobalCoPointSlaves() const
1752 {
1753  if (debug)
1754  {
1755  Pout<< "globalMeshData::calcGlobalCoPointSlaves() :"
1756  << " calculating coupled master to collocated"
1757  << " slave point addressing." << endl;
1758  }
1759 
1760  // Allocate unique tag for all comms
1761  const int oldTag = UPstream::incrMsgType();
1762 
1763  // Calculate connected points for master points.
1764  globalPoints globalData(mesh_, coupledPatch(), true, false);
1765 
1766  globalCoPointSlavesPtr_.reset
1767  (
1768  new labelListList
1769  (
1770  std::move(globalData.pointPoints())
1771  )
1772  );
1773  globalCoPointSlavesMapPtr_.reset
1774  (
1775  new mapDistribute
1776  (
1777  std::move(globalData.map())
1778  )
1779  );
1780 
1781  UPstream::msgType(oldTag);
1782 
1783  if (debug)
1784  {
1785  Pout<< "globalMeshData::calcGlobalCoPointSlaves() :"
1786  << " finished calculating coupled master to collocated"
1787  << " slave point addressing." << endl;
1788  }
1789 }
1790 
1791 
1792 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1793 
1795 :
1796  mesh_(mesh),
1797  processorTopology_
1798  (
1799  processorTopology::New<processorPolyPatch>
1800  (
1801  mesh.boundaryMesh(),
1802  mesh_.comm()
1803  )
1804  ),
1805  nGlobalPoints_(-1),
1806  nGlobalEdges_(-1)
1807 {
1809 }
1810 
1811 
1812 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1813 
1814 // A non-default destructor since we had incomplete types in the header
1816 {}
1817 
1818 
1820 {
1821  // Point
1822  nGlobalPoints_ = -1;
1823  sharedPointLabelsPtr_.clear();
1824  sharedPointAddrPtr_.clear();
1825  sharedPointGlobalLabelsPtr_.clear();
1826 
1827  // Edge
1828  nGlobalEdges_ = -1;
1829  sharedEdgeLabelsPtr_.clear();
1830  sharedEdgeAddrPtr_.clear();
1831 
1832  // Coupled patch
1833  coupledPatchPtr_.clear();
1834  coupledPatchMeshEdgesPtr_.clear();
1835  coupledPatchMeshEdgeMapPtr_.clear();
1836  globalTransformsPtr_.clear();
1837 
1838  // Point
1839  globalPointNumberingPtr_.clear();
1840  globalPointSlavesPtr_.clear();
1841  globalPointTransformedSlavesPtr_.clear();
1842  globalPointSlavesMapPtr_.clear();
1843 
1844  // Edge
1845  globalEdgeNumberingPtr_.clear();
1846  globalEdgeSlavesPtr_.clear();
1847  globalEdgeTransformedSlavesPtr_.clear();
1848  globalEdgeOrientationPtr_.clear();
1849  globalEdgeSlavesMapPtr_.clear();
1850 
1851  // Face
1852  globalBoundaryFaceNumberingPtr_.clear();
1853  globalPointBoundaryFacesPtr_.clear();
1854  globalPointTransformedBoundaryFacesPtr_.clear();
1855  globalPointBoundaryFacesMapPtr_.clear();
1856 
1857  // Cell
1858  boundaryCellsPtr_.clear();
1859  globalBoundaryCellNumberingPtr_.clear();
1860  globalPointBoundaryCellsPtr_.clear();
1861  globalPointTransformedBoundaryCellsPtr_.clear();
1862  globalPointBoundaryCellsMapPtr_.clear();
1863 
1864  // Other: collocated points
1865  globalCoPointSlavesPtr_.clear();
1866  globalCoPointSlavesMapPtr_.clear();
1867 }
1868 
1869 
1870 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1871 
1873 {
1874  if (!sharedPointGlobalLabelsPtr_)
1875  {
1876  sharedPointGlobalLabelsPtr_.reset
1877  (
1878  new labelList(sharedPointLabels().size())
1879  );
1880  labelList& sharedPointGlobalLabels = sharedPointGlobalLabelsPtr_();
1881 
1882  IOobject addrHeader
1883  (
1884  "pointProcAddressing",
1885  mesh_.facesInstance()/polyMesh::meshSubDir,
1886  mesh_,
1888  );
1889 
1890  if (addrHeader.typeHeaderOk<labelIOList>(true))
1891  {
1892  // There is a pointProcAddressing file so use it to get labels
1893  // on the original mesh
1894  Pout<< "globalMeshData::sharedPointGlobalLabels : "
1895  << "Reading pointProcAddressing" << endl;
1896 
1897  labelIOList pointProcAddressing(addrHeader);
1898 
1899  const labelList& pointLabels = sharedPointLabels();
1900 
1901  forAll(pointLabels, i)
1902  {
1903  // Get my mesh point
1904  label pointi = pointLabels[i];
1905 
1906  // Map to mesh point of original mesh
1907  sharedPointGlobalLabels[i] = pointProcAddressing[pointi];
1908  }
1909  }
1910  else
1911  {
1912  Pout<< "globalMeshData::sharedPointGlobalLabels :"
1913  << " Setting pointProcAddressing to -1" << endl;
1914 
1915  sharedPointGlobalLabels = -1;
1916  }
1917  }
1918 
1919  return *sharedPointGlobalLabelsPtr_;
1920 }
1921 
1922 
1924 {
1925  // Get all processors to send their shared points to master.
1926  // (not very efficient)
1927 
1928  // Allocate unique tag for all comms
1929  const int oldTag = UPstream::incrMsgType();
1930 
1931  pointField sharedPoints(nGlobalPoints());
1932  const labelList& pointAddr = sharedPointAddr();
1933  const labelList& pointLabels = sharedPointLabels();
1934 
1935  if (UPstream::master())
1936  {
1937  // Master:
1938  // insert my own data first
1939  forAll(pointLabels, i)
1940  {
1941  label sharedPointi = pointAddr[i];
1942 
1943  sharedPoints[sharedPointi] = mesh_.points()[pointLabels[i]];
1944  }
1945 
1946  // Receive data and insert
1947  for (const int proci : UPstream::subProcs())
1948  {
1949  IPstream fromProc(UPstream::commsTypes::scheduled, proci);
1950 
1951  labelList nbrSharedPointAddr;
1952  pointField nbrSharedPoints;
1953  fromProc >> nbrSharedPointAddr >> nbrSharedPoints;
1954 
1955  forAll(nbrSharedPointAddr, i)
1956  {
1957  label sharedPointi = nbrSharedPointAddr[i];
1958 
1959  sharedPoints[sharedPointi] = nbrSharedPoints[i];
1960  }
1961  }
1962  }
1963  else
1964  {
1965  if (UPstream::parRun())
1966  {
1967  // Send address and points
1968  OPstream toMaster
1969  (
1972  );
1973  toMaster
1974  << pointAddr
1975  << pointField(mesh_.points(), pointLabels);
1976  }
1977  }
1978 
1979  // Broadcast: sharedPoints to all
1980  Pstream::broadcast(sharedPoints); // == worldComm
1981 
1982  // Reset tag
1983  UPstream::msgType(oldTag);
1984 
1985  return sharedPoints;
1986 }
1987 
1988 
1990 {
1991  // Allocate unique tag for all comms
1992  const int oldTag = UPstream::incrMsgType();
1993 
1994  // Get coords of my shared points
1995  pointField sharedPoints(mesh_.points(), sharedPointLabels());
1996 
1997  // Append from all processors, globally consistent
1999 
2000  // Merge tolerance
2001  scalar tolDim = matchTol_ * mesh_.bounds().mag();
2002 
2003  labelList pointMap;
2005  (
2006  sharedPoints, // coordinates to merge
2007  tolDim, // tolerance
2008  false, // verbosity
2009  pointMap
2010  );
2011 
2012  // Reset tag
2013  UPstream::msgType(oldTag);
2014 
2015  return sharedPoints;
2016 }
2017 
2018 
2019 Foam::label Foam::globalMeshData::nGlobalPoints() const
2020 {
2021  if (nGlobalPoints_ == -1)
2022  {
2023  calcSharedPoints();
2024  }
2025  return nGlobalPoints_;
2026 }
2027 
2028 
2030 {
2031  if (!sharedPointLabelsPtr_)
2032  {
2033  calcSharedPoints();
2034  }
2035  return *sharedPointLabelsPtr_;
2036 }
2037 
2038 
2040 {
2041  if (!sharedPointAddrPtr_)
2042  {
2043  calcSharedPoints();
2044  }
2045  return *sharedPointAddrPtr_;
2046 }
2047 
2048 
2049 Foam::label Foam::globalMeshData::nGlobalEdges() const
2050 {
2051  if (nGlobalEdges_ == -1)
2052  {
2053  calcSharedEdges();
2054  }
2055  return nGlobalEdges_;
2056 }
2057 
2058 
2060 {
2061  if (!sharedEdgeLabelsPtr_)
2062  {
2063  calcSharedEdges();
2064  }
2065  return *sharedEdgeLabelsPtr_;
2066 }
2067 
2068 
2070 {
2071  if (!sharedEdgeAddrPtr_)
2072  {
2073  calcSharedEdges();
2074  }
2075  return *sharedEdgeAddrPtr_;
2076 }
2077 
2078 
2080 {
2081  if (!coupledPatchPtr_)
2082  {
2083  const polyBoundaryMesh& bMesh = mesh_.boundaryMesh();
2084 
2085  label nCoupled = 0;
2086 
2087  forAll(bMesh, patchi)
2088  {
2089  const polyPatch& pp = bMesh[patchi];
2090 
2091  if (pp.coupled())
2092  {
2093  nCoupled += pp.size();
2094  }
2095  }
2096  labelList coupledFaces(nCoupled);
2097  nCoupled = 0;
2098 
2099  forAll(bMesh, patchi)
2100  {
2101  const polyPatch& pp = bMesh[patchi];
2102 
2103  if (pp.coupled())
2104  {
2105  label facei = pp.start();
2106 
2107  forAll(pp, i)
2108  {
2109  coupledFaces[nCoupled++] = facei++;
2110  }
2111  }
2112  }
2113 
2114  coupledPatchPtr_.reset
2115  (
2117  (
2118  IndirectList<face>
2119  (
2120  mesh_.faces(),
2121  coupledFaces
2122  ),
2123  mesh_.points()
2124  )
2125  );
2126 
2127  if (debug)
2128  {
2129  Pout<< "globalMeshData::coupledPatch() :"
2130  << " constructed coupled faces patch:"
2131  << " faces:" << coupledPatchPtr_().size()
2132  << " points:" << coupledPatchPtr_().nPoints()
2133  << endl;
2134  }
2135  }
2136  return *coupledPatchPtr_;
2137 }
2138 
2139 
2141 {
2142  if (!coupledPatchMeshEdgesPtr_)
2143  {
2144  coupledPatchMeshEdgesPtr_.reset
2145  (
2146  new labelList
2147  (
2148  coupledPatch().meshEdges
2149  (
2150  mesh_.edges(),
2151  mesh_.pointEdges()
2152  )
2153  )
2154  );
2155  }
2156  return *coupledPatchMeshEdgesPtr_;
2157 }
2158 
2159 
2161 const
2162 {
2163  if (!coupledPatchMeshEdgeMapPtr_)
2164  {
2165  const labelList& me = coupledPatchMeshEdges();
2166 
2167  coupledPatchMeshEdgeMapPtr_.reset
2168  (
2170  );
2171  }
2172  return *coupledPatchMeshEdgeMapPtr_;
2173 }
2174 
2175 
2177 {
2178  if (!globalPointNumberingPtr_)
2179  {
2180  // Allocate unique tag for all comms
2181  const int oldTag = UPstream::incrMsgType();
2182 
2183  globalPointNumberingPtr_.reset
2184  (
2185  new globalIndex(coupledPatch().nPoints())
2186  );
2187 
2188  // Reset tag
2190  }
2191  return *globalPointNumberingPtr_;
2192 }
2193 
2194 
2197 {
2198  if (!globalTransformsPtr_)
2199  {
2200  // Allocate unique tag for all comms
2201  const int oldTag = UPstream::incrMsgType();
2202 
2203  globalTransformsPtr_.reset(new globalIndexAndTransform(mesh_));
2204 
2205  // Reset tag
2206  UPstream::msgType(oldTag);
2207  }
2208  return *globalTransformsPtr_;
2209 }
2210 
2211 
2213 {
2214  if (!globalPointSlavesPtr_)
2215  {
2216  calcGlobalPointSlaves();
2217  }
2218  return *globalPointSlavesPtr_;
2219 }
2220 
2221 
2223 const
2224 {
2225  if (!globalPointTransformedSlavesPtr_)
2226  {
2227  calcGlobalPointSlaves();
2228  }
2229  return *globalPointTransformedSlavesPtr_;
2230 }
2231 
2232 
2234 {
2235  if (!globalPointSlavesMapPtr_)
2236  {
2237  calcGlobalPointSlaves();
2238  }
2239  return *globalPointSlavesMapPtr_;
2240 }
2241 
2242 
2244 {
2245  if (!globalEdgeNumberingPtr_)
2246  {
2247  // Allocate unique tag for all comms
2248  const int oldTag = UPstream::incrMsgType();
2249 
2250  globalEdgeNumberingPtr_.reset
2251  (
2252  new globalIndex(coupledPatch().nEdges())
2253  );
2254 
2255  // Reset tag
2256  UPstream::msgType(oldTag);
2257  }
2258  return *globalEdgeNumberingPtr_;
2259 }
2260 
2261 
2263 {
2264  if (!globalEdgeSlavesPtr_)
2265  {
2266  calcGlobalEdgeSlaves();
2267  }
2268  return *globalEdgeSlavesPtr_;
2269 }
2270 
2271 
2273 const
2274 {
2275  if (!globalEdgeTransformedSlavesPtr_)
2276  {
2277  calcGlobalEdgeSlaves();
2278  }
2279  return *globalEdgeTransformedSlavesPtr_;
2280 }
2281 
2282 
2284 {
2285  if (!globalEdgeOrientationPtr_)
2286  {
2287  calcGlobalEdgeOrientation();
2288  }
2289  return *globalEdgeOrientationPtr_;
2290 }
2291 
2292 
2294 {
2295  if (!globalEdgeSlavesMapPtr_)
2296  {
2297  calcGlobalEdgeSlaves();
2298  }
2299  return *globalEdgeSlavesMapPtr_;
2300 }
2301 
2302 
2304 const
2305 {
2306  if (!globalBoundaryFaceNumberingPtr_)
2307  {
2308  calcGlobalPointBoundaryFaces();
2309  }
2310  return *globalBoundaryFaceNumberingPtr_;
2311 }
2312 
2313 
2315 const
2316 {
2317  if (!globalPointBoundaryFacesPtr_)
2318  {
2319  calcGlobalPointBoundaryFaces();
2320  }
2321  return *globalPointBoundaryFacesPtr_;
2322 }
2323 
2324 
2325 const Foam::labelListList&
2327 {
2328  if (!globalPointTransformedBoundaryFacesPtr_)
2329  {
2330  calcGlobalPointBoundaryFaces();
2331  }
2332  return *globalPointTransformedBoundaryFacesPtr_;
2333 }
2334 
2335 
2337 const
2338 {
2339  if (!globalPointBoundaryFacesMapPtr_)
2340  {
2341  calcGlobalPointBoundaryFaces();
2342  }
2343  return *globalPointBoundaryFacesMapPtr_;
2344 }
2345 
2346 
2348 {
2349  if (!boundaryCellsPtr_)
2350  {
2351  calcGlobalPointBoundaryCells();
2352  }
2353  return *boundaryCellsPtr_;
2354 }
2355 
2356 
2358 const
2359 {
2360  if (!globalBoundaryCellNumberingPtr_)
2361  {
2362  calcGlobalPointBoundaryCells();
2363  }
2364  return *globalBoundaryCellNumberingPtr_;
2365 }
2366 
2367 
2369 const
2370 {
2371  if (!globalPointBoundaryCellsPtr_)
2372  {
2373  calcGlobalPointBoundaryCells();
2374  }
2375  return *globalPointBoundaryCellsPtr_;
2376 }
2377 
2378 
2379 const Foam::labelListList&
2381 {
2382  if (!globalPointTransformedBoundaryCellsPtr_)
2383  {
2384  calcGlobalPointBoundaryCells();
2385  }
2386  return *globalPointTransformedBoundaryCellsPtr_;
2387 }
2388 
2389 
2391 const
2392 {
2393  if (!globalPointBoundaryCellsMapPtr_)
2394  {
2395  calcGlobalPointBoundaryCells();
2396  }
2397  return *globalPointBoundaryCellsMapPtr_;
2398 }
2399 
2400 
2402 {
2403  if (!globalCoPointSlavesPtr_)
2404  {
2405  calcGlobalCoPointSlaves();
2406  }
2407  return *globalCoPointSlavesPtr_;
2408 }
2409 
2410 
2412 {
2413  if (!globalCoPointSlavesMapPtr_)
2414  {
2415  calcGlobalCoPointSlaves();
2416  }
2417  return *globalCoPointSlavesMapPtr_;
2418 }
2419 
2420 
2422 (
2423  labelList& pointToGlobal,
2424  labelList& uniquePoints
2425 ) const
2426 {
2427  const indirectPrimitivePatch& cpp = coupledPatch();
2428  const globalIndex& globalCoupledPoints = globalPointNumbering();
2429  // Use collocated only
2430  const labelListList& pointSlaves = globalCoPointSlaves();
2431  const mapDistribute& pointSlavesMap = globalCoPointSlavesMap();
2432 
2433  // Allocate unique tag for all comms
2434  const int oldTag = UPstream::incrMsgType();
2435 
2436  // Points are either
2437  // - master with slaves
2438  // - slave with a master
2439  // - other (since e.g. non-collocated cyclics not connected)
2440 
2441  labelList masterGlobalPoint(cpp.nPoints(), -1);
2442  forAll(masterGlobalPoint, pointi)
2443  {
2444  const labelList& slavePoints = pointSlaves[pointi];
2445  if (slavePoints.size() > 0)
2446  {
2447  masterGlobalPoint[pointi] = globalCoupledPoints.toGlobal(pointi);
2448  }
2449  }
2450 
2451  // Sync by taking max
2452  syncData
2453  (
2454  masterGlobalPoint,
2455  pointSlaves,
2456  labelListList(0), // no transforms
2457  pointSlavesMap,
2458  maxEqOp<label>()
2459  );
2460 
2461 
2462  // 1. Count number of masters on my processor.
2463  label nMaster = 0;
2464  bitSet isMaster(mesh_.nPoints(), true);
2465  forAll(pointSlaves, pointi)
2466  {
2467  if (masterGlobalPoint[pointi] == -1)
2468  {
2469  // unconnected point (e.g. from separated cyclic)
2470  nMaster++;
2471  }
2472  else if
2473  (
2474  masterGlobalPoint[pointi]
2475  == globalCoupledPoints.toGlobal(pointi)
2476  )
2477  {
2478  // connected master
2479  nMaster++;
2480  }
2481  else
2482  {
2483  // connected slave point
2484  isMaster.unset(cpp.meshPoints()[pointi]);
2485  }
2486  }
2487 
2488  label myUniquePoints = mesh_.nPoints() - cpp.nPoints() + nMaster;
2489 
2490  //Pout<< "Points :" << nl
2491  // << " mesh : " << mesh_.nPoints() << nl
2492  // << " of which coupled : " << cpp.nPoints() << nl
2493  // << " of which master : " << nMaster << nl
2494  // << endl;
2495 
2496 
2497  // 2. Create global indexing for unique points.
2498  autoPtr<globalIndex> globalPointsPtr(new globalIndex(myUniquePoints));
2499 
2500 
2501  // 3. Assign global point numbers. Keep slaves unset.
2502  pointToGlobal.setSize(mesh_.nPoints());
2503  pointToGlobal = -1;
2504  uniquePoints.setSize(myUniquePoints);
2505  nMaster = 0;
2506 
2507  forAll(isMaster, meshPointi)
2508  {
2509  if (isMaster[meshPointi])
2510  {
2511  pointToGlobal[meshPointi] = globalPointsPtr().toGlobal(nMaster);
2512  uniquePoints[nMaster] = meshPointi;
2513  nMaster++;
2514  }
2515  }
2516 
2517 
2518  // 4. Push global index for coupled points to slaves.
2519  {
2520  labelList masterToGlobal(pointSlavesMap.constructSize(), -1);
2521 
2522  forAll(pointSlaves, pointi)
2523  {
2524  const labelList& slaves = pointSlaves[pointi];
2525 
2526  if (slaves.size() > 0)
2527  {
2528  // Duplicate master globalpoint into slave slots
2529  label meshPointi = cpp.meshPoints()[pointi];
2530  masterToGlobal[pointi] = pointToGlobal[meshPointi];
2531  forAll(slaves, i)
2532  {
2533  masterToGlobal[slaves[i]] = masterToGlobal[pointi];
2534  }
2535  }
2536  }
2537 
2538  // Send back
2539  pointSlavesMap.reverseDistribute(cpp.nPoints(), masterToGlobal);
2540 
2541  // On slave copy master index into overal map.
2542  forAll(pointSlaves, pointi)
2543  {
2544  label meshPointi = cpp.meshPoints()[pointi];
2545 
2546  if (!isMaster[meshPointi])
2547  {
2548  pointToGlobal[meshPointi] = masterToGlobal[pointi];
2549  }
2550  }
2551  }
2552 
2553  // Restore tag
2555 
2556  return globalPointsPtr;
2557 }
2558 
2559 
2561 (
2562  const labelUList& meshPoints,
2563  const Map<label>& /* unused: meshPointMap */,
2564  labelList& pointToGlobal,
2565  labelList& uniqueMeshPoints
2566 ) const
2567 {
2568  const indirectPrimitivePatch& cpp = coupledPatch();
2569  const labelListList& pointSlaves = globalCoPointSlaves();
2570  const mapDistribute& pointSlavesMap = globalCoPointSlavesMap();
2571 
2572 
2573  // The patch points come in two variants:
2574  // - not on a coupled patch so guaranteed unique
2575  // - on a coupled patch
2576  // If the point is on a coupled patch the problem is that the
2577  // master-slave structure (globalPointSlaves etc.) assigns one of the
2578  // coupled points to be the master but this master point is not
2579  // necessarily on the patch itself! (it might just be connected to the
2580  // patch point via coupled patches).
2581 
2582 
2583  // Allocate unique tag for all comms
2584  const int oldTag = UPstream::incrMsgType();
2585 
2586  // Determine mapping:
2587  // - from patch point to coupled point (or -1)
2588  // - from coupled point to global patch point
2589  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2590 
2591  const globalIndex globalPPoints(meshPoints.size());
2592 
2593  labelList patchToCoupled(meshPoints.size(), -1);
2594  labelList coupledToGlobalPatch(pointSlavesMap.constructSize(), -1);
2595  //label nCoupled = 0;
2596 
2597  // Note: loop over patch since usually smaller
2598  forAll(meshPoints, patchPointi)
2599  {
2600  label meshPointi = meshPoints[patchPointi];
2601 
2602  const auto iter = cpp.meshPointMap().cfind(meshPointi);
2603 
2604  if (iter.good())
2605  {
2606  patchToCoupled[patchPointi] = iter();
2607  coupledToGlobalPatch[iter()] = globalPPoints.toGlobal(patchPointi);
2608  //++nCoupled;
2609  }
2610  }
2611 
2612  //Pout<< "Patch:" << nl
2613  // << " points:" << meshPoints.size() << nl
2614  // << " of which on coupled patch:" << nCoupled << endl;
2615 
2616 
2617  // Determine master of connected points
2618  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2619  // Problem is that the coupled master might not be on the patch. So
2620  // work out the best patch-point master from all connected points.
2621  // - if the coupled master is on the patch it becomes the patch-point master
2622  // - else the slave with the lowest numbered patch point label
2623 
2624  // Get all data on master
2625  pointSlavesMap.distribute(coupledToGlobalPatch);
2626  forAll(pointSlaves, coupledPointi)
2627  {
2628  const labelList& slaves = pointSlaves[coupledPointi];
2629 
2630  if (slaves.size() > 0)
2631  {
2632  // I am master. What is the best candidate for patch-point master
2633  label masterI = labelMax;
2634  if (coupledToGlobalPatch[coupledPointi] != -1)
2635  {
2636  // I am master and on the coupled patch. Use me.
2637  masterI = coupledToGlobalPatch[coupledPointi];
2638  }
2639  else
2640  {
2641  // Get min of slaves as master.
2642  forAll(slaves, i)
2643  {
2644  label slavePp = coupledToGlobalPatch[slaves[i]];
2645  if (slavePp != -1 && slavePp < masterI)
2646  {
2647  masterI = slavePp;
2648  }
2649  }
2650  }
2651 
2652  if (masterI != labelMax)
2653  {
2654  // Push back
2655  coupledToGlobalPatch[coupledPointi] = masterI;
2656  forAll(slaves, i)
2657  {
2658  coupledToGlobalPatch[slaves[i]] = masterI;
2659  }
2660  }
2661  }
2662  }
2663  pointSlavesMap.reverseDistribute(cpp.nPoints(), coupledToGlobalPatch);
2664 
2665 
2666  // Generate compact numbering for master points
2667  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2668  // Now coupledToGlobalPatch is the globalIndex of the master point.
2669  // Now every processor can check whether they hold it and generate a
2670  // compact numbering.
2671 
2672  label nMasters = 0;
2673  forAll(meshPoints, patchPointi)
2674  {
2675  if (patchToCoupled[patchPointi] == -1)
2676  {
2677  nMasters++;
2678  }
2679  else
2680  {
2681  label coupledPointi = patchToCoupled[patchPointi];
2682  if
2683  (
2684  globalPPoints.toGlobal(patchPointi)
2685  == coupledToGlobalPatch[coupledPointi]
2686  )
2687  {
2688  // I am the master
2689  nMasters++;
2690  }
2691  }
2692  }
2693 
2694  autoPtr<globalIndex> globalPointsPtr(new globalIndex(nMasters));
2695 
2696  //Pout<< "Patch:" << nl
2697  // << " points:" << meshPoints.size() << nl
2698  // << " of which on coupled patch:" << nCoupled << nl
2699  // << " of which master:" << nMasters << endl;
2700 
2701 
2702 
2703  // Push back compact numbering for master point onto slaves
2704  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2705 
2706  pointToGlobal.setSize(meshPoints.size());
2707  pointToGlobal = -1;
2708  uniqueMeshPoints.setSize(nMasters);
2709 
2710  // Sync master in global point numbering so all know the master point.
2711  // Initialise globalMaster to be -1 except at a globalMaster.
2712  labelList globalMaster(cpp.nPoints(), -1);
2713 
2714  nMasters = 0;
2715  forAll(meshPoints, patchPointi)
2716  {
2717  if (patchToCoupled[patchPointi] == -1)
2718  {
2719  uniqueMeshPoints[nMasters++] = meshPoints[patchPointi];
2720  }
2721  else
2722  {
2723  label coupledPointi = patchToCoupled[patchPointi];
2724  if
2725  (
2726  globalPPoints.toGlobal(patchPointi)
2727  == coupledToGlobalPatch[coupledPointi]
2728  )
2729  {
2730  globalMaster[coupledPointi] =
2731  globalPointsPtr().toGlobal(nMasters);
2732  uniqueMeshPoints[nMasters++] = meshPoints[patchPointi];
2733  }
2734  }
2735  }
2736 
2737 
2738  // Sync by taking max
2739  syncData
2740  (
2741  globalMaster,
2742  pointSlaves,
2743  labelListList(0), // no transforms
2744  pointSlavesMap,
2745  maxEqOp<label>()
2746  );
2747 
2748 
2749  // Now everyone has the master point in globalPointsPtr numbering. Fill
2750  // in the pointToGlobal map.
2751  nMasters = 0;
2752  forAll(meshPoints, patchPointi)
2753  {
2754  if (patchToCoupled[patchPointi] == -1)
2755  {
2756  pointToGlobal[patchPointi] = globalPointsPtr().toGlobal(nMasters++);
2757  }
2758  else
2759  {
2760  label coupledPointi = patchToCoupled[patchPointi];
2761  pointToGlobal[patchPointi] = globalMaster[coupledPointi];
2762 
2763  if
2764  (
2765  globalPPoints.toGlobal(patchPointi)
2766  == coupledToGlobalPatch[coupledPointi]
2767  )
2768  {
2769  nMasters++;
2770  }
2771  }
2772  }
2773 
2774  // Restore tag
2775  UPstream::msgType(oldTag);
2776 
2777  return globalPointsPtr;
2778 }
2779 
2780 
2781 void Foam::globalMeshData::movePoints(const pointField& newPoints)
2782 {
2783  // Topology does not change and we don't store any geometry so nothing
2784  // needs to be done.
2785  // Only global transformations might change but this is not really
2786  // supported.
2787 }
2788 
2789 
2791 {
2792  // Clear out old data
2793  clearOut();
2794 
2795  // Do processor patch addressing
2796  initProcAddr();
2797 
2798  scalar tolDim = matchTol_ * mesh_.bounds().mag();
2799 
2800  if (debug)
2801  {
2802  Pout<< "globalMeshData : merge dist:" << tolDim << endl;
2803  }
2804 
2805 
2806  const label comm = mesh_.comm();
2807  const label oldWarnComm = UPstream::commWarn(comm);
2808 
2809  if (UPstream::is_parallel(comm))
2810  {
2811  const label myProci = UPstream::myProcNo(comm);
2812  const label numProc = UPstream::nProcs(comm);
2813 
2814  // Gather all three sizes together
2815  labelList allSizes(3*numProc);
2816  {
2817  label* tup = allSizes.begin(3*myProci);
2818  tup[0] = mesh_.nPoints();
2819  tup[1] = mesh_.nFaces();
2820  tup[2] = mesh_.nCells();
2821  }
2822 
2823  UPstream::mpiAllGather(allSizes.data(), 3, comm);
2824 
2825  // Extract counts per mesh entity
2826  // TBD: check for label overflow?
2827 
2828  labelList counts(numProc);
2829  for (label proci = 0, idx = 0; proci < numProc; ++proci, idx += 3)
2830  {
2831  counts[proci] = allSizes[idx];
2832  }
2833  globalMeshPointAddr_.reset(counts);
2834 
2835  for (label proci = 0, idx = 1; proci < numProc; ++proci, idx += 3)
2836  {
2837  counts[proci] = allSizes[idx];
2838  }
2839  globalMeshFaceAddr_.reset(counts);
2840 
2841  for (label proci = 0, idx = 2; proci < numProc; ++proci, idx += 3)
2842  {
2843  counts[proci] = allSizes[idx];
2844  }
2845  globalMeshCellAddr_.reset(counts);
2846  }
2847  else
2848  {
2849  globalMeshPointAddr_.reset(globalIndex::gatherNone{}, mesh_.nPoints());
2850  globalMeshFaceAddr_.reset(globalIndex::gatherNone{}, mesh_.nFaces());
2851  globalMeshCellAddr_.reset(globalIndex::gatherNone{}, mesh_.nCells());
2852  }
2853 
2854  // Restore communicator settings
2855  UPstream::commWarn(oldWarnComm);
2856 
2857  if (debug)
2858  {
2859  Info<< "globalMeshData : Total points/faces/cells : ("
2860  << nTotalPoints() << ' '
2861  << nTotalFaces() << ' '
2862  << nTotalCells() << ')' << endl;
2863  }
2864 }
2865 
2866 
2867 // ************************************************************************* //
const labelList & sharedPointLabels() const
Return indices of local points that are globally shared.
const Map< label > & coupledPatchMeshEdgeMap() const
Return map from mesh edges to coupledPatch edges.
label comm() const noexcept
The communicator used for parallel communication.
Definition: polyMesh.H:701
label nPoints() const
Number of points supporting patch faces.
const labelListList & globalPointSlaves() const
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
const mapDistribute & globalCoPointSlavesMap() const
const labelListList & globalPointTransformedSlaves() const
pointField geometricSharedPoints() const
Like sharedPoints but keeps cyclic points separate. (does geometric merging; uses matchTol_*bb as mer...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
static int incrMsgType(int val=1) noexcept
Increment the message tag for standard messages.
Definition: UPstream.H:1809
const globalIndex & globalBoundaryCellNumbering() const
Numbering of boundary cells is according to boundaryCells()
labelList pointLabels(nPoints, -1)
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:150
const labelList & sharedPointGlobalLabels() const
Return shared point global labels. Tries to read &#39;pointProcAddressing&#39; and returns list or -1 if none...
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:600
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:526
List< edge > edgeList
List of edge.
Definition: edgeList.H:32
void distribute(List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Distribute List data using default commsType, default flip/negate operator.
const labelListList & globalPointTransformedBoundaryFaces() const
const mapDistribute & globalEdgeSlavesMap() const
static const Foam::scalar matchTol_
Geometric tolerance (fraction of bounding box)
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
void clearOut()
Remove all demand driven data.
UIndirectList< label > labelUIndList
UIndirectList of labels.
Definition: IndirectList.H:65
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:411
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1586
const mapDistribute & globalPointSlavesMap() const
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
const bitSet & globalEdgeOrientation() const
Is my edge same orientation as master edge.
label constructSize() const noexcept
Constructed data size.
const labelListList & globalPointBoundaryCells() const
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:168
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:1787
List< labelPair > labelPairList
List of labelPair.
Definition: labelPair.H:33
autoPtr< globalIndex > mergePoints(labelList &pointToGlobal, labelList &uniquePoints) const
Helper for merging (collocated!) mesh point data.
static void broadcast(Type &value, const int communicator=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
const labelListList & globalEdgeSlaves() const
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition: UPstream.H:1611
const labelList & coupledPatchMeshEdges() const
Return map from coupledPatch edges to mesh edges.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field...
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
const labelListList & globalPointBoundaryFaces() const
const dimensionedScalar me
Electron mass.
static bool less(const vector &x, const vector &y)
To compare normals.
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
const labelList & boundaryCells() const
From boundary cell to mesh cell.
static label commWarn(const label communicator) noexcept
Alter communicator debugging setting. Warns for use of any communicator differing from specified...
Definition: UPstream.H:1040
label nGlobalEdges() const
Return number of globally shared edges.
List helper to append y elements onto the end of x.
Definition: ListOps.H:711
scalar y
A list of faces which address into the list of points.
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:61
const globalIndex & globalEdgeNumbering() const
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1602
label nGlobalPoints() const
Return number of globally shared points.
const Map< label > & meshPointMap() const
Mesh point map.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const labelList & sharedEdgeAddr() const
Return addressing into the complete globally shared edge list.
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:325
dynamicFvMesh & mesh
const globalIndexAndTransform & globalTransforms() const
Global transforms numbering.
"scheduled" (MPI standard) : (MPI_Send, MPI_Recv)
static void recv(Type &value, const int fromProcNo, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, IOstreamOption::streamFormat fmt=IOstreamOption::BINARY)
Receive and deserialize a value. Uses operator>> for de-serialization.
Definition: IPstream.H:80
static int compare(const Pair< label > &a, const Pair< label > &b)
Compare Pairs.
Definition: PairI.H:24
const_iterator cfind(const Key &key) const
Find and return an const_iterator set at the hashed entry.
Definition: HashTableI.H:113
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:609
label nPoints
void sort(UList< T > &list)
Sort the list.
Definition: UList.C:295
static constexpr int masterNo() noexcept
Relative rank for the master process - is always 0.
Definition: UPstream.H:1596
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
const globalIndex & globalPointNumbering() const
Numbering of coupled points is according to coupledPatch.
static bool is_parallel(const label communicator=worldComm)
True if parallel algorithm or exchange is required.
Definition: UPstream.H:1648
label inplaceMergePoints(PointList &points, const scalar mergeTol, const bool verbose, labelList &pointToUnique)
Inplace merge points, preserving the original point order. All points closer/equal mergeTol are to be...
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
errorManip< error > abort(error &err)
Definition: errorManip.H:139
void reverseDistribute(const label constructSize, List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Reverse distribute data using default commsType.
static void mpiAllGather(Type *allData, int count, const int communicator=UPstream::worldComm)
Gather/scatter identically-sized data.
refinementData transform(const tensor &, const refinementData val)
No-op rotational transform for base types.
int debug
Static debugging option.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:51
~globalMeshData()
Destructor.
defineTypeNameAndDebug(combustionModel, 0)
Geometric merging of points. See below.
labelList f(nPoints)
Define the processor-processor connection table by walking a list of patches and detecting the proces...
void movePoints(const pointField &newPoints)
Update for moving points.
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
static void combineReduce(T &value, CombineOp cop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) applying cop to inplace combine value from different processors...
const labelListList & globalPointTransformedBoundaryCells() const
void operator()(T &x, const T &y) const
Definition: ops.H:74
Class containing processor-to-processor mapping information.
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1619
void updateMesh()
Change global mesh data given a topological change. Does a.
messageStream Info
Information stream (stdout output on master, null elsewhere)
constexpr label labelMax
Definition: label.H:55
label n
static rangeType subProcs(const label communicator=worldComm)
Range of process indices for sub-processes.
Definition: UPstream.H:1727
List< label > labelList
A List of labels.
Definition: List.H:61
const mapDistribute & globalPointBoundaryFacesMap() const
const labelList & sharedPointAddr() const
Return addressing into the complete globally shared points list.
bool send()
Send buffer contents now and not in destructor [advanced usage]. Returns true on success.
Definition: OPstreams.C:84
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:180
pointField sharedPoints() const
Collect coordinates of shared points on all processors. (does parallel communication!) ...
PrimitivePatch< List< face >, const pointField > bMesh
Holder of faceList and points. (v.s. e.g. primitivePatch which references points) ...
Definition: bMesh.H:39
Map< label > invertToMap(const labelUList &values)
Create inverse mapping, which is a lookup table into the given list.
Definition: ListOps.C:105
const mapDistribute & globalPointBoundaryCellsMap() const
bool found
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
const labelList & sharedEdgeLabels() const
Return indices of local edges that are globally shared.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
Determination and storage of the possible independent transforms introduced by coupledPolyPatches, as well as all of the possible permutations of these transforms generated by the presence of multiple coupledPolyPatches, i.e. more than one cyclic boundary. Note that any given point can be on maximum 3 transforms only (and these transforms have to be perpendicular)
const labelListList & globalCoPointSlaves() const
A HashTable to objects of type <T> with a label key.
const labelListList & globalEdgeTransformedSlaves() const
globalMeshData(const globalMeshData &)=delete
No copy construct.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127
const globalIndex & globalBoundaryFaceNumbering() const
Numbering of boundary faces is face-mesh.nInternalFaces()