2#include <Eigen/src/Core/util/Meta.h>
64#include "precice/impl/versions.hpp"
85 int solverProcessIndex,
86 int solverProcessSize,
94 "This participant's name is an empty string. "
95 "When constructing a preCICE interface you need to pass the name of the "
96 "participant as first argument to the constructor.");
100 "Passing \"nullptr\" as \"communicator\" to Participant constructor is not allowed. "
101 "Please use the Participant constructor without the \"communicator\" argument, if you don't want to pass an MPI communicator.");
103 "The solver process index needs to be a non-negative number, not: {}. "
104 "Please check the value given when constructing a preCICE interface.",
107 "The solver process size needs to be a positive number, not: {}. "
108 "Please check the value given when constructing a preCICE interface.",
111 "The solver process index, currently: {} needs to be smaller than the solver process size, currently: {}. "
112 "Please check the values given when constructing a preCICE interface.",
121#ifndef PRECICE_NO_MPI
133 "The solver process index given in the preCICE interface constructor({}) does not match the rank of the passed MPI communicator ({}).",
137 "The solver process size given in the preCICE interface constructor({}) does not match the size of the passed MPI communicator ({}).",
142 PRECICE_WARN_IF(communicator.
has_value(),
"preCICE was configured without MPI but you passed an MPI communicator. preCICE ignores the communicator and continues.");
150 Event e2(
"startProfilingBackend");
183 PRECICE_INFO(
"This is preCICE version {}", PRECICE_VERSION);
184 PRECICE_INFO(
"Revision info: {}", precice::preciceRevision);
190#ifndef PRECICE_NO_DEBUG_LOG
193 " (without debug log)"
195#ifndef PRECICE_NO_TRACE_LOG
198#ifndef PRECICE_NO_ASSERTIONS
208 PRECICE_INFO(
"Configuring preCICE with configuration \"{}\"", configurationFileName);
215 "In the preCICE configuration, only one participant is defined. "
216 "One participant makes no coupled simulation. "
217 "Please add at least another one.");
229 "A parallel participant needs an intra-participant communication");
231 "You cannot use an intra-participant communication with a serial participant. "
232 "If you do not know exactly what an intra-participant communication is and why you want to use it "
233 "you probably just want to remove the intraComm tag from the preCICE configuration.");
241 _meshLock.add(meshContext->mesh->getName(),
false);
254 "Initial data has to be written to preCICE before calling initialize(). "
255 "After defining your mesh, call requiresInitialData() to check if the participant is required to write initial data using the writeData() function.");
258 PRECICE_CHECK(
_userEvents.empty(),
"There are unstopped user defined events. Please stop them using stopLastProfilingSection() before calling initialize().");
263 for (
const auto &context :
_accessor->usedMeshContexts()) {
264 if (context->provideMesh) {
265 e.
addData(
"meshSize" + context->mesh->getName(), context->mesh->nVertices());
274 for (
auto &context :
_accessor->writeDataContexts()) {
275 const double startTime = 0.0;
276 context.storeBufferedData(startTime);
309 for (
const auto &context :
_accessor->usedMeshContexts()) {
310 if (context->provideMesh) {
311 e.
addData(
"meshSize" + context->mesh->getName(), context->mesh->nVertices());
329 if (meshContext->provideMesh) {
330 auto &
mesh = *meshContext->mesh;
338 PRECICE_INFO(
"Setting up primary communication to coupling partner/s");
339 Event e2(
"connectPrimaries");
340 for (
auto &m2nPair :
_m2ns) {
341 auto &bm2n = m2nPair.second;
342 bool requesting = bm2n.isRequesting;
343 if (bm2n.m2n->isConnected()) {
344 PRECICE_DEBUG(
"Primary connection {} {} already connected.", (requesting ?
"from" :
"to"), bm2n.remoteName);
346 PRECICE_DEBUG((requesting ?
"Awaiting primary connection from {}" :
"Establishing primary connection to {}"), bm2n.remoteName);
347 bm2n.prepareEstablishment();
349 PRECICE_DEBUG(
"Established primary connection {} {}", (requesting ?
"from " :
"to "), bm2n.remoteName);
356 Event e3(
"repartitioning");
360 PRECICE_INFO(
"Setting up preliminary secondary communication to coupling partner/s");
361 for (
auto &m2nPair :
_m2ns) {
362 auto &bm2n = m2nPair.second;
363 bm2n.preConnectSecondaryRanks();
369 PRECICE_INFO(
"Setting up secondary communication to coupling partner/s");
370 Event e4(
"connectSecondaries");
371 for (
auto &m2nPair :
_m2ns) {
372 auto &bm2n = m2nPair.second;
373 bm2n.connectSecondaryRanks();
374 PRECICE_DEBUG(
"Established secondary connection {} {}", (bm2n.isRequesting ?
"from " :
"to "), bm2n.remoteName);
378 for (
auto &m2nPair :
_m2ns) {
379 m2nPair.second.cleanupEstablishment();
388 watchPoint->initialize();
391 watchIntegral->initialize();
396 double computedTimeStepSize)
402 PRECICE_CHECK(
_userEvents.empty(),
"There are unstopped user defined events. Please stop them using stopLastProfilingSection() before calling advance().");
419 PRECICE_CHECK(computedTimeStepSize > 0.0,
"advance() cannot be called with a negative time step size {}.", computedTimeStepSize);
431 const bool isAtWindowEnd =
_couplingScheme->addComputedTime(computedTimeStepSize);
438 int sumOfChanges =
std::accumulate(totalMeshChanges.begin(), totalMeshChanges.end(), 0);
456 const bool timeWindowComplete =
_couplingScheme->isTimeWindowComplete();
458 handleDataAfterAdvance(isAtWindowEnd, timeWindowComplete, timeSteppedTo, timeAfterAdvance, dataToReceive);
462 PRECICE_DEBUG(
"Mapped {} samples in write mappings and {} samples in read mappings",
493 if (reachedTimeWindowEnd) {
501 if (!reachedTimeWindowEnd) {
508 PRECICE_ASSERT(
math::greaterEquals(timeAfterAdvance, timeSteppedTo),
"We must have stayed or moved forwards in time (min-time-step-size).", timeAfterAdvance, timeSteppedTo);
519 if (reachedTimeWindowEnd) {
526 for (
auto &context :
_accessor->readDataContexts()) {
527 context.invalidateMappingCache();
531 for (
auto &context :
_accessor->writeDataContexts()) {
532 context.invalidateMappingCache();
537 for (
auto &context :
_accessor->readDataContexts()) {
538 context.resetInitialGuesses();
540 for (
auto &context :
_accessor->writeDataContexts()) {
541 context.resetInitialGuesses();
551 for (
auto &context :
_accessor->writeDataContexts()) {
568 context.completeJustInTimeMapping();
569 context.storeBufferedData(
time);
575 for (
auto &context :
_accessor->usedMeshContexts()) {
576 for (
const auto &name : context->mesh->availableData()) {
577 context->mesh->data(name)->timeStepsStorage().trimBefore(
time);
584 for (
auto &context :
_accessor->writeDataContexts()) {
585 context.trimAfter(
time);
631#ifndef PRECICE_NO_GINKGO
645 return _accessor->usedMeshContext(meshName).mesh->getDimensions();
653 return _accessor->usedMeshContext(meshName).mesh->data(dataName)->getDimensions();
676 const double nextTimeStepSize =
_couplingScheme->getNextTimeStepMaxSize();
684 "preCICE just returned a maximum time step size of {}. Such a small value can happen if you use many substeps per time window over multiple time windows due to added-up differences of machine precision.",
686 return nextTimeStepSize;
734 if (!
_accessor->isDataWrite(meshName, dataName))
749 "initialize() has to be called before accessing data of the received mesh \"{}\" on participant \"{}\".",
758 "but no access region was defined although this is necessary for parallel runs. "
759 "Please define an access region using \"setMeshAccessRegion()\" before calling \"getMeshVertexSize()\".",
764 PRECICE_DEBUG(
"Filtered {} of {} vertices out on mesh {} due to the local access region. Mesh size in the access region: {}", context.
mesh->
nVertices() - result, context.
mesh->
nVertices(), meshName, result);
769 "You are calling \"getMeshVertexSize()\" on a received mesh without api-access enabled (<receive-mesh name=\"{0}\" ... api-access=\"false\"/>). "
770 "Note that enabling api-access is required for this function to work properly with direct mesh access and just-in-time mappings.",
781 PRECICE_CHECK(
_allowsRemeshing,
"Cannot reset meshes. This feature needs to be enabled using <precice-configuration experimental=\"1\" allow-remeshing=\"1\">.");
786 PRECICE_CHECK(
_couplingScheme->isTimeWindowComplete(),
"Cannot remesh while subcycling or iterating. Remeshing is only allowed when the time window is completed.");
803 "Cannot set vertex for mesh \"{}\". Expected {} position components but found {}.", meshName,
mesh.getDimensions(), position.
size());
805 auto index =
mesh.createVertex(Eigen::Map<const Eigen::VectorXd>{position.
data(),
mesh.getDimensions()}).getID();
806 mesh.allocateDataValues();
808 const auto newSize =
mesh.nVertices();
809 for (
auto &context :
_accessor->writeDataContexts()) {
810 if (context.getMeshName() ==
mesh.getName()) {
811 context.resizeBufferTo(newSize);
828 const auto meshDims =
mesh.getDimensions();
829 const auto expectedPositionSize = ids.
size() * meshDims;
831 "Input sizes are inconsistent attempting to set vertices on {}D mesh \"{}\". "
832 "You passed {} vertex indices and {} position components, but we expected {} position components ({} x {}).",
833 meshDims, meshName, ids.
size(), positions.
size(), expectedPositionSize, ids.
size(), meshDims);
836 const Eigen::Map<const Eigen::MatrixXd> posMatrix{
837 positions.
data(),
mesh.getDimensions(),
static_cast<EIGEN_DEFAULT_DENSE_INDEX_TYPE
>(ids.
size())};
838 for (
unsigned long i = 0; i < ids.
size(); ++i) {
839 ids[i] =
mesh.createVertex(posMatrix.col(i)).getID();
841 mesh.allocateDataValues();
843 const auto newSize =
mesh.nVertices();
844 for (
auto &context :
_accessor->writeDataContexts()) {
845 if (context.getMeshName() ==
mesh.getName()) {
846 context.resizeBufferTo(newSize);
870 mesh.createEdge(v0, v1);
886 "Cannot interpret passed vertex IDs attempting to set edges of mesh \"{}\" . "
887 "You passed {} vertex indices, but we expected an even number.",
888 meshName, vertices.
size());
890 auto end = vertices.
end();
892 return !mesh.isValidVertexID(vid);
902 for (
unsigned long i = 0; i < vertices.
size() / 2; ++i) {
903 auto aid = vertices[2 * i];
904 auto bid = vertices[2 * i + 1];
928 "setMeshTriangle() was called with repeated Vertex IDs ({}, {}, {}).",
929 first, second, third);
935 mesh.createTriangle(A, B, C);
951 "Cannot interpret passed vertex IDs attempting to set triangles of mesh \"{}\" . "
952 "You passed {} vertex indices, which isn't dividable by 3.",
953 meshName, vertices.
size());
955 auto end = vertices.
end();
957 return !mesh.isValidVertexID(vid);
967 for (
unsigned long i = 0; i < vertices.
size() / 3; ++i) {
968 auto aid = vertices[3 * i];
969 auto bid = vertices[3 * i + 1];
970 auto cid = vertices[3 * i + 2];
971 mesh.createTriangle(
mesh.vertex(aid),
985 second, third, fourth);
1005 "The four vertices that form the quad are not unique. The resulting shape may be a point, line or triangle. "
1006 "Please check that the adapter sends the four unique vertices that form the quad, or that the mesh on the interface is composed of quads.");
1009 PRECICE_CHECK(convexity.convex,
"The given quad is not convex. "
1010 "Please check that the adapter send the four correct vertices or that the interface is composed of quads.");
1018 double distance02 = (reordered[0]->getCoords() - reordered[2]->getCoords()).norm();
1019 double distance13 = (reordered[1]->getCoords() - reordered[3]->getCoords()).norm();
1022 if (distance02 <= distance13) {
1023 mesh.createTriangle(*reordered[0], *reordered[2], *reordered[1]);
1024 mesh.createTriangle(*reordered[0], *reordered[2], *reordered[3]);
1026 mesh.createTriangle(*reordered[1], *reordered[3], *reordered[0]);
1027 mesh.createTriangle(*reordered[1], *reordered[3], *reordered[2]);
1044 "Cannot interpret passed vertex IDs attempting to set quads of mesh \"{}\" . "
1045 "You passed {} vertex indices, which isn't dividable by 4.",
1046 meshName, vertices.
size());
1048 auto end = vertices.
end();
1050 return !mesh.isValidVertexID(vid);
1058 for (
unsigned long i = 0; i < vertices.
size() / 4; ++i) {
1059 auto aid = vertices[4 * i];
1060 auto bid = vertices[4 * i + 1];
1061 auto cid = vertices[4 * i + 2];
1062 auto did = vertices[4 * i + 3];
1065 PRECICE_CHECK(
utils::unique_elements(vertexIDs),
"The four vertex ID's of the quad nr {} are not unique. Please check that the vertices that form the quad are correct.", i);
1069 "The four vertices that form the quad nr {} are not unique. The resulting shape may be a point, line or triangle. "
1070 "Please check that the adapter sends the four unique vertices that form the quad, or that the mesh on the interface is composed of quads.",
1074 PRECICE_CHECK(convexity.convex,
"The given quad nr {} is not convex. "
1075 "Please check that the adapter send the four correct vertices or that the interface is composed of quads.",
1083 double distance02 = (reordered[0]->getCoords() - reordered[2]->getCoords()).norm();
1084 double distance13 = (reordered[1]->getCoords() - reordered[3]->getCoords()).norm();
1086 if (distance02 <= distance13) {
1087 mesh.createTriangle(*reordered[0], *reordered[2], *reordered[1]);
1088 mesh.createTriangle(*reordered[0], *reordered[2], *reordered[3]);
1090 mesh.createTriangle(*reordered[1], *reordered[3], *reordered[0]);
1091 mesh.createTriangle(*reordered[1], *reordered[3], *reordered[2]);
1107 "Please set the mesh dimension to 3 in the preCICE configuration file.");
1125 mesh.createTetrahedron(A, B, C, D);
1136 "Please set the mesh dimension to 3 in the preCICE configuration file.");
1143 "Cannot interpret passed vertex IDs attempting to set quads of mesh \"{}\" . "
1144 "You passed {} vertex indices, which isn't dividable by 4.",
1145 meshName, vertices.
size());
1147 auto end = vertices.
end();
1149 return !mesh.isValidVertexID(vid);
1159 for (
unsigned long i = 0; i < vertices.
size() / 4; ++i) {
1160 auto aid = vertices[4 * i];
1161 auto bid = vertices[4 * i + 1];
1162 auto cid = vertices[4 * i + 2];
1163 auto did = vertices[4 * i + 3];
1164 mesh.createTetrahedron(
mesh.vertex(aid),
1179 PRECICE_CHECK(
_state ==
State::Constructed || (
_state ==
State::Initialized &&
isCouplingOngoing()),
"Calling writeData(...) is forbidden if coupling is not ongoing, because the data you are trying to write will not be used anymore. You can fix this by always calling writeData(...) before the advance(...) call in your simulation loop or by using Participant::isCouplingOngoing() to implement a safeguard.");
1189 const auto expectedDataSize = vertices.
size() * dataDims;
1191 "Input sizes are inconsistent attempting to write {}D data \"{}\" to mesh \"{}\". "
1192 "You passed {} vertex indices and {} data components, but we expected {} data components ({} x {}).",
1193 dataDims, dataName, meshName,
1194 vertices.
size(), values.
size(), expectedDataSize, dataDims, vertices.
size());
1200 PRECICE_ERROR(
"Cannot write data \"{}\" to mesh \"{}\" due to invalid Vertex ID at vertices[{}]. "
1201 "Please make sure you only use the results from calls to setMeshVertex/Vertices().",
1202 dataName, meshName, *index);
1212 double relativeReadTime,
1219 PRECICE_CHECK(relativeReadTime >= 0,
"readData(...) cannot sample data before the current time.");
1220 PRECICE_CHECK(
isCouplingOngoing() ||
math::equals(relativeReadTime, 0.0),
"Calling readData(...) with relativeReadTime = {} is forbidden if coupling is not ongoing. If coupling finished, only data for relativeReadTime = 0 is available. Please always use precice.getMaxTimeStepSize() to obtain the maximum allowed relativeReadTime.", relativeReadTime);
1225 "Cannot read from mesh \"{}\" after it has been reset. Please read data before calling resetMesh().",
1235 "This is typically a configuration issue of the data flow. "
1236 "Check if the data is correctly exchanged to this participant \"{}\" and mapped to mesh \"{}\".",
1240 const auto expectedDataSize = vertices.
size() * dataDims;
1242 "Input/Output sizes are inconsistent attempting to read {}D data \"{}\" from mesh \"{}\". "
1243 "You passed {} vertex indices and {} data components, but we expected {} data components ({} x {}).",
1244 dataDims, dataName, meshName,
1245 vertices.
size(), values.
size(), expectedDataSize, dataDims, vertices.
size());
1248 PRECICE_ERROR(
"Cannot read data \"{}\" from mesh \"{}\" due to invalid Vertex ID at vertices[{}]. "
1249 "Please make sure you only use the results from calls to setMeshVertex/Vertices().",
1250 dataName, meshName, *index);
1256 context.
readValues(vertices, readTime, values);
1263 double relativeReadTime,
1271 PRECICE_CHECK(relativeReadTime >= 0,
"mapAndReadData(...) cannot sample data before the current time.");
1272 PRECICE_CHECK(
isCouplingOngoing() ||
math::equals(relativeReadTime, 0.0),
"Calling mapAndReadData(...) with relativeReadTime = {} is forbidden if coupling is not ongoing. If coupling finished, only data for relativeReadTime = 0 is available. Please always use precice.getMaxTimeStepSize() to obtain the maximum allowed relativeReadTime.", relativeReadTime);
1278 "This participant attempteded to map and read data (via \"mapAndReadData\") from mesh \"{0}\", "
1279 "but mesh \"{0}\" is either not a received mesh or its api access was not enabled in the configuration. "
1280 "mapAndReadData({0}, ...) is only valid for (<receive-mesh name=\"{0}\" ... api-access=\"true\"/>).",
1285 "The function \"mapAndReadData\" was called on mesh \"{0}\", "
1286 "but no access region was defined although this is necessary for parallel runs. "
1287 "Please define an access region using \"setMeshAccessRegion()\" before calling \"mapAndReadData()\".",
1290 PRECICE_CHECK(!
_accessor->meshContext(meshName).mesh->empty(),
"This participant tries to mapAndRead data values for data \"{0}\" on mesh \"{1}\", but the mesh \"{1}\" is empty within the defined access region on this rank. "
1291 "How should the provided data values be read? Please make sure the mesh \"{1}\" is non-empty within the access region.",
1292 dataName, meshName);
1296 "The function \"mapAndReadData\" was called on mesh \"{0}\", but no matching just-in-time mapping was configured. "
1297 "Please define a mapping in read direction from the mesh \{0}\" and omit the \"to\" attribute from the definition. "
1298 "Example \"<mapping:nearest-neighbor direction=\"read\" from=\"{0}\" constraint=\"consistent\" />",
1311 const auto nVertices = (coordinates.
size() / dim);
1319 "Input sizes are inconsistent attempting to mapAndRead {}D data \"{}\" from mesh \"{}\". "
1320 "You passed {} vertex indices and {} data components, but we expected {} data components ({} x {}).",
1321 dataDims, dataName, meshName,
1322 nVertices, values.
size(), nVertices * dataDims, dataDims, nVertices);
1338 PRECICE_CHECK(
_state ==
State::Initialized &&
isCouplingOngoing(),
"Calling writeAndMapData(...) is forbidden if coupling is not ongoing, because the data you are trying to write will not be used anymore. You can fix this by always calling writeAndMapData(...) before the advance(...) call in your simulation loop or by using Participant::isCouplingOngoing() to implement a safeguard.");
1344 "This participant attempteded to map and read data (via \"writeAndMapData\") from mesh \"{0}\", "
1345 "but mesh \"{0}\" is either not a received mesh or its api access was not enabled in the configuration. "
1346 "writeAndMapData({0}, ...) is only valid for (<receive-mesh name=\"{0}\" ... api-access=\"true\"/>).",
1351 "The function \"writeAndMapData\" was called on mesh \"{0}\", "
1352 "but no access region was defined although this is necessary for parallel runs. "
1353 "Please define an access region using \"setMeshAccessRegion()\" before calling \"writeAndMapData()\".",
1358 "The function \"writeAndMapData\" was called on mesh \"{0}\", but no matching just-in-time mapping was configured. "
1359 "Please define a mapping in write direction to the mesh \{0}\" and omit the \"from\" attribute from the definition. "
1360 "Example \"<mapping:nearest-neighbor direction=\"write\" to=\"{0}\" constraint=\"conservative\" />",
1373 const auto nVertices = (coordinates.
size() / dim);
1380 "Input sizes are inconsistent attempting to write {}D data \"{}\" to mesh \"{}\". "
1381 "You passed {} vertex indices and {} data components, but we expected {} data components ({} x {}).",
1382 dataDims, dataName, meshName,
1383 nVertices, values.
size(), nVertices * dataDims, dataDims, nVertices);
1385 PRECICE_CHECK(!context.
mesh->
empty(),
"This participant tries to mapAndWrite data values for data \"{0}\" on mesh \"{1}\", but the mesh \"{1}\" is empty within the defined access region on this rank. "
1386 "Where should the provided data go? Please make sure the mesh \"{1}\" is non-empty within the access region.",
1387 dataName, meshName);
1413 PRECICE_CHECK(context.
hasGradient(),
"Data \"{}\" has no gradient values available. Please set the gradient flag to true under the data attribute in the configuration file.", dataName);
1416 PRECICE_ERROR(
"Cannot write gradient data \"{}\" to mesh \"{}\" due to invalid Vertex ID at vertices[{}]. "
1417 "Please make sure you only use the results from calls to setMeshVertex/Vertices().",
1418 dataName, meshName, *index);
1423 const auto gradientComponents = meshDims * dataDims;
1424 const auto expectedComponents = vertices.
size() * gradientComponents;
1426 "Input sizes are inconsistent attempting to write gradient for data \"{}\" to mesh \"{}\". "
1427 "A single gradient/Jacobian for {}D data on a {}D mesh has {} components. "
1428 "You passed {} vertex indices and {} gradient components, but we expected {} gradient components. ",
1430 dataDims, meshDims, gradientComponents,
1431 vertices.
size(), gradients.
size(), expectedComponents);
1447 "This participant attempteded to set an access region (via \"setMeshAccessRegion\") on mesh \"{0}\", "
1448 "but mesh \"{0}\" is either not a received mesh or its api access was not enabled in the configuration. "
1449 "setMeshAccessRegion(...) is only valid for (<receive-mesh name=\"{0}\" ... api-access=\"true\"/>).",
1459 int dim =
mesh.getDimensions();
1461 "Incorrect amount of bounding box components attempting to set the bounding box of {}D mesh \"{}\" . "
1462 "You passed {} limits, but we expected {} ({}x2).",
1463 dim, meshName, boundingBox.
size(), dim * 2, dim);
1469 for (
int d = 0; d < dim; ++d) {
1471 PRECICE_CHECK(boundingBox[2 * d] <= boundingBox[2 * d + 1],
"Your bounding box is ill defined, i.e. it has a negative volume. The required format is [x_min, x_max...]");
1472 bounds[2 * d] = boundingBox[2 * d];
1473 bounds[2 * d + 1] = boundingBox[2 * d + 1];
1489 "This participant attempteded to get mesh vertex IDs and coordinates (via \"getMeshVertexIDsAndCoordinates\") from mesh \"{0}\", "
1490 "but mesh \"{0}\" is either not a received mesh or its api access was not enabled in the configuration. "
1491 "getMeshVertexIDsAndCoordinates(...) is only valid for (<receive-mesh name=\"{0}\" ... api-access=\"true\"/>).",
1496 "The function \"getMeshVertexIDsAndCoordinates\" was called on mesh \"{0}\", "
1497 "but no access region was defined although this is necessary for parallel runs. "
1498 "Please define an access region using \"setMeshAccessRegion()\" before calling \"getMeshVertexIDsAndCoordinates()\".",
1505 "initialize() has to be called before accessing data of the received mesh \"{}\" on participant \"{}\".",
1517 const auto meshSize = filteredVertices.size();
1520 const auto meshDims =
mesh.getDimensions();
1522 "Output size is incorrect attempting to get vertex ids of {}D mesh \"{}\". "
1523 "You passed {} vertex indices, but we expected {}. "
1524 "Use getMeshVertexSize(\"{}\") to receive the required amount of vertices.",
1525 meshDims, meshName, ids.
size(), meshSize, meshName);
1526 const auto expectedCoordinatesSize =
static_cast<unsigned long>(meshDims * meshSize);
1528 "Output size is incorrect attempting to get vertex coordinates of {}D mesh \"{}\". "
1529 "You passed {} coordinate components, but we expected {} ({}x{}). "
1530 "Use getMeshVertexSize(\"{}\") and getMeshDimensions(\"{}\") to receive the required amount components",
1531 meshDims, meshName, coordinates.
size(), expectedCoordinatesSize, meshSize, meshDims, meshName, meshName);
1533 PRECICE_ASSERT(ids.
size() <=
mesh.nVertices(),
"The queried size exceeds the number of available points.");
1535 Eigen::Map<Eigen::MatrixXd> posMatrix{
1536 coordinates.
data(),
mesh.getDimensions(),
static_cast<EIGEN_DEFAULT_DENSE_INDEX_TYPE
>(ids.
size())};
1538 for (
unsigned long i = 0; i < ids.
size(); i++) {
1539 auto localID = filteredVertices[i].get().getID();
1542 posMatrix.col(i) = filteredVertices[i].get().getCoords();
1551 return lhs->mesh->getName() < rhs->mesh->getName();
1555 if (meshContext->provideMesh)
1556 meshContext->mesh->computeBoundingBox();
1558 meshContext->clearMappings();
1562 meshContext->partition->compareBoundingBoxes();
1572 auto &contexts =
_accessor->usedMeshContexts();
1574 std::sort(contexts.begin(), contexts.end(),
1576 return lhs->mesh->getName() < rhs->mesh->getName();
1580 meshContext->partition->communicate();
1587 for (
auto &m2nPair :
_m2ns) {
1588 if (m2nPair.second.m2n->usesTwoLevelInitialization()) {
1597 [](
MeshContext const *
const meshContext) ->
bool {
1598 return meshContext->provideMesh;
1603 meshContext->partition->compute();
1604 if (not meshContext->provideMesh) {
1605 meshContext->mesh->computeBoundingBox();
1608 meshContext->mesh->allocateDataValues();
1610 const auto requiredSize = meshContext->mesh->nVertices();
1611 for (
auto &context :
_accessor->writeDataContexts()) {
1612 if (context.getMeshName() == meshContext->mesh->getName()) {
1613 context.resizeBufferTo(requiredSize);
1622 bool anyMappingChanged =
false;
1624 if (not context.mapping->hasComputedMapping()) {
1626 "Automatic RBF mapping alias from mesh \"{}\" to mesh \"{}\" in \"{}\" direction resolves to \"{}\" .",
1627 context.mapping->getInputMesh()->getName(), context.mapping->getOutputMesh()->getName(), mappingType, context.mapping->getName());
1628 PRECICE_INFO(
"Computing \"{}\" mapping from mesh \"{}\" to mesh \"{}\" in \"{}\" direction.",
1629 context.mapping->getName(), context.mapping->getInputMesh()->getName(), context.mapping->getOutputMesh()->getName(), mappingType);
1630 context.mapping->computeMapping();
1631 anyMappingChanged =
true;
1634 if (anyMappingChanged) {
1635 _accessor->initializeMappingDataCache(mappingType);
1648 for (
auto &context :
_accessor->writeDataContexts()) {
1649 if (context.hasMapping()) {
1650 PRECICE_DEBUG(
"Map initial write data \"{}\" from mesh \"{}\"", context.getDataName(), context.getMeshName());
1665 for (
auto &context :
_accessor->writeDataContexts()) {
1666 if (context.hasMapping()) {
1667 PRECICE_DEBUG(
"Map write data \"{}\" from mesh \"{}\"", context.getDataName(), context.getMeshName());
1676 for (
auto &context :
_accessor->readDataContexts()) {
1677 if (context.hasMapping()) {
1682 context.clearToDataFor(fromData);
1684 context.trimToDataAfterFor(fromData, startOfTimeWindow);
1699 for (
auto &context :
_accessor->readDataContexts()) {
1700 if (context.hasMapping()) {
1701 PRECICE_DEBUG(
"Map initial read data \"{}\" to mesh \"{}\"", context.getDataName(), context.getMeshName());
1717 for (
auto &context :
_accessor->readDataContexts()) {
1718 if (context.hasMapping()) {
1719 PRECICE_DEBUG(
"Map read data \"{}\" to mesh \"{}\"", context.getDataName(), context.getMeshName());
1762 for (
auto &context :
_accessor->writeDataContexts()) {
1764 context.resetBufferedData();
1771 const auto &partConfig = *
config.getParticipantConfiguration();
1773 "This participant's name, which was specified in the constructor of the preCICE interface as \"{}\", "
1774 "is not defined in the preCICE configuration. "
1775 "Please double-check the correct spelling.",
1803 "Found ambiguous values for the time step size passed to preCICE in \"advance\". On rank {}, the value is {}, while on rank 0, the value is {}.",
1804 secondaryRank, dt, computedTimeStepSize);
1816 [[maybe_unused]]
auto remoteChanges1 =
_couplingScheme->firstSynchronization(localChanges);
1819 [[maybe_unused]]
auto remoteChanges2 =
_couplingScheme->secondSynchronization();
1832 for (
auto &iter :
_m2ns) {
1833 auto bm2n = iter.second;
1834 if (!bm2n.m2n->isConnected()) {
1835 PRECICE_DEBUG(
"Skipping closure of defective connection with {}", bm2n.remoteName);
1839 auto comm = bm2n.m2n->getPrimaryRankCommunication();
1840 PRECICE_DEBUG(
"Synchronizing primary rank with {}", bm2n.remoteName);
1841 if (bm2n.isRequesting) {
1842 comm->send(ping, 0);
1844 comm->receive(receive, 0);
1848 comm->receive(receive, 0);
1850 comm->send(pong, 0);
1854 PRECICE_DEBUG(
"Closing distributed communication with {}", bm2n.remoteName);
1855 bm2n.m2n->closeDistributedConnections();
1857 PRECICE_DEBUG(
"Closing communication with {}", bm2n.remoteName);
1858 bm2n.m2n->closeConnection();
1871 return *
_accessor->usedMeshContext(meshName).mesh;
1892 for (
auto context :
_accessor->usedMeshContexts()) {
1895 PRECICE_DEBUG(
"Mesh changes of rank: {}", localMeshChanges);
1903 PRECICE_DEBUG(
"Mesh changes of participant: {}", totalMeshChangesInt);
1904 return totalMeshChangesInt;
1909 auto meshContexts =
_accessor->usedMeshContexts();
1911 if (totalMeshChanges[i] > 0.0) {
1912 meshContexts[i]->mesh->clearDataStamples();
1924 PRECICE_DEBUG(
"Remeshing is{} required by this participant.", (requestReinit ?
"" :
" not"));
1926 bool swarmReinitRequired = requestReinit;
1927 for (
auto &iter :
_m2ns) {
1928 PRECICE_DEBUG(
"Coordinating remeshing with {}", iter.first);
1929 bool received =
false;
1930 auto &comm = *iter.second.m2n->getPrimaryRankCommunication();
1931 if (iter.second.isRequesting) {
1932 comm.send(requestReinit, 0);
1933 comm.receive(received, 0);
1935 comm.receive(received, 0);
1936 comm.send(requestReinit, 0);
1938 swarmReinitRequired |= received;
1940 PRECICE_DEBUG(
"Coordinated that overall{} remeshing is required.", (swarmReinitRequired ?
"" :
" no"));
1943 return swarmReinitRequired;
1945 bool swarmReinitRequired =
false;
1947 return swarmReinitRequired;
1954 "The provided section name \"{}\" may not contain a forward-slash \"/\"",
#define PRECICE_ERROR(...)
#define PRECICE_WARN_IF(condition,...)
#define PRECICE_DEBUG(...)
#define PRECICE_TRACE(...)
#define PRECICE_INFO_IF(condition,...)
#define PRECICE_INFO(...)
#define PRECICE_CHECK(check,...)
#define PRECICE_VALIDATE_DATA_NAME(mesh, data)
#define PRECICE_REQUIRE_DATA_WRITE(mesh, data)
#define PRECICE_REQUIRE_MESH_USE(name)
#define PRECICE_REQUIRE_DATA_READ(mesh, data)
#define PRECICE_REQUIRE_MESH_MODIFY(name)
#define PRECICE_VALIDATE_DATA(data, size)
#define PRECICE_EXPERIMENTAL_API()
#define PRECICE_VALIDATE_MESH_NAME(name)
#define PRECICE_ASSERT(...)
int getDimensions() const
void clear()
Removes all mesh elements and data values (does not remove data or the bounding boxes).
const std::string & getName() const
Returns the name of the mesh, as set in the config file.
std::size_t nVertices() const
Returns the number of vertices.
bool empty() const
Does the mesh contain any vertices?
Main class for preCICE XML configuration tree.
@ WriteCheckpoint
Is the participant required to write a checkpoint?
@ ReadCheckpoint
Is the participant required to read a previously written checkpoint?
@ InitializeData
Is the initialization of coupling data required?
bool hasJustInTimeMapping() const
bool hasGradient() const
Returns whether _providedData has gradient.
int getDataDimensions() const
Get the dimensions of _providedData.
int getSpatialDimensions() const
Get the spatial dimensions of _providedData.
std::optional< std::size_t > locateInvalidVertexID(const Container &c)
CloseChannels
Which channels to close in closeCommunicationChannels()
void writeGradientData(std::string_view meshName, std::string_view dataName, ::precice::span< const VertexID > vertices, ::precice::span< const double > gradients)
Writes vector gradient data to a mesh.
int getMeshVertexSize(std::string_view meshName) const
Returns the number of vertices of a mesh.
utils::MultiLock< std::string > _meshLock
void setMeshQuad(std::string_view meshName, VertexID first, VertexID second, VertexID third, VertexID fourth)
Sets a planar surface mesh quadrangle from vertex IDs.
bool requiresInitialData()
void setMeshTetrahedra(std::string_view meshName, ::precice::span< const VertexID > vertices)
Sets multiple mesh tetrahedra from vertex IDs.
bool requiresGradientDataFor(std::string_view meshName, std::string_view dataName) const
Checks if the given data set requires gradient data. We check if the data object has been initialized...
int getDataDimensions(std::string_view meshName, std::string_view dataName) const
Returns the spatial dimensionality of the given data on the given mesh.
impl::PtrParticipant determineAccessingParticipant(const config::Configuration &config)
Determines participant accessing this interface from the configuration.
MeshChanges getTotalMeshChanges() const
void advanceCouplingScheme()
Advances the coupling schemes.
void computePartitions()
Communicate meshes and create partitions.
void setMeshEdge(std::string_view meshName, VertexID first, VertexID second)
Sets a mesh edge from vertex IDs.
std::vector< impl::PtrParticipant > _participants
Holds information about solvers participating in the coupled simulation.
bool requiresMeshConnectivityFor(std::string_view meshName) const
Checks if the given mesh requires connectivity.
void setMeshTriangles(std::string_view meshName, ::precice::span< const VertexID > vertices)
Sets multiple mesh triangles from vertex IDs.
int _executedReadMappings
Counts the amount of samples mapped in read mappings executed in the latest advance.
void clearStamplesOfChangedMeshes(MeshChanges totalMeshChanges)
Clears stample of changed meshes to make them consistent after the reinitialization.
void performDataActions(const std::set< action::Action::Timing > &timings)
Performs all data actions with given timing.
void setMeshTriangle(std::string_view meshName, VertexID first, VertexID second, VertexID third)
Sets mesh triangle from vertex IDs.
bool requiresWritingCheckpoint()
double getMaxTimeStepSize() const
Get the maximum allowed time step size of the current window.
cplscheme::PtrCouplingScheme _couplingScheme
long int _numberAdvanceCalls
Counts calls to advance for plotting.
bool _allowsExperimental
Are experimental API calls allowed?
void handleDataBeforeAdvance(bool reachedTimeWindowEnd, double timeSteppedTo)
Completes everything data-related between adding time to and advancing the coupling scheme.
void setMeshTetrahedron(std::string_view meshName, VertexID first, VertexID second, VertexID third, VertexID fourth)
Set tetrahedron in 3D mesh from vertex ID.
void handleDataAfterAdvance(bool reachedTimeWindowEnd, bool isTimeWindowComplete, double timeSteppedTo, double timeAfterAdvance, const cplscheme::ImplicitData &receivedData)
Completes everything data-related after advancing the coupling scheme.
void samplizeWriteData(double time)
Creates a Stample at the given time for each write Data and zeros the buffers.
void setMeshQuads(std::string_view meshName, ::precice::span< const VertexID > vertices)
Sets multiple mesh quads from vertex IDs.
void getMeshVertexIDsAndCoordinates(std::string_view meshName, ::precice::span< VertexID > ids, ::precice::span< double > coordinates) const
getMeshVertexIDsAndCoordinates Iterates over the region of interest defined by bounding boxes and rea...
int _accessorCommunicatorSize
void closeCommunicationChannels(CloseChannels cc)
Syncs the primary ranks of all connected participants.
bool reinitHandshake(bool requestReinit) const
void trimSendDataAfter(double time)
Discards send (currently write) data of a participant after a given time when another iteration is re...
std::unique_ptr< profiling::Event > _solverInitEvent
ParticipantImpl(std::string_view participantName, std::string_view configurationFileName, int solverProcessIndex, int solverProcessSize, std::optional< void * > communicator)
Generic constructor for ParticipantImpl.
void advance(double computedTimeStepSize)
Advances preCICE after the solver has computed one time step.
std::string _accessorName
void setMeshAccessRegion(std::string_view meshName, ::precice::span< const double > boundingBox) const
setMeshAccessRegion Define a region of interest on a received mesh (<receive-mesh ....
void writeData(std::string_view meshName, std::string_view dataName, ::precice::span< const VertexID > vertices, ::precice::span< const double > values)
Writes data to a mesh.
void mapInitialReadData()
std::vector< profiling::Event > _userEvents
void handleExports(ExportTiming timing)
~ParticipantImpl()
Destructor.
bool isCouplingOngoing() const
Checks if the coupled simulation is still ongoing.
State _state
The current State of the Participant.
void mapInitialWrittenData()
Computes, and performs write mappings of the initial data in initialize.
impl::PtrParticipant _accessor
void setMeshVertices(std::string_view meshName, ::precice::span< const double > positions, ::precice::span< VertexID > ids)
Creates multiple mesh vertices.
void resetMesh(std::string_view meshName)
std::vector< int > MeshChanges
How many ranks have changed each used mesh.
MappedSamples mappedSamples() const
Returns the amount of mapped read and write samples in the last call to advance.
void finalize()
Finalizes preCICE.
bool requiresReadingCheckpoint()
int _executedWriteMappings
Counts the amount of samples mapped in write mappings executed in the latest advance.
void trimReadMappedData(double timeAfterAdvance, bool isTimeWindowComplete, const cplscheme::ImplicitData &fromData)
Removes samples in mapped to data connected to received data via a mapping.
std::map< std::string, m2n::BoundM2N > _m2ns
void reinitialize()
Reinitializes preCICE.
void setupWatcher()
Setup mesh watcher such as WatchPoints.
bool isTimeWindowComplete() const
Checks if the current coupling window is completed.
void setMeshEdges(std::string_view meshName, ::precice::span< const VertexID > vertices)
Sets multiple mesh edges from vertex IDs.
std::string _configHash
The hash of the configuration file used to configure this participant.
void setupCommunication()
Connect participants including repartitioning.
bool _allowsRemeshing
Are experimental remeshing API calls allowed?
VertexID setMeshVertex(std::string_view meshName, ::precice::span< const double > position)
Creates a mesh vertex.
void syncTimestep(double computedTimeStepSize)
Syncs the time step size between all ranks (all time steps sizes should be the same!...
void readData(std::string_view meshName, std::string_view dataName, ::precice::span< const VertexID > vertices, double relativeReadTime, ::precice::span< double > values) const
Reads data values from a mesh. Values correspond to a given point in time relative to the beginning o...
const mesh::Mesh & mesh(const std::string &meshName) const
Allows to access a registered mesh.
void compareBoundingBoxes()
Communicate bounding boxes and look for overlaps.
bool _waitInFinalize
Are participants waiting for each other in finalize?
void startProfilingSection(std::string_view eventName)
void initializeIntraCommunication()
Initializes intra-participant communication.
void resetWrittenData()
Resets written data.
void trimOldDataBefore(double time)
Discards data before the given time for all meshes and data known by this participant.
void mapAndReadData(std::string_view meshName, std::string_view dataName, ::precice::span< const double > coordinates, double relativeReadTime, ::precice::span< double > values) const
Reads data values from a mesh using a just-in-time data mapping. Values correspond to a given point i...
std::unique_ptr< profiling::Event > _solverAdvanceEvent
bool requiresUserDefinedAccessRegion(std::string_view meshName) const
void configure(std::string_view configurationFileName)
Configures the coupling interface from the given xml file.
void mapWrittenData(std::optional< double > after=std::nullopt)
Computes, and performs suitable write mappings either entirely or after given time.
void initialize()
Fully initializes preCICE and coupling data.
void writeAndMapData(std::string_view meshName, std::string_view dataName, ::precice::span< const double > coordinates, ::precice::span< const double > values)
Writes data values to a mesh using a just-in-time mapping (experimental).
void computeMappings(std::vector< MappingContext > &contexts, const std::string &mappingType)
Helper for mapWrittenData and mapReadData.
int getMeshDimensions(std::string_view meshName) const
Returns the spatial dimensionality of the given mesh.
void stopLastProfilingSection()
Stores one Data object with related mesh. Context stores data to be read from and potentially provide...
bool hasSamples() const
Are there samples to read from?
void readValues(::precice::span< const VertexID > vertices, double time, ::precice::span< double > values) const
Samples data at a given point in time within the current time window for given indices.
void mapAndReadValues(::precice::span< const double > coordinates, double readTime, ::precice::span< double > values)
Forwards the just-in-time mapping API call for reading data to the data context.
Stores one Data object with related mesh. Context stores data to be written to and potentially provid...
void writeGradientsIntoDataBuffer(::precice::span< const VertexID > vertices, ::precice::span< const double > gradients)
Store gradients in _writeDataBuffer.
void writeAndMapValues(::precice::span< const double > coordinates, ::precice::span< const double > values)
Forwards the just-in-time mapping API call for writing data to the data context.
void writeValuesIntoDataBuffer(::precice::span< const VertexID > vertices, ::precice::span< const double > values)
Store values in _writeDataBuffer.
Container and creator for meshes.
static EventRegistry & instance()
Returns the only instance (singleton) of the EventRegistry class.
void startBackend()
Create the file and starts the filestream if profiling is turned on.
void initialize(std::string_view applicationName, int rank=0, int size=1)
Sets the global start time.
void finalize()
Sets the global end time and flushes buffers.
void stop()
Stops a running event.
void addData(std::string_view key, int value)
Adds named integer data, associated to an event.
A C++ 11 implementation of the non-owning C++20 std::span type.
constexpr pointer data() const noexcept
PRECICE_SPAN_NODISCARD constexpr bool empty() const noexcept
constexpr iterator begin() const noexcept
constexpr iterator end() const noexcept
constexpr size_type size() const noexcept
static void barrier()
Synchronizes all ranks.
static void allreduceSum(precice::span< const double > sendData, precice::span< double > rcvData)
static bool isPrimary()
True if this process is running the primary rank.
static void broadcast(bool &value)
static auto allSecondaryRanks()
Returns an iterable range over salve ranks [1, _size)
static bool isParallel()
True if this process is running in parallel.
static bool isSecondary()
True if this process is running a secondary rank.
static com::PtrCommunication & getCommunication()
Intra-participant communication.
static void configure(Rank rank, int size)
Configures the intra-participant communication.
static void finalizeOrCleanupMPI()
Finalized a managed MPI environment or cleans up after an non-managed session.
static CommStatePtr current()
Returns an owning pointer to the current CommState.
static void initializeOrDetectMPI(std::optional< Communicator > userProvided=std::nullopt)
static void finalize()
Finalizes Petsc environment.
T current_path(T... args)
contains actions to modify exchanged data.
std::unique_ptr< Action > PtrAction
std::shared_ptr< WatchPoint > PtrWatchPoint
std::string errorInvalidVertexID(int vid)
static constexpr auto errorInvalidVertexIDRange
std::shared_ptr< ParticipantState > PtrParticipant
std::shared_ptr< WatchIntegral > PtrWatchIntegral
void setMPIRank(int const rank)
void setParticipant(std::string const &participant)
ConvexityResult isConvexQuad(std::array< Eigen::VectorXd, 4 > coords)
constexpr bool equals(const Eigen::MatrixBase< DerivedA > &A, const Eigen::MatrixBase< DerivedB > &B, double tolerance=NUMERICAL_ZERO_DIFFERENCE)
Compares two Eigen::MatrixBase for equality up to tolerance.
std::enable_if< std::is_arithmetic< Scalar >::value, bool >::type smallerEquals(Scalar A, Scalar B, Scalar tolerance=NUMERICAL_ZERO_DIFFERENCE)
constexpr double NUMERICAL_ZERO_DIFFERENCE
std::enable_if< std::is_arithmetic< Scalar >::value, bool >::type greaterEquals(Scalar A, Scalar B, Scalar tolerance=NUMERICAL_ZERO_DIFFERENCE)
std::enable_if< std::is_arithmetic< Scalar >::value, bool >::type greater(Scalar A, Scalar B, Scalar tolerance=NUMERICAL_ZERO_DIFFERENCE)
std::array< Eigen::VectorXd, n > coordsFor(const Mesh &mesh, const std::array< int, n > &vertexIDs)
Given a mesh and an array of vertexIDS, this function returns an array of coordinates of the vertices...
std::array< Vertex *, n > vertexPtrsFor(Mesh &mesh, const std::array< int, n > &vertexIDs)
Given a mesh and an array of vertexIDS, this function returns an array of pointers to vertices.
std::size_t countVerticesInBoundingBox(mesh::PtrMesh mesh, const mesh::BoundingBox &bb)
Given a Mesh and a bounding box, counts all vertices within the bounding box.
static constexpr Group API
Convenience instance of the Cat::API.
static constexpr SynchronizeTag Synchronize
Convenience instance of the SynchronizeTag.
static constexpr Group Fundamental
Convenience instance of the Cat::Fundamental.
contains the time interpolation logic.
auto reorder_array(const std::array< Index, n > &order, const std::array< T, n > &elements) -> std::array< T, n >
Reorders an array given an array of unique indices.
std::pair< InputIt, InputIt > find_first_range(InputIt first, InputIt last, Predicate p)
Finds the first range in [first, last[ that fulfills a predicate.
bool unique_elements(const Container &c, BinaryPredicate p={})
auto make_array(Elements &&...elements) -> std::array< typename std::common_type< Elements... >::type, sizeof...(Elements)>
Function that generates an array from given elements.
std::string configure(XMLTag &tag, const precice::xml::ConfigurationContext &context, std::string_view configurationFilename)
Configures the given configuration from file configurationFilename.
T stable_partition(T... args)
Holds a data mapping and related information.
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.
void checkVerticesInsideAccessRegion(precice::span< const double > coordinates, const int meshDim, std::string_view functionName) const
std::shared_ptr< mesh::BoundingBox > userDefinedAccessRegion
std::vector< std::reference_wrapper< const mesh::Vertex > > filterVerticesToLocalAccessRegion(bool requiresBB) const
Tightly coupled to the parameters of Participant()