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-2021 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 template<class SubListType>
36 (
37  const List<SubListType>& lists,
38  const bool checkOverflow
39 )
40 {
42 
43  const label len = lists.size();
44 
45  if (len)
46  {
47  values.resize(len+1);
48 
49  label start = 0;
50  for (label i = 0; i < len; ++i)
51  {
52  values[i] = start;
53  start += lists[i].size();
54 
55  if (checkOverflow && start < values[i])
56  {
58  << "Overflow : sum of sizes exceeds labelMax ("
59  << labelMax << ") after index " << i << nl
60  << "Please recompile with larger datatype for label." << nl
61  << exit(FatalError);
62  }
63  }
64  values[len] = start;
65  }
66 
67  return values;
68 }
69 
70 
71 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
72 
73 template<class ProcIDsContainer, class Type>
75 (
76  const labelUList& off,
77  const label comm,
78  const ProcIDsContainer& procIDs,
79  const UList<Type>& fld,
80  List<Type>& allFld,
81  const int tag,
82  const Pstream::commsTypes commsType
83 )
84 {
85  if
86  (
88  && commsType == Pstream::commsTypes::nonBlocking
89  )
90  {
92  << "Cannot use nonBlocking with non-contiguous data"
93  << exit(FatalError);
94  // Could also warn and change to scheduled etc...
95  }
96 
97  if (Pstream::myProcNo(comm) == procIDs[0])
98  {
99  allFld.resize_nocopy(off.last());
100 
101  // Assign my local data - respect offset information
102  // so that we can request 0 entries to be copied.
103  // Also handle the case where we have a slice of the full
104  // list.
105 
106  SubList<Type>(allFld, off[1]-off[0], off[0]) =
107  SubList<Type>(fld, off[1]-off[0]);
108 
109  if
110  (
111  commsType == Pstream::commsTypes::scheduled
112  || commsType == Pstream::commsTypes::blocking
113  )
114  {
115  for (label i = 1; i < procIDs.size(); ++i)
116  {
117  SubList<Type> procSlot(allFld, off[i+1]-off[i], off[i]);
118 
120  {
122  (
123  commsType,
124  procIDs[i],
125  procSlot.data_bytes(),
126  procSlot.size_bytes(),
127  tag,
128  comm
129  );
130  }
131  else
132  {
133  IPstream fromProc
134  (
135  commsType,
136  procIDs[i],
137  0,
138  tag,
139  comm
140  );
141  fromProc >> procSlot;
142  }
143  }
144  }
145  else
146  {
147  // nonBlocking && is_contiguous == true (already checked)
148 
149  const label startOfRequests = Pstream::nRequests();
150 
151  // Set up reads
152  for (label i = 1; i < procIDs.size(); ++i)
153  {
154  SubList<Type> procSlot(allFld, off[i+1]-off[i], off[i]);
155 
157  (
158  commsType,
159  procIDs[i],
160  procSlot.data_bytes(),
161  procSlot.size_bytes(),
162  tag,
163  comm
164  );
165  }
166 
167  // Wait for all to finish
168  Pstream::waitRequests(startOfRequests);
169  }
170  }
171  else
172  {
173  if
174  (
175  commsType == Pstream::commsTypes::scheduled
176  || commsType == Pstream::commsTypes::blocking
177  )
178  {
180  {
182  (
183  commsType,
184  procIDs[0],
185  fld.cdata_bytes(),
186  fld.size_bytes(),
187  tag,
188  comm
189  );
190  }
191  else
192  {
193  OPstream toMaster
194  (
195  commsType,
196  procIDs[0],
197  0,
198  tag,
199  comm
200  );
201  toMaster << fld;
202  }
203  }
204  else
205  {
206  // nonBlocking && is_contiguous == true (already checked)
207 
208  const label startOfRequests = Pstream::nRequests();
209 
210  // Set up write
212  (
213  commsType,
214  procIDs[0],
215  fld.cdata_bytes(),
216  fld.size_bytes(),
217  tag,
218  comm
219  );
220 
221  // Wait for all to finish
222  Pstream::waitRequests(startOfRequests);
223  }
224  }
225 }
226 
227 
228 template<class Type, class Addr>
230 (
231  const labelUList& off,
232  const label comm,
233  const UList<int>& procIDs,
235  List<Type>& allFld,
236  const int tag,
237  const Pstream::commsTypes commsType
238 )
239 {
240  if (commsType == Pstream::commsTypes::nonBlocking)
241  {
243  << "Cannot use nonBlocking with indirect list of data"
244  << exit(FatalError);
245  // Could also warn and change to scheduled etc...
246  }
247 
248  if (Pstream::myProcNo(comm) == procIDs[0])
249  {
250  allFld.resize_nocopy(off.last());
251 
252  // Assign my local data - respect offset information
253  // so that we can request 0 entries to be copied
254 
255  SubList<Type> localSlot(allFld, off[1]-off[0], off[0]);
256  if (!localSlot.empty())
257  {
258  localSlot = fld;
259  }
260 
261  // Already verified commsType != nonBlocking
262  for (label i = 1; i < procIDs.size(); ++i)
263  {
264  SubList<Type> procSlot(allFld, off[i+1]-off[i], off[i]);
265 
266  IPstream fromProc
267  (
268  commsType,
269  procIDs[i],
270  0,
271  tag,
272  comm
273  );
274  fromProc >> procSlot;
275  }
276  }
277  else
278  {
279  OPstream toMaster
280  (
281  commsType,
282  procIDs[0],
283  0,
284  tag,
285  comm
286  );
287  toMaster << fld;
288  }
289 }
290 
291 
292 template<class Type>
294 (
295  const UList<Type>& fld,
296  List<Type>& allFld,
297  const int tag,
298  const Pstream::commsTypes commsType,
299  const label comm
300 ) const
301 {
302  gather
303  (
304  comm,
305  UPstream::procID(comm),
306  fld,
307  allFld,
308  tag,
309  commsType
310  );
311 }
312 
313 
314 template<class Type, class Addr>
316 (
318  List<Type>& allFld,
319  const int tag,
320  const Pstream::commsTypes commsType,
321  const label comm
322 ) const
323 {
324  gather
325  (
326  offsets_,
327  comm,
328  UPstream::procID(comm),
329  fld,
330  allFld,
331  tag,
332  commsType
333  );
334 }
335 
336 
337 template<class ProcIDsContainer, class Type>
339 (
340  const labelUList& off,
341  const label comm,
342  const ProcIDsContainer& procIDs,
343  List<Type>& fld,
344  const int tag,
345  const Pstream::commsTypes commsType
346 )
347 {
348  List<Type> allFld;
349 
350  gather(off, comm, procIDs, fld, allFld, tag, commsType);
351 
352  if (Pstream::myProcNo(comm) == procIDs[0])
353  {
354  fld.transfer(allFld);
355  }
356 }
357 
358 
359 template<class Type>
361 (
362  List<Type>& fld,
363  const int tag,
364  const Pstream::commsTypes commsType,
365  const label comm
366 ) const
367 {
368  List<Type> allFld;
369 
370  gather
371  (
372  comm,
373  UPstream::procID(comm),
374  fld,
375  allFld,
376  tag,
377  commsType
378  );
379 
380  if (Pstream::master(comm))
381  {
382  fld.transfer(allFld);
383  }
384  else
385  {
386  fld.clear();
387  }
388 }
389 
390 
391 template<class Type, class OutputContainer>
393 (
394  const UList<Type>& sendData,
395  OutputContainer& allValues,
396  const label comm
397 ) const
398 {
400  {
402  << "Cannot be called for non-contiguous data" << nl
403  << abort(FatalError);
404  }
405 
406  const label proci = Pstream::myProcNo(comm);
407 
408  const globalIndex& globalAddr = *this;
409 
410  // Must be the same as Pstream::nProcs(comm), at least on master!!
411  const label nproc = globalAddr.nProcs();
412 
413  auto nSendBytes = sendData.size_bytes();
414 
415  // Respect local size information so that we can request
416  // 0 entries to be sent on master
417 
418  if (proci < nproc && !globalAddr.localSize(proci))
419  {
420  nSendBytes = 0;
421  }
422 
423  List<int> recvSizes;
424  List<int> recvOffsets;
425 
426  if (Pstream::master(comm))
427  {
428  allValues.resize_nocopy(globalAddr.size());
429 
430  recvSizes.resize(nproc);
431  recvOffsets.resize(nproc+1);
432 
433  for (label proci = 0; proci < nproc; ++proci)
434  {
435  recvSizes[proci] = globalAddr.localSize(proci) * sizeof(Type);
436  recvOffsets[proci] = globalAddr.localStart(proci) * sizeof(Type);
437  }
438  recvOffsets[nproc] = globalAddr.size() * sizeof(Type);
439  }
440  else
441  {
442  allValues.clear();
443  }
444 
445  UPstream::gather
446  (
447  sendData.cdata_bytes(),
448  nSendBytes,
449  allValues.data_bytes(),
450  recvSizes,
451  recvOffsets,
452  comm
453  );
454 }
455 
456 
457 template<class Type, class OutputContainer>
458 OutputContainer Foam::globalIndex::mpiGather
459 (
460  const UList<Type>& sendData,
461  const label comm
462 ) const
463 {
464  OutputContainer allValues;
465  mpiGather<Type, OutputContainer>(sendData, allValues, comm);
466  return allValues;
467 }
468 
469 
470 template<class Type>
472 (
473  const UList<Type>& fld,
474  List<Type>& allFld,
475  const int tag,
476  const Pstream::commsTypes commsType
477 )
478 {
479  globalIndex(fld.size()).gather(fld, allFld, tag, commsType);
480 }
481 
482 
483 template<class Type>
485 (
486  List<Type>& fld,
487  const int tag,
488  const Pstream::commsTypes commsType
489 )
490 {
491  globalIndex(fld.size()).gather(fld, tag, commsType);
492 }
493 
494 
495 template<class ProcIDsContainer, class Type>
497 (
498  const labelUList& off,
499  const label comm,
500  const ProcIDsContainer& procIDs,
501  const UList<Type>& allFld,
502  UList<Type>& fld,
503  const int tag,
504  const Pstream::commsTypes commsType
505 )
506 {
507  if
508  (
510  && commsType == Pstream::commsTypes::nonBlocking
511  )
512  {
514  << "Cannot use nonBlocking with non-contiguous data"
515  << exit(FatalError);
516  // Could also warn and change to scheduled etc...
517  }
518 
519  if (Pstream::myProcNo(comm) == procIDs[0])
520  {
521  const SubList<Type> localSlot(allFld, off[1]-off[0], off[0]);
522 
523  if (!localSlot.empty())
524  {
525  fld.deepCopy(localSlot);
526  }
527 
528  if
529  (
530  commsType == Pstream::commsTypes::scheduled
531  || commsType == Pstream::commsTypes::blocking
532  )
533  {
534  for (label i = 1; i < procIDs.size(); ++i)
535  {
536  const SubList<Type> procSlot(allFld, off[i+1]-off[i], off[i]);
537 
539  {
541  (
542  commsType,
543  procIDs[i],
544  procSlot.cdata_bytes(),
545  procSlot.size_bytes(),
546  tag,
547  comm
548  );
549  }
550  else
551  {
552  OPstream toProc
553  (
554  commsType,
555  procIDs[i],
556  0,
557  tag,
558  comm
559  );
560  toProc << procSlot;
561  }
562  }
563  }
564  else
565  {
566  // nonBlocking && is_contiguous == true (already checked)
567 
568  const label startOfRequests = Pstream::nRequests();
569 
570  // Set up writes
571  for (label i = 1; i < procIDs.size(); ++i)
572  {
573  const SubList<Type> procSlot(allFld, off[i+1]-off[i], off[i]);
574 
576  (
577  commsType,
578  procIDs[i],
579  procSlot.cdata_bytes(),
580  procSlot.size_bytes(),
581  tag,
582  comm
583  );
584  }
585 
586  // Wait for all to finish
587  Pstream::waitRequests(startOfRequests);
588  }
589  }
590  else
591  {
592  if
593  (
594  commsType == Pstream::commsTypes::scheduled
595  || commsType == Pstream::commsTypes::blocking
596  )
597  {
599  {
601  (
602  commsType,
603  procIDs[0],
604  fld.data_bytes(),
605  fld.size_bytes(),
606  tag,
607  comm
608  );
609  }
610  else
611  {
612  IPstream fromMaster
613  (
614  commsType,
615  procIDs[0],
616  0,
617  tag,
618  comm
619  );
620  fromMaster >> fld;
621  }
622  }
623  else
624  {
625  // nonBlocking && is_contiguous == true (already checked)
626 
627  const label startOfRequests = Pstream::nRequests();
628 
629  // Set up read
631  (
632  commsType,
633  procIDs[0],
634  fld.data_bytes(),
635  fld.size_bytes(),
636  tag,
637  comm
638  );
639 
640  // Wait for all to finish
641  Pstream::waitRequests(startOfRequests);
642  }
643  }
644 }
645 
646 
647 template<class Type>
649 (
650  const UList<Type>& allFld,
651  UList<Type>& fld,
652  const int tag,
653  const Pstream::commsTypes commsType,
654  const label comm
655 ) const
656 {
657  scatter
658  (
659  offsets_,
660  comm,
661  UPstream::procID(comm),
662  allFld,
663  fld,
664  tag,
665  commsType
666  );
667 }
668 
669 
670 template<class Type, class CombineOp>
672 (
673  List<Type>& allFld,
674  const labelUList& globalIds,
675  const CombineOp& cop,
676  const label comm,
677  const int tag
678 ) const
679 {
680  allFld.resize_nocopy(globalIds.size());
681  if (globalIds.size())
682  {
683  // Sort according to processor
684  labelList order;
686  DynamicList<label> validBins(Pstream::nProcs());
687  bin
688  (
689  offsets(),
690  globalIds,
691  order,
692  bins,
693  validBins
694  );
695 
696  // Send local indices to individual processors as local index
697  PstreamBuffers sendBufs(Pstream::commsTypes::nonBlocking, tag, comm);
698 
699  for (const auto proci : validBins)
700  {
701  const labelUList& es = bins[proci];
702 
703  labelList localIDs(es.size());
704  forAll(es, i)
705  {
706  localIDs[i] = toLocal(proci, es[i]);
707  }
708 
709  UOPstream os(proci, sendBufs);
710  os << localIDs;
711  }
712  labelList recvSizes;
713  sendBufs.finishedSends(recvSizes);
714 
715 
716  PstreamBuffers returnBufs(Pstream::commsTypes::nonBlocking, tag, comm);
717 
718  forAll(recvSizes, proci)
719  {
720  if (recvSizes[proci])
721  {
722  UIPstream is(proci, sendBufs);
723  labelList localIDs(is);
724 
725  // Collect entries
726  List<Type> fld(localIDs.size());
727  cop(fld, localIDs);
728 
729  UOPstream os(proci, returnBufs);
730  os << fld;
731  }
732  }
733  returnBufs.finishedSends();
734 
735  // Slot back
736  for (const auto proci : validBins)
737  {
738  label start = bins.offsets()[proci];
739  const SubList<label> es
740  (
741  order,
742  bins.offsets()[proci+1]-start, // start
743  start
744  );
745  UIPstream is(proci, returnBufs);
746  List<Type> fld(is);
747 
748  UIndirectList<Type>(allFld, es) = fld;
749  }
750  }
751 }
752 
753 
754 // ************************************************************************* //
Foam::UList::cdata_bytes
const char * cdata_bytes() const noexcept
Return pointer to the underlying array serving as data storage,.
Definition: UListI.H:244
Foam::CompactListList::offsets
const List< label > & offsets() const
Return the offset table (= size()+1)
Definition: CompactListListI.H:142
Foam::globalIndex::gather
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 Pstream::commsTypes=Pstream::commsTypes::nonBlocking)
Collect data in processor order on master (== procIDs[0]).
Definition: globalIndexTemplates.C:75
Foam::labelMax
constexpr label labelMax
Definition: label.H:61
Foam::UOPstream
Output inter-processor communications stream operating on external buffer.
Definition: UOPstream.H:57
Foam::List::resize
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:139
Foam::globalIndex::localStart
label localStart() const
My local start.
Definition: globalIndexI.H:175
Foam::DynamicList< label >
Foam::HashTableOps::values
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:149
Foam::OPstream
Output inter-processor communications stream.
Definition: OPstream.H:53
Foam::SubList
A List obtained as a section of another List.
Definition: SubList.H:54
Foam::CompactListList
A packed storage unstructured matrix of objects of type <T> using an offset table for access.
Definition: CompactListList.H:63
globalIndex.H
Foam::PstreamBuffers
Buffers for inter-processor communications streams (UOPstream, UIPstream).
Definition: PstreamBuffers.H:88
Foam::globalIndex::calcListOffsets
static labelList calcListOffsets(const List< SubListType > &lists, const bool checkOverflow=false)
Foam::globalIndex::localSize
label localSize() const
My local size.
Definition: globalIndexI.H:187
Foam::List::resize_nocopy
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:146
Foam::globalIndex::get
void get(List< Type > &allFld, const labelUList &globalIds, const CombineOp &cop, const label comm=UPstream::worldComm, const int tag=UPstream::msgType()) const
Definition: globalIndexTemplates.C:672
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::blockMeshTools::read
void read(Istream &, label &val, const dictionary &)
In-place read with dictionary lookup.
Definition: blockMeshTools.C:57
Foam::UList::last
T & last()
Return the last element of the list.
Definition: UListI.H:216
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.
Definition: PstreamBuffers.C:73
Foam::globalIndex::gatherOp
static void gatherOp(const UList< Type > &fld, List< Type > &allFld, const int tag=UPstream::msgType(), const Pstream::commsTypes=Pstream::commsTypes::nonBlocking)
Collect data in processor order on master.
Definition: globalIndexTemplates.C:472
Foam::FatalError
error FatalError
os
OBJstream os(runTime.globalPath()/outputName)
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::globalIndex
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:68
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::UPstream::commsTypes
commsTypes
Types of communications.
Definition: UPstream.H:69
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::globalIndex::size
label size() const
Global sum of localSizes.
Definition: globalIndexI.H:151
Foam::globalIndex::mpiGather
void mpiGather(const UList< Type > &sendData, OutputContainer &allValues, const label comm=UPstream::worldComm) const
Collect contiguous data using a MPI_Gatherv call.
Definition: globalIndexTemplates.C:393
Foam::globalIndex::nProcs
label nProcs() const noexcept
The number of processors covered by the offsets.
Definition: globalIndexI.H:106
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
Foam::UList< label >
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:36
Foam::globalIndex::scatter
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 Pstream::commsTypes=Pstream::commsTypes::nonBlocking)
Distribute data in processor order. Requires fld to be sized!
Definition: globalIndexTemplates.C:497
Foam::UIndirectList
A List with indirect addressing.
Definition: faMatrix.H:60
Foam::IPstream
Input inter-processor communications stream.
Definition: IPstream.H:53
Foam::IndirectListBase
Base for lists with indirect addressing, templated on the list contents type and the addressing type....
Definition: IndirectListBase.H:56
Foam::UList::size
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
Foam::UIPstream
Input inter-processor communications stream operating on external buffer.
Definition: UIPstream.H:56
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:328
Foam::UList::size_bytes
std::streamsize size_bytes() const noexcept
Number of contiguous bytes for the List data.
Definition: UListI.H:258
Foam::is_contiguous
A template class to specify that a data type can be considered as being contiguous in memory.
Definition: contiguous.H:75