53 XMLTag tag(*
this,
TAG, XMLTag::OCCUR_ONCE_OR_MORE);
54 doc =
"Represents one solver using preCICE. At least two ";
55 doc +=
"participants have to be defined.";
56 tag.setDocumentation(doc);
58 auto attrName = XMLAttribute<std::string>(
ATTR_NAME)
60 "Name of the participant. Has to match the name given on construction "
61 "of the precice::Participant object used by the participant.");
62 tag.addAttribute(attrName);
64 XMLTag tagWriteData(*
this,
TAG_WRITE, XMLTag::OCCUR_ARBITRARY);
65 doc =
"Sets data to be written by the participant to preCICE. ";
66 doc +=
"Data is defined by using the <data> tag.";
67 tagWriteData.setDocumentation(doc);
68 XMLTag tagReadData(*
this,
TAG_READ, XMLTag::OCCUR_ARBITRARY);
69 doc =
"Sets data to be read by the participant from preCICE. ";
70 doc +=
"Data is defined by using the <data> tag.";
71 tagReadData.setDocumentation(doc);
72 auto attrDataName = XMLAttribute<std::string>(
ATTR_NAME)
73 .setDocumentation(
"Name of the data.");
74 tagWriteData.addAttribute(attrDataName);
75 tagReadData.addAttribute(attrDataName);
76 auto attrMesh = XMLAttribute<std::string>(
ATTR_MESH)
78 "Mesh the data belongs to. If data should be read/written to several "
79 "meshes, this has to be specified separately for each mesh.");
80 tagWriteData.addAttribute(attrMesh);
81 tagReadData.addAttribute(attrMesh);
83 tag.addSubtag(tagWriteData);
84 tag.addSubtag(tagReadData);
95 doc =
"A watch point can be used to follow the transient changes of data ";
96 doc +=
"and mesh vertex coordinates at a given point";
97 tagWatchPoint.setDocumentation(doc);
98 doc =
"Name of the watch point. Is taken in combination with the participant ";
99 doc +=
"name to construct the filename the watch point data is written to.";
100 attrName.setDocumentation(doc);
101 tagWatchPoint.addAttribute(attrName);
102 doc =
"Mesh to be watched.";
103 attrMesh.setDocumentation(doc);
104 tagWatchPoint.addAttribute(attrMesh);
107 "The coordinates of the watch point. If the watch point is not put exactly "
108 "on the mesh to observe, the closest projection of the point onto the "
109 "mesh is considered instead, and values/coordinates are interpolated "
110 "linearly to that point.");
111 tagWatchPoint.addAttribute(attrCoordinate);
112 tag.addSubtag(tagWatchPoint);
115 .setDocumentation(
"Whether the vertex data is scaled with the element area before "
116 "summing up or not. In 2D, vertex data is scaled with the average length of "
117 "neighboring edges. In 3D, vertex data is scaled with the average surface of "
118 "neighboring triangles. If false, vertex data is directly summed up.");
120 doc =
"A watch integral can be used to follow the transient change of integral data ";
121 doc +=
"and surface area for a given coupling mesh.";
122 tagWatchIntegral.setDocumentation(doc);
123 doc =
"Name of the watch integral. Is taken in combination with the participant ";
124 doc +=
"name to construct the filename the watch integral data is written to.";
125 attrName.setDocumentation(doc);
126 tagWatchIntegral.addAttribute(attrName);
127 doc =
"Mesh to be watched.";
128 attrMesh.setDocumentation(doc);
129 tagWatchIntegral.addAttribute(attrMesh);
130 tagWatchIntegral.addAttribute(attrScaleWitConn);
131 tag.addSubtag(tagWatchIntegral);
134 doc =
"Provide a mesh (see tag `<mesh>`) to other participants.";
135 tagProvideMesh.setDocumentation(doc);
136 attrName.setDocumentation(
"Name of the mesh to provide.");
137 tagProvideMesh.addAttribute(attrName);
138 tag.addSubtag(tagProvideMesh);
141 doc =
"Makes a remote mesh (see tag `<mesh>`) available to this participant.";
142 tagReceiveMesh.setDocumentation(doc);
143 attrName.setDocumentation(
"Name of the mesh to receive.");
144 tagReceiveMesh.addAttribute(attrName);
145 auto attrFrom = XMLAttribute<std::string>(
ATTR_FROM)
146 .setDocumentation(
"The name of the participant to receive the mesh from. "
147 "This participant needs to provide the mesh using `<provide-mesh />`.");
151 "Enables access to the data on this received mesh via the preCICE API functions without having to map it to a provided mesh. "
152 "This is required for direct access or just-in-time mappings. "
153 "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. "
154 "In such cases the API function `setMeshAccessRegion()` must be used to define the region of interest. "
155 "See the user documentation for more information.");
156 tagReceiveMesh.addAttribute(attrEnableAccess);
160 "Deprecated: use \"api-access\" instead.");
161 tagReceiveMesh.addAttribute(attrDirectAccess);
165 "For parallel execution, a received mesh needs to be decomposed. "
166 "A geometric filter based on bounding-boxes around the local mesh can speed up this process. "
167 "This setting controls if and where this filter is applied. "
168 "`on-primary-rank` is beneficial for a huge mesh and a low number of processors, but is incompatible with two-level initialization. "
169 "`on-secondary-ranks` performs better for a very high number of processors. "
170 "Both result in the same distribution if the safety-factor is sufficiently large. "
171 "`no-filter` may be useful for very asymmetric cases and for debugging. "
172 "If a mapping based on RBFs (rbf-pum,global-rbf) is used, the filter has no influence and is always `no-filter`.")
175 tagReceiveMesh.addAttribute(attrGeoFilter);
177 tagReceiveMesh.addAttribute(attrFrom);
180 "The safety factor of the geometric filter uniformly scales the rank-local bounding box by the given factor. "
181 "A safety-factor of `0.5` means that the bounding box is 150% of its original size.");
182 tagReceiveMesh.addAttribute(attrSafetyFactor);
184 tag.addSubtag(tagReceiveMesh);
187 XMLTag::Occurrence intraCommOcc = XMLTag::OCCUR_NOT_OR_ONCE;
189 XMLTag tagIntraComm(*
this,
"sockets", intraCommOcc,
TAG_INTRA_COMM);
190 doc =
"A solver in parallel needs a communication between its ranks. ";
191 doc +=
"By default, the participant's MPI_COM_WORLD is reused.";
192 doc +=
"Use this tag to use TCP/IP sockets instead.";
193 tagIntraComm.setDocumentation(doc);
195 auto attrPort = makeXMLAttribute(
"port", 0)
197 "Port number (16-bit unsigned integer) to be used for socket "
198 "communication. The default is \"0\", what means that OS will "
199 "dynamically search for a free port (if at least one exists) and "
200 "bind it automatically.");
201 tagIntraComm.addAttribute(attrPort);
205 "Interface name to be used for socket communication. "
206 "Default is the canonical name of the loopback interface of your platform. "
207 "Might be different on supercomputing systems, e.g. \"ib0\" "
208 "for the InfiniBand on SuperMUC. ");
209 tagIntraComm.addAttribute(attrNetwork);
213 "Directory where connection information is exchanged. By default, the "
214 "directory of startup is chosen.");
215 tagIntraComm.addAttribute(attrExchangeDirectory);
221 doc =
"A solver in parallel needs a communication between its ranks. ";
222 doc +=
"By default, the participant's MPI_COM_WORLD is reused.";
223 doc +=
"Use this tag to use MPI with separated communication spaces instead instead.";
224 tagIntraComm.setDocumentation(doc);
228 "Directory where connection information is exchanged. By default, the "
229 "directory of startup is chosen.");
230 tagIntraComm.addAttribute(attrExchangeDirectory);
235 for (XMLTag &tagIntraComm : intraCommTags) {
236 tag.addSubtag(tagIntraComm);
432 for (
const ConfMapping &confMapping :
_mappingConfig->mappings()) {
436 auto fromMesh = confMapping.fromMesh->getName();
437 auto toMesh = confMapping.toMesh->getName();
442 PRECICE_CHECK(participant->isMeshReceived(fromMesh) || confMapping.toMesh->isJustInTime() || participant->isMeshProvided(toMesh),
443 "A read mapping of participant \"{}\" needs to map from a received to a provided mesh, but in this case they are swapped. "
444 "Did you intent to map from mesh \"{}\" to mesh \"{}\", or use a write mapping instead?",
445 participant->getName(), confMapping.toMesh->getName(), confMapping.fromMesh->getName());
447 "Participant \"{}\" has a read mapping from mesh \"{}\", without receiving it. "
448 "Please add a receive-mesh tag with name=\"{}\"",
449 participant->getName(), fromMesh, fromMesh);
451 PRECICE_CHECK(confMapping.toMesh->isJustInTime() || participant->isMeshProvided(toMesh),
452 "Participant \"{}\" has a read mapping to mesh \"{}\", without providing it. "
453 "Please add a provide-mesh tag with name=\"{}\"",
454 participant->getName(), toMesh, toMesh);
457 PRECICE_CHECK(confMapping.fromMesh->isJustInTime() || participant->isMeshProvided(fromMesh) || participant->isMeshReceived(toMesh),
458 "A write mapping of participant \"{}\" needs to map from a provided to a received mesh, but in this case they are swapped. "
459 "Did you intent to map from mesh \"{}\" to mesh \"{}\", or use a read mapping instead?",
460 participant->getName(), confMapping.toMesh->getName(), confMapping.fromMesh->getName());
462 PRECICE_CHECK(confMapping.fromMesh->isJustInTime() || participant->isMeshProvided(fromMesh),
463 "Participant \"{}\" has a write mapping from mesh \"{}\", without providing it. "
464 "Please add a provided-mesh tag with name=\"{}\"",
465 participant->getName(), fromMesh, fromMesh);
467 "Participant \"{}\" has a write mapping to mesh \"{}\", without receiving it. "
468 "Please add a receive-mesh tag with name=\"{}\"",
469 participant->getName(), toMesh, toMesh);
472 if (context.
size > 1 && context.
name == participant->getName()) {
477 PRECICE_ERROR(
"For a parallel participant, only the mapping combinations read-consistent and write-conservative are allowed");
478 }
else if (confMapping.mapping->isScaledConsistent()) {
479 PRECICE_ERROR(
"Scaled consistent mapping is not yet supported for a parallel participant. "
480 "You could run in serial or use a plain (read-)consistent mapping instead.");
484 PRECICE_CHECK(!confMapping.mapping->isScaledConsistent() || !(confMapping.fromMesh->isJustInTime() || confMapping.toMesh->isJustInTime()),
485 "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());
489 if (confMapping.requiresBasisFunction) {
490 if (!confMapping.fromMesh->isJustInTime()) {
493 if (!confMapping.toMesh->isJustInTime()) {
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 PRECICE_CHECK(participant->meshContext(context.getMeshName()).provideMesh || !(participant->isDirectAccessAllowed(context.getMeshName()) &&
_remeshing),
"Writing data via API access (configuration <write-data ... mesh=\"{}\") is not (yet) supported with remeshing", context.getMeshName());
662 for (
const auto &meshContext : participant->usedMeshContexts()) {
664 exportContext.meshName = meshContext->mesh->getName();
670 if (context.
size > 1) {
672 if (context.
name == participant->getName()) {
673 PRECICE_ERROR(
"You attempted to use the legacy VTK exporter with the parallel participant {}, which isn't supported. "
674 "Migrate to another exporter, such as the VTU exporter by specifying \"<export:vtu ... />\" instead of \"<export:vtk ... />\".",
675 participant->getName());
679 participant->getName(),
680 exportContext.location,
683 exportContext.everyNTimeWindows,
687 }
else if (exportContext.type ==
VALUE_VTU) {
689 participant->getName(),
690 exportContext.location,
693 exportContext.everyNTimeWindows,
696 }
else if (exportContext.type ==
VALUE_VTP) {
698 participant->getName(),
699 exportContext.location,
702 exportContext.everyNTimeWindows,
705 }
else if (exportContext.type ==
VALUE_CSV) {
707 participant->getName(),
708 exportContext.location,
711 exportContext.everyNTimeWindows,
715 PRECICE_ERROR(
"Participant {} defines an <export/> tag of unknown type \"{}\".",
718 exportContext.exporter = std::move(exporter);
722 PRECICE_WARN_IF(exportContext.everyNTimeWindows > 1 && exportContext.everyIteration,
723 "Participant {} defines an exporter of type {} which exports every iteration. "
724 "This overrides the every-n-time-window value you provided.",
730 if (context.
name == participant->getName()) {
733 "Participant \"{}\" defines watchpoint \"{}\" for mesh \"{}\" which is not provided by the participant. "
734 "Please add <provide-mesh name=\"{}\" /> to the participant.",
736 const auto &meshContext = participant->usedMeshContext(
config.nameMesh);
738 "Participant \"{}\" defines watchpoint \"{}\" for the received mesh \"{}\", which is not allowed. "
739 "Please move the watchpoint definition to the participant providing mesh \"{}\".",
742 "Provided coordinate to watch is {}D, which does not match the dimension of the {}D mesh \"{}\".",
743 config.coordinates.size(), meshContext.mesh->getDimensions(), meshContext.mesh->getName());
744 std::string filename =
"precice-" + participant->getName() +
"-watchpoint-" +
config.name +
".log";
751 if (context.
name == participant->getName()) {
754 "Participant \"{}\" defines watch integral \"{}\" for mesh \"{}\" which is not used by the participant. "
755 "Please add a provide-mesh node with name=\"{}\".",
757 const auto &meshContext = participant->usedMeshContext(
config.nameMesh);
759 "Participant \"{}\" defines watch integral \"{}\" for the received mesh \"{}\", which is not allowed. "
760 "Please move the watchpoint definition to the participant providing mesh \"{}\".",
763 std::string filename =
"precice-" + participant->getName() +
"-watchintegral-" +
config.name +
".log";
773 PRECICE_INFO(
"Implicit intra-participant communications for parallel participants using preCICE without MPI defaults to a sockets intracomm using the default loopback device {}. "
774 "Define your own <intra-comm:sockets ... /> to modify these defaults.",
780 participant->setUsePrimaryRank(
true);