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-2016, 2019 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "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 )
134 {
135  if (!Pstream::parRun())
136  {
137  // Do only me to me.
138 
139  const labelList& mySubMap = subMap[Pstream::myProcNo()];
140 
141  List<T> subField(mySubMap.size());
142  forAll(mySubMap, i)
143  {
144  subField[i] = accessAndFlip(field, mySubMap[i], subHasFlip, negOp);
145  }
146 
147  // Receive sub field from myself (subField)
148  const labelList& map = constructMap[Pstream::myProcNo()];
149 
150  field.setSize(constructSize);
151 
152  flipAndCombine
153  (
154  map,
155  constructHasFlip,
156  subField,
157  eqOp<T>(),
158  negOp,
159  field
160  );
161 
162  return;
163  }
164 
165  if (commsType == Pstream::commsTypes::blocking)
166  {
167  // Since buffered sending can reuse the field to collect the
168  // received data.
169 
170  // Send sub field to neighbour
171  for (label domain = 0; domain < Pstream::nProcs(); domain++)
172  {
173  const labelList& map = subMap[domain];
174 
175  if (domain != Pstream::myProcNo() && map.size())
176  {
177  OPstream toNbr(Pstream::commsTypes::blocking, domain, 0, tag);
178 
179  List<T> subField(map.size());
180  forAll(subField, i)
181  {
182  subField[i] = accessAndFlip
183  (
184  field,
185  map[i],
186  subHasFlip,
187  negOp
188  );
189  }
190  toNbr << subField;
191  }
192  }
193 
194  // Subset myself
195  const labelList& mySubMap = subMap[Pstream::myProcNo()];
196 
197  List<T> subField(mySubMap.size());
198  forAll(mySubMap, i)
199  {
200  subField[i] = accessAndFlip(field, mySubMap[i], subHasFlip, negOp);
201  }
202 
203  // Receive sub field from myself (subField)
204  const labelList& map = constructMap[Pstream::myProcNo()];
205 
206  field.setSize(constructSize);
207 
208  flipAndCombine
209  (
210  map,
211  constructHasFlip,
212  subField,
213  eqOp<T>(),
214  negOp,
215  field
216  );
217 
218  // Receive sub field from neighbour
219  for (label domain = 0; domain < Pstream::nProcs(); domain++)
220  {
221  const labelList& map = constructMap[domain];
222 
223  if (domain != Pstream::myProcNo() && map.size())
224  {
225  IPstream fromNbr(Pstream::commsTypes::blocking, domain, 0, tag);
226  List<T> subField(fromNbr);
227 
228  checkReceivedSize(domain, map.size(), subField.size());
229 
230  flipAndCombine
231  (
232  map,
233  constructHasFlip,
234  subField,
235  eqOp<T>(),
236  negOp,
237  field
238  );
239  }
240  }
241  }
242  else if (commsType == Pstream::commsTypes::scheduled)
243  {
244  // Need to make sure I don't overwrite field with received data
245  // since the data might need to be sent to another processor. So
246  // allocate a new field for the results.
247  List<T> newField(constructSize);
248 
249  // Receive sub field from myself
250  {
251  const labelList& mySubMap = subMap[Pstream::myProcNo()];
252 
253  List<T> subField(mySubMap.size());
254  forAll(subField, i)
255  {
256  subField[i] = accessAndFlip
257  (
258  field,
259  mySubMap[i],
260  subHasFlip,
261  negOp
262  );
263  }
264 
265  // Receive sub field from myself (subField)
266  flipAndCombine
267  (
268  constructMap[Pstream::myProcNo()],
269  constructHasFlip,
270  subField,
271  eqOp<T>(),
272  negOp,
273  newField
274  );
275  }
276 
277  // Schedule will already have pruned 0-sized comms
278  forAll(schedule, i)
279  {
280  const labelPair& twoProcs = schedule[i];
281  // twoProcs is a swap pair of processors. The first one is the
282  // one that needs to send first and then receive.
283 
284  label sendProc = twoProcs[0];
285  label recvProc = twoProcs[1];
286 
287  if (Pstream::myProcNo() == sendProc)
288  {
289  // I am send first, receive next
290  {
291  OPstream toNbr
292  (
293  Pstream::commsTypes::scheduled,
294  recvProc,
295  0,
296  tag
297  );
298 
299  const labelList& map = subMap[recvProc];
300  List<T> subField(map.size());
301  forAll(subField, i)
302  {
303  subField[i] = accessAndFlip
304  (
305  field,
306  map[i],
307  subHasFlip,
308  negOp
309  );
310  }
311  toNbr << subField;
312  }
313  {
314  IPstream fromNbr
315  (
316  Pstream::commsTypes::scheduled,
317  recvProc,
318  0,
319  tag
320  );
321  List<T> subField(fromNbr);
322 
323  const labelList& map = constructMap[recvProc];
324 
325  checkReceivedSize(recvProc, map.size(), subField.size());
326 
327  flipAndCombine
328  (
329  map,
330  constructHasFlip,
331  subField,
332  eqOp<T>(),
333  negOp,
334  newField
335  );
336  }
337  }
338  else
339  {
340  // I am receive first, send next
341  {
342  IPstream fromNbr
343  (
344  Pstream::commsTypes::scheduled,
345  sendProc,
346  0,
347  tag
348  );
349  List<T> subField(fromNbr);
350 
351  const labelList& map = constructMap[sendProc];
352 
353  checkReceivedSize(sendProc, map.size(), subField.size());
354 
355  flipAndCombine
356  (
357  map,
358  constructHasFlip,
359  subField,
360  eqOp<T>(),
361  negOp,
362  newField
363  );
364  }
365  {
366  OPstream toNbr
367  (
368  Pstream::commsTypes::scheduled,
369  sendProc,
370  0,
371  tag
372  );
373 
374  const labelList& map = subMap[sendProc];
375  List<T> subField(map.size());
376  forAll(subField, i)
377  {
378  subField[i] = accessAndFlip
379  (
380  field,
381  map[i],
382  subHasFlip,
383  negOp
384  );
385  }
386  toNbr << subField;
387  }
388  }
389  }
390  field.transfer(newField);
391  }
392  else if (commsType == Pstream::commsTypes::nonBlocking)
393  {
394  label nOutstanding = Pstream::nRequests();
395 
397  {
398  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking, tag);
399 
400  // Stream data into buffer
401  for (label domain = 0; domain < Pstream::nProcs(); domain++)
402  {
403  const labelList& map = subMap[domain];
404 
405  if (domain != Pstream::myProcNo() && map.size())
406  {
407  // Put data into send buffer
408  UOPstream toDomain(domain, pBufs);
409 
410  List<T> subField(map.size());
411  forAll(subField, i)
412  {
413  subField[i] = accessAndFlip
414  (
415  field,
416  map[i],
417  subHasFlip,
418  negOp
419  );
420  }
421  toDomain << subField;
422  }
423  }
424 
425  // Start receiving. Do not block.
426  pBufs.finishedSends(false);
427 
428  {
429  // Set up 'send' to myself
430  const labelList& mySub = subMap[Pstream::myProcNo()];
431  List<T> mySubField(mySub.size());
432  forAll(mySub, i)
433  {
434  mySubField[i] = accessAndFlip
435  (
436  field,
437  mySub[i],
438  subHasFlip,
439  negOp
440  );
441  }
442  // Combine bits. Note that can reuse field storage
443  field.setSize(constructSize);
444  // Receive sub field from myself
445  {
446  const labelList& map = constructMap[Pstream::myProcNo()];
447 
448  flipAndCombine
449  (
450  map,
451  constructHasFlip,
452  mySubField,
453  eqOp<T>(),
454  negOp,
455  field
456  );
457  }
458  }
459 
460  // Block ourselves, waiting only for the current comms
461  Pstream::waitRequests(nOutstanding);
462 
463  // Consume
464  for (label domain = 0; domain < Pstream::nProcs(); domain++)
465  {
466  const labelList& map = constructMap[domain];
467 
468  if (domain != Pstream::myProcNo() && map.size())
469  {
470  UIPstream str(domain, pBufs);
471  List<T> recvField(str);
472 
473  checkReceivedSize(domain, map.size(), recvField.size());
474 
475  flipAndCombine
476  (
477  map,
478  constructHasFlip,
479  recvField,
480  eqOp<T>(),
481  negOp,
482  field
483  );
484  }
485  }
486  }
487  else
488  {
489  // Set up sends to neighbours
490 
491  List<List<T>> sendFields(Pstream::nProcs());
492 
493  for (label domain = 0; domain < Pstream::nProcs(); domain++)
494  {
495  const labelList& map = subMap[domain];
496 
497  if (domain != Pstream::myProcNo() && map.size())
498  {
499  List<T>& subField = sendFields[domain];
500  subField.setSize(map.size());
501  forAll(map, i)
502  {
503  subField[i] = accessAndFlip
504  (
505  field,
506  map[i],
507  subHasFlip,
508  negOp
509  );
510  }
511 
513  (
514  Pstream::commsTypes::nonBlocking,
515  domain,
516  reinterpret_cast<const char*>(subField.begin()),
517  subField.byteSize(),
518  tag
519  );
520  }
521  }
522 
523  // Set up receives from neighbours
524 
525  List<List<T>> recvFields(Pstream::nProcs());
526 
527  for (label domain = 0; domain < Pstream::nProcs(); domain++)
528  {
529  const labelList& map = constructMap[domain];
530 
531  if (domain != Pstream::myProcNo() && map.size())
532  {
533  recvFields[domain].setSize(map.size());
535  (
536  Pstream::commsTypes::nonBlocking,
537  domain,
538  reinterpret_cast<char*>(recvFields[domain].begin()),
539  recvFields[domain].byteSize(),
540  tag
541  );
542  }
543  }
544 
545 
546  // Set up 'send' to myself
547 
548  {
549  const labelList& map = subMap[Pstream::myProcNo()];
550 
551  List<T>& subField = sendFields[Pstream::myProcNo()];
552  subField.setSize(map.size());
553  forAll(map, i)
554  {
555  subField[i] = accessAndFlip
556  (
557  field,
558  map[i],
559  subHasFlip,
560  negOp
561  );
562  }
563  }
564 
565 
566  // Combine bits. Note that can reuse field storage
567 
568  field.setSize(constructSize);
569 
570 
571  // Receive sub field from myself (sendFields[Pstream::myProcNo()])
572  {
573  const labelList& map = constructMap[Pstream::myProcNo()];
574  const List<T>& subField = sendFields[Pstream::myProcNo()];
575 
576  flipAndCombine
577  (
578  map,
579  constructHasFlip,
580  subField,
581  eqOp<T>(),
582  negOp,
583  field
584  );
585  }
586 
587 
588  // Wait for all to finish
589 
590  Pstream::waitRequests(nOutstanding);
591 
592 
593  // Collect neighbour fields
594 
595  for (label domain = 0; domain < Pstream::nProcs(); domain++)
596  {
597  const labelList& map = constructMap[domain];
598 
599  if (domain != Pstream::myProcNo() && map.size())
600  {
601  const List<T>& subField = recvFields[domain];
602 
603  checkReceivedSize(domain, map.size(), subField.size());
604 
605  flipAndCombine
606  (
607  map,
608  constructHasFlip,
609  subField,
610  eqOp<T>(),
611  negOp,
612  field
613  );
614  }
615  }
616  }
617  }
618  else
619  {
621  << "Unknown communication schedule " << int(commsType)
622  << abort(FatalError);
623  }
624 }
625 
626 
627 // Distribute list.
628 template<class T, class CombineOp, class negateOp>
630 (
631  const Pstream::commsTypes commsType,
632  const List<labelPair>& schedule,
633  const label constructSize,
634  const labelListList& subMap,
635  const bool subHasFlip,
636  const labelListList& constructMap,
637  const bool constructHasFlip,
638  List<T>& field,
639  const CombineOp& cop,
640  const negateOp& negOp,
641  const T& nullValue,
642  const int tag
643 )
644 {
645  if (!Pstream::parRun())
646  {
647  // Do only me to me.
648 
649  const labelList& mySubMap = subMap[Pstream::myProcNo()];
650 
651  List<T> subField(mySubMap.size());
652  forAll(mySubMap, i)
653  {
654  subField[i] = accessAndFlip(field, mySubMap[i], subHasFlip, negOp);
655  }
656 
657  // Receive sub field from myself (subField)
658  const labelList& map = constructMap[Pstream::myProcNo()];
659 
660  field.setSize(constructSize);
661  field = nullValue;
662 
663  flipAndCombine(map, constructHasFlip, subField, cop, negOp, field);
664 
665  return;
666  }
667 
668  if (commsType == Pstream::commsTypes::blocking)
669  {
670  // Since buffered sending can reuse the field to collect the
671  // received data.
672 
673  // Send sub field to neighbour
674  for (label domain = 0; domain < Pstream::nProcs(); domain++)
675  {
676  const labelList& map = subMap[domain];
677 
678  if (domain != Pstream::myProcNo() && map.size())
679  {
680  OPstream toNbr(Pstream::commsTypes::blocking, domain, 0, tag);
681  List<T> subField(map.size());
682  forAll(subField, i)
683  {
684  subField[i] = accessAndFlip
685  (
686  field,
687  map[i],
688  subHasFlip,
689  negOp
690  );
691  }
692  toNbr << subField;
693  }
694  }
695 
696  // Subset myself
697  const labelList& mySubMap = subMap[Pstream::myProcNo()];
698 
699  List<T> subField(mySubMap.size());
700  forAll(mySubMap, i)
701  {
702  subField[i] = accessAndFlip(field, mySubMap[i], subHasFlip, negOp);
703  }
704 
705  // Receive sub field from myself (subField)
706  const labelList& map = constructMap[Pstream::myProcNo()];
707 
708  field.setSize(constructSize);
709  field = nullValue;
710 
711  flipAndCombine(map, constructHasFlip, subField, cop, negOp, field);
712 
713  // Receive sub field from neighbour
714  for (label domain = 0; domain < Pstream::nProcs(); domain++)
715  {
716  const labelList& map = constructMap[domain];
717 
718  if (domain != Pstream::myProcNo() && map.size())
719  {
720  IPstream fromNbr(Pstream::commsTypes::blocking, domain, 0, tag);
721  List<T> subField(fromNbr);
722 
723  checkReceivedSize(domain, map.size(), subField.size());
724 
725  flipAndCombine
726  (
727  map,
728  constructHasFlip,
729  subField,
730  cop,
731  negOp,
732  field
733  );
734  }
735  }
736  }
737  else if (commsType == Pstream::commsTypes::scheduled)
738  {
739  // Need to make sure I don't overwrite field with received data
740  // since the data might need to be sent to another processor. So
741  // allocate a new field for the results.
742  List<T> newField(constructSize, nullValue);
743 
744  {
745  const labelList& mySubMap = subMap[Pstream::myProcNo()];
746 
747  // Subset myself
748  List<T> subField(mySubMap.size());
749  forAll(subField, i)
750  {
751  subField[i] = accessAndFlip
752  (
753  field,
754  mySubMap[i],
755  subHasFlip,
756  negOp
757  );
758  }
759 
760  // Receive sub field from myself (subField)
761  const labelList& map = constructMap[Pstream::myProcNo()];
762 
763  flipAndCombine
764  (
765  map,
766  constructHasFlip,
767  subField,
768  cop,
769  negOp,
770  newField
771  );
772  }
773 
774 
775  // Schedule will already have pruned 0-sized comms
776  forAll(schedule, i)
777  {
778  const labelPair& twoProcs = schedule[i];
779  // twoProcs is a swap pair of processors. The first one is the
780  // one that needs to send first and then receive.
781 
782  label sendProc = twoProcs[0];
783  label recvProc = twoProcs[1];
784 
785  if (Pstream::myProcNo() == sendProc)
786  {
787  // I am send first, receive next
788  {
789  OPstream toNbr
790  (
791  Pstream::commsTypes::scheduled,
792  recvProc,
793  0,
794  tag
795  );
796 
797  const labelList& map = subMap[recvProc];
798 
799  List<T> subField(map.size());
800  forAll(subField, i)
801  {
802  subField[i] = accessAndFlip
803  (
804  field,
805  map[i],
806  subHasFlip,
807  negOp
808  );
809  }
810  toNbr << subField;
811  }
812  {
813  IPstream fromNbr
814  (
815  Pstream::commsTypes::scheduled,
816  recvProc,
817  0,
818  tag
819  );
820  List<T> subField(fromNbr);
821  const labelList& map = constructMap[recvProc];
822 
823  checkReceivedSize(recvProc, map.size(), subField.size());
824 
825  flipAndCombine
826  (
827  map,
828  constructHasFlip,
829  subField,
830  cop,
831  negOp,
832  newField
833  );
834  }
835  }
836  else
837  {
838  // I am receive first, send next
839  {
840  IPstream fromNbr
841  (
842  Pstream::commsTypes::scheduled,
843  sendProc,
844  0,
845  tag
846  );
847  List<T> subField(fromNbr);
848  const labelList& map = constructMap[sendProc];
849 
850  checkReceivedSize(sendProc, map.size(), subField.size());
851 
852  flipAndCombine
853  (
854  map,
855  constructHasFlip,
856  subField,
857  cop,
858  negOp,
859  newField
860  );
861  }
862  {
863  OPstream toNbr
864  (
865  Pstream::commsTypes::scheduled,
866  sendProc,
867  0,
868  tag
869  );
870 
871  const labelList& map = subMap[sendProc];
872 
873  List<T> subField(map.size());
874  forAll(subField, i)
875  {
876  subField[i] = accessAndFlip
877  (
878  field,
879  map[i],
880  subHasFlip,
881  negOp
882  );
883  }
884  toNbr << subField;
885  }
886  }
887  }
888  field.transfer(newField);
889  }
890  else if (commsType == Pstream::commsTypes::nonBlocking)
891  {
892  label nOutstanding = Pstream::nRequests();
893 
895  {
896  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking, tag);
897 
898  // Stream data into buffer
899  for (label domain = 0; domain < Pstream::nProcs(); domain++)
900  {
901  const labelList& map = subMap[domain];
902 
903  if (domain != Pstream::myProcNo() && map.size())
904  {
905  // Put data into send buffer
906  UOPstream toDomain(domain, pBufs);
907 
908  List<T> subField(map.size());
909  forAll(subField, i)
910  {
911  subField[i] = accessAndFlip
912  (
913  field,
914  map[i],
915  subHasFlip,
916  negOp
917  );
918  }
919  toDomain << subField;
920  }
921  }
922 
923  // Start receiving. Do not block.
924  pBufs.finishedSends(false);
925 
926  {
927  // Set up 'send' to myself
928  const labelList& myMap = subMap[Pstream::myProcNo()];
929 
930  List<T> mySubField(myMap.size());
931  forAll(myMap, i)
932  {
933  mySubField[i] = accessAndFlip
934  (
935  field,
936  myMap[i],
937  subHasFlip,
938  negOp
939  );
940  }
941 
942  // Combine bits. Note that can reuse field storage
943  field.setSize(constructSize);
944  field = nullValue;
945  // Receive sub field from myself
946  {
947  const labelList& map = constructMap[Pstream::myProcNo()];
948 
949  flipAndCombine
950  (
951  map,
952  constructHasFlip,
953  mySubField,
954  cop,
955  negOp,
956  field
957  );
958  }
959  }
960 
961  // Block ourselves, waiting only for the current comms
962  Pstream::waitRequests(nOutstanding);
963 
964  // Consume
965  for (label domain = 0; domain < Pstream::nProcs(); domain++)
966  {
967  const labelList& map = constructMap[domain];
968 
969  if (domain != Pstream::myProcNo() && map.size())
970  {
971  UIPstream str(domain, pBufs);
972  List<T> recvField(str);
973 
974  checkReceivedSize(domain, map.size(), recvField.size());
975 
976  flipAndCombine
977  (
978  map,
979  constructHasFlip,
980  recvField,
981  cop,
982  negOp,
983  field
984  );
985  }
986  }
987  }
988  else
989  {
990  // Set up sends to neighbours
991 
992  List<List<T>> sendFields(Pstream::nProcs());
993 
994  for (label domain = 0; domain < Pstream::nProcs(); domain++)
995  {
996  const labelList& map = subMap[domain];
997 
998  if (domain != Pstream::myProcNo() && map.size())
999  {
1000  List<T>& subField = sendFields[domain];
1001  subField.setSize(map.size());
1002  forAll(map, i)
1003  {
1004  subField[i] = accessAndFlip
1005  (
1006  field,
1007  map[i],
1008  subHasFlip,
1009  negOp
1010  );
1011  }
1012 
1014  (
1015  Pstream::commsTypes::nonBlocking,
1016  domain,
1017  reinterpret_cast<const char*>(subField.begin()),
1018  subField.size()*sizeof(T),
1019  tag
1020  );
1021  }
1022  }
1023 
1024  // Set up receives from neighbours
1025 
1026  List<List<T>> recvFields(Pstream::nProcs());
1027 
1028  for (label domain = 0; domain < Pstream::nProcs(); domain++)
1029  {
1030  const labelList& map = constructMap[domain];
1031 
1032  if (domain != Pstream::myProcNo() && map.size())
1033  {
1034  recvFields[domain].setSize(map.size());
1036  (
1037  Pstream::commsTypes::nonBlocking,
1038  domain,
1039  reinterpret_cast<char*>(recvFields[domain].begin()),
1040  recvFields[domain].size()*sizeof(T),
1041  tag
1042  );
1043  }
1044  }
1045 
1046  // Set up 'send' to myself
1047 
1048  {
1049  const labelList& map = subMap[Pstream::myProcNo()];
1050 
1051  List<T>& subField = sendFields[Pstream::myProcNo()];
1052  subField.setSize(map.size());
1053  forAll(map, i)
1054  {
1055  subField[i] = accessAndFlip
1056  (
1057  field,
1058  map[i],
1059  subHasFlip,
1060  negOp
1061  );
1062  }
1063  }
1064 
1065 
1066  // Combine bits. Note that can reuse field storage
1067 
1068  field.setSize(constructSize);
1069  field = nullValue;
1070 
1071  // Receive sub field from myself (subField)
1072  {
1073  const labelList& map = constructMap[Pstream::myProcNo()];
1074  const List<T>& subField = sendFields[Pstream::myProcNo()];
1075 
1076  flipAndCombine
1077  (
1078  map,
1079  constructHasFlip,
1080  subField,
1081  cop,
1082  negOp,
1083  field
1084  );
1085  }
1086 
1087 
1088  // Wait for all to finish
1089 
1090  Pstream::waitRequests(nOutstanding);
1091 
1092 
1093  // Collect neighbour fields
1094 
1095  for (label domain = 0; domain < Pstream::nProcs(); domain++)
1096  {
1097  const labelList& map = constructMap[domain];
1098 
1099  if (domain != Pstream::myProcNo() && map.size())
1100  {
1101  const List<T>& subField = recvFields[domain];
1102 
1103  checkReceivedSize(domain, map.size(), subField.size());
1104 
1105  flipAndCombine
1106  (
1107  map,
1108  constructHasFlip,
1109  subField,
1110  cop,
1111  negOp,
1112  field
1113  );
1114  }
1115  }
1116  }
1117  }
1118  else
1119  {
1121  << "Unknown communication schedule " << int(commsType)
1122  << abort(FatalError);
1123  }
1124 }
1125 
1126 
1127 template<class T>
1129 const
1130 {
1131  // Stream data into buffer
1132  for (label domain = 0; domain < Pstream::nProcs(); domain++)
1133  {
1134  const labelList& map = subMap_[domain];
1135 
1136  if (map.size())
1137  {
1138  // Put data into send buffer
1139  UOPstream toDomain(domain, pBufs);
1140 
1141  List<T> subField(map.size());
1142  forAll(subField, i)
1143  {
1144  subField[i] = accessAndFlip
1145  (
1146  field,
1147  map[i],
1148  subHasFlip_,
1149  flipOp()
1150  );
1151  }
1152  toDomain << subField;
1153  }
1154  }
1155 
1156  // Start sending and receiving but do not block.
1157  pBufs.finishedSends(false);
1158 }
1159 
1160 
1161 template<class T>
1163 const
1164 {
1165  // Consume
1166  field.setSize(constructSize_);
1167 
1168  for (label domain = 0; domain < Pstream::nProcs(); domain++)
1169  {
1170  const labelList& map = constructMap_[domain];
1171 
1172  if (map.size())
1173  {
1174  UIPstream str(domain, pBufs);
1175  List<T> recvField(str);
1176 
1177  if (recvField.size() != map.size())
1178  {
1180  << "Expected from processor " << domain
1181  << " " << map.size() << " but received "
1182  << recvField.size() << " elements."
1183  << abort(FatalError);
1184  }
1185 
1186  flipAndCombine
1187  (
1188  map,
1189  constructHasFlip_,
1190  recvField,
1191  eqOp<T>(),
1192  flipOp(),
1193  field
1194  );
1195  }
1196  }
1197 }
1198 
1199 
1200 //- Distribute data using default commsType.
1201 template<class T, class negateOp>
1204  List<T>& fld,
1205  const negateOp& negOp,
1206  const int tag
1207 ) const
1208 {
1210  {
1211  distribute
1212  (
1214  List<labelPair>(),
1215  constructSize_,
1216  subMap_,
1217  subHasFlip_,
1218  constructMap_,
1219  constructHasFlip_,
1220  fld,
1221  negOp,
1222  tag
1223  );
1224  }
1226  {
1227  distribute
1228  (
1230  schedule(),
1231  constructSize_,
1232  subMap_,
1233  subHasFlip_,
1234  constructMap_,
1235  constructHasFlip_,
1236  fld,
1237  negOp,
1238  tag
1239  );
1240  }
1241  else
1242  {
1243  distribute
1244  (
1246  List<labelPair>(),
1247  constructSize_,
1248  subMap_,
1249  subHasFlip_,
1250  constructMap_,
1251  constructHasFlip_,
1252  fld,
1253  negOp,
1254  tag
1255  );
1256  }
1257 }
1258 
1259 
1260 //- Distribute data using default commsType.
1261 template<class T>
1264  List<T>& fld,
1265  const int tag
1266 ) const
1267 {
1268  distribute(fld, flipOp(), tag);
1269 }
1270 
1271 
1272 //- Distribute data using default commsType.
1273 template<class T>
1277  const int tag
1278 ) const
1279 {
1280  fld.shrink();
1281 
1282  List<T>& fldList = static_cast<List<T>&>(fld);
1283 
1284  distribute(fldList, tag);
1285 
1286  fld.setCapacity(fldList.size());
1287 }
1288 
1289 
1290 //- Reverse distribute data using default commsType.
1291 template<class T>
1294  const label constructSize,
1295  List<T>& fld,
1296  const int tag
1297 ) const
1298 {
1300  {
1301  distribute
1302  (
1304  List<labelPair>(),
1305  constructSize,
1306  constructMap_,
1307  constructHasFlip_,
1308  subMap_,
1309  subHasFlip_,
1310  fld,
1311  flipOp(),
1312  tag
1313  );
1314  }
1316  {
1317  distribute
1318  (
1320  schedule(),
1321  constructSize,
1322  constructMap_,
1323  constructHasFlip_,
1324  subMap_,
1325  subHasFlip_,
1326  fld,
1327  flipOp(),
1328  tag
1329  );
1330  }
1331  else
1332  {
1333  distribute
1334  (
1336  List<labelPair>(),
1337  constructSize,
1338  constructMap_,
1339  constructHasFlip_,
1340  subMap_,
1341  subHasFlip_,
1342  fld,
1343  flipOp(),
1344  tag
1345  );
1346  }
1347 }
1348 
1349 
1350 //- Reverse distribute data using default commsType.
1351 // Since constructSize might be larger than supplied size supply
1352 // a nullValue
1353 template<class T>
1356  const label constructSize,
1357  const T& nullValue,
1358  List<T>& fld,
1359  const int tag
1360 ) const
1361 {
1363  {
1364  distribute
1365  (
1367  List<labelPair>(),
1368  constructSize,
1369  constructMap_,
1370  constructHasFlip_,
1371  subMap_,
1372  subHasFlip_,
1373  fld,
1374  eqOp<T>(),
1375  flipOp(),
1376  nullValue,
1377  tag
1378  );
1379  }
1381  {
1382  distribute
1383  (
1385  schedule(),
1386  constructSize,
1387  constructMap_,
1388  constructHasFlip_,
1389  subMap_,
1390  subHasFlip_,
1391  fld,
1392  eqOp<T>(),
1393  flipOp(),
1394  nullValue,
1395  tag
1396  );
1397  }
1398  else
1399  {
1400  distribute
1401  (
1403  List<labelPair>(),
1404  constructSize,
1405  constructMap_,
1406  constructHasFlip_,
1407  subMap_,
1408  subHasFlip_,
1409  fld,
1410  eqOp<T>(),
1411  flipOp(),
1412  nullValue,
1413  tag
1414  );
1415  }
1416 }
1417 
1418 
1419 // ************************************************************************* //
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:1293
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
stdFoam::begin
constexpr auto begin(C &c) -> decltype(c.begin())
Return iterator to the beginning of the container c.
Definition: stdFoam.H:91
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:57
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())
Distribute data. Note:schedule only used for.
Definition: mapDistributeBaseTemplates.C:122
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:1128
Foam::UPstream::nProcs
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:426
Foam::PstreamBuffers
Buffers for inter-processor communications streams (UOPstream, UIPstream).
Definition: PstreamBuffers.H:88
Foam::mapDistributeBase::receive
void receive(PstreamBuffers &, List< T > &) const
Do all receives using PstreamBuffers.
Definition: mapDistributeBaseTemplates.C:1162
Foam::UPstream::defaultCommsType
static commsTypes defaultCommsType
Default commsType.
Definition: UPstream.H:273
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:290
PstreamCombineReduceOps.H
Combination-Reduction operation for a parallel run. The information from all nodes is collected on th...
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:62
Foam::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:137
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:66
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
Foam::Pair
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: Pair.H:54
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:102
Foam::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::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