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);
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 />`.");
146 "Enables access to the data on this received mesh via the preCICE API functions without having to map it to a provided mesh. "
147 "This is required for direct access or just-in-time mappings. "
148 "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. "
149 "In such cases the API function `setMeshAccessRegion()` must be used to define the region of interest. "
150 "See the user documentation for more information.");
151 tagReceiveMesh.addAttribute(attrEnableAccess);
155 "Deprecated: use \"api-access\" instead.");
156 tagReceiveMesh.addAttribute(attrDirectAccess);
160 "For parallel execution, a received mesh needs to be decomposed. "
161 "A geometric filter based on bounding-boxes around the local mesh can speed up this process. "
162 "This setting controls if and where this filter is applied. "
163 "`on-primary-rank` is beneficial for a huge mesh and a low number of processors, but is incompatible with two-level initialization. "
164 "`on-secondary-ranks` performs better for a very high number of processors. "
165 "Both result in the same distribution if the safety-factor is sufficiently large. "
166 "`no-filter` may be useful for very asymmetric cases and for debugging. "
167 "If a mapping based on RBFs (rbf-pum,global-rbf) is used, the filter has no influence and is always `no-filter`.")
170 tagReceiveMesh.addAttribute(attrGeoFilter);
172 tagReceiveMesh.addAttribute(attrFrom);
175 "The safety factor of the geometric filter uniformly scales the rank-local bounding box by the given factor. "
176 "A safety-factor of `0.5` means that the bounding box is 150% of its original size.");
177 tagReceiveMesh.addAttribute(attrSafetyFactor);
179 tag.addSubtag(tagReceiveMesh);
182 XMLTag::Occurrence intraCommOcc = XMLTag::OCCUR_NOT_OR_ONCE;
184 XMLTag tagIntraComm(*
this,
"sockets", intraCommOcc,
TAG_INTRA_COMM);
185 doc =
"A solver in parallel needs a communication between its ranks. ";
186 doc +=
"By default, the participant's MPI_COM_WORLD is reused.";
187 doc +=
"Use this tag to use TCP/IP sockets instead.";
188 tagIntraComm.setDocumentation(doc);
190 auto attrPort = makeXMLAttribute(
"port", 0)
192 "Port number (16-bit unsigned integer) to be used for socket "
193 "communication. The default is \"0\", what means that OS will "
194 "dynamically search for a free port (if at least one exists) and "
195 "bind it automatically.");
196 tagIntraComm.addAttribute(attrPort);
200 "Interface name to be used for socket communication. "
201 "Default is the canonical name of the loopback interface of your platform. "
202 "Might be different on supercomputing systems, e.g. \"ib0\" "
203 "for the InfiniBand on SuperMUC. ");
204 tagIntraComm.addAttribute(attrNetwork);
208 "Directory where connection information is exchanged. By default, the "
209 "directory of startup is chosen.");
210 tagIntraComm.addAttribute(attrExchangeDirectory);
216 doc =
"A solver in parallel needs a communication between its ranks. ";
217 doc +=
"By default, the participant's MPI_COM_WORLD is reused.";
218 doc +=
"Use this tag to use MPI with separated communication spaces instead instead.";
219 tagIntraComm.setDocumentation(doc);
223 "Directory where connection information is exchanged. By default, the "
224 "directory of startup is chosen.");
225 tagIntraComm.addAttribute(attrExchangeDirectory);
230 for (XMLTag &tagIntraComm : intraCommTags) {
231 tag.addSubtag(tagIntraComm);
417 for (
const ConfMapping &confMapping :
_mappingConfig->mappings()) {
421 auto fromMesh = confMapping.fromMesh->getName();
422 auto toMesh = confMapping.toMesh->getName();
427 PRECICE_CHECK(participant->isMeshReceived(fromMesh) || confMapping.toMesh->isJustInTime() || participant->isMeshProvided(toMesh),
428 "A read mapping of participant \"{}\" needs to map from a received to a provided mesh, but in this case they are swapped. "
429 "Did you intent to map from mesh \"{}\" to mesh \"{}\", or use a write mapping instead?",
430 participant->getName(), confMapping.toMesh->getName(), confMapping.fromMesh->getName());
432 "Participant \"{}\" has a read mapping from mesh \"{}\", without receiving it. "
433 "Please add a receive-mesh tag with name=\"{}\"",
434 participant->getName(), fromMesh, fromMesh);
436 PRECICE_CHECK(confMapping.toMesh->isJustInTime() || participant->isMeshProvided(toMesh),
437 "Participant \"{}\" has a read mapping to mesh \"{}\", without providing it. "
438 "Please add a provide-mesh tag with name=\"{}\"",
439 participant->getName(), toMesh, toMesh);
442 PRECICE_CHECK(confMapping.fromMesh->isJustInTime() || participant->isMeshProvided(fromMesh) || participant->isMeshReceived(toMesh),
443 "A write mapping of participant \"{}\" needs to map from a provided to a received mesh, but in this case they are swapped. "
444 "Did you intent to map from mesh \"{}\" to mesh \"{}\", or use a read mapping instead?",
445 participant->getName(), confMapping.toMesh->getName(), confMapping.fromMesh->getName());
447 PRECICE_CHECK(confMapping.fromMesh->isJustInTime() || participant->isMeshProvided(fromMesh),
448 "Participant \"{}\" has a write mapping from mesh \"{}\", without providing it. "
449 "Please add a provided-mesh tag with name=\"{}\"",
450 participant->getName(), fromMesh, fromMesh);
452 "Participant \"{}\" has a write mapping to mesh \"{}\", without receiving it. "
453 "Please add a receive-mesh tag with name=\"{}\"",
454 participant->getName(), toMesh, toMesh);
457 if (context.
size > 1 && context.
name == participant->getName()) {
462 PRECICE_ERROR(
"For a parallel participant, only the mapping combinations read-consistent and write-conservative are allowed");
463 }
else if (confMapping.mapping->isScaledConsistent()) {
464 PRECICE_ERROR(
"Scaled consistent mapping is not yet supported for a parallel participant. "
465 "You could run in serial or use a plain (read-)consistent mapping instead.");
469 PRECICE_CHECK(!confMapping.mapping->isScaledConsistent() || !(confMapping.fromMesh->isJustInTime() || confMapping.toMesh->isJustInTime()),
470 "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());
474 if (confMapping.requiresBasisFunction) {
475 if (!confMapping.fromMesh->isJustInTime()) {
478 if (!confMapping.toMesh->isJustInTime()) {
487 mappingContext.
fromMeshID = confMapping.fromMesh->getID();
488 mappingContext.
toMeshID = confMapping.toMesh->getID();
494 map = confMapping.mapping;
498 const mesh::PtrMesh &input = confMapping.fromMesh->isJustInTime() ? confMapping.fromMesh : participant->meshContext(fromMesh).mesh;
499 const mesh::PtrMesh &output = confMapping.toMesh->isJustInTime() ? confMapping.toMesh : participant->meshContext(toMesh).mesh;
500 PRECICE_DEBUG(
"Configure mapping for input={}, output={}", input->getName(), output->getName());
501 map->setMeshes(input, output);
506 participant->addWriteMappingContext(mappingContext);
509 participant->addReadMappingContext(mappingContext);
514 if (!input->isJustInTime()) {
515 participant->configureInputMeshContext(fromMesh, mappingContext, map->getInputRequirement());
517 if (!output->isJustInTime()) {
518 participant->configureOutputMeshContext(toMesh, mappingContext, map->getOutputRequirement());
530 bool dataFound =
false;
531 for (
auto &dataContext : participant->writeDataContexts()) {
533 const int fromMeshID = dataContext.getMeshID();
535 if (mappingContext.fromMeshID == fromMeshID) {
540 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getOutputMesh()->getName());
544 if (meshContext.
mesh->hasDataName(dataContext.getDataName())) {
546 PRECICE_CHECK(participant->isMeshProvided(dataContext.getMeshName()),
547 "Participant \"{}\" has to provide mesh \"{}\" to be able to write data to it. "
548 "Please add a provide-mesh node with name=\"{}\".",
549 participant->getName(), dataContext.getMeshName(), dataContext.getMeshName());
553 dataContext.appendMappingConfiguration(mappingContext, meshContext);
555 if (mappingContext.mapping->requiresGradientData() ==
true) {
556 mappingContext.requireGradientData(dataContext.getDataName());
560 }
else if (mappingContext.mapping->getInputMesh()->isJustInTime()) {
561 const int toMeshID = dataContext.getMeshID();
563 if (mappingContext.toMeshID == toMeshID) {
564 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getOutputMesh()->getName());
565 dataContext.addJustInTimeMapping(mappingContext, meshContext);
566 if (mappingContext.mapping->requiresGradientData() ==
true) {
567 mappingContext.requireGradientData(dataContext.getDataName());
574 "Participant \"{}\" defines a write mapping from mesh \"{}\" to mesh \"{}\", "
575 "but there is either no corresponding write-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());
583 bool dataFound =
false;
584 for (
auto &dataContext : participant->readDataContexts()) {
586 const int toMeshID = dataContext.getMeshID();
587 if (mappingContext.toMeshID == toMeshID) {
589 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getInputMesh()->getName());
592 if (meshContext.
mesh->hasDataName(dataContext.getDataName())) {
594 PRECICE_CHECK(participant->isMeshProvided(dataContext.getMeshName()),
595 "Participant \"{}\" has to provide mesh \"{}\" in order to read data from it. "
596 "Please add a provide-mesh node with name=\"{}\".",
597 participant->getName(), dataContext.getMeshName(), dataContext.getMeshName());
598 dataContext.appendMappingConfiguration(mappingContext, meshContext);
600 if (mappingContext.mapping->requiresGradientData() ==
true) {
601 mappingContext.requireGradientData(dataContext.getDataName());
605 }
else if (mappingContext.mapping->getOutputMesh()->isJustInTime()) {
606 const int fromMeshID = dataContext.getMeshID();
608 if (mappingContext.fromMeshID == fromMeshID) {
609 impl::MeshContext &meshContext = participant->meshContext(mappingContext.mapping->getInputMesh()->getName());
611 dataContext.addJustInTimeMapping(mappingContext, meshContext);
612 if (mappingContext.mapping->requiresGradientData() ==
true) {
613 mappingContext.requireGradientData(dataContext.getDataName());
620 "Participant \"{}\" defines a read mapping from mesh \"{}\" to mesh \"{}\", "
621 "but there is either no corresponding read-data tag or the meshes used "
622 "by this participant lack the necessary use-data tags.",
623 participant->getName(), mappingContext.mapping->getInputMesh()->getName(), mappingContext.mapping->getOutputMesh()->getName());
630 "Data action of participant \"{}\" uses mesh \"{}\", which is not used by the participant. "
631 "Please add a provide-mesh or receive-mesh node with name=\"{}\".",
639 for (
auto &context : participant->writeDataContexts()) {
640 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());
647 for (
const auto &meshContext : participant->usedMeshContexts()) {
649 exportContext.meshName = meshContext->mesh->getName();
655 if (context.
size > 1) {
657 if (context.
name == participant->getName()) {
658 PRECICE_ERROR(
"You attempted to use the legacy VTK exporter with the parallel participant {}, which isn't supported."
659 "Migrate to another exporter, such as the VTU exporter by specifying \"<export:vtu ... />\" instead of \"<export:vtk ... />\".",
660 participant->getName());
664 participant->getName(),
665 exportContext.location,
668 exportContext.everyNTimeWindows,
672 }
else if (exportContext.type ==
VALUE_VTU) {
674 participant->getName(),
675 exportContext.location,
678 exportContext.everyNTimeWindows,
681 }
else if (exportContext.type ==
VALUE_VTP) {
683 participant->getName(),
684 exportContext.location,
687 exportContext.everyNTimeWindows,
690 }
else if (exportContext.type ==
VALUE_CSV) {
692 participant->getName(),
693 exportContext.location,
696 exportContext.everyNTimeWindows,
700 PRECICE_ERROR(
"Participant {} defines an <export/> tag of unknown type \"{}\".",
703 exportContext.exporter = std::move(exporter);
707 PRECICE_WARN_IF(exportContext.everyNTimeWindows > 1 && exportContext.everyIteration,
708 "Participant {} defines an exporter of type {} which exports every iteration. "
709 "This overrides the every-n-time-window value you provided.",
715 if (context.
name == participant->getName()) {
718 "Participant \"{}\" defines watchpoint \"{}\" for mesh \"{}\" which is not provided by the participant. "
719 "Please add <provide-mesh name=\"{}\" /> to the participant.",
721 const auto &meshContext = participant->usedMeshContext(
config.nameMesh);
723 "Participant \"{}\" defines watchpoint \"{}\" for the received mesh \"{}\", which is not allowed. "
724 "Please move the watchpoint definition to the participant providing mesh \"{}\".",
727 "Provided coordinate to watch is {}D, which does not match the dimension of the {}D mesh \"{}\".",
728 config.coordinates.size(), meshContext.mesh->getDimensions(), meshContext.mesh->getName());
729 std::string filename =
"precice-" + participant->getName() +
"-watchpoint-" +
config.name +
".log";
736 if (context.
name == participant->getName()) {
739 "Participant \"{}\" defines watch integral \"{}\" for mesh \"{}\" which is not used by the participant. "
740 "Please add a provide-mesh node with name=\"{}\".",
742 const auto &meshContext = participant->usedMeshContext(
config.nameMesh);
744 "Participant \"{}\" defines watch integral \"{}\" for the received mesh \"{}\", which is not allowed. "
745 "Please move the watchpoint definition to the participant providing mesh \"{}\".",
748 std::string filename =
"precice-" + participant->getName() +
"-watchintegral-" +
config.name +
".log";
757 PRECICE_ERROR(
"Implicit intra-participant communications for parallel participants are only available if preCICE was built with MPI. "
758 "Either explicitly define an intra-participant communication for each parallel participant or rebuild preCICE with \"PRECICE_MPICommunication=ON\".");
761 participant->setUsePrimaryRank(
true);