preCICE v3.1.1
Loading...
Searching...
No Matches
Parallel.cpp
Go to the documentation of this file.
1#include "Parallel.hpp"
2#include <algorithm>
3#include <map>
4#include <memory>
5#include <numeric>
6#include <ostream>
7#include <utility>
8#include <vector>
9#include "assertion.hpp"
11#include "logging/LogMacros.hpp"
12#include "logging/Logger.hpp"
13
14namespace precice::utils {
15
16logging::Logger Parallel::_log("utils::Parallel");
17
20
22
24
26{
27 comm = other.comm;
28 other.comm = MPI_COMM_NULL;
29 _owning = other._owning;
30 parent = std::move(other.parent);
31}
32
34{
35 comm = other.comm;
36 other.comm = MPI_COMM_NULL;
37 _owning = other._owning;
38 parent = std::move(other.parent);
39 return *this;
40}
41
43{
44#ifndef PRECICE_NO_MPI
45 if (_owning && comm != MPI_COMM_SELF && comm != MPI_COMM_NULL && comm != MPI_COMM_WORLD) {
46 MPI_Comm_free(&comm);
47 }
48#endif // not PRECICE_NO_MPI
49}
50
52{
53 int processRank = 0;
54#ifndef PRECICE_NO_MPI
55 MPI_Comm_rank(comm, &processRank);
56#endif // not PRECICE_NO_MPI
57 return processRank;
58}
59
61{
62
63 int communicatorSize = 1;
64#ifndef PRECICE_NO_MPI
65 MPI_Comm_size(comm, &communicatorSize);
66#endif // not PRECICE_NO_MPI
67 return communicatorSize;
68}
69
71{
72#ifndef PRECICE_NO_MPI
74 if (!isNull()) {
75 MPI_Barrier(comm);
76 }
77#endif // not PRECICE_NO_MPI
78}
79
81{
82#ifndef PRECICE_NO_MPI
83 return comm == MPI_COMM_NULL;
84#else
85 return true;
86#endif
87}
88
90{
91#ifndef PRECICE_NO_MPI
92 return fromComm(MPI_COMM_WORLD);
93#else
94 return null();
95#endif
96}
97
99{
100 return std::make_shared<CommState>();
101}
102
104{
105#ifndef PRECICE_NO_MPI
106 return fromComm(MPI_COMM_SELF);
107#else
108 return null();
109#endif
110}
111
113{
114 CommStatePtr state = null();
115 state->comm = comm;
116 return state;
117}
118
120{
121 CommStatePtr state = null();
122 state->comm = comm;
123 state->_owning = false;
124 return state;
125}
126
128{
129 if (comm == MPI_COMM_NULL) {
130 out << "COMM_NULL:invalid";
131 return;
132 }
133#ifndef PRECICE_NO_MPI
134 if (comm == MPI_COMM_SELF) {
135 out << "COMM_SELF:1/1";
136 return;
137 }
138 out << "COMM" << ((comm == MPI_COMM_WORLD) ? "_WORLD:" : ":");
139 out << rank() << '/' << size();
140 if (!_owning)
141 out << "EXTERN";
142#endif
143}
144
146
155
160
166
168{
170 PRECICE_ASSERT(newState != nullptr, "pushState cannot to be called with nullptr!");
171 PRECICE_ASSERT(newState->parent == nullptr, "The parent of the given state must be empty!");
172#ifndef NDEBUG
173 PRECICE_DEBUG("Update comm state from {} to {}", *current(), *newState);
174#endif
175 newState->parent = _currentState;
176 _currentState = std::move(newState);
177}
178
180{
181#ifndef PRECICE_NO_MPI
182 int isMPIInitialized{-1};
183 MPI_Initialized(&isMPIInitialized);
184 return isMPIInitialized != 0;
185#else
186 return false;
187#endif // not PRECICE_NO_MPI
188}
189
191{
192#ifndef PRECICE_NO_MPI
194 "MPI cannot be initialized twice. You need to handle the MPI lifetime yourself.");
195
196 bool isInit = isMPIInitialized();
197
198 // Handle user-provided Communicator first
199 if (userProvided.has_value()) {
200 PRECICE_ASSERT(isInit, "A user-provided comm can only exist if MPI has been initialized.");
203 return;
204 }
205
206 // preCICE needs to initialize MPI itself
207 if (!isInit) {
208 MPI_Init(nullptr, nullptr);
212 return;
213 }
214
215 // preCICE is constructed in testing mode
216 if (_currentState == nullptr) {
217 // User initialized MPI but didn't pass a communicator
218 // We need to use MPI_COMM_WORLD
221 return;
222 }
223
224 // We are in testing mode as \ref _currentState has been altered.
226 return;
227#endif
228}
229
231{
232#ifndef PRECICE_NO_MPI
233 // Make sure all com states are freed at this point in time
236 } else {
237 _currentState = nullptr;
238 }
239
241 MPI_Finalize();
242 PRECICE_ASSERT(_mpiInitializedByPrecice, "Something changed this state!");
243 }
244
246#endif // not PRECICE_NO_MPI
247}
248
250 int * argc,
251 char ***argv)
252{
253#ifndef PRECICE_NO_MPI
254 PRECICE_ASSERT(!isMPIInitialized(), "MPI was already initialized.");
255 MPI_Init(argc, argv);
256 // By altering the commstate, preCICE will know that it is testing mode
258#endif // not PRECICE_NO_MPI
259}
260
262{
263 // Make sure all com states are freed at this point in time
265#ifndef PRECICE_NO_MPI
266 MPI_Finalize();
267#endif // not PRECICE_NO_MPI
268}
269
270// State altering
271
273{
274#ifndef PRECICE_NO_MPI
275 PRECICE_TRACE(group.value_or(-1));
276
277 // Passing the same key maintains rank order
278 constexpr int keepTheSameOrder{0};
279
280 MPI_Comm newComm = MPI_COMM_NULL;
281 // Passing MPI_UNDEFINED as group results in MPI_COMM_NULL
282 auto err = MPI_Comm_split(current()->comm, group.value_or(MPI_UNDEFINED), keepTheSameOrder, &newComm);
283 PRECICE_ASSERT(err == MPI_SUCCESS, "MPI_Comm_split failed!", group.has_value(), group.value_or(-1));
284
285 // Assemble and set new state
287#endif // not PRECICE_NO_MPI
288}
289
291{
293 auto state = current();
294 if (state->parent) {
295 _currentState = state->parent;
296 }
297}
298
300{
301 // Do not use TRACE or DEBUG here!
302#ifndef PRECICE_NO_MPI
303 if (_currentState) {
304 return _currentState->rank();
305 }
306#endif // not PRECICE_NO_MPI
307 return 0;
308}
309
311{
312 value.print(out);
313 return out;
314}
315
316} // namespace precice::utils
317
318//#endif // not PRECICE_NO_MPI
std::ostream & out
#define PRECICE_DEBUG(...)
Definition LogMacros.hpp:64
#define PRECICE_TRACE(...)
Definition LogMacros.hpp:95
int MPI_Comm_rank(MPI_Comm comm, int *rank)
Definition MPI_Mock.hpp:24
int MPI_Barrier(MPI_Comm comm)
Definition MPI_Mock.hpp:19
static MPI_Comm MPI_COMM_WORLD
Definition MPI_Mock.hpp:13
int MPI_Comm_size(MPI_Comm comm, int *size)
Definition MPI_Mock.hpp:30
#define PRECICE_ASSERT(...)
Definition assertion.hpp:87
static bool isMPIInitialized()
Return true if MPI is initialized.
Definition Parallel.cpp:179
static InitializationState _initState
Definition Parallel.hpp:234
static void finalizeTestingMPI()
Unconditionally finalizes MPI environment.
Definition Parallel.cpp:261
std::shared_ptr< CommState > CommStatePtr
Definition Parallel.hpp:35
static void resetCommState()
Definition Parallel.cpp:156
static void finalizeOrCleanupMPI()
Finalized a managed MPI environment or cleans up after an non-managed session.
Definition Parallel.cpp:230
static CommStatePtr current()
Returns an owning pointer to the current CommState.
Definition Parallel.cpp:147
static Rank getProcessRank()
Definition Parallel.cpp:299
static void resetManagedMPI()
Definition Parallel.cpp:161
static void pushState(CommStatePtr newState)
Definition Parallel.cpp:167
InitializationState
Kind of initialization that took place.
Definition Parallel.hpp:226
@ Unmanaged
preCICE manages the lifetime of the MPI environment
@ Managed
Communicator was provided by the user.
@ Testing
preCICE was initialized in an existing MPI environment
static CommStatePtr _currentState
Definition Parallel.hpp:220
static bool _mpiInitializedByPrecice
Flag to saveguard against reinitializing MPI, which is forbidden.
Definition Parallel.hpp:223
static void initializeOrDetectMPI(std::optional< Communicator > userProvided=std::nullopt)
Definition Parallel.cpp:190
static void initializeTestingMPI(int *argc, char ***argv)
Definition Parallel.cpp:249
static void splitCommunicator(std::optional< int > group=std::nullopt)
Splits and creates a local MPI communicator according to groupName.
Definition Parallel.cpp:272
static logging::Logger _log
Definition Parallel.hpp:218
contains precice-related utilities.
std::ostream & operator<<(std::ostream &out, const RangePreview< Iter > &rp)
Allows streaming of RangePreview objects.
T has_value(T... args)
static CommStatePtr world()
returns a commstate containing MPI_COMM_WORLD
Definition Parallel.cpp:89
void print(std::ostream &out) const
pretty printer for comms
Definition Parallel.cpp:127
int size() const
Returns size of comm.
Definition Parallel.cpp:60
Rank rank() const
Returns the current rank in comm.
Definition Parallel.cpp:51
static CommStatePtr fromComm(Communicator comm)
returns the commstate representing comm
Definition Parallel.cpp:112
static CommStatePtr self()
returns the commstate representing MPI_COMM_SELF
Definition Parallel.cpp:103
static CommStatePtr null()
returns an blank commstate representing MPI_COMM_NULL
Definition Parallel.cpp:98
CommState & operator=(const CommState &)=delete
bool _owning
Whether this state owns the communicator and has to free it.
Definition Parallel.hpp:49
bool isNull() const
Returns weather the comm is NULL.
Definition Parallel.cpp:80
Communicator comm
The native communicator that represents this state.
Definition Parallel.hpp:43
CommStatePtr parent
A shared pointer to the parent CommState.
Definition Parallel.hpp:46
static CommStatePtr fromExtern(Communicator comm)
Definition Parallel.cpp:119
~CommState() noexcept
Frees the communicator if allowed.
Definition Parallel.cpp:42
T value_or(T... args)