preCICE v3.1.1
Loading...
Searching...
No Matches
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"
19#include "mesh/Data.hpp"
22#include "query/Index.hpp"
24#include "testing/Testing.hpp"
25#include "utils/IntraComm.hpp"
26#include "utils/Parallel.hpp"
27#include "utils/Petsc.hpp"
28
29namespace precice::testing {
30
32
34{
35 if (!invalid && _petsc) {
37 }
38 if (!invalid) {
39 // Always clean up tests.
41 }
42 if (!invalid && _initIntraComm) {
45 }
46
47 // Reset communicators
50}
51
53{
55 auto dir = location.parent_path();
56 dir /= filename;
58}
59
61{
62 return prefix(testing::getTestName() + ".xml");
63}
64
65bool TestContext::hasSize(int size) const
66{
67 return this->size == size;
68}
69
71{
72 if (std::find(_names.begin(), _names.end(), name) == _names.end()) {
73 throw std::runtime_error("The requested name \"" + name + "\" does not exist!");
74 }
75 return this->name == name;
76}
77
78bool TestContext::isRank(Rank rank) const
79{
80 if (rank >= size) {
81 throw std::runtime_error("The requested Rank does not exist!");
82 }
83 return this->rank == rank;
84}
85
87{
88 return isRank(0);
89}
90
92{
93 using testing::Require;
94 switch (requirement) {
95 case Require::PETSc:
96 _petsc = true;
97 _events = true;
98 break;
99 case Require::Events:
100 _events = true;
101 break;
102 default:
104 }
105}
106
108{
109 if (_simple) {
111 }
112 // @TODO add check if name already registered
113 _names.push_back(participant.name);
114 participants.emplace_back(std::move(participant));
115}
116
118{
119 this->name = p.name;
120 this->size = p.size;
123 this->rank = this->_contextComm->rank();
124}
125
126void TestContext::initialize(const Participants &participants)
127{
128 Par::Parallel::CommState::world()->synchronize();
129 initializeMPI(participants);
130 Par::Parallel::CommState::world()->synchronize();
134}
135
137{
138 auto baseComm = Par::current();
139 const int globalRank = baseComm->rank();
140 const int available = baseComm->size();
141
142 // groups contain the accumulated sizes of previous groups
143 std::vector<int> groups(participants.size());
144 std::transform(participants.begin(), participants.end(), groups.begin(), [](const auto &p) { return p.size; });
145 std::partial_sum(groups.begin(), groups.end(), groups.begin());
146
147 // Check if there are enough ranks available
148 auto required = groups.back();
149 if (required > available) {
150 throw std::runtime_error{"This test requests " + std::to_string(required) + " ranks, but there are only " + std::to_string(available) + " available"};
151 }
152
153 // Check if this rank isn't needed
154 if (globalRank >= required) {
155 Par::splitCommunicator(); // No group
156 invalid = true;
157 return;
158 }
159
160 // Find the participant this rank is assigned to
161 auto position = std::upper_bound(groups.begin(), groups.end(), globalRank);
162 auto participant = std::distance(groups.begin(), position);
163 Par::splitCommunicator(participant);
164 setContextFrom(participants[participant]);
165}
166
168{
169 if (invalid)
170 return;
171
172 // Establish a consistent state for all tests
177
178 if (!_initIntraComm || hasSize(1))
179 return;
180
181#ifndef PRECICE_NO_MPI
183#else
185#endif
186
187 intraComm->connectIntraComm(name, "", rank, size);
188
189 utils::IntraComm::getCommunication() = std::move(intraComm);
190}
191
193{
194 if (invalid) {
195 return;
196 }
197 // Always initialize the events
199 er.initialize(name, rank, size);
200 if (_events) { // Enable them if they are requested
202 er.setDirectory("./precice-profiling");
203 } else {
205 }
206 er.startBackend();
207}
208
215
216m2n::PtrM2N TestContext::connectPrimaryRanks(const std::string &acceptor, const std::string &requestor, const ConnectionOptions &options) const
217{
218 auto participantCom = com::PtrCommunication(new com::SocketCommunication());
219
221 switch (options.type) {
223 distrFactory.reset(new m2n::GatherScatterComFactory(participantCom));
224 break;
227 break;
228 default:
229 throw std::runtime_error{"ConnectionType unknown"};
230 };
231 auto m2n = m2n::PtrM2N(new m2n::M2N(participantCom, distrFactory, options.useOnlyPrimaryCom, options.useTwoLevelInit));
232
233 if (std::find(_names.begin(), _names.end(), acceptor) == _names.end()) {
234 throw std::runtime_error{
235 "Acceptor \"" + acceptor + "\" not defined in this context."};
236 }
237 if (std::find(_names.begin(), _names.end(), requestor) == _names.end()) {
238 throw std::runtime_error{
239 "Requestor \"" + requestor + "\" not defined in this context."};
240 }
241
242 if (isNamed(acceptor)) {
243 m2n->acceptPrimaryRankConnection(acceptor, requestor);
244 } else if (isNamed(requestor)) {
245 m2n->requestPrimaryRankConnection(acceptor, requestor);
246 } else {
247 throw std::runtime_error{"You try to connect " + acceptor + " and " + requestor + ", but this context is named " + name};
248 }
249 return m2n;
250}
251
253{
254 if (invalid)
255 return "This test context is invalid!";
256
258 os << "Test context";
259 if (name.empty()) {
260 os << " is unnamed";
261 } else {
262 os << " represents \"" << name << '"';
263 }
264 os << " and runs on rank " << rank << " out of " << size << '.';
265
266 if (_initIntraComm || _events || _petsc) {
267 os << " Initialized: {";
268 if (_initIntraComm)
269 os << " IntraComm Communication ";
270 if (_events)
271 os << " Events";
272 if (_petsc)
273 os << " PETSc";
274 os << '}';
275 }
276 return os.str();
277}
278
279} // namespace precice::testing
std::string prefix
std::string name
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.
M2N communication class. This layer is necessary since communication between two participants can be ...
Definition M2N.hpp:31
static EventRegistry & instance()
Returns the only instance (singleton) of the EventRegistry class.
void finalize()
Sets the global end time and flushes buffers.
void handleOption(Participants &participants, ParticipantState participant)
bool _petsc
whether to initialize PETSc
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 to initialize an intra-participant connection
bool _simple
whether this Context was created with a Ranks constructor
m2n::PtrM2N connectPrimaryRanks(const std::string &acceptor, const std::string &requestor, const ConnectionOptions &options=ConnectionOptions{}) const
void initializePetsc()
Initialize PETSc if required.
bool invalid
whether this context is valid or not
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 _events
whether to initialize events
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.
std::vector< std::string > _names
contains the name of every known Participant
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)
std::string config() const
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:98
static void initialize(utils::Parallel::Communicator comm)
Initializes the Petsc environment.
Definition Petsc.cpp:78
T distance(T... args)
T emplace_back(T... args)
T empty(T... args)
T end(T... args)
T find(T... args)
std::shared_ptr< Communication > PtrCommunication
void setMPIRank(int const rank)
void setParticipant(std::string const &participant)
std::shared_ptr< M2N > PtrM2N
contains the testing framework.
Definition helper.hpp:9
@ PETSc
Require to initialize PETSc. This implies the initialization of Events.
@ Events
Require to initialize Event.
std::string getTestPath()
Returns the full path to the file containing the current test.
Definition Testing.cpp:41
std::string getTestName()
Returns the name of the current test.
Definition Testing.cpp:47
int Rank
Definition Types.hpp:37
T partial_sum(T... args)
T push_back(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
std::string name
the name of the participant
bool initIntraComm
whether to initialize an intra-participant communication for this participant
T terminate(T... args)
T to_string(T... args)
T transform(T... args)
T upper_bound(T... args)