Loading...
Searching...
No Matches
UPstreamGatherScatter.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) 2022-2025 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26\*---------------------------------------------------------------------------*/
27
28#include "Pstream.H"
31#include "vector.H" // for debugging
32
33#undef STRINGIFY
34#undef STRING_QUOTE
35
36#define STRINGIFY(content) #content
37#define STRING_QUOTE(input) STRINGIFY(input)
38
39// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
40
41namespace
42{
43
44inline bool is_nonAggregate(Foam::UPstream::dataTypes id) noexcept
45{
46 return
47 (
50 )
51 ||
52 (
55 );
56}
57
58// Local function to print some error information
59inline void printErrorNonIntrinsic
60(
61 const char* context,
63)
64{
65 using namespace Foam;
66
68 << "Bad input for " << context << ": likely a programming problem\n"
69 << " Non-intrinsic/non-user data (type:" << int(dataTypeId) << ")\n"
70 << Foam::endl;
71}
72
73} // End anonymous namespace
74
75
76// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
77
79(
80 const void* sendData, // Type checking done by caller
81 void* recvData, // Type checking done by caller
82 int count,
83 const UPstream::dataTypes dataTypeId, // Proper type passed by caller
84
85 const int communicator, // Index into MPICommunicators_
87)
88{
89 MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
90
91 if (FOAM_UNLIKELY(UPstream::debug))
92 {
93 Perr<< "[mpi_gather] :";
94
95 // Appears to be an in-place request
96 if
97 (
99 && (!sendData || (sendData == recvData))
100 )
101 {
102 Perr<< " (inplace)";
103 }
104
105 Perr<< " type:" << int(dataTypeId) << " count:" << count
106 << " comm:" << communicator
107 << Foam::endl;
108 }
109
110 {
111 // Regular gather
112
114 (
115 sendData,
116 recvData,
117 count,
118 datatype,
120 req
121 );
122 }
123}
124
125
126// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
127
129(
130 const void* sendData, // Type checking done by caller
131 void* recvData, // Type checking done by caller
132 int count,
133 const UPstream::dataTypes dataTypeId, // Proper type passed by caller
134
135 const int communicator, // Index into MPICommunicators_
137)
138{
139 MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
140
141 if (FOAM_UNLIKELY(UPstream::debug))
142 {
143 Perr<< "[mpi_scatter] :";
144
145 // Appears to be an in-place request
146 if
147 (
148 UPstream::master(communicator)
149 && (!recvData || (sendData == recvData))
150 )
151 {
152 Perr<< " (inplace)";
153 }
154
155 Perr<< " type:" << int(dataTypeId) << " count:" << count
156 << " comm:" << communicator
157 << Foam::endl;
158 }
159
160 {
161 // Regular scatter
162
164 (
165 sendData,
166 recvData,
167 count,
168 datatype,
169 communicator,
170 req
171 );
172 }
173}
174
175
176// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
177
179(
180 void* allData, // Type checking done by caller
181 int count,
182 const UPstream::dataTypes dataTypeId, // Proper type passed by caller
183
184 const int communicator, // Index into MPICommunicators_
186)
187{
188 MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
189
190 if (FOAM_UNLIKELY(UPstream::debug))
191 {
192 Perr<< "[mpi_allgather] :"
193 << " type:" << int(dataTypeId) << " count:" << count
194 << " comm:" << communicator
195 << Foam::endl;
196 }
197
198 {
199 // Regular all gather
200
202 (
203 allData,
204 count,
205 datatype,
206 communicator,
207 req
208 );
209 }
210}
211
212
213// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
214
216(
217 const void* sendData,
218 int sendCount,
219 void* recvData,
220 const UList<int>& recvCounts,
221 const UList<int>& recvOffsets,
222
223 const UPstream::dataTypes dataTypeId, // Proper type passed by caller
224 const int communicator
225)
226{
227 MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
228
229 // Runtime assert that we are not using aggregated data types
230 if (FOAM_UNLIKELY(!is_nonAggregate(dataTypeId)))
231 {
233 printErrorNonIntrinsic("MPI_Gatherv()", dataTypeId);
235 }
236
237 const label np = UPstream::nProcs(communicator);
238
239 // For total-size calculation,
240 // don't rely on recvOffsets being (np+1)
241 const int totalSize =
242 (
243 (UPstream::master(communicator) && np > 1)
244 ? (recvOffsets[np-1] + recvCounts[np-1])
245 : 0
246 );
247
248 if (FOAM_UNLIKELY(UPstream::debug))
249 {
250 Perr<< "[mpi_gatherv] :"
251 << " type:" << int(dataTypeId)
252 << " count:" << sendCount
253 << " total:" << totalSize
254 << " comm:" << communicator
255 << " recvCounts:" << flatOutput(recvCounts)
256 << " recvOffsets:" << flatOutput(recvOffsets)
257 << Foam::endl;
258 }
259
260 {
262 (
263 sendData, sendCount,
264 recvData, recvCounts, recvOffsets,
265 datatype, communicator
266 );
267 }
268
269 // Extended debugging. Limit to master:
270
271 #if 0
272 if (FOAM_UNLIKELY(UPstream::debug))
273 {
274 if (UPstream::master(communicator))
275 {
276 switch (dataTypeId)
277 {
278 #undef dataPrinter
279 #define dataPrinter(enumType, nativeType) \
280 case UPstream::dataTypes::enumType : \
281 { \
282 UList<nativeType> combined \
283 ( \
284 static_cast<nativeType*>(recvData), \
285 totalSize \
286 ); \
287 \
288 Info<< "[mpi_gatherv] => " \
289 "List<" STRING_QUOTE(nativeType) "> "; \
290 combined.writeList(Info) << Foam::endl; \
291 \
292 break; \
293 }
294
295 // Some common types
296 dataPrinter(type_int32, int32_t);
297 dataPrinter(type_int64, int64_t);
298 dataPrinter(type_float, float);
299 dataPrinter(type_double, double);
300 dataPrinter(type_3float, floatVector);
301 dataPrinter(type_3double, doubleVector);
302
303 // Some other type
304 default: break;
305 #undef dataPrinter
306 }
307 }
308 }
309 #endif
310}
311
312
313// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
314
316(
317 const void* sendData,
318 const UList<int>& sendCounts,
319 const UList<int>& sendOffsets,
320
321 void* recvData,
322 int recvCount,
323
324 const UPstream::dataTypes dataTypeId, // Proper type passed by caller
325 const int communicator
326)
327{
328 MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
329
330 // Runtime assert that we are not using aggregated data types
331 if (FOAM_UNLIKELY(!is_nonAggregate(dataTypeId)))
332 {
334 printErrorNonIntrinsic("MPI_Scatterv()", dataTypeId);
336 }
337
338 {
340 (
341 sendData, sendCounts, sendOffsets,
342 recvData, recvCount,
343 datatype, communicator
344 );
345 }
346}
347
348
349// ************************************************************************* //
Functions to wrap MPI_Bcast, MPI_Allreduce, MPI_Iallreduce etc.
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition UList.H:89
An opaque wrapper for MPI_Request with a vendor-independent representation without any <mpi....
Definition UPstream.H:2919
Wrapper for internally indexed communicator label. Always invokes UPstream::allocateCommunicatorCompo...
Definition UPstream.H:2546
static void mpi_scatter(const void *sendData, void *recvData, int count, const UPstream::dataTypes dataTypeId, const int communicator, UPstream::Request *req=nullptr)
Send identically-sized (contiguous) data from rank 0 to all other ranks.
static void mpi_allgather(void *allData, int count, const UPstream::dataTypes dataTypeId, const int communicator, UPstream::Request *req=nullptr)
Gather/scatter identically-sized data.
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
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:1697
static void mpi_scatterv(const void *sendData, const UList< int > &sendCounts, const UList< int > &sendOffsets, void *recvData, int recvCount, const UPstream::dataTypes dataTypeId, const int communicator)
Send variable length data from rank 0 to all ranks. (caution: known to scale poorly).
static void mpi_gather(const void *sendData, void *recvData, int count, const UPstream::dataTypes dataTypeId, const int communicator, UPstream::Request *req=nullptr)
Receive identically-sized (contiguous) data from all ranks, placing the result on rank 0.
dataTypes
Mapping of some fundamental and aggregate types to MPI data types.
Definition UPstream.H:107
@ Basic_end
(internal use) end marker [basic types]
Definition UPstream.H:125
@ User_begin
(internal use) begin marker [user types]
Definition UPstream.H:125
@ User_end
(internal use) end marker [user types]
Definition UPstream.H:139
@ Basic_begin
(internal use) begin marker [basic/all types]
Definition UPstream.H:112
static void mpi_gatherv(const void *sendData, int sendCount, void *recvData, const UList< int > &recvCounts, const UList< int > &recvOffsets, const UPstream::dataTypes dataTypeId, const int communicator)
Receive variable length data from all ranks, placing the result on rank 0. (caution: known to scale p...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition BitOps.H:73
void scatterv(const Type *sendData, const UList< int > &sendCounts, const UList< int > &sendOffsets, Type *recvData, int recvCount, MPI_Datatype datatype, const int communicator, UPstream::Request *req=nullptr)
void gather(const Type *sendData, Type *recvData, int count, MPI_Datatype datatype, const int communicator, UPstream::Request *req=nullptr)
void scatter(const Type *sendData, Type *recvData, int count, MPI_Datatype datatype, const int communicator, UPstream::Request *req=nullptr)
void gatherv(const Type *sendData, int sendCount, Type *recvData, const UList< int > &recvCounts, const UList< int > &recvOffsets, MPI_Datatype datatype, const int communicator, UPstream::Request *req=nullptr)
void allGather(Type *allData, int count, MPI_Datatype datatype, const int communicator, UPstream::Request *req=nullptr)
MPI_Datatype getDataType(UPstream::dataTypes id)
Lookup of dataTypes enumeration as an MPI_Datatype.
Namespace for OpenFOAM.
Vector< float > floatVector
Definition vector.H:50
prefixOSstream Perr
OSstream wrapped stderr (std::cerr) with parallel prefix.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
Vector< double > doubleVector
Definition vector.H:54
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition FlatOutput.H:217
errorManip< error > abort(error &err)
Definition errorManip.H:139
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
#define FOAM_UNLIKELY(cond)
Definition stdFoam.H:64