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-2020 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 "commSchedule.H"
31 #include "labelPairHashes.H"
32 #include "globalIndex.H"
33 #include "ListOps.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39  defineTypeNameAndDebug(mapDistributeBase, 0);
40 }
41 
42 
43 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
44 
46 (
47  const labelListList& subMap,
48  const labelListList& constructMap,
49  const int tag,
50  const label comm
51 )
52 {
53  const label myRank = Pstream::myProcNo(comm);
54  const label nProcs = Pstream::nProcs(comm);
55 
56  // Communications: send and receive processor
57  List<labelPair> allComms;
58 
59  {
60  labelPairHashSet commsSet(nProcs);
61 
62  // Find what communication is required
63  forAll(subMap, proci)
64  {
65  if (proci != myRank)
66  {
67  if (subMap[proci].size())
68  {
69  // I need to send to proci
70  commsSet.insert(labelPair(myRank, proci));
71  }
72  if (constructMap[proci].size())
73  {
74  // I need to receive from proci
75  commsSet.insert(labelPair(proci, myRank));
76  }
77  }
78  }
79  allComms = commsSet.toc();
80  }
81 
82 
83  // Reduce
84  if (Pstream::master(comm))
85  {
86  // Receive and merge
87  for (const int slave : Pstream::subProcs(comm))
88  {
89  IPstream fromSlave
90  (
91  Pstream::commsTypes::scheduled,
92  slave,
93  0,
94  tag,
95  comm
96  );
97  List<labelPair> nbrData(fromSlave);
98 
99  forAll(nbrData, i)
100  {
101  if (!allComms.found(nbrData[i]))
102  {
103  label sz = allComms.size();
104  allComms.setSize(sz+1);
105  allComms[sz] = nbrData[i];
106  }
107  }
108  }
109  // Send back
110  for (const int slave : Pstream::subProcs(comm))
111  {
112  OPstream toSlave
113  (
114  Pstream::commsTypes::scheduled,
115  slave,
116  0,
117  tag,
118  comm
119  );
120  toSlave << allComms;
121  }
122  }
123  else
124  {
125  {
126  OPstream toMaster
127  (
128  Pstream::commsTypes::scheduled,
129  Pstream::masterNo(),
130  0,
131  tag,
132  comm
133  );
134  toMaster << allComms;
135  }
136  {
137  IPstream fromMaster
138  (
139  Pstream::commsTypes::scheduled,
140  Pstream::masterNo(),
141  0,
142  tag,
143  comm
144  );
145  fromMaster >> allComms;
146  }
147  }
148 
149 
150  // Determine my schedule.
151  labelList mySchedule
152  (
154  (
155  nProcs,
156  allComms
157  ).procSchedule()[myRank]
158  );
159 
160  // Processors involved in my schedule
161  return List<labelPair>(UIndirectList<labelPair>(allComms, mySchedule));
162 
163 
164  //if (debug)
165  //{
166  // Pout<< "I need to:" << endl;
167  // const List<labelPair>& comms = schedule();
168  // forAll(comms, i)
169  // {
170  // const labelPair& twoProcs = comms[i];
171  // label sendProc = twoProcs[0];
172  // label recvProc = twoProcs[1];
173  //
174  // if (recvProc == myRank)
175  // {
176  // Pout<< " receive from " << sendProc << endl;
177  // }
178  // else
179  // {
180  // Pout<< " send to " << recvProc << endl;
181  // }
182  // }
183  //}
184 }
185 
186 
188 {
189  if (!schedulePtr_)
190  {
191  schedulePtr_.reset
192  (
193  new List<labelPair>
194  (
196  )
197  );
198  }
199  return *schedulePtr_;
200 }
201 
202 
204 (
205  const label proci,
206  const label expectedSize,
207  const label receivedSize
208 )
209 {
210  if (receivedSize != expectedSize)
211  {
213  << "Expected from processor " << proci
214  << " " << expectedSize << " but received "
215  << receivedSize << " elements."
216  << abort(FatalError);
217  }
218 }
219 
220 
222 {
223  const label myRank = Pstream::myProcNo(comm_);
224  const label nProcs = Pstream::nProcs(comm_);
225 
226  // Determine offsets of remote data.
227  labelList minIndex(nProcs, labelMax);
228  labelList maxIndex(nProcs, labelMin);
229  forAll(constructMap_, proci)
230  {
231  const labelList& construct = constructMap_[proci];
232  if (constructHasFlip_)
233  {
234  forAll(construct, i)
235  {
236  label index = mag(construct[i])-1;
237  minIndex[proci] = min(minIndex[proci], index);
238  maxIndex[proci] = max(maxIndex[proci], index);
239  }
240  }
241  else
242  {
243  forAll(construct, i)
244  {
245  label index = construct[i];
246  minIndex[proci] = min(minIndex[proci], index);
247  maxIndex[proci] = max(maxIndex[proci], index);
248  }
249  }
250  }
251 
252  label localSize;
253  if (maxIndex[myRank] == labelMin)
254  {
255  localSize = 0;
256  }
257  else
258  {
259  localSize = maxIndex[myRank]+1;
260  }
261 
262  os << "Layout: (constructSize:" << constructSize_
263  << " subHasFlip:" << subHasFlip_
264  << " constructHasFlip:" << constructHasFlip_
265  << ")" << endl
266  << "local (processor " << myRank << "):" << endl
267  << " start : 0" << endl
268  << " size : " << localSize << endl;
269 
270  label offset = localSize;
271  forAll(minIndex, proci)
272  {
273  if (proci != myRank)
274  {
275  if (constructMap_[proci].size() > 0)
276  {
277  if (minIndex[proci] != offset)
278  {
280  << "offset:" << offset
281  << " proci:" << proci
282  << " minIndex:" << minIndex[proci]
283  << abort(FatalError);
284  }
285 
286  label size = maxIndex[proci]-minIndex[proci]+1;
287  os << "processor " << proci << ':' << endl
288  << " start : " << offset << endl
289  << " size : " << size << endl;
290 
291  offset += size;
292  }
293  }
294  }
295 }
296 
297 
299 (
300  const globalIndex& globalNumbering,
301  const labelUList& elements,
302  List<Map<label>>& compactMap
303 ) const
304 {
305  const label myRank = Pstream::myProcNo(comm_);
306  const label nProcs = Pstream::nProcs(comm_);
307 
308  compactMap.setSize(nProcs);
309 
310  // Count all (non-local) elements needed. Just for presizing map.
311  labelList nNonLocal(nProcs, Zero);
312 
313  for (const label globalIdx : elements)
314  {
315  if (globalIdx != -1 && !globalNumbering.isLocal(globalIdx))
316  {
317  label proci = globalNumbering.whichProcID(globalIdx);
318  nNonLocal[proci]++;
319  }
320  }
321 
322  forAll(compactMap, proci)
323  {
324  compactMap[proci].clear();
325  if (proci != myRank)
326  {
327  compactMap[proci].resize(2*nNonLocal[proci]);
328  }
329  }
330 
331 
332  // Collect all (non-local) elements needed.
333  for (const label globalIdx : elements)
334  {
335  if (globalIdx != -1 && !globalNumbering.isLocal(globalIdx))
336  {
337  label proci = globalNumbering.whichProcID(globalIdx);
338  label index = globalNumbering.toLocal(proci, globalIdx);
339  label nCompact = compactMap[proci].size();
340  compactMap[proci].insert(index, nCompact);
341  }
342  }
343 }
344 
345 
347 (
348  const globalIndex& globalNumbering,
349  const labelListList& cellCells,
350  List<Map<label>>& compactMap
351 ) const
352 {
353  const label myRank = Pstream::myProcNo(comm_);
354  const label nProcs = Pstream::nProcs(comm_);
355 
356  compactMap.setSize(nProcs);
357 
358  // Count all (non-local) elements needed. Just for presizing map.
359  labelList nNonLocal(nProcs, Zero);
360 
361  for (const labelList& cCells : cellCells)
362  {
363  for (const label globalIdx : cCells)
364  {
365  if (globalIdx != -1 && !globalNumbering.isLocal(globalIdx))
366  {
367  label proci = globalNumbering.whichProcID(globalIdx);
368  nNonLocal[proci]++;
369  }
370  }
371  }
372 
373  forAll(compactMap, proci)
374  {
375  compactMap[proci].clear();
376  if (proci != myRank)
377  {
378  compactMap[proci].resize(2*nNonLocal[proci]);
379  }
380  }
381 
382 
383  // Collect all (non-local) elements needed.
384  for (const labelList& cCells : cellCells)
385  {
386  for (const label globalIdx : cCells)
387  {
388  if (globalIdx != -1 && !globalNumbering.isLocal(globalIdx))
389  {
390  label proci = globalNumbering.whichProcID(globalIdx);
391  label index = globalNumbering.toLocal(proci, globalIdx);
392  label nCompact = compactMap[proci].size();
393  compactMap[proci].insert(index, nCompact);
394  }
395  }
396  }
397 }
398 
399 
401 (
402  const int tag,
403  const globalIndex& globalNumbering,
404  labelList& elements,
405  List<Map<label>>& compactMap,
406  labelList& compactStart
407 )
408 {
409  const label myRank = Pstream::myProcNo(comm_);
410  const label nProcs = Pstream::nProcs(comm_);
411 
412  // The overall compact addressing is
413  // - myProcNo data first (uncompacted)
414  // - all other processors consecutively
415 
416  compactStart.setSize(nProcs);
417  compactStart[myRank] = 0;
418  constructSize_ = globalNumbering.localSize();
419  forAll(compactStart, proci)
420  {
421  if (proci != myRank)
422  {
423  compactStart[proci] = constructSize_;
424  constructSize_ += compactMap[proci].size();
425  }
426  }
427 
428 
429 
430  // Find out what to receive/send in compact addressing.
431 
432  // What I want to receive is what others have to send
433  labelListList wantedRemoteElements(nProcs);
434  // Compact addressing for received data
435  constructMap_.setSize(nProcs);
436  forAll(compactMap, proci)
437  {
438  if (proci == myRank)
439  {
440  // All my own elements are used
441  label nLocal = globalNumbering.localSize();
442  wantedRemoteElements[proci] = identity(nLocal);
443  constructMap_[proci] = identity(nLocal);
444  }
445  else
446  {
447  // Remote elements wanted from processor proci
448  labelList& remoteElem = wantedRemoteElements[proci];
449  labelList& localElem = constructMap_[proci];
450  remoteElem.setSize(compactMap[proci].size());
451  localElem.setSize(compactMap[proci].size());
452  label i = 0;
453  forAllIters(compactMap[proci], iter)
454  {
455  const label compactI = compactStart[proci] + iter.val();
456  remoteElem[i] = iter.key();
457  localElem[i] = compactI;
458  iter() = compactI;
459  i++;
460  }
461  }
462  }
463 
464  subMap_.setSize(nProcs);
465  Pstream::exchange<labelList, label>
466  (
467  wantedRemoteElements,
468  subMap_,
469  tag,
470  comm_
471  );
472 
473  // Renumber elements
474  for (label& elem : elements)
475  {
476  elem = renumber(globalNumbering, compactMap, elem);
477  }
478 }
479 
480 
482 (
483  const int tag,
484  const globalIndex& globalNumbering,
485  labelListList& cellCells,
486  List<Map<label>>& compactMap,
487  labelList& compactStart
488 )
489 {
490  const label myRank = Pstream::myProcNo(comm_);
491  const label nProcs = Pstream::nProcs(comm_);
492 
493  // The overall compact addressing is
494  // - myProcNo data first (uncompacted)
495  // - all other processors consecutively
496 
497  compactStart.setSize(nProcs);
498  compactStart[myRank] = 0;
499  constructSize_ = globalNumbering.localSize();
500  forAll(compactStart, proci)
501  {
502  if (proci != myRank)
503  {
504  compactStart[proci] = constructSize_;
505  constructSize_ += compactMap[proci].size();
506  }
507  }
508 
509 
510  // Find out what to receive/send in compact addressing.
511 
512  // What I want to receive is what others have to send
513  labelListList wantedRemoteElements(nProcs);
514  // Compact addressing for received data
515  constructMap_.setSize(nProcs);
516  forAll(compactMap, proci)
517  {
518  if (proci == myRank)
519  {
520  // All my own elements are used
521  label nLocal = globalNumbering.localSize();
522  wantedRemoteElements[proci] = identity(nLocal);
523  constructMap_[proci] = identity(nLocal);
524  }
525  else
526  {
527  // Remote elements wanted from processor proci
528  labelList& remoteElem = wantedRemoteElements[proci];
529  labelList& localElem = constructMap_[proci];
530  remoteElem.setSize(compactMap[proci].size());
531  localElem.setSize(compactMap[proci].size());
532  label i = 0;
533  forAllIters(compactMap[proci], iter)
534  {
535  const label compactI = compactStart[proci] + iter.val();
536  remoteElem[i] = iter.key();
537  localElem[i] = compactI;
538  iter() = compactI;
539  i++;
540  }
541  }
542  }
543 
544  subMap_.setSize(nProcs);
545  Pstream::exchange<labelList, label>
546  (
547  wantedRemoteElements,
548  subMap_,
549  tag,
550  comm_
551  );
552 
553  // Renumber elements
554  for (labelList& cCells : cellCells)
555  {
556  for (label& celli : cCells)
557  {
558  celli = renumber(globalNumbering, compactMap, celli);
559  }
560  }
561 }
562 
563 
564 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
565 
567 :
568  constructSize_(0),
569  subHasFlip_(false),
570  constructHasFlip_(false),
571  comm_(comm),
572  schedulePtr_()
573 {}
574 
575 
576 
578 :
579  constructSize_(map.constructSize_),
580  subMap_(map.subMap_),
581  constructMap_(map.constructMap_),
582  subHasFlip_(map.subHasFlip_),
583  constructHasFlip_(map.constructHasFlip_),
584  comm_(map.comm_),
585  schedulePtr_()
586 {}
587 
588 
590 :
592 {
593  transfer(map);
594 }
595 
596 
598 (
599  const label constructSize,
600  labelListList&& subMap,
601  labelListList&& constructMap,
602  const bool subHasFlip,
603  const bool constructHasFlip,
604  const label comm
605 )
606 :
607  constructSize_(constructSize),
608  subMap_(std::move(subMap)),
609  constructMap_(std::move(constructMap)),
610  subHasFlip_(subHasFlip),
611  constructHasFlip_(constructHasFlip),
612  comm_(comm),
613  schedulePtr_()
614 {}
615 
616 
618 (
619  const labelUList& sendProcs,
620  const labelUList& recvProcs,
621  const label comm
622 )
623 :
624  constructSize_(0),
625  subHasFlip_(false),
626  constructHasFlip_(false),
627  comm_(comm),
628  schedulePtr_()
629 {
630  const label myRank = Pstream::myProcNo(comm_);
631  const label nProcs = Pstream::nProcs(comm_);
632 
633  if (sendProcs.size() != recvProcs.size())
634  {
636  << "The send and receive data is not the same length. sendProcs:"
637  << sendProcs.size() << " recvProcs:" << recvProcs.size()
638  << abort(FatalError);
639  }
640 
641  // Per processor the number of samples we have to send/receive.
642  labelList nSend(nProcs, Zero);
643  labelList nRecv(nProcs, Zero);
644 
645  forAll(sendProcs, sampleI)
646  {
647  const label sendProc = sendProcs[sampleI];
648  const label recvProc = recvProcs[sampleI];
649 
650  // Note that also need to include local communication (both
651  // RecvProc and sendProc on local processor)
652 
653  if (myRank == sendProc)
654  {
655  // I am the sender. Count destination processor.
656  nSend[recvProc]++;
657  }
658  if (myRank == recvProc)
659  {
660  // I am the receiver.
661  nRecv[sendProc]++;
662  }
663  }
664 
665  subMap_.setSize(nProcs);
666  constructMap_.setSize(nProcs);
667  forAll(nSend, proci)
668  {
669  subMap_[proci].setSize(nSend[proci]);
670  constructMap_[proci].setSize(nRecv[proci]);
671  }
672  nSend = 0;
673  nRecv = 0;
674 
675  forAll(sendProcs, sampleI)
676  {
677  const label sendProc = sendProcs[sampleI];
678  const label recvProc = recvProcs[sampleI];
679 
680  if (myRank == sendProc)
681  {
682  // I am the sender. Store index I need to send.
683  subMap_[recvProc][nSend[recvProc]++] = sampleI;
684  }
685  if (myRank == recvProc)
686  {
687  // I am the receiver.
688  constructMap_[sendProc][nRecv[sendProc]++] = sampleI;
689  // Largest entry inside constructMap
690  constructSize_ = sampleI+1;
691  }
692  }
693 }
694 
695 
697 (
698  const globalIndex& globalNumbering,
699  labelList& elements,
700  List<Map<label>>& compactMap,
701  const int tag,
702  const label comm
703 )
704 :
705  constructSize_(0),
706  subHasFlip_(false),
707  constructHasFlip_(false),
708  comm_(comm),
709  schedulePtr_()
710 {
711  // Construct per processor compact addressing of the global elements
712  // needed. The ones from the local processor are not included since
713  // these are always all needed.
714  calcCompactAddressing
715  (
716  globalNumbering,
717  elements,
718  compactMap
719  );
720 
722  //forAll(compactMap, proci)
723  //{
724  // if (proci != myRank)
725  // {
726  // Map<label>& globalMap = compactMap[proci];
727  //
728  // const List<label> sorted(globalMap.sortedToc());
729  //
730  // forAll(sorted, i)
731  // {
732  // globalMap(sorted[i]) = i;
733  // }
734  // }
735  //}
736 
737 
738  // Exchange what I need with processor that supplies it. Renumber elements
739  // into compact numbering
740  labelList compactStart;
741  exchangeAddressing
742  (
743  tag,
744  globalNumbering,
745  elements,
746  compactMap,
747  compactStart
748  );
749 
750  if (debug)
751  {
752  printLayout(Pout);
753  }
754 }
755 
756 
758 (
759  const globalIndex& globalNumbering,
760  labelListList& cellCells,
761  List<Map<label>>& compactMap,
762  const int tag,
763  const label comm
764 )
765 :
766  constructSize_(0),
767  subHasFlip_(false),
768  constructHasFlip_(false),
769  comm_(comm),
770  schedulePtr_()
771 {
772  // Construct per processor compact addressing of the global elements
773  // needed. The ones from the local processor are not included since
774  // these are always all needed.
775  calcCompactAddressing
776  (
777  globalNumbering,
778  cellCells,
779  compactMap
780  );
781 
783  //forAll(compactMap, proci)
784  //{
785  // if (proci != myRank)
786  // {
787  // Map<label>& globalMap = compactMap[proci];
788  //
789  // const List<label> sorted(globalMap.sortedToc());
790  //
791  // forAll(sorted, i)
792  // {
793  // globalMap(sorted[i]) = i;
794  // }
795  // }
796  //}
797 
798 
799  // Exchange what I need with processor that supplies it. Renumber elements
800  // into compact numbering
801  labelList compactStart;
802  exchangeAddressing
803  (
804  tag,
805  globalNumbering,
806  cellCells,
807  compactMap,
808  compactStart
809  );
810 
811  if (debug)
812  {
813  printLayout(Pout);
814  }
815 }
816 
817 
819 (
820  labelListList&& subMap,
821  const bool subHasFlip,
822  const bool constructHasFlip,
823  const label comm
824 )
825 :
826  constructSize_(0),
827  subMap_(std::move(subMap)),
828  subHasFlip_(subHasFlip),
829  constructHasFlip_(constructHasFlip),
830  comm_(comm),
831  schedulePtr_()
832 {
833  const label myRank = Pstream::myProcNo(comm_);
834  const label nProcs = Pstream::nProcs(comm_);
835 
836  // Send over how many i need to receive.
837  labelList recvSizes;
838  Pstream::exchangeSizes(subMap_, recvSizes, comm_);
839 
840  // Determine order of receiving
841  labelListList constructMap(nProcs);
842 
843  // My local segments first
844  label nLocal = recvSizes[myRank];
845  {
846  labelList& myMap = constructMap[myRank];
847  myMap.setSize(nLocal);
848  forAll(myMap, i)
849  {
850  myMap[i] = i;
851  }
852  }
853 
854  label segmenti = nLocal;
855  forAll(constructMap, proci)
856  {
857  if (proci != myRank)
858  {
859  // What i need to receive is what other processor is sending to me.
860  label nRecv = recvSizes[proci];
861  constructMap[proci].setSize(nRecv);
862 
863  for (label i = 0; i < nRecv; i++)
864  {
865  constructMap[proci][i] = segmenti++;
866  }
867  }
868  }
869 
870  constructSize_ = segmenti;
871  constructMap_.transfer(constructMap);
872 }
873 
874 
876 {
877  is >> *this;
878 }
879 
880 
881 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
882 
884 {
885  if (this == &rhs)
886  {
887  // Self-assignment is a no-op
888  return;
889  }
890 
891  constructSize_ = rhs.constructSize_;
892  subMap_.transfer(rhs.subMap_);
893  constructMap_.transfer(rhs.constructMap_);
894  subHasFlip_ = rhs.subHasFlip_;
895  constructHasFlip_ = rhs.constructHasFlip_;
896  comm_ = rhs.comm_;
897  schedulePtr_.clear();
898 
899  rhs.constructSize_ = 0;
900  rhs.subHasFlip_ = false;
901  rhs.constructHasFlip_ = false;
902 }
903 
904 
906 (
907  const globalIndex& globalNumbering,
908  const List<Map<label>>& compactMap,
909  const label globalI
910 )
911 {
912  if (globalI == -1)
913  {
914  return globalI;
915  }
916  if (globalNumbering.isLocal(globalI))
917  {
918  return globalNumbering.toLocal(globalI);
919  }
920  else
921  {
922  label proci = globalNumbering.whichProcID(globalI);
923  label index = globalNumbering.toLocal(proci, globalI);
924  return compactMap[proci][index];
925  }
926 }
927 
928 
930 (
931  const boolList& elemIsUsed,
932  const int tag
933 )
934 {
935  const label myRank = Pstream::myProcNo(comm_);
936  const label nProcs = Pstream::nProcs(comm_);
937 
938  // 1. send back to sender. Have sender delete the corresponding element
939  // from the submap and do the same to the constructMap locally
940  // (and in same order).
941 
942  // Send elemIsUsed field to neighbour. Use nonblocking code from
943  // mapDistributeBase but in reverse order.
944  if (Pstream::parRun())
945  {
946  label startOfRequests = Pstream::nRequests();
947 
948  // Set up receives from neighbours
949 
950  List<boolList> recvFields(nProcs);
951 
952  for (const int domain : Pstream::allProcs(comm_))
953  {
954  const labelList& map = subMap_[domain];
955 
956  if (domain != myRank && map.size())
957  {
958  recvFields[domain].setSize(map.size());
960  (
962  domain,
963  reinterpret_cast<char*>(recvFields[domain].data()),
964  recvFields[domain].size()*sizeof(bool),
965  tag,
966  comm_
967  );
968  }
969  }
970 
971 
972  List<boolList> sendFields(nProcs);
973 
974  for (const int domain : Pstream::allProcs(comm_))
975  {
976  const labelList& map = constructMap_[domain];
977 
978  if (domain != myRank && map.size())
979  {
980  boolList& subField = sendFields[domain];
981  subField.setSize(map.size());
982  forAll(map, i)
983  {
984  subField[i] = accessAndFlip
985  (
986  elemIsUsed,
987  map[i],
988  constructHasFlip_,
989  noOp() // do not flip elemIsUsed value
990  );
991  }
992 
994  (
996  domain,
997  reinterpret_cast<const char*>(subField.cdata()),
998  subField.size()*sizeof(bool),
999  tag,
1000  comm_
1001  );
1002  }
1003  }
1004 
1005 
1006 
1007  // Set up 'send' to myself - write directly into recvFields
1008 
1009  {
1010  const labelList& map = constructMap_[myRank];
1011 
1012  recvFields[myRank].setSize(map.size());
1013  forAll(map, i)
1014  {
1015  recvFields[myRank][i] = accessAndFlip
1016  (
1017  elemIsUsed,
1018  map[i],
1019  constructHasFlip_,
1020  noOp() // do not flip elemIsUsed value
1021  );
1022  }
1023  }
1024 
1025 
1026  // Wait for all to finish
1027 
1028  Pstream::waitRequests(startOfRequests);
1029 
1030 
1031  // Compact out all submap entries that are referring to unused elements
1032  for (const int domain : Pstream::allProcs(comm_))
1033  {
1034  const labelList& map = subMap_[domain];
1035 
1036  labelList newMap(map.size());
1037  label newI = 0;
1038 
1039  forAll(map, i)
1040  {
1041  if (recvFields[domain][i])
1042  {
1043  // So element is used on destination side
1044  newMap[newI++] = map[i];
1045  }
1046  }
1047  if (newI < map.size())
1048  {
1049  newMap.setSize(newI);
1050  subMap_[domain].transfer(newMap);
1051  }
1052  }
1053  }
1054 
1055 
1056  // 2. remove from construct map - since end-result (element in elemIsUsed)
1057  // not used.
1058 
1059  label maxConstructIndex = -1;
1060 
1061  for (const int domain : Pstream::allProcs(comm_))
1062  {
1063  const labelList& map = constructMap_[domain];
1064 
1065  labelList newMap(map.size());
1066  label newI = 0;
1067 
1068  forAll(map, i)
1069  {
1070  label destinationI = map[i];
1071  if (constructHasFlip_)
1072  {
1073  destinationI = mag(destinationI)-1;
1074  }
1075 
1076  // Is element is used on destination side
1077  if (elemIsUsed[destinationI])
1078  {
1079  maxConstructIndex = max(maxConstructIndex, destinationI);
1080 
1081  newMap[newI++] = map[i];
1082  }
1083  }
1084  if (newI < map.size())
1085  {
1086  newMap.setSize(newI);
1087  constructMap_[domain].transfer(newMap);
1088  }
1089  }
1090 
1091  constructSize_ = maxConstructIndex+1;
1092 
1093  // Clear the schedule (note:not necessary if nothing changed)
1094  schedulePtr_.clear();
1095 }
1096 
1097 
1100  const boolList& elemIsUsed,
1101  const label localSize, // max index for subMap
1102  labelList& oldToNewSub,
1103  labelList& oldToNewConstruct,
1104  const int tag
1105 )
1106 {
1107  const label myRank = Pstream::myProcNo(comm_);
1108  const label nProcs = Pstream::nProcs(comm_);
1109 
1110  // 1. send back to sender. Have sender delete the corresponding element
1111  // from the submap and do the same to the constructMap locally
1112  // (and in same order).
1113 
1114  // Send elemIsUsed field to neighbour. Use nonblocking code from
1115  // mapDistributeBase but in reverse order.
1116  if (Pstream::parRun())
1117  {
1118  label startOfRequests = Pstream::nRequests();
1119 
1120  // Set up receives from neighbours
1121 
1122  List<boolList> recvFields(nProcs);
1123 
1124  for (const int domain : Pstream::allProcs(comm_))
1125  {
1126  const labelList& map = subMap_[domain];
1127 
1128  if (domain != myRank && map.size())
1129  {
1130  recvFields[domain].setSize(map.size());
1132  (
1134  domain,
1135  reinterpret_cast<char*>(recvFields[domain].data()),
1136  recvFields[domain].size()*sizeof(bool),
1137  tag,
1138  comm_
1139  );
1140  }
1141  }
1142 
1143 
1144  List<boolList> sendFields(nProcs);
1145 
1146  for (const int domain : Pstream::allProcs(comm_))
1147  {
1148  const labelList& map = constructMap_[domain];
1149 
1150  if (domain != myRank && map.size())
1151  {
1152  boolList& subField = sendFields[domain];
1153  subField.setSize(map.size());
1154  forAll(map, i)
1155  {
1156  label index = map[i];
1157  if (constructHasFlip_)
1158  {
1159  index = mag(index)-1;
1160  }
1161  subField[i] = elemIsUsed[index];
1162  }
1163 
1165  (
1167  domain,
1168  reinterpret_cast<const char*>(subField.cdata()),
1169  subField.size()*sizeof(bool),
1170  tag,
1171  comm_
1172  );
1173  }
1174  }
1175 
1176 
1177 
1178  // Set up 'send' to myself - write directly into recvFields
1179 
1180  {
1181  const labelList& map = constructMap_[myRank];
1182 
1183  recvFields[myRank].setSize(map.size());
1184  forAll(map, i)
1185  {
1186  label index = map[i];
1187  if (constructHasFlip_)
1188  {
1189  index = mag(index)-1;
1190  }
1191  recvFields[myRank][i] = elemIsUsed[index];
1192  }
1193  }
1194 
1195 
1196  // Wait for all to finish
1197 
1198  Pstream::waitRequests(startOfRequests);
1199 
1200 
1201 
1202 
1203  // Work out which elements on the sending side are needed
1204  {
1205  oldToNewSub.setSize(localSize, -1);
1206 
1207  boolList sendElemIsUsed(localSize, false);
1208 
1209  for (const int domain : Pstream::allProcs(comm_))
1210  {
1211  const labelList& map = subMap_[domain];
1212  forAll(map, i)
1213  {
1214  if (recvFields[domain][i])
1215  {
1216  label index = map[i];
1217  if (subHasFlip_)
1218  {
1219  index = mag(index)-1;
1220  }
1221  sendElemIsUsed[index] = true;
1222  }
1223  }
1224  }
1225 
1226  label newI = 0;
1227  forAll(sendElemIsUsed, i)
1228  {
1229  if (sendElemIsUsed[i])
1230  {
1231  oldToNewSub[i] = newI++;
1232  }
1233  }
1234  }
1235 
1236 
1237  // Compact out all submap entries that are referring to unused elements
1238  for (const int domain : Pstream::allProcs(comm_))
1239  {
1240  const labelList& map = subMap_[domain];
1241 
1242  labelList newMap(map.size());
1243  label newI = 0;
1244 
1245  forAll(map, i)
1246  {
1247  if (recvFields[domain][i])
1248  {
1249  // So element is used on destination side
1250  label index = map[i];
1251  label sign = 1;
1252  if (subHasFlip_)
1253  {
1254  if (index < 0)
1255  {
1256  sign = -1;
1257  }
1258  index = mag(index)-1;
1259  }
1260  label newIndex = oldToNewSub[index];
1261  if (subHasFlip_)
1262  {
1263  newIndex = sign*(newIndex+1);
1264  }
1265  newMap[newI++] = newIndex;
1266  }
1267  }
1268  newMap.setSize(newI);
1269  subMap_[domain].transfer(newMap);
1270  }
1271  }
1272 
1273 
1274  // 2. remove from construct map - since end-result (element in elemIsUsed)
1275  // not used.
1276 
1277 
1278  oldToNewConstruct.setSize(elemIsUsed.size(), -1);
1279  constructSize_ = 0;
1280  forAll(elemIsUsed, i)
1281  {
1282  if (elemIsUsed[i])
1283  {
1284  oldToNewConstruct[i] = constructSize_++;
1285  }
1286  }
1287 
1288  for (const int domain : Pstream::allProcs(comm_))
1289  {
1290  const labelList& map = constructMap_[domain];
1291 
1292  labelList newMap(map.size());
1293  label newI = 0;
1294 
1295  forAll(map, i)
1296  {
1297  label destinationI = map[i];
1298  label sign = 1;
1299  if (constructHasFlip_)
1300  {
1301  if (destinationI < 0)
1302  {
1303  sign = -1;
1304  }
1305  destinationI = mag(destinationI)-1;
1306  }
1307 
1308  // Is element is used on destination side
1309  if (elemIsUsed[destinationI])
1310  {
1311  label newIndex = oldToNewConstruct[destinationI];
1312  if (constructHasFlip_)
1313  {
1314  newIndex = sign*(newIndex+1);
1315  }
1316  newMap[newI++] = newIndex;
1317  }
1318  }
1319  newMap.setSize(newI);
1320  constructMap_[domain].transfer(newMap);
1321  }
1322 }
1323 
1324 
1325 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1326 
1328 {
1329  if (this == &rhs)
1330  {
1331  return; // Self-assignment is a no-op
1332  }
1333 
1334  constructSize_ = rhs.constructSize_;
1335  subMap_ = rhs.subMap_;
1336  constructMap_ = rhs.constructMap_;
1337  subHasFlip_ = rhs.subHasFlip_;
1338  constructHasFlip_ = rhs.constructHasFlip_;
1339  comm_ = rhs.comm_;
1340  schedulePtr_.clear();
1341 }
1342 
1343 
1345 {
1346  if (this != &rhs)
1347  {
1348  // Avoid self assignment
1349  transfer(rhs);
1350  }
1351 }
1352 
1353 
1354 // * * * * * * * * * * * * * * Istream Operator * * * * * * * * * * * * * * //
1355 
1357 {
1359 
1360  is >> map.constructSize_ >> map.subMap_ >> map.constructMap_
1361  >> map.subHasFlip_ >> map.constructHasFlip_
1362  >> map.comm_;
1363 
1364  return is;
1365 }
1366 
1367 
1368 // * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * * //
1369 
1371 {
1372  os << map.constructSize_ << token::NL
1373  << map.subMap_ << token::NL
1374  << map.constructMap_ << token::NL
1375  << map.subHasFlip_ << token::SPACE << map.constructHasFlip_
1376  << token::SPACE << map.comm_ << token::NL;
1377 
1378  return os;
1379 }
1380 
1381 
1382 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::mapDistributeBase::subMap_
labelListList subMap_
Maps from subsetted data back to original data.
Definition: mapDistributeBase.H:113
Foam::UPstream::commsTypes::nonBlocking
mapDistributeBase.H
Foam::labelMax
constexpr label labelMax
Definition: label.H:61
Foam::mapDistributeBase::renumber
static label renumber(const globalIndex &, const List< Map< label >> &compactMap, const label globalElement)
Helper for construct from globalIndex. Renumbers element.
Definition: mapDistributeBase.C:906
Foam::mapDistributeBase::operator=
void operator=(const mapDistributeBase &rhs)
Copy assignment.
Definition: mapDistributeBase.C:1327
Foam::HashTable::toc
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition: HashTable.C:121
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::OPstream
Output inter-processor communications stream.
Definition: OPstream.H:52
globalIndex.H
Foam::UPstream::parRun
static bool & parRun()
Test if this a parallel run, or allow modify access.
Definition: UPstream.H:434
Foam::Pstream::exchangeSizes
static void exchangeSizes(const Container &sendData, labelList &sizes, const label comm=UPstream::worldComm)
Helper: exchange sizes of sendData. sendData is the data per.
Definition: exchange.C:349
Foam::IOstream::fatalCheck
bool fatalCheck(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:57
Foam::Map< label >
Foam::UPstream::waitRequests
static void waitRequests(const label start=0)
Wait until all requests (from start onwards) have finished.
Definition: UPstream.C:234
Foam::globalIndex::localSize
label localSize() const
My local size.
Definition: globalIndexI.H:124
Foam::globalIndex::isLocal
bool isLocal(const label i) const
Is on local processor.
Definition: globalIndexI.H:148
Foam::operator>>
Istream & operator>>(Istream &, directionInfo &)
Definition: directionInfo.C:230
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::commSchedule
Determines the order in which a set of processors should communicate with one another.
Definition: commSchedule.H:67
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Foam::mapDistributeBase::transfer
void transfer(mapDistributeBase &rhs)
Transfer the contents of the argument and annul the argument.
Definition: mapDistributeBase.C:883
Foam::sign
dimensionedScalar sign(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:166
Foam::HashSet
A HashTable with keys but without contents that is similar to std::unordered_set.
Definition: HashSet.H:83
Foam::mapDistributeBase::schedulePtr_
autoPtr< List< labelPair > > schedulePtr_
Schedule.
Definition: mapDistributeBase.H:128
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::UIPstream::read
static label read(const commsTypes commsType, const int fromProcNo, char *buf, const std::streamsize bufSize, const int tag=UPstream::msgType(), const label communicator=0)
Read into given buffer from given processor and return the.
Definition: UIPread.C:81
Foam::labelPair
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
commSchedule.H
Foam::operator<<
Ostream & operator<<(Ostream &, const boundaryPatch &p)
Write boundaryPatch as dictionary entries (without surrounding braces)
Definition: boundaryPatch.C:83
Foam::UOPstream::write
static bool write(const commsTypes commsType, const int toProcNo, const char *buf, const std::streamsize bufSize, const int tag=UPstream::msgType(), const label communicator=0)
Write given buffer to given processor.
Definition: UOPwrite.C:36
Foam::mapDistributeBase::mapDistributeBase
mapDistributeBase(const label comm=UPstream::worldComm)
Construct null.
Definition: mapDistributeBase.C:566
labelPairHashes.H
A HashTable to objects of type <T> with a labelPair key. The hashing is based on labelPair (FixedList...
Foam::mapDistributeBase::comm_
label comm_
Communicator to use for parallel operations.
Definition: mapDistributeBase.H:125
Foam::mapDistributeBase::schedule
const List< labelPair > & schedule() const
Return a schedule. Demand driven. See above.
Definition: mapDistributeBase.C:187
Foam::Istream
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:61
Foam::mapDistributeBase::calcCompactAddressing
void calcCompactAddressing(const globalIndex &globalNumbering, const labelUList &elements, List< Map< label >> &compactMap) const
Construct per processor compact addressing of the global elements.
Definition: mapDistributeBase.C:299
Foam::List::transfer
void transfer(List< T > &list)
Definition: List.C:459
Foam::mapDistributeBase::constructSize_
label constructSize_
Size of reconstructed data.
Definition: mapDistributeBase.H:110
Foam::mapDistributeBase::checkReceivedSize
static void checkReceivedSize(const label proci, const label expectedSize, const label receivedSize)
Definition: mapDistributeBase.C:204
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
forAllIters
#define forAllIters(container, iter)
Iterate across all elements in the container object.
Definition: stdFoam.H:223
Foam::token::NL
Newline [isspace].
Definition: token.H:119
Foam::FatalError
error FatalError
Foam::mapDistributeBase::subHasFlip_
bool subHasFlip_
Whether subMap includes flip or not.
Definition: mapDistributeBase.H:119
Foam::mapDistributeBase::constructHasFlip_
bool constructHasFlip_
Whether constructMap includes flip or not.
Definition: mapDistributeBase.H:122
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::mapDistributeBase::compact
void compact(const boolList &elemIsUsed, const int tag=UPstream::msgType())
Compact maps. Gets per field a bool whether it is used (locally)
Definition: mapDistributeBase.C:930
Foam::globalIndex
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:68
Foam::mapDistributeBase::printLayout
void printLayout(Ostream &os) const
Debug: print layout. Can only be used on maps with sorted.
Definition: mapDistributeBase.C:221
Foam::mapDistributeBase::exchangeAddressing
void exchangeAddressing(const int tag, const globalIndex &globalNumbering, labelList &elements, List< Map< label >> &compactMap, labelList &compactStart)
Definition: mapDistributeBase.C:401
Foam::globalIndex::toLocal
label toLocal(const label i) const
From global to local on current processor.
Definition: globalIndexI.H:229
Foam::renumber
IntListType renumber(const labelUList &oldToNew, const IntListType &input)
Renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:37
Foam::UPstream::msgType
static int & msgType()
Message tag of standard messages.
Definition: UPstream.H:541
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:381
Foam::UPstream::allProcs
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition: UPstream.H:509
Foam::mapDistributeBase::constructMap_
labelListList constructMap_
Maps from subsetted data to new reconstructed data.
Definition: mapDistributeBase.H:116
Foam::UPstream::nRequests
static label nRequests()
Get number of outstanding requests.
Definition: UPstream.C:224
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:464
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::token::SPACE
Space [isspace].
Definition: token.H:117
Foam::globalIndex::whichProcID
label whichProcID(const label i) const
Which processor does global come from? Binary search.
Definition: globalIndexI.H:235
Foam::UList< label >
Foam::identity
labelList identity(const label len, label start=0)
Create identity map of the given length with (map[i] == i)
Definition: labelList.C:38
Foam::HashSet::insert
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:181
bool
bool
Definition: EEqn.H:20
FUNCTION_NAME
#define FUNCTION_NAME
Definition: messageStream.H:270
Foam::labelMin
constexpr label labelMin
Definition: label.H:60
Foam::mapDistributeBase
Class containing processor-to-processor mapping information.
Definition: mapDistributeBase.H:103
Foam::UList::size
void size(const label n) noexcept
Override size to be inconsistent with allocated storage.
Definition: UListI.H:360
Foam::UIndirectList
A List with indirect addressing.
Definition: faMatrix.H:60
Foam::IPstream
Input inter-processor communications stream.
Definition: IPstream.H:52
ListOps.H
Various functions to operate on Lists.
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::data
Database for solution data, solver performance and other reduced data.
Definition: data.H:55
Foam::UPstream::nProcs
static label nProcs(const label communicator=worldComm)
Number of processes in parallel run, and 1 for serial run.
Definition: UPstream.H:446
Foam::noOp
Pass through value. Should never be specialized.
Definition: flipOp.H:64