PstreamGatherList.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) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2022 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 Description
28  Gather data from all processors onto single processor according to some
29  communication schedule (usually linear-to-master or tree-to-master).
30  The gathered data will be a list with element procID the data from processor
31  procID. Before calling every processor should insert its value into
32  values[UPstream::myProcNo(comm)].
33  Note: after gather every processor only knows its own data and that of the
34  processors below it. Only the 'master' of the communication schedule holds
35  a fully filled List. Use scatter to distribute the data.
36 
37 \*---------------------------------------------------------------------------*/
38 
39 #include "IPstream.H"
40 #include "OPstream.H"
41 #include "contiguous.H"
42 
43 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
44 
45 template<class T>
47 (
48  const List<UPstream::commsStruct>& comms,
49  List<T>& values,
50  const int tag,
51  const label comm
52 )
53 {
54  if (UPstream::parRun() && UPstream::nProcs(comm) > 1)
55  {
56  if (values.size() != UPstream::nProcs(comm))
57  {
59  << "Size of list:" << values.size()
60  << " does not equal the number of processors:"
61  << UPstream::nProcs(comm)
63  }
64 
65  // My communication order
66  const commsStruct& myComm = comms[UPstream::myProcNo(comm)];
67 
68  // Receive from my downstairs neighbours
69  for (const label belowID : myComm.below())
70  {
71  const labelList& belowLeaves = comms[belowID].allBelow();
72 
74  {
75  List<T> received(belowLeaves.size() + 1);
76 
78  (
80  belowID,
81  received.data_bytes(),
82  received.size_bytes(),
83  tag,
84  comm
85  );
86 
87  values[belowID] = received[0];
88 
89  forAll(belowLeaves, leafI)
90  {
91  values[belowLeaves[leafI]] = received[leafI + 1];
92  }
93  }
94  else
95  {
96  IPstream fromBelow
97  (
99  belowID,
100  0,
101  tag,
102  comm
103  );
104  fromBelow >> values[belowID];
105 
106  if (debug & 2)
107  {
108  Pout<< " received through "
109  << belowID << " data from:" << belowID
110  << " data:" << values[belowID] << endl;
111  }
112 
113  // Receive from all other processors below belowID
114  for (const label leafID : belowLeaves)
115  {
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 
143  {
144  List<T> sending(belowLeaves.size() + 1);
145  sending[0] = values[UPstream::myProcNo(comm)];
146 
147  forAll(belowLeaves, leafI)
148  {
149  sending[leafI + 1] = values[belowLeaves[leafI]];
150  }
151 
153  (
155  myComm.above(),
156  sending.cdata_bytes(),
157  sending.size_bytes(),
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  for (const label leafID : belowLeaves)
175  {
176  if (debug & 2)
177  {
178  Pout<< " sending to "
179  << myComm.above() << " data from:" << leafID
180  << " data:" << values[leafID] << endl;
181  }
182  toAbove << values[leafID];
183  }
184  }
185  }
186  }
187 }
188 
189 
190 template<class T>
192 (
193  const List<UPstream::commsStruct>& comms,
194  List<T>& values,
195  const int tag,
196  const label comm
197 )
198 {
199  // Apart from the additional (size == nProcs) check, the only difference
200  // between scatterList() and using broadcast(List<T>&) or a regular
201  // scatter(List<T>&) is that processor-local data is skipped.
202 
203  if (UPstream::parRun() && UPstream::nProcs(comm) > 1)
204  {
205  if (values.size() != UPstream::nProcs(comm))
206  {
208  << "Size of list:" << values.size()
209  << " does not equal the number of processors:"
210  << UPstream::nProcs(comm)
212  }
213 
214  // My communication order
215  const commsStruct& myComm = comms[UPstream::myProcNo(comm)];
216 
217  // Receive from up
218  if (myComm.above() != -1)
219  {
220  const labelList& notBelowLeaves = myComm.allNotBelow();
221 
222  if (is_contiguous<T>::value)
223  {
224  List<T> received(notBelowLeaves.size());
225 
227  (
229  myComm.above(),
230  received.data_bytes(),
231  received.size_bytes(),
232  tag,
233  comm
234  );
235 
236  forAll(notBelowLeaves, leafI)
237  {
238  values[notBelowLeaves[leafI]] = received[leafI];
239  }
240  }
241  else
242  {
243  IPstream fromAbove
244  (
246  myComm.above(),
247  0,
248  tag,
249  comm
250  );
251 
252  for (const label leafID : notBelowLeaves)
253  {
254  fromAbove >> values[leafID];
255 
256  if (debug & 2)
257  {
258  Pout<< " received through "
259  << myComm.above() << " data for:" << leafID
260  << " data:" << values[leafID] << endl;
261  }
262  }
263  }
264  }
265 
266  // Send to my downstairs neighbours
267  forAllReverse(myComm.below(), belowI)
268  {
269  const label belowID = myComm.below()[belowI];
270  const labelList& notBelowLeaves = comms[belowID].allNotBelow();
271 
272  if (is_contiguous<T>::value)
273  {
274  List<T> sending(notBelowLeaves.size());
275 
276  forAll(notBelowLeaves, leafI)
277  {
278  sending[leafI] = values[notBelowLeaves[leafI]];
279  }
280 
282  (
284  belowID,
285  sending.cdata_bytes(),
286  sending.size_bytes(),
287  tag,
288  comm
289  );
290  }
291  else
292  {
293  OPstream toBelow
294  (
296  belowID,
297  0,
298  tag,
299  comm
300  );
301 
302  // Send data destined for all other processors below belowID
303  for (const label leafID : notBelowLeaves)
304  {
305  toBelow << values[leafID];
306 
307  if (debug & 2)
308  {
309  Pout<< " sent through "
310  << belowID << " data for:" << leafID
311  << " data:" << values[leafID] << endl;
312  }
313  }
314  }
315  }
316  }
317 }
318 
319 
320 template<class T>
322 (
323  List<T>& values,
324  const int tag,
325  const label comm
326 )
327 {
329 }
330 
331 
332 template<class T>
334 (
335  List<T>& values,
336  const int tag,
337  const label comm
338 )
339 {
341 }
342 
343 
344 template<class T>
346 (
347  List<T>& values,
348  const int tag,
349  const label comm
350 )
351 {
352  if (UPstream::parRun() && UPstream::nProcs(comm) > 1)
353  {
354  const auto& comms = UPstream::whichCommunication(comm);
355 
356  Pstream::gatherList(comms, values, tag, comm);
357  Pstream::scatterList(comms, values, tag, comm);
358  }
359 }
360 
361 
362 // ************************************************************************* //
const labelList & below() const noexcept
The procIDs of all processors directly below.
Definition: UPstream.H:162
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)
Write buffer contents to given processor.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:118
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:578
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:639
static const List< commsStruct > & whichCommunication(const label communicator=worldComm)
Communication schedule for linear/tree all-to-master (proc 0). Chooses based on the value of UPstream...
Definition: UPstream.H:790
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:688
label above() const noexcept
The procID of the processor directly above.
Definition: UPstream.H:154
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
Input inter-processor communications stream.
Definition: IPstream.H:49
const char * cdata_bytes() const noexcept
Return pointer to the underlying array serving as data storage,.
Definition: UListI.H:237
static void allGatherList(List< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses linear/tree communication. ...
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:164
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator) is 1 for serial run.
Definition: UPstream.H:656
static void gatherList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
Gather data, but keep individual values separate. Uses the specified communication schedule...
"scheduled" : (MPI_Send, MPI_Recv)
errorManip< error > abort(error &err)
Definition: errorManip.H:139
Structure for communicating between processors.
Definition: UPstream.H:84
const labelList & allBelow() const noexcept
The procIDs of all processors below (so not just directly below)
Definition: UPstream.H:171
int debug
Static debugging option.
Output inter-processor communications stream.
Definition: OPstream.H:49
A template class to specify that a data type can be considered as being contiguous in memory...
Definition: contiguous.H:71
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: stdFoam.H:429
List< label > labelList
A List of labels.
Definition: List.H:62
static label read(const commsTypes commsType, const int fromProcNo, char *buf, const std::streamsize bufSize, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Read buffer contents from given processor.
Definition: UIPstreamRead.C:35
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
std::streamsize size_bytes() const noexcept
Number of contiguous bytes for the List data.
Definition: UListI.H:251
static void scatterList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
Scatter data. Reverse of gatherList.