globalIndexTemplates.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) 2013-2017 OpenFOAM Foundation
9  Copyright (C) 2019-2024 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 "globalIndex.H"
30 
31 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
32 
33 // Cannot use non-blocking for non-contiguous data.
34 // template<class Type>
35 // inline Foam::UPstream::commsTypes getCommsType
36 // (
37 // const UPstream::commsTypes preferred
38 // )
39 // {
40 // return
41 // (
42 // (
43 // !is_contiguous<Type>::value
44 // && UPstream::commsTypes::nonBlocking == preferred
45 // )
46 // ? UPstream::commsTypes::scheduled
47 // : preferred
48 // );
49 // }
50 
51 
52 template<class Addr>
55 (
56  const IndirectListBase<label, Addr>& counts,
57  const bool checkOverflow
58 )
59 {
61 
62  const label len = counts.size();
63 
64  if (len)
65  {
66  values.resize(len+1);
67 
68  label start = 0;
69  for (label i = 0; i < len; ++i)
70  {
71  const label count = counts[i];
72 
73  values[i] = start;
74  start += count;
75 
76  if (checkOverflow && start < values[i])
77  {
78  reportOverflowAndExit(i, values[i], count);
79  }
80  }
81  values[len] = start;
82  }
83 
84  return values;
85 }
86 
87 
88 template<class SubListType>
91 (
92  const List<SubListType>& lists,
93  const bool checkOverflow
94 )
95 {
97 
98  const label len = lists.size();
99 
100  if (len)
101  {
102  values.resize(len+1);
103 
104  label start = 0;
105  for (label i = 0; i < len; ++i)
106  {
107  const label count = lists[i].size();
108 
109  values[i] = start;
110  start += count;
111 
112  if (checkOverflow && start < values[i])
113  {
114  reportOverflowAndExit(i, values[i], count);
115  }
116  }
117  values[len] = start;
118  }
120  return values;
121 }
122 
123 
124 template<class ProcIDsContainer, class Type>
126 (
127  const label comm,
128  const ProcIDsContainer& procIDs,
129  const Type& localValue,
130  List<Type>& allValues,
131  const int tag,
132  const UPstream::commsTypes preferredCommsType
133 )
134 {
135  // low-level: no parRun guard
136 
137  // Cannot use non-blocking for non-contiguous data.
138  const UPstream::commsTypes commsType =
139  (
140  (
142  && UPstream::commsTypes::nonBlocking == preferredCommsType
143  )
145  : preferredCommsType
146  );
147 
148  const label startOfRequests = UPstream::nRequests();
149 
150  const int masterProci = procIDs.size() ? procIDs[0] : 0;
151 
152  if (UPstream::myProcNo(comm) == masterProci)
153  {
154  allValues.resize_nocopy(procIDs.size());
155  allValues[0] = localValue;
156 
157  for (label i = 1; i < procIDs.size(); ++i)
158  {
160  {
162  (
163  commsType,
164  procIDs[i],
165  reinterpret_cast<char*>(&allValues[i]),
166  sizeof(Type),
167  tag,
168  comm
169  );
170  }
171  else
172  {
173  IPstream::recv(allValues[i], procIDs[i], tag, comm);
174  }
175  }
176  }
177  else
178  {
179  allValues.clear(); // safety: zero-size on non-master
180 
181  if (is_contiguous<Type>::value)
182  {
184  (
185  commsType,
186  masterProci,
187  reinterpret_cast<const char*>(&localValue),
188  sizeof(Type),
189  tag,
190  comm
191  );
192  }
193  else
194  {
195  OPstream::send(localValue, commsType, masterProci, tag, comm);
196  }
197  }
198 
199  if (commsType == UPstream::commsTypes::nonBlocking)
200  {
201  // Wait for outstanding requests
202  UPstream::waitRequests(startOfRequests);
203  }
204 }
205 
206 
207 template<class ProcIDsContainer, class Type>
209 (
210  const labelUList& off, // needed on master only
211  const label comm,
212  const ProcIDsContainer& procIDs,
213  const UList<Type>& fld,
214  List<Type>& allFld,
215  const int tag,
216  const UPstream::commsTypes preferredCommsType
217 )
218 {
219  // low-level: no parRun guard
220 
221  // Cannot use non-blocking for non-contiguous data.
222  const UPstream::commsTypes commsType =
223  (
224  (
225  !is_contiguous<Type>::value
226  && UPstream::commsTypes::nonBlocking == preferredCommsType
227  )
229  : preferredCommsType
230  );
231 
232  const label startOfRequests = UPstream::nRequests();
233 
234  const int masterProci = procIDs.size() ? procIDs[0] : 0;
235 
236  if (UPstream::myProcNo(comm) == masterProci)
237  {
238  allFld.resize_nocopy(off.back()); // == totalSize()
239 
240  // Assign my local data - respect offset information
241  // so that we can request 0 entries to be copied.
242  // Also handle the case where we have a slice of the full
243  // list.
244 
245  SubList<Type>(allFld, off[1]-off[0], off[0]) =
246  SubList<Type>(fld, off[1]-off[0]);
247 
248  for (label i = 1; i < procIDs.size(); ++i)
249  {
250  SubList<Type> procSlot(allFld, off[i+1]-off[i], off[i]);
251 
252  if (procSlot.empty())
253  {
254  // Nothing to do
255  }
256  else if (is_contiguous<Type>::value)
257  {
259  (
260  commsType,
261  procIDs[i],
262  procSlot.data_bytes(),
263  procSlot.size_bytes(),
264  tag,
265  comm
266  );
267  }
268  else
269  {
270  IPstream::recv(procSlot, procIDs[i], tag, comm);
271  }
272  }
273  }
274  else
275  {
276  if (fld.empty())
277  {
278  // Nothing to do
279  }
280  else if (is_contiguous<Type>::value)
281  {
283  (
284  commsType,
285  masterProci,
286  fld.cdata_bytes(),
287  fld.size_bytes(),
288  tag,
289  comm
290  );
291  }
292  else
293  {
294  OPstream::send(fld, commsType, masterProci, tag, comm);
295  }
296  }
297 
298  if (commsType == UPstream::commsTypes::nonBlocking)
299  {
300  // Wait for outstanding requests
301  UPstream::waitRequests(startOfRequests);
302  }
303 }
304 
305 
306 template<class ProcIDsContainer, class Type, class Addr>
308 (
309  const labelUList& off, // needed on master only
310  const label comm,
311  const ProcIDsContainer& procIDs,
312  const IndirectListBase<Type, Addr>& fld,
313  List<Type>& allFld,
314  const int tag,
315  const UPstream::commsTypes preferredCommsType
316 )
317 {
318  // low-level: no parRun guard
319 
320  if (is_contiguous<Type>::value)
321  {
322  // Flatten list (locally) so that we can benefit from using direct
323  // read/write of contiguous data
324 
325  gather
326  (
327  off,
328  comm,
329  procIDs,
330  List<Type>(fld),
331  allFld,
332  tag,
333  preferredCommsType
334  );
335  return;
336  }
337 
338  // Cannot use non-blocking for non-contiguous data.
339  const UPstream::commsTypes commsType =
340  (
341  (
342  !is_contiguous<Type>::value
343  && UPstream::commsTypes::nonBlocking == preferredCommsType
344  )
346  : preferredCommsType
347  );
348 
349  const label startOfRequests = UPstream::nRequests();
350 
351  const int masterProci = procIDs.size() ? procIDs[0] : 0;
352 
353  if (UPstream::myProcNo(comm) == masterProci)
354  {
355  allFld.resize_nocopy(off.back()); // == totalSize()
356 
357  // Assign my local data - respect offset information
358  // so that we can request 0 entries to be copied
359 
360  SubList<Type> localSlot(allFld, off[1]-off[0], off[0]);
361  if (!localSlot.empty())
362  {
363  localSlot = fld;
364  }
365 
366  // Already verified commsType != nonBlocking
367  for (label i = 1; i < procIDs.size(); ++i)
368  {
369  SubList<Type> procSlot(allFld, off[i+1]-off[i], off[i]);
370 
371  if (procSlot.empty())
372  {
373  // Nothing to do
374  }
375  else
376  {
377  IPstream::recv(procSlot, procIDs[i], tag, comm);
378  }
379  }
380  }
381  else
382  {
383  if (fld.empty())
384  {
385  // Nothing to do
386  }
387  else
388  {
389  OPstream::send(fld, commsType, masterProci, tag, comm);
390  }
391  }
392 
393  if (commsType == UPstream::commsTypes::nonBlocking)
394  {
395  // Wait for outstanding requests
396  UPstream::waitRequests(startOfRequests);
397  }
398 }
399 
400 
401 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
402 
403 template<class Type>
405 (
406  const UList<Type>& sendData,
407  List<Type>& allData,
408  const int tag,
409  const UPstream::commsTypes commsType,
410  const label comm
411 ) const
412 {
413  if (!UPstream::parRun())
414  {
415  // Serial: direct copy
416  allData = sendData;
417  return;
418  }
419 
420  {
422  (
423  offsets_, // needed on master only
424  comm,
425  UPstream::allProcs(comm), // All communicator ranks
426  sendData,
427  allData,
428  tag,
429  commsType
430  );
431  if (!UPstream::master(comm))
432  {
433  allData.clear(); // safety: zero-size on non-master
434  }
435  }
436 }
437 
438 
439 template<class Type, class Addr>
441 (
442  const IndirectListBase<Type, Addr>& sendData,
443  List<Type>& allData,
444  const int tag,
445  const UPstream::commsTypes commsType,
446  const label comm
447 ) const
448 {
449  if (!UPstream::parRun())
450  {
451  // Serial: direct copy
452  allData = sendData;
453  return;
454  }
455 
456  {
458  (
459  offsets_, // needed on master only
460  comm,
461  UPstream::allProcs(comm), // All communicator ranks
462  sendData,
463  allData,
464  tag,
465  commsType
466  );
467  if (!UPstream::master(comm))
468  {
469  allData.clear(); // safety: zero-size on non-master
470  }
471  }
472 }
473 
474 
475 template<class Type, class OutputContainer>
476 OutputContainer Foam::globalIndex::gather
477 (
478  const UList<Type>& sendData,
479  const int tag,
480  const UPstream::commsTypes commsType,
481  const label comm
482 ) const
483 {
484  OutputContainer allData;
485  gather(sendData, allData, tag, commsType, comm);
486  return allData;
487 }
488 
489 
490 template<class Type, class Addr, class OutputContainer>
491 OutputContainer Foam::globalIndex::gather
492 (
493  const IndirectListBase<Type, Addr>& sendData,
494  const int tag,
495  const UPstream::commsTypes commsType,
496  const label comm
497 ) const
498 {
499  OutputContainer allData;
500  gather(sendData, allData, tag, commsType, comm);
501  return allData;
502 }
503 
504 
505 template<class Type>
507 (
508  List<Type>& fld,
509  const int tag,
510  const UPstream::commsTypes commsType,
511  const label comm
512 ) const
513 {
514  if (UPstream::parRun())
515  {
516  List<Type> allData;
517  gather(fld, allData, tag, commsType, comm);
518 
519  if (UPstream::master(comm))
520  {
521  fld.transfer(allData);
522  }
523  else
524  {
525  fld.clear(); // zero-size on non-master
526  }
527  }
528  // Serial: (no-op)
529 }
530 
531 
532 template<class Type, class OutputContainer>
534 (
535  const UList<Type>& sendData,
536  OutputContainer& allData,
537  const label comm,
538 
539  const UPstream::commsTypes commsType,
540  const int tag
541 ) const
542 {
543  if (!UPstream::parRun())
544  {
545  // Serial: direct copy
546  allData = sendData;
547  return;
548  }
549 
550  // MPI_Gatherv requires contiguous data, but a byte-wise transfer can
551  // quickly exceed the 'int' limits used for MPI sizes/offsets.
552  // Thus gather label/scalar components when possible to increase the
553  // effective size limit.
554  //
555  // Note: cannot rely on pTraits (cmptType, nComponents) since this method
556  // needs to compile (and work) even with things like strings etc.
557 
558  // Single char ad hoc "enum":
559  // - b(yte): gather bytes
560  // - f(loat): gather scalars components
561  // - i(nt): gather label components
562  // - 0: gather with Pstream read/write etc.
563 
564  List<int> recvCounts;
565  List<int> recvOffsets;
566 
567  char dataMode(0);
568  int nCmpts(0);
569 
570  if (is_contiguous<Type>::value)
571  {
572  if (is_contiguous_scalar<Type>::value)
573  {
574  dataMode = 'f';
575  nCmpts = static_cast<int>(sizeof(Type)/sizeof(scalar));
576  }
577  else if (is_contiguous_label<Type>::value)
578  {
579  dataMode = 'i';
580  nCmpts = static_cast<int>(sizeof(Type)/sizeof(label));
581  }
582  else
583  {
584  dataMode = 'b';
585  nCmpts = static_cast<int>(sizeof(Type));
586  }
587 
588  // Offsets must fit into int
589  if (UPstream::master(comm))
590  {
591  const globalIndex& globalAddr = *this;
592 
593  if (globalAddr.totalSize() > (INT_MAX/nCmpts))
594  {
595  // Offsets do not fit into int - revert to manual.
596  dataMode = 0;
597  }
598  else
599  {
600  // Must be same as Pstream::nProcs(comm), at least on master!
601  const label nproc = globalAddr.nProcs();
602 
603  allData.resize_nocopy(globalAddr.totalSize());
604 
605  recvCounts.resize(nproc);
606  recvOffsets.resize(nproc+1);
607 
608  for (label proci = 0; proci < nproc; ++proci)
609  {
610  recvCounts[proci] = globalAddr.localSize(proci)*nCmpts;
611  recvOffsets[proci] = globalAddr.localStart(proci)*nCmpts;
612  }
613  recvOffsets[nproc] = globalAddr.totalSize()*nCmpts;
614 
615  // Assign local data directly
616 
617  recvCounts[0] = 0; // ie, ignore for MPI_Gatherv
618  SubList<Type>(allData, globalAddr.range(0)) =
619  SubList<Type>(sendData, globalAddr.range(0));
620  }
621  }
622 
623  // Consistent information for everyone
624  UPstream::broadcast(&dataMode, 1, comm);
625  }
626 
627  // Dispatch
628  switch (dataMode)
629  {
630  case 'b': // Byte-wise
631  {
633  (
634  sendData.cdata_bytes(),
635  sendData.size_bytes(),
636  allData.data_bytes(),
637  recvCounts,
638  recvOffsets,
639  comm
640  );
641  break;
642  }
643  case 'f': // Float (scalar) components
644  {
645  typedef scalar cmptType;
646 
648  (
649  reinterpret_cast<const cmptType*>(sendData.cdata()),
650  (sendData.size()*nCmpts),
651  reinterpret_cast<cmptType*>(allData.data()),
652  recvCounts,
653  recvOffsets,
654  comm
655  );
656  break;
657  }
658  case 'i': // Int (label) components
659  {
660  typedef label cmptType;
661 
663  (
664  reinterpret_cast<const cmptType*>(sendData.cdata()),
665  (sendData.size()*nCmpts),
666  reinterpret_cast<cmptType*>(allData.data()),
667  recvCounts,
668  recvOffsets,
669  comm
670  );
671  break;
672  }
673  default: // Regular (manual) gathering
674  {
676  (
677  offsets_, // needed on master only
678  comm,
679  UPstream::allProcs(comm), // All communicator ranks
680  sendData,
681  allData,
682  tag,
683  commsType
684  );
685  break;
686  }
687  }
688 
689  if (!UPstream::master(comm))
690  {
691  allData.clear(); // safety: zero-size on non-master
692  }
693 }
694 
695 
696 template<class Type, class OutputContainer>
697 OutputContainer Foam::globalIndex::mpiGather
698 (
699  const UList<Type>& sendData,
700  const label comm,
701 
702  const UPstream::commsTypes commsType,
703  const int tag
704 ) const
705 {
706  OutputContainer allData;
707  mpiGather(sendData, allData, comm, commsType, tag);
708  return allData;
709 }
710 
711 
712 template<class Type>
714 (
715  List<Type>& fld,
716  const label comm,
717 
718  const UPstream::commsTypes commsType,
719  const int tag
720 ) const
721 {
722  if (UPstream::parRun())
723  {
724  List<Type> allData;
725  mpiGather(fld, allData, comm, commsType, tag);
726 
727  if (UPstream::master(comm))
728  {
729  fld.transfer(allData);
730  }
731  else
732  {
733  fld.clear(); // zero-size on non-master
734  }
735  }
736  // Serial: (no-op)
737 }
738 
739 
740 template<class Type, class OutputContainer>
742 (
743  const UList<Type>& sendData,
744  OutputContainer& allData,
745  const label comm,
746 
747  const UPstream::commsTypes commsType,
748  const int tag
749 )
750 {
751  if (UPstream::parRun())
752  {
753  // Gather sizes - only needed on master
754  globalIndex(globalIndex::gatherOnly{}, sendData.size(), comm)
755  .mpiGather(sendData, allData, comm, commsType, tag);
756  }
757  else
758  {
759  // Serial: direct copy
760  allData = sendData;
761  }
762 }
763 
764 
765 template<class Type, class OutputContainer>
766 OutputContainer Foam::globalIndex::mpiGatherOp
767 (
768  const UList<Type>& sendData,
769  const label comm,
770 
771  const UPstream::commsTypes commsType,
772  const int tag
773 )
774 {
775  OutputContainer allData;
776  mpiGatherOp(sendData, allData, comm, commsType, tag);
777  return allData;
778 }
779 
780 
781 template<class Type>
783 (
784  List<Type>& fld,
785  const label comm,
786 
787  const UPstream::commsTypes commsType,
788  const int tag
789 )
790 {
791  if (UPstream::parRun())
792  {
793  List<Type> allData;
794  mpiGatherOp(fld, allData, comm, commsType, tag);
795 
796  if (UPstream::master(comm))
797  {
798  fld.transfer(allData);
799  }
800  else
801  {
802  fld.clear(); // zero-size on non-master
803  }
804  }
805  // Serial: (no-op)
806 }
807 
808 
809 template<class Type>
811 (
812  const UList<Type>& sendData,
813  List<Type>& allData,
814  const int tag,
815  const UPstream::commsTypes commsType,
816  const label comm
817 )
818 {
819  if (UPstream::parRun())
820  {
821  // Gather sizes - only needed on master
822  globalIndex(globalIndex::gatherOnly{}, sendData.size(), comm)
823  .gather(sendData, allData, tag, commsType, comm);
824  }
825  else
826  {
827  // Serial: direct copy
828  allData = sendData;
829  }
830 }
831 
832 
833 template<class Type, class Addr>
835 (
836  const IndirectListBase<Type, Addr>& sendData,
837  List<Type>& allData,
838  const int tag,
839  const UPstream::commsTypes commsType,
840  const label comm
841 )
842 {
843  if (UPstream::parRun())
844  {
845  // Gather sizes - only needed on master
846  globalIndex(globalIndex::gatherOnly{}, sendData.size(), comm)
847  .gather(sendData, allData, tag, commsType, comm);
848  }
849  else
850  {
851  // Serial: direct copy
852  allData = List<Type>(sendData);
853  }
854 }
855 
856 
857 template<class Type, class OutputContainer>
858 OutputContainer Foam::globalIndex::gatherOp
859 (
860  const UList<Type>& sendData,
861  const int tag,
862  const UPstream::commsTypes commsType,
863  const label comm
864 )
865 {
866  OutputContainer allData;
867  gatherOp(sendData, allData, tag, commsType, comm);
868  return allData;
869 }
870 
871 
872 template<class Type, class Addr, class OutputContainer>
873 OutputContainer Foam::globalIndex::gatherOp
874 (
875  const IndirectListBase<Type, Addr>& sendData,
876  const int tag,
877  const UPstream::commsTypes commsType,
878  const label comm
879 )
880 {
881  OutputContainer allData;
882  gatherOp(sendData, allData, tag, commsType, comm);
883  return allData;
884 }
885 
886 
887 template<class Type>
889 (
890  List<Type>& fld,
891  const int tag,
892  const UPstream::commsTypes commsType,
893  const label comm
894 )
895 {
896  if (UPstream::parRun())
897  {
898  // Gather sizes - only needed on master
899  globalIndex(globalIndex::gatherOnly{}, fld.size(), comm)
900  .gather(fld, tag, commsType, comm);
901  }
902  // Serial: (no-op)
903 }
904 
905 
906 template<class ProcIDsContainer, class Type>
908 (
909  const labelUList& off, // needed on master only
910  const label comm,
911  const ProcIDsContainer& procIDs,
912  const UList<Type>& allFld,
913  UList<Type>& fld,
914  const int tag,
915  const UPstream::commsTypes preferredCommsType
916 )
917 {
918  // low-level: no parRun guard
919 
920  // Cannot use non-blocking for non-contiguous data.
921  const UPstream::commsTypes commsType =
922  (
923  (
924  !is_contiguous<Type>::value
925  && UPstream::commsTypes::nonBlocking == preferredCommsType
926  )
928  : preferredCommsType
929  );
930 
931  const label startOfRequests = UPstream::nRequests();
932 
933  const int masterProci = procIDs.size() ? procIDs[0] : 0;
934 
935  if (UPstream::myProcNo(comm) == masterProci)
936  {
937  for (label i = 1; i < procIDs.size(); ++i)
938  {
939  const SubList<Type> procSlot(allFld, off[i+1]-off[i], off[i]);
940 
941  if (procSlot.empty())
942  {
943  // Nothing to do
944  }
945  else if (is_contiguous<Type>::value)
946  {
948  (
949  commsType,
950  procIDs[i],
951  procSlot.cdata_bytes(),
952  procSlot.size_bytes(),
953  tag,
954  comm
955  );
956  }
957  else
958  {
959  OPstream::send(procSlot, commsType, procIDs[i], tag, comm);
960  }
961  }
962 
963  // Assign my local data - respect offset information
964  // so that we can request 0 entries to be copied.
965  // Also handle the case where we have a slice of the full
966  // list.
967 
968  SubList<Type>(fld, off[1]-off[0]) =
969  SubList<Type>(allFld, off[1]-off[0], off[0]);
970  }
971  else
972  {
973  // Note: we are receiving into UList, so sizes MUST match or we
974  // have a problem. Can therefore reasonably assume that a zero-sized
975  // send matches a zero-sized receive, and we can skip that.
976 
977  if (fld.empty())
978  {
979  // Nothing to do
980  }
981  else if (is_contiguous<Type>::value)
982  {
984  (
985  commsType,
986  masterProci,
987  fld.data_bytes(),
988  fld.size_bytes(),
989  tag,
990  comm
991  );
992  }
993  else
994  {
995  IPstream::recv(fld, masterProci, tag, comm);
996  }
997  }
998 
999  if (commsType == UPstream::commsTypes::nonBlocking)
1000  {
1001  // Wait for outstanding requests
1002  UPstream::waitRequests(startOfRequests);
1003  }
1004 }
1005 
1006 
1007 template<class Type>
1009 (
1010  const UList<Type>& allData,
1011  UList<Type>& localData,
1012  const int tag,
1013  const UPstream::commsTypes commsType,
1014  const label comm
1015 ) const
1016 {
1017  if (UPstream::parRun())
1018  {
1019  scatter
1020  (
1021  offsets_, // needed on master only
1022  comm,
1023  UPstream::allProcs(comm), // All communicator ranks
1024  allData,
1025  localData,
1026  tag,
1027  commsType
1028  );
1029  }
1030  else
1031  {
1032  // Serial: direct copy
1033  // - fails miserably if incorrectly dimensioned!
1034  localData.deepCopy(allData);
1035  }
1036 }
1037 
1038 
1039 template<class Type, class OutputContainer>
1040 OutputContainer Foam::globalIndex::scatter
1041 (
1042  const UList<Type>& allData,
1043  const int tag,
1044  const UPstream::commsTypes commsType,
1045  const label comm
1046 ) const
1047 {
1048  if (UPstream::parRun())
1049  {
1050  // The globalIndex might be correct on master only,
1051  // so scatter local sizes to ensure consistency
1052 
1053  const label count
1054  (
1055  UPstream::listScatterValues<label>(this->localSizes(), comm)
1056  );
1057 
1058  OutputContainer localData(count);
1059  this->scatter(allData, localData, tag, commsType, comm);
1060 
1061  return localData;
1062  }
1063  else
1064  {
1065  // Serial: direct copy
1066  return OutputContainer(allData);
1067  }
1068 }
1069 
1070 
1071 template<class Type, class CombineOp>
1073 (
1074  List<Type>& allFld,
1075  const labelUList& globalIds,
1076  const CombineOp& cop,
1077  const label comm,
1078  const int tag
1079 ) const
1080 {
1081  allFld.resize_nocopy(globalIds.size());
1082 
1083  if (globalIds.size())
1084  {
1085  // Sort according to processor
1086  labelList order;
1087  DynamicList<label> validBins(Pstream::nProcs());
1088 
1089  CompactListList<label> bins
1090  (
1091  bin(offsets(), globalIds, order, validBins)
1092  );
1093 
1094  // Send local indices to individual processors as local index
1095  PstreamBuffers sendBufs(comm, tag);
1096 
1097  for (const auto proci : validBins)
1098  {
1099  labelList localIDs(bins[proci]);
1100 
1101  for (label& val : localIDs)
1102  {
1103  val = toLocal(proci, val);
1104  }
1105 
1106  UOPstream os(proci, sendBufs);
1107  os << localIDs;
1108  }
1109  sendBufs.finishedSends();
1110 
1111 
1112  PstreamBuffers returnBufs(comm, tag);
1113 
1114  for (const int proci : sendBufs.allProcs())
1115  {
1116  if (sendBufs.recvDataCount(proci))
1117  {
1118  UIPstream is(proci, sendBufs);
1119  labelList localIDs(is);
1120 
1121  // Collect entries
1122  List<Type> fld(localIDs.size());
1123  cop(fld, localIDs);
1124 
1125  UOPstream os(proci, returnBufs);
1126  os << fld;
1127  }
1128  }
1129  returnBufs.finishedSends();
1130 
1131  // Slot back
1132  for (const auto proci : validBins)
1133  {
1134  label start = bins.offsets()[proci];
1135  const SubList<label> es
1136  (
1137  order,
1138  bins.offsets()[proci+1]-start, // start
1139  start
1140  );
1141  UIPstream is(proci, returnBufs);
1142  List<Type> fld(is);
1143 
1144  UIndirectList<Type>(allFld, es) = fld;
1145  }
1146  }
1147 }
1148 
1149 
1150 // ************************************************************************* //
static labelList calcOffsets(const labelUList &counts, const bool checkOverflow=false)
Calculate offsets from a list of local sizes, with optional check for label overflow.
Definition: globalIndex.C:189
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
static void mpiGatherOp(const UList< Type > &sendData, OutputContainer &allData, const label comm=UPstream::worldComm, const UPstream::commsTypes=UPstream::commsTypes::nonBlocking, const int tag=UPstream::msgType())
Use MPI_Gatherv call to collect contiguous data when possible (in serial: performs a simple copy)...
commsTypes
Communications types.
Definition: UPstream.H:77
static label nRequests() noexcept
Number of outstanding requests (on the internal list of requests)
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition: UPstream.H:1188
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1061
Dispatch tag: Construct &#39;one-sided&#39; from local sizes, using gather but no broadcast.
Definition: globalIndex.H:118
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:168
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1086
Base for lists with indirect addressing, templated on the list contents type and the addressing type...
static void waitRequests()
Wait for all requests to finish.
Definition: UPstream.H:1561
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
void gather(const Type *sendData, Type *recvData, int count, MPI_Datatype datatype, const label comm, UPstream::Request *req=nullptr, label *requestID=nullptr)
static void mpiGatherInplaceOp(List< Type > &fld, const label comm=UPstream::worldComm, const UPstream::commsTypes=UPstream::commsTypes::nonBlocking, const int tag=UPstream::msgType())
Use MPI_Gatherv call to inplace collect contiguous data when possible. (in serial: a no-op)...
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:164
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:61
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1077
static void recv(Type &value, const int fromProcNo, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm, IOstreamOption::streamFormat fmt=IOstreamOption::BINARY)
Receive and deserialize a value. Uses operator>> for de-serialization.
Definition: IPstream.H:81
"scheduled" (MPI standard) : (MPI_Send, MPI_Recv)
static labelList calcListOffsets(const List< SubListType > &lists, const bool checkOverflow=false)
Calculate offsets from list of lists, with optional check for label overflow.
void mpiGather(const UList< Type > &sendData, OutputContainer &allData, const label comm=UPstream::worldComm, const UPstream::commsTypes=UPstream::commsTypes::nonBlocking, const int tag=UPstream::msgType()) const
Use MPI_Gatherv call for contiguous data when possible (in serial: performs a simple copy)...
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:130
void mpiGatherInplace(List< Type > &fld, const label comm=UPstream::worldComm, const UPstream::commsTypes=UPstream::commsTypes::nonBlocking, const int tag=UPstream::msgType()) const
Use MPI_Gatherv call to inplace collect contiguous data when possible. (in serial: a no-op)...
static void gather(const char *sendData, int sendCount, char *recvData, const UList< int > &recvCounts, const UList< int > &recvOffsets, const label communicator=worldComm)
Receive variable length char data from all ranks.
label size() const noexcept
The number of elements in the list.
void scatter(const Type *sendData, Type *recvData, int count, MPI_Datatype datatype, const label comm, UPstream::Request *req=nullptr, label *requestID=nullptr)
static void gatherValues(const label comm, const ProcIDsContainer &procIDs, const Type &localValue, List< Type > &allValues, const int tag=UPstream::msgType(), const UPstream::commsTypes=UPstream::commsTypes::nonBlocking)
Collect single values in processor order on master (== procIDs[0]).
OBJstream os(runTime.globalPath()/outputName)
void get(List< Type > &allFld, const labelUList &globalIds, const CombineOp &cop, const label comm=UPstream::worldComm, const int tag=UPstream::msgType()) const
Get (potentially remote) data. Elements required given as global indices.
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))
static void gatherInplaceOp(List< Type > &fld, const int tag=UPstream::msgType(), const UPstream::commsTypes=UPstream::commsTypes::nonBlocking, const label comm=UPstream::worldComm)
Inplace collect data in processor order on master (in serial: a no-op).
A template class to specify that a data type can be considered as being contiguous in memory...
Definition: contiguous.H:70
static bool broadcast(char *buf, const std::streamsize bufSize, const label communicator, const int rootProcNo=masterNo())
Broadcast buffer contents to all processes in given communicator. The sizes must match on all process...
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1094
static bool write(const UPstream::commsTypes commsType, const int toProcNo, const char *buf, const std::streamsize bufSize, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm, UPstream::Request *req=nullptr, const UPstream::sendModes sendMode=UPstream::sendModes::normal)
Write buffer contents to given processor.
"nonBlocking" (immediate) : (MPI_Isend, MPI_Irecv)
void gatherInplace(List< Type > &fld, const int tag=UPstream::msgType(), const UPstream::commsTypes=UPstream::commsTypes::nonBlocking, const label comm=UPstream::worldComm) const
Inplace collect data in processor order on master (in serial: a no-op).
static void gather(const labelUList &offsets, const label comm, const ProcIDsContainer &procIDs, const UList< Type > &fld, List< Type > &allFld, const int tag=UPstream::msgType(), const UPstream::commsTypes=UPstream::commsTypes::nonBlocking)
Collect data in processor order on master (== procIDs[0]).
List< label > labelList
A List of labels.
Definition: List.H:62
bool send()
Send buffer contents now and not in destructor [advanced usage]. Returns true on success.
Definition: OPstreams.C:84
static void gatherOp(const UList< Type > &sendData, List< Type > &allData, const int tag=UPstream::msgType(), const UPstream::commsTypes=UPstream::commsTypes::nonBlocking, const label comm=UPstream::worldComm)
Collect data in processor order on master (in serial: performs a simple copy).
static std::streamsize read(const UPstream::commsTypes commsType, const int fromProcNo, char *buf, const std::streamsize bufSize, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm, UPstream::Request *req=nullptr)
Read buffer contents from given processor.
Definition: UIPstreamRead.C:35
static void scatter(const labelUList &offsets, const label comm, const ProcIDsContainer &procIDs, const UList< Type > &allFld, UList< Type > &fld, const int tag=UPstream::msgType(), const UPstream::commsTypes=UPstream::commsTypes::nonBlocking)
Distribute data in processor order.