mapDistributeBaseTemplates.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2015-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "Pstream.H"
30 #include "PstreamBuffers.H"
32 #include "flipOp.H"
33 
34 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35 
36 template<class T, class CombineOp, class negateOp>
38 (
39  const labelUList& map,
40  const bool hasFlip,
41  const UList<T>& rhs,
42  const CombineOp& cop,
43  const negateOp& negOp,
44  List<T>& lhs
45 )
46 {
47  if (hasFlip)
48  {
49  forAll(map, i)
50  {
51  if (map[i] > 0)
52  {
53  label index = map[i]-1;
54  cop(lhs[index], rhs[i]);
55  }
56  else if (map[i] < 0)
57  {
58  label index = -map[i]-1;
59  cop(lhs[index], negOp(rhs[i]));
60  }
61  else
62  {
64  << "At index " << i << " out of " << map.size()
65  << " have illegal index " << map[i]
66  << " for field " << rhs.size() << " with flipMap"
67  << exit(FatalError);
68  }
69  }
70  }
71  else
72  {
73  forAll(map, i)
74  {
75  cop(lhs[map[i]], rhs[i]);
76  }
77  }
78 }
79 
80 
81 template<class T, class negateOp>
83 (
84  const UList<T>& fld,
85  const label index,
86  const bool hasFlip,
87  const negateOp& negOp
88 )
89 {
90  T t;
91  if (hasFlip)
92  {
93  if (index > 0)
94  {
95  t = fld[index-1];
96  }
97  else if (index < 0)
98  {
99  t = negOp(fld[-index-1]);
100  }
101  else
102  {
104  << "Illegal index " << index
105  << " into field of size " << fld.size()
106  << " with face-flipping"
107  << exit(FatalError);
108  t = fld[index];
109  }
110  }
111  else
112  {
113  t = fld[index];
114  }
115  return t;
116 }
117 
118 
119 // Distribute list.
120 template<class T, class negateOp>
122 (
123  const Pstream::commsTypes commsType,
124  const List<labelPair>& schedule,
125  const label constructSize,
126  const labelListList& subMap,
127  const bool subHasFlip,
128  const labelListList& constructMap,
129  const bool constructHasFlip,
130  List<T>& field,
131  const negateOp& negOp,
132  const int tag,
133  const label comm
134 )
135 {
136  const label myRank = Pstream::myProcNo(comm);
137  const label nProcs = Pstream::nProcs(comm);
138 
139  if (!Pstream::parRun())
140  {
141  // Do only me to me.
142 
143  const labelList& mySubMap = subMap[myRank];
144 
145  List<T> subField(mySubMap.size());
146  forAll(mySubMap, i)
147  {
148  subField[i] = accessAndFlip(field, mySubMap[i], subHasFlip, negOp);
149  }
150 
151  // Receive sub field from myself (subField)
152  const labelList& map = constructMap[myRank];
153 
154  field.setSize(constructSize);
155 
156  flipAndCombine
157  (
158  map,
159  constructHasFlip,
160  subField,
161  eqOp<T>(),
162  negOp,
163  field
164  );
165 
166  return;
167  }
168 
169  if (commsType == Pstream::commsTypes::blocking)
170  {
171  // Since buffered sending can reuse the field to collect the
172  // received data.
173 
174  // Send sub field to neighbour
175  for (const int domain : Pstream::allProcs(comm))
176  {
177  const labelList& map = subMap[domain];
178 
179  if (domain != myRank && map.size())
180  {
181  OPstream toNbr
182  (
183  Pstream::commsTypes::blocking,
184  domain,
185  0,
186  tag,
187  comm
188  );
189 
190  List<T> subField(map.size());
191  forAll(subField, i)
192  {
193  subField[i] = accessAndFlip
194  (
195  field,
196  map[i],
197  subHasFlip,
198  negOp
199  );
200  }
201  toNbr << subField;
202  }
203  }
204 
205  // Subset myself
206  const labelList& mySubMap = subMap[myRank];
207 
208  List<T> subField(mySubMap.size());
209  forAll(mySubMap, i)
210  {
211  subField[i] = accessAndFlip(field, mySubMap[i], subHasFlip, negOp);
212  }
213 
214  // Receive sub field from myself (subField)
215  const labelList& map = constructMap[myRank];
216 
217  field.setSize(constructSize);
218 
219  flipAndCombine
220  (
221  map,
222  constructHasFlip,
223  subField,
224  eqOp<T>(),
225  negOp,
226  field
227  );
228 
229  // Receive sub field from neighbour
230  for (const int domain : Pstream::allProcs(comm))
231  {
232  const labelList& map = constructMap[domain];
233 
234  if (domain != myRank && map.size())
235  {
236  IPstream fromNbr
237  (
238  Pstream::commsTypes::blocking,
239  domain,
240  0,
241  tag,
242  comm
243  );
244  List<T> subField(fromNbr);
245 
246  checkReceivedSize(domain, map.size(), subField.size());
247 
248  flipAndCombine
249  (
250  map,
251  constructHasFlip,
252  subField,
253  eqOp<T>(),
254  negOp,
255  field
256  );
257  }
258  }
259  }
260  else if (commsType == Pstream::commsTypes::scheduled)
261  {
262  // Need to make sure I don't overwrite field with received data
263  // since the data might need to be sent to another processor. So
264  // allocate a new field for the results.
265  List<T> newField(constructSize);
266 
267  // Receive sub field from myself
268  {
269  const labelList& mySubMap = subMap[myRank];
270 
271  List<T> subField(mySubMap.size());
272  forAll(subField, i)
273  {
274  subField[i] = accessAndFlip
275  (
276  field,
277  mySubMap[i],
278  subHasFlip,
279  negOp
280  );
281  }
282 
283  // Receive sub field from myself (subField)
284  flipAndCombine
285  (
286  constructMap[myRank],
287  constructHasFlip,
288  subField,
289  eqOp<T>(),
290  negOp,
291  newField
292  );
293  }
294 
295  // Schedule will already have pruned 0-sized comms
296  forAll(schedule, i)
297  {
298  const labelPair& twoProcs = schedule[i];
299  // twoProcs is a swap pair of processors. The first one is the
300  // one that needs to send first and then receive.
301 
302  label sendProc = twoProcs[0];
303  label recvProc = twoProcs[1];
304 
305  if (myRank == sendProc)
306  {
307  // I am send first, receive next
308  {
309  OPstream toNbr
310  (
311  Pstream::commsTypes::scheduled,
312  recvProc,
313  0,
314  tag,
315  comm
316  );
317 
318  const labelList& map = subMap[recvProc];
319  List<T> subField(map.size());
320  forAll(subField, i)
321  {
322  subField[i] = accessAndFlip
323  (
324  field,
325  map[i],
326  subHasFlip,
327  negOp
328  );
329  }
330  toNbr << subField;
331  }
332  {
333  IPstream fromNbr
334  (
335  Pstream::commsTypes::scheduled,
336  recvProc,
337  0,
338  tag,
339  comm
340  );
341  List<T> subField(fromNbr);
342 
343  const labelList& map = constructMap[recvProc];
344 
345  checkReceivedSize(recvProc, map.size(), subField.size());
346 
347  flipAndCombine
348  (
349  map,
350  constructHasFlip,
351  subField,
352  eqOp<T>(),
353  negOp,
354  newField
355  );
356  }
357  }
358  else
359  {
360  // I am receive first, send next
361  {
362  IPstream fromNbr
363  (
364  Pstream::commsTypes::scheduled,
365  sendProc,
366  0,
367  tag,
368  comm
369  );
370  List<T> subField(fromNbr);
371 
372  const labelList& map = constructMap[sendProc];
373 
374  checkReceivedSize(sendProc, map.size(), subField.size());
375 
376  flipAndCombine
377  (
378  map,
379  constructHasFlip,
380  subField,
381  eqOp<T>(),
382  negOp,
383  newField
384  );
385  }
386  {
387  OPstream toNbr
388  (
389  Pstream::commsTypes::scheduled,
390  sendProc,
391  0,
392  tag,
393  comm
394  );
395 
396  const labelList& map = subMap[sendProc];
397  List<T> subField(map.size());
398  forAll(subField, i)
399  {
400  subField[i] = accessAndFlip
401  (
402  field,
403  map[i],
404  subHasFlip,
405  negOp
406  );
407  }
408  toNbr << subField;
409  }
410  }
411  }
412  field.transfer(newField);
413  }
414  else if (commsType == Pstream::commsTypes::nonBlocking)
415  {
416  label nOutstanding = Pstream::nRequests();
417 
419  {
420  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking, tag, comm);
421 
422  // Stream data into buffer
423  for (const int domain : Pstream::allProcs(comm))
424  {
425  const labelList& map = subMap[domain];
426 
427  if (domain != myRank && map.size())
428  {
429  // Put data into send buffer
430  UOPstream toDomain(domain, pBufs);
431 
432  List<T> subField(map.size());
433  forAll(subField, i)
434  {
435  subField[i] = accessAndFlip
436  (
437  field,
438  map[i],
439  subHasFlip,
440  negOp
441  );
442  }
443  toDomain << subField;
444  }
445  }
446 
447  // Start receiving. Do not block.
448  pBufs.finishedSends(false);
449 
450  {
451  // Set up 'send' to myself
452  const labelList& mySub = subMap[myRank];
453  List<T> mySubField(mySub.size());
454  forAll(mySub, i)
455  {
456  mySubField[i] = accessAndFlip
457  (
458  field,
459  mySub[i],
460  subHasFlip,
461  negOp
462  );
463  }
464  // Combine bits. Note that can reuse field storage
465  field.setSize(constructSize);
466  // Receive sub field from myself
467  {
468  const labelList& map = constructMap[myRank];
469 
470  flipAndCombine
471  (
472  map,
473  constructHasFlip,
474  mySubField,
475  eqOp<T>(),
476  negOp,
477  field
478  );
479  }
480  }
481 
482  // Block ourselves, waiting only for the current comms
483  Pstream::waitRequests(nOutstanding);
484 
485  // Consume
486  for (const int domain : Pstream::allProcs(comm))
487  {
488  const labelList& map = constructMap[domain];
489 
490  if (domain != myRank && map.size())
491  {
492  UIPstream str(domain, pBufs);
493  List<T> recvField(str);
494 
495  checkReceivedSize(domain, map.size(), recvField.size());
496 
497  flipAndCombine
498  (
499  map,
500  constructHasFlip,
501  recvField,
502  eqOp<T>(),
503  negOp,
504  field
505  );
506  }
507  }
508  }
509  else
510  {
511  // Set up sends to neighbours
512 
513  List<List<T>> sendFields(nProcs);
514 
515  for (const int domain : Pstream::allProcs(comm))
516  {
517  const labelList& map = subMap[domain];
518 
519  if (domain != myRank && map.size())
520  {
521  List<T>& subField = sendFields[domain];
522  subField.setSize(map.size());
523  forAll(map, i)
524  {
525  subField[i] = accessAndFlip
526  (
527  field,
528  map[i],
529  subHasFlip,
530  negOp
531  );
532  }
533 
535  (
536  Pstream::commsTypes::nonBlocking,
537  domain,
538  reinterpret_cast<const char*>(subField.cdata()),
539  subField.byteSize(),
540  tag,
541  comm
542  );
543  }
544  }
545 
546  // Set up receives from neighbours
547 
548  List<List<T>> recvFields(nProcs);
549 
550  for (const int domain : Pstream::allProcs(comm))
551  {
552  const labelList& map = constructMap[domain];
553 
554  if (domain != myRank && map.size())
555  {
556  recvFields[domain].setSize(map.size());
558  (
559  Pstream::commsTypes::nonBlocking,
560  domain,
561  reinterpret_cast<char*>(recvFields[domain].data()),
562  recvFields[domain].byteSize(),
563  tag,
564  comm
565  );
566  }
567  }
568 
569 
570  // Set up 'send' to myself
571 
572  {
573  const labelList& map = subMap[myRank];
574 
575  List<T>& subField = sendFields[myRank];
576  subField.setSize(map.size());
577  forAll(map, i)
578  {
579  subField[i] = accessAndFlip
580  (
581  field,
582  map[i],
583  subHasFlip,
584  negOp
585  );
586  }
587  }
588 
589 
590  // Combine bits. Note that can reuse field storage
591 
592  field.setSize(constructSize);
593 
594 
595  // Receive sub field from myself (sendFields[myRank])
596  {
597  const labelList& map = constructMap[myRank];
598  const List<T>& subField = sendFields[myRank];
599 
600  flipAndCombine
601  (
602  map,
603  constructHasFlip,
604  subField,
605  eqOp<T>(),
606  negOp,
607  field
608  );
609  }
610 
611 
612  // Wait for all to finish
613 
614  Pstream::waitRequests(nOutstanding);
615 
616 
617  // Collect neighbour fields
618 
619  for (const int domain : Pstream::allProcs(comm))
620  {
621  const labelList& map = constructMap[domain];
622 
623  if (domain != myRank && map.size())
624  {
625  const List<T>& subField = recvFields[domain];
626 
627  checkReceivedSize(domain, map.size(), subField.size());
628 
629  flipAndCombine
630  (
631  map,
632  constructHasFlip,
633  subField,
634  eqOp<T>(),
635  negOp,
636  field
637  );
638  }
639  }
640  }
641  }
642  else
643  {
645  << "Unknown communication schedule " << int(commsType)
646  << abort(FatalError);
647  }
648 }
649 
650 
651 // Distribute list.
652 template<class T, class CombineOp, class negateOp>
654 (
655  const Pstream::commsTypes commsType,
656  const List<labelPair>& schedule,
657  const label constructSize,
658  const labelListList& subMap,
659  const bool subHasFlip,
660  const labelListList& constructMap,
661  const bool constructHasFlip,
662  List<T>& field,
663  const T& nullValue,
664  const CombineOp& cop,
665  const negateOp& negOp,
666  const int tag,
667  const label comm
668 )
669 {
670  const label myRank = Pstream::myProcNo(comm);
671  const label nProcs = Pstream::nProcs(comm);
672 
673  if (!Pstream::parRun())
674  {
675  // Do only me to me.
676 
677  const labelList& mySubMap = subMap[myRank];
678 
679  List<T> subField(mySubMap.size());
680  forAll(mySubMap, i)
681  {
682  subField[i] = accessAndFlip(field, mySubMap[i], subHasFlip, negOp);
683  }
684 
685  // Receive sub field from myself (subField)
686  const labelList& map = constructMap[myRank];
687 
688  field.setSize(constructSize);
689  field = nullValue;
690 
691  flipAndCombine(map, constructHasFlip, subField, cop, negOp, field);
692 
693  return;
694  }
695 
696  if (commsType == Pstream::commsTypes::blocking)
697  {
698  // Since buffered sending can reuse the field to collect the
699  // received data.
700 
701  // Send sub field to neighbour
702  for (const int domain : Pstream::allProcs(comm))
703  {
704  const labelList& map = subMap[domain];
705 
706  if (domain != myRank && map.size())
707  {
708  OPstream toNbr
709  (
710  Pstream::commsTypes::blocking,
711  domain,
712  0,
713  tag,
714  comm
715  );
716  List<T> subField(map.size());
717  forAll(subField, i)
718  {
719  subField[i] = accessAndFlip
720  (
721  field,
722  map[i],
723  subHasFlip,
724  negOp
725  );
726  }
727  toNbr << subField;
728  }
729  }
730 
731  // Subset myself
732  const labelList& mySubMap = subMap[myRank];
733 
734  List<T> subField(mySubMap.size());
735  forAll(mySubMap, i)
736  {
737  subField[i] = accessAndFlip(field, mySubMap[i], subHasFlip, negOp);
738  }
739 
740  // Receive sub field from myself (subField)
741  const labelList& map = constructMap[myRank];
742 
743  field.setSize(constructSize);
744  field = nullValue;
745 
746  flipAndCombine(map, constructHasFlip, subField, cop, negOp, field);
747 
748  // Receive sub field from neighbour
749  for (const int domain : Pstream::allProcs(comm))
750  {
751  const labelList& map = constructMap[domain];
752 
753  if (domain != myRank && map.size())
754  {
755  IPstream fromNbr
756  (
757  Pstream::commsTypes::blocking,
758  domain,
759  0,
760  tag,
761  comm
762  );
763  List<T> subField(fromNbr);
764 
765  checkReceivedSize(domain, map.size(), subField.size());
766 
767  flipAndCombine
768  (
769  map,
770  constructHasFlip,
771  subField,
772  cop,
773  negOp,
774  field
775  );
776  }
777  }
778  }
779  else if (commsType == Pstream::commsTypes::scheduled)
780  {
781  // Need to make sure I don't overwrite field with received data
782  // since the data might need to be sent to another processor. So
783  // allocate a new field for the results.
784  List<T> newField(constructSize, nullValue);
785 
786  {
787  const labelList& mySubMap = subMap[myRank];
788 
789  // Subset myself
790  List<T> subField(mySubMap.size());
791  forAll(subField, i)
792  {
793  subField[i] = accessAndFlip
794  (
795  field,
796  mySubMap[i],
797  subHasFlip,
798  negOp
799  );
800  }
801 
802  // Receive sub field from myself (subField)
803  const labelList& map = constructMap[myRank];
804 
805  flipAndCombine
806  (
807  map,
808  constructHasFlip,
809  subField,
810  cop,
811  negOp,
812  newField
813  );
814  }
815 
816 
817  // Schedule will already have pruned 0-sized comms
818  forAll(schedule, i)
819  {
820  const labelPair& twoProcs = schedule[i];
821  // twoProcs is a swap pair of processors. The first one is the
822  // one that needs to send first and then receive.
823 
824  label sendProc = twoProcs[0];
825  label recvProc = twoProcs[1];
826 
827  if (myRank == sendProc)
828  {
829  // I am send first, receive next
830  {
831  OPstream toNbr
832  (
833  Pstream::commsTypes::scheduled,
834  recvProc,
835  0,
836  tag,
837  comm
838  );
839 
840  const labelList& map = subMap[recvProc];
841 
842  List<T> subField(map.size());
843  forAll(subField, i)
844  {
845  subField[i] = accessAndFlip
846  (
847  field,
848  map[i],
849  subHasFlip,
850  negOp
851  );
852  }
853  toNbr << subField;
854  }
855  {
856  IPstream fromNbr
857  (
858  Pstream::commsTypes::scheduled,
859  recvProc,
860  0,
861  tag,
862  comm
863  );
864  List<T> subField(fromNbr);
865  const labelList& map = constructMap[recvProc];
866 
867  checkReceivedSize(recvProc, map.size(), subField.size());
868 
869  flipAndCombine
870  (
871  map,
872  constructHasFlip,
873  subField,
874  cop,
875  negOp,
876  newField
877  );
878  }
879  }
880  else
881  {
882  // I am receive first, send next
883  {
884  IPstream fromNbr
885  (
886  Pstream::commsTypes::scheduled,
887  sendProc,
888  0,
889  tag,
890  comm
891  );
892  List<T> subField(fromNbr);
893  const labelList& map = constructMap[sendProc];
894 
895  checkReceivedSize(sendProc, map.size(), subField.size());
896 
897  flipAndCombine
898  (
899  map,
900  constructHasFlip,
901  subField,
902  cop,
903  negOp,
904  newField
905  );
906  }
907  {
908  OPstream toNbr
909  (
910  Pstream::commsTypes::scheduled,
911  sendProc,
912  0,
913  tag,
914  comm
915  );
916 
917  const labelList& map = subMap[sendProc];
918 
919  List<T> subField(map.size());
920  forAll(subField, i)
921  {
922  subField[i] = accessAndFlip
923  (
924  field,
925  map[i],
926  subHasFlip,
927  negOp
928  );
929  }
930  toNbr << subField;
931  }
932  }
933  }
934  field.transfer(newField);
935  }
936  else if (commsType == Pstream::commsTypes::nonBlocking)
937  {
938  label nOutstanding = Pstream::nRequests();
939 
941  {
942  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking, tag, comm);
943 
944  // Stream data into buffer
945  for (const int domain : Pstream::allProcs(comm))
946  {
947  const labelList& map = subMap[domain];
948 
949  if (domain != myRank && map.size())
950  {
951  // Put data into send buffer
952  UOPstream toDomain(domain, pBufs);
953 
954  List<T> subField(map.size());
955  forAll(subField, i)
956  {
957  subField[i] = accessAndFlip
958  (
959  field,
960  map[i],
961  subHasFlip,
962  negOp
963  );
964  }
965  toDomain << subField;
966  }
967  }
968 
969  // Start receiving. Do not block.
970  pBufs.finishedSends(false);
971 
972  {
973  // Set up 'send' to myself
974  const labelList& myMap = subMap[myRank];
975 
976  List<T> mySubField(myMap.size());
977  forAll(myMap, i)
978  {
979  mySubField[i] = accessAndFlip
980  (
981  field,
982  myMap[i],
983  subHasFlip,
984  negOp
985  );
986  }
987 
988  // Combine bits. Note that can reuse field storage
989  field.setSize(constructSize);
990  field = nullValue;
991  // Receive sub field from myself
992  {
993  const labelList& map = constructMap[myRank];
994 
995  flipAndCombine
996  (
997  map,
998  constructHasFlip,
999  mySubField,
1000  cop,
1001  negOp,
1002  field
1003  );
1004  }
1005  }
1006 
1007  // Block ourselves, waiting only for the current comms
1008  Pstream::waitRequests(nOutstanding);
1009 
1010  // Consume
1011  for (const int domain : Pstream::allProcs(comm))
1012  {
1013  const labelList& map = constructMap[domain];
1014 
1015  if (domain != myRank && map.size())
1016  {
1017  UIPstream str(domain, pBufs);
1018  List<T> recvField(str);
1019 
1020  checkReceivedSize(domain, map.size(), recvField.size());
1021 
1022  flipAndCombine
1023  (
1024  map,
1025  constructHasFlip,
1026  recvField,
1027  cop,
1028  negOp,
1029  field
1030  );
1031  }
1032  }
1033  }
1034  else
1035  {
1036  // Set up sends to neighbours
1037 
1038  List<List<T>> sendFields(nProcs);
1039 
1040  for (const int domain : Pstream::allProcs(comm))
1041  {
1042  const labelList& map = subMap[domain];
1043 
1044  if (domain != myRank && map.size())
1045  {
1046  List<T>& subField = sendFields[domain];
1047  subField.setSize(map.size());
1048  forAll(map, i)
1049  {
1050  subField[i] = accessAndFlip
1051  (
1052  field,
1053  map[i],
1054  subHasFlip,
1055  negOp
1056  );
1057  }
1058 
1060  (
1061  Pstream::commsTypes::nonBlocking,
1062  domain,
1063  reinterpret_cast<const char*>(subField.cdata()),
1064  subField.size()*sizeof(T),
1065  tag,
1066  comm
1067  );
1068  }
1069  }
1070 
1071  // Set up receives from neighbours
1072 
1073  List<List<T>> recvFields(nProcs);
1074 
1075  for (const int domain : Pstream::allProcs(comm))
1076  {
1077  const labelList& map = constructMap[domain];
1078 
1079  if (domain != myRank && map.size())
1080  {
1081  recvFields[domain].setSize(map.size());
1083  (
1084  Pstream::commsTypes::nonBlocking,
1085  domain,
1086  reinterpret_cast<char*>(recvFields[domain].data()),
1087  recvFields[domain].size()*sizeof(T),
1088  tag,
1089  comm
1090  );
1091  }
1092  }
1093 
1094  // Set up 'send' to myself
1095 
1096  {
1097  const labelList& map = subMap[myRank];
1098 
1099  List<T>& subField = sendFields[myRank];
1100  subField.setSize(map.size());
1101  forAll(map, i)
1102  {
1103  subField[i] = accessAndFlip
1104  (
1105  field,
1106  map[i],
1107  subHasFlip,
1108  negOp
1109  );
1110  }
1111  }
1112 
1113 
1114  // Combine bits. Note that can reuse field storage
1115 
1116  field.setSize(constructSize);
1117  field = nullValue;
1118 
1119  // Receive sub field from myself (subField)
1120  {
1121  const labelList& map = constructMap[myRank];
1122  const List<T>& subField = sendFields[myRank];
1123 
1124  flipAndCombine
1125  (
1126  map,
1127  constructHasFlip,
1128  subField,
1129  cop,
1130  negOp,
1131  field
1132  );
1133  }
1134 
1135 
1136  // Wait for all to finish
1137 
1138  Pstream::waitRequests(nOutstanding);
1139 
1140 
1141  // Collect neighbour fields
1142 
1143  for (const int domain : Pstream::allProcs(comm))
1144  {
1145  const labelList& map = constructMap[domain];
1146 
1147  if (domain != myRank && map.size())
1148  {
1149  const List<T>& subField = recvFields[domain];
1150 
1151  checkReceivedSize(domain, map.size(), subField.size());
1152 
1153  flipAndCombine
1154  (
1155  map,
1156  constructHasFlip,
1157  subField,
1158  cop,
1159  negOp,
1160  field
1161  );
1162  }
1163  }
1164  }
1165  }
1166  else
1167  {
1169  << "Unknown communication schedule " << int(commsType)
1170  << abort(FatalError);
1171  }
1172 }
1173 
1174 
1175 template<class T>
1177 const
1178 {
1179  // Stream data into buffer
1180  for (const int domain : Pstream::allProcs(comm_))
1181  {
1182  const labelList& map = subMap_[domain];
1183 
1184  if (map.size())
1185  {
1186  // Put data into send buffer
1187  UOPstream toDomain(domain, pBufs);
1188 
1189  List<T> subField(map.size());
1190  forAll(subField, i)
1191  {
1192  subField[i] = accessAndFlip
1193  (
1194  field,
1195  map[i],
1196  subHasFlip_,
1197  flipOp()
1198  );
1199  }
1200  toDomain << subField;
1201  }
1202  }
1203 
1204  // Start sending and receiving but do not block.
1205  pBufs.finishedSends(false);
1206 }
1207 
1208 
1209 template<class T>
1211 const
1212 {
1213  // Consume
1214  field.setSize(constructSize_);
1215 
1216  for (const int domain : Pstream::allProcs(comm_))
1217  {
1218  const labelList& map = constructMap_[domain];
1219 
1220  if (map.size())
1221  {
1222  UIPstream str(domain, pBufs);
1223  List<T> recvField(str);
1224 
1225  if (recvField.size() != map.size())
1226  {
1228  << "Expected from processor " << domain
1229  << " " << map.size() << " but received "
1230  << recvField.size() << " elements."
1231  << abort(FatalError);
1232  }
1233 
1234  flipAndCombine
1235  (
1236  map,
1237  constructHasFlip_,
1238  recvField,
1239  eqOp<T>(),
1240  flipOp(),
1241  field
1242  );
1243  }
1244  }
1245 }
1246 
1247 
1248 //- Distribute data using default commsType.
1249 template<class T, class negateOp>
1252  List<T>& fld,
1253  const negateOp& negOp,
1254  const int tag
1255 ) const
1256 {
1258  {
1259  distribute
1260  (
1262  List<labelPair>(),
1263  constructSize_,
1264  subMap_,
1265  subHasFlip_,
1266  constructMap_,
1267  constructHasFlip_,
1268  fld,
1269  negOp,
1270  tag,
1271  comm_
1272  );
1273  }
1275  {
1276  distribute
1277  (
1279  schedule(),
1280  constructSize_,
1281  subMap_,
1282  subHasFlip_,
1283  constructMap_,
1284  constructHasFlip_,
1285  fld,
1286  negOp,
1287  tag,
1288  comm_
1289  );
1290  }
1291  else
1292  {
1293  distribute
1294  (
1296  List<labelPair>(),
1297  constructSize_,
1298  subMap_,
1299  subHasFlip_,
1300  constructMap_,
1301  constructHasFlip_,
1302  fld,
1303  negOp,
1304  tag,
1305  comm_
1306  );
1307  }
1308 }
1309 
1310 
1311 //- Distribute data using default commsType.
1312 template<class T>
1315  List<T>& fld,
1316  const int tag
1317 ) const
1318 {
1319  distribute(fld, flipOp(), tag);
1320 }
1321 
1322 
1323 //- Distribute data using default commsType.
1324 template<class T>
1328  const int tag
1329 ) const
1330 {
1331  fld.shrink();
1332 
1333  List<T>& fldList = static_cast<List<T>&>(fld);
1334 
1335  distribute(fldList, tag);
1336 
1337  fld.setCapacity(fldList.size());
1338 }
1339 
1340 
1341 //- Reverse distribute data using default commsType.
1342 template<class T>
1345  const label constructSize,
1346  List<T>& fld,
1347  const int tag
1348 ) const
1349 {
1351  {
1352  distribute
1353  (
1355  List<labelPair>(),
1356  constructSize,
1357  constructMap_,
1358  constructHasFlip_,
1359  subMap_,
1360  subHasFlip_,
1361  fld,
1362  flipOp(),
1363  tag,
1364  comm_
1365  );
1366  }
1368  {
1369  distribute
1370  (
1372  schedule(),
1373  constructSize,
1374  constructMap_,
1375  constructHasFlip_,
1376  subMap_,
1377  subHasFlip_,
1378  fld,
1379  flipOp(),
1380  tag,
1381  comm_
1382  );
1383  }
1384  else
1385  {
1386  distribute
1387  (
1389  List<labelPair>(),
1390  constructSize,
1391  constructMap_,
1392  constructHasFlip_,
1393  subMap_,
1394  subHasFlip_,
1395  fld,
1396  flipOp(),
1397  tag,
1398  comm_
1399  );
1400  }
1401 }
1402 
1403 
1404 //- Reverse distribute data using default commsType.
1405 // Since constructSize might be larger than supplied size supply
1406 // a nullValue
1407 template<class T>
1410  const label constructSize,
1411  const T& nullValue,
1412  List<T>& fld,
1413  const int tag
1414 ) const
1415 {
1417  {
1418  distribute
1419  (
1421  List<labelPair>(),
1422  constructSize,
1423  constructMap_,
1424  constructHasFlip_,
1425  subMap_,
1426  subHasFlip_,
1427  fld,
1428  nullValue,
1429  eqOp<T>(),
1430  flipOp(),
1431  tag,
1432  comm_
1433  );
1434  }
1436  {
1437  distribute
1438  (
1440  schedule(),
1441  constructSize,
1442  constructMap_,
1443  constructHasFlip_,
1444  subMap_,
1445  subHasFlip_,
1446  fld,
1447  nullValue,
1448  eqOp<T>(),
1449  flipOp(),
1450  tag,
1451  comm_
1452  );
1453  }
1454  else
1455  {
1456  distribute
1457  (
1459  List<labelPair>(),
1460  constructSize,
1461  constructMap_,
1462  constructHasFlip_,
1463  subMap_,
1464  subHasFlip_,
1465  fld,
1466  nullValue,
1467  eqOp<T>(),
1468  flipOp(),
1469  tag,
1470  comm_
1471  );
1472  }
1473 }
1474 
1475 
1476 // ************************************************************************* //
Foam::mapDistributeBase::reverseDistribute
void reverseDistribute(const label constructSize, List< T > &, const int tag=UPstream::msgType()) const
Reverse distribute data using default commsType.
Definition: mapDistributeBaseTemplates.C:1344
Foam::mapDistributeBase::accessAndFlip
static T accessAndFlip(const UList< T > &fld, const label index, const bool hasFlip, const negateOp &negOp)
Definition: mapDistributeBaseTemplates.C:83
Foam::UPstream::commsTypes::blocking
Foam::mapDistributeBase::subMap_
labelListList subMap_
Maps from subsetted data back to original data.
Definition: mapDistributeBase.H:113
Foam::UPstream::commsTypes::nonBlocking
Foam::UOPstream
Output inter-processor communications stream operating on external buffer.
Definition: UOPstream.H:57
Foam::DynamicList
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:55
Foam::OPstream
Output inter-processor communications stream.
Definition: OPstream.H:52
Foam::mapDistributeBase::send
void send(PstreamBuffers &, const List< T > &) const
Do all sends using PstreamBuffers.
Definition: mapDistributeBaseTemplates.C:1176
Foam::PstreamBuffers
Buffers for inter-processor communications streams (UOPstream, UIPstream).
Definition: PstreamBuffers.H:87
Foam::mapDistributeBase::receive
void receive(PstreamBuffers &, List< T > &) const
Do all receives using PstreamBuffers.
Definition: mapDistributeBaseTemplates.C:1210
Foam::UPstream::defaultCommsType
static commsTypes defaultCommsType
Default commsType.
Definition: UPstream.H:283
Foam::mapDistributeBase::flipAndCombine
static void flipAndCombine(const labelUList &map, const bool hasFlip, const UList< T > &rhs, const CombineOp &cop, const negateOp &negOp, List< T > &lhs)
Definition: mapDistributeBaseTemplates.C:38
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
PstreamCombineReduceOps.H
Combination-Reduction operation for a parallel run. The information from all nodes is collected on th...
Foam::mapDistributeBase::comm_
label comm_
Communicator to use for parallel operations.
Definition: mapDistributeBase.H:125
Foam::mapDistributeBase::distribute
static void distribute(const Pstream::commsTypes commsType, const List< labelPair > &schedule, const label constructSize, const labelListList &subMap, const bool subHasFlip, const labelListList &constructMap, const bool constructHasFlip, List< T > &, const negateOp &negOp, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Distribute data. Note:schedule only used for.
Definition: mapDistributeBaseTemplates.C:122
Foam::T
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
Definition: FieldFieldFunctions.C:58
field
rDeltaTY field()
fld
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Definition: gmvOutputLagrangian.H:23
Foam::PstreamBuffers::finishedSends
void finishedSends(const bool block=true)
Mark all sends as having been done. This will start receives.
Definition: PstreamBuffers.C:80
Foam::UPstream::commsTypes::scheduled
Foam::blockMeshTools::read
void read(Istream &, label &, const dictionary &)
In-place read with dictionary lookup.
Definition: blockMeshTools.C:33
Foam::FatalError
error FatalError
Foam::mapDistributeBase::subHasFlip_
bool subHasFlip_
Whether subMap includes flip or not.
Definition: mapDistributeBase.H:119
Foam::eqOp
Definition: ops.H:71
Pstream.H
flipOp.H
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
T
const volScalarField & T
Definition: createFieldRefs.H:2
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::UPstream::commsTypes
commsTypes
Types of communications.
Definition: UPstream.H:69
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:381
Foam::UPstream::allProcs
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition: UPstream.H:509
Foam::Pair< label >
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
Foam::UList< label >
PstreamBuffers.H
Foam::vtk::write
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
Definition: foamVtkOutputTemplates.C:35
Foam::UList::size
void size(const label n) noexcept
Override size to be inconsistent with allocated storage.
Definition: UListI.H:360
Foam::IPstream
Input inter-processor communications stream.
Definition: IPstream.H:52
Foam::UIPstream
Input inter-processor communications stream operating on external buffer.
Definition: UIPstream.H:56
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::data
Database for solution data, solver performance and other reduced data.
Definition: data.H:55
Foam::is_contiguous
A template class to specify that a data type can be considered as being contiguous in memory.
Definition: contiguous.H:75
Foam::flipOp
Functor to negate primitives. Dummy for most other types.
Definition: flipOp.H:53