preCICE v3.1.1
Loading...
Searching...
No Matches
M2NConfiguration.cpp
Go to the documentation of this file.
2#include <list>
3#include <ostream>
4#include <stdexcept>
10#include "logging/LogMacros.hpp"
13#include "m2n/M2N.hpp"
15#include "utils/Helpers.hpp"
16#include "utils/assertion.hpp"
17#include "utils/networking.hpp"
18#include "xml/ConfigParser.hpp"
19#include "xml/XMLAttribute.hpp"
20
21#ifndef PRECICE_NO_MPI
22#include <mpi.h>
23#endif
24
25namespace precice::m2n {
27{
28 using namespace xml;
29 std::string doc;
31 XMLTag::Occurrence occ = XMLTag::OCCUR_ARBITRARY;
32 {
33 XMLTag tag(*this, "sockets", occ, TAG);
34 doc = "Communication via Sockets.";
35 tag.setDocumentation(doc);
36
37 auto attrPort = makeXMLAttribute("port", 0)
39 "Port number (16-bit unsigned integer) to be used for socket "
40 "communication. The default is \"0\", what means that the OS will "
41 "dynamically search for a free port (if at least one exists) and "
42 "bind it automatically.");
43 tag.addAttribute(attrPort);
44
45 auto attrNetwork = makeXMLAttribute("network", utils::networking::loopbackInterfaceName())
47 "Interface name to be used for socket communication. "
48 "Default is the canonical name of the loopback interface of your platform. "
49 "Might be different on supercomputing systems, e.g. \"ib0\" "
50 "for the InfiniBand on SuperMUC. ");
51 tag.addAttribute(attrNetwork);
52
53 auto attrExchangeDirectory = makeXMLAttribute(ATTR_EXCHANGE_DIRECTORY, "")
55 "Directory where connection information is exchanged. By default, the "
56 "directory of startup is chosen, and both solvers have to be started "
57 "in the same directory.");
58 tag.addAttribute(attrExchangeDirectory);
59 tags.push_back(tag);
60 }
61 {
62 XMLTag tag(*this, "mpi-multiple-ports", occ, TAG);
63 doc = "Communication via MPI with startup in separated communication spaces, using multiple communicators.";
64 tag.setDocumentation(doc);
65
66 auto attrExchangeDirectory = makeXMLAttribute(ATTR_EXCHANGE_DIRECTORY, "")
68 "Directory where connection information is exchanged. By default, the "
69 "directory of startup is chosen, and both solvers have to be started "
70 "in the same directory.");
71 tag.addAttribute(attrExchangeDirectory);
72 tags.push_back(tag);
73 }
74 {
75 XMLTag tag(*this, "mpi", occ, TAG);
76 doc = "Communication via MPI with startup in separated communication spaces, using a single communicator";
77 tag.setDocumentation(doc);
78
79 auto attrExchangeDirectory = makeXMLAttribute(ATTR_EXCHANGE_DIRECTORY, "")
81 "Directory where connection information is exchanged. By default, the "
82 "directory of startup is chosen, and both solvers have to be started "
83 "in the same directory.");
84 tag.addAttribute(attrExchangeDirectory);
85 tags.push_back(tag);
86 }
87
88 XMLAttribute<bool> attrEnforce(ATTR_ENFORCE_GATHER_SCATTER, false);
89 attrEnforce.setDocumentation("Enforce the distributed communication to a gather-scatter scheme. "
90 "Only recommended for trouble shooting.");
91
92 XMLAttribute<bool> attrTwoLevel(ATTR_USE_TWO_LEVEL_INIT, false);
93 attrTwoLevel.setDocumentation("Use a two-level initialization scheme. "
94 "Recommended for large parallel runs (>5000 MPI ranks).");
95
96 auto attrFrom = XMLAttribute<std::string>("acceptor")
97 .setDocumentation(
98 "First participant name involved in communication. For performance reasons, we recommend to use "
99 "the participant with less ranks at the coupling interface as \"acceptor\" in the m2n communication.");
100 auto attrTo = XMLAttribute<std::string>("connector")
101 .setDocumentation("Second participant name involved in communication.");
102
103 for (XMLTag &tag : tags) {
104 tag.addAttribute(attrFrom);
105 tag.addAttribute(attrTo);
106 tag.addAttribute(attrEnforce);
107 tag.addAttribute(attrTwoLevel);
108 parent.addSubtag(tag);
109 }
110}
111
113{
114 for (ConfiguredM2N &conf : _m2ns) {
115 if ((conf.acceptor == acceptor && conf.connector == connector) ||
116 (conf.connector == acceptor && conf.acceptor == connector)) {
117 return conf.m2n;
118 }
119 }
120 PRECICE_ERROR("There is no m2n communication configured between participants \"" + acceptor + "\" and \"" + connector + "\". Please add an appropriate \"<m2n />\" tag.");
121}
122
123bool M2NConfiguration::isM2NConfigured(const std::string &acceptor, const std::string &connector)
124{
126 [acceptor, connector](const auto &conf) {
127 return (conf.acceptor == acceptor && conf.connector == connector) || (conf.connector == acceptor && conf.acceptor == connector);
128 });
129}
130
132{
133 if (tag.getNamespace() == TAG) {
134 std::string acceptor = tag.getStringAttributeValue("acceptor");
135 std::string connector = tag.getStringAttributeValue("connector");
136 checkDuplicates(acceptor, connector);
137 bool enforceGatherScatter = tag.getBooleanAttributeValue(ATTR_ENFORCE_GATHER_SCATTER);
138 bool useTwoLevelInit = tag.getBooleanAttributeValue(ATTR_USE_TWO_LEVEL_INIT);
139
140 if (enforceGatherScatter && useTwoLevelInit) {
141 throw std::runtime_error{std::string{"A gather-scatter m2n communication cannot use two-level initialization. Please switch either "} + "\"" + ATTR_ENFORCE_GATHER_SCATTER + "\" or \"" + ATTR_USE_TWO_LEVEL_INIT + "\" off."};
142 }
143 if (context.size == 1 && useTwoLevelInit) {
144 throw std::runtime_error{"To use two-level initialization, both participants need to run in parallel. If you want to run in serial please switch two-level initialization off."};
145 }
146
149 const std::string tagName = tag.getName();
150 if (tagName == "sockets") {
151 std::string network = tag.getStringAttributeValue("network");
152 int port = tag.getIntAttributeValue("port");
153
154 PRECICE_CHECK(not utils::isTruncated<unsigned short>(port),
155 "The value given for the \"port\" attribute is not a 16-bit unsigned integer: {}", port);
156
158 comFactory = std::make_shared<com::SocketCommunicationFactory>(port, false, network, dir);
159 com = comFactory->newCommunication();
160 } else if (tagName == "mpi-multiple-ports") {
162#ifdef PRECICE_NO_MPI
163 PRECICE_ERROR("Communication type \"mpi-multiple-ports\" can only be used if preCICE was compiled with MPI support enabled. "
164 "Either switch to a \"sockets\" communication or recompile preCICE with \"PRECICE_MPICommunication=ON\".");
165#else
166#ifdef OMPI_MAJOR_VERSION
167 PRECICE_WARN("preCICE was compiled with OpenMPI and configured to use <m2n:mpi-multiple-ports />, which can cause issues in connection build-up. Consider switching to sockets if you encounter problems. Ignore this warning if participants find each other and the simulation starts.");
168#endif
169 comFactory = std::make_shared<com::MPIPortsCommunicationFactory>(dir);
170 com = comFactory->newCommunication();
171#endif
172 } else if (tagName == "mpi") {
174#ifdef PRECICE_NO_MPI
175 PRECICE_ERROR("Communication type \"{}\" can only be used if preCICE was compiled with MPI support enabled. "
176 "Either switch to a \"sockets\" communication or recompile preCICE with \"PRECICE_MPICommunication=ON\".",
177 tagName);
178#else
179#ifdef OMPI_MAJOR_VERSION
180 PRECICE_WARN("preCICE was compiled with OpenMPI and configured to use <m2n:{} />, which can cause issues in connection build-up. Consider switching to sockets if you encounter problems. Ignore this warning if participants find each other and the simulation starts.", tagName);
181#endif
182 comFactory = std::make_shared<com::MPISinglePortsCommunicationFactory>(dir);
183 com = comFactory->newCommunication();
184#endif
185 }
186
187 PRECICE_ASSERT(com.get() != nullptr);
188
190 if (enforceGatherScatter) {
191 distrFactory = std::make_shared<GatherScatterComFactory>(com);
192 } else {
193 distrFactory = std::make_shared<PointToPointComFactory>(comFactory);
194 }
195 PRECICE_ASSERT(distrFactory.get() != nullptr);
196
197 _m2ns.emplace_back(ConfiguredM2N{
198 std::make_shared<m2n::M2N>(com, distrFactory, false, useTwoLevelInit),
199 acceptor,
200 connector});
201 }
202}
203
205 const std::string &acceptor,
206 const std::string &connector)
207{
208 using std::get;
209 bool alreadyAdded = false;
210 for (ConfiguredM2N &conf : _m2ns) {
211 alreadyAdded |= conf.acceptor == acceptor && conf.connector == connector;
212 alreadyAdded |= conf.connector == acceptor && conf.acceptor == connector;
213 }
214 PRECICE_CHECK(!alreadyAdded, "Multiple m2n communications between participant \"" + acceptor + "\" and \"" + connector + "\" are not allowed. Please remove redundant <m2n /> tags between them.");
215}
216
217} // namespace precice::m2n
#define PRECICE_ERROR(...)
Definition LogMacros.hpp:15
#define PRECICE_WARN(...)
Definition LogMacros.hpp:11
#define PRECICE_CHECK(check,...)
Definition LogMacros.hpp:35
T any_of(T... args)
#define PRECICE_ASSERT(...)
Definition assertion.hpp:87
T begin(T... args)
const std::string ATTR_EXCHANGE_DIRECTORY
bool isM2NConfigured(const std::string &acceptor, const std::string &connector)
std::vector< ConfiguredM2N > _m2ns
const std::string ATTR_USE_TWO_LEVEL_INIT
m2n::PtrM2N getM2N(const std::string &acceptor, const std::string &connector)
Returns the communication object for the given user names.
virtual void xmlTagCallback(const xml::ConfigurationContext &context, xml::XMLTag &callingTag)
Callback at begin of XML tag.
M2NConfiguration(xml::XMLTag &parent)
void checkDuplicates(const std::string &acceptor, const std::string &connector)
const std::string ATTR_ENFORCE_GATHER_SCATTER
XMLAttribute & setDocumentation(std::string documentation)
Sets a documentation string for the attribute.
Represents an XML tag to be configured automatically.
Definition XMLTag.hpp:31
const std::string & getNamespace() const
Returns xml namespace.
Definition XMLTag.hpp:159
std::string getStringAttributeValue(const std::string &name, std::optional< std::string > default_value=std::nullopt) const
Definition XMLTag.cpp:142
bool getBooleanAttributeValue(const std::string &name, std::optional< bool > default_value=std::nullopt) const
Definition XMLTag.cpp:155
const std::string & getName() const
Returns name (without namespace).
Definition XMLTag.hpp:153
int getIntAttributeValue(const std::string &name, std::optional< int > default_value=std::nullopt) const
Definition XMLTag.cpp:129
XMLTag & addSubtag(const XMLTag &tag)
Adds an XML tag as subtag by making a copy of the given tag.
Definition XMLTag.cpp:41
T end(T... args)
T get(T... args)
contains the logic of the parallel communication between participants.
Definition BoundM2N.cpp:12
std::string loopbackInterfaceName()
Returns the name of the canonical loopback interface on this system.
Definition networking.cpp:5
T push_back(T... args)
Tightly coupled to the parameters of Participant()
Definition XMLTag.hpp:24