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