43 : _meshConfig(
std::move(meshConfiguration))
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);
53 auto attrName = XMLAttribute<std::string>(
ATTR_NAME)
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);
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)
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);
78 tag.addSubtag(tagWriteData);
79 tag.addSubtag(tagReadData);
84 _actionConfig = std::make_shared<action::ActionConfiguration>(
87 _exportConfig = std::make_shared<io::ExportConfiguration>(tag);
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);
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);
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.");
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);
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);
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);
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);
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\").")
166 tagReceiveMesh.addAttribute(attrGeoFilter);
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);
180 tag.addSubtag(tagReceiveMesh);
183 XMLTag::Occurrence intraCommOcc = XMLTag::OCCUR_NOT_OR_ONCE;
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);
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);
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);
209 "Directory where connection information is exchanged. By default, the "
210 "directory of startup is chosen.");
211 tagIntraComm.addAttribute(attrExchangeDirectory);
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);
224 "Directory where connection information is exchanged. By default, the "
225 "directory of startup is chosen.");
226 tagIntraComm.addAttribute(attrExchangeDirectory);
231 for (XMLTag &tagIntraComm : intraCommTags) {
232 tag.addSubtag(tagIntraComm);
409 for (
const ConfMapping &confMapping :
_mappingConfig->mappings()) {
413 auto fromMesh = confMapping.fromMesh->getName();
414 auto toMesh = confMapping.toMesh->getName();
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);
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);
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);
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);
438 if (context.
size > 1 && context.
name == participant->getName()) {
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.");
450 const auto & fromMeshID = confMapping.fromMesh->getID();
451 const auto & toMeshID = confMapping.toMesh->getID();
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());
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());
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());
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());
476 if (confMapping.requiresBasisFunction) {
487 map = confMapping.mapping;
492 PRECICE_DEBUG(
"Configure mapping for input={}, output={}", input->getName(), output->getName());
493 map->setMeshes(input, output);
496 participant->addWriteMappingContext(mappingContext);
499 participant->addReadMappingContext(mappingContext);
515 bool dataFound =
false;
516 for (
auto &dataContext : participant->writeDataContexts()) {
518 const int fromMeshID = dataContext.getMeshID();
519 if (mappingContext.fromMeshID == fromMeshID) {
521 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getOutputMesh()->getName());
524 if (meshContext.
mesh->hasDataName(dataContext.getDataName())) {
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);
532 if (mappingContext.mapping->requiresGradientData() ==
true) {
533 mappingContext.requireGradientData(dataContext.getDataName());
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());
549 bool dataFound =
false;
550 for (
auto &dataContext : participant->readDataContexts()) {
552 const int toMeshID = dataContext.getMeshID();
553 if (mappingContext.toMeshID == toMeshID) {
555 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getInputMesh()->getName());
558 if (meshContext.
mesh->hasDataName(dataContext.getDataName())) {
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);
566 if (mappingContext.mapping->requiresGradientData() ==
true) {
567 mappingContext.requireGradientData(dataContext.getDataName());
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());
582 bool used =
_participants.back()->isMeshUsed(action->getMesh()->getName());
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());
598 if (context.
size > 1) {
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());
608 }
else if (exportContext.type ==
VALUE_VTU) {
610 }
else if (exportContext.type ==
VALUE_VTP) {
612 }
else if (exportContext.type ==
VALUE_CSV) {
615 PRECICE_ERROR(
"Participant {} defines an <export/> tag of unknown type \"{}\".",
618 exportContext.exporter = std::move(exporter);
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);
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);
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)));
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);
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);
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));
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\".");
665 participant->setUsePrimaryRank(
true);