preCICE v3.1.1
Loading...
Searching...
No Matches
ParticipantConfiguration.cpp
Go to the documentation of this file.
2#include <algorithm>
3#include <boost/range/adaptor/transformed.hpp>
4#include <list>
5#include <memory>
6#include <stdexcept>
7#include <utility>
8
9#include "action/Action.hpp"
12#include "com/SharedPointer.hpp"
14#include "io/ExportCSV.hpp"
15#include "io/ExportContext.hpp"
16#include "io/ExportVTK.hpp"
17#include "io/ExportVTP.hpp"
18#include "io/ExportVTU.hpp"
19#include "io/SharedPointer.hpp"
21#include "logging/LogMacros.hpp"
22#include "mapping/Mapping.hpp"
23#include "mesh/Data.hpp"
24#include "mesh/Mesh.hpp"
32#include "utils/IntraComm.hpp"
33#include "utils/assertion.hpp"
34#include "utils/networking.hpp"
35#include "xml/ConfigParser.hpp"
36#include "xml/XMLAttribute.hpp"
37
38namespace precice::config {
39
41 xml::XMLTag & parent,
42 mesh::PtrMeshConfiguration meshConfiguration)
43 : _meshConfig(std::move(meshConfiguration))
44{
46 using namespace xml;
47 std::string doc;
48 XMLTag tag(*this, TAG, XMLTag::OCCUR_ONCE_OR_MORE);
49 doc = "Represents one solver using preCICE. At least two ";
50 doc += "participants have to be defined.";
51 tag.setDocumentation(doc);
52
53 auto attrName = XMLAttribute<std::string>(ATTR_NAME)
54 .setDocumentation(
55 "Name of the participant. Has to match the name given on construction "
56 "of the precice::Participant object used by the participant.");
57 tag.addAttribute(attrName);
58
59 XMLTag tagWriteData(*this, TAG_WRITE, XMLTag::OCCUR_ARBITRARY);
60 doc = "Sets data to be written by the participant to preCICE. ";
61 doc += "Data is defined by using the <data> tag.";
62 tagWriteData.setDocumentation(doc);
63 XMLTag tagReadData(*this, TAG_READ, XMLTag::OCCUR_ARBITRARY);
64 doc = "Sets data to be read by the participant from preCICE. ";
65 doc += "Data is defined by using the <data> tag.";
66 tagReadData.setDocumentation(doc);
67 auto attrDataName = XMLAttribute<std::string>(ATTR_NAME)
68 .setDocumentation("Name of the data.");
69 tagWriteData.addAttribute(attrDataName);
70 tagReadData.addAttribute(attrDataName);
71 auto attrMesh = XMLAttribute<std::string>(ATTR_MESH)
72 .setDocumentation(
73 "Mesh the data belongs to. If data should be read/written to several "
74 "meshes, this has to be specified separately for each mesh.");
75 tagWriteData.addAttribute(attrMesh);
76 tagReadData.addAttribute(attrMesh);
77
78 tag.addSubtag(tagWriteData);
79 tag.addSubtag(tagReadData);
80
81 _mappingConfig = std::make_shared<mapping::MappingConfiguration>(
82 tag, _meshConfig);
83
84 _actionConfig = std::make_shared<action::ActionConfiguration>(
85 tag, _meshConfig);
86
87 _exportConfig = std::make_shared<io::ExportConfiguration>(tag);
88
89 XMLTag tagWatchPoint(*this, TAG_WATCH_POINT, XMLTag::OCCUR_ARBITRARY);
90 doc = "A watch point can be used to follow the transient changes of data ";
91 doc += "and mesh vertex coordinates at a given point";
92 tagWatchPoint.setDocumentation(doc);
93 doc = "Name of the watch point. Is taken in combination with the participant ";
94 doc += "name to construct the filename the watch point data is written to.";
95 attrName.setDocumentation(doc);
96 tagWatchPoint.addAttribute(attrName);
97 doc = "Mesh to be watched.";
98 attrMesh.setDocumentation(doc);
99 tagWatchPoint.addAttribute(attrMesh);
100 auto attrCoordinate = XMLAttribute<Eigen::VectorXd>(ATTR_COORDINATE)
101 .setDocumentation(
102 "The coordinates of the watch point. If the watch point is not put exactly "
103 "on the mesh to observe, the closest projection of the point onto the "
104 "mesh is considered instead, and values/coordinates are interpolated "
105 "linearly to that point.");
106 tagWatchPoint.addAttribute(attrCoordinate);
107 tag.addSubtag(tagWatchPoint);
108
109 auto attrScaleWitConn = XMLAttribute<bool>(ATTR_SCALE_WITH_CONN)
110 .setDocumentation("Whether the vertex data is scaled with the element area before "
111 "summing up or not. In 2D, vertex data is scaled with the average length of "
112 "neighboring edges. In 3D, vertex data is scaled with the average surface of "
113 "neighboring triangles. If false, vertex data is directly summed up.");
114 XMLTag tagWatchIntegral(*this, TAG_WATCH_INTEGRAL, XMLTag::OCCUR_ARBITRARY);
115 doc = "A watch integral can be used to follow the transient change of integral data ";
116 doc += "and surface area for a given coupling mesh.";
117 tagWatchIntegral.setDocumentation(doc);
118 doc = "Name of the watch integral. Is taken in combination with the participant ";
119 doc += "name to construct the filename the watch integral data is written to.";
120 attrName.setDocumentation(doc);
121 tagWatchIntegral.addAttribute(attrName);
122 doc = "Mesh to be watched.";
123 attrMesh.setDocumentation(doc);
124 tagWatchIntegral.addAttribute(attrMesh);
125 tagWatchIntegral.addAttribute(attrScaleWitConn);
126 tag.addSubtag(tagWatchIntegral);
127
128 XMLTag tagProvideMesh(*this, TAG_PROVIDE_MESH, XMLTag::OCCUR_ARBITRARY);
129 doc = "Provide a mesh (see tag <mesh>) to other participants.";
130 tagProvideMesh.setDocumentation(doc);
131 attrName.setDocumentation("Name of the mesh to provide.");
132 tagProvideMesh.addAttribute(attrName);
133 tag.addSubtag(tagProvideMesh);
134
135 XMLTag tagReceiveMesh(*this, TAG_RECEIVE_MESH, XMLTag::OCCUR_ARBITRARY);
136 doc = "Makes a remote mesh (see tag <mesh>) available to this participant.";
137 tagReceiveMesh.setDocumentation(doc);
138 attrName.setDocumentation("Name of the mesh to receive.");
139 tagReceiveMesh.addAttribute(attrName);
140 auto attrFrom = XMLAttribute<std::string>(ATTR_FROM)
141 .setDocumentation("The name of the participant to receive the mesh from. "
142 "This participant needs to provide the mesh using <provide-mesh />.");
143 tagReceiveMesh.addAttribute(attrFrom);
144 auto attrSafetyFactor = makeXMLAttribute(ATTR_SAFETY_FACTOR, 0.5)
146 "If a mesh is received from another partipant (see tag <from>), it needs to be"
147 "decomposed at the receiving participant. To speed up this process, "
148 "a geometric filter (see tag <geometric-filter>), i.e. filtering by bounding boxes around the local mesh, can be used. "
149 "This safety factor defines by which factor this local information is "
150 "increased. An example: 0.5 means that the bounding box is 150% of its original size.");
151 tagReceiveMesh.addAttribute(attrSafetyFactor);
152
153 auto attrGeoFilter = XMLAttribute<std::string>(ATTR_GEOMETRIC_FILTER)
155 "If a mesh is received from another partipant (see tag <from>), it needs to be"
156 "decomposed at the receiving participant. To speed up this process, "
157 "a geometric filter, i.e. filtering by bounding boxes around the local mesh, can be used. "
158 "Two different variants are implemented: a filter \"on-primary\" strategy, "
159 "which is beneficial for a huge mesh and a low number of processors, and a filter "
160 "\"on-secondary\" strategy, which performs better for a very high number of "
161 "processors. Both result in the same distribution (if the safety factor is sufficiently large). "
162 "\"on-primary\" is not supported if you use two-level initialization. "
163 "For very asymmetric cases, the filter can also be switched off completely (\"no-filter\").")
165 .setDefaultValue(VALUE_FILTER_ON_SECONDARY_RANKS);
166 tagReceiveMesh.addAttribute(attrGeoFilter);
167
168 auto attrDirectAccess = makeXMLAttribute(ATTR_DIRECT_ACCESS, false)
170 "If a mesh is received from another partipant (see tag <from>), it needs to be"
171 "decomposed at the receiving participant. In case a mapping is defined, the "
172 "mesh is decomposed according to the local provided mesh associated to the mapping. "
173 "In case no mapping has been defined (you want to access "
174 "the mesh and related data direct), there is no obvious way on how to decompose the "
175 "mesh, since no mesh needs to be provided by the participant. For this purpose, bounding "
176 "boxes can be defined (see API function \"setMeshAccessRegion\") and used by selecting "
177 "the option direct-access=\"true\".");
178 tagReceiveMesh.addAttribute(attrDirectAccess);
179
180 tag.addSubtag(tagReceiveMesh);
181
182 std::list<XMLTag> intraCommTags;
183 XMLTag::Occurrence intraCommOcc = XMLTag::OCCUR_NOT_OR_ONCE;
184 {
185 XMLTag tagIntraComm(*this, "sockets", intraCommOcc, TAG_INTRA_COMM);
186 doc = "A solver in parallel needs a communication between its ranks. ";
187 doc += "By default, the participant's MPI_COM_WORLD is reused.";
188 doc += "Use this tag to use TCP/IP sockets instead.";
189 tagIntraComm.setDocumentation(doc);
190
191 auto attrPort = makeXMLAttribute("port", 0)
193 "Port number (16-bit unsigned integer) to be used for socket "
194 "communication. The default is \"0\", what means that OS will "
195 "dynamically search for a free port (if at least one exists) and "
196 "bind it automatically.");
197 tagIntraComm.addAttribute(attrPort);
198
199 auto attrNetwork = makeXMLAttribute(ATTR_NETWORK, utils::networking::loopbackInterfaceName())
201 "Interface name to be used for socket communication. "
202 "Default is the canonical name of the loopback interface of your platform. "
203 "Might be different on supercomputing systems, e.g. \"ib0\" "
204 "for the InfiniBand on SuperMUC. ");
205 tagIntraComm.addAttribute(attrNetwork);
206
207 auto attrExchangeDirectory = makeXMLAttribute(ATTR_EXCHANGE_DIRECTORY, "")
209 "Directory where connection information is exchanged. By default, the "
210 "directory of startup is chosen.");
211 tagIntraComm.addAttribute(attrExchangeDirectory);
212
213 intraCommTags.push_back(tagIntraComm);
214 }
215 {
216 XMLTag tagIntraComm(*this, "mpi", intraCommOcc, TAG_INTRA_COMM);
217 doc = "A solver in parallel needs a communication between its ranks. ";
218 doc += "By default, the participant's MPI_COM_WORLD is reused.";
219 doc += "Use this tag to use MPI with separated communication spaces instead instead.";
220 tagIntraComm.setDocumentation(doc);
221
222 auto attrExchangeDirectory = makeXMLAttribute(ATTR_EXCHANGE_DIRECTORY, "")
224 "Directory where connection information is exchanged. By default, the "
225 "directory of startup is chosen.");
226 tagIntraComm.addAttribute(attrExchangeDirectory);
227
228 intraCommTags.push_back(tagIntraComm);
229 }
230
231 for (XMLTag &tagIntraComm : intraCommTags) {
232 tag.addSubtag(tagIntraComm);
233 }
234 parent.addSubtag(tag);
235}
236
238 bool experimental)
239{
240 _experimental = experimental;
241 _mappingConfig->setExperimental(_experimental);
242}
243
245 const xml::ConfigurationContext &context,
246 xml::XMLTag & tag)
247{
248 PRECICE_TRACE(tag.getName());
249 if (tag.getName() == TAG) {
252 _participants.push_back(p);
253 } else if (tag.getName() == TAG_PROVIDE_MESH) {
255
256 mesh::PtrMesh mesh = _meshConfig->getMesh(name);
257 PRECICE_CHECK(mesh,
258 R"(Participant "{}" attempts to provide an unknown mesh "{}". <mesh name="{}"> needs to be defined first.)",
259 _participants.back()->getName(), name, name);
260 _participants.back()->provideMesh(mesh);
261 } else if (tag.getName() == TAG_RECEIVE_MESH) {
264 double safetyFactor = tag.getDoubleAttributeValue(ATTR_SAFETY_FACTOR);
266 const bool allowDirectAccess = tag.getBooleanAttributeValue(ATTR_DIRECT_ACCESS);
267
268 // Start with defining the mesh
269 mesh::PtrMesh mesh = _meshConfig->getMesh(name);
270 PRECICE_CHECK(mesh,
271 R"(Participant "{}" attempts to provide an unknown mesh "{}". <mesh name="{}"> needs to be defined first.)",
272 _participants.back()->getName(), name, name);
273
274 // Then check the attributes
275 PRECICE_CHECK(!from.empty(),
276 R"(Participant "{}" receives mesh "{}", but doesn't specify where from. )"
277 "Please add the name of the other participant to the receive-mesh tag: <receive-mesh name=\"{}\" from=\"(other participant)\" ... />",
278 context.name, name, name);
279
280 PRECICE_CHECK(_participants.back()->getName() != from,
281 "Participant \"{}\" cannot receive mesh \"{}\" from itself. "
282 "To provide a mesh, use <provide-mesh name=\"{}\" /> instead.",
283 context.name, name, name);
284
285 PRECICE_CHECK(safetyFactor >= 0,
286 "Participant \"{}\" receives mesh \"{}\" with safety-factor=\"{}\". "
287 "Please use a positive or zero safety-factor instead.",
288 context.name, name, safetyFactor);
289
290 _participants.back()->receiveMesh(mesh, from, safetyFactor, geoFilter, allowDirectAccess);
291 } else if (tag.getName() == TAG_WRITE) {
292 const std::string &dataName = tag.getStringAttributeValue(ATTR_NAME);
294 mesh::PtrMesh mesh = _meshConfig->getMesh(meshName);
295 PRECICE_CHECK(mesh,
296 R"(Participant "{}" attempts to read data "{}" from an unknown mesh "{}". <mesh name="{}"> needs to be defined first.)",
297 _participants.back()->getName(), dataName, meshName, meshName);
298 mesh::PtrData data = getData(mesh, dataName);
299 _participants.back()->addWriteData(data, mesh);
300 } else if (tag.getName() == TAG_READ) {
301 const std::string &dataName = tag.getStringAttributeValue(ATTR_NAME);
303 mesh::PtrMesh mesh = _meshConfig->getMesh(meshName);
304 PRECICE_CHECK(mesh,
305 R"(Participant "{}" attempts to write data "{}" to an unknown mesh "{}". <mesh name="{}"> needs to be defined first.)",
306 _participants.back()->getName(), dataName, meshName, meshName);
307 mesh::PtrData data = getData(mesh, dataName);
308 _participants.back()->addReadData(data, mesh);
309 } else if (tag.getName() == TAG_WATCH_POINT) {
310 WatchPointConfig config;
313 config.coordinates = tag.getEigenVectorXdAttributeValue(ATTR_COORDINATE, _meshConfig->getMesh(config.nameMesh)->getDimensions());
314 _watchPointConfigs.push_back(config);
315 } else if (tag.getName() == TAG_WATCH_INTEGRAL) {
316 WatchIntegralConfig config;
320 _watchIntegralConfigs.push_back(config);
321 } else if (tag.getNamespace() == TAG_INTRA_COMM) {
324 _isIntraCommDefined = true;
325 _participants.back()->setUsePrimaryRank(true);
326 }
327}
328
330 const xml::ConfigurationContext &context,
331 xml::XMLTag & tag)
332{
333 if (tag.getName() == TAG) {
335 }
336}
337
343
345{
346 auto participant = std::find_if(_participants.begin(), _participants.end(), [&participantName](const auto &p) { return p->getName() == participantName; });
347 PRECICE_ASSERT(participant != _participants.end(), "Did not find participant \"{}\"", participantName);
348
349 return *participant;
350}
351
353{
354 auto range = _participants | boost::adaptors::transformed([](auto &p) { return p->getName(); });
355 return {range.begin(), range.end()};
356}
357
359{
360 return std::any_of(_participants.begin(), _participants.end(), [name](auto &p) { return p->getName() == name; });
361}
362
364{
365 PRECICE_ASSERT(!hasParticipant(wrongName));
366
367 const auto names = knownParticipants();
368 const auto matches = utils::computeMatches(wrongName, names);
369
370 // Typo detection
371 if (matches.front().distance < 3) {
372 return fmt::format("Did you mean: \"{}\"?", matches.front().name);
373 }
374
375 return fmt::format("Available participants are: {}.", fmt::join(names, ", "));
376}
377
389
391 const mesh::PtrMesh &mesh,
392 const std::string & nameData) const
393{
394 PRECICE_CHECK(mesh->hasDataName(nameData),
395 "Participant \"{}\" asks for data \"{}\" from mesh \"{}\", but this mesh does not use such data. "
396 "Please add a use-data tag with name=\"{}\" to this mesh.",
397 _participants.back()->getName(), nameData, mesh->getName(), nameData);
398 return mesh->data(nameData);
399}
400
402 const xml::ConfigurationContext &context,
403 const impl::PtrParticipant & participant)
404{
405 PRECICE_TRACE(participant->getName());
406
407 // Set input/output meshes for data mappings and mesh requirements
409 for (const ConfMapping &confMapping : _mappingConfig->mappings()) {
410
411 checkIllDefinedMappings(confMapping, participant);
412
413 auto fromMesh = confMapping.fromMesh->getName();
414 auto toMesh = confMapping.toMesh->getName();
415
416 if (confMapping.direction == mapping::MappingConfiguration::Direction::READ) {
418 PRECICE_CHECK(participant->isMeshReceived(fromMesh),
419 "Participant \"{}\" has a read mapping from mesh \"{}\", without receiving it. "
420 "Please add a receive-mesh tag with name=\"{}\"",
421 participant->getName(), fromMesh, fromMesh);
422 PRECICE_CHECK(participant->isMeshProvided(toMesh),
423 "Participant \"{}\" has a read mapping to mesh \"{}\", without providing it. "
424 "Please add a provide-mesh tag with name=\"{}\"",
425 participant->getName(), toMesh, toMesh);
426 } else {
427 // A write mapping maps from provided to received
428 PRECICE_CHECK(participant->isMeshProvided(fromMesh),
429 "Participant \"{}\" has a write mapping from mesh \"{}\", without providing it. "
430 "Please add a provided-mesh tag with name=\"{}\"",
431 participant->getName(), fromMesh, fromMesh);
432 PRECICE_CHECK(participant->isMeshReceived(toMesh),
433 "Participant \"{}\" has a write mapping to mesh \"{}\", without receiving it. "
434 "Please add a receive-mesh tag with name=\"{}\"",
435 participant->getName(), toMesh, toMesh);
436 }
437
438 if (context.size > 1 && context.name == participant->getName()) {
439 if ((confMapping.direction == mapping::MappingConfiguration::WRITE &&
440 confMapping.mapping->getConstraint() == mapping::Mapping::CONSISTENT) ||
441 (confMapping.direction == mapping::MappingConfiguration::READ &&
442 confMapping.mapping->getConstraint() == mapping::Mapping::CONSERVATIVE)) {
443 PRECICE_ERROR("For a parallel participant, only the mapping combinations read-consistent and write-conservative are allowed");
444 } else if (confMapping.mapping->isScaledConsistent()) {
445 PRECICE_ERROR("Scaled consistent mapping is not yet supported for a parallel participant. "
446 "You could run in serial or use a plain (read-)consistent mapping instead.");
447 }
448 }
449
450 const auto & fromMeshID = confMapping.fromMesh->getID();
451 const auto & toMeshID = confMapping.toMesh->getID();
452 impl::MeshContext &fromMeshContext = participant->meshContext(fromMesh);
453 impl::MeshContext &toMeshContext = participant->meshContext(toMesh);
454
455 if (confMapping.direction == mapping::MappingConfiguration::READ) {
456 PRECICE_CHECK(toMeshContext.provideMesh,
457 "A read mapping of participant \"{}\" needs to map TO a provided mesh. Mesh \"{1}\" is not provided. "
458 "Please add the tag <provide-mesh name=\"{1}\" /> to the participant.",
459 participant->getName(), confMapping.toMesh->getName());
460 PRECICE_CHECK(not fromMeshContext.receiveMeshFrom.empty(),
461 "A read mapping of participant \"{}\" needs to map FROM a received mesh. Mesh \"{1}\" is not received. "
462 "Please add the tag <receive-mesh name=\"{1}\" /> to the participant.",
463 participant->getName(), confMapping.toMesh->getName());
464 } else {
465 PRECICE_CHECK(fromMeshContext.provideMesh,
466 "A write mapping of participant \"{}\" needs to map FROM a provided mesh. Mesh \"{1}\" is not provided. "
467 "Please add the tag <provide-mesh name=\"{1}\" /> to the participant.",
468 participant->getName(), confMapping.fromMesh->getName());
469 PRECICE_CHECK(not toMeshContext.receiveMeshFrom.empty(),
470 "A write mapping of participant \"{}\" needs to map TO a received mesh. Mesh \"{1}\" is not received. "
471 "Please add the tag <receive-mesh name=\"{1}\" /> to the participant.",
472 participant->getName(), confMapping.toMesh->getName());
473 }
474
475 // @TODO: is this still correct?
476 if (confMapping.requiresBasisFunction) {
479 }
480
481 precice::impl::MappingContext mappingContext;
482 mappingContext.fromMeshID = fromMeshID;
483 mappingContext.toMeshID = toMeshID;
484
485 mapping::PtrMapping &map = mappingContext.mapping;
486 PRECICE_ASSERT(map.get() == nullptr);
487 map = confMapping.mapping;
488 mappingContext.configuredWithAliasTag = confMapping.configuredWithAliasTag;
489
490 const mesh::PtrMesh &input = fromMeshContext.mesh;
491 const mesh::PtrMesh &output = toMeshContext.mesh;
492 PRECICE_DEBUG("Configure mapping for input={}, output={}", input->getName(), output->getName());
493 map->setMeshes(input, output);
494
495 if (confMapping.direction == mapping::MappingConfiguration::WRITE) {
496 participant->addWriteMappingContext(mappingContext);
497 } else {
498 PRECICE_ASSERT(confMapping.direction == mapping::MappingConfiguration::READ);
499 participant->addReadMappingContext(mappingContext);
500 }
501
502 fromMeshContext.meshRequirement = std::max(
503 fromMeshContext.meshRequirement, map->getInputRequirement());
504 toMeshContext.meshRequirement = std::max(
505 toMeshContext.meshRequirement, map->getOutputRequirement());
506
507 fromMeshContext.fromMappingContexts.push_back(mappingContext);
508 toMeshContext.toMappingContexts.push_back(mappingContext);
509 }
510 _mappingConfig->resetMappings();
511
512 // Iterate over all write mappings
513 for (impl::MappingContext &mappingContext : participant->writeMappingContexts()) {
514 // Check, whether we can find a corresponding write data context
515 bool dataFound = false;
516 for (auto &dataContext : participant->writeDataContexts()) {
517 // First we look for the "from" mesh ID
518 const int fromMeshID = dataContext.getMeshID();
519 if (mappingContext.fromMeshID == fromMeshID) {
520 // Second we look for the "to" mesh ID
521 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getOutputMesh()->getName());
522 // If this is true, we actually found a proper configuration
523 // If it is false, we look for another "from" mesh ID, because we might have multiple read and write mappings
524 if (meshContext.mesh->hasDataName(dataContext.getDataName())) {
525 // Check, if the fromMesh is a provided mesh
526 PRECICE_CHECK(participant->isMeshProvided(dataContext.getMeshName()),
527 "Participant \"{}\" has to provide mesh \"{}\" to be able to write data to it. "
528 "Please add a provide-mesh node with name=\"{}\".",
529 participant->getName(), dataContext.getMeshName(), dataContext.getMeshName());
530 dataContext.appendMappingConfiguration(mappingContext, meshContext);
531 // Enable gradient data if required
532 if (mappingContext.mapping->requiresGradientData() == true) {
533 mappingContext.requireGradientData(dataContext.getDataName());
534 }
535 dataFound = true;
536 }
537 }
538 }
539 PRECICE_CHECK(dataFound,
540 "Participant \"{}\" defines a write mapping from mesh \"{}\" to mesh \"{}\", "
541 "but there is either no corresponding write-data tag or the meshes used "
542 "by this participant lack the necessary use-data tags.",
543 participant->getName(), mappingContext.mapping->getInputMesh()->getName(), mappingContext.mapping->getOutputMesh()->getName());
544 }
545
546 // Iterate over all read mappings
547 for (impl::MappingContext &mappingContext : participant->readMappingContexts()) {
548 // Check, weather we can find a corresponding read data context
549 bool dataFound = false;
550 for (auto &dataContext : participant->readDataContexts()) {
551 // First we look for the "to" mesh ID
552 const int toMeshID = dataContext.getMeshID();
553 if (mappingContext.toMeshID == toMeshID) {
554 // Second we look for the "from" mesh ID
555 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getInputMesh()->getName());
556 // If this is true, we actually found a proper configuration
557 // If it is false, we look for another "from" mesh ID, because we might have multiple read and write mappings
558 if (meshContext.mesh->hasDataName(dataContext.getDataName())) {
559 // Check, if the toMesh is a provided mesh
560 PRECICE_CHECK(participant->isMeshProvided(dataContext.getMeshName()),
561 "Participant \"{}\" has to provide mesh \"{}\" in order to read data from it. "
562 "Please add a provide-mesh node with name=\"{}\".",
563 participant->getName(), dataContext.getMeshName(), dataContext.getMeshName());
564 dataContext.appendMappingConfiguration(mappingContext, meshContext);
565 // Enable gradient data if required
566 if (mappingContext.mapping->requiresGradientData() == true) {
567 mappingContext.requireGradientData(dataContext.getDataName());
568 }
569 dataFound = true;
570 }
571 }
572 }
573 PRECICE_CHECK(dataFound,
574 "Participant \"{}\" defines a read mapping from mesh \"{}\" to mesh \"{}\", "
575 "but there is either no corresponding read-data tag or the meshes used "
576 "by this participant lack the necessary use-data tags.",
577 participant->getName(), mappingContext.mapping->getInputMesh()->getName(), mappingContext.mapping->getOutputMesh()->getName());
578 }
579
580 // Add actions
581 for (const action::PtrAction &action : _actionConfig->actions()) {
582 bool used = _participants.back()->isMeshUsed(action->getMesh()->getName());
583 PRECICE_CHECK(used,
584 "Data action of participant \"{}\" uses mesh \"{}\", which is not used by the participant. "
585 "Please add a provide-mesh or receive-mesh node with name=\"{}\".",
586 _participants.back()->getName(), action->getMesh()->getName(), action->getMesh()->getName());
587 }
588 for (action::PtrAction &action : _actionConfig->extractActions()) {
589 _participants.back()->addAction(std::move(action));
590 }
591
592 // Add export contexts
593 for (io::ExportContext &exportContext : _exportConfig->exportContexts()) {
594 io::PtrExport exporter;
595 if (exportContext.type == VALUE_VTK) {
596 // This is handled with respect to the current configuration context.
597 // Hence, this is potentially wrong for every participant other than context.name.
598 if (context.size > 1) {
599 // Only display the warning message if this participant configuration is the current one.
600 if (context.name == participant->getName()) {
601 PRECICE_ERROR("You attempted to use the legacy VTK exporter with the parallel participant {}, which isn't supported."
602 "Migrate to another exporter, such as the VTU exporter by specifying \"<export:vtu ... />\" instead of \"<export:vtk ... />\".",
603 participant->getName());
604 }
605 } else {
606 exporter = io::PtrExport(new io::ExportVTK());
607 }
608 } else if (exportContext.type == VALUE_VTU) {
609 exporter = io::PtrExport(new io::ExportVTU());
610 } else if (exportContext.type == VALUE_VTP) {
611 exporter = io::PtrExport(new io::ExportVTP());
612 } else if (exportContext.type == VALUE_CSV) {
613 exporter = io::PtrExport(new io::ExportCSV());
614 } else {
615 PRECICE_ERROR("Participant {} defines an <export/> tag of unknown type \"{}\".",
616 _participants.back()->getName(), exportContext.type);
617 }
618 exportContext.exporter = std::move(exporter);
619
620 _participants.back()->addExportContext(exportContext);
621 }
622 _exportConfig->resetExports();
623
624 // Create watch points
625 for (const WatchPointConfig &config : _watchPointConfigs) {
626 PRECICE_CHECK(participant->isMeshUsed(config.nameMesh),
627 "Participant \"{}\" defines watchpoint \"{}\" for mesh \"{}\" which is not provided by the participant. "
628 "Please add <provide-mesh name=\"{}\" /> to the participant.",
629 participant->getName(), config.name, config.nameMesh, config.nameMesh);
630 const auto &meshContext = participant->usedMeshContext(config.nameMesh);
631 PRECICE_CHECK(meshContext.provideMesh,
632 "Participant \"{}\" defines watchpoint \"{}\" for the received mesh \"{}\", which is not allowed. "
633 "Please move the watchpoint definition to the participant providing mesh \"{}\".",
634 participant->getName(), config.name, config.nameMesh, config.nameMesh);
635
636 std::string filename = "precice-" + participant->getName() + "-watchpoint-" + config.name + ".log";
637 participant->addWatchPoint(std::make_shared<impl::WatchPoint>(config.coordinates, meshContext.mesh, std::move(filename)));
638 }
639 _watchPointConfigs.clear();
640
641 // Create watch integrals
642 for (const WatchIntegralConfig &config : _watchIntegralConfigs) {
643 PRECICE_CHECK(participant->isMeshUsed(config.nameMesh),
644 "Participant \"{}\" defines watch integral \"{}\" for mesh \"{}\" which is not used by the participant. "
645 "Please add a provide-mesh node with name=\"{}\".",
646 participant->getName(), config.name, config.nameMesh, config.nameMesh);
647 const auto &meshContext = participant->usedMeshContext(config.nameMesh);
648 PRECICE_CHECK(meshContext.provideMesh,
649 "Participant \"{}\" defines watch integral \"{}\" for the received mesh \"{}\", which is not allowed. "
650 "Please move the watchpoint definition to the participant providing mesh \"{}\".",
651 participant->getName(), config.name, config.nameMesh, config.nameMesh);
652
653 std::string filename = "precice-" + participant->getName() + "-watchintegral-" + config.name + ".log";
654 participant->addWatchIntegral(std::make_shared<impl::WatchIntegral>(meshContext.mesh, std::move(filename), config.isScalingOn));
655 }
656 _watchIntegralConfigs.clear();
657
658 // create default primary communication if needed
659 if (context.size > 1 && not _isIntraCommDefined && participant->getName() == context.name) {
660#ifdef PRECICE_NO_MPI
661 PRECICE_ERROR("Implicit intra-participant communications for parallel participants are only available if preCICE was built with MPI. "
662 "Either explicitly define an intra-participant communication for each parallel participant or rebuild preCICE with \"PRECICE_MPICommunication=ON\".");
663#else
664 utils::IntraComm::getCommunication() = std::make_shared<com::MPIDirectCommunication>();
665 participant->setUsePrimaryRank(true);
666#endif
667 }
668 _isIntraCommDefined = false; // to not mess up with previous participant
669}
670
673 const impl::PtrParticipant & participant)
674{
677
678 for (const ConfMapping &configuredMapping : _mappingConfig->mappings()) {
679 bool sameToMesh = mapping.toMesh->getName() == configuredMapping.toMesh->getName();
680 bool sameFromMesh = mapping.fromMesh->getName() == configuredMapping.fromMesh->getName();
681 if (sameToMesh && sameFromMesh) {
682 // It's really the same mapping, not a duplicated one. Those are already checked for in MappingConfiguration.
683 return;
684 }
685
686 if (sameToMesh) {
687 for (const mesh::PtrData &data : mapping.fromMesh->data()) {
688 for (const mesh::PtrData &configuredData : configuredMapping.fromMesh->data()) {
689 bool sameFromData = data->getName() == configuredData->getName();
690
691 if (not sameFromData) {
692 continue;
693 }
694
695 bool sameDirection = false;
696
698 for (const auto &dataContext : participant->writeDataContexts()) {
699 sameDirection |= data->getName() == dataContext.getDataName();
700 }
701 }
703 for (const auto &dataContext : participant->readDataContexts()) {
704 sameDirection |= data->getName() == dataContext.getDataName();
705 }
706 }
707 PRECICE_CHECK(!sameDirection,
708 "There cannot be two mappings to mesh \"{}\" if the meshes from which is mapped contain "
709 "duplicated data fields that are also actually mapped on this participant. "
710 "Here, both from meshes contain data \"{}\". "
711 "The mapping is not well defined. "
712 "Which data \"{}\" should be mapped to mesh \"{}\"?",
713 mapping.toMesh->getName(), data->getName(), data->getName(), mapping.toMesh->getName());
714 }
715 }
716 }
717 }
718}
719
720} // namespace precice::config
#define PRECICE_ERROR(...)
Definition LogMacros.hpp:15
#define PRECICE_DEBUG(...)
Definition LogMacros.hpp:64
#define PRECICE_TRACE(...)
Definition LogMacros.hpp:95
#define PRECICE_CHECK(check,...)
Definition LogMacros.hpp:35
std::string name
T any_of(T... args)
#define PRECICE_ASSERT(...)
Definition assertion.hpp:87
T begin(T... args)
Configuration for communication channels between a primary and its secondary ranks....
PtrCommunication createCommunication(const xml::XMLTag &tag) const
Returns a communication object of given type.
const std::vector< impl::PtrParticipant > & getParticipants() const
Returns all configured participants.
std::vector< impl::PtrParticipant > _participants
ParticipantConfiguration(xml::XMLTag &parent, mesh::PtrMeshConfiguration meshConfiguration)
partition::ReceivedPartition::GeometricFilter getGeoFilter(const std::string &geoFilter) const
virtual void xmlEndTagCallback(const xml::ConfigurationContext &context, xml::XMLTag &callingTag)
Callback function required for use of automatic configuration.
const mesh::PtrData & getData(const mesh::PtrMesh &mesh, const std::string &nameData) const
void finishParticipantConfiguration(const xml::ConfigurationContext &context, const impl::PtrParticipant &participant)
std::string hintFor(std::string_view wrongName) const
void checkIllDefinedMappings(const mapping::MappingConfiguration::ConfiguredMapping &mapping, const impl::PtrParticipant &participant)
Check whether a mapping to the same mesh and with similar data fields already exists.
virtual void xmlTagCallback(const xml::ConfigurationContext &context, xml::XMLTag &callingTag)
Callback function required for use of automatic configuration.
std::vector< WatchIntegralConfig > _watchIntegralConfigs
const impl::PtrParticipant getParticipant(const std::string &participantName) const
Returns a participant with the given name.
Holds coupling state of one participating solver in coupled simulation.
Writes polygonal, or triangle meshes to vtk files.
Definition ExportVTK.hpp:19
GeometricFilter
Defines the type of geometric filter used.
@ ON_PRIMARY_RANK
Filter at primary rank and communicate only filtered mesh.
@ ON_SECONDARY_RANKS
Filter after communication on all secondary ranks.
@ NO_FILTER
No geometric filter used (e.g. for RBF mappings)
static com::PtrCommunication & getCommunication()
Intra-participant communication.
Definition IntraComm.hpp:31
XMLAttribute & setOptions(std::vector< ATTRIBUTE_T > options)
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
Eigen::VectorXd getEigenVectorXdAttributeValue(const std::string &name, int dimensions) const
Returns Eigen vector attribute value with given dimensions.
Definition XMLTag.cpp:168
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
double getDoubleAttributeValue(const std::string &name, std::optional< double > default_value=std::nullopt) const
Definition XMLTag.cpp:116
XMLTag & addSubtag(const XMLTag &tag)
Adds an XML tag as subtag by making a copy of the given tag.
Definition XMLTag.cpp:41
T empty(T... args)
T find_if(T... args)
T get(T... args)
vector< double > getData()
Definition mainA.cpp:19
T max(T... args)
std::shared_ptr< Export > PtrExport
std::string loopbackInterfaceName()
Returns the name of the canonical loopback interface on this system.
Definition networking.cpp:5
std::vector< StringMatch > computeMatches(std::string_view given, const Container &expected)
Definition String.hpp:95
STL namespace.
T push_back(T... args)
Holds a data mapping and related information.
mapping::PtrMapping mapping
Data mapping.
MeshID fromMeshID
id of mesh from which is mapped
bool configuredWithAliasTag
used the automatic rbf alias tag in order to set the mapping
MeshID toMeshID
id of mesh to which is mapped
Stores a mesh and related objects and data.
mesh::PtrMesh mesh
Mesh holding the geometry data structure.
mapping::Mapping::MeshRequirement meshRequirement
Determines which mesh type has to be provided by the accessor.
partition::ReceivedPartition::GeometricFilter geoFilter
type of geometric filter
std::vector< MappingContext > toMappingContexts
Mappings used when mapping data to the mesh. Can be empty.
std::string receiveMeshFrom
Name of participant that creates the mesh.
bool provideMesh
True, if accessor does create the mesh.
std::vector< MappingContext > fromMappingContexts
Mappings used when mapping data from the mesh. Can be empty.
Direction direction
Direction of mapping (important to set input and output mesh).
Tightly coupled to the parameters of Participant()
Definition XMLTag.hpp:24