55 XMLTag tag(*
this,
TAG, XMLTag::OCCUR_ONCE_OR_MORE);
56 doc =
"Represents one solver using preCICE. At least two ";
57 doc +=
"participants have to be defined.";
58 tag.setDocumentation(doc);
60 auto attrName = XMLAttribute<std::string>(
ATTR_NAME)
62 "Name of the participant. Has to match the name given on construction "
63 "of the precice::Participant object used by the participant.");
64 tag.addAttribute(attrName);
66 XMLTag tagWriteData(*
this,
TAG_WRITE, XMLTag::OCCUR_ARBITRARY);
67 doc =
"Sets data to be written by the participant to preCICE. ";
68 doc +=
"Data is defined by using the <data> tag.";
69 tagWriteData.setDocumentation(doc);
70 XMLTag tagReadData(*
this,
TAG_READ, XMLTag::OCCUR_ARBITRARY);
71 doc =
"Sets data to be read by the participant from preCICE. ";
72 doc +=
"Data is defined by using the <data> tag.";
73 tagReadData.setDocumentation(doc);
74 auto attrDataName = XMLAttribute<std::string>(
ATTR_NAME)
75 .setDocumentation(
"Name of the data.");
76 tagWriteData.addAttribute(attrDataName);
77 tagReadData.addAttribute(attrDataName);
78 auto attrMesh = XMLAttribute<std::string>(
ATTR_MESH)
80 "Mesh the data belongs to. If data should be read/written to several "
81 "meshes, this has to be specified separately for each mesh.");
82 tagWriteData.addAttribute(attrMesh);
83 tagReadData.addAttribute(attrMesh);
85 tag.addSubtag(tagWriteData);
86 tag.addSubtag(tagReadData);
91 _actionConfig = std::make_shared<action::ActionConfiguration>(
94 _exportConfig = std::make_shared<io::ExportConfiguration>(tag);
97 doc =
"A watch point can be used to follow the transient changes of data ";
98 doc +=
"and mesh vertex coordinates at a given point";
99 tagWatchPoint.setDocumentation(doc);
100 doc =
"Name of the watch point. Is taken in combination with the participant ";
101 doc +=
"name to construct the filename the watch point data is written to.";
102 attrName.setDocumentation(doc);
103 tagWatchPoint.addAttribute(attrName);
104 doc =
"Mesh to be watched.";
105 attrMesh.setDocumentation(doc);
106 tagWatchPoint.addAttribute(attrMesh);
109 "The coordinates of the watch point. If the watch point is not put exactly "
110 "on the mesh to observe, the closest projection of the point onto the "
111 "mesh is considered instead, and values/coordinates are interpolated "
112 "linearly to that point.");
113 tagWatchPoint.addAttribute(attrCoordinate);
114 tag.addSubtag(tagWatchPoint);
117 .setDocumentation(
"Whether the vertex data is scaled with the element area before "
118 "summing up or not. In 2D, vertex data is scaled with the average length of "
119 "neighboring edges. In 3D, vertex data is scaled with the average surface of "
120 "neighboring triangles. If false, vertex data is directly summed up.");
122 doc =
"A watch integral can be used to follow the transient change of integral data ";
123 doc +=
"and surface area for a given coupling mesh.";
124 tagWatchIntegral.setDocumentation(doc);
125 doc =
"Name of the watch integral. Is taken in combination with the participant ";
126 doc +=
"name to construct the filename the watch integral data is written to.";
127 attrName.setDocumentation(doc);
128 tagWatchIntegral.addAttribute(attrName);
129 doc =
"Mesh to be watched.";
130 attrMesh.setDocumentation(doc);
131 tagWatchIntegral.addAttribute(attrMesh);
132 tagWatchIntegral.addAttribute(attrScaleWitConn);
133 tag.addSubtag(tagWatchIntegral);
136 doc =
"Provide a mesh (see tag `<mesh>`) to other participants.";
137 tagProvideMesh.setDocumentation(doc);
138 attrName.setDocumentation(
"Name of the mesh to provide.");
139 tagProvideMesh.addAttribute(attrName);
140 tag.addSubtag(tagProvideMesh);
143 doc =
"Makes a remote mesh (see tag `<mesh>`) available to this participant.";
144 tagReceiveMesh.setDocumentation(doc);
145 attrName.setDocumentation(
"Name of the mesh to receive.");
146 tagReceiveMesh.addAttribute(attrName);
147 auto attrFrom = XMLAttribute<std::string>(
ATTR_FROM)
148 .setDocumentation(
"The name of the participant to receive the mesh from. "
149 "This participant needs to provide the mesh using `<provide-mesh />`.");
153 "Enables access to the data on this received mesh via the preCICE API functions without having to map it to a provided mesh. "
154 "This is required for direct access or just-in-time mappings. "
155 "A received mesh needs to be decomposed in preCICE using a region of interest, which cannot be inferred, if there are no mappings to or from a provided mesh. "
156 "In such cases the API function `setMeshAccessRegion()` must be used to define the region of interest. "
157 "See the user documentation for more information.");
158 tagReceiveMesh.addAttribute(attrEnableAccess);
162 "Deprecated: use \"api-access\" instead.");
163 tagReceiveMesh.addAttribute(attrDirectAccess);
167 "For parallel execution, a received mesh needs to be decomposed. "
168 "A geometric filter based on bounding-boxes around the local mesh can speed up this process. "
169 "This setting controls if and where this filter is applied. "
170 "`on-primary-rank` is beneficial for a huge mesh and a low number of processors, but is incompatible with two-level initialization. "
171 "`on-secondary-ranks` performs better for a very high number of processors. "
172 "Both result in the same distribution if the safety-factor is sufficiently large. "
173 "`no-filter` may be useful for very asymmetric cases and for debugging. "
174 "If a mapping based on RBFs (rbf-pum,global-rbf) is used, the filter has no influence and is always `no-filter`.")
177 tagReceiveMesh.addAttribute(attrGeoFilter);
179 tagReceiveMesh.addAttribute(attrFrom);
182 "The safety factor of the geometric filter uniformly scales the rank-local bounding box by the given factor. "
183 "A safety-factor of `0.5` means that the bounding box is 150% of its original size.");
184 tagReceiveMesh.addAttribute(attrSafetyFactor);
186 tag.addSubtag(tagReceiveMesh);
188 std::list<XMLTag> intraCommTags;
189 XMLTag::Occurrence intraCommOcc = XMLTag::OCCUR_NOT_OR_ONCE;
191 XMLTag tagIntraComm(*
this,
"sockets", intraCommOcc,
TAG_INTRA_COMM);
192 doc =
"A solver in parallel needs a communication between its ranks. ";
193 doc +=
"By default, the participant's MPI_COM_WORLD is reused.";
194 doc +=
"Use this tag to use TCP/IP sockets instead.";
195 tagIntraComm.setDocumentation(doc);
197 auto attrPort = makeXMLAttribute(
"port", 0)
199 "Port number (16-bit unsigned integer) to be used for socket "
200 "communication. The default is \"0\", what means that OS will "
201 "dynamically search for a free port (if at least one exists) and "
202 "bind it automatically.");
203 tagIntraComm.addAttribute(attrPort);
207 "Interface name to be used for socket communication. "
208 "Default is the canonical name of the loopback interface of your platform. "
209 "Might be different on supercomputing systems, e.g. \"ib0\" "
210 "for the InfiniBand on SuperMUC. ");
211 tagIntraComm.addAttribute(attrNetwork);
215 "Directory where connection information is exchanged. By default, the "
216 "directory of startup is chosen.");
217 tagIntraComm.addAttribute(attrExchangeDirectory);
219 intraCommTags.push_back(tagIntraComm);
223 doc =
"A solver in parallel needs a communication between its ranks. ";
224 doc +=
"By default, the participant's MPI_COM_WORLD is reused.";
225 doc +=
"Use this tag to use MPI with separated communication spaces instead instead.";
226 tagIntraComm.setDocumentation(doc);
230 "Directory where connection information is exchanged. By default, the "
231 "directory of startup is chosen.");
232 tagIntraComm.addAttribute(attrExchangeDirectory);
234 intraCommTags.push_back(tagIntraComm);
237 for (XMLTag &tagIntraComm : intraCommTags) {
238 tag.addSubtag(tagIntraComm);
434 for (
const ConfMapping &confMapping :
_mappingConfig->mappings()) {
438 auto fromMesh = confMapping.fromMesh->getName();
439 auto toMesh = confMapping.toMesh->getName();
445 "Participant \"{}\" has a read mapping from mesh \"{}\", without receiving it. "
446 "Please add a receive-mesh tag with name=\"{}\"",
447 participant->getName(), fromMesh, fromMesh);
449 PRECICE_CHECK(confMapping.toMesh->isJustInTime() || participant->isMeshProvided(toMesh),
450 "Participant \"{}\" has a read mapping to mesh \"{}\", without providing it. "
451 "Please add a provide-mesh tag with name=\"{}\"",
452 participant->getName(), toMesh, toMesh);
456 PRECICE_CHECK(confMapping.fromMesh->isJustInTime() || participant->isMeshProvided(fromMesh),
457 "Participant \"{}\" has a write mapping from mesh \"{}\", without providing it. "
458 "Please add a provided-mesh tag with name=\"{}\"",
459 participant->getName(), fromMesh, fromMesh);
461 "Participant \"{}\" has a write mapping to mesh \"{}\", without receiving it. "
462 "Please add a receive-mesh tag with name=\"{}\"",
463 participant->getName(), toMesh, toMesh);
466 if (context.
size > 1 && context.
name == participant->getName()) {
471 PRECICE_ERROR(
"For a parallel participant, only the mapping combinations read-consistent and write-conservative are allowed");
472 }
else if (confMapping.mapping->isScaledConsistent()) {
473 PRECICE_ERROR(
"Scaled consistent mapping is not yet supported for a parallel participant. "
474 "You could run in serial or use a plain (read-)consistent mapping instead.");
478 PRECICE_CHECK(!confMapping.mapping->isScaledConsistent() || !(confMapping.fromMesh->isJustInTime() || confMapping.toMesh->isJustInTime()),
479 "The just-in-time mapping from mesh \"{}\" to mesh \"{}\" was configured with a scaled-consistent constraint. A scaled-consistent constraint is not implemented for just-in-time mappings in preCICE.", confMapping.fromMesh->getName(), confMapping.toMesh->getName());
483 if (confMapping.requiresBasisFunction) {
484 if (!confMapping.fromMesh->isJustInTime()) {
486 if (participant->isMeshReceived(fromMesh)) {
490 if (!confMapping.toMesh->isJustInTime()) {
492 if (participant->isMeshReceived(toMesh)) {
502 mappingContext.
fromMeshID = confMapping.fromMesh->getID();
503 mappingContext.
toMeshID = confMapping.toMesh->getID();
509 map = confMapping.mapping;
513 const mesh::PtrMesh &input = confMapping.fromMesh->isJustInTime() ? confMapping.fromMesh : participant->meshContext(fromMesh).mesh;
514 const mesh::PtrMesh &output = confMapping.toMesh->isJustInTime() ? confMapping.toMesh : participant->meshContext(toMesh).mesh;
516 map->setMeshes(input, output);
521 participant->addWriteMappingContext(mappingContext);
524 participant->addReadMappingContext(mappingContext);
530 participant->configureInputMeshContext(fromMesh, mappingContext, map->getInputRequirement());
533 participant->configureOutputMeshContext(toMesh, mappingContext, map->getOutputRequirement());
545 bool dataFound =
false;
546 for (
auto &dataContext : participant->writeDataContexts()) {
548 const int fromMeshID = dataContext.getMeshID();
550 if (mappingContext.fromMeshID == fromMeshID) {
555 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getOutputMesh()->getName());
561 PRECICE_CHECK(participant->isMeshProvided(dataContext.getMeshName()),
562 "Participant \"{}\" has to provide mesh \"{}\" to be able to write data to it. "
563 "Please add a provide-mesh node with name=\"{}\".",
564 participant->getName(), dataContext.getMeshName(), dataContext.getMeshName());
568 dataContext.appendMappingConfiguration(mappingContext, meshContext);
570 if (mappingContext.mapping->requiresGradientData() ==
true) {
571 mappingContext.requireGradientData(dataContext.getDataName());
575 }
else if (mappingContext.mapping->getInputMesh()->isJustInTime()) {
576 const int toMeshID = dataContext.getMeshID();
578 if (mappingContext.toMeshID == toMeshID) {
579 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getOutputMesh()->getName());
580 dataContext.addJustInTimeMapping(mappingContext, meshContext);
581 if (mappingContext.mapping->requiresGradientData() ==
true) {
582 mappingContext.requireGradientData(dataContext.getDataName());
589 "Participant \"{}\" defines a write mapping from mesh \"{}\" to mesh \"{}\", "
590 "but there is either no corresponding write-data tag or the meshes used "
591 "by this participant lack the necessary use-data tags.",
592 participant->getName(), mappingContext.mapping->getInputMesh()->getName(), mappingContext.mapping->getOutputMesh()->getName());
598 bool dataFound =
false;
599 for (
auto &dataContext : participant->readDataContexts()) {
601 const int toMeshID = dataContext.getMeshID();
602 if (mappingContext.toMeshID == toMeshID) {
604 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getInputMesh()->getName());
609 PRECICE_CHECK(participant->isMeshProvided(dataContext.getMeshName()),
610 "Participant \"{}\" has to provide mesh \"{}\" in order to read data from it. "
611 "Please add a provide-mesh node with name=\"{}\".",
612 participant->getName(), dataContext.getMeshName(), dataContext.getMeshName());
613 dataContext.appendMappingConfiguration(mappingContext, meshContext);
615 if (mappingContext.mapping->requiresGradientData() ==
true) {
616 mappingContext.requireGradientData(dataContext.getDataName());
620 }
else if (mappingContext.mapping->getOutputMesh()->isJustInTime()) {
621 const int fromMeshID = dataContext.getMeshID();
623 if (mappingContext.fromMeshID == fromMeshID) {
624 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getInputMesh()->getName());
626 dataContext.addJustInTimeMapping(mappingContext, meshContext);
627 if (mappingContext.mapping->requiresGradientData() ==
true) {
628 mappingContext.requireGradientData(dataContext.getDataName());
635 "Participant \"{}\" defines a read mapping from mesh \"{}\" to mesh \"{}\", "
636 "but there is either no corresponding read-data tag or the meshes used "
637 "by this participant lack the necessary use-data tags.",
638 participant->getName(), mappingContext.mapping->getInputMesh()->getName(), mappingContext.mapping->getOutputMesh()->getName());
645 "Data action of participant \"{}\" uses mesh \"{}\", which is not used by the participant. "
646 "Please add a provide-mesh or receive-mesh node with name=\"{}\".",
654 for (
auto &context : participant->writeDataContexts()) {
655 bool isProvided = participant->isMeshProvided(context.getMeshName());
656 PRECICE_CHECK(isProvided || !(participant->isDirectAccessAllowed(context.getMeshName()) &&
_remeshing),
"Writing data via API access (configuration <write-data ... mesh=\"{}\") is not (yet) supported with remeshing", context.getMeshName());
665 exportContext.meshName = meshContext.mesh->getName();
671 if (context.
size > 1) {
673 if (context.
name == participant->getName()) {
674 PRECICE_ERROR(
"You attempted to use the legacy VTK exporter with the parallel participant {}, which isn't supported. "
675 "Migrate to another exporter, such as the VTU exporter by specifying \"<export:vtu ... />\" instead of \"<export:vtk ... />\".",
676 participant->getName());
680 participant->getName(),
681 exportContext.location,
684 exportContext.everyNTimeWindows,
688 }
else if (exportContext.type ==
VALUE_VTU) {
690 participant->getName(),
691 exportContext.location,
694 exportContext.everyNTimeWindows,
697 }
else if (exportContext.type ==
VALUE_VTP) {
699 participant->getName(),
700 exportContext.location,
703 exportContext.everyNTimeWindows,
706 }
else if (exportContext.type ==
VALUE_CSV) {
708 participant->getName(),
709 exportContext.location,
712 exportContext.everyNTimeWindows,
716 PRECICE_ERROR(
"Participant {} defines an <export/> tag of unknown type \"{}\".",
719 exportContext.exporter = std::move(exporter);
724 for (
const auto &meshContext : participant->providedMeshContexts()) {
725 createExporter(meshContext);
729 for (
const auto &meshContext : participant->receivedMeshContexts()) {
730 createExporter(meshContext);
733 PRECICE_WARN_IF(exportContext.everyNTimeWindows > 1 && exportContext.everyIteration,
734 "Participant {} defines an exporter of type {} which exports every iteration. "
735 "This overrides the every-n-time-window value you provided.",
741 if (context.
name == participant->getName()) {
744 "Participant \"{}\" defines watchpoint \"{}\" for mesh \"{}\" which is not provided by the participant. "
745 "Please add <provide-mesh name=\"{}\" /> to the participant.",
749 "Participant \"{}\" defines watchpoint \"{}\" for the received mesh \"{}\", which is not allowed. "
750 "Please move the watchpoint definition to the participant providing mesh \"{}\".",
752 const auto &meshContext = participant->providedMeshContext(
config.nameMesh);
754 "Provided coordinate to watch is {}D, which does not match the dimension of the {}D mesh \"{}\".",
755 config.coordinates.size(), meshContext.mesh->getDimensions(), meshContext.mesh->getName());
756 std::string filename =
"precice-" + participant->getName() +
"-watchpoint-" +
config.name +
".log";
757 participant->addWatchPoint(std::make_shared<impl::WatchPoint>(
config.coordinates, meshContext.mesh, std::move(filename)));
763 if (context.
name == participant->getName()) {
766 "Participant \"{}\" defines watch integral \"{}\" for mesh \"{}\" which is not used by the participant. "
767 "Please add a provide-mesh node with name=\"{}\".",
769 const auto &meshContext = participant->meshContext(
config.nameMesh);
771 "Participant \"{}\" defines watch integral \"{}\" for the received mesh \"{}\", which is not allowed. "
772 "Please move the watchpoint definition to the participant providing mesh \"{}\".",
775 std::string filename =
"precice-" + participant->getName() +
"-watchintegral-" +
config.name +
".log";
776 participant->addWatchIntegral(std::make_shared<impl::WatchIntegral>(meshContext.mesh, std::move(filename),
config.isScalingOn));
785 PRECICE_INFO(
"Implicit intra-participant communications for parallel participants using preCICE without MPI defaults to a sockets intracomm using the default loopback device {}. "
786 "Define your own <intra-comm:sockets ... /> to modify these defaults.",
792 participant->setUsePrimaryRank(
true);