gatherScatterList.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2025 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 Description
25  Gather data from all processors onto single processor according to some
26  communication schedule (usually linear-to-master or tree-to-master).
27  The gathered data will be a list with element procID the data from processor
28  procID. Before calling every processor should insert its value into
29  Values[UPstream::myProcNo(comm)].
30  Note: after gather every processor only knows its own data and that of the
31  processors below it. Only the 'master' of the communication schedule holds
32  a fully filled List. Use scatter to distribute the data.
33 
34 \*---------------------------------------------------------------------------*/
35 
36 #include "IPstream.H"
37 #include "OPstream.H"
38 #include "contiguous.H"
39 #include "ListListOps.H"
40 
41 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
42 
43 template<class T>
45 (
46  const List<UPstream::commsStruct>& comms,
47  List<T>& Values,
48  const int tag,
49  const label comm
50 )
51 {
52  if (UPstream::parRun() && UPstream::nProcs(comm) > 1)
53  {
54  if (Values.size() != UPstream::nProcs(comm))
55  {
57  << "Size of list:" << Values.size()
58  << " does not equal the number of processors:"
59  << UPstream::nProcs(comm)
61  }
62 
63  // Get my communication order
64  const commsStruct& myComm = comms[UPstream::myProcNo(comm)];
65 
66  // Receive from my downstairs neighbours
67  forAll(myComm.below(), belowI)
68  {
69  label belowID = myComm.below()[belowI];
70  const labelList& belowLeaves = comms[belowID].allBelow();
71 
72  if (contiguous<T>())
73  {
74  List<T> receivedValues(belowLeaves.size() + 1);
75 
77  (
79  belowID,
80  reinterpret_cast<char*>(receivedValues.begin()),
81  receivedValues.byteSize(),
82  tag,
83  comm
84  );
85 
86  Values[belowID] = receivedValues[0];
87 
88  forAll(belowLeaves, leafI)
89  {
90  Values[belowLeaves[leafI]] = receivedValues[leafI + 1];
91  }
92  }
93  else
94  {
95  IPstream fromBelow
96  (
98  belowID,
99  0,
100  tag,
101  comm
102  );
103  fromBelow >> Values[belowID];
104 
105  if (debug & 2)
106  {
107  Pout<< " received through "
108  << belowID << " data from:" << belowID
109  << " data:" << Values[belowID] << endl;
110  }
111 
112  // Receive from all other processors below belowID
113  forAll(belowLeaves, leafI)
114  {
115  label leafID = belowLeaves[leafI];
116  fromBelow >> Values[leafID];
117 
118  if (debug & 2)
119  {
120  Pout<< " received through "
121  << belowID << " data from:" << leafID
122  << " data:" << Values[leafID] << endl;
123  }
124  }
125  }
126  }
127 
128  // Send up from Values:
129  // - my own value first
130  // - all belowLeaves next
131  if (myComm.above() != -1)
132  {
133  const labelList& belowLeaves = myComm.allBelow();
134 
135  if (debug & 2)
136  {
137  Pout<< " sending to " << myComm.above()
138  << " data from me:" << UPstream::myProcNo(comm)
139  << " data:" << Values[UPstream::myProcNo(comm)] << endl;
140  }
141 
142  if (contiguous<T>())
143  {
144  List<T> sendingValues(belowLeaves.size() + 1);
145  sendingValues[0] = Values[UPstream::myProcNo(comm)];
146 
147  forAll(belowLeaves, leafI)
148  {
149  sendingValues[leafI + 1] = Values[belowLeaves[leafI]];
150  }
151 
153  (
155  myComm.above(),
156  reinterpret_cast<const char*>(sendingValues.begin()),
157  sendingValues.byteSize(),
158  tag,
159  comm
160  );
161  }
162  else
163  {
164  OPstream toAbove
165  (
167  myComm.above(),
168  0,
169  tag,
170  comm
171  );
172  toAbove << Values[UPstream::myProcNo(comm)];
173 
174  forAll(belowLeaves, leafI)
175  {
176  label leafID = belowLeaves[leafI];
177 
178  if (debug & 2)
179  {
180  Pout<< " sending to "
181  << myComm.above() << " data from:" << leafID
182  << " data:" << Values[leafID] << endl;
183  }
184  toAbove << Values[leafID];
185  }
186  }
187  }
188  }
189 }
190 
191 
192 template<class T>
193 void Foam::Pstream::gatherList(List<T>& Values, const int tag, const label comm)
194 {
196  {
197  gatherList(UPstream::linearCommunication(comm), Values, tag, comm);
198  }
199  else
200  {
201  gatherList(UPstream::treeCommunication(comm), Values, tag, comm);
202  }
203 }
204 
205 
206 template<class T>
208 (
209  const List<UPstream::commsStruct>& comms,
210  List<T>& Values,
211  const int tag,
212  const label comm
213 )
214 {
215  if (UPstream::parRun() && UPstream::nProcs(comm) > 1)
216  {
217  if (Values.size() != UPstream::nProcs(comm))
218  {
220  << "Size of list:" << Values.size()
221  << " does not equal the number of processors:"
222  << UPstream::nProcs(comm)
224  }
225 
226  // Get my communication order
227  const commsStruct& myComm = comms[UPstream::myProcNo(comm)];
228 
229  // Receive from up
230  if (myComm.above() != -1)
231  {
232  const labelList& notBelowLeaves = myComm.allNotBelow();
233 
234  if (contiguous<T>())
235  {
236  List<T> receivedValues(notBelowLeaves.size());
237 
239  (
241  myComm.above(),
242  reinterpret_cast<char*>(receivedValues.begin()),
243  receivedValues.byteSize(),
244  tag,
245  comm
246  );
247 
248  forAll(notBelowLeaves, leafI)
249  {
250  Values[notBelowLeaves[leafI]] = receivedValues[leafI];
251  }
252  }
253  else
254  {
255  IPstream fromAbove
256  (
258  myComm.above(),
259  0,
260  tag,
261  comm
262  );
263 
264  forAll(notBelowLeaves, leafI)
265  {
266  label leafID = notBelowLeaves[leafI];
267  fromAbove >> Values[leafID];
268 
269  if (debug)
270  {
271  Pout<< " received through "
272  << myComm.above() << " data for:" << leafID
273  << " data:" << Values[leafID] << endl;
274  }
275  }
276  }
277  }
278 
279  // Send to my downstairs neighbours
280  forAllReverse(myComm.below(), belowI)
281  {
282  label belowID = myComm.below()[belowI];
283  const labelList& notBelowLeaves = comms[belowID].allNotBelow();
284 
285  if (contiguous<T>())
286  {
287  List<T> sendingValues(notBelowLeaves.size());
288 
289  forAll(notBelowLeaves, leafI)
290  {
291  sendingValues[leafI] = Values[notBelowLeaves[leafI]];
292  }
293 
295  (
297  belowID,
298  reinterpret_cast<const char*>(sendingValues.begin()),
299  sendingValues.byteSize(),
300  tag,
301  comm
302  );
303  }
304  else
305  {
306  OPstream toBelow
307  (
309  belowID,
310  0,
311  tag,
312  comm
313  );
314 
315  // Send data destined for all other processors below belowID
316  forAll(notBelowLeaves, leafI)
317  {
318  label leafID = notBelowLeaves[leafI];
319  toBelow << Values[leafID];
320 
321  if (debug)
322  {
323  Pout<< " sent through "
324  << belowID << " data for:" << leafID
325  << " data:" << Values[leafID] << endl;
326  }
327  }
328  }
329  }
330  }
331 }
332 
333 
334 template<class T>
336 (
337  List<T>& Values,
338  const int tag,
339  const label comm
340 )
341 {
343  {
344  scatterList(UPstream::linearCommunication(comm), Values, tag, comm);
345  }
346  else
347  {
348  scatterList(UPstream::treeCommunication(comm), Values, tag, comm);
349  }
350 }
351 
352 
353 template<class ListType>
354 void Foam::Pstream::concatenateList(ListType& list)
355 {
356  typedef typename ListType::value_type Type;
357 
358  List<List<Type>> gatheredList(Pstream::nProcs());
359  gatheredList[Pstream::myProcNo()] = list;
360  Pstream::gatherList(gatheredList);
361 
362  if (Pstream::master())
363  {
364  list = ListListOps::combine<List<Type>>
365  (
366  gatheredList,
368  );
369  }
370 }
371 
372 
373 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: UList.H:461
Input inter-processor communications stream.
Definition: IPstream.H:54
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
Output inter-processor communications stream.
Definition: OPstream.H:54
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
static void concatenateList(ListType &list)
Gather the given list and concatenate on the master.
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
static label read(const commsTypes commsType, const int fromProcNo, char *buf, const std::streamsize bufSize, const int tag=UPstream::msgType(), const label communicator=0)
Read into given buffer from given processor and return the.
Definition: UIPread.C:80
iterator begin()
Return an iterator to begin traversing the UList.
Definition: UListI.H:216
std::streamsize byteSize() const
Return the binary size in number of characters of the UList.
Definition: UList.C:100
virtual Ostream & write(const token &)
Write token.
Definition: Ostream.C:51
Structure for communicating between processors.
Definition: UPstream.H:77
const labelList & allNotBelow() const
Definition: UPstream.H:140
const labelList & allBelow() const
Definition: UPstream.H:135
const labelList & below() const
Definition: UPstream.H:130
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
static int nProcsSimpleSum
Number of processors at which the sum algorithm changes from linear.
Definition: UPstream.H:269
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static const List< commsStruct > & linearCommunication(const label communicator=0)
Communication schedule for linear all-to-master (proc 0)
Definition: UPstream.H:459
static const List< commsStruct > & treeCommunication(const label communicator=0)
Communication schedule for tree all-to-master (proc 0)
Definition: UPstream.H:468
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
Template function to specify if the data of a type are contiguous.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
errorManip< error > abort(error &err)
Definition: errorManip.H:131
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
error FatalError