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-2023 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  IPstream fromProc
231  (
233  proci,
234  0,
235  tag,
236  comm
237  );
238  List<labelPair> nbrData(fromProc);
239 
240  for (const labelPair& connection : nbrData)
241  {
242  allComms.push_uniq(connection);
243  }
244  }
245  }
246  else
247  {
248  if (UPstream::parRun())
249  {
250  OPstream toMaster
251  (
254  0,
255  tag,
256  comm
257  );
258  toMaster << allComms;
259  }
260  }
261 
262  // Broadcast: send comms information to all
263  Pstream::broadcast(allComms, comm);
264 
265  // Determine my schedule.
266  labelList mySchedule
267  (
268  commSchedule
269  (
270  nProcs,
271  allComms
272  ).procSchedule()[myRank]
273  );
274 
275  // Processors involved in my schedule
276  return List<labelPair>(allComms, mySchedule);
277 }
278 
279 
281 {
282  if (!schedulePtr_)
283  {
284  schedulePtr_.reset
285  (
286  new List<labelPair>
287  (
288  schedule(subMap_, constructMap_, UPstream::msgType(), comm_)
289  )
290  );
291  }
292 
293  return *schedulePtr_;
294 }
295 
296 
298 (
299  const UPstream::commsTypes commsType
300 ) const
301 {
302  if (commsType == UPstream::commsTypes::scheduled)
303  {
304  return schedule();
305  }
306 
307  return List<labelPair>::null();
308 }
309 
310 
311 void Foam::mapDistributeBase::printLayout(Ostream& os) const
312 {
313  const label myRank = UPstream::myProcNo(comm_);
314  const label nProcs = UPstream::nProcs(comm_);
315 
316  // Determine offsets of remote data.
317  labelList minIndex(nProcs, labelMax);
318  labelList maxIndex(nProcs, labelMin);
319  forAll(constructMap_, proci)
320  {
321  const labelList& construct = constructMap_[proci];
322  if (constructHasFlip_)
323  {
324  forAll(construct, i)
325  {
326  label index = mag(construct[i])-1;
327  minIndex[proci] = min(minIndex[proci], index);
328  maxIndex[proci] = max(maxIndex[proci], index);
329  }
330  }
331  else
332  {
333  forAll(construct, i)
334  {
335  label index = construct[i];
336  minIndex[proci] = min(minIndex[proci], index);
337  maxIndex[proci] = max(maxIndex[proci], index);
338  }
339  }
340  }
341 
342  label localSize(0);
343 
344  if (maxIndex[myRank] != labelMin)
345  {
346  localSize = maxIndex[myRank]+1;
347  }
348 
349  os << "Layout: (constructSize:" << constructSize_
350  << " subHasFlip:" << subHasFlip_
351  << " constructHasFlip:" << constructHasFlip_
352  << ")" << nl
353  << "local (processor " << myRank << "):" << nl
354  << " start : 0" << nl
355  << " size : " << localSize << endl;
356 
357  label offset = localSize;
358  forAll(minIndex, proci)
359  {
360  if (proci != myRank && !constructMap_[proci].empty())
361  {
362  label size(0);
363 
364  if (maxIndex[proci] != labelMin)
365  {
366  size = maxIndex[proci]-minIndex[proci]+1;
367  if (minIndex[proci] != offset)
368  {
370  << "offset:" << offset
371  << " proci:" << proci
372  << " minIndex:" << minIndex[proci]
373  << abort(FatalError);
374  }
375  }
376 
377  os << "processor " << proci << ':' << nl
378  << " start : " << offset << nl
379  << " size : " << size << endl;
380 
381  offset += size;
382  }
383  }
384 }
385 
386 
388 (
389  const globalIndex& globalNumbering,
390  const labelUList& elements,
391  List<Map<label>>& compactMap
392 ) const
393 {
394  const label myRank = UPstream::myProcNo(comm_);
395  const label nProcs = UPstream::nProcs(comm_);
396 
397  // Count all (non-local) elements needed. Just for presizing map.
398  labelList nNonLocal(nProcs, Zero);
399 
400  for (const label globalIdx : elements)
401  {
402  if (globalIdx != -1 && !globalNumbering.isLocal(myRank, globalIdx))
403  {
404  label proci = globalNumbering.whichProcID(myRank, globalIdx);
405  nNonLocal[proci]++;
406  }
407  }
408 
409  compactMap.resize_nocopy(nProcs);
410 
411  forAll(compactMap, proci)
412  {
413  compactMap[proci].clear();
414  if (proci != myRank)
415  {
416  compactMap[proci].reserve(nNonLocal[proci]);
417  }
418  }
419 
420 
421  // Collect all (non-local) elements needed.
422  for (const label globalIdx : elements)
423  {
424  if (globalIdx != -1 && !globalNumbering.isLocal(myRank, globalIdx))
425  {
426  label proci = globalNumbering.whichProcID(myRank, globalIdx);
427  label index = globalNumbering.toLocal(proci, globalIdx);
428  compactMap[proci].insert(index, compactMap[proci].size());
429  }
430  }
431 }
432 
433 
435 (
436  const globalIndex& globalNumbering,
437  const labelListList& cellCells,
438  List<Map<label>>& compactMap
439 ) const
440 {
441  const label myRank = UPstream::myProcNo(comm_);
442  const label nProcs = UPstream::nProcs(comm_);
443 
444  // Count all (non-local) elements needed. Just for presizing map.
445  labelList nNonLocal(nProcs, Zero);
446 
447  for (const labelList& cCells : cellCells)
448  {
449  for (const label globalIdx : cCells)
450  {
451  if (globalIdx != -1 && !globalNumbering.isLocal(myRank, globalIdx))
452  {
453  label proci = globalNumbering.whichProcID(myRank, globalIdx);
454  nNonLocal[proci]++;
455  }
456  }
457  }
458 
459  compactMap.resize_nocopy(nProcs);
460 
461  forAll(compactMap, proci)
462  {
463  compactMap[proci].clear();
464  if (proci != myRank)
465  {
466  compactMap[proci].reserve(nNonLocal[proci]);
467  }
468  }
469 
470 
471  // Collect all (non-local) elements needed.
472  for (const labelList& cCells : cellCells)
473  {
474  for (const label globalIdx : cCells)
475  {
476  if (globalIdx != -1 && !globalNumbering.isLocal(myRank, globalIdx))
477  {
478  label proci = globalNumbering.whichProcID(myRank, globalIdx);
479  label index = globalNumbering.toLocal(proci, globalIdx);
480  compactMap[proci].insert(index, compactMap[proci].size());
481  }
482  }
483  }
484 }
485 
486 
488 (
489  const int tag,
490  const globalIndex& globalNumbering,
491  labelList& elements,
492  List<Map<label>>& compactMap,
493  labelList& compactStart
494 )
495 {
496  const label myRank = UPstream::myProcNo(comm_);
497  const label nProcs = UPstream::nProcs(comm_);
498 
499  // The overall compact addressing is
500  // - myProcNo data first (uncompacted)
501  // - all other processors consecutively
502 
503  compactStart.setSize(nProcs);
504  compactStart[myRank] = 0;
505  constructSize_ = globalNumbering.localSize(myRank);
506  forAll(compactStart, proci)
507  {
508  if (proci != myRank)
509  {
510  compactStart[proci] = constructSize_;
511  constructSize_ += compactMap[proci].size();
512  }
513  }
514 
515 
516  // Find out what to receive/send in compact addressing.
517 
518  // What I want to receive is what others have to send
519  labelListList wantedRemoteElements(nProcs);
520  // Compact addressing for received data
521  constructMap_.setSize(nProcs);
522  forAll(compactMap, proci)
523  {
524  if (proci == myRank)
525  {
526  // All my own elements are used
527  label nLocal = globalNumbering.localSize(myRank);
528  wantedRemoteElements[proci] = identity(nLocal);
529  constructMap_[proci] = identity(nLocal);
530  }
531  else
532  {
533  // Remote elements wanted from processor proci
534  labelList& remoteElem = wantedRemoteElements[proci];
535  labelList& localElem = constructMap_[proci];
536  remoteElem.setSize(compactMap[proci].size());
537  localElem.setSize(compactMap[proci].size());
538  label i = 0;
539  forAllIters(compactMap[proci], iter)
540  {
541  const label compactI = compactStart[proci] + iter.val();
542  remoteElem[i] = iter.key();
543  localElem[i] = compactI;
544  iter.val() = compactI;
545  i++;
546  }
547  }
548  }
549 
550  subMap_.setSize(nProcs);
551  Pstream::exchange<labelList, label>
552  (
553  wantedRemoteElements,
554  subMap_,
555  tag,
556  comm_
557  );
558 
559  // Renumber elements
560  for (label& elem : elements)
561  {
562  elem = renumber(globalNumbering, comm_, compactMap, elem);
563  }
564 }
565 
566 
568 (
569  const int tag,
570  const globalIndex& globalNumbering,
571  labelListList& cellCells,
572  List<Map<label>>& compactMap,
573  labelList& compactStart
574 )
575 {
576  const label myRank = UPstream::myProcNo(comm_);
577  const label nProcs = UPstream::nProcs(comm_);
578 
579  // The overall compact addressing is
580  // - myProcNo data first (uncompacted)
581  // - all other processors consecutively
582 
583  compactStart.setSize(nProcs);
584  compactStart[myRank] = 0;
585  constructSize_ = globalNumbering.localSize(myRank);
586  forAll(compactStart, proci)
587  {
588  if (proci != myRank)
589  {
590  compactStart[proci] = constructSize_;
591  constructSize_ += compactMap[proci].size();
592  }
593  }
594 
595 
596  // Find out what to receive/send in compact addressing.
597 
598  // What I want to receive is what others have to send
599  labelListList wantedRemoteElements(nProcs);
600  // Compact addressing for received data
601  constructMap_.setSize(nProcs);
602  forAll(compactMap, proci)
603  {
604  if (proci == myRank)
605  {
606  // All my own elements are used
607  label nLocal = globalNumbering.localSize(myRank);
608  wantedRemoteElements[proci] = identity(nLocal);
609  constructMap_[proci] = identity(nLocal);
610  }
611  else
612  {
613  // Remote elements wanted from processor proci
614  labelList& remoteElem = wantedRemoteElements[proci];
615  labelList& localElem = constructMap_[proci];
616  remoteElem.setSize(compactMap[proci].size());
617  localElem.setSize(compactMap[proci].size());
618  label i = 0;
619  forAllIters(compactMap[proci], iter)
620  {
621  const label compactI = compactStart[proci] + iter.val();
622  remoteElem[i] = iter.key();
623  localElem[i] = compactI;
624  iter.val() = compactI;
625  i++;
626  }
627  }
628  }
629 
630  subMap_.setSize(nProcs);
631  Pstream::exchange<labelList, label>
632  (
633  wantedRemoteElements,
634  subMap_,
635  tag,
636  comm_
637  );
638 
639  // Renumber elements
640  for (labelList& cCells : cellCells)
641  {
642  for (label& celli : cCells)
643  {
644  celli = renumber(globalNumbering, comm_, compactMap, celli);
645  }
646  }
647 }
648 
649 
650 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
653 :
654  mapDistributeBase(UPstream::worldComm)
655 {}
656 
657 
659 :
660  constructSize_(0),
661  subMap_(),
662  constructMap_(),
663  subHasFlip_(false),
664  constructHasFlip_(false),
665  comm_(comm),
666  schedulePtr_(nullptr)
667 {}
668 
669 
671 :
672  constructSize_(map.constructSize_),
673  subMap_(map.subMap_),
674  constructMap_(map.constructMap_),
675  subHasFlip_(map.subHasFlip_),
676  constructHasFlip_(map.constructHasFlip_),
677  comm_(map.comm_),
678  schedulePtr_(nullptr)
679 {}
680 
681 
683 :
684  mapDistributeBase(map.comm())
685 {
686  transfer(map);
687 }
688 
689 
691 (
692  const label constructSize,
693  labelListList&& subMap,
694  labelListList&& constructMap,
695  const bool subHasFlip,
696  const bool constructHasFlip,
697  const label comm
698 )
699 :
700  constructSize_(constructSize),
701  subMap_(std::move(subMap)),
702  constructMap_(std::move(constructMap)),
703  subHasFlip_(subHasFlip),
704  constructHasFlip_(constructHasFlip),
705  comm_(comm),
706  schedulePtr_(nullptr)
707 {}
708 
709 
711 (
712  const labelUList& sendProcs,
713  const labelUList& recvProcs,
714  const label comm
715 )
716 :
717  constructSize_(0),
718  subMap_(),
719  constructMap_(),
720  subHasFlip_(false),
721  constructHasFlip_(false),
722  comm_(comm),
723  schedulePtr_(nullptr)
724 {
725  const label myRank = UPstream::myProcNo(comm_);
726  const label nProcs = UPstream::nProcs(comm_);
727 
728  if (sendProcs.size() != recvProcs.size())
729  {
731  << "The send and receive data is not the same length. sendProcs:"
732  << sendProcs.size() << " recvProcs:" << recvProcs.size()
733  << abort(FatalError);
734  }
735 
736  // Per processor the number of samples we have to send/receive.
737  labelList nSend(nProcs, Zero);
738  labelList nRecv(nProcs, Zero);
739 
740  forAll(sendProcs, sampleI)
741  {
742  const label sendProc = sendProcs[sampleI];
743  const label recvProc = recvProcs[sampleI];
744 
745  // Note that also need to include local communication (both
746  // RecvProc and sendProc on local processor)
747 
748  if (myRank == sendProc)
749  {
750  // I am the sender.
751  nSend[recvProc]++;
752  }
753  if (myRank == recvProc)
754  {
755  // I am the receiver.
756  nRecv[sendProc]++;
757  }
758  }
759 
760  subMap_.setSize(nProcs);
761  constructMap_.setSize(nProcs);
762  forAll(nSend, proci)
763  {
764  subMap_[proci].setSize(nSend[proci]);
765  constructMap_[proci].setSize(nRecv[proci]);
766  }
767  nSend = 0;
768  nRecv = 0;
769 
770  // Largest entry inside constructMap
771  label maxRecvIndex = -1;
772 
773  forAll(sendProcs, sampleI)
774  {
775  const label sendProc = sendProcs[sampleI];
776  const label recvProc = recvProcs[sampleI];
777 
778  if (myRank == sendProc)
779  {
780  // I am the sender. Store index I need to send.
781  subMap_[recvProc][nSend[recvProc]++] = sampleI;
782  }
783  if (myRank == recvProc)
784  {
785  // I am the receiver.
786  constructMap_[sendProc][nRecv[sendProc]++] = sampleI;
787  maxRecvIndex = sampleI;
788  }
789  }
790 
791  constructSize_ = maxRecvIndex+1;
792 }
793 
794 
796 (
797  const globalIndex& globalNumbering,
798  labelList& elements,
799  List<Map<label>>& compactMap,
800  const int tag,
801  const label comm
802 )
803 :
804  constructSize_(0),
805  subMap_(),
806  constructMap_(),
807  subHasFlip_(false),
808  constructHasFlip_(false),
809  comm_(comm),
810  schedulePtr_(nullptr)
811 {
812  // Construct per processor compact addressing of the global elements
813  // needed. The ones from the local processor are not included since
814  // these are always all needed.
816  (
817  globalNumbering,
818  elements,
819  compactMap
820  );
821 
823  //forAll(compactMap, proci)
824  //{
825  // if (proci != myRank)
826  // {
827  // Map<label>& globalMap = compactMap[proci];
828  //
829  // const List<label> sorted(globalMap.sortedToc());
830  //
831  // forAll(sorted, i)
832  // {
833  // globalMap(sorted[i]) = i;
834  // }
835  // }
836  //}
837 
838 
839  // Exchange what I need with processor that supplies it. Renumber elements
840  // into compact numbering
841  labelList compactStart;
843  (
844  tag,
845  globalNumbering,
846  elements,
847  compactMap,
848  compactStart
849  );
850 
851  if (debug)
852  {
853  printLayout(Pout);
854  }
855 }
856 
857 
859 (
860  const globalIndex& globalNumbering,
861  labelListList& cellCells,
862  List<Map<label>>& compactMap,
863  const int tag,
864  const label comm
865 )
866 :
867  constructSize_(0),
868  subMap_(),
869  constructMap_(),
870  subHasFlip_(false),
871  constructHasFlip_(false),
872  comm_(comm),
873  schedulePtr_(nullptr)
874 {
875  // Construct per processor compact addressing of the global elements
876  // needed. The ones from the local processor are not included since
877  // these are always all needed.
879  (
880  globalNumbering,
881  cellCells,
882  compactMap
883  );
884 
886  //forAll(compactMap, proci)
887  //{
888  // if (proci != myRank)
889  // {
890  // Map<label>& globalMap = compactMap[proci];
891  //
892  // const List<label> sorted(globalMap.sortedToc());
893  //
894  // forAll(sorted, i)
895  // {
896  // globalMap(sorted[i]) = i;
897  // }
898  // }
899  //}
900 
901 
902  // Exchange what I need with processor that supplies it. Renumber elements
903  // into compact numbering
904  labelList compactStart;
906  (
907  tag,
908  globalNumbering,
909  cellCells,
910  compactMap,
911  compactStart
912  );
913 
914  if (debug)
915  {
916  printLayout(Pout);
917  }
918 }
919 
920 
922 (
923  const layoutTypes constructLayout,
924  labelListList&& subMap,
925  const bool subHasFlip,
926  const bool constructHasFlip,
927  const label comm
928 )
929 :
930  constructSize_(0),
931  subMap_(std::move(subMap)),
932  constructMap_(),
933  subHasFlip_(subHasFlip),
934  constructHasFlip_(constructHasFlip),
935  comm_(comm),
936  schedulePtr_(nullptr)
937 {
938  const label myRank = UPstream::myProcNo(comm_);
939  const label nProcs = UPstream::nProcs(comm_);
940 
941  // Send over how many i need to receive.
942  labelList recvSizes;
943  Pstream::exchangeSizes(subMap_, recvSizes, comm_);
944 
945  constructSize_ = 0;
946  constructMap_.resize(nProcs);
947 
948  // The order of receiving:
949 
950  if (constructLayout == layoutTypes::linear)
951  {
952  forAll(constructMap_, proci)
953  {
954  const label len = recvSizes[proci];
955 
956  constructMap_[proci] = identity(len, constructSize_);
957  constructSize_ += len;
958  }
959  }
960  else
961  {
962  // layoutTypes::localFirst
963 
964  // My data first
965  {
966  const label len = recvSizes[myRank];
967 
968  constructMap_[myRank] = identity(len, constructSize_);
969  constructSize_ += len;
970  }
971 
972  // What the other processors are sending to me
973  forAll(constructMap_, proci)
974  {
975  if (proci != myRank)
976  {
977  const label len = recvSizes[proci];
978 
979  constructMap_[proci] = identity(len, constructSize_);
980  constructSize_ += len;
981  }
982  }
983  }
984 }
985 
986 
988 (
989  labelListList&& subMap,
990  const bool subHasFlip,
991  const bool constructHasFlip,
992  const label comm
993 )
994 :
995  mapDistributeBase
996  (
997  layoutTypes::localFirst,
998  std::move(subMap),
999  subHasFlip,
1000  constructHasFlip,
1001  comm
1002  )
1003 {}
1004 
1005 
1007 (
1009  const labelList& localRanks,
1010  const label newComm,
1011  const labelListList& newToOldRanks,// from newComm to comm_
1012  labelList& startOfLocal,
1013  List<Map<label>>& compactMaps
1014 )
1015 :
1016  constructSize_(0),
1017  subHasFlip_(false),
1018  constructHasFlip_(false),
1019  comm_(-1),
1020  schedulePtr_(nullptr)
1021 {
1022  if (maps.empty())
1023  {
1024  return;
1025  }
1026 
1027  comm_ = newComm;
1028  subHasFlip_ = maps[0].subHasFlip();
1029  constructHasFlip_ = maps[0].constructHasFlip();
1030 
1031  const label nNewRanks = newToOldRanks.size();
1032  const label myNewRank = UPstream::myProcNo(newComm);
1033  if (nNewRanks != UPstream::nProcs(newComm))
1034  {
1035  FatalErrorInFunction<< "nNewRanks:" << nNewRanks
1036  << " nProcs:" << UPstream::nProcs(newComm)
1037  << exit(FatalError);
1038  }
1039 
1040  if (localRanks.size() != maps.size())
1041  {
1043  << "Number of maps:" << maps.size()
1044  << " number of localRanks:" << localRanks.size()
1045  << exit(FatalError);
1046  }
1047 
1048  // Sanity checks
1049  const auto& map0 = maps[0];
1050  forAll(maps, mapi)
1051  {
1052  const auto& map = maps[mapi];
1053 
1054  if
1055  (
1056  (map.comm() != map0.comm())
1057  || (map.subHasFlip() != map0.subHasFlip())
1058  || (map.constructHasFlip() != map0.constructHasFlip())
1059  )
1060  {
1062  << "Maps should all be the same form"
1063  << " Map " << mapi
1064  << " has comm:" << map.comm()
1065  << " subHasFlip:" << map.subHasFlip()
1066  << " constructHasFlip:" << map.constructHasFlip()
1067  << " which is different from map 0"
1068  << exit(FatalError);
1069  }
1070 
1071  const label localRank = localRanks[mapi];
1072  const auto& constructOwn = maps[mapi].constructMap()[localRank];
1073  forAll(constructOwn, i)
1074  {
1075  if (constructOwn[i] != i)
1076  {
1078  << "Maps constructMap not identity."
1079  << " Map " << mapi
1080  << " constructMap:" << flatOutput(constructOwn)
1081  << exit(FatalError);
1082  }
1083  }
1084  }
1085 
1086 
1087  constructMap_.resize_nocopy(nNewRanks);
1088  subMap_.resize_nocopy(nNewRanks);
1089 
1090 
1091  // Store starts
1092  startOfLocal.setSize(maps.size()+1);
1093  compactMaps.resize_nocopy(maps.size());
1094 
1095  label constructi = 0;
1096  forAll(maps, mapi)
1097  {
1098  startOfLocal[mapi] = constructi;
1099  const label localRank = localRanks[mapi];
1100  const auto& map = maps[mapi].constructMap()[localRank];
1101 
1102  // Presize compaction array
1103  const label nRemote = maps[mapi].constructSize()-map.size();
1104  compactMaps[mapi].resize(2*nRemote);
1105 
1106  constructi += map.size();
1107  }
1108  startOfLocal.last() = constructi;
1109 
1110 
1111  // Determine start of constructed remote data. This is used to get the
1112  // local offset which can then be used to get the relative subMap location.
1113  labelListList startOfRemote(maps.size());
1114  forAll(maps, mapi)
1115  {
1116  const label nOldProcs = maps[mapi].constructMap().size();
1117  labelList& starts = startOfRemote[mapi];
1118 
1119  starts.setSize(nOldProcs, labelMax);
1120  forAll(maps[mapi].constructMap(), oldProci)
1121  {
1122  const labelList& map = maps[mapi].constructMap()[oldProci];
1123  forAll(map, i)
1124  {
1125  const label index
1126  (
1127  constructHasFlip_
1128  ? mag(map[i])-1
1129  : map[i]
1130  );
1131  starts[oldProci] = min(starts[oldProci], index);
1132  }
1133  }
1134  }
1135 
1136 
1137  // Construct map
1138  // ~~~~~~~~~~~~~
1139  // - all localRanks:
1140  // - data gets appended in map order
1141  // - map is just an offset (startOfLocal)
1142  // - all previously remote ranks:
1143  // - data is already present according to startOfLocal
1144  // - map is old-to-new index
1145  // - all still remote ranks:
1146  // - data gets appended in map order after the startOfLocal
1147  // - map is old-to-new index
1148 
1149 
1150  // Append local (= myRank) data. TBD: assumes subMap and constructMap
1151  // are identity maps.
1152  {
1153  labelList& myConstruct = constructMap_[myNewRank];
1154  myConstruct.resize_nocopy(constructi);
1155  constructi = 0;
1156  forAll(maps, mapi)
1157  {
1158  const label localRank = localRanks[mapi];
1159  const auto& map = maps[mapi].constructMap()[localRank];
1160  const label offset = startOfLocal[mapi];
1161 
1162  forAll(map, i)
1163  {
1164  if (constructHasFlip_)
1165  {
1166  forAll(map, i)
1167  {
1168  if (map[i] < 0)
1169  {
1170  myConstruct[constructi++] = map[i]-offset;
1171  }
1172  else
1173  {
1174  myConstruct[constructi++] = map[i]+offset;
1175  }
1176  }
1177  }
1178  else
1179  {
1180  myConstruct[constructi++] = map[i]+offset;
1181  }
1182  }
1183  }
1184  }
1185 
1186  // Filter remote construct data
1187  {
1188  // Remote ranks that are now local
1189  // - store new index for mapping stencils
1190  // - no need to construct since already
1191  const auto& oldProcs = newToOldRanks[myNewRank];
1192 
1193  forAll(maps, mapi)
1194  {
1195  for (const label oldProci : oldProcs)
1196  {
1197  if (oldProci != localRanks[mapi])
1198  {
1199  const auto& map = maps[mapi].constructMap()[oldProci];
1200 
1201  if (!map.size())
1202  {
1203  continue;
1204  }
1205 
1206 
1207  // The slots come from a local map so we can look up the
1208  // new location
1209  const label sourceMapi = localRanks.find(oldProci);
1210  const auto& subMap =
1211  maps[sourceMapi].subMap()[localRanks[mapi]];
1212 
1213  //Pout<< "From oldRank:" << oldProci
1214  // << " sending to masterRank:" << localRanks[mapi]
1215  // << " elements:" << flatOutput(subMap)
1216  // << nl
1217  // << " received as elements:" << flatOutput(map)
1218  // << endl;
1219 
1220  if (map.size() != subMap.size())
1221  {
1222  FatalErrorInFunction << "Problem:"
1223  << "oldProci:" << oldProci
1224  << " mapi:" << mapi
1225  << " constructMap:" << map.size()
1226  << " sourceMapi:" << sourceMapi
1227  << " subMap:" << subMap.size()
1228  << exit(FatalError);
1229  }
1230 
1231  const label offset = startOfLocal[sourceMapi];
1232  // Construct map starts after the local data
1233  const label nMapLocal = startOfRemote[mapi][oldProci];
1234 
1235  auto& cptMap = compactMaps[mapi];
1236  forAll(map, i)
1237  {
1238  // old slot position to new slot position
1239  const label index
1240  (
1241  constructHasFlip_
1242  ? mag(map[i])-1
1243  : map[i]
1244  );
1245  const label newIndex = subMap[index-nMapLocal]+offset;
1246 
1247  // Note: should always warn for duplicates? Or only if
1248  // different?
1249  if
1250  (
1251  !cptMap.insert(index, newIndex)
1252  && cptMap[index] != newIndex
1253  )
1254  {
1255  FatalErrorInFunction<< "Duplicate insertion"
1256  << "From oldProc:" << oldProci
1257  << " on map:" << mapi
1258  << " at index:" << i
1259  << " have construct slot:" << index
1260  << " new index:" << newIndex
1261  << " but already have entry:" << cptMap[index]
1262  << " on for that slot"
1263  << exit(FatalError);
1264  }
1265  }
1266  }
1267  }
1268  }
1269 
1270 
1271  // Remote ranks that are still remote
1272  // - store new index for mapping stencils
1273  // - append to construction
1274 
1275  // Either loop over all old ranks and filter out ones already handled
1276  // or loop over all new ranks and avoid myNewRank
1277 
1278  forAll(newToOldRanks, newProci)
1279  {
1280  if (newProci != myNewRank)
1281  {
1282  const auto& oldProcs = newToOldRanks[newProci];
1283 
1284  label allSize = 0;
1285  forAll(maps, mapi)
1286  {
1287  for (const label oldProci : oldProcs)
1288  {
1289  allSize += maps[mapi].constructMap()[oldProci].size();
1290  }
1291  }
1292 
1293  labelList& myConstruct = constructMap_[newProci];
1294  myConstruct.resize_nocopy(allSize);
1295 
1296  allSize = 0;
1297  forAll(maps, mapi)
1298  {
1299  for (const label oldProci : oldProcs)
1300  {
1301  const auto& map = maps[mapi].constructMap()[oldProci];
1302  // Construct map starts after the local data
1303  const label nMapLocal = startOfRemote[mapi][oldProci];
1304  SubList<label> slice(myConstruct, map.size(), allSize);
1305 
1306  if (constructHasFlip_)
1307  {
1308  forAll(map, i)
1309  {
1310  if (map[i] < 0)
1311  {
1312  slice[i] = map[i]+nMapLocal-constructi;
1313  }
1314  else
1315  {
1316  slice[i] = map[i]-nMapLocal+constructi;
1317  }
1318  }
1319 
1320  auto& cptMap = compactMaps[mapi];
1321  forAll(map, i)
1322  {
1323  cptMap.insert(mag(map[i])-1,mag(slice[i])-1);
1324  }
1325  }
1326  else
1327  {
1328  forAll(map, i)
1329  {
1330  slice[i] = map[i]-nMapLocal+constructi;
1331  compactMaps[mapi].insert(map[i], slice[i]);
1332  }
1333  }
1334  allSize += map.size();
1335  constructi += map.size();
1336  }
1337  }
1338  }
1339  }
1340  }
1341 
1342 
1343  // Sub (=send) map
1344  // ~~~~~~~~~~~~~~~
1345  // - all localRanks:
1346  // - get appended in map order
1347  // - all previously remote ranks:
1348  // - not needed. Stay empty
1349  // - all still remote ranks:
1350  // - convert to new local index
1351 
1352  // Append local (= myRank) data
1353  {
1354  label allSize = 0;
1355  forAll(maps, mapi)
1356  {
1357  const label localRank = localRanks[mapi];
1358  allSize += maps[mapi].subMap()[localRank].size();
1359  }
1360 
1361  labelList& mySub = subMap_[myNewRank];
1362  mySub.resize_nocopy(allSize);
1363  allSize = 0;
1364  forAll(maps, mapi)
1365  {
1366  const label localRank = localRanks[mapi];
1367  const auto& map = maps[mapi].subMap()[localRank];
1368  SubList<label> slice(mySub, map.size(), allSize);
1369 
1370  if (subHasFlip_)
1371  {
1372  forAll(slice, i)
1373  {
1374  if (map[i] < 0)
1375  {
1376  slice[i] = map[i]-startOfLocal[mapi];
1377  }
1378  else
1379  {
1380  slice[i] = map[i]+startOfLocal[mapi];
1381  }
1382  }
1383  }
1384  else
1385  {
1386  forAll(slice, i)
1387  {
1388  slice[i] = map[i]+startOfLocal[mapi];
1389  }
1390  }
1391  allSize += map.size();
1392  }
1393  }
1394  // Filter remote sub data
1395  forAll(newToOldRanks, newProci)
1396  {
1397  if (newProci != myNewRank)
1398  {
1399  const auto& oldProcs = newToOldRanks[newProci];
1400 
1401  label allSize = 0;
1402  forAll(maps, mapi)
1403  {
1404  for (const label oldProci : oldProcs)
1405  {
1406  allSize += maps[mapi].subMap()[oldProci].size();
1407  }
1408  }
1409 
1410  labelList& mySub = subMap_[newProci];
1411  mySub.resize_nocopy(allSize);
1412 
1413  allSize = 0;
1414  for (const label oldProci : oldProcs)
1415  {
1416  forAll(maps, mapi)
1417  {
1418  const auto& map = maps[mapi].subMap()[oldProci];
1419  SubList<label> slice(mySub, map.size(), allSize);
1420  if (subHasFlip_)
1421  {
1422  forAll(map, i)
1423  {
1424  if (map[i] < 0)
1425  {
1426  slice[i] = map[i]-startOfLocal[mapi];
1427  }
1428  else
1429  {
1430  slice[i] = map[i]+startOfLocal[mapi];
1431  }
1432  }
1433  }
1434  else
1435  {
1436  forAll(map, i)
1437  {
1438  slice[i] = map[i]+startOfLocal[mapi];
1439  }
1440  }
1441  allSize += map.size();
1442  }
1443  }
1444  }
1445  }
1446 
1448  constructSize_ = constructi;
1449 }
1450 
1451 
1452 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
1453 
1455 {
1456  labelList sizes(subMap_.size());
1457  forAll(subMap_, i)
1458  {
1459  sizes[i] = subMap_[i].size();
1460  }
1461  return sizes;
1462 }
1463 
1464 
1466 {
1467  labelList sizes(constructMap_.size());
1468  forAll(constructMap_, i)
1469  {
1470  sizes[i] = constructMap_[i].size();
1471  }
1472  return sizes;
1473 }
1474 
1475 
1477 {
1478  label total = 0;
1479  for (const auto& list : subMap_)
1480  {
1481  total += list.size();
1482  }
1483  return total;
1484 }
1485 
1486 
1488 {
1489  label total = 0;
1490  for (const auto& list : constructMap_)
1491  {
1492  total += list.size();
1493  }
1494  return total;
1495 }
1496 
1497 
1499 {
1500  constructSize_ = 0;
1501  subMap_.clear();
1502  constructMap_.clear();
1503  subHasFlip_ = false;
1504  constructHasFlip_ = false;
1505  // Leave comm_ intact
1506  schedulePtr_.reset(nullptr);
1507 }
1508 
1509 
1511 {
1512  if (this == &rhs)
1513  {
1514  // Self-assignment is a no-op
1515  return;
1516  }
1517 
1518  constructSize_ = rhs.constructSize_;
1519  subMap_.transfer(rhs.subMap_);
1520  constructMap_.transfer(rhs.constructMap_);
1521  subHasFlip_ = rhs.subHasFlip_;
1522  constructHasFlip_ = rhs.constructHasFlip_;
1523  comm_ = rhs.comm_;
1524  schedulePtr_.reset(nullptr);
1525 
1526  rhs.constructSize_ = 0;
1527  rhs.subHasFlip_ = false;
1528  rhs.constructHasFlip_ = false;
1529 }
1530 
1531 
1533 (
1534  const globalIndex& globalNumbering,
1535  const label comm,
1536  const List<Map<label>>& compactMap,
1537  const label globalI
1538 )
1539 {
1540  const label myRank = Pstream::myProcNo(comm);
1541 
1542  if (globalI == -1)
1543  {
1544  return globalI;
1545  }
1546  if (globalNumbering.isLocal(myRank, globalI))
1547  {
1548  return globalNumbering.toLocal(myRank, globalI);
1549  }
1550  else
1551  {
1552  label proci = globalNumbering.whichProcID(myRank, globalI);
1553  label index = globalNumbering.toLocal(proci, globalI);
1554  return compactMap[proci][index];
1555  }
1556 }
1557 
1558 
1559 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1560 
1561 void Foam::mapDistributeBase::operator=(const mapDistributeBase& rhs)
1562 {
1563  if (this == &rhs)
1564  {
1565  return; // Self-assignment is a no-op
1566  }
1567 
1568  constructSize_ = rhs.constructSize_;
1569  subMap_ = rhs.subMap_;
1570  constructMap_ = rhs.constructMap_;
1571  subHasFlip_ = rhs.subHasFlip_;
1572  constructHasFlip_ = rhs.constructHasFlip_;
1573  comm_ = rhs.comm_;
1574  schedulePtr_.reset(nullptr);
1575 }
1576 
1577 
1579 {
1580  if (this != &rhs)
1581  {
1582  // Avoid self assignment
1583  transfer(rhs);
1584  }
1585 }
1586 
1587 
1588 // ************************************************************************* //
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:160
commsTypes
Communications types.
Definition: UPstream.H:72
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:598
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 (not the indices) of 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:1049
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:175
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:1229
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:1074
static const List< T > & null()
Return a null List.
Definition: ListI.H:130
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:1065
void setSize(const label n)
Alias for resize()
Definition: List.H:316
const List< labelPair > & whichSchedule(const UPstream::commsTypes commsType) const
Return real or dummy schedule depending on the communication type.
"scheduled" : (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:1059
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:867
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:1082
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:1185
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...
labelList constructMapSizes() const
The sizes of the constructMap lists.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Inter-processor communications stream.
Definition: UPstream.H:60
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