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-2025 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"
31 #include "flipOp.H"
32 
33 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
34 
35 template<class T, class CombineOp, class NegateOp>
37 (
38  UList<T>& lhs,
39  const UList<T>& rhs,
40 
41  const labelUList& map,
42  const bool hasFlip,
43  const CombineOp& cop,
44  const NegateOp& negOp
45 )
46 {
47  const label len = map.size();
48 
49  // FULLDEBUG: if (lhs.size() < max(map)) FatalError ...;
50  // FULLDEBUG: if (rhs.size() < len) FatalError ...;
51 
52  if (hasFlip)
53  {
54  for (label i = 0; i < len; ++i)
55  {
56  const label index = map[i];
57 
58  if (index > 0)
59  {
60  cop(lhs[index-1], rhs[i]);
61  }
62  else if (index < 0)
63  {
64  cop(lhs[-index-1], negOp(rhs[i]));
65  }
66  else
67  {
69  << "Illegal flip index '0' at " << i << '/' << map.size()
70  << " for list:" << rhs.size() << nl
71  << exit(FatalError);
72  }
73  }
74  }
75  else
76  {
77  for (label i = 0; i < len; ++i)
78  {
79  cop(lhs[map[i]], rhs[i]);
80  }
81  }
82 }
83 
84 
85 template<class T, class NegateOp>
87 (
88  UList<T>& output,
89  const UList<T>& values,
90  const labelUList& map,
91  const bool hasFlip,
92  const NegateOp& negOp
93 )
94 {
95  const label len = map.size();
96 
97  // FULLDEBUG: if (values.size() < max(map)) FatalError ...;
98  // FULLDEBUG: if (output.size() < len) FatalError ...;
99 
100  if (hasFlip)
101  {
102  for (label i = 0; i < len; ++i)
103  {
104  const label index = map[i];
105 
106  if (index > 0)
107  {
108  output[i] = values[index-1];
109  }
110  else if (index < 0)
111  {
112  output[i] = negOp(values[-index-1]);
113  }
114  else
115  {
117  << "Illegal flip index '0' at " << i << '/' << map.size()
118  << " for list:" << values.size() << nl
119  << exit(FatalError);
120  }
121  }
122  }
123  else
124  {
125  // Like indirect list
126  for (label i = 0; i < len; ++i)
127  {
128  output[i] = values[map[i]];
129  }
130  }
131 }
132 
133 
134 template<class T, class NegateOp>
136 (
137  const UList<T>& values,
138  const labelUList& map,
139  const bool hasFlip,
140  const NegateOp& negOp
141 )
142 {
143  List<T> output(map.size());
144  accessAndFlip(output, values, map, hasFlip, negOp);
145  return output;
146 }
147 
148 
149 template<class T, class NegateOp>
151 (
152  const labelListList& subMap,
153  const bool subHasFlip,
154  const labelListList& constructMap,
155  const bool constructHasFlip,
156  const UList<T>& field,
157 
158  labelRange& sendRequests,
159  PtrList<List<T>>& sendFields,
160 
161  labelRange& recvRequests,
162  PtrList<List<T>>& recvFields,
163 
164  const NegateOp& negOp,
165  const int tag,
166  const label comm
167 )
168 {
169  if constexpr (!is_contiguous_v<T>)
170  {
172  << "Only contiguous is currently supported"
174  }
175 
176  const auto myRank = UPstream::myProcNo(comm);
177  const auto nProcs = UPstream::nProcs(comm);
178 
179 
180  // Set up receives from neighbours
181  recvRequests.start() = UPstream::nRequests();
182  recvRequests.size() = 0;
183 
184  recvFields.resize(nProcs);
185 
186  for (const int proci : UPstream::allProcs(comm))
187  {
188  const labelList& map = constructMap[proci];
189 
190  if (proci == myRank)
191  {
192  // No communication for myself - but recvFields may be used
193  }
194  else if (map.empty())
195  {
196  // No receive necessary
197  (void) recvFields.release(proci);
198  }
199  else
200  {
201  List<T>& subField = recvFields.try_emplace(proci);
202  subField.resize_nocopy(map.size());
203 
205  (
207  proci,
208  subField,
209  tag,
210  comm
211  );
212  }
213  }
214 
215  // Finished setting up the receives
216  recvRequests.size() = (UPstream::nRequests() - recvRequests.start());
217 
218 
219  // Set up sends to neighbours
220  sendRequests.start() = UPstream::nRequests();
221  sendRequests.size() = 0;
222 
223  sendFields.resize(nProcs);
224 
225  for (const int proci : UPstream::allProcs(comm))
226  {
227  const labelList& map = subMap[proci];
228 
229  if (proci == myRank)
230  {
231  // No communication - sendFields not needed
232  (void) sendFields.release(proci);
233  }
234  else if (map.empty())
235  {
236  // No send necessary
237  (void) sendFields.release(proci);
238  }
239  else
240  {
241  List<T>& subField = sendFields.try_emplace(proci);
242  subField.resize_nocopy(map.size());
243 
244  accessAndFlip(subField, field, map, subHasFlip, negOp);
245 
247  (
249  proci,
250  subField,
251  tag,
252  comm
253  );
254  }
255  }
256 
257  // Finished setting up the sends
258  sendRequests.size() = (UPstream::nRequests() - sendRequests.start());
259 
260 
261  // Set up 'send' to myself - copy directly into recvFields
262  {
263  const labelList& map = subMap[myRank];
264 
265  if (map.empty())
266  {
267  // Nothing to send/recv
268  (void) recvFields.release(myRank);
269  }
270  else
271  {
272  List<T>& subField = recvFields.try_emplace(myRank);
273  subField.resize_nocopy(map.size());
274 
275  accessAndFlip(subField, field, map, subHasFlip, negOp);
276  }
277  }
278 }
279 
280 
281 template<class T>
283 (
284  const UList<T>& field,
285  labelRange& sendRequests,
286  PtrList<List<T>>& sendFields,
287  labelRange& recvRequests,
288  PtrList<List<T>>& recvFields,
289  const int tag
290 ) const
291 {
292  send
293  (
294  subMap_,
295  subHasFlip_,
296  constructMap_,
297  constructHasFlip_,
298  field,
299  sendRequests, sendFields,
300  recvRequests, recvFields,
301  flipOp(),
302  tag,
303  comm_
304  );
305 }
306 
307 
308 template<class T, class CombineOp, class NegateOp>
310 (
311  const label constructSize,
312  const labelListList& constructMap,
313  const bool constructHasFlip,
314  const labelRange& requests,
315  const UPtrList<List<T>>& recvFields,
316  List<T>& field,
317  const CombineOp& cop,
318  const NegateOp& negOp,
319  const int tag,
320  const label comm
321 )
322 {
323  if constexpr (!is_contiguous_v<T>)
324  {
326  << "Only contiguous is currently supported"
328  }
329 
330  const auto myRank = UPstream::myProcNo(comm);
331  [[maybe_unused]]
332  const auto nProcs = UPstream::nProcs(comm);
333 
334 
335  // Receiving from which procs - according to map information
336 
337  DynamicList<int> recvProcs(nProcs);
338  for (const int proci : UPstream::allProcs(comm))
339  {
340  const labelList& map = constructMap[proci];
341 
342  if (proci != myRank && map.size())
343  {
344  recvProcs.push_back(proci);
345 
346  const auto* subFieldPtr = recvFields.get(proci);
347  if (subFieldPtr)
348  {
349  checkReceivedSize(proci, map.size(), subFieldPtr->size());
350  }
351  else
352  {
354  << "From processor " << proci
355  << " : unallocated receive field."
356  << " Expected size " << map.size()
357  << " on comm " << comm
358  << " with procs " << UPstream::nProcs(comm) << nl
359  << exit(FatalError);
360  }
361  }
362  }
363 
364 
365  // Combining bits - can reuse field storage
366  field.resize_nocopy(constructSize);
367 
368 
369  // Received sub field from myself : recvFields[myRank]
370  if (recvFields.test(myRank))
371  {
372  const labelList& map = constructMap[myRank];
373  const List<T>& subField = recvFields[myRank];
374 
375  // Unlikely to need a size check
376  // checkReceivedSize(myRank, map.size(), subField.size());
377 
378  flipAndCombine
379  (
380  field,
381  subField,
382  map,
383  constructHasFlip,
384  cop,
385  negOp
386  );
387  }
388 
389 
390  // NB: do NOT use polling and dispatch here.
391  // There is no certainty if the listed requests are still pending or
392  // have already been waited on before calling this method.
393 
394  // Wait for (receive) requests, but the range may also include
395  // other requests depending on what the caller provided
396 
397  UPstream::waitRequests(requests.start(), requests.size());
398 
399 
400  // Process received fields
401 
402  {
403  for (const int proci : recvProcs)
404  {
405  const labelList& map = constructMap[proci];
406  const List<T>& subField = recvFields[proci];
407 
408  // Already checked the sizes previously
409  // checkReceivedSize(proci, map.size(), subField.size());
410 
411  flipAndCombine
412  (
413  field,
414  subField,
415  map,
416  constructHasFlip,
417  cop,
418  negOp
419  );
420  }
421  }
422 }
423 
424 
425 template<class T>
427 (
428  const labelRange& requests,
429  const UPtrList<List<T>>& recvFields,
430  List<T>& field,
431  const int tag
432 ) const
433 {
434  receive
435  (
436  constructSize_,
437  constructMap_,
438  constructHasFlip_,
439  requests,
440  recvFields,
441  field,
442  eqOp<T>(),
443  flipOp(),
444  tag,
445  comm_
446  );
447 }
448 
449 
450 template<class T, class CombineOp, class NegateOp>
452 (
453  const UPstream::commsTypes commsType,
454  const UList<labelPair>& schedule,
455  const label constructSize,
456  const labelListList& subMap,
457  const bool subHasFlip,
458  const labelListList& constructMap,
459  const bool constructHasFlip,
460  List<T>& field,
461  const T& nullValue,
462  const CombineOp& cop,
463  const NegateOp& negOp,
464  const int tag,
465  const label comm
466 )
467 {
468  const auto myRank = UPstream::myProcNo(comm);
469  [[maybe_unused]]
470  const auto nProcs = UPstream::nProcs(comm);
471 
472  if (!UPstream::parRun())
473  {
474  // Do only me to me.
475 
476  List<T> subField
477  (
478  accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
479  );
480 
481  // Receive sub field from myself (subField)
482  const labelList& map = constructMap[myRank];
483 
484  // Combining bits - can now reuse field storage
485  field.resize_nocopy(constructSize);
486  field = nullValue;
487 
488  flipAndCombine
489  (
490  field,
491  subField,
492  map,
493  constructHasFlip,
494  cop,
495  negOp
496  );
497 
498  return;
499  }
500 
501  if (commsType == UPstream::commsTypes::buffered)
502  {
503  // Since buffered sending can reuse the field to collect the
504  // received data.
505 
506  // Send sub field to neighbour
507  for (const int proci : UPstream::allProcs(comm))
508  {
509  const labelList& map = subMap[proci];
510 
511  if (proci != myRank && map.size())
512  {
513  List<T> subField
514  (
515  accessAndFlip(field, map, subHasFlip, negOp)
516  );
517 
518  // buffered send
519  OPstream os(commsType, proci, 0, tag, comm);
520  os << subField;
521  }
522  }
523 
524  {
525  // Subset myself
526  List<T> subField
527  (
528  accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
529  );
530 
531  // Receive sub field from myself (subField)
532  const labelList& map = constructMap[myRank];
533 
534  // Combining bits - can now reuse field storage
535  field.resize_nocopy(constructSize);
536  field = nullValue;
537 
538  flipAndCombine
539  (
540  field,
541  subField,
542  map,
543  constructHasFlip,
544  cop,
545  negOp
546  );
547  }
548 
549  // Receive and process sub-field from neighbours
550  for (const int proci : UPstream::allProcs(comm))
551  {
552  const labelList& map = constructMap[proci];
553 
554  if (proci != myRank && map.size())
555  {
556  List<T> subField;
557  IPstream::recv(subField, proci, tag, comm);
558 
559  checkReceivedSize(proci, map.size(), subField.size());
560 
561  flipAndCombine
562  (
563  field,
564  subField,
565  map,
566  constructHasFlip,
567  cop,
568  negOp
569  );
570  }
571  }
572  }
573  else if (commsType == UPstream::commsTypes::scheduled)
574  {
575  // Need to make sure I don't overwrite field with received data
576  // since the data might need to be sent to another processor. So
577  // allocate a new field for the results.
578  List<T> newField;
579  newField.resize_nocopy(constructSize);
580  newField = nullValue;
581 
582  // First handle self
583  {
584  // Subset myself
585  List<T> subField
586  (
587  accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
588  );
589 
590  // Receive sub field from myself (subField)
591  const labelList& map = constructMap[myRank];
592 
593  flipAndCombine
594  (
595  newField,
596  subField,
597  map,
598  constructHasFlip,
599  cop,
600  negOp
601  );
602  }
603 
604 
605  // Schedule will already have pruned 0-sized comms
606  for (const labelPair& twoProcs : schedule)
607  {
608  // twoProcs is a swap pair of processors. The first one is the
609  // one that needs to send first and then receive.
610 
611  if (twoProcs.first() == myRank)
612  {
613  // I am send first, receive next
614  const label nbrProc = twoProcs.second();
615 
616  {
617  const labelList& map = subMap[nbrProc];
618 
619  List<T> subField
620  (
621  accessAndFlip(field, map, subHasFlip, negOp)
622  );
623 
624  OPstream::send(subField, nbrProc, tag, comm);
625  }
626  {
627  List<T> subField;
628  IPstream::recv(subField, nbrProc, tag, comm);
629 
630  const labelList& map = constructMap[nbrProc];
631 
632  checkReceivedSize(nbrProc, map.size(), subField.size());
633 
634  flipAndCombine
635  (
636  newField,
637  subField,
638  map,
639  constructHasFlip,
640  cop,
641  negOp
642  );
643  }
644  }
645  else
646  {
647  // I am receive first, send next
648  const label nbrProc = twoProcs.first();
649 
650  {
651  List<T> subField;
652  IPstream::recv(subField, nbrProc, tag, comm);
653 
654  const labelList& map = constructMap[nbrProc];
655 
656  checkReceivedSize(nbrProc, map.size(), subField.size());
657 
658  flipAndCombine
659  (
660  newField,
661  subField,
662  map,
663  constructHasFlip,
664  cop,
665  negOp
666  );
667  }
668  {
669  const labelList& map = subMap[nbrProc];
670 
671  List<T> subField
672  (
673  accessAndFlip(field, map, subHasFlip, negOp)
674  );
675 
676  OPstream::send(subField, nbrProc, tag, comm);
677  }
678  }
679  }
680  field.transfer(newField);
681  }
682  else if (commsType == UPstream::commsTypes::nonBlocking)
683  {
684  const label startOfRequests = UPstream::nRequests();
685 
686  if constexpr (!is_contiguous_v<T>)
687  {
688  PstreamBuffers pBufs(comm, tag);
689 
690  // Stream data into buffer
691  for (const int proci : UPstream::allProcs(comm))
692  {
693  const labelList& map = subMap[proci];
694 
695  if (proci != myRank && map.size())
696  {
697  List<T> subField
698  (
699  accessAndFlip(field, map, subHasFlip, negOp)
700  );
701 
702  UOPstream os(proci, pBufs);
703  os << subField;
704  }
705  }
706 
707  // Initiate receiving - do yet not block
708  pBufs.finishedSends(false);
709 
710  {
711  // Set up 'send' to myself
712  List<T> subField
713  (
714  accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
715  );
716 
717  // Combining bits - can now reuse field storage
718  field.resize_nocopy(constructSize);
719  field = nullValue;
720 
721  // Receive sub field from myself
722  const labelList& map = constructMap[myRank];
723 
724  flipAndCombine
725  (
726  field,
727  subField,
728  map,
729  constructHasFlip,
730  cop,
731  negOp
732  );
733  }
734 
735  // Wait for receive requests (and the send requests too)
736  UPstream::waitRequests(startOfRequests);
737 
738  // Receive and process neighbour fields
739  for (const int proci : UPstream::allProcs(comm))
740  {
741  const labelList& map = constructMap[proci];
742 
743  if (proci != myRank && map.size())
744  {
745  UIPstream is(proci, pBufs);
746  List<T> subField(is);
747 
748  checkReceivedSize(proci, map.size(), subField.size());
749 
750  flipAndCombine
751  (
752  field,
753  subField,
754  map,
755  constructHasFlip,
756  cop,
757  negOp
758  );
759  }
760  }
761  }
762  else
763  {
764  // Set up receives from neighbours
765 
766  List<List<T>> recvFields(nProcs);
767  DynamicList<int> recvProcs(nProcs);
768 
769  for (const int proci : UPstream::allProcs(comm))
770  {
771  const labelList& map = constructMap[proci];
772 
773  if (proci != myRank && map.size())
774  {
775  recvProcs.push_back(proci);
776  List<T>& subField = recvFields[proci];
777  subField.resize_nocopy(map.size());
778 
780  (
782  proci,
783  subField,
784  tag,
785  comm
786  );
787  }
788  }
789 
790 
791  // Set up sends to neighbours
792 
793  List<List<T>> sendFields(nProcs);
794 
795  for (const int proci : UPstream::allProcs(comm))
796  {
797  const labelList& map = subMap[proci];
798 
799  if (proci != myRank && map.size())
800  {
801  List<T>& subField = sendFields[proci];
802  subField.resize_nocopy(map.size());
803 
804  accessAndFlip(subField, field, map, subHasFlip, negOp);
805 
807  (
809  proci,
810  subField,
811  tag,
812  comm
813  );
814  }
815  }
816 
817  // Set up 'send' to myself - copy directly into recvFields
818  {
819  const labelList& map = subMap[myRank];
820  List<T>& subField = recvFields[myRank];
821  subField.resize_nocopy(map.size());
822 
823  accessAndFlip(subField, field, map, subHasFlip, negOp);
824  }
825 
826 
827  // Combining bits - can now reuse field storage
828  field.resize_nocopy(constructSize);
829  field = nullValue;
830 
831  // Receive sub field from myself : recvFields[myRank]
832  {
833  const labelList& map = constructMap[myRank];
834  const List<T>& subField = recvFields[myRank];
835 
836  // Probably don't need a size check
837  // checkReceivedSize(myRank, map.size(), subField.size());
838 
839  flipAndCombine
840  (
841  field,
842  subField,
843  map,
844  constructHasFlip,
845  cop,
846  negOp
847  );
848  }
849 
850 
851  // Poll for completed receive requests and dispatch
852  DynamicList<int> indices(recvProcs.size());
853  while
854  (
856  (
857  startOfRequests,
858  recvProcs.size(),
859  &indices
860  )
861  )
862  {
863  for (const int idx : indices)
864  {
865  const int proci = recvProcs[idx];
866  const labelList& map = constructMap[proci];
867  const List<T>& subField = recvFields[proci];
868 
869  // No size check - was dimensioned above
870  // checkReceivedSize(proci, map.size(), subField.size());
871 
872  flipAndCombine
873  (
874  field,
875  subField,
876  map,
877  constructHasFlip,
878  cop,
879  negOp
880  );
881  }
882  }
883 
884  // Wait for any remaining requests
885  UPstream::waitRequests(startOfRequests);
886  }
887  }
888  else
889  {
891  << "Unknown communication schedule " << int(commsType)
893  }
894 }
895 
896 
897 template<class T, class CombineOp, class NegateOp>
899 (
900  const UPstream::commsTypes commsType,
901  const UList<labelPair>& schedule,
902 
903  const UList<T>& inField, // input field
904  const labelListList& subMap,
905  const bool subHasFlip,
906 
907  List<T>& field,
908  const label constructSize,
909  const labelListList& constructMap,
910  const bool constructHasFlip,
911  const T& nullValue,
912  const CombineOp& cop,
913  const NegateOp& negOp,
914 
915  const int tag,
916  const label comm
917 )
918 {
919  const auto myRank = UPstream::myProcNo(comm);
920  const auto nProcs = UPstream::nProcs(comm);
921 
922  if (!UPstream::parRun())
923  {
924  // Do only me to me.
925 
926  List<T> subField
927  (
928  accessAndFlip(inField, subMap[myRank], subHasFlip, negOp)
929  );
930 
931  // Receive sub field from myself (subField)
932  const labelList& map = constructMap[myRank];
933 
934  // Combining bits - can now reuse field storage
935  field.resize_nocopy(constructSize);
936  field = nullValue;
937 
938  flipAndCombine
939  (
940  field,
941  subField,
942  map,
943  constructHasFlip,
944  cop,
945  negOp
946  );
947 
948  return;
949  }
950 
951  if (commsType != UPstream::commsTypes::nonBlocking)
952  {
954  << "Unsupport communication type " << int(commsType)
955  << abort(FatalError);
956  }
957 
958  const label startOfRequests = UPstream::nRequests();
959 
960  if constexpr (!is_contiguous_v<T>)
961  {
962  PstreamBuffers pBufs(comm, tag);
963 
964  // Stream data into buffer
965  for (const int proci : UPstream::allProcs(comm))
966  {
967  const labelList& map = subMap[proci];
968 
969  if (proci != myRank && map.size())
970  {
971  List<T> subField
972  (
973  accessAndFlip(inField, map, subHasFlip, negOp)
974  );
975 
976  UOPstream os(proci, pBufs);
977  os << subField;
978  }
979  }
980 
981  // Initiate receiving - do yet not block
982  pBufs.finishedSends(false);
983 
984  {
985  // Set up 'send' to myself
986  List<T> subField
987  (
988  accessAndFlip(inField, subMap[myRank], subHasFlip, negOp)
989  );
990 
991  // Combining bits - can now reuse field storage
992  field.resize_nocopy(constructSize);
993  field = nullValue;
994 
995  // Receive sub field from myself
996  const labelList& map = constructMap[myRank];
997 
998  flipAndCombine
999  (
1000  field,
1001  subField,
1002  map,
1003  constructHasFlip,
1004  cop,
1005  negOp
1006  );
1007  }
1008 
1009  // Wait for receive requests (and the send requests too)
1010  UPstream::waitRequests(startOfRequests);
1011 
1012  // Receive and process neighbour fields
1013  for (const int proci : UPstream::allProcs(comm))
1014  {
1015  const labelList& map = constructMap[proci];
1016 
1017  if (proci != myRank && map.size())
1018  {
1019  UIPstream is(proci, pBufs);
1020  List<T> subField(is);
1021 
1022  checkReceivedSize(proci, map.size(), subField.size());
1023 
1024  flipAndCombine
1025  (
1026  field,
1027  subField,
1028  map,
1029  constructHasFlip,
1030  cop,
1031  negOp
1032  );
1033  }
1034  }
1035  }
1036  else
1037  {
1038  // Set up receives from neighbours
1039 
1040  List<List<T>> recvFields(nProcs);
1041  DynamicList<int> recvProcs(nProcs);
1042 
1043  for (const int proci : UPstream::allProcs(comm))
1044  {
1045  const labelList& map = constructMap[proci];
1046 
1047  if (proci != myRank && map.size())
1048  {
1049  recvProcs.push_back(proci);
1050  List<T>& subField = recvFields[proci];
1051  subField.resize_nocopy(map.size());
1052 
1054  (
1056  proci,
1057  subField.data_bytes(),
1058  subField.size_bytes(),
1059  tag,
1060  comm
1061  );
1062  }
1063  }
1064 
1065 
1066  // Set up sends to neighbours
1067 
1068  List<List<T>> sendFields(nProcs);
1069 
1070  for (const int proci : UPstream::allProcs(comm))
1071  {
1072  const labelList& map = subMap[proci];
1073 
1074  if (proci != myRank && map.size())
1075  {
1076  List<T>& subField = sendFields[proci];
1077  subField.resize_nocopy(map.size());
1078 
1079  accessAndFlip(subField, inField, map, subHasFlip, negOp);
1080 
1082  (
1084  proci,
1085  subField.cdata_bytes(),
1086  subField.size_bytes(),
1087  tag,
1088  comm
1089  );
1090  }
1091  }
1092 
1093  // Set up 'send' to myself - copy directly into recvFields
1094  {
1095  const labelList& map = subMap[myRank];
1096  List<T>& subField = recvFields[myRank];
1097  subField.resize_nocopy(map.size());
1098 
1099  accessAndFlip(subField, inField, map, subHasFlip, negOp);
1100  }
1101 
1102 
1103  // Combining bits - can now reuse field storage
1104  field.resize_nocopy(constructSize);
1105  field = nullValue;
1106 
1107  // Receive sub field from myself : recvFields[myRank]
1108  {
1109  const labelList& map = constructMap[myRank];
1110  const List<T>& subField = recvFields[myRank];
1111 
1112  // Probably don't need a size check
1113  // checkReceivedSize(myRank, map.size(), subField.size());
1114 
1115  flipAndCombine
1116  (
1117  field,
1118  subField,
1119  map,
1120  constructHasFlip,
1121  cop,
1122  negOp
1123  );
1124  }
1125 
1126 
1127  // Poll for completed receive requests and dispatch
1128  DynamicList<int> indices(recvProcs.size());
1129  while
1130  (
1132  (
1133  startOfRequests,
1134  recvProcs.size(),
1135  &indices
1136  )
1137  )
1138  {
1139  for (const int idx : indices)
1140  {
1141  const int proci = recvProcs[idx];
1142  const labelList& map = constructMap[proci];
1143  const List<T>& subField = recvFields[proci];
1144 
1145  // No size check - was dimensioned above
1146  // checkReceivedSize(proci, map.size(), subField.size());
1147 
1148  flipAndCombine
1149  (
1150  field,
1151  subField,
1152  map,
1153  constructHasFlip,
1154  cop,
1155  negOp
1156  );
1157  }
1158  }
1159 
1160  // Wait for any remaining requests
1161  UPstream::waitRequests(startOfRequests);
1162  }
1163 }
1164 
1165 
1166 template<class T, class NegateOp>
1168 (
1169  const UPstream::commsTypes commsType,
1170  const UList<labelPair>& schedule,
1171  const label constructSize,
1172  const labelListList& subMap,
1173  const bool subHasFlip,
1174  const labelListList& constructMap,
1175  const bool constructHasFlip,
1176  List<T>& field,
1177  const NegateOp& negOp,
1178  const int tag,
1179  const label comm
1180 )
1181 {
1182  const auto myRank = UPstream::myProcNo(comm);
1183  [[maybe_unused]]
1184  const auto nProcs = UPstream::nProcs(comm);
1185 
1186  if (!UPstream::parRun())
1187  {
1188  // Do only me to me.
1189 
1190  List<T> subField
1191  (
1192  accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
1193  );
1194 
1195  // Receive sub field from myself (subField)
1196  const labelList& map = constructMap[myRank];
1197 
1198  // Combining bits - can now reuse field storage
1199  field.resize_nocopy(constructSize);
1200 
1201  flipAndCombine
1202  (
1203  field,
1204  subField,
1205  map,
1206  constructHasFlip,
1207  eqOp<T>(),
1208  negOp
1209  );
1210 
1211  return;
1212  }
1213 
1214  if (commsType == UPstream::commsTypes::buffered)
1215  {
1216  // Since buffered sending can reuse the field to collect the
1217  // received data.
1218 
1219  // Send sub field to neighbour
1220  for (const int proci : UPstream::allProcs(comm))
1221  {
1222  const labelList& map = subMap[proci];
1223 
1224  if (proci != myRank && map.size())
1225  {
1226  List<T> subField
1227  (
1228  accessAndFlip(field, map, subHasFlip, negOp)
1229  );
1230 
1231  // buffered send
1232  OPstream os(commsType, proci, 0, tag, comm);
1233  os << subField;
1234  }
1235  }
1236 
1237  {
1238  // Subset myself
1239  List<T> subField
1240  (
1241  accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
1242  );
1243 
1244  // Receive sub field from myself (subField)
1245  const labelList& map = constructMap[myRank];
1246 
1247  // Combining bits - can now reuse field storage
1248  field.resize_nocopy(constructSize);
1249 
1250  flipAndCombine
1251  (
1252  field,
1253  subField,
1254  map,
1255  constructHasFlip,
1256  eqOp<T>(),
1257  negOp
1258  );
1259  }
1260 
1261  // Receive and process sub-field from neighbours
1262  for (const int proci : UPstream::allProcs(comm))
1263  {
1264  const labelList& map = constructMap[proci];
1265 
1266  if (proci != myRank && map.size())
1267  {
1268  List<T> subField;
1269  IPstream::recv(subField, proci, tag, comm);
1270 
1271  checkReceivedSize(proci, map.size(), subField.size());
1272 
1273  flipAndCombine
1274  (
1275  field,
1276  subField,
1277  map,
1278  constructHasFlip,
1279  eqOp<T>(),
1280  negOp
1281  );
1282  }
1283  }
1284  }
1285  else if (commsType == UPstream::commsTypes::scheduled)
1286  {
1287  // Need to make sure I don't overwrite field with received data
1288  // since the data might need to be sent to another processor. So
1289  // allocate a new field for the results.
1290  List<T> newField;
1291  newField.resize_nocopy(constructSize);
1292 
1293  // First handle self
1294  {
1295  // Subset myself
1296  List<T> subField
1297  (
1298  accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
1299  );
1300 
1301  // Receive sub field from myself (subField)
1302  const labelList& map = constructMap[myRank];
1303 
1304  flipAndCombine
1305  (
1306  newField,
1307  subField,
1308  map,
1309  constructHasFlip,
1310  eqOp<T>(),
1311  negOp
1312  );
1313  }
1314 
1315  // Schedule will already have pruned 0-sized comms
1316  for (const labelPair& twoProcs : schedule)
1317  {
1318  // twoProcs is a swap pair of processors. The first one is the
1319  // one that needs to send first and then receive.
1320 
1321  if (twoProcs.first() == myRank)
1322  {
1323  // I am send first, receive next
1324  const label nbrProc = twoProcs.second();
1325 
1326  {
1327  const labelList& map = subMap[nbrProc];
1328  List<T> subField
1329  (
1330  accessAndFlip(field, map, subHasFlip, negOp)
1331  );
1332 
1333  OPstream::send(subField, nbrProc, tag, comm);
1334  }
1335  {
1336  List<T> subField;
1337  IPstream::recv(subField, nbrProc, tag, comm);
1338 
1339  const labelList& map = constructMap[nbrProc];
1340 
1341  checkReceivedSize(nbrProc, map.size(), subField.size());
1342 
1343  flipAndCombine
1344  (
1345  newField,
1346  subField,
1347  map,
1348  constructHasFlip,
1349  eqOp<T>(),
1350  negOp
1351  );
1352  }
1353  }
1354  else
1355  {
1356  // I am receive first, send next
1357  const label nbrProc = twoProcs.first();
1358 
1359  {
1360  List<T> subField;
1361  IPstream::recv(subField, nbrProc, tag, comm);
1362 
1363  const labelList& map = constructMap[nbrProc];
1364 
1365  checkReceivedSize(nbrProc, map.size(), subField.size());
1366 
1367  flipAndCombine
1368  (
1369  newField,
1370  subField,
1371  map,
1372  constructHasFlip,
1373  eqOp<T>(),
1374  negOp
1375  );
1376  }
1377  {
1378  const labelList& map = subMap[nbrProc];
1379  List<T> subField
1380  (
1381  accessAndFlip(field, map, subHasFlip, negOp)
1382  );
1383 
1384  OPstream::send(subField, nbrProc, tag, comm);
1385  }
1386  }
1387  }
1388  field.transfer(newField);
1389  }
1390  else if (commsType == UPstream::commsTypes::nonBlocking)
1391  {
1392  const label startOfRequests = UPstream::nRequests();
1393 
1394  if constexpr (!is_contiguous_v<T>)
1395  {
1396  PstreamBuffers pBufs(comm, tag);
1397 
1398  // Stream data into buffer
1399  for (const int proci : UPstream::allProcs(comm))
1400  {
1401  const labelList& map = subMap[proci];
1402 
1403  if (proci != myRank && map.size())
1404  {
1405  List<T> subField
1406  (
1407  accessAndFlip(field, map, subHasFlip, negOp)
1408  );
1409 
1410  UOPstream os(proci, pBufs);
1411  os << subField;
1412  }
1413  }
1414 
1415  // Initiate receiving - do yet not block
1416  pBufs.finishedSends(false);
1417 
1418  {
1419  // Set up 'send' to myself
1420  List<T> subField
1421  (
1422  accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
1423  );
1424 
1425  // Combining bits - can now reuse field storage
1426  field.resize_nocopy(constructSize);
1427 
1428  // Receive sub field from myself
1429  const labelList& map = constructMap[myRank];
1430 
1431  flipAndCombine
1432  (
1433  field,
1434  subField,
1435  map,
1436  constructHasFlip,
1437  eqOp<T>(),
1438  negOp
1439  );
1440  }
1441 
1442  // Wait for receive requests (and the send requests too)
1443  UPstream::waitRequests(startOfRequests);
1444 
1445  // Receive and process neighbour fields
1446  for (const int proci : UPstream::allProcs(comm))
1447  {
1448  const labelList& map = constructMap[proci];
1449 
1450  if (proci != myRank && map.size())
1451  {
1452  UIPstream is(proci, pBufs);
1453  List<T> subField(is);
1454 
1455  checkReceivedSize(proci, map.size(), subField.size());
1456 
1457  flipAndCombine
1458  (
1459  field,
1460  subField,
1461  map,
1462  constructHasFlip,
1463  eqOp<T>(),
1464  negOp
1465  );
1466  }
1467  }
1468  }
1469  else
1470  {
1471  // Set up receives from neighbours
1472 
1473  List<List<T>> recvFields(nProcs);
1474  DynamicList<int> recvProcs(nProcs);
1475 
1476  for (const int proci : UPstream::allProcs(comm))
1477  {
1478  const labelList& map = constructMap[proci];
1479 
1480  if (proci != myRank && map.size())
1481  {
1482  recvProcs.push_back(proci);
1483  List<T>& subField = recvFields[proci];
1484  subField.resize_nocopy(map.size());
1485 
1487  (
1489  proci,
1490  subField,
1491  tag,
1492  comm
1493  );
1494  }
1495  }
1496 
1497 
1498  // Set up sends to neighbours
1499 
1500  List<List<T>> sendFields(nProcs);
1501 
1502  for (const int proci : UPstream::allProcs(comm))
1503  {
1504  const labelList& map = subMap[proci];
1505 
1506  if (proci != myRank && map.size())
1507  {
1508  List<T>& subField = sendFields[proci];
1509  subField.resize_nocopy(map.size());
1510 
1511  accessAndFlip(subField, field, map, subHasFlip, negOp);
1512 
1514  (
1516  proci,
1517  subField,
1518  tag,
1519  comm
1520  );
1521  }
1522  }
1523 
1524  // Set up 'send' to myself - copy directly into recvFields
1525  {
1526  const labelList& map = subMap[myRank];
1527  List<T>& subField = recvFields[myRank];
1528  subField.resize_nocopy(map.size());
1529 
1530  accessAndFlip(subField, field, map, subHasFlip, negOp);
1531  }
1532 
1533 
1534  // Combining bits - can now reuse field storage
1535  field.resize_nocopy(constructSize);
1536 
1537 
1538  // Receive sub field from myself : recvFields[myRank]
1539  {
1540  const labelList& map = constructMap[myRank];
1541  const List<T>& subField = recvFields[myRank];
1542 
1543  // Probably don't need a size check
1544  // checkReceivedSize(myRank, map.size(), subField.size());
1545 
1546  flipAndCombine
1547  (
1548  field,
1549  subField,
1550  map,
1551  constructHasFlip,
1552  eqOp<T>(),
1553  negOp
1554  );
1555  }
1556 
1557 
1558  // Poll for completed receive requests and dispatch
1559  DynamicList<int> indices(recvProcs.size());
1560  while
1561  (
1563  (
1564  startOfRequests,
1565  recvProcs.size(),
1566  &indices
1567  )
1568  )
1569  {
1570  for (const int idx : indices)
1571  {
1572  const int proci = recvProcs[idx];
1573  const labelList& map = constructMap[proci];
1574  const List<T>& subField = recvFields[proci];
1575 
1576  // No size check - was dimensioned above
1577  // checkReceivedSize(proci, map.size(), subField.size());
1578 
1579  flipAndCombine
1580  (
1581  field,
1582  subField,
1583  map,
1584  constructHasFlip,
1585  eqOp<T>(),
1586  negOp
1587  );
1588  }
1589  }
1590 
1591  // Wait for any remaining requests
1592  UPstream::waitRequests(startOfRequests);
1593  }
1594  }
1595  else
1596  {
1598  << "Unknown communication schedule " << int(commsType)
1600  }
1601 }
1602 
1603 
1604 template<class T>
1606 (
1607  PstreamBuffers& pBufs,
1608  const UList<T>& field
1609 ) const
1610 {
1611  // Stream data into buffer
1612  for (const int proci : UPstream::allProcs(comm_))
1613  {
1614  const labelList& map = subMap_[proci];
1615 
1616  if (map.size())
1617  {
1618  List<T> subField
1619  (
1620  accessAndFlip(field, map, subHasFlip_, flipOp())
1621  );
1622 
1623  UOPstream os(proci, pBufs);
1624  os << subField;
1625  }
1626  }
1627 
1628  // Start sending and receiving but do not block.
1629  pBufs.finishedSends(false);
1630 }
1631 
1632 
1633 template<class T>
1635 (
1636  PstreamBuffers& pBufs,
1637  List<T>& field
1638 ) const
1639 {
1640  // Consume
1641  field.resize_nocopy(constructSize_);
1642 
1643  for (const int proci : UPstream::allProcs(comm_))
1644  {
1645  const labelList& map = constructMap_[proci];
1646 
1647  if (map.size())
1648  {
1649  UIPstream is(proci, pBufs);
1650  List<T> subField(is);
1651 
1652  checkReceivedSize(proci, map.size(), subField.size());
1653 
1654  flipAndCombine
1655  (
1656  field,
1657  subField,
1658  map,
1659  constructHasFlip_,
1660  eqOp<T>(),
1661  flipOp()
1662  );
1663  }
1664  }
1665 }
1666 
1667 
1668 template<class T, class NegateOp>
1670 (
1671  const UPstream::commsTypes commsType,
1672  List<T>& values,
1673  const NegateOp& negOp,
1674  const int tag
1675 ) const
1676 {
1677  distribute
1678  (
1679  commsType,
1680  whichSchedule(commsType),
1681  constructSize_,
1682  subMap_,
1683  subHasFlip_,
1684  constructMap_,
1685  constructHasFlip_,
1686  values,
1687  negOp,
1688  tag,
1689  comm_
1690  );
1691 }
1692 
1693 
1694 template<class T, class NegateOp>
1696 (
1697  const UPstream::commsTypes commsType,
1698  const T& nullValue,
1699  List<T>& values,
1700  const NegateOp& negOp,
1701  const int tag
1702 ) const
1703 {
1704  distribute
1705  (
1706  commsType,
1707  whichSchedule(commsType),
1708  constructSize_,
1709  subMap_,
1710  subHasFlip_,
1711  constructMap_,
1712  constructHasFlip_,
1713  values,
1714  nullValue,
1715  eqOp<T>(),
1716  negOp,
1717  tag,
1718  comm_
1719  );
1720 }
1721 
1722 
1723 template<class T, class NegateOp>
1725 (
1726  List<T>& values,
1727  const NegateOp& negOp,
1728  const int tag
1729 ) const
1730 {
1731  distribute
1732  (
1734  );
1735 }
1736 
1737 
1738 template<class T>
1740 (
1741  const UPstream::commsTypes commsType,
1742  List<T>& values,
1743  const int tag
1744 ) const
1746  distribute(commsType, values, flipOp(), tag);
1747 }
1748 
1749 
1750 template<class T>
1752 (
1753  const UPstream::commsTypes commsType,
1755  const int tag
1756 ) const
1757 {
1758  List<T> work(std::move(values));
1759 
1760  distribute(commsType, work, tag);
1762  values = std::move(work);
1763 }
1764 
1765 
1766 template<class T>
1768 (
1769  List<T>& values,
1770  const int tag
1771 ) const
1773  distribute(UPstream::defaultCommsType, values, tag);
1774 }
1775 
1776 
1777 template<class T>
1779 (
1781  const int tag
1782 ) const
1784  distribute(UPstream::defaultCommsType, values, tag);
1785 }
1786 
1787 
1788 template<class T>
1790 (
1791  const UPstream::commsTypes commsType,
1792  const label constructSize,
1793  List<T>& values,
1794  const int tag
1795 ) const
1796 {
1797  reverseDistribute<T, flipOp>
1798  (
1799  commsType,
1800  constructSize,
1801  values,
1802  flipOp(),
1803  tag
1804  );
1805 }
1806 
1807 
1808 template<class T, class NegateOp>
1810 (
1811  const UPstream::commsTypes commsType,
1812  const label constructSize,
1813  List<T>& values,
1814  const NegateOp& negOp,
1815  const int tag
1816 ) const
1817 {
1818  distribute
1819  (
1820  commsType,
1821  whichSchedule(commsType),
1822  constructSize,
1823  constructMap_,
1824  constructHasFlip_,
1825  subMap_,
1826  subHasFlip_,
1827  values,
1828  negOp,
1829  tag,
1830  comm_
1831  );
1832 }
1833 
1834 
1835 template<class T>
1837 (
1838  const UPstream::commsTypes commsType,
1839  const label constructSize,
1840  const T& nullValue,
1841  List<T>& values,
1842  const int tag
1843 ) const
1844 {
1845  distribute
1846  (
1847  commsType,
1848  whichSchedule(commsType),
1849  constructSize,
1850  constructMap_,
1851  constructHasFlip_,
1852  subMap_,
1853  subHasFlip_,
1854  values,
1855 
1856  nullValue,
1857  eqOp<T>(),
1858  flipOp(),
1859 
1860  tag,
1861  comm_
1862  );
1863 }
1864 
1865 
1866 template<class T>
1868 (
1869  const label constructSize,
1870  List<T>& values,
1871  const int tag
1872 ) const
1873 {
1874  reverseDistribute
1875  (
1877  constructSize,
1878  values,
1879  tag
1880  );
1881 }
1882 
1883 
1884 template<class T>
1886 (
1887  const label constructSize,
1888  const T& nullValue,
1889  List<T>& values,
1890  const int tag
1891 ) const
1892 {
1893  reverseDistribute
1894  (
1896  constructSize,
1897  nullValue,
1898  values,
1899  tag
1900  );
1901 }
1902 
1903 
1904 // ************************************************************************* //
void send(PstreamBuffers &pBufs, const UList< T > &field) const
Do all sends using PstreamBuffers.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:119
Definition: ops.H:65
rDeltaTY field()
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
commsTypes
Communications types.
Definition: UPstream.H:81
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:652
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
static label nRequests() noexcept
Number of outstanding requests (on the internal list of requests)
A range or interval of labels defined by a start and a size.
Definition: labelRange.H:63
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
static bool waitSomeRequests(label pos, label len=-1, DynamicList< int > *indices=nullptr)
Wait until some requests (from position onwards) have finished. Corresponds to MPI_Waitsome() ...
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1774
static int myProcNo(label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition: UPstream.H:1799
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:171
static std::streamsize read(const UPstream::commsTypes commsType, const int fromProcNo, Type *buffer, std::streamsize count, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, UPstream::Request *req=nullptr)
Receive buffer contents (contiguous types) from given processor.
void push_back(const T &val)
Append an element at the end of the list.
Definition: ListI.H:221
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
static void waitRequests()
Wait for all requests to finish.
Definition: UPstream.H:2619
UList< label > labelUList
A UList of labels.
Definition: UList.H:76
static rangeType allProcs(label communicator=worldComm)
Range of process indices for all processes.
Definition: UPstream.H:1950
void rhs(fvMatrix< typename Expr::value_type > &m, const Expr &expression)
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:164
Input inter-processor communications stream using MPI send/recv etc. - operating on external buffer...
Definition: UIPstream.H:365
static void accessAndFlip(UList< T > &output, const UList< T > &values, const labelUList &map, const bool hasFlip, const NegateOp &negOp)
Lookup field values at specified map indices and save after any flip negation operations.
"scheduled" (MPI standard) : (MPI_Send, MPI_Recv)
static void recv(Type &value, const int fromProcNo, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, IOstreamOption::streamFormat fmt=IOstreamOption::BINARY)
Receive and deserialize a value. Uses operator>> for de-serialization.
Definition: IPstream.H:115
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:51
void finishedSends(const bool wait=true)
Mark the send phase as being finished.
void reverseDistribute(const label constructSize, List< T > &values, const int tag=UPstream::msgType()) const
Reverse distribute data using default commsType and the default flip/negate operator.
static void flipAndCombine(UList< T > &lhs, const UList< T > &rhs, const labelUList &map, const bool hasFlip, const CombineOp &cop, const NegateOp &negOp)
Combine field values (after any flip negation operation) into the specified mapped target locations...
static bool write(const UPstream::commsTypes commsType, const int toProcNo, const Type *buffer, std::streamsize count, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, UPstream::Request *req=nullptr, const UPstream::sendModes sendMode=UPstream::sendModes::normal)
Write buffer contents (contiguous types only) to given processor.
A list of pointers to objects of type <T>, without allocation/deallocation management of the pointers...
Definition: HashTable.H:106
errorManip< error > abort(error &err)
Definition: errorManip.H:139
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
Buffers for inter-processor communications streams (UOPstream, UIPstream).
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
void receive(PstreamBuffers &pBufs, List< T > &field) const
Do all receives using PstreamBuffers.
static commsTypes defaultCommsType
Default commsType.
Definition: UPstream.H:1070
static label nProcs(label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1790
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Definition: PtrList.H:56
constexpr IntType size() const noexcept
The size of the range.
Definition: IntRange.H:208
constexpr IntType start() const noexcept
The (inclusive) lower value of the range.
Definition: IntRange.H:218
"nonBlocking" (immediate) : (MPI_Isend, MPI_Irecv)
List< label > labelList
A List of labels.
Definition: List.H:61
"buffered" : (MPI_Bsend, MPI_Recv)
bool send()
Send buffer contents now and not in destructor [advanced usage]. Returns true on success.
Definition: OPstreams.C:96
Negation for scalar/vectorspace/etc, otherwise pass through.
Definition: flipOp.H:62
static void distribute(const UPstream::commsTypes commsType, const UList< labelPair > &schedule, const label constructSize, const labelListList &subMap, const bool subHasFlip, const labelListList &constructMap, const bool constructHasFlip, List< T > &field, const T &nullValue, const CombineOp &cop, const NegateOp &negOp, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Distribute combine data with specified combine operation and negate operator (for flips)...