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