mapDistributeBase.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) 2015-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 "mapDistributeBase.H"
30 #include "bitSet.H"
31 #include "commSchedule.H"
32 #include "labelPairHashes.H"
33 #include "globalIndex.H"
34 #include "ListOps.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
41 }
42 
43 
44 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
45 
47 {
48  for (const label val : map)
49  {
50  if (!val)
51  {
52  // Cannot be flipped addressing if it contains zero.
53  return false;
54  }
55  else if (val < 0)
56  {
57  // Must be flipped addressing if it contains negatives.
58  return true;
59  }
60  }
61 
62  return false;
63 }
64 
65 
67 {
68  for (const labelList& map : maps)
69  {
70  for (const label val : map)
71  {
72  if (!val)
73  {
74  // Cannot be flipped addressing if it contains zero.
75  return false;
76  }
77  else if (val < 0)
78  {
79  // Must be flipped addressing if it contains negatives.
80  return true;
81  }
82  }
83  }
84 
85  return false;
86 }
87 
88 
90 (
91  const labelListList& maps,
92  const bool hasFlip
93 )
94 {
95  label maxIndex = -1;
96 
97  for (const labelList& map : maps)
98  {
99  for (label index : map)
100  {
101  if (hasFlip)
102  {
103  index = mag(index)-1;
104  }
105 
106  maxIndex = max(maxIndex, index);
107  }
108  }
109 
110  return (maxIndex+1);
111 }
112 
113 
115 (
116  const labelUList& elements,
117  const labelListList& maps,
118  const bool hasFlip
119 )
120 {
121  if (elements.empty())
122  {
123  return 0;
124  }
125 
126  // Moderately efficient markup/search
127 
128  bitSet unvisited(elements);
129  label nUnmapped = unvisited.count();
130 
131  if (hasFlip)
132  {
133  for (const labelList& map : maps)
134  {
135  for (label index : map)
136  {
137  index = mag(index)-1;
138 
139  if (unvisited.unset(index))
140  {
141  --nUnmapped;
142  if (!nUnmapped) break;
143  }
144  }
145  }
146  }
147  else
148  {
149  for (const labelList& map : maps)
150  {
151  for (label index : map)
152  {
153  if (unvisited.unset(index))
154  {
155  --nUnmapped;
156  if (!nUnmapped) break;
157  }
158  }
159  }
160  }
161 
162  return nUnmapped;
163 }
164 
165 
167 (
168  const label proci,
169  const label expectedSize,
170  const label receivedSize
171 )
172 {
173  if (receivedSize != expectedSize)
174  {
176  << "From processor " << proci
177  << " : expected " << expectedSize
178  << " but received " << receivedSize << " elements" << nl
179  << abort(FatalError);
180  }
181 }
182 
183 
184 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
185 
187 (
188  const labelListList& subMap,
189  const labelListList& constructMap,
190  const int tag,
191  const label comm
192 )
193 {
194  const label myRank = UPstream::myProcNo(comm);
195  const label nProcs = UPstream::nProcs(comm);
196 
197  // Communications: send and receive processor
198  List<labelPair> allComms;
199 
200  {
201  labelPairHashSet commsSet(nProcs);
202 
203  // Find what communication is required
204  forAll(subMap, proci)
205  {
206  if (proci != myRank)
207  {
208  if (subMap[proci].size())
209  {
210  // I need to send to proci
211  commsSet.insert(labelPair(myRank, proci));
212  }
213  if (constructMap[proci].size())
214  {
215  // I need to receive from proci
216  commsSet.insert(labelPair(proci, myRank));
217  }
218  }
219  }
220  allComms = commsSet.toc();
221  }
222 
223 
224  // Gather/reduce
225  if (UPstream::master(comm))
226  {
227  // Receive and merge
228  for (const int proci : UPstream::subProcs(comm))
229  {
230  List<labelPair> nbrData;
231  IPstream::recv(nbrData, proci, tag, comm);
232 
233  for (const labelPair& connection : nbrData)
234  {
235  allComms.push_uniq(connection);
236  }
237  }
238  }
239  else
240  {
241  if (UPstream::parRun())
242  {
243  OPstream::send(allComms, UPstream::masterNo(), tag, comm);
244  }
245  }
246 
247  // Broadcast: send comms information to all
248  Pstream::broadcast(allComms, comm);
249 
250  // Determine my schedule.
251  labelList mySchedule
252  (
253  commSchedule
254  (
255  nProcs,
256  allComms
257  ).procSchedule()[myRank]
258  );
259 
260  // Processors involved in my schedule
261  return List<labelPair>(allComms, mySchedule);
262 }
263 
264 
266 {
267  if (!schedulePtr_)
268  {
269  schedulePtr_.reset
270  (
271  new List<labelPair>
272  (
273  schedule(subMap_, constructMap_, UPstream::msgType(), comm_)
274  )
275  );
276  }
277 
278  return *schedulePtr_;
279 }
280 
281 
283 (
284  const UPstream::commsTypes commsType
285 ) const
286 {
287  if (commsType == UPstream::commsTypes::scheduled)
288  {
289  return schedule();
290  }
291 
292  return List<labelPair>::null();
293 }
294 
295 
296 void Foam::mapDistributeBase::printLayout(Ostream& os) const
297 {
298  const label myRank = UPstream::myProcNo(comm_);
299  const label nProcs = UPstream::nProcs(comm_);
300 
301  // Determine offsets of remote data.
302  labelList minIndex(nProcs, labelMax);
303  labelList maxIndex(nProcs, labelMin);
304  forAll(constructMap_, proci)
305  {
306  const labelList& construct = constructMap_[proci];
307  if (constructHasFlip_)
308  {
309  forAll(construct, i)
310  {
311  label index = mag(construct[i])-1;
312  minIndex[proci] = min(minIndex[proci], index);
313  maxIndex[proci] = max(maxIndex[proci], index);
314  }
315  }
316  else
317  {
318  forAll(construct, i)
319  {
320  label index = construct[i];
321  minIndex[proci] = min(minIndex[proci], index);
322  maxIndex[proci] = max(maxIndex[proci], index);
323  }
324  }
325  }
326 
327  label localSize(0);
328 
329  if (maxIndex[myRank] != labelMin)
330  {
331  localSize = maxIndex[myRank]+1;
332  }
333 
334  os << "Layout: (constructSize:" << constructSize_
335  << " subHasFlip:" << subHasFlip_
336  << " constructHasFlip:" << constructHasFlip_
337  << ")" << nl
338  << "local (processor " << myRank << "):" << nl
339  << " start : 0" << nl
340  << " size : " << localSize << endl;
341 
342  label offset = localSize;
343  forAll(minIndex, proci)
344  {
345  if (proci != myRank && !constructMap_[proci].empty())
346  {
347  label size(0);
348 
349  if (maxIndex[proci] != labelMin)
350  {
351  size = maxIndex[proci]-minIndex[proci]+1;
352  if (minIndex[proci] != offset)
353  {
355  << "offset:" << offset
356  << " proci:" << proci
357  << " minIndex:" << minIndex[proci]
358  << abort(FatalError);
359  }
360  }
361 
362  os << "processor " << proci << ':' << nl
363  << " start : " << offset << nl
364  << " size : " << size << endl;
365 
366  offset += size;
367  }
368  }
369 }
370 
371 
373 (
374  const globalIndex& globalNumbering,
375  const labelUList& elements,
376  List<Map<label>>& compactMap
377 ) const
378 {
379  const label myRank = UPstream::myProcNo(comm_);
380  const label nProcs = UPstream::nProcs(comm_);
381 
382  // Count all (non-local) elements needed. Just for presizing map.
383  labelList nNonLocal(nProcs, Zero);
384 
385  for (const label globalIdx : elements)
386  {
387  if (globalIdx != -1 && !globalNumbering.isLocal(myRank, globalIdx))
388  {
389  label proci = globalNumbering.whichProcID(myRank, globalIdx);
390  nNonLocal[proci]++;
391  }
392  }
393 
394  compactMap.resize_nocopy(nProcs);
395 
396  forAll(compactMap, proci)
397  {
398  compactMap[proci].clear();
399  if (proci != myRank)
400  {
401  compactMap[proci].reserve(nNonLocal[proci]);
402  }
403  }
404 
405 
406  // Collect all (non-local) elements needed.
407  for (const label globalIdx : elements)
408  {
409  if (globalIdx != -1 && !globalNumbering.isLocal(myRank, globalIdx))
410  {
411  label proci = globalNumbering.whichProcID(myRank, globalIdx);
412  label index = globalNumbering.toLocal(proci, globalIdx);
413  compactMap[proci].insert(index, compactMap[proci].size());
414  }
415  }
416 }
417 
418 
420 (
421  const globalIndex& globalNumbering,
422  const labelListList& cellCells,
423  List<Map<label>>& compactMap
424 ) const
425 {
426  const label myRank = UPstream::myProcNo(comm_);
427  const label nProcs = UPstream::nProcs(comm_);
428 
429  // Count all (non-local) elements needed. Just for presizing map.
430  labelList nNonLocal(nProcs, Zero);
431 
432  for (const labelList& cCells : cellCells)
433  {
434  for (const label globalIdx : cCells)
435  {
436  if (globalIdx != -1 && !globalNumbering.isLocal(myRank, globalIdx))
437  {
438  label proci = globalNumbering.whichProcID(myRank, globalIdx);
439  nNonLocal[proci]++;
440  }
441  }
442  }
443 
444  compactMap.resize_nocopy(nProcs);
445 
446  forAll(compactMap, proci)
447  {
448  compactMap[proci].clear();
449  if (proci != myRank)
450  {
451  compactMap[proci].reserve(nNonLocal[proci]);
452  }
453  }
454 
455 
456  // Collect all (non-local) elements needed.
457  for (const labelList& cCells : cellCells)
458  {
459  for (const label globalIdx : cCells)
460  {
461  if (globalIdx != -1 && !globalNumbering.isLocal(myRank, globalIdx))
462  {
463  label proci = globalNumbering.whichProcID(myRank, globalIdx);
464  label index = globalNumbering.toLocal(proci, globalIdx);
465  compactMap[proci].insert(index, compactMap[proci].size());
466  }
467  }
468  }
469 }
470 
471 
473 (
474  const int tag,
475  const globalIndex& globalNumbering,
476  labelList& elements,
477  List<Map<label>>& compactMap,
478  labelList& compactStart
479 )
480 {
481  const label myRank = UPstream::myProcNo(comm_);
482  const label nProcs = UPstream::nProcs(comm_);
483 
484  // The overall compact addressing is
485  // - myProcNo data first (uncompacted)
486  // - all other processors consecutively
487 
488  compactStart.setSize(nProcs);
489  compactStart[myRank] = 0;
490  constructSize_ = globalNumbering.localSize(myRank);
491  forAll(compactStart, proci)
492  {
493  if (proci != myRank)
494  {
495  compactStart[proci] = constructSize_;
496  constructSize_ += compactMap[proci].size();
497  }
498  }
499 
500 
501  // Find out what to receive/send in compact addressing.
502 
503  // What I want to receive is what others have to send
504  labelListList wantedRemoteElements(nProcs);
505  // Compact addressing for received data
506  constructMap_.setSize(nProcs);
507  forAll(compactMap, proci)
508  {
509  if (proci == myRank)
510  {
511  // All my own elements are used
512  label nLocal = globalNumbering.localSize(myRank);
513  wantedRemoteElements[proci] = identity(nLocal);
514  constructMap_[proci] = identity(nLocal);
515  }
516  else
517  {
518  // Remote elements wanted from processor proci
519  labelList& remoteElem = wantedRemoteElements[proci];
520  labelList& localElem = constructMap_[proci];
521  remoteElem.setSize(compactMap[proci].size());
522  localElem.setSize(compactMap[proci].size());
523  label i = 0;
524  forAllIters(compactMap[proci], iter)
525  {
526  const label compactI = compactStart[proci] + iter.val();
527  remoteElem[i] = iter.key();
528  localElem[i] = compactI;
529  iter.val() = compactI;
530  i++;
531  }
532  }
533  }
534 
535  subMap_.setSize(nProcs);
536  Pstream::exchange<labelList, label>
537  (
538  wantedRemoteElements,
539  subMap_,
540  tag,
541  comm_
542  );
543 
544  // Renumber elements
545  for (label& elem : elements)
546  {
547  elem = renumber(globalNumbering, comm_, compactMap, elem);
548  }
549 }
550 
551 
553 (
554  const int tag,
555  const globalIndex& globalNumbering,
556  labelListList& cellCells,
557  List<Map<label>>& compactMap,
558  labelList& compactStart
559 )
560 {
561  const label myRank = UPstream::myProcNo(comm_);
562  const label nProcs = UPstream::nProcs(comm_);
563 
564  // The overall compact addressing is
565  // - myProcNo data first (uncompacted)
566  // - all other processors consecutively
567 
568  compactStart.setSize(nProcs);
569  compactStart[myRank] = 0;
570  constructSize_ = globalNumbering.localSize(myRank);
571  forAll(compactStart, proci)
572  {
573  if (proci != myRank)
574  {
575  compactStart[proci] = constructSize_;
576  constructSize_ += compactMap[proci].size();
577  }
578  }
579 
580 
581  // Find out what to receive/send in compact addressing.
582 
583  // What I want to receive is what others have to send
584  labelListList wantedRemoteElements(nProcs);
585  // Compact addressing for received data
586  constructMap_.setSize(nProcs);
587  forAll(compactMap, proci)
588  {
589  if (proci == myRank)
590  {
591  // All my own elements are used
592  label nLocal = globalNumbering.localSize(myRank);
593  wantedRemoteElements[proci] = identity(nLocal);
594  constructMap_[proci] = identity(nLocal);
595  }
596  else
597  {
598  // Remote elements wanted from processor proci
599  labelList& remoteElem = wantedRemoteElements[proci];
600  labelList& localElem = constructMap_[proci];
601  remoteElem.setSize(compactMap[proci].size());
602  localElem.setSize(compactMap[proci].size());
603  label i = 0;
604  forAllIters(compactMap[proci], iter)
605  {
606  const label compactI = compactStart[proci] + iter.val();
607  remoteElem[i] = iter.key();
608  localElem[i] = compactI;
609  iter.val() = compactI;
610  i++;
611  }
612  }
613  }
614 
615  subMap_.setSize(nProcs);
616  Pstream::exchange<labelList, label>
617  (
618  wantedRemoteElements,
619  subMap_,
620  tag,
621  comm_
622  );
623 
624  // Renumber elements
625  for (labelList& cCells : cellCells)
626  {
627  for (label& celli : cCells)
628  {
629  celli = renumber(globalNumbering, comm_, compactMap, celli);
630  }
631  }
632 }
633 
634 
635 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
638 :
639  mapDistributeBase(UPstream::worldComm)
640 {}
641 
642 
644 :
645  constructSize_(0),
646  subMap_(),
647  constructMap_(),
648  subHasFlip_(false),
649  constructHasFlip_(false),
650  comm_(comm),
651  schedulePtr_(nullptr)
652 {}
653 
654 
656 :
657  constructSize_(map.constructSize_),
658  subMap_(map.subMap_),
659  constructMap_(map.constructMap_),
660  subHasFlip_(map.subHasFlip_),
661  constructHasFlip_(map.constructHasFlip_),
662  comm_(map.comm_),
663  schedulePtr_(nullptr)
664 {}
665 
666 
668 :
669  mapDistributeBase(map.comm())
670 {
671  transfer(map);
672 }
673 
674 
676 (
677  const label constructSize,
678  labelListList&& subMap,
679  labelListList&& constructMap,
680  const bool subHasFlip,
681  const bool constructHasFlip,
682  const label comm
683 )
684 :
685  constructSize_(constructSize),
686  subMap_(std::move(subMap)),
687  constructMap_(std::move(constructMap)),
688  subHasFlip_(subHasFlip),
689  constructHasFlip_(constructHasFlip),
690  comm_(comm),
691  schedulePtr_(nullptr)
692 {}
693 
694 
696 (
697  const labelUList& sendProcs,
698  const labelUList& recvProcs,
699  const label comm
700 )
701 :
702  constructSize_(0),
703  subMap_(),
704  constructMap_(),
705  subHasFlip_(false),
706  constructHasFlip_(false),
707  comm_(comm),
708  schedulePtr_(nullptr)
709 {
710  const label myRank = UPstream::myProcNo(comm_);
711  const label nProcs = UPstream::nProcs(comm_);
712 
713  if (sendProcs.size() != recvProcs.size())
714  {
716  << "The send and receive data is not the same length. sendProcs:"
717  << sendProcs.size() << " recvProcs:" << recvProcs.size()
718  << abort(FatalError);
719  }
720 
721  // Per processor the number of samples we have to send/receive.
722  labelList nSend(nProcs, Zero);
723  labelList nRecv(nProcs, Zero);
724 
725  forAll(sendProcs, sampleI)
726  {
727  const label sendProc = sendProcs[sampleI];
728  const label recvProc = recvProcs[sampleI];
729 
730  // Note that also need to include local communication (both
731  // RecvProc and sendProc on local processor)
732 
733  if (myRank == sendProc)
734  {
735  // I am the sender.
736  nSend[recvProc]++;
737  }
738  if (myRank == recvProc)
739  {
740  // I am the receiver.
741  nRecv[sendProc]++;
742  }
743  }
744 
745  subMap_.setSize(nProcs);
746  constructMap_.setSize(nProcs);
747  forAll(nSend, proci)
748  {
749  subMap_[proci].setSize(nSend[proci]);
750  constructMap_[proci].setSize(nRecv[proci]);
751  }
752  nSend = 0;
753  nRecv = 0;
754 
755  // Largest entry inside constructMap
756  label maxRecvIndex = -1;
757 
758  forAll(sendProcs, sampleI)
759  {
760  const label sendProc = sendProcs[sampleI];
761  const label recvProc = recvProcs[sampleI];
762 
763  if (myRank == sendProc)
764  {
765  // I am the sender. Store index I need to send.
766  subMap_[recvProc][nSend[recvProc]++] = sampleI;
767  }
768  if (myRank == recvProc)
769  {
770  // I am the receiver.
771  constructMap_[sendProc][nRecv[sendProc]++] = sampleI;
772  maxRecvIndex = sampleI;
773  }
774  }
775 
776  constructSize_ = maxRecvIndex+1;
777 }
778 
779 
781 (
782  const globalIndex& globalNumbering,
783  labelList& elements,
784  List<Map<label>>& compactMap,
785  const int tag,
786  const label comm
787 )
788 :
789  constructSize_(0),
790  subMap_(),
791  constructMap_(),
792  subHasFlip_(false),
793  constructHasFlip_(false),
794  comm_(comm),
795  schedulePtr_(nullptr)
796 {
797  // Construct per processor compact addressing of the global elements
798  // needed. The ones from the local processor are not included since
799  // these are always all needed.
801  (
802  globalNumbering,
803  elements,
804  compactMap
805  );
806 
808  //forAll(compactMap, proci)
809  //{
810  // if (proci != myRank)
811  // {
812  // Map<label>& globalMap = compactMap[proci];
813  //
814  // const List<label> sorted(globalMap.sortedToc());
815  //
816  // forAll(sorted, i)
817  // {
818  // globalMap(sorted[i]) = i;
819  // }
820  // }
821  //}
822 
823 
824  // Exchange what I need with processor that supplies it. Renumber elements
825  // into compact numbering
826  labelList compactStart;
828  (
829  tag,
830  globalNumbering,
831  elements,
832  compactMap,
833  compactStart
834  );
835 
836  if (debug)
837  {
838  printLayout(Pout);
839  }
840 }
841 
842 
844 (
845  const globalIndex& globalNumbering,
846  labelListList& cellCells,
847  List<Map<label>>& compactMap,
848  const int tag,
849  const label comm
850 )
851 :
852  constructSize_(0),
853  subMap_(),
854  constructMap_(),
855  subHasFlip_(false),
856  constructHasFlip_(false),
857  comm_(comm),
858  schedulePtr_(nullptr)
859 {
860  // Construct per processor compact addressing of the global elements
861  // needed. The ones from the local processor are not included since
862  // these are always all needed.
864  (
865  globalNumbering,
866  cellCells,
867  compactMap
868  );
869 
871  //forAll(compactMap, proci)
872  //{
873  // if (proci != myRank)
874  // {
875  // Map<label>& globalMap = compactMap[proci];
876  //
877  // const List<label> sorted(globalMap.sortedToc());
878  //
879  // forAll(sorted, i)
880  // {
881  // globalMap(sorted[i]) = i;
882  // }
883  // }
884  //}
885 
886 
887  // Exchange what I need with processor that supplies it. Renumber elements
888  // into compact numbering
889  labelList compactStart;
891  (
892  tag,
893  globalNumbering,
894  cellCells,
895  compactMap,
896  compactStart
897  );
898 
899  if (debug)
900  {
901  printLayout(Pout);
902  }
903 }
904 
905 
907 (
908  const layoutTypes constructLayout,
909  labelListList&& subMap,
910  const bool subHasFlip,
911  const bool constructHasFlip,
912  const label comm
913 )
914 :
915  constructSize_(0),
916  subMap_(std::move(subMap)),
917  constructMap_(),
918  subHasFlip_(subHasFlip),
919  constructHasFlip_(constructHasFlip),
920  comm_(comm),
921  schedulePtr_(nullptr)
922 {
923  const label myRank = UPstream::myProcNo(comm_);
924  const label nProcs = UPstream::nProcs(comm_);
925 
926  // Send over how many i need to receive.
927  labelList recvSizes;
928  Pstream::exchangeSizes(subMap_, recvSizes, comm_);
929 
930  constructSize_ = 0;
931  constructMap_.resize(nProcs);
932 
933  // The order of receiving:
934 
935  if (constructLayout == layoutTypes::linear)
936  {
937  forAll(constructMap_, proci)
938  {
939  const label len = recvSizes[proci];
940 
941  constructMap_[proci] = identity(len, constructSize_);
942  constructSize_ += len;
943  }
944  }
945  else
946  {
947  // layoutTypes::localFirst
948 
949  // My data first
950  {
951  const label len = recvSizes[myRank];
952 
953  constructMap_[myRank] = identity(len, constructSize_);
954  constructSize_ += len;
955  }
956 
957  // What the other processors are sending to me
958  forAll(constructMap_, proci)
959  {
960  if (proci != myRank)
961  {
962  const label len = recvSizes[proci];
963 
964  constructMap_[proci] = identity(len, constructSize_);
965  constructSize_ += len;
966  }
967  }
968  }
969 }
970 
971 
973 (
974  labelListList&& subMap,
975  const bool subHasFlip,
976  const bool constructHasFlip,
977  const label comm
978 )
979 :
980  mapDistributeBase
981  (
982  layoutTypes::localFirst,
983  std::move(subMap),
984  subHasFlip,
985  constructHasFlip,
986  comm
987  )
988 {}
989 
990 
992 (
994  const labelList& localRanks,
995  const label newComm,
996  const labelListList& newToOldRanks,// from newComm to comm_
997  labelList& startOfLocal,
998  List<Map<label>>& compactMaps
999 )
1000 :
1001  constructSize_(0),
1002  subHasFlip_(false),
1003  constructHasFlip_(false),
1004  comm_(-1),
1005  schedulePtr_(nullptr)
1006 {
1007  if (maps.empty())
1008  {
1009  return;
1010  }
1011 
1012  comm_ = newComm;
1013  subHasFlip_ = maps[0].subHasFlip();
1014  constructHasFlip_ = maps[0].constructHasFlip();
1015 
1016  const label nNewRanks = newToOldRanks.size();
1017  const label myNewRank = UPstream::myProcNo(newComm);
1018  if (nNewRanks != UPstream::nProcs(newComm))
1019  {
1020  FatalErrorInFunction<< "nNewRanks:" << nNewRanks
1021  << " nProcs:" << UPstream::nProcs(newComm)
1022  << exit(FatalError);
1023  }
1024 
1025  if (localRanks.size() != maps.size())
1026  {
1028  << "Number of maps:" << maps.size()
1029  << " number of localRanks:" << localRanks.size()
1030  << exit(FatalError);
1031  }
1032 
1033  // Sanity checks
1034  const auto& map0 = maps[0];
1035  forAll(maps, mapi)
1036  {
1037  const auto& map = maps[mapi];
1038 
1039  if
1040  (
1041  (map.comm() != map0.comm())
1042  || (map.subHasFlip() != map0.subHasFlip())
1043  || (map.constructHasFlip() != map0.constructHasFlip())
1044  )
1045  {
1047  << "Maps should all be the same form"
1048  << " Map " << mapi
1049  << " has comm:" << map.comm()
1050  << " subHasFlip:" << map.subHasFlip()
1051  << " constructHasFlip:" << map.constructHasFlip()
1052  << " which is different from map 0"
1053  << exit(FatalError);
1054  }
1055 
1056  const label localRank = localRanks[mapi];
1057  const auto& constructOwn = maps[mapi].constructMap()[localRank];
1058  forAll(constructOwn, i)
1059  {
1060  if (constructOwn[i] != i)
1061  {
1063  << "Maps constructMap not identity."
1064  << " Map " << mapi
1065  << " constructMap:" << flatOutput(constructOwn)
1066  << exit(FatalError);
1067  }
1068  }
1069  }
1070 
1071 
1072  constructMap_.resize_nocopy(nNewRanks);
1073  subMap_.resize_nocopy(nNewRanks);
1074 
1075 
1076  // Store starts
1077  startOfLocal.setSize(maps.size()+1);
1078  compactMaps.resize_nocopy(maps.size());
1079 
1080  label constructi = 0;
1081  forAll(maps, mapi)
1082  {
1083  startOfLocal[mapi] = constructi;
1084  const label localRank = localRanks[mapi];
1085  const auto& map = maps[mapi].constructMap()[localRank];
1086 
1087  // Presize compaction array
1088  const label nRemote = maps[mapi].constructSize()-map.size();
1089  compactMaps[mapi].resize(2*nRemote);
1090 
1091  constructi += map.size();
1092  }
1093  startOfLocal.last() = constructi;
1094 
1095 
1096  // Determine start of constructed remote data. This is used to get the
1097  // local offset which can then be used to get the relative subMap location.
1098  labelListList startOfRemote(maps.size());
1099  forAll(maps, mapi)
1100  {
1101  const label nOldProcs = maps[mapi].constructMap().size();
1102  labelList& starts = startOfRemote[mapi];
1103 
1104  starts.setSize(nOldProcs, labelMax);
1105  forAll(maps[mapi].constructMap(), oldProci)
1106  {
1107  const labelList& map = maps[mapi].constructMap()[oldProci];
1108  forAll(map, i)
1109  {
1110  const label index
1111  (
1112  constructHasFlip_
1113  ? mag(map[i])-1
1114  : map[i]
1115  );
1116  starts[oldProci] = min(starts[oldProci], index);
1117  }
1118  }
1119  }
1120 
1121 
1122  // Construct map
1123  // ~~~~~~~~~~~~~
1124  // - all localRanks:
1125  // - data gets appended in map order
1126  // - map is just an offset (startOfLocal)
1127  // - all previously remote ranks:
1128  // - data is already present according to startOfLocal
1129  // - map is old-to-new index
1130  // - all still remote ranks:
1131  // - data gets appended in map order after the startOfLocal
1132  // - map is old-to-new index
1133 
1134 
1135  // Append local (= myRank) data. TBD: assumes subMap and constructMap
1136  // are identity maps.
1137  {
1138  labelList& myConstruct = constructMap_[myNewRank];
1139  myConstruct.resize_nocopy(constructi);
1140  constructi = 0;
1141  forAll(maps, mapi)
1142  {
1143  const label localRank = localRanks[mapi];
1144  const auto& map = maps[mapi].constructMap()[localRank];
1145  const label offset = startOfLocal[mapi];
1146 
1147  forAll(map, i)
1148  {
1149  if (constructHasFlip_)
1150  {
1151  forAll(map, i)
1152  {
1153  if (map[i] < 0)
1154  {
1155  myConstruct[constructi++] = map[i]-offset;
1156  }
1157  else
1158  {
1159  myConstruct[constructi++] = map[i]+offset;
1160  }
1161  }
1162  }
1163  else
1164  {
1165  myConstruct[constructi++] = map[i]+offset;
1166  }
1167  }
1168  }
1169  }
1170 
1171  // Filter remote construct data
1172  {
1173  // Remote ranks that are now local
1174  // - store new index for mapping stencils
1175  // - no need to construct since already
1176  const auto& oldProcs = newToOldRanks[myNewRank];
1177 
1178  forAll(maps, mapi)
1179  {
1180  for (const label oldProci : oldProcs)
1181  {
1182  if (oldProci != localRanks[mapi])
1183  {
1184  const auto& map = maps[mapi].constructMap()[oldProci];
1185 
1186  if (!map.size())
1187  {
1188  continue;
1189  }
1190 
1191 
1192  // The slots come from a local map so we can look up the
1193  // new location
1194  const label sourceMapi = localRanks.find(oldProci);
1195  const auto& subMap =
1196  maps[sourceMapi].subMap()[localRanks[mapi]];
1197 
1198  //Pout<< "From oldRank:" << oldProci
1199  // << " sending to masterRank:" << localRanks[mapi]
1200  // << " elements:" << flatOutput(subMap)
1201  // << nl
1202  // << " received as elements:" << flatOutput(map)
1203  // << endl;
1204 
1205  if (map.size() != subMap.size())
1206  {
1207  FatalErrorInFunction << "Problem:"
1208  << "oldProci:" << oldProci
1209  << " mapi:" << mapi
1210  << " constructMap:" << map.size()
1211  << " sourceMapi:" << sourceMapi
1212  << " subMap:" << subMap.size()
1213  << exit(FatalError);
1214  }
1215 
1216  const label offset = startOfLocal[sourceMapi];
1217  // Construct map starts after the local data
1218  const label nMapLocal = startOfRemote[mapi][oldProci];
1219 
1220  auto& cptMap = compactMaps[mapi];
1221  forAll(map, i)
1222  {
1223  // old slot position to new slot position
1224  const label index
1225  (
1226  constructHasFlip_
1227  ? mag(map[i])-1
1228  : map[i]
1229  );
1230  const label newIndex = subMap[index-nMapLocal]+offset;
1231 
1232  // Note: should always warn for duplicates? Or only if
1233  // different?
1234  if
1235  (
1236  !cptMap.insert(index, newIndex)
1237  && cptMap[index] != newIndex
1238  )
1239  {
1240  FatalErrorInFunction<< "Duplicate insertion"
1241  << "From oldProc:" << oldProci
1242  << " on map:" << mapi
1243  << " at index:" << i
1244  << " have construct slot:" << index
1245  << " new index:" << newIndex
1246  << " but already have entry:" << cptMap[index]
1247  << " on for that slot"
1248  << exit(FatalError);
1249  }
1250  }
1251  }
1252  }
1253  }
1254 
1255 
1256  // Remote ranks that are still remote
1257  // - store new index for mapping stencils
1258  // - append to construction
1259 
1260  // Either loop over all old ranks and filter out ones already handled
1261  // or loop over all new ranks and avoid myNewRank
1262 
1263  forAll(newToOldRanks, newProci)
1264  {
1265  if (newProci != myNewRank)
1266  {
1267  const auto& oldProcs = newToOldRanks[newProci];
1268 
1269  label allSize = 0;
1270  forAll(maps, mapi)
1271  {
1272  for (const label oldProci : oldProcs)
1273  {
1274  allSize += maps[mapi].constructMap()[oldProci].size();
1275  }
1276  }
1277 
1278  labelList& myConstruct = constructMap_[newProci];
1279  myConstruct.resize_nocopy(allSize);
1280 
1281  allSize = 0;
1282  forAll(maps, mapi)
1283  {
1284  for (const label oldProci : oldProcs)
1285  {
1286  const auto& map = maps[mapi].constructMap()[oldProci];
1287  // Construct map starts after the local data
1288  const label nMapLocal = startOfRemote[mapi][oldProci];
1289  SubList<label> slice(myConstruct, map.size(), allSize);
1290 
1291  if (constructHasFlip_)
1292  {
1293  forAll(map, i)
1294  {
1295  if (map[i] < 0)
1296  {
1297  slice[i] = map[i]+nMapLocal-constructi;
1298  }
1299  else
1300  {
1301  slice[i] = map[i]-nMapLocal+constructi;
1302  }
1303  }
1304 
1305  auto& cptMap = compactMaps[mapi];
1306  forAll(map, i)
1307  {
1308  cptMap.insert(mag(map[i])-1,mag(slice[i])-1);
1309  }
1310  }
1311  else
1312  {
1313  forAll(map, i)
1314  {
1315  slice[i] = map[i]-nMapLocal+constructi;
1316  compactMaps[mapi].insert(map[i], slice[i]);
1317  }
1318  }
1319  allSize += map.size();
1320  constructi += map.size();
1321  }
1322  }
1323  }
1324  }
1325  }
1326 
1327 
1328  // Sub (=send) map
1329  // ~~~~~~~~~~~~~~~
1330  // - all localRanks:
1331  // - get appended in map order
1332  // - all previously remote ranks:
1333  // - not needed. Stay empty
1334  // - all still remote ranks:
1335  // - convert to new local index
1336 
1337  // Append local (= myRank) data
1338  {
1339  label allSize = 0;
1340  forAll(maps, mapi)
1341  {
1342  const label localRank = localRanks[mapi];
1343  allSize += maps[mapi].subMap()[localRank].size();
1344  }
1345 
1346  labelList& mySub = subMap_[myNewRank];
1347  mySub.resize_nocopy(allSize);
1348  allSize = 0;
1349  forAll(maps, mapi)
1350  {
1351  const label localRank = localRanks[mapi];
1352  const auto& map = maps[mapi].subMap()[localRank];
1353  SubList<label> slice(mySub, map.size(), allSize);
1354 
1355  if (subHasFlip_)
1356  {
1357  forAll(slice, i)
1358  {
1359  if (map[i] < 0)
1360  {
1361  slice[i] = map[i]-startOfLocal[mapi];
1362  }
1363  else
1364  {
1365  slice[i] = map[i]+startOfLocal[mapi];
1366  }
1367  }
1368  }
1369  else
1370  {
1371  forAll(slice, i)
1372  {
1373  slice[i] = map[i]+startOfLocal[mapi];
1374  }
1375  }
1376  allSize += map.size();
1377  }
1378  }
1379  // Filter remote sub data
1380  forAll(newToOldRanks, newProci)
1381  {
1382  if (newProci != myNewRank)
1383  {
1384  const auto& oldProcs = newToOldRanks[newProci];
1385 
1386  label allSize = 0;
1387  forAll(maps, mapi)
1388  {
1389  for (const label oldProci : oldProcs)
1390  {
1391  allSize += maps[mapi].subMap()[oldProci].size();
1392  }
1393  }
1394 
1395  labelList& mySub = subMap_[newProci];
1396  mySub.resize_nocopy(allSize);
1397 
1398  allSize = 0;
1399  for (const label oldProci : oldProcs)
1400  {
1401  forAll(maps, mapi)
1402  {
1403  const auto& map = maps[mapi].subMap()[oldProci];
1404  SubList<label> slice(mySub, map.size(), allSize);
1405  if (subHasFlip_)
1406  {
1407  forAll(map, i)
1408  {
1409  if (map[i] < 0)
1410  {
1411  slice[i] = map[i]-startOfLocal[mapi];
1412  }
1413  else
1414  {
1415  slice[i] = map[i]+startOfLocal[mapi];
1416  }
1417  }
1418  }
1419  else
1420  {
1421  forAll(map, i)
1422  {
1423  slice[i] = map[i]+startOfLocal[mapi];
1424  }
1425  }
1426  allSize += map.size();
1427  }
1428  }
1429  }
1430  }
1431 
1433  constructSize_ = constructi;
1434 }
1435 
1436 
1437 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
1438 
1440 {
1441  labelList sizes(subMap_.size());
1442  forAll(subMap_, i)
1443  {
1444  sizes[i] = subMap_[i].size();
1445  }
1446  return sizes;
1447 }
1448 
1449 
1451 {
1452  labelList sizes(constructMap_.size());
1453  forAll(constructMap_, i)
1454  {
1455  sizes[i] = constructMap_[i].size();
1456  }
1457  return sizes;
1458 }
1459 
1460 
1462 {
1463  label total = 0;
1464  for (const auto& list : subMap_)
1465  {
1466  total += list.size();
1467  }
1468  return total;
1469 }
1470 
1471 
1473 {
1474  label total = 0;
1475  for (const auto& list : constructMap_)
1476  {
1477  total += list.size();
1478  }
1479  return total;
1480 }
1481 
1482 
1484 {
1485  constructSize_ = 0;
1486  subMap_.clear();
1487  constructMap_.clear();
1488  subHasFlip_ = false;
1489  constructHasFlip_ = false;
1490  // Leave comm_ intact
1491  schedulePtr_.reset(nullptr);
1492 }
1493 
1494 
1496 {
1497  if (this == &rhs)
1498  {
1499  // Self-assignment is a no-op
1500  return;
1501  }
1502 
1503  constructSize_ = rhs.constructSize_;
1504  subMap_.transfer(rhs.subMap_);
1505  constructMap_.transfer(rhs.constructMap_);
1506  subHasFlip_ = rhs.subHasFlip_;
1507  constructHasFlip_ = rhs.constructHasFlip_;
1508  comm_ = rhs.comm_;
1509  schedulePtr_.reset(nullptr);
1510 
1511  rhs.constructSize_ = 0;
1512  rhs.subHasFlip_ = false;
1513  rhs.constructHasFlip_ = false;
1514 }
1515 
1516 
1518 (
1519  const globalIndex& globalNumbering,
1520  const label comm,
1521  const List<Map<label>>& compactMap,
1522  const label globalI
1523 )
1524 {
1525  const label myRank = Pstream::myProcNo(comm);
1526 
1527  if (globalI == -1)
1528  {
1529  return globalI;
1530  }
1531  if (globalNumbering.isLocal(myRank, globalI))
1532  {
1533  return globalNumbering.toLocal(myRank, globalI);
1534  }
1535  else
1536  {
1537  label proci = globalNumbering.whichProcID(myRank, globalI);
1538  label index = globalNumbering.toLocal(proci, globalI);
1539  return compactMap[proci][index];
1540  }
1541 }
1542 
1543 
1544 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1545 
1546 void Foam::mapDistributeBase::operator=(const mapDistributeBase& rhs)
1547 {
1548  if (this == &rhs)
1549  {
1550  return; // Self-assignment is a no-op
1551  }
1552 
1553  constructSize_ = rhs.constructSize_;
1554  subMap_ = rhs.subMap_;
1555  constructMap_ = rhs.constructMap_;
1556  subHasFlip_ = rhs.subHasFlip_;
1557  constructHasFlip_ = rhs.constructHasFlip_;
1558  comm_ = rhs.comm_;
1559  schedulePtr_.reset(nullptr);
1560 }
1561 
1562 
1564 {
1565  if (this != &rhs)
1566  {
1567  // Avoid self assignment
1568  transfer(rhs);
1569  }
1570 }
1571 
1572 
1573 // ************************************************************************* //
label toLocal(const label proci, const label i) const
From global to local on proci.
Definition: globalIndexI.H:377
void calcCompactAddressing(const globalIndex &globalNumbering, const labelUList &elements, List< Map< label >> &compactMap) const
Construct per processor compact addressing of the global elements.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
static label countUnmapped(const labelUList &elements, const labelListList &maps, const bool hasFlip)
Count the number of unmapped elements.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:153
commsTypes
Communications types.
Definition: UPstream.H:77
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
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
const List< labelPair > & schedule() const
Return a schedule. Demand driven. See above.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
IntListType renumber(const labelUList &oldToNew, const IntListType &input)
Renumber the values within a list.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
label whichProcID(const label proci, const label i) const
Which processor does global id come from? Checks proci first (assumed to occur reasonably frequently)...
Definition: globalIndexI.H:485
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1061
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
constexpr label labelMin
Definition: label.H:54
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
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
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
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:61
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
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
void setSize(const label n)
Alias for resize()
Definition: List.H:320
const List< labelPair > & whichSchedule(const UPstream::commsTypes commsType) const
Return real or dummy schedule depending on the communication type.
"scheduled" (MPI standard) : (MPI_Send, MPI_Recv)
static bool hasFlipAddressing(const labelUList &map)
Test for flip addressing, where flips are encoded as negative indices and non-flips are encoded as po...
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
static constexpr int masterNo() noexcept
Relative rank for the master process - is always 0.
Definition: UPstream.H:1071
void printLayout(Ostream &os) const
Debug: print layout. Can only be used on maps with sorted.
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
#define forAllIters(container, iter)
Iterate across all elements in the container object.
Definition: stdFoam.H:336
bool isLocal(const label proci, const label i) const
Is on processor proci.
Definition: globalIndexI.H:294
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
void transfer(mapDistributeBase &rhs)
Transfer the contents of the argument and annul the argument.
A list of pointers to objects of type <T>, without allocation/deallocation management of the pointers...
Definition: HashTable.H:106
errorManip< error > abort(error &err)
Definition: errorManip.H:139
A HashTable to objects of type <T> with a labelPair key. The hashing is based on labelPair (FixedList...
label find(const T &val) const
Find index of the first occurrence of the value.
Definition: UList.C:173
void operator=(const mapDistributeBase &rhs)
Copy assignment.
Class containing processor-to-processor mapping information.
const direction noexcept
Definition: Scalar.H:258
int debug
Static debugging option.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:51
OBJstream os(runTime.globalPath()/outputName)
defineTypeNameAndDebug(combustionModel, 0)
label subMapTotalSize() const noexcept
The sum of the subMap list sizes.
T & last()
Access last element of the list, position [size()-1].
Definition: UList.H:876
const labelListList & constructMap() const noexcept
From subsetted data to new reconstructed data.
static label renumber(const globalIndex &, const label comm, const List< Map< label >> &compactMap, const label globalElement)
Helper for construct from globalIndex. Renumbers element.
bool empty() const noexcept
True if the list is empty (ie, size() is zero)
Definition: UPtrListI.H:99
void exchangeAddressing(const int tag, const globalIndex &globalNumbering, labelList &elements, List< Map< label >> &compactMap, labelList &compactStart)
labelList subMapSizes() const
The sizes of the subMap lists.
void clear()
Reset to zero size, only retaining communicator.
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1094
static void exchangeSizes(const labelUList &sendProcs, const labelUList &recvProcs, const Container &sendBufs, labelList &sizes, const label tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Helper: exchange sizes of sendBufs for specified send/recv ranks.
static void checkReceivedSize(const label proci, const label expectedSize, const label receivedSize)
Fatal if expected != received size.
static label getMappedSize(const labelListList &maps, const bool hasFlip)
Scan the maps for the max addressed index.
constexpr label labelMax
Definition: label.H:55
label constructMapTotalSize() const noexcept
The sum of the constructMap list sizes.
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
mapDistributeBase() noexcept
Default construct (uses worldComm)
const labelListList & subMap() const noexcept
From subsetted data back to original data.
HashSet< labelPair, Foam::Hash< labelPair > > labelPairHashSet
A HashSet for a labelPair. The hashing is based on labelPair (FixedList) and is thus non-commutative...
bool send()
Send buffer contents now and not in destructor [advanced usage]. Returns true on success.
Definition: OPstreams.C:84
labelList constructMapSizes() const
The sizes of the constructMap lists.
static const List< T > & null() noexcept
Return a null List (reference to a nullObject). Behaves like an empty List.
Definition: List.H:153
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Inter-processor communications stream.
Definition: UPstream.H:65
Namespace for OpenFOAM.
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127