preCICE v3.2.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
TestContext.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <exception>
3#include <filesystem>
4#include <memory>
5#include <numeric>
6#include <ostream>
7#include <utility>
8
11#include "com/SharedPointer.hpp"
17#include "m2n/M2N.hpp"
20#include "mesh/Data.hpp"
23#include "query/Index.hpp"
25#include "testing/Testing.hpp"
26#include "utils/IntraComm.hpp"
27#include "utils/Parallel.hpp"
28#include "utils/Petsc.hpp"
29
30namespace precice::testing {
31
33
34// TestSetup
35
37{
38 using testing::Require;
39 switch (requirement) {
40 case Require::PETSc:
41 petsc = true;
42 events = true;
43 break;
44 case Require::Events:
45 events = true;
46 break;
47 case Require::Ginkgo:
48 ginkgo = true;
49 events = true;
50 break;
51 default:
53 }
54}
55
57{
58 participants.emplace_back(participant);
59}
60
62{
63 participants.emplace_back("Unnamed"_on(ranks));
64}
65
67{
68 return std::accumulate(participants.begin(), participants.end(), 0, [](int i, const ParticipantState &ps) { return i + ps.size; });
69}
70
71// TestContext
72
74 : _setup(setup)
75{
76 for (const auto &p : setup.participants) {
77 _names.emplace(p.name);
78 }
80}
81
83{
84 if (!invalid && _setup.petsc) {
86 }
87 if (!invalid) {
88 // Always clean up tests.
90 }
91 if (!invalid && _initIntraComm) {
94 }
95
96 // Reset communicators
99}
100
102{
104 auto dir = location.parent_path();
105 dir /= filename;
107}
108
110{
111 return prefix(testing::getTestName() + ".xml");
112}
113
114bool TestContext::hasSize(int size) const
115{
116 return this->size == size;
117}
118
120{
121 if (_names.count(name) == 0) {
122 throw std::runtime_error("The requested name \"" + name + "\" does not exist!");
123 }
124 return this->name == name;
125}
126
127bool TestContext::isRank(Rank rank) const
128{
129 if (rank >= size) {
130 throw std::runtime_error("The requested Rank does not exist!");
131 }
132 return this->rank == rank;
133}
134
136{
137 return isRank(0);
138}
139
141{
142 this->name = p.name;
143 this->size = p.size;
146 this->rank = this->_contextComm->rank();
147}
148
149void TestContext::initialize(const Participants &participants)
150{
151 Par::Parallel::CommState::world()->synchronize();
152 initializeMPI(participants);
153 Par::Parallel::CommState::world()->synchronize();
158}
159
161{
162 auto baseComm = Par::current();
163 const int globalRank = baseComm->rank();
164 const int available = baseComm->size();
165
166 // groups contain the accumulated sizes of previous groups
167 std::vector<int> groups(participants.size());
168 std::transform(participants.begin(), participants.end(), groups.begin(), [](const auto &p) { return p.size; });
169 std::partial_sum(groups.begin(), groups.end(), groups.begin());
170
171 // Check if there are enough ranks available
172 auto required = groups.back();
173 if (required > available) {
174 throw std::runtime_error{"This test requests " + std::to_string(required) + " ranks, but there are only " + std::to_string(available) + " available"};
175 }
176
177 // Check if this rank isn't needed
178 if (globalRank >= required) {
179 Par::splitCommunicator(); // No group
180 invalid = true;
181 return;
182 }
183
184 // Find the participant this rank is assigned to
185 auto position = std::upper_bound(groups.begin(), groups.end(), globalRank);
186 auto participant = std::distance(groups.begin(), position);
187 Par::splitCommunicator(participant);
188 setContextFrom(participants[participant]);
189}
190
192{
193 if (invalid)
194 return;
195
196 // Establish a consistent state for all tests
201
202 if (!_initIntraComm || hasSize(1))
203 return;
204
205#ifndef PRECICE_NO_MPI
207#else
209#endif
210
211 intraComm->connectIntraComm(name, "", rank, size);
212
213 utils::IntraComm::getCommunication() = std::move(intraComm);
214}
215
217{
218 if (invalid) {
219 return;
220 }
221 // Always initialize the events
223 er.initialize(name, rank, size);
224 if (_setup.events) { // Enable them if they are requested
226 er.setDirectory("./precice-profiling");
227 } else {
229 }
230 er.startBackend();
231}
232
239
241{
242 if (!invalid && _setup.ginkgo) {
243#ifndef PRECICE_NO_GINKGO
244 int argc = 0;
245 char **argv;
247#endif
248 }
249}
250
251m2n::PtrM2N TestContext::connectPrimaryRanks(const std::string &acceptor, const std::string &connector, const ConnectionOptions &options) const
252{
253 auto participantCom = com::PtrCommunication(new com::SocketCommunication());
254
256 switch (options.type) {
258 distrFactory = std::make_shared<m2n::GatherScatterComFactory>(participantCom);
259 break;
262 break;
263 default:
264 throw std::runtime_error{"ConnectionType unknown"};
265 };
266 auto m2n = std::make_shared<m2n::M2N>(participantCom, distrFactory, options.useOnlyPrimaryCom, options.useTwoLevelInit);
267
268 if (_names.count(acceptor) == 0) {
269 throw std::runtime_error{
270 "Acceptor \"" + acceptor + "\" not defined in this context."};
271 }
272 if (_names.count(connector) == 0) {
273 throw std::runtime_error{
274 "Connector \"" + connector + "\" not defined in this context."};
275 }
276
277 std::string configHash = "NOPE";
278 if (isNamed(acceptor)) {
279 m2n->acceptPrimaryRankConnection(acceptor, connector, configHash);
280 } else if (isNamed(connector)) {
281 m2n->requestPrimaryRankConnection(acceptor, connector, configHash);
282 } else {
283 throw std::runtime_error{"You try to connect " + acceptor + " and " + connector + ", but this context is named " + name};
284 }
285 return m2n;
286}
287
289{
290 if (invalid)
291 return "This test context is invalid!";
292
294 os << "Test context of " << testing::getFullTestName();
295 if (name.empty()) {
296 os << " is unnamed";
297 } else {
298 os << " represents \"" << name << '"';
299 }
300 os << " and runs on rank " << rank << " out of " << size << '.';
301
303 os << " Initialized: {";
304 if (_initIntraComm)
305 os << " IntraComm Communication ";
306 if (_setup.events)
307 os << " Events";
308 if (_setup.petsc)
309 os << " PETSc";
310 os << '}';
311 }
312 return os.str();
313}
314
315} // namespace precice::testing
std::string prefix
std::string name
T accumulate(T... args)
T back(T... args)
T begin(T... args)
T weakly_canonical(T... args)
Provides connection methods for processes located in one communicator.
Implements Communication by using sockets.
static void initialize(int *argc, char ***argv)
Definition Ginkgo.cpp:12
static EventRegistry & instance()
Returns the only instance (singleton) of the EventRegistry class.
void finalize()
Sets the global end time and flushes buffers.
bool isRank(Rank rank) const
Check whether this context has a given rank inside the Participant.
std::string prefix(const std::string &filename) const
void initialize(const Participants &participants)
Main entrypoint.
bool _initIntraComm
whether this context needs to initialize the intracomm
void initializePetsc()
Initialize PETSc if required.
bool invalid
whether this context is valid or not
m2n::PtrM2N connectPrimaryRanks(const std::string &acceptor, const std::string &connector, const ConnectionOptions &options=ConnectionOptions{}) const
std::set< std::string > _names
contains the name of every known Participant
void initializeMPI(const Participants &participants)
bool isNamed(const std::string &name) const
Check whether this context has a given name.
int size
the size of the Communicator of the current participant
std::string describe() const
Provides a user- and log-friendly description of the current context.
bool hasSize(int size) const
Check whether this context has a given size.
utils::Parallel::CommStatePtr _contextComm
the MPI communicator of the context
void initializeIntraComm()
Initialize the intra-participant communication connection if requested.
void initializeGinkgo()
Initialize Ginkgo if required.
void initializeEvents()
Initialize Events if required.
Rank rank
the rank of the current participant
std::string name
the name of the current participant
void setContextFrom(const ParticipantState &p)
static com::PtrCommunication & getCommunication()
Intra-participant communication.
Definition IntraComm.hpp:31
static void configure(Rank rank, int size)
Configures the intra-participant communication.
Definition IntraComm.cpp:31
Utility class for managing MPI operations.
Definition Parallel.hpp:24
static void resetCommState()
Definition Parallel.cpp:156
static CommStatePtr current()
Returns an owning pointer to the current CommState.
Definition Parallel.cpp:147
static void resetManagedMPI()
Definition Parallel.cpp:161
static void splitCommunicator(std::optional< int > group=std::nullopt)
Splits and creates a local MPI communicator according to groupName.
Definition Parallel.cpp:272
static void finalize()
Finalizes Petsc environment.
Definition Petsc.cpp:58
static void initialize(utils::Parallel::Communicator comm)
Initializes the Petsc environment.
Definition Petsc.cpp:38
T count(T... args)
T distance(T... args)
T emplace(T... args)
T empty(T... args)
T end(T... args)
T make_unique(T... args)
std::shared_ptr< Communication > PtrCommunication
void setMPIRank(int const rank)
void setParticipant(std::string const &participant)
contains the testing framework.
Definition helper.hpp:9
@ PETSc
Require to initialize PETSc. This implies the initialization of Events.
@ Events
Require to initialize Event.
@ Ginkgo
Ginkgo initialization.
std::string getFullTestName()
Return the full name of the current test as seen in boost assertions.
Definition Testing.cpp:60
std::string getTestPath()
Returns the full path to the file containing the current test.
Definition Testing.cpp:43
std::string getTestName()
Returns the name of the current test.
Definition Testing.cpp:49
PETSc related utilities.
Definition Petsc.cpp:81
int Rank
Definition Types.hpp:37
T partial_sum(T... args)
T reset(T... args)
T size(T... args)
Represents a ParticipantState in a test.
int size
the amount of ranks this participant runs on
bool initIntraComm
whether to initialize an intra-participant communication for this participant
std::string_view name
the name of the participant
Contains the setup description of a test including participants and requirements.
bool petsc
whether to initialize PETSc
int totalRanks() const
total amount of ranks required by this setup
std::vector< ParticipantState > participants
All known participants.
bool events
whether to initialize events
bool ginkgo
whether to initialize Ginkgo (the device)
void handleOption(ParticipantState participants)
T terminate(T... args)
T to_string(T... args)
T transform(T... args)
T upper_bound(T... args)