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-2016 OpenFOAM Foundation
6  \\/ M anipulation |
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  {
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  (
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  (
176  schedule(subMap_, constructMap_, Pstream::msgType())
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 
277 (
278  const globalIndex& globalNumbering,
279  const labelList& elements,
280  List<Map<label>>& compactMap
281 ) const
282 {
283  compactMap.setSize(Pstream::nProcs());
284 
285  // Count all (non-local) elements needed. Just for presizing map.
286  labelList nNonLocal(Pstream::nProcs(), 0);
287 
288  forAll(elements, i)
289  {
290  label globalIndex = elements[i];
291 
292  if (globalIndex != -1 && !globalNumbering.isLocal(globalIndex))
293  {
294  label proci = globalNumbering.whichProcID(globalIndex);
295  nNonLocal[proci]++;
296  }
297  }
298 
299  forAll(compactMap, proci)
300  {
301  compactMap[proci].clear();
302  if (proci != Pstream::myProcNo())
303  {
304  compactMap[proci].resize(2*nNonLocal[proci]);
305  }
306  }
307 
308 
309  // Collect all (non-local) elements needed.
310  forAll(elements, i)
311  {
312  label globalIndex = elements[i];
313 
314  if (globalIndex != -1 && !globalNumbering.isLocal(globalIndex))
315  {
316  label proci = globalNumbering.whichProcID(globalIndex);
317  label index = globalNumbering.toLocal(proci, globalIndex);
318  label nCompact = compactMap[proci].size();
319  compactMap[proci].insert(index, nCompact);
320  }
321  }
322 }
323 
324 
326 (
327  const globalIndex& globalNumbering,
328  const labelListList& cellCells,
329  List<Map<label>>& compactMap
330 ) const
331 {
332  compactMap.setSize(Pstream::nProcs());
333 
334  // Count all (non-local) elements needed. Just for presizing map.
335  labelList nNonLocal(Pstream::nProcs(), 0);
336 
337  forAll(cellCells, cellI)
338  {
339  const labelList& cCells = cellCells[cellI];
340 
341  forAll(cCells, i)
342  {
343  label globalIndex = cCells[i];
344 
345  if (globalIndex != -1 && !globalNumbering.isLocal(globalIndex))
346  {
347  label proci = globalNumbering.whichProcID(globalIndex);
348  nNonLocal[proci]++;
349  }
350  }
351  }
352 
353  forAll(compactMap, proci)
354  {
355  compactMap[proci].clear();
356  if (proci != Pstream::myProcNo())
357  {
358  compactMap[proci].resize(2*nNonLocal[proci]);
359  }
360  }
361 
362 
363  // Collect all (non-local) elements needed.
364  forAll(cellCells, cellI)
365  {
366  const labelList& cCells = cellCells[cellI];
367 
368  forAll(cCells, i)
369  {
370  label globalIndex = cCells[i];
371 
372  if (globalIndex != -1 && !globalNumbering.isLocal(globalIndex))
373  {
374  label proci = globalNumbering.whichProcID(globalIndex);
375  label index = globalNumbering.toLocal(proci, globalIndex);
376  label nCompact = compactMap[proci].size();
377  compactMap[proci].insert(index, nCompact);
378  }
379  }
380  }
381 }
382 
383 
385 (
386  const int tag,
387  const globalIndex& globalNumbering,
388  labelList& elements,
389  List<Map<label>>& compactMap,
390  labelList& compactStart
391 )
392 {
393  // The overall compact addressing is
394  // - myProcNo data first (uncompacted)
395  // - all other processors consecutively
396 
397  compactStart.setSize(Pstream::nProcs());
398  compactStart[Pstream::myProcNo()] = 0;
399  constructSize_ = globalNumbering.localSize();
400  forAll(compactStart, proci)
401  {
402  if (proci != Pstream::myProcNo())
403  {
404  compactStart[proci] = constructSize_;
405  constructSize_ += compactMap[proci].size();
406  }
407  }
408 
409 
410 
411  // Find out what to receive/send in compact addressing.
412 
413  // What I want to receive is what others have to send
414  labelListList wantedRemoteElements(Pstream::nProcs());
415  // Compact addressing for received data
416  constructMap_.setSize(Pstream::nProcs());
417  forAll(compactMap, proci)
418  {
419  if (proci == Pstream::myProcNo())
420  {
421  // All my own elements are used
422  label nLocal = globalNumbering.localSize();
423  wantedRemoteElements[proci] = identity(nLocal);
424  constructMap_[proci] = identity(nLocal);
425  }
426  else
427  {
428  // Remote elements wanted from processor proci
429  labelList& remoteElem = wantedRemoteElements[proci];
430  labelList& localElem = constructMap_[proci];
431  remoteElem.setSize(compactMap[proci].size());
432  localElem.setSize(compactMap[proci].size());
433  label i = 0;
434  forAllIter(Map<label>, compactMap[proci], iter)
435  {
436  const label compactI = compactStart[proci] + iter();
437  remoteElem[i] = iter.key();
438  localElem[i] = compactI;
439  iter() = compactI;
440  i++;
441  }
442  }
443  }
444 
445  subMap_.setSize(Pstream::nProcs());
446  Pstream::exchange<labelList, label>
447  (
448  wantedRemoteElements,
449  subMap_,
450  tag,
451  Pstream::worldComm //TBD
452  );
453 
454  // Renumber elements
455  forAll(elements, i)
456  {
457  elements[i] = renumber(globalNumbering, compactMap, elements[i]);
458  }
459 }
460 
461 
463 (
464  const int tag,
465  const globalIndex& globalNumbering,
466  labelListList& cellCells,
467  List<Map<label>>& compactMap,
468  labelList& compactStart
469 )
470 {
471  // The overall compact addressing is
472  // - myProcNo data first (uncompacted)
473  // - all other processors consecutively
474 
475  compactStart.setSize(Pstream::nProcs());
476  compactStart[Pstream::myProcNo()] = 0;
477  constructSize_ = globalNumbering.localSize();
478  forAll(compactStart, proci)
479  {
480  if (proci != Pstream::myProcNo())
481  {
482  compactStart[proci] = constructSize_;
483  constructSize_ += compactMap[proci].size();
484  }
485  }
486 
487 
488 
489  // Find out what to receive/send in compact addressing.
490 
491  // What I want to receive is what others have to send
492  labelListList wantedRemoteElements(Pstream::nProcs());
493  // Compact addressing for received data
494  constructMap_.setSize(Pstream::nProcs());
495  forAll(compactMap, proci)
496  {
497  if (proci == Pstream::myProcNo())
498  {
499  // All my own elements are used
500  label nLocal = globalNumbering.localSize();
501  wantedRemoteElements[proci] = identity(nLocal);
502  constructMap_[proci] = identity(nLocal);
503  }
504  else
505  {
506  // Remote elements wanted from processor proci
507  labelList& remoteElem = wantedRemoteElements[proci];
508  labelList& localElem = constructMap_[proci];
509  remoteElem.setSize(compactMap[proci].size());
510  localElem.setSize(compactMap[proci].size());
511  label i = 0;
512  forAllIter(Map<label>, compactMap[proci], iter)
513  {
514  const label compactI = compactStart[proci] + iter();
515  remoteElem[i] = iter.key();
516  localElem[i] = compactI;
517  iter() = compactI;
518  i++;
519  }
520  }
521  }
522 
523  subMap_.setSize(Pstream::nProcs());
524  Pstream::exchange<labelList, label>
525  (
526  wantedRemoteElements,
527  subMap_,
528  tag,
529  Pstream::worldComm //TBD
530  );
531 
532  // Renumber elements
533  forAll(cellCells, cellI)
534  {
535  labelList& cCells = cellCells[cellI];
536 
537  forAll(cCells, i)
538  {
539  cCells[i] = renumber(globalNumbering, compactMap, cCells[i]);
540  }
541  }
542 }
543 
544 
545 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
546 
548 :
549  constructSize_(0),
550  subHasFlip_(false),
551  constructHasFlip_(false),
552  schedulePtr_()
553 {}
554 
555 
557 (
558  const label constructSize,
559  const Xfer<labelListList>& subMap,
560  const Xfer<labelListList>& constructMap,
561  const bool subHasFlip,
562  const bool constructHasFlip
563 )
564 :
565  constructSize_(constructSize),
566  subMap_(subMap),
567  constructMap_(constructMap),
568  subHasFlip_(subHasFlip),
569  constructHasFlip_(constructHasFlip),
570  schedulePtr_()
571 {}
572 
573 
575 (
576  const labelList& sendProcs,
577  const labelList& recvProcs
578 )
579 :
580  constructSize_(0),
581  subHasFlip_(false),
582  constructHasFlip_(false),
583  schedulePtr_()
584 {
585  if (sendProcs.size() != recvProcs.size())
586  {
588  << "The send and receive data is not the same length. sendProcs:"
589  << sendProcs.size() << " recvProcs:" << recvProcs.size()
590  << abort(FatalError);
591  }
592 
593  // Per processor the number of samples we have to send/receive.
594  labelList nSend(Pstream::nProcs(), 0);
595  labelList nRecv(Pstream::nProcs(), 0);
596 
597  forAll(sendProcs, sampleI)
598  {
599  label sendProc = sendProcs[sampleI];
600  label recvProc = recvProcs[sampleI];
601 
602  // Note that also need to include local communication (both
603  // RecvProc and sendProc on local processor)
604 
605  if (Pstream::myProcNo() == sendProc)
606  {
607  // I am the sender. Count destination processor.
608  nSend[recvProc]++;
609  }
610  if (Pstream::myProcNo() == recvProc)
611  {
612  // I am the receiver.
613  nRecv[sendProc]++;
614  }
615  }
616 
619  forAll(nSend, proci)
620  {
621  subMap_[proci].setSize(nSend[proci]);
622  constructMap_[proci].setSize(nRecv[proci]);
623  }
624  nSend = 0;
625  nRecv = 0;
626 
627  forAll(sendProcs, sampleI)
628  {
629  label sendProc = sendProcs[sampleI];
630  label recvProc = recvProcs[sampleI];
631 
632  if (Pstream::myProcNo() == sendProc)
633  {
634  // I am the sender. Store index I need to send.
635  subMap_[recvProc][nSend[recvProc]++] = sampleI;
636  }
637  if (Pstream::myProcNo() == recvProc)
638  {
639  // I am the receiver.
640  constructMap_[sendProc][nRecv[sendProc]++] = sampleI;
641  // Largest entry inside constructMap
642  constructSize_ = sampleI+1;
643  }
644  }
645 }
646 
647 
649 (
650  const globalIndex& globalNumbering,
651  labelList& elements,
652  List<Map<label>>& compactMap,
653  const int tag
654 )
655 :
656  constructSize_(0),
657  subHasFlip_(false),
658  constructHasFlip_(false),
659  schedulePtr_()
660 {
661  // Construct per processor compact addressing of the global elements
662  // needed. The ones from the local processor are not included since
663  // these are always all needed.
665  (
666  globalNumbering,
667  elements,
668  compactMap
669  );
670 
672  //forAll(compactMap, proci)
673  //{
674  // if (proci != Pstream::myProcNo())
675  // {
676  // Map<label>& globalMap = compactMap[proci];
677  //
678  // SortableList<label> sorted(globalMap.toc().xfer());
679  //
680  // forAll(sorted, i)
681  // {
682  // Map<label>::iterator iter = globalMap.find(sorted[i]);
683  // iter() = i;
684  // }
685  // }
686  //}
687 
688 
689  // Exchange what I need with processor that supplies it. Renumber elements
690  // into compact numbering
691  labelList compactStart;
693  (
694  tag,
695  globalNumbering,
696  elements,
697  compactMap,
698  compactStart
699  );
700 
701  if (debug)
702  {
703  printLayout(Pout);
704  }
705 }
706 
707 
709 (
710  const globalIndex& globalNumbering,
711  labelListList& cellCells,
712  List<Map<label>>& compactMap,
713  const int tag
714 )
715 :
716  constructSize_(0),
717  subHasFlip_(false),
718  constructHasFlip_(false),
719  schedulePtr_()
720 {
721  // Construct per processor compact addressing of the global elements
722  // needed. The ones from the local processor are not included since
723  // these are always all needed.
725  (
726  globalNumbering,
727  cellCells,
728  compactMap
729  );
730 
732  //forAll(compactMap, proci)
733  //{
734  // if (proci != Pstream::myProcNo())
735  // {
736  // Map<label>& globalMap = compactMap[proci];
737  //
738  // SortableList<label> sorted(globalMap.toc().xfer());
739  //
740  // forAll(sorted, i)
741  // {
742  // Map<label>::iterator iter = globalMap.find(sorted[i]);
743  // iter() = i;
744  // }
745  // }
746  //}
747 
748 
749  // Exchange what I need with processor that supplies it. Renumber elements
750  // into compact numbering
751  labelList compactStart;
753  (
754  tag,
755  globalNumbering,
756  cellCells,
757  compactMap,
758  compactStart
759  );
760 
761  if (debug)
762  {
763  printLayout(Pout);
764  }
765 }
766 
767 
769 :
771  subMap_(map.subMap_),
775  schedulePtr_()
776 {}
777 
778 
780 :
782  subMap_(map().subMap_.xfer()),
784  subHasFlip_(map().subHasFlip_),
786  schedulePtr_()
787 {}
788 
789 
791 {
792  is >> *this;
793 }
794 
795 
796 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
797 
799 {
801  subMap_.transfer(rhs.subMap_);
803  subHasFlip_ = rhs.subHasFlip_;
805  schedulePtr_.clear();
806 }
807 
808 
810 {
811  return xferMove(*this);
812 }
813 
814 
816 (
817  const globalIndex& globalNumbering,
818  const List<Map<label>>& compactMap,
819  const label globalI
820 )
821 {
822  if (globalI == -1)
823  {
824  return globalI;
825  }
826  if (globalNumbering.isLocal(globalI))
827  {
828  return globalNumbering.toLocal(globalI);
829  }
830  else
831  {
832  label proci = globalNumbering.whichProcID(globalI);
833  label index = globalNumbering.toLocal(proci, globalI);
834  return compactMap[proci][index];
835  }
836 }
837 
838 
839 void Foam::mapDistributeBase::compact(const boolList& elemIsUsed, const int tag)
840 {
841  // 1. send back to sender. Have sender delete the corresponding element
842  // from the submap and do the same to the constructMap locally
843  // (and in same order).
844 
845  // Send elemIsUsed field to neighbour. Use nonblocking code from
846  // mapDistributeBase but in reverse order.
847  if (Pstream::parRun())
848  {
849  label startOfRequests = Pstream::nRequests();
850 
851  // Set up receives from neighbours
852 
853  List<boolList> recvFields(Pstream::nProcs());
854 
855  for (label domain = 0; domain < Pstream::nProcs(); domain++)
856  {
857  const labelList& map = subMap_[domain];
858 
859  if (domain != Pstream::myProcNo() && map.size())
860  {
861  recvFields[domain].setSize(map.size());
863  (
865  domain,
866  reinterpret_cast<char*>(recvFields[domain].begin()),
867  recvFields[domain].size()*sizeof(bool),
868  tag
869  );
870  }
871  }
872 
873 
874  List<boolList> sendFields(Pstream::nProcs());
875 
876  for (label domain = 0; domain < Pstream::nProcs(); domain++)
877  {
878  const labelList& map = constructMap_[domain];
879 
880  if (domain != Pstream::myProcNo() && map.size())
881  {
882  boolList& subField = sendFields[domain];
883  subField.setSize(map.size());
884  forAll(map, i)
885  {
886  subField[i] = accessAndFlip
887  (
888  elemIsUsed,
889  map[i],
891  noOp() // do not flip elemIsUsed value
892  );
893  }
894 
896  (
898  domain,
899  reinterpret_cast<const char*>(subField.begin()),
900  subField.size()*sizeof(bool),
901  tag
902  );
903  }
904  }
905 
906 
907 
908  // Set up 'send' to myself - write directly into recvFields
909 
910  {
911  const labelList& map = constructMap_[Pstream::myProcNo()];
912 
913  recvFields[Pstream::myProcNo()].setSize(map.size());
914  forAll(map, i)
915  {
916  recvFields[Pstream::myProcNo()][i] = accessAndFlip
917  (
918  elemIsUsed,
919  map[i],
921  noOp() // do not flip elemIsUsed value
922  );
923  }
924  }
925 
926 
927  // Wait for all to finish
928 
929  Pstream::waitRequests(startOfRequests);
930 
931 
932  // Compact out all submap entries that are referring to unused elements
933  for (label domain = 0; domain < Pstream::nProcs(); domain++)
934  {
935  const labelList& map = subMap_[domain];
936 
937  labelList newMap(map.size());
938  label newI = 0;
939 
940  forAll(map, i)
941  {
942  if (recvFields[domain][i])
943  {
944  // So element is used on destination side
945  newMap[newI++] = map[i];
946  }
947  }
948  if (newI < map.size())
949  {
950  newMap.setSize(newI);
951  subMap_[domain].transfer(newMap);
952  }
953  }
954  }
955 
956 
957  // 2. remove from construct map - since end-result (element in elemIsUsed)
958  // not used.
959 
960  label maxConstructIndex = -1;
961 
962  for (label domain = 0; domain < Pstream::nProcs(); domain++)
963  {
964  const labelList& map = constructMap_[domain];
965 
966  labelList newMap(map.size());
967  label newI = 0;
968 
969  forAll(map, i)
970  {
971  label destinationI = map[i];
972  if (constructHasFlip_)
973  {
974  destinationI = mag(destinationI)-1;
975  }
976 
977  // Is element is used on destination side
978  if (elemIsUsed[destinationI])
979  {
980  maxConstructIndex = max(maxConstructIndex, destinationI);
981 
982  newMap[newI++] = map[i];
983  }
984  }
985  if (newI < map.size())
986  {
987  newMap.setSize(newI);
988  constructMap_[domain].transfer(newMap);
989  }
990  }
991 
992  constructSize_ = maxConstructIndex+1;
993 
994  // Clear the schedule (note:not necessary if nothing changed)
995  schedulePtr_.clear();
996 }
997 
998 
1001  const boolList& elemIsUsed,
1002  const label localSize, // max index for subMap
1003  labelList& oldToNewSub,
1004  labelList& oldToNewConstruct,
1005  const int tag
1006 )
1007 {
1008  // 1. send back to sender. Have sender delete the corresponding element
1009  // from the submap and do the same to the constructMap locally
1010  // (and in same order).
1011 
1012  // Send elemIsUsed field to neighbour. Use nonblocking code from
1013  // mapDistributeBase but in reverse order.
1014  if (Pstream::parRun())
1015  {
1016  label startOfRequests = Pstream::nRequests();
1017 
1018  // Set up receives from neighbours
1019 
1020  List<boolList> recvFields(Pstream::nProcs());
1021 
1022  for (label domain = 0; domain < Pstream::nProcs(); domain++)
1023  {
1024  const labelList& map = subMap_[domain];
1025 
1026  if (domain != Pstream::myProcNo() && map.size())
1027  {
1028  recvFields[domain].setSize(map.size());
1030  (
1032  domain,
1033  reinterpret_cast<char*>(recvFields[domain].begin()),
1034  recvFields[domain].size()*sizeof(bool),
1035  tag
1036  );
1037  }
1038  }
1039 
1040 
1041  List<boolList> sendFields(Pstream::nProcs());
1042 
1043  for (label domain = 0; domain < Pstream::nProcs(); domain++)
1044  {
1045  const labelList& map = constructMap_[domain];
1046 
1047  if (domain != Pstream::myProcNo() && map.size())
1048  {
1049  boolList& subField = sendFields[domain];
1050  subField.setSize(map.size());
1051  forAll(map, i)
1052  {
1053  label index = map[i];
1054  if (constructHasFlip_)
1055  {
1056  index = mag(index)-1;
1057  }
1058  subField[i] = elemIsUsed[index];
1059  }
1060 
1062  (
1064  domain,
1065  reinterpret_cast<const char*>(subField.begin()),
1066  subField.size()*sizeof(bool),
1067  tag
1068  );
1069  }
1070  }
1071 
1072 
1073 
1074  // Set up 'send' to myself - write directly into recvFields
1075 
1076  {
1077  const labelList& map = constructMap_[Pstream::myProcNo()];
1078 
1079  recvFields[Pstream::myProcNo()].setSize(map.size());
1080  forAll(map, i)
1081  {
1082  label index = map[i];
1083  if (constructHasFlip_)
1084  {
1085  index = mag(index)-1;
1086  }
1087  recvFields[Pstream::myProcNo()][i] = elemIsUsed[index];
1088  }
1089  }
1090 
1091 
1092  // Wait for all to finish
1093 
1094  Pstream::waitRequests(startOfRequests);
1095 
1096 
1097 
1098 
1099  // Work out which elements on the sending side are needed
1100  {
1101  oldToNewSub.setSize(localSize, -1);
1102 
1103  boolList sendElemIsUsed(localSize, false);
1104 
1105  for (label domain = 0; domain < Pstream::nProcs(); domain++)
1106  {
1107  const labelList& map = subMap_[domain];
1108  forAll(map, i)
1109  {
1110  if (recvFields[domain][i])
1111  {
1112  label index = map[i];
1113  if (subHasFlip_)
1114  {
1115  index = mag(index)-1;
1116  }
1117  sendElemIsUsed[index] = true;
1118  }
1119  }
1120  }
1121 
1122  label newI = 0;
1123  forAll(sendElemIsUsed, i)
1124  {
1125  if (sendElemIsUsed[i])
1126  {
1127  oldToNewSub[i] = newI++;
1128  }
1129  }
1130  }
1131 
1132 
1133  // Compact out all submap entries that are referring to unused elements
1134  for (label domain = 0; domain < Pstream::nProcs(); domain++)
1135  {
1136  const labelList& map = subMap_[domain];
1137 
1138  labelList newMap(map.size());
1139  label newI = 0;
1140 
1141  forAll(map, i)
1142  {
1143  if (recvFields[domain][i])
1144  {
1145  // So element is used on destination side
1146  label index = map[i];
1147  label sign = 1;
1148  if (subHasFlip_)
1149  {
1150  if (index < 0)
1151  {
1152  sign = -1;
1153  }
1154  index = mag(index)-1;
1155  }
1156  label newIndex = oldToNewSub[index];
1157  if (subHasFlip_)
1158  {
1159  newIndex = sign*(newIndex+1);
1160  }
1161  newMap[newI++] = newIndex;
1162  }
1163  }
1164  newMap.setSize(newI);
1165  subMap_[domain].transfer(newMap);
1166  }
1167  }
1168 
1169 
1170  // 2. remove from construct map - since end-result (element in elemIsUsed)
1171  // not used.
1172 
1173 
1174  oldToNewConstruct.setSize(elemIsUsed.size(), -1);
1175  constructSize_ = 0;
1176  forAll(elemIsUsed, i)
1177  {
1178  if (elemIsUsed[i])
1179  {
1180  oldToNewConstruct[i] = constructSize_++;
1181  }
1182  }
1183 
1184  for (label domain = 0; domain < Pstream::nProcs(); domain++)
1185  {
1186  const labelList& map = constructMap_[domain];
1187 
1188  labelList newMap(map.size());
1189  label newI = 0;
1190 
1191  forAll(map, i)
1192  {
1193  label destinationI = map[i];
1194  label sign = 1;
1195  if (constructHasFlip_)
1196  {
1197  if (destinationI < 0)
1198  {
1199  sign = -1;
1200  }
1201  destinationI = mag(destinationI)-1;
1202  }
1203 
1204  // Is element is used on destination side
1205  if (elemIsUsed[destinationI])
1206  {
1207  label newIndex = oldToNewConstruct[destinationI];
1208  if (constructHasFlip_)
1209  {
1210  newIndex = sign*(newIndex+1);
1211  }
1212  newMap[newI++] = newIndex;
1213  }
1214  }
1215  newMap.setSize(newI);
1216  constructMap_[domain].transfer(newMap);
1217  }
1218 }
1219 
1220 
1221 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1222 
1224 {
1225  // Check for assignment to self
1226  if (this == &rhs)
1227  {
1229  << "Attempted assignment to self"
1230  << abort(FatalError);
1231  }
1233  subMap_ = rhs.subMap_;
1235  subHasFlip_ = rhs.subHasFlip_;
1237  schedulePtr_.clear();
1238 }
1239 
1240 
1241 // * * * * * * * * * * * * * * Istream Operator * * * * * * * * * * * * * * //
1242 
1244 {
1245  is.fatalCheck("operator>>(Istream&, mapDistributeBase&)");
1246 
1247  is >> map.constructSize_ >> map.subMap_ >> map.constructMap_
1248  >> map.subHasFlip_ >> map.constructHasFlip_;
1249 
1250  return is;
1251 }
1252 
1253 
1254 // * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * * //
1255 
1257 {
1258  os << map.constructSize_ << token::NL
1259  << map.subMap_ << token::NL
1260  << map.constructMap_ << token::NL
1261  << map.subHasFlip_ << token::SPACE << map.constructHasFlip_
1262  << token::NL;
1263 
1264  return os;
1265 }
1266 
1267 
1268 // ************************************************************************* //
ListType renumber(const labelUList &oldToNew, const ListType &)
Renumber the values (not the indices) of a list.
dimensionedScalar sign(const dimensionedScalar &ds)
A simple container for copying or transferring objects of type <T>.
Definition: Xfer.H:85
A HashTable with keys but without contents.
Definition: HashSet.H:59
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
void compact(const boolList &elemIsUsed, const int tag=UPstream::msgType())
Compact maps. Gets per field a bool whether it is used (locally)
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
static int masterNo()
Process index of the master.
Definition: UPstream.H:405
static label renumber(const globalIndex &, const List< Map< label >> &compactMap, const label globalElement)
Helper for construct from globalIndex. Renumbers element.
void printLayout(Ostream &os) const
Debug: print layout. Can only be used on maps with sorted.
error FatalError
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
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
static int firstSlave()
Process index of first slave.
Definition: UPstream.H:434
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:453
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
labelListList subMap_
Maps from subsetted data back to original data.
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:417
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:411
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
static label nRequests()
Get number of outstanding requests.
Definition: UPstream.C:107
static int & msgType()
Message tag of standard messages.
Definition: UPstream.H:464
static label worldComm
Default communicator (all processors)
Definition: UPstream.H:274
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:116
Xfer< mapDistributeBase > xfer()
Transfer contents to the Xfer container.
mapDistributeBase()
Construct null.
label constructSize_
Size of reconstructed data.
Various functions to operate on Lists.
Input inter-processor communications stream.
Definition: IPstream.H:50
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:63
Xfer< T > xferMove(T &)
Construct by transferring the contents of the arg.
autoPtr< List< labelPair > > schedulePtr_
Schedule.
Istream & operator>>(Istream &, directionInfo &)
static T accessAndFlip(const UList< T > &fld, const label index, const bool hasFlip, const negateOp &negOp)
iterator begin()
Return an iterator to begin traversing the UList.
Definition: UListI.H:216
label whichProcID(const label i) const
Which processor does global come from? Binary search.
Definition: globalIndexI.H:123
Pair< label > labelPair
Label pair.
Definition: labelPair.H:48
static const label labelMax
Definition: label.H:62
errorManip< error > abort(error &err)
Definition: errorManip.H:131
labelListList constructMap_
Maps from subsetted data to new reconstructed data.
List< Key > toc() const
Return the table of contents.
void operator=(const mapDistributeBase &)
Class containing processor-to-processor mapping information.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:53
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53
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
Determines the order in which a set of processors should communicate with one another.
Definition: commSchedule.H:65
defineTypeNameAndDebug(combustionModel, 0)
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
const List< labelPair > & schedule() const
Return a schedule. Demand driven. See above.
Output inter-processor communications stream.
Definition: OPstream.H:50
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurence of given element and return index,.
static void waitRequests(const label start=0)
Wait until all requests (from start onwards) have finished.
Definition: UPstream.C:117
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
bool subHasFlip_
Whether subMap includes flip or not.
void calcCompactAddressing(const globalIndex &globalNumbering, const labelList &elements, List< Map< label >> &compactMap) const
Construct per processor compact addressing of the global elements.
void setSize(const label)
Reset size of List.
Definition: List.C:295
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:393
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:399
void exchangeAddressing(const int tag, const globalIndex &globalNumbering, labelList &elements, List< Map< label >> &compactMap, labelList &compactStart)
bool constructHasFlip_
Whether constructMap includes flip or not.
label localSize() const
My local size.
Definition: globalIndexI.H:60
A List with indirect addressing.
Definition: fvMatrix.H:106
Ostream & operator<<(Ostream &, const ensightPart &)
static void checkReceivedSize(const label proci, const label expectedSize, const label receivedSize)
dimensioned< scalar > mag(const dimensioned< Type > &)
bool isLocal(const label i) const
Is on local processor.
Definition: globalIndexI.H:95
void transfer(mapDistributeBase &)
Transfer the contents of the argument and annul the argument.
label toLocal(const label i) const
From global to local on current processor.
Definition: globalIndexI.H:117
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:365
static const label labelMin
Definition: label.H:61
void fatalCheck(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:105
Namespace for OpenFOAM.
static int lastSlave(const label communicator=0)
Process index of last slave.
Definition: UPstream.H:440