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  globalMeshPointAddr_(),
1798  globalMeshFaceAddr_(),
1799  globalMeshCellAddr_(),
1800  processorTopology_
1801  (
1802  processorTopology::New<processorPolyPatch>
1803  (
1804  mesh.boundaryMesh(),
1805  mesh_.comm()
1806  )
1807  ),
1808  processorPatches_(),
1809  processorPatchIndices_(),
1810  processorPatchNeighbours_(),
1811  nGlobalPoints_(-1),
1812  sharedPointLabelsPtr_(nullptr),
1813  sharedPointAddrPtr_(nullptr),
1814  sharedPointGlobalLabelsPtr_(nullptr),
1815  nGlobalEdges_(-1),
1816  sharedEdgeLabelsPtr_(nullptr),
1817  sharedEdgeAddrPtr_(nullptr)
1818 {
1820 }
1821 
1822 
1823 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1824 
1825 // A non-default destructor since we had incomplete types in the header
1827 {}
1828 
1829 
1831 {
1832  // Point
1833  nGlobalPoints_ = -1;
1834  sharedPointLabelsPtr_.clear();
1835  sharedPointAddrPtr_.clear();
1836  sharedPointGlobalLabelsPtr_.clear();
1837 
1838  // Edge
1839  nGlobalEdges_ = -1;
1840  sharedEdgeLabelsPtr_.clear();
1841  sharedEdgeAddrPtr_.clear();
1842 
1843  // Coupled patch
1844  coupledPatchPtr_.clear();
1845  coupledPatchMeshEdgesPtr_.clear();
1846  coupledPatchMeshEdgeMapPtr_.clear();
1847  globalTransformsPtr_.clear();
1848 
1849  // Point
1850  globalPointNumberingPtr_.clear();
1851  globalPointSlavesPtr_.clear();
1852  globalPointTransformedSlavesPtr_.clear();
1853  globalPointSlavesMapPtr_.clear();
1854 
1855  // Edge
1856  globalEdgeNumberingPtr_.clear();
1857  globalEdgeSlavesPtr_.clear();
1858  globalEdgeTransformedSlavesPtr_.clear();
1859  globalEdgeOrientationPtr_.clear();
1860  globalEdgeSlavesMapPtr_.clear();
1861 
1862  // Face
1863  globalBoundaryFaceNumberingPtr_.clear();
1864  globalPointBoundaryFacesPtr_.clear();
1865  globalPointTransformedBoundaryFacesPtr_.clear();
1866  globalPointBoundaryFacesMapPtr_.clear();
1867 
1868  // Cell
1869  boundaryCellsPtr_.clear();
1870  globalBoundaryCellNumberingPtr_.clear();
1871  globalPointBoundaryCellsPtr_.clear();
1872  globalPointTransformedBoundaryCellsPtr_.clear();
1873  globalPointBoundaryCellsMapPtr_.clear();
1874 
1875  // Other: collocated points
1876  globalCoPointSlavesPtr_.clear();
1877  globalCoPointSlavesMapPtr_.clear();
1878 }
1879 
1880 
1881 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1882 
1884 {
1885  if (!sharedPointGlobalLabelsPtr_)
1886  {
1887  sharedPointGlobalLabelsPtr_.reset
1888  (
1889  new labelList(sharedPointLabels().size())
1890  );
1891  labelList& sharedPointGlobalLabels = sharedPointGlobalLabelsPtr_();
1892 
1893  IOobject addrHeader
1894  (
1895  "pointProcAddressing",
1896  mesh_.facesInstance()/polyMesh::meshSubDir,
1897  mesh_,
1899  );
1900 
1901  if (addrHeader.typeHeaderOk<labelIOList>(true))
1902  {
1903  // There is a pointProcAddressing file so use it to get labels
1904  // on the original mesh
1905  Pout<< "globalMeshData::sharedPointGlobalLabels : "
1906  << "Reading pointProcAddressing" << endl;
1907 
1908  labelIOList pointProcAddressing(addrHeader);
1909 
1910  const labelList& pointLabels = sharedPointLabels();
1911 
1912  forAll(pointLabels, i)
1913  {
1914  // Get my mesh point
1915  label pointi = pointLabels[i];
1916 
1917  // Map to mesh point of original mesh
1918  sharedPointGlobalLabels[i] = pointProcAddressing[pointi];
1919  }
1920  }
1921  else
1922  {
1923  Pout<< "globalMeshData::sharedPointGlobalLabels :"
1924  << " Setting pointProcAddressing to -1" << endl;
1925 
1926  sharedPointGlobalLabels = -1;
1927  }
1928  }
1929 
1930  return *sharedPointGlobalLabelsPtr_;
1931 }
1932 
1933 
1935 {
1936  // Get all processors to send their shared points to master.
1937  // (not very efficient)
1938 
1939  // Allocate unique tag for all comms
1940  const int oldTag = UPstream::incrMsgType();
1941 
1942  pointField sharedPoints(nGlobalPoints());
1943  const labelList& pointAddr = sharedPointAddr();
1944  const labelList& pointLabels = sharedPointLabels();
1945 
1946  if (UPstream::master())
1947  {
1948  // Master:
1949  // insert my own data first
1950  forAll(pointLabels, i)
1951  {
1952  label sharedPointi = pointAddr[i];
1953 
1954  sharedPoints[sharedPointi] = mesh_.points()[pointLabels[i]];
1955  }
1956 
1957  // Receive data and insert
1958  for (const int proci : UPstream::subProcs())
1959  {
1960  IPstream fromProc(UPstream::commsTypes::scheduled, proci);
1961 
1962  labelList nbrSharedPointAddr;
1963  pointField nbrSharedPoints;
1964  fromProc >> nbrSharedPointAddr >> nbrSharedPoints;
1965 
1966  forAll(nbrSharedPointAddr, i)
1967  {
1968  label sharedPointi = nbrSharedPointAddr[i];
1969 
1970  sharedPoints[sharedPointi] = nbrSharedPoints[i];
1971  }
1972  }
1973  }
1974  else
1975  {
1976  if (UPstream::parRun())
1977  {
1978  // Send address and points
1979  OPstream toMaster
1980  (
1983  );
1984  toMaster
1985  << pointAddr
1986  << pointField(mesh_.points(), pointLabels);
1987  }
1988  }
1989 
1990  // Broadcast: sharedPoints to all
1991  Pstream::broadcast(sharedPoints); // == worldComm
1992 
1993  // Reset tag
1994  UPstream::msgType(oldTag);
1995 
1996  return sharedPoints;
1997 }
1998 
1999 
2001 {
2002  // Allocate unique tag for all comms
2003  const int oldTag = UPstream::incrMsgType();
2004 
2005  // Get coords of my shared points
2006  pointField sharedPoints(mesh_.points(), sharedPointLabels());
2007 
2008  // Append from all processors, globally consistent
2010 
2011  // Merge tolerance
2012  scalar tolDim = matchTol_ * mesh_.bounds().mag();
2013 
2014  labelList pointMap;
2016  (
2017  sharedPoints, // coordinates to merge
2018  tolDim, // tolerance
2019  false, // verbosity
2020  pointMap
2021  );
2022 
2023  // Reset tag
2024  UPstream::msgType(oldTag);
2025 
2026  return sharedPoints;
2027 }
2028 
2029 
2030 Foam::label Foam::globalMeshData::nGlobalPoints() const
2031 {
2032  if (nGlobalPoints_ == -1)
2033  {
2034  calcSharedPoints();
2035  }
2036  return nGlobalPoints_;
2037 }
2038 
2039 
2041 {
2042  if (!sharedPointLabelsPtr_)
2043  {
2044  calcSharedPoints();
2045  }
2046  return *sharedPointLabelsPtr_;
2047 }
2048 
2049 
2051 {
2052  if (!sharedPointAddrPtr_)
2053  {
2054  calcSharedPoints();
2055  }
2056  return *sharedPointAddrPtr_;
2057 }
2058 
2059 
2060 Foam::label Foam::globalMeshData::nGlobalEdges() const
2061 {
2062  if (nGlobalEdges_ == -1)
2063  {
2064  calcSharedEdges();
2065  }
2066  return nGlobalEdges_;
2067 }
2068 
2069 
2071 {
2072  if (!sharedEdgeLabelsPtr_)
2073  {
2074  calcSharedEdges();
2075  }
2076  return *sharedEdgeLabelsPtr_;
2077 }
2078 
2079 
2081 {
2082  if (!sharedEdgeAddrPtr_)
2083  {
2084  calcSharedEdges();
2085  }
2086  return *sharedEdgeAddrPtr_;
2087 }
2088 
2089 
2091 {
2092  if (!coupledPatchPtr_)
2093  {
2094  const polyBoundaryMesh& bMesh = mesh_.boundaryMesh();
2095 
2096  label nCoupled = 0;
2097 
2098  forAll(bMesh, patchi)
2099  {
2100  const polyPatch& pp = bMesh[patchi];
2101 
2102  if (pp.coupled())
2103  {
2104  nCoupled += pp.size();
2105  }
2106  }
2107  labelList coupledFaces(nCoupled);
2108  nCoupled = 0;
2109 
2110  forAll(bMesh, patchi)
2111  {
2112  const polyPatch& pp = bMesh[patchi];
2113 
2114  if (pp.coupled())
2115  {
2116  label facei = pp.start();
2117 
2118  forAll(pp, i)
2119  {
2120  coupledFaces[nCoupled++] = facei++;
2121  }
2122  }
2123  }
2124 
2125  coupledPatchPtr_.reset
2126  (
2128  (
2129  IndirectList<face>
2130  (
2131  mesh_.faces(),
2132  coupledFaces
2133  ),
2134  mesh_.points()
2135  )
2136  );
2137 
2138  if (debug)
2139  {
2140  Pout<< "globalMeshData::coupledPatch() :"
2141  << " constructed coupled faces patch:"
2142  << " faces:" << coupledPatchPtr_().size()
2143  << " points:" << coupledPatchPtr_().nPoints()
2144  << endl;
2145  }
2146  }
2147  return *coupledPatchPtr_;
2148 }
2149 
2150 
2152 {
2153  if (!coupledPatchMeshEdgesPtr_)
2154  {
2155  coupledPatchMeshEdgesPtr_.reset
2156  (
2157  new labelList
2158  (
2159  coupledPatch().meshEdges
2160  (
2161  mesh_.edges(),
2162  mesh_.pointEdges()
2163  )
2164  )
2165  );
2166  }
2167  return *coupledPatchMeshEdgesPtr_;
2168 }
2169 
2170 
2172 const
2173 {
2174  if (!coupledPatchMeshEdgeMapPtr_)
2175  {
2176  const labelList& me = coupledPatchMeshEdges();
2177 
2178  coupledPatchMeshEdgeMapPtr_.reset
2179  (
2181  );
2182  }
2183  return *coupledPatchMeshEdgeMapPtr_;
2184 }
2185 
2186 
2188 {
2189  if (!globalPointNumberingPtr_)
2190  {
2191  // Allocate unique tag for all comms
2192  const int oldTag = UPstream::incrMsgType();
2193 
2194  globalPointNumberingPtr_.reset
2195  (
2196  new globalIndex(coupledPatch().nPoints())
2197  );
2198 
2199  // Reset tag
2201  }
2202  return *globalPointNumberingPtr_;
2203 }
2204 
2205 
2208 {
2209  if (!globalTransformsPtr_)
2210  {
2211  // Allocate unique tag for all comms
2212  const int oldTag = UPstream::incrMsgType();
2213 
2214  globalTransformsPtr_.reset(new globalIndexAndTransform(mesh_));
2215 
2216  // Reset tag
2217  UPstream::msgType(oldTag);
2218  }
2219  return *globalTransformsPtr_;
2220 }
2221 
2222 
2224 {
2225  if (!globalPointSlavesPtr_)
2226  {
2227  calcGlobalPointSlaves();
2228  }
2229  return *globalPointSlavesPtr_;
2230 }
2231 
2232 
2234 const
2235 {
2236  if (!globalPointTransformedSlavesPtr_)
2237  {
2238  calcGlobalPointSlaves();
2239  }
2240  return *globalPointTransformedSlavesPtr_;
2241 }
2242 
2243 
2245 {
2246  if (!globalPointSlavesMapPtr_)
2247  {
2248  calcGlobalPointSlaves();
2249  }
2250  return *globalPointSlavesMapPtr_;
2251 }
2252 
2253 
2255 {
2256  if (!globalEdgeNumberingPtr_)
2257  {
2258  // Allocate unique tag for all comms
2259  const int oldTag = UPstream::incrMsgType();
2260 
2261  globalEdgeNumberingPtr_.reset
2262  (
2263  new globalIndex(coupledPatch().nEdges())
2264  );
2265 
2266  // Reset tag
2267  UPstream::msgType(oldTag);
2268  }
2269  return *globalEdgeNumberingPtr_;
2270 }
2271 
2272 
2274 {
2275  if (!globalEdgeSlavesPtr_)
2276  {
2277  calcGlobalEdgeSlaves();
2278  }
2279  return *globalEdgeSlavesPtr_;
2280 }
2281 
2282 
2284 const
2285 {
2286  if (!globalEdgeTransformedSlavesPtr_)
2287  {
2288  calcGlobalEdgeSlaves();
2289  }
2290  return *globalEdgeTransformedSlavesPtr_;
2291 }
2292 
2293 
2295 {
2296  if (!globalEdgeOrientationPtr_)
2297  {
2298  calcGlobalEdgeOrientation();
2299  }
2300  return *globalEdgeOrientationPtr_;
2301 }
2302 
2303 
2305 {
2306  if (!globalEdgeSlavesMapPtr_)
2307  {
2308  calcGlobalEdgeSlaves();
2309  }
2310  return *globalEdgeSlavesMapPtr_;
2311 }
2312 
2313 
2315 const
2316 {
2317  if (!globalBoundaryFaceNumberingPtr_)
2318  {
2319  calcGlobalPointBoundaryFaces();
2320  }
2321  return *globalBoundaryFaceNumberingPtr_;
2322 }
2323 
2324 
2326 const
2327 {
2328  if (!globalPointBoundaryFacesPtr_)
2329  {
2330  calcGlobalPointBoundaryFaces();
2331  }
2332  return *globalPointBoundaryFacesPtr_;
2333 }
2334 
2335 
2336 const Foam::labelListList&
2338 {
2339  if (!globalPointTransformedBoundaryFacesPtr_)
2340  {
2341  calcGlobalPointBoundaryFaces();
2342  }
2343  return *globalPointTransformedBoundaryFacesPtr_;
2344 }
2345 
2346 
2348 const
2349 {
2350  if (!globalPointBoundaryFacesMapPtr_)
2351  {
2352  calcGlobalPointBoundaryFaces();
2353  }
2354  return *globalPointBoundaryFacesMapPtr_;
2355 }
2356 
2357 
2359 {
2360  if (!boundaryCellsPtr_)
2361  {
2362  calcGlobalPointBoundaryCells();
2363  }
2364  return *boundaryCellsPtr_;
2365 }
2366 
2367 
2369 const
2370 {
2371  if (!globalBoundaryCellNumberingPtr_)
2372  {
2373  calcGlobalPointBoundaryCells();
2374  }
2375  return *globalBoundaryCellNumberingPtr_;
2376 }
2377 
2378 
2380 const
2381 {
2382  if (!globalPointBoundaryCellsPtr_)
2383  {
2384  calcGlobalPointBoundaryCells();
2385  }
2386  return *globalPointBoundaryCellsPtr_;
2387 }
2388 
2389 
2390 const Foam::labelListList&
2392 {
2393  if (!globalPointTransformedBoundaryCellsPtr_)
2394  {
2395  calcGlobalPointBoundaryCells();
2396  }
2397  return *globalPointTransformedBoundaryCellsPtr_;
2398 }
2399 
2400 
2402 const
2403 {
2404  if (!globalPointBoundaryCellsMapPtr_)
2405  {
2406  calcGlobalPointBoundaryCells();
2407  }
2408  return *globalPointBoundaryCellsMapPtr_;
2409 }
2410 
2411 
2413 {
2414  if (!globalCoPointSlavesPtr_)
2415  {
2416  calcGlobalCoPointSlaves();
2417  }
2418  return *globalCoPointSlavesPtr_;
2419 }
2420 
2421 
2423 {
2424  if (!globalCoPointSlavesMapPtr_)
2425  {
2426  calcGlobalCoPointSlaves();
2427  }
2428  return *globalCoPointSlavesMapPtr_;
2429 }
2430 
2431 
2433 (
2434  labelList& pointToGlobal,
2435  labelList& uniquePoints
2436 ) const
2437 {
2438  const indirectPrimitivePatch& cpp = coupledPatch();
2439  const globalIndex& globalCoupledPoints = globalPointNumbering();
2440  // Use collocated only
2441  const labelListList& pointSlaves = globalCoPointSlaves();
2442  const mapDistribute& pointSlavesMap = globalCoPointSlavesMap();
2443 
2444  // Allocate unique tag for all comms
2445  const int oldTag = UPstream::incrMsgType();
2446 
2447  // Points are either
2448  // - master with slaves
2449  // - slave with a master
2450  // - other (since e.g. non-collocated cyclics not connected)
2451 
2452  labelList masterGlobalPoint(cpp.nPoints(), -1);
2453  forAll(masterGlobalPoint, pointi)
2454  {
2455  const labelList& slavePoints = pointSlaves[pointi];
2456  if (slavePoints.size() > 0)
2457  {
2458  masterGlobalPoint[pointi] = globalCoupledPoints.toGlobal(pointi);
2459  }
2460  }
2461 
2462  // Sync by taking max
2463  syncData
2464  (
2465  masterGlobalPoint,
2466  pointSlaves,
2467  labelListList(0), // no transforms
2468  pointSlavesMap,
2469  maxEqOp<label>()
2470  );
2471 
2472 
2473  // 1. Count number of masters on my processor.
2474  label nMaster = 0;
2475  bitSet isMaster(mesh_.nPoints(), true);
2476  forAll(pointSlaves, pointi)
2477  {
2478  if (masterGlobalPoint[pointi] == -1)
2479  {
2480  // unconnected point (e.g. from separated cyclic)
2481  nMaster++;
2482  }
2483  else if
2484  (
2485  masterGlobalPoint[pointi]
2486  == globalCoupledPoints.toGlobal(pointi)
2487  )
2488  {
2489  // connected master
2490  nMaster++;
2491  }
2492  else
2493  {
2494  // connected slave point
2495  isMaster.unset(cpp.meshPoints()[pointi]);
2496  }
2497  }
2498 
2499  label myUniquePoints = mesh_.nPoints() - cpp.nPoints() + nMaster;
2500 
2501  //Pout<< "Points :" << nl
2502  // << " mesh : " << mesh_.nPoints() << nl
2503  // << " of which coupled : " << cpp.nPoints() << nl
2504  // << " of which master : " << nMaster << nl
2505  // << endl;
2506 
2507 
2508  // 2. Create global indexing for unique points.
2509  autoPtr<globalIndex> globalPointsPtr(new globalIndex(myUniquePoints));
2510 
2511 
2512  // 3. Assign global point numbers. Keep slaves unset.
2513  pointToGlobal.setSize(mesh_.nPoints());
2514  pointToGlobal = -1;
2515  uniquePoints.setSize(myUniquePoints);
2516  nMaster = 0;
2517 
2518  forAll(isMaster, meshPointi)
2519  {
2520  if (isMaster[meshPointi])
2521  {
2522  pointToGlobal[meshPointi] = globalPointsPtr().toGlobal(nMaster);
2523  uniquePoints[nMaster] = meshPointi;
2524  nMaster++;
2525  }
2526  }
2527 
2528 
2529  // 4. Push global index for coupled points to slaves.
2530  {
2531  labelList masterToGlobal(pointSlavesMap.constructSize(), -1);
2532 
2533  forAll(pointSlaves, pointi)
2534  {
2535  const labelList& slaves = pointSlaves[pointi];
2536 
2537  if (slaves.size() > 0)
2538  {
2539  // Duplicate master globalpoint into slave slots
2540  label meshPointi = cpp.meshPoints()[pointi];
2541  masterToGlobal[pointi] = pointToGlobal[meshPointi];
2542  forAll(slaves, i)
2543  {
2544  masterToGlobal[slaves[i]] = masterToGlobal[pointi];
2545  }
2546  }
2547  }
2548 
2549  // Send back
2550  pointSlavesMap.reverseDistribute(cpp.nPoints(), masterToGlobal);
2551 
2552  // On slave copy master index into overal map.
2553  forAll(pointSlaves, pointi)
2554  {
2555  label meshPointi = cpp.meshPoints()[pointi];
2556 
2557  if (!isMaster[meshPointi])
2558  {
2559  pointToGlobal[meshPointi] = masterToGlobal[pointi];
2560  }
2561  }
2562  }
2563 
2564  // Restore tag
2566 
2567  return globalPointsPtr;
2568 }
2569 
2570 
2572 (
2573  const labelUList& meshPoints,
2574  const Map<label>& /* unused: meshPointMap */,
2575  labelList& pointToGlobal,
2576  labelList& uniqueMeshPoints
2577 ) const
2578 {
2579  const indirectPrimitivePatch& cpp = coupledPatch();
2580  const labelListList& pointSlaves = globalCoPointSlaves();
2581  const mapDistribute& pointSlavesMap = globalCoPointSlavesMap();
2582 
2583 
2584  // The patch points come in two variants:
2585  // - not on a coupled patch so guaranteed unique
2586  // - on a coupled patch
2587  // If the point is on a coupled patch the problem is that the
2588  // master-slave structure (globalPointSlaves etc.) assigns one of the
2589  // coupled points to be the master but this master point is not
2590  // necessarily on the patch itself! (it might just be connected to the
2591  // patch point via coupled patches).
2592 
2593 
2594  // Allocate unique tag for all comms
2595  const int oldTag = UPstream::incrMsgType();
2596 
2597  // Determine mapping:
2598  // - from patch point to coupled point (or -1)
2599  // - from coupled point to global patch point
2600  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2601 
2602  const globalIndex globalPPoints(meshPoints.size());
2603 
2604  labelList patchToCoupled(meshPoints.size(), -1);
2605  labelList coupledToGlobalPatch(pointSlavesMap.constructSize(), -1);
2606  //label nCoupled = 0;
2607 
2608  // Note: loop over patch since usually smaller
2609  forAll(meshPoints, patchPointi)
2610  {
2611  label meshPointi = meshPoints[patchPointi];
2612 
2613  const auto iter = cpp.meshPointMap().cfind(meshPointi);
2614 
2615  if (iter.good())
2616  {
2617  patchToCoupled[patchPointi] = iter();
2618  coupledToGlobalPatch[iter()] = globalPPoints.toGlobal(patchPointi);
2619  //++nCoupled;
2620  }
2621  }
2622 
2623  //Pout<< "Patch:" << nl
2624  // << " points:" << meshPoints.size() << nl
2625  // << " of which on coupled patch:" << nCoupled << endl;
2626 
2627 
2628  // Determine master of connected points
2629  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2630  // Problem is that the coupled master might not be on the patch. So
2631  // work out the best patch-point master from all connected points.
2632  // - if the coupled master is on the patch it becomes the patch-point master
2633  // - else the slave with the lowest numbered patch point label
2634 
2635  // Get all data on master
2636  pointSlavesMap.distribute(coupledToGlobalPatch);
2637  forAll(pointSlaves, coupledPointi)
2638  {
2639  const labelList& slaves = pointSlaves[coupledPointi];
2640 
2641  if (slaves.size() > 0)
2642  {
2643  // I am master. What is the best candidate for patch-point master
2644  label masterI = labelMax;
2645  if (coupledToGlobalPatch[coupledPointi] != -1)
2646  {
2647  // I am master and on the coupled patch. Use me.
2648  masterI = coupledToGlobalPatch[coupledPointi];
2649  }
2650  else
2651  {
2652  // Get min of slaves as master.
2653  forAll(slaves, i)
2654  {
2655  label slavePp = coupledToGlobalPatch[slaves[i]];
2656  if (slavePp != -1 && slavePp < masterI)
2657  {
2658  masterI = slavePp;
2659  }
2660  }
2661  }
2662 
2663  if (masterI != labelMax)
2664  {
2665  // Push back
2666  coupledToGlobalPatch[coupledPointi] = masterI;
2667  forAll(slaves, i)
2668  {
2669  coupledToGlobalPatch[slaves[i]] = masterI;
2670  }
2671  }
2672  }
2673  }
2674  pointSlavesMap.reverseDistribute(cpp.nPoints(), coupledToGlobalPatch);
2675 
2676 
2677  // Generate compact numbering for master points
2678  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2679  // Now coupledToGlobalPatch is the globalIndex of the master point.
2680  // Now every processor can check whether they hold it and generate a
2681  // compact numbering.
2682 
2683  label nMasters = 0;
2684  forAll(meshPoints, patchPointi)
2685  {
2686  if (patchToCoupled[patchPointi] == -1)
2687  {
2688  nMasters++;
2689  }
2690  else
2691  {
2692  label coupledPointi = patchToCoupled[patchPointi];
2693  if
2694  (
2695  globalPPoints.toGlobal(patchPointi)
2696  == coupledToGlobalPatch[coupledPointi]
2697  )
2698  {
2699  // I am the master
2700  nMasters++;
2701  }
2702  }
2703  }
2704 
2705  autoPtr<globalIndex> globalPointsPtr(new globalIndex(nMasters));
2706 
2707  //Pout<< "Patch:" << nl
2708  // << " points:" << meshPoints.size() << nl
2709  // << " of which on coupled patch:" << nCoupled << nl
2710  // << " of which master:" << nMasters << endl;
2711 
2712 
2713 
2714  // Push back compact numbering for master point onto slaves
2715  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2716 
2717  pointToGlobal.setSize(meshPoints.size());
2718  pointToGlobal = -1;
2719  uniqueMeshPoints.setSize(nMasters);
2720 
2721  // Sync master in global point numbering so all know the master point.
2722  // Initialise globalMaster to be -1 except at a globalMaster.
2723  labelList globalMaster(cpp.nPoints(), -1);
2724 
2725  nMasters = 0;
2726  forAll(meshPoints, patchPointi)
2727  {
2728  if (patchToCoupled[patchPointi] == -1)
2729  {
2730  uniqueMeshPoints[nMasters++] = meshPoints[patchPointi];
2731  }
2732  else
2733  {
2734  label coupledPointi = patchToCoupled[patchPointi];
2735  if
2736  (
2737  globalPPoints.toGlobal(patchPointi)
2738  == coupledToGlobalPatch[coupledPointi]
2739  )
2740  {
2741  globalMaster[coupledPointi] =
2742  globalPointsPtr().toGlobal(nMasters);
2743  uniqueMeshPoints[nMasters++] = meshPoints[patchPointi];
2744  }
2745  }
2746  }
2747 
2748 
2749  // Sync by taking max
2750  syncData
2751  (
2752  globalMaster,
2753  pointSlaves,
2754  labelListList(0), // no transforms
2755  pointSlavesMap,
2756  maxEqOp<label>()
2757  );
2758 
2759 
2760  // Now everyone has the master point in globalPointsPtr numbering. Fill
2761  // in the pointToGlobal map.
2762  nMasters = 0;
2763  forAll(meshPoints, patchPointi)
2764  {
2765  if (patchToCoupled[patchPointi] == -1)
2766  {
2767  pointToGlobal[patchPointi] = globalPointsPtr().toGlobal(nMasters++);
2768  }
2769  else
2770  {
2771  label coupledPointi = patchToCoupled[patchPointi];
2772  pointToGlobal[patchPointi] = globalMaster[coupledPointi];
2773 
2774  if
2775  (
2776  globalPPoints.toGlobal(patchPointi)
2777  == coupledToGlobalPatch[coupledPointi]
2778  )
2779  {
2780  nMasters++;
2781  }
2782  }
2783  }
2784 
2785  // Restore tag
2786  UPstream::msgType(oldTag);
2787 
2788  return globalPointsPtr;
2789 }
2790 
2791 
2792 void Foam::globalMeshData::movePoints(const pointField& newPoints)
2793 {
2794  // Topology does not change and we don't store any geometry so nothing
2795  // needs to be done.
2796  // Only global transformations might change but this is not really
2797  // supported.
2798 }
2799 
2800 
2802 {
2803  // Clear out old data
2804  clearOut();
2805 
2806  // Do processor patch addressing
2807  initProcAddr();
2808 
2809  scalar tolDim = matchTol_ * mesh_.bounds().mag();
2810 
2811  if (debug)
2812  {
2813  Pout<< "globalMeshData : merge dist:" << tolDim << endl;
2814  }
2815 
2816 
2817  const label comm = mesh_.comm();
2818  const label oldWarnComm = UPstream::commWarn(comm);
2819 
2820  if (UPstream::is_parallel(comm))
2821  {
2822  const label myProci = UPstream::myProcNo(comm);
2823  const label numProc = UPstream::nProcs(comm);
2824 
2825  // Gather all three sizes together
2826  labelList allSizes(3*numProc);
2827  {
2828  label* tup = allSizes.begin(3*myProci);
2829  tup[0] = mesh_.nPoints();
2830  tup[1] = mesh_.nFaces();
2831  tup[2] = mesh_.nCells();
2832  }
2833 
2834  UPstream::mpiAllGather(allSizes.data(), 3, comm);
2835 
2836  // Extract counts per mesh entity
2837  // TBD: check for label overflow?
2838 
2839  labelList counts(numProc);
2840  for (label proci = 0, idx = 0; proci < numProc; ++proci, idx += 3)
2841  {
2842  counts[proci] = allSizes[idx];
2843  }
2844  globalMeshPointAddr_.reset(counts);
2845 
2846  for (label proci = 0, idx = 1; proci < numProc; ++proci, idx += 3)
2847  {
2848  counts[proci] = allSizes[idx];
2849  }
2850  globalMeshFaceAddr_.reset(counts);
2851 
2852  for (label proci = 0, idx = 2; proci < numProc; ++proci, idx += 3)
2853  {
2854  counts[proci] = allSizes[idx];
2855  }
2856  globalMeshCellAddr_.reset(counts);
2857  }
2858  else
2859  {
2860  globalMeshPointAddr_.reset(globalIndex::gatherNone{}, mesh_.nPoints());
2861  globalMeshFaceAddr_.reset(globalIndex::gatherNone{}, mesh_.nFaces());
2862  globalMeshCellAddr_.reset(globalIndex::gatherNone{}, mesh_.nCells());
2863  }
2864 
2865  // Restore communicator settings
2866  UPstream::commWarn(oldWarnComm);
2867 
2868  if (debug)
2869  {
2870  Info<< "globalMeshData : Total points/faces/cells : ("
2871  << nTotalPoints() << ' '
2872  << nTotalFaces() << ' '
2873  << nTotalCells() << ')' << endl;
2874  }
2875 }
2876 
2877 
2878 // ************************************************************************* //
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:116
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:1274
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:153
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:608
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:521
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:531
static void mpiAllGather(char *allData, int count, const label communicator=worldComm)
Gather/scatter identically-sized char data.
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1061
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:1252
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.
const labelListList & globalEdgeSlaves() const
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1086
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.
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
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:461
label nGlobalEdges() const
Return number of globally shared edges.
List helper to append y elements onto the end of x.
Definition: ListOps.H:712
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:1077
label nGlobalPoints() const
Return number of globally shared points.
const Map< label > & meshPointMap() const
Mesh point map.
static void recv(Type &value, const int fromProcNo, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm, IOstreamOption::streamFormat fmt=IOstreamOption::BINARY)
Receive and deserialize a value. Uses operator>> for de-serialization.
Definition: IPstream.H:81
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:320
dynamicFvMesh & mesh
const globalIndexAndTransform & globalTransforms() const
Global transforms numbering.
"scheduled" (MPI standard) : (MPI_Send, MPI_Recv)
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:296
static void combineReduce(T &value, const CombineOp &cop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) applying cop to inplace combine value from different processors...
static constexpr int masterNo() noexcept
Relative rank for the master process - is always 0.
Definition: UPstream.H:1071
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:1123
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.
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.
const labelListList & globalPointTransformedBoundaryCells() const
void operator()(T &x, const T &y) const
Definition: ops.H:76
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:1094
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:1197
List< label > labelList
A List of labels.
Definition: List.H:62
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:107
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()