preCICE v3.1.1
Loading...
Searching...
No Matches
ParticipantImpl.cpp
Go to the documentation of this file.
1#include <Eigen/Core>
2#include <Eigen/src/Core/util/Meta.h>
3#include <algorithm>
4#include <array>
5#include <cmath>
6#include <deque>
7#include <functional>
8#include <iterator>
9#include <memory>
10#include <optional>
11#include <ostream>
12#include <sstream>
13#include <tuple>
14#include <utility>
15
16#include "ParticipantImpl.hpp"
18#include "com/Communication.hpp"
19#include "com/SharedPointer.hpp"
23#include "io/Export.hpp"
24#include "io/ExportContext.hpp"
25#include "io/SharedPointer.hpp"
27#include "logging/LogMacros.hpp"
28#include "m2n/BoundM2N.hpp"
29#include "m2n/M2N.hpp"
30#include "m2n/SharedPointer.hpp"
32#include "mapping/Mapping.hpp"
35#include "math/differences.hpp"
36#include "math/geometry.hpp"
37#include "mesh/Data.hpp"
38#include "mesh/Edge.hpp"
39#include "mesh/Mesh.hpp"
41#include "mesh/Utils.hpp"
42#include "mesh/Vertex.hpp"
61#include "precice/impl/versions.hpp"
62#include "profiling/Event.hpp"
66#include "utils/EigenIO.hpp"
67#include "utils/Helpers.hpp"
68#include "utils/IntraComm.hpp"
69#include "utils/Parallel.hpp"
70#include "utils/Petsc.hpp"
71#include "utils/algorithm.hpp"
72#include "utils/assertion.hpp"
73#include "xml/XMLTag.hpp"
74
76
77namespace precice::impl {
78
80 std::string_view participantName,
81 std::string_view configurationFileName,
82 int solverProcessIndex,
83 int solverProcessSize,
84 std::optional<void *> communicator)
85 : _accessorName(participantName),
86 _accessorProcessRank(solverProcessIndex),
87 _accessorCommunicatorSize(solverProcessSize)
88{
89
90 PRECICE_CHECK(!communicator || communicator.value() != nullptr,
91 "Passing \"nullptr\" as \"communicator\" to Participant constructor is not allowed. "
92 "Please use the Participant constructor without the \"communicator\" argument, if you don't want to pass an MPI communicator.");
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.");
98 "The solver process index needs to be a non-negative number, not: {}. "
99 "Please check the value given when constructing a preCICE interface.",
102 "The solver process size needs to be a positive number, not: {}. "
103 "Please check the value given when constructing a preCICE interface.",
106 "The solver process index, currently: {} needs to be smaller than the solver process size, currently: {}. "
107 "Please check the values given when constructing a preCICE interface.",
109
110 // Set the global communicator to the passed communicator.
111 // This is a noop if preCICE is not configured with MPI.
112#ifndef PRECICE_NO_MPI
113 if (communicator.has_value()) {
114 auto commptr = static_cast<utils::Parallel::Communicator *>(communicator.value());
116 } else {
118 }
119#endif
120
122
125 Event e("construction", profiling::Fundamental);
126 profiling::ScopedEventPrefix sep("construction/");
127
128 Event e1("configure", profiling::Fundamental);
129 configure(configurationFileName);
130 e1.stop();
131
132 // Backend settings have been configured
133 Event e2("startProfilingBackend");
135 e2.stop();
136
137 PRECICE_DEBUG("Initialize intra-participant communication");
140 }
141
142 // This block cannot be merged with the one above as it only configures calls
143 // utils::Parallel::initializeMPI, which is needed for getProcessRank.
144#ifndef PRECICE_NO_MPI
145 const auto currentRank = utils::Parallel::current()->rank();
146 PRECICE_CHECK(_accessorProcessRank == currentRank,
147 "The solver process index given in the preCICE interface constructor({}) does not match the rank of the passed MPI communicator ({}).",
148 _accessorProcessRank, currentRank);
149 const auto currentSize = utils::Parallel::current()->size();
151 "The solver process size given in the preCICE interface constructor({}) does not match the size of the passed MPI communicator ({}).",
152 _accessorCommunicatorSize, currentSize);
153#endif
154
155 e.stop();
156 sep.pop();
157 _solverInitEvent = std::make_unique<profiling::Event>("solver.initialize", profiling::Fundamental, profiling::Synchronize);
158}
159
161{
162 if (_state != State::Finalized) {
163 PRECICE_INFO("Implicitly finalizing in destructor");
164 finalize();
165 }
166}
167
169 std::string_view configurationFileName)
170{
171
178 xml::configure(config.getXMLTag(), context, configurationFileName);
179 if (_accessorProcessRank == 0) {
180 PRECICE_INFO("This is preCICE version {}", PRECICE_VERSION);
181 PRECICE_INFO("Revision info: {}", precice::preciceRevision);
182 PRECICE_INFO("Build type: "
183#ifndef NDEBUG
184 "Debug"
185#else // NDEBUG
186 "Release"
187#ifndef PRECICE_NO_DEBUG_LOG
188 " + debug log"
189#else
190 " (without debug log)"
191#endif
192#ifndef PRECICE_NO_TRACE_LOG
193 " + trace log"
194#endif
195#ifndef PRECICE_NO_ASSERTIONS
196 " + assertions"
197#endif
198#endif // NDEBUG
199 );
200 PRECICE_INFO("Configuring preCICE with configuration \"{}\"", configurationFileName);
201 PRECICE_INFO("I am participant \"{}\"", _accessorName);
202 }
203
205
207
211 _accessor->setMeshIdManager(config.getMeshConfiguration()->extractMeshIdManager());
212
213 PRECICE_ASSERT(_accessorCommunicatorSize == 1 || _accessor->useIntraComm(),
214 "A parallel participant needs an intra-participant communication");
215 PRECICE_CHECK(not(_accessorCommunicatorSize == 1 && _accessor->useIntraComm()),
216 "You cannot use an intra-participant communication with a serial participant. "
217 "If you do not know exactly what an intra-participant communication is and why you want to use it "
218 "you probably just want to remove the intraComm tag from the preCICE configuration.");
219
221
222 _participants = config.getParticipantConfiguration()->getParticipants();
224
225 PRECICE_CHECK(_participants.size() > 1,
226 "In the preCICE configuration, only one participant is defined. "
227 "One participant makes no coupled simulation. "
228 "Please add at least another one.");
230
233 _couplingScheme = cplSchemeConfig->getCouplingScheme(_accessorName);
234
235 // Register all MeshIds to the lock, but unlock them straight away as
236 // writing is allowed after configuration.
237 for (const MeshContext *meshContext : _accessor->usedMeshContexts()) {
238 _meshLock.add(meshContext->mesh->getName(), false);
239 }
240}
241
243{
245 PRECICE_CHECK(_state != State::Finalized, "initialize() cannot be called after finalize().");
246 PRECICE_CHECK(_state != State::Initialized, "initialize() may only be called once.");
247 PRECICE_ASSERT(not _couplingScheme->isInitialized());
248
250 PRECICE_CHECK(not failedToInitialize,
251 "Initial data has to be written to preCICE before calling initialize(). "
252 "After defining your mesh, call requiresInitialData() to check if the participant is required to write initial data using the writeData() function.");
253
254 _solverInitEvent.reset();
256 profiling::ScopedEventPrefix sep("initialize/");
257
258 PRECICE_DEBUG("Preprocessing provided meshes");
259 for (MeshContext *meshContext : _accessor->usedMeshContexts()) {
260 if (meshContext->provideMesh) {
261 auto &mesh = *(meshContext->mesh);
262 Event e("preprocess." + mesh.getName(), profiling::Synchronize);
263 meshContext->mesh->preprocess();
264 }
265 }
266
267 // Setup communication
268
269 PRECICE_INFO("Setting up primary communication to coupling partner/s");
270 for (auto &m2nPair : _m2ns) {
271 auto &bm2n = m2nPair.second;
272 bool requesting = bm2n.isRequesting;
273 if (bm2n.m2n->isConnected()) {
274 PRECICE_DEBUG("Primary connection {} {} already connected.", (requesting ? "from" : "to"), bm2n.remoteName);
275 } else {
276 PRECICE_DEBUG((requesting ? "Awaiting primary connection from {}" : "Establishing primary connection to {}"), bm2n.remoteName);
277 bm2n.prepareEstablishment();
278 bm2n.connectPrimaryRanks();
279 PRECICE_DEBUG("Established primary connection {} {}", (requesting ? "from " : "to "), bm2n.remoteName);
280 }
281 }
282
283 PRECICE_INFO("Primary ranks are connected");
284
286
287 PRECICE_INFO("Setting up preliminary secondary communication to coupling partner/s");
288 for (auto &m2nPair : _m2ns) {
289 auto &bm2n = m2nPair.second;
290 bm2n.preConnectSecondaryRanks();
291 }
292
294
295 PRECICE_INFO("Setting up secondary communication to coupling partner/s");
296 for (auto &m2nPair : _m2ns) {
297 auto &bm2n = m2nPair.second;
298 bm2n.connectSecondaryRanks();
299 PRECICE_DEBUG("Established secondary connection {} {}", (bm2n.isRequesting ? "from " : "to "), bm2n.remoteName);
300 }
301 PRECICE_INFO("Secondary ranks are connected");
302
303 for (auto &m2nPair : _m2ns) {
304 m2nPair.second.cleanupEstablishment();
305 }
306
307 PRECICE_DEBUG("Initialize watchpoints");
308 for (PtrWatchPoint &watchPoint : _accessor->watchPoints()) {
309 watchPoint->initialize();
310 }
311 for (PtrWatchIntegral &watchIntegral : _accessor->watchIntegrals()) {
312 watchIntegral->initialize();
313 }
314
315 // Initialize coupling state, overwrite these values for restart
316 const double time = 0.0;
317 const int timeWindow = 1;
318
320
321 for (auto &context : _accessor->writeDataContexts()) {
322 context.storeBufferedData(time);
323 }
324
327
328 PRECICE_DEBUG("Initialize coupling schemes");
329 _couplingScheme->initialize(time, timeWindow);
330
333
334 PRECICE_DEBUG("Plot output");
335 _accessor->exportInitial();
336
338
339 e.stop();
340 sep.pop();
341
343 PRECICE_INFO(_couplingScheme->printCouplingState());
344 _solverAdvanceEvent = std::make_unique<profiling::Event>("solver.advance", profiling::Fundamental, profiling::Synchronize);
345}
346
348 double computedTimeStepSize)
349{
350
351 PRECICE_TRACE(computedTimeStepSize);
352
353 // Events for the solver time, stopped when we enter, restarted when we leave advance
354 PRECICE_ASSERT(_solverAdvanceEvent, "The advance event is created in initialize");
355 _solverAdvanceEvent->stop();
356
358 profiling::ScopedEventPrefix sep("advance/");
359
360 PRECICE_CHECK(_state != State::Constructed, "initialize() has to be called before advance().");
361 PRECICE_CHECK(_state != State::Finalized, "advance() cannot be called after finalize().");
362 PRECICE_CHECK(_state == State::Initialized, "initialize() has to be called before advance().");
363 PRECICE_ASSERT(_couplingScheme->isInitialized());
364 PRECICE_CHECK(isCouplingOngoing(), "advance() cannot be called when isCouplingOngoing() returns false.");
365 PRECICE_CHECK(!math::equals(computedTimeStepSize, 0.0), "advance() cannot be called with a time step size of 0.");
366 PRECICE_CHECK(computedTimeStepSize > 0.0, "advance() cannot be called with a negative time step size {}.", computedTimeStepSize);
368
369#ifndef NDEBUG
370 PRECICE_DEBUG("Synchronize time step size");
372 syncTimestep(computedTimeStepSize);
373 }
374#endif
375
376 // Update the coupling scheme time state. Necessary to get correct remainder.
377 const bool isAtWindowEnd = _couplingScheme->addComputedTime(computedTimeStepSize);
378 const double timeSteppedTo = _couplingScheme->getTime();
379 const auto dataToReceive = _couplingScheme->implicitDataToReceive();
380
381 handleDataBeforeAdvance(isAtWindowEnd, timeSteppedTo);
382
384
385 // In clase if an implicit scheme, this may be before timeSteppedTo
386 const double timeAfterAdvance = _couplingScheme->getTime();
387 const bool timeWindowComplete = _couplingScheme->isTimeWindowComplete();
388
389 handleDataAfterAdvance(isAtWindowEnd, timeWindowComplete, timeSteppedTo, timeAfterAdvance, dataToReceive);
390
391 PRECICE_INFO(_couplingScheme->printCouplingState());
392
393 PRECICE_DEBUG("Mapped {} samples in write mappings and {} samples in read mappings",
395
397
398 sep.pop();
399 e.stop();
400 _solverAdvanceEvent->start();
401}
402
403void ParticipantImpl::handleDataBeforeAdvance(bool reachedTimeWindowEnd, double timeSteppedTo)
404{
405 if (reachedTimeWindowEnd || _couplingScheme->requiresSubsteps()) {
406 samplizeWriteData(timeSteppedTo);
407 }
409
410 // Reset mapping counters here to cover subcycling
413
414 if (reachedTimeWindowEnd) {
415 mapWrittenData(_couplingScheme->getTimeWindowStart());
417 }
418}
419
420void ParticipantImpl::handleDataAfterAdvance(bool reachedTimeWindowEnd, bool isTimeWindowComplete, double timeSteppedTo, double timeAfterAdvance, const cplscheme::ImplicitData &receivedData)
421{
422 if (!reachedTimeWindowEnd) {
423 // We are subcycling
424 return;
425 }
426
428 // Move to next time window
429 PRECICE_ASSERT(math::greaterEquals(timeAfterAdvance, timeSteppedTo), "We must have stayed or moved forwards in time (min-time-step-size).", timeAfterAdvance, timeSteppedTo);
430
431 // As we move forward, there may now be old samples lying around
432 trimOldDataBefore(_couplingScheme->getTimeWindowStart());
433 } else {
434 // We are iterating
435 PRECICE_ASSERT(math::greater(timeSteppedTo, timeAfterAdvance), "We must have moved back in time!");
436
437 trimSendDataAfter(timeAfterAdvance);
438 }
439
440 if (reachedTimeWindowEnd) {
441 trimReadMappedData(timeAfterAdvance, isTimeWindowComplete, receivedData);
442 mapReadData();
444 }
445
447 // Reset initial guesses for iterative mappings
448 for (auto &context : _accessor->readDataContexts()) {
449 context.resetInitialGuesses();
450 }
451 for (auto &context : _accessor->writeDataContexts()) {
452 context.resetInitialGuesses();
453 }
454 }
455
457}
458
460{
461 // store buffered write data in sample storage and reset the buffer
462 for (auto &context : _accessor->writeDataContexts()) {
463 context.storeBufferedData(time);
464 }
465}
466
468{
469 for (auto &context : _accessor->usedMeshContexts()) {
470 for (const auto &name : context->mesh->availableData()) {
471 context->mesh->data(name)->timeStepsStorage().trimBefore(time);
472 }
473 }
474}
475
477{
478 for (auto &context : _accessor->writeDataContexts()) {
479 context.trimAfter(time);
480 }
481}
482
484{
486 PRECICE_CHECK(_state != State::Finalized, "finalize() may only be called once.");
487
488 // Events for the solver time, finally stopped here
489 _solverAdvanceEvent.reset();
490
491 Event e("finalize", profiling::Fundamental);
492 profiling::ScopedEventPrefix sep("finalize/");
493
494 if (_state == State::Initialized) {
495
496 PRECICE_ASSERT(_couplingScheme->isInitialized());
497 PRECICE_DEBUG("Finalize coupling scheme");
498 _couplingScheme->finalize();
499
501 }
502
503 // Release ownership
505 _participants.clear();
507
508 // Close Connections
509 PRECICE_DEBUG("Close intra-participant communication");
511 utils::IntraComm::getCommunication()->closeConnection();
513 }
514 _m2ns.clear();
515
516 // Stop and print Event logging
517 e.stop();
518
519 // Finalize PETSc and Events first
522
523 // Finally clear events and finalize MPI
526}
527
529{
530 PRECICE_TRACE(meshName);
532 return _accessor->usedMeshContext(meshName).mesh->getDimensions();
533}
534
536{
537 PRECICE_TRACE(meshName, dataName);
539 PRECICE_VALIDATE_DATA_NAME(meshName, dataName);
540 return _accessor->usedMeshContext(meshName).mesh->data(dataName)->getDimensions();
541}
542
544{
546 PRECICE_CHECK(_state != State::Finalized, "isCouplingOngoing() cannot be called after finalize().");
547 PRECICE_CHECK(_state == State::Initialized, "initialize() has to be called before isCouplingOngoing() can be evaluated.");
548 return _couplingScheme->isCouplingOngoing();
549}
550
552{
554 PRECICE_CHECK(_state != State::Constructed, "initialize() has to be called before isTimeWindowComplete().");
555 PRECICE_CHECK(_state != State::Finalized, "isTimeWindowComplete() cannot be called after finalize().");
556 return _couplingScheme->isTimeWindowComplete();
557}
558
560{
561 PRECICE_CHECK(_state != State::Finalized, "getMaxTimeStepSize() cannot be called after finalize().");
562 PRECICE_CHECK(_state == State::Initialized, "initialize() has to be called before getMaxTimeStepSize() can be evaluated.");
563 const double nextTimeStepSize = _couplingScheme->getNextTimeStepMaxSize();
564 // PRECICE_ASSERT(!math::equals(nextTimeStepSize, 0.0), nextTimeStepSize); // @todo requires https://github.com/precice/precice/issues/1904
565 // PRECICE_ASSERT(math::greater(nextTimeStepSize, 0.0), nextTimeStepSize); // @todo requires https://github.com/precice/precice/issues/1904
566
567 // safeguard needed because _couplingScheme->getNextTimeStepMaxSize() returns 0, if not isCouplingOngoing()
568 // actual case where we want to warn the user
570 isCouplingOngoing() && not math::greater(nextTimeStepSize, 0.0, 100 * math::NUMERICAL_ZERO_DIFFERENCE),
571 "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.",
572 nextTimeStepSize);
573 return nextTimeStepSize;
574}
575
577{
579 PRECICE_CHECK(_state == State::Constructed, "requiresInitialData() has to be called before initialize().");
581 if (required) {
583 }
584 return required;
585}
586
588{
590 PRECICE_CHECK(_state == State::Initialized, "initialize() has to be called before requiresWritingCheckpoint().");
592 if (required) {
594 }
595 return required;
596}
597
599{
601 PRECICE_CHECK(_state == State::Initialized, "initialize() has to be called before requiresReadingCheckpoint().");
603 if (required) {
605 }
606 return required;
607}
608
610{
612 MeshContext &context = _accessor->usedMeshContext(meshName);
614}
615
617 std::string_view dataName) const
618{
619 PRECICE_VALIDATE_DATA_NAME(meshName, dataName);
620 // Read data never requires gradients
621 if (!_accessor->isDataWrite(meshName, dataName))
622 return false;
623
624 WriteDataContext &context = _accessor->writeDataContext(meshName, dataName);
625 return context.hasGradient();
626}
627
629 std::string_view meshName) const
630{
631 PRECICE_TRACE(meshName);
632 PRECICE_REQUIRE_MESH_USE(meshName);
633 // In case we access received mesh data: check, if the requested mesh data has already been received.
634 // Otherwise, the function call doesn't make any sense
635 PRECICE_CHECK((_state == State::Initialized) || _accessor->isMeshProvided(meshName), "initialize() has to be called before accessing"
636 " data of the received mesh \"{}\" on participant \"{}\".",
637 meshName, _accessor->getName());
638 MeshContext &context = _accessor->usedMeshContext(meshName);
639 PRECICE_ASSERT(context.mesh.get() != nullptr);
640 return context.mesh->nVertices();
641}
642
645 std::string_view meshName)
646{
648 PRECICE_TRACE(meshName);
650 impl::MeshContext &context = _accessor->usedMeshContext(meshName);
651
652 PRECICE_DEBUG("Clear mesh positions for mesh \"{}\"", context.mesh->getName());
653 _meshLock.unlock(meshName);
654 context.mesh->clear();
655}
656
658 std::string_view meshName,
660{
661 PRECICE_TRACE(meshName);
663 MeshContext &context = _accessor->usedMeshContext(meshName);
664 auto & mesh = *context.mesh;
665 PRECICE_CHECK(position.size() == static_cast<unsigned long>(mesh.getDimensions()),
666 "Cannot set vertex for mesh \"{}\". Expected {} position components but found {}.", meshName, mesh.getDimensions(), position.size());
667 auto index = mesh.createVertex(Eigen::Map<const Eigen::VectorXd>{position.data(), mesh.getDimensions()}).getID();
669
670 const auto newSize = mesh.nVertices();
671 for (auto &context : _accessor->writeDataContexts()) {
672 if (context.getMeshName() == mesh.getName()) {
673 context.resizeBufferTo(newSize);
674 }
675 }
676
677 return index;
678}
679
681 std::string_view meshName,
684{
685 PRECICE_TRACE(meshName, positions.size(), ids.size());
687 MeshContext &context = _accessor->usedMeshContext(meshName);
688 auto & mesh = *context.mesh;
689
690 const auto meshDims = mesh.getDimensions();
691 const auto expectedPositionSize = ids.size() * meshDims;
692 PRECICE_CHECK(positions.size() == expectedPositionSize,
693 "Input sizes are inconsistent attempting to set vertices on {}D mesh \"{}\". "
694 "You passed {} vertices indices and {} position components, but we expected {} position components ({} x {}).",
695 meshDims, meshName, ids.size(), positions.size(), expectedPositionSize, ids.size(), meshDims);
696
697 const Eigen::Map<const Eigen::MatrixXd> posMatrix{
698 positions.data(), mesh.getDimensions(), static_cast<EIGEN_DEFAULT_DENSE_INDEX_TYPE>(ids.size())};
699 for (unsigned long i = 0; i < ids.size(); ++i) {
700 ids[i] = mesh.createVertex(posMatrix.col(i)).getID();
701 }
703
704 const auto newSize = mesh.nVertices();
705 for (auto &context : _accessor->writeDataContexts()) {
706 if (context.getMeshName() == mesh.getName()) {
707 context.resizeBufferTo(newSize);
708 }
709 }
710}
711
713 std::string_view meshName,
714 VertexID first,
715 VertexID second)
716{
717 PRECICE_TRACE(meshName, first, second);
719 MeshContext &context = _accessor->usedMeshContext(meshName);
721 mesh::PtrMesh &mesh = context.mesh;
723 PRECICE_CHECK(mesh->isValidVertexID(first), errorInvalidVertexID(first));
724 PRECICE_CHECK(mesh->isValidVertexID(second), errorInvalidVertexID(second));
725 mesh::Vertex &v0 = mesh->vertex(first);
726 mesh::Vertex &v1 = mesh->vertex(second);
727 mesh->createEdge(v0, v1);
728 }
729}
730
732 std::string_view meshName,
734{
735 PRECICE_TRACE(meshName, vertices.size());
737 MeshContext &context = _accessor->usedMeshContext(meshName);
739 return;
740 }
741
742 mesh::PtrMesh &mesh = context.mesh;
743 PRECICE_CHECK(vertices.size() % 2 == 0,
744 "Cannot interpret passed vertex IDs attempting to set edges of mesh \"{}\" . "
745 "You passed {} vertices, but we expected an even number.",
746 meshName, vertices.size());
747 {
748 auto end = vertices.end();
749 auto [first, last] = utils::find_first_range(vertices.begin(), end, [&mesh](VertexID vid) {
750 return !mesh->isValidVertexID(vid);
751 });
752 PRECICE_CHECK(first == end,
754 std::distance(vertices.begin(), first),
755 std::distance(vertices.begin(), last));
756 }
757
758 for (unsigned long i = 0; i < vertices.size() / 2; ++i) {
759 auto aid = vertices[2 * i];
760 auto bid = vertices[2 * i + 1];
761 mesh->createEdge(mesh->vertex(aid), mesh->vertex(bid));
762 }
763}
764
766 std::string_view meshName,
767 VertexID first,
768 VertexID second,
769 VertexID third)
770{
771 PRECICE_TRACE(meshName, first,
772 second, third);
773
775 MeshContext &context = _accessor->usedMeshContext(meshName);
777 mesh::PtrMesh &mesh = context.mesh;
779 PRECICE_CHECK(mesh->isValidVertexID(first), errorInvalidVertexID(first));
780 PRECICE_CHECK(mesh->isValidVertexID(second), errorInvalidVertexID(second));
781 PRECICE_CHECK(mesh->isValidVertexID(third), errorInvalidVertexID(third));
783 "setMeshTriangle() was called with repeated Vertex IDs ({}, {}, {}).",
784 first, second, third);
785 mesh::Vertex *vertices[3];
786 vertices[0] = &mesh->vertex(first);
787 vertices[1] = &mesh->vertex(second);
788 vertices[2] = &mesh->vertex(third);
790 vertices[1]->getCoords(), vertices[2]->getCoords())),
791 "setMeshTriangle() was called with vertices located at identical coordinates (IDs: {}, {}, {}).",
792 first, second, third);
793 mesh::Edge *edges[3];
794 edges[0] = &mesh->createEdge(*vertices[0], *vertices[1]);
795 edges[1] = &mesh->createEdge(*vertices[1], *vertices[2]);
796 edges[2] = &mesh->createEdge(*vertices[2], *vertices[0]);
797
798 mesh->createTriangle(*edges[0], *edges[1], *edges[2]);
799 }
800}
801
803 std::string_view meshName,
805{
806 PRECICE_TRACE(meshName, vertices.size());
808 MeshContext &context = _accessor->usedMeshContext(meshName);
810 return;
811 }
812
813 mesh::PtrMesh &mesh = context.mesh;
814 PRECICE_CHECK(vertices.size() % 3 == 0,
815 "Cannot interpret passed vertex IDs attempting to set triangles of mesh \"{}\" . "
816 "You passed {} vertices, which isn't dividable by 3.",
817 meshName, vertices.size());
818 {
819 auto end = vertices.end();
820 auto [first, last] = utils::find_first_range(vertices.begin(), end, [&mesh](VertexID vid) {
821 return !mesh->isValidVertexID(vid);
822 });
823 PRECICE_CHECK(first == end,
825 std::distance(vertices.begin(), first),
826 std::distance(vertices.begin(), last));
827 }
828
829 for (unsigned long i = 0; i < vertices.size() / 3; ++i) {
830 auto aid = vertices[3 * i];
831 auto bid = vertices[3 * i + 1];
832 auto cid = vertices[3 * i + 2];
833 mesh->createTriangle(mesh->vertex(aid),
834 mesh->vertex(bid),
835 mesh->vertex(cid));
836 }
837}
838
840 std::string_view meshName,
841 VertexID first,
842 VertexID second,
843 VertexID third,
844 VertexID fourth)
845{
846 PRECICE_TRACE(meshName, first,
847 second, third, fourth);
849 MeshContext &context = _accessor->usedMeshContext(meshName);
850 PRECICE_CHECK(context.mesh->getDimensions() == 3, "setMeshQuad is only possible for 3D meshes."
851 " Please set the mesh dimension to 3 in the preCICE configuration file.");
853 PRECICE_ASSERT(context.mesh);
854 mesh::Mesh &mesh = *(context.mesh);
860
861 auto vertexIDs = utils::make_array(first, second, third, fourth);
862 PRECICE_CHECK(utils::unique_elements(vertexIDs), "The four vertex ID's are not unique. Please check that the vertices that form the quad are correct.");
863
864 auto coords = mesh::coordsFor(mesh, vertexIDs);
866 "The four vertices that form the quad are not unique. The resulting shape may be a point, line or triangle."
867 "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.");
868
869 auto convexity = math::geometry::isConvexQuad(coords);
870 PRECICE_CHECK(convexity.convex, "The given quad is not convex. "
871 "Please check that the adapter send the four correct vertices or that the interface is composed of quads.");
872 auto reordered = utils::reorder_array(convexity.vertexOrder, mesh::vertexPtrsFor(mesh, vertexIDs));
873
874 // Vertices are now in the order: V0-V1-V2-V3-V0.
875 // Use the shortest diagonal to split the quad into 2 triangles.
876 // Vertices are now in V0-V1-V2-V3-V0 order. The new edge, e[4] is either 0-2 or 1-3
877 double distance02 = (reordered[0]->getCoords() - reordered[2]->getCoords()).norm();
878 double distance13 = (reordered[1]->getCoords() - reordered[3]->getCoords()).norm();
879
880 // The new edge, e[4], is the shortest diagonal of the quad
881 if (distance02 <= distance13) {
882 mesh.createTriangle(*reordered[0], *reordered[2], *reordered[1]);
883 mesh.createTriangle(*reordered[0], *reordered[2], *reordered[3]);
884 } else {
885 mesh.createTriangle(*reordered[1], *reordered[3], *reordered[0]);
886 mesh.createTriangle(*reordered[1], *reordered[3], *reordered[2]);
887 }
888 }
889}
890
892 std::string_view meshName,
894{
895 PRECICE_TRACE(meshName, vertices.size());
897 MeshContext &context = _accessor->usedMeshContext(meshName);
899 return;
900 }
901
902 mesh::Mesh &mesh = *(context.mesh);
903 PRECICE_CHECK(vertices.size() % 4 == 0,
904 "Cannot interpret passed vertex IDs attempting to set quads of mesh \"{}\" . "
905 "You passed {} vertices, which isn't dividable by 4.",
906 meshName, vertices.size());
907 {
908 auto end = vertices.end();
909 auto [first, last] = utils::find_first_range(vertices.begin(), end, [&mesh](VertexID vid) {
910 return !mesh.isValidVertexID(vid);
911 });
912 PRECICE_CHECK(first == end,
914 std::distance(vertices.begin(), first),
915 std::distance(vertices.begin(), last));
916 }
917
918 for (unsigned long i = 0; i < vertices.size() / 4; ++i) {
919 auto aid = vertices[4 * i];
920 auto bid = vertices[4 * i + 1];
921 auto cid = vertices[4 * i + 2];
922 auto did = vertices[4 * i + 3];
923
924 auto vertexIDs = utils::make_array(aid, bid, cid, did);
925 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);
926
927 auto coords = mesh::coordsFor(mesh, vertexIDs);
929 "The four vertices that form the quad nr {} are not unique. The resulting shape may be a point, line or triangle."
930 "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.",
931 i);
932
933 auto convexity = math::geometry::isConvexQuad(coords);
934 PRECICE_CHECK(convexity.convex, "The given quad nr {} is not convex. "
935 "Please check that the adapter send the four correct vertices or that the interface is composed of quads.",
936 i);
937 auto reordered = utils::reorder_array(convexity.vertexOrder, mesh::vertexPtrsFor(mesh, vertexIDs));
938
939 // Use the shortest diagonal to split the quad into 2 triangles.
940 // Vertices are now in V0-V1-V2-V3-V0 order. The new edge, e[4] is either 0-2 or 1-3
941 double distance02 = (reordered[0]->getCoords() - reordered[2]->getCoords()).norm();
942 double distance13 = (reordered[1]->getCoords() - reordered[3]->getCoords()).norm();
943
944 if (distance02 <= distance13) {
945 mesh.createTriangle(*reordered[0], *reordered[2], *reordered[1]);
946 mesh.createTriangle(*reordered[0], *reordered[2], *reordered[3]);
947 } else {
948 mesh.createTriangle(*reordered[1], *reordered[3], *reordered[0]);
949 mesh.createTriangle(*reordered[1], *reordered[3], *reordered[2]);
950 }
951 }
952}
953
955 std::string_view meshName,
956 VertexID first,
957 VertexID second,
958 VertexID third,
959 VertexID fourth)
960{
961 PRECICE_TRACE(meshName, first, second, third, fourth);
963 MeshContext &context = _accessor->usedMeshContext(meshName);
964 PRECICE_CHECK(context.mesh->getDimensions() == 3, "setMeshTetrahedron is only possible for 3D meshes."
965 " Please set the mesh dimension to 3 in the preCICE configuration file.");
967 mesh::PtrMesh &mesh = context.mesh;
969 PRECICE_CHECK(mesh->isValidVertexID(first), errorInvalidVertexID(first));
970 PRECICE_CHECK(mesh->isValidVertexID(second), errorInvalidVertexID(second));
971 PRECICE_CHECK(mesh->isValidVertexID(third), errorInvalidVertexID(third));
972 PRECICE_CHECK(mesh->isValidVertexID(fourth), errorInvalidVertexID(fourth));
973 mesh::Vertex &A = mesh->vertex(first);
974 mesh::Vertex &B = mesh->vertex(second);
975 mesh::Vertex &C = mesh->vertex(third);
976 mesh::Vertex &D = mesh->vertex(fourth);
977
978 mesh->createTetrahedron(A, B, C, D);
979 }
980}
981
983 std::string_view meshName,
985{
986 PRECICE_TRACE(meshName, vertices.size());
988 MeshContext &context = _accessor->usedMeshContext(meshName);
990 return;
991 }
992
993 mesh::PtrMesh &mesh = context.mesh;
994 PRECICE_CHECK(vertices.size() % 4 == 0,
995 "Cannot interpret passed vertex IDs attempting to set quads of mesh \"{}\" . "
996 "You passed {} vertices, which isn't dividable by 4.",
997 meshName, vertices.size());
998 {
999 auto end = vertices.end();
1000 auto [first, last] = utils::find_first_range(vertices.begin(), end, [&mesh](VertexID vid) {
1001 return !mesh->isValidVertexID(vid);
1002 });
1003 PRECICE_CHECK(first == end,
1005 std::distance(vertices.begin(), first),
1006 std::distance(vertices.begin(), last));
1007 }
1008
1009 for (unsigned long i = 0; i < vertices.size() / 4; ++i) {
1010 auto aid = vertices[4 * i];
1011 auto bid = vertices[4 * i + 1];
1012 auto cid = vertices[4 * i + 2];
1013 auto did = vertices[4 * i + 3];
1014 mesh->createTetrahedron(mesh->vertex(aid),
1015 mesh->vertex(bid),
1016 mesh->vertex(cid),
1017 mesh->vertex(did));
1018 }
1019}
1020
1022 std::string_view meshName,
1023 std::string_view dataName,
1026{
1027 PRECICE_TRACE(meshName, dataName, vertices.size());
1028 PRECICE_CHECK(_state != State::Finalized, "writeData(...) cannot be called after finalize().");
1029 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.");
1030 PRECICE_REQUIRE_DATA_WRITE(meshName, dataName);
1031 // Inconsistent sizes will be handled below
1032 if (vertices.empty() && values.empty()) {
1033 return;
1034 }
1035
1036 WriteDataContext &context = _accessor->writeDataContext(meshName, dataName);
1037
1038 const auto dataDims = context.getDataDimensions();
1039 const auto expectedDataSize = vertices.size() * dataDims;
1040 PRECICE_CHECK(expectedDataSize == values.size(),
1041 "Input sizes are inconsistent attempting to write {}D data \"{}\" to mesh \"{}\". "
1042 "You passed {} vertices and {} data components, but we expected {} data components ({} x {}).",
1043 dataDims, dataName, meshName,
1044 vertices.size(), values.size(), expectedDataSize, dataDims, vertices.size());
1045
1046 // Sizes are correct at this point
1047 PRECICE_VALIDATE_DATA(values.data(), values.size()); // TODO Only take span
1048
1049 if (auto index = context.locateInvalidVertexID(vertices); index) {
1050 PRECICE_ERROR("Cannot write data \"{}\" to mesh \"{}\" due to invalid Vertex ID at vertices[{}]. "
1051 "Please make sure you only use the results from calls to setMeshVertex/Vertices().",
1052 dataName, meshName, *index);
1053 }
1054 context.writeValuesIntoDataBuffer(vertices, values);
1055}
1056
1058 std::string_view meshName,
1059 std::string_view dataName,
1061 double relativeReadTime,
1062 ::precice::span<double> values) const
1063{
1064 PRECICE_TRACE(meshName, dataName, vertices.size(), relativeReadTime);
1065 PRECICE_CHECK(_state != State::Constructed, "readData(...) cannot be called before initialize().");
1066 PRECICE_CHECK(_state != State::Finalized, "readData(...) cannot be called after finalize().");
1067 PRECICE_CHECK(math::smallerEquals(relativeReadTime, _couplingScheme->getNextTimeStepMaxSize()), "readData(...) cannot sample data outside of current time window.");
1068 PRECICE_CHECK(relativeReadTime >= 0, "readData(...) cannot sample data before the current time.");
1069 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);
1070
1071 PRECICE_REQUIRE_DATA_READ(meshName, dataName);
1072
1073 // Inconsistent sizes will be handled below
1074 if (vertices.empty() && values.empty()) {
1075 return;
1076 }
1077
1078 ReadDataContext &context = _accessor->readDataContext(meshName, dataName);
1079 const auto dataDims = context.getDataDimensions();
1080 const auto expectedDataSize = vertices.size() * dataDims;
1081 PRECICE_CHECK(expectedDataSize == values.size(),
1082 "Input/Output sizes are inconsistent attempting to read {}D data \"{}\" from mesh \"{}\". "
1083 "You passed {} vertices and {} data components, but we expected {} data components ({} x {}).",
1084 dataDims, dataName, meshName,
1085 vertices.size(), values.size(), expectedDataSize, dataDims, vertices.size());
1086
1087 if (auto index = context.locateInvalidVertexID(vertices); index) {
1088 PRECICE_ERROR("Cannot read data \"{}\" from mesh \"{}\" due to invalid Vertex ID at vertices[{}]. "
1089 "Please make sure you only use the results from calls to setMeshVertex/Vertices().",
1090 dataName, meshName, *index);
1091 }
1092
1093 double readTime = _couplingScheme->getTime() + relativeReadTime;
1094 context.readValues(vertices, readTime, values);
1095}
1096
1098 std::string_view meshName,
1099 std::string_view dataName,
1102{
1104
1105 // Asserts and checks
1106 PRECICE_TRACE(meshName, dataName, vertices.size());
1107 PRECICE_CHECK(_state != State::Finalized, "writeGradientData(...) cannot be called after finalize().");
1108 PRECICE_REQUIRE_DATA_WRITE(meshName, dataName);
1109
1110 // Inconsistent sizes will be handled below
1111 if ((vertices.empty() && gradients.empty()) || !requiresGradientDataFor(meshName, dataName)) {
1112 return;
1113 }
1114
1115 // Get the data
1116 WriteDataContext &context = _accessor->writeDataContext(meshName, dataName);
1117
1118 // Check if the Data object of given mesh has been initialized with gradient data
1119 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);
1120
1121 if (auto index = context.locateInvalidVertexID(vertices); index) {
1122 PRECICE_ERROR("Cannot write gradient data \"{}\" to mesh \"{}\" due to invalid Vertex ID at vertices[{}]. "
1123 "Please make sure you only use the results from calls to setMeshVertex/Vertices().",
1124 dataName, meshName, *index);
1125 }
1126
1127 const auto dataDims = context.getDataDimensions();
1128 const auto meshDims = context.getSpatialDimensions();
1129 const auto gradientComponents = meshDims * dataDims;
1130 const auto expectedComponents = vertices.size() * gradientComponents;
1131 PRECICE_CHECK(expectedComponents == gradients.size(),
1132 "Input sizes are inconsistent attempting to write gradient for data \"{}\" to mesh \"{}\". "
1133 "A single gradient/Jacobian for {}D data on a {}D mesh has {} components. "
1134 "You passed {} vertices and {} gradient components, but we expected {} gradient components. ",
1135 dataName, meshName,
1136 dataDims, meshDims, gradientComponents,
1137 vertices.size(), gradients.size(), expectedComponents);
1138
1139 PRECICE_VALIDATE_DATA(gradients.data(), gradients.size());
1140
1141 context.writeGradientsIntoDataBuffer(vertices, gradients);
1142}
1143
1145 const std::string_view meshName,
1146 ::precice::span<const double> boundingBox) const
1147{
1148 PRECICE_TRACE(meshName, boundingBox.size());
1149 PRECICE_REQUIRE_MESH_USE(meshName);
1150 PRECICE_CHECK(_state != State::Finalized, "setMeshAccessRegion() cannot be called after finalize().");
1151 PRECICE_CHECK(_state != State::Initialized, "setMeshAccessRegion() needs to be called before initialize().");
1152 PRECICE_CHECK(!_accessRegionDefined, "setMeshAccessRegion may only be called once.");
1153
1154 // Get the related mesh
1155 MeshContext & context = _accessor->meshContext(meshName);
1156 mesh::PtrMesh mesh(context.mesh);
1157 int dim = mesh->getDimensions();
1158 PRECICE_CHECK(boundingBox.size() == static_cast<unsigned long>(dim) * 2,
1159 "Incorrect amount of bounding box components attempting to set the bounding box of {}D mesh \"{}\" . "
1160 "You passed {} limits, but we expected {} ({}x2).",
1161 dim, meshName, boundingBox.size(), dim * 2, dim);
1162
1163 // Transform bounds into a suitable format
1164 PRECICE_DEBUG("Define bounding box");
1165 std::vector<double> bounds(dim * 2);
1166
1167 for (int d = 0; d < dim; ++d) {
1168 // Check that min is lower or equal to max
1169 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...]");
1170 bounds[2 * d] = boundingBox[2 * d];
1171 bounds[2 * d + 1] = boundingBox[2 * d + 1];
1172 }
1173 // Create a bounding box
1174 mesh::BoundingBox providedBoundingBox(bounds);
1175 // Expand the mesh associated bounding box
1176 mesh->expandBoundingBox(providedBoundingBox);
1177 // and set a flag so that we know the function was called
1178 _accessRegionDefined = true;
1179}
1180
1182 const std::string_view meshName,
1184 ::precice::span<double> coordinates) const
1185{
1186 PRECICE_TRACE(meshName, ids.size(), coordinates.size());
1187 PRECICE_REQUIRE_MESH_USE(meshName);
1188 PRECICE_DEBUG("Get {} mesh vertices with IDs", ids.size());
1189
1190 // Check, if the requested mesh data has already been received. Otherwise, the function call doesn't make any sense
1191 PRECICE_CHECK((_state == State::Initialized) || _accessor->isMeshProvided(meshName), "initialize() has to be called before accessing"
1192 " data of the received mesh \"{}\" on participant \"{}\".",
1193 meshName, _accessor->getName());
1194
1195 if (ids.empty() && coordinates.empty()) {
1196 return;
1197 }
1198 const MeshContext & context = _accessor->meshContext(meshName);
1199 const mesh::PtrMesh mesh(context.mesh);
1200
1201 const auto meshSize = mesh->nVertices();
1202 const auto meshDims = mesh->getDimensions();
1203 PRECICE_CHECK(ids.size() == meshSize,
1204 "Output size is incorrect attempting to get vertex ids of {}D mesh \"{}\". "
1205 "You passed {} vertices indices, but we expected {}. "
1206 "Use getMeshVertexSize(\"{}\") to receive the required amount of vertices.",
1207 meshDims, meshName, ids.size(), meshSize, meshName);
1208 const auto expectedCoordinatesSize = static_cast<unsigned long>(meshDims * meshSize);
1209 PRECICE_CHECK(coordinates.size() == expectedCoordinatesSize,
1210 "Output size is incorrect attempting to get vertex coordinates of {}D mesh \"{}\". "
1211 "You passed {} coordinate components, but we expected {} ({}x{}). "
1212 "Use getMeshVertexSize(\"{}\") and getMeshDimensions(\"{}\") to receive the required amount components",
1213 meshDims, meshName, coordinates.size(), expectedCoordinatesSize, meshSize, meshDims, meshName, meshName);
1214
1215 PRECICE_CHECK(ids.size() <= meshSize, "The queried size exceeds the number of available points.");
1216
1217 Eigen::Map<Eigen::MatrixXd> posMatrix{
1218 coordinates.data(), mesh->getDimensions(), static_cast<EIGEN_DEFAULT_DENSE_INDEX_TYPE>(ids.size())};
1219
1220 for (unsigned long i = 0; i < ids.size(); i++) {
1221 PRECICE_ASSERT(mesh->isValidVertexID(i), i, meshSize);
1222 ids[i] = mesh->vertex(i).getID();
1223 posMatrix.col(i) = mesh->vertex(i).getCoords();
1224 }
1225}
1226
1229{
1230 PRECICE_TRACE();
1231 for (const auto &m2nConf : config->m2ns()) {
1232 if (m2nConf.acceptor != _accessorName && m2nConf.connector != _accessorName) {
1233 continue;
1234 }
1235
1236 std::string comPartner("");
1237 bool isRequesting;
1238 if (m2nConf.acceptor == _accessorName) {
1239 comPartner = m2nConf.connector;
1240 isRequesting = true;
1241 } else {
1242 comPartner = m2nConf.acceptor;
1243 isRequesting = false;
1244 }
1245
1246 PRECICE_ASSERT(!comPartner.empty());
1247 for (const impl::PtrParticipant &participant : _participants) {
1248 if (participant->getName() == comPartner) {
1249 PRECICE_ASSERT(not utils::contained(comPartner, _m2ns), comPartner);
1250 PRECICE_ASSERT(m2nConf.m2n);
1251
1252 _m2ns[comPartner] = [&] {
1253 m2n::BoundM2N bound;
1254 bound.m2n = m2nConf.m2n;
1255 bound.localName = _accessorName;
1256 bound.remoteName = comPartner;
1257 bound.isRequesting = isRequesting;
1258 return bound;
1259 }();
1260 }
1261 }
1262 }
1263}
1264
1266 const m2n::M2NConfiguration::SharedPointer &m2nConfig)
1267{
1268 PRECICE_TRACE();
1269 for (MeshContext *context : _accessor->usedMeshContexts()) {
1270
1271 if (context->provideMesh) { // Accessor provides mesh
1272 PRECICE_CHECK(context->receiveMeshFrom.empty(),
1273 "Participant \"{}\" cannot provide and receive mesh {}!",
1274 _accessorName, context->mesh->getName());
1275
1276 context->partition = partition::PtrPartition(new partition::ProvidedPartition(context->mesh));
1277
1278 for (auto &receiver : _participants) {
1279 for (auto &receiverContext : receiver->usedMeshContexts()) {
1280 if (receiverContext->receiveMeshFrom == _accessorName && receiverContext->mesh->getName() == context->mesh->getName()) {
1281 // meshRequirement has to be copied from "from" to provide", since
1282 // mapping are only defined at "provide"
1283 if (receiverContext->meshRequirement > context->meshRequirement) {
1284 context->meshRequirement = receiverContext->meshRequirement;
1285 }
1286
1287 m2n::PtrM2N m2n = m2nConfig->getM2N(receiver->getName(), _accessorName);
1288 m2n->createDistributedCommunication(context->mesh);
1289 context->partition->addM2N(m2n);
1290 }
1291 }
1292 }
1293
1294 } else { // Accessor receives mesh
1295 std::string receiver(_accessorName);
1296 std::string provider(context->receiveMeshFrom);
1297
1298 PRECICE_DEBUG("Receiving mesh from {}", provider);
1299
1300 context->partition = partition::PtrPartition(new partition::ReceivedPartition(context->mesh, context->geoFilter, context->safetyFactor, context->allowDirectAccess));
1301
1302 m2n::PtrM2N m2n = m2nConfig->getM2N(receiver, provider);
1303 m2n->createDistributedCommunication(context->mesh);
1304 context->partition->addM2N(m2n);
1305 for (const MappingContext &mappingContext : context->fromMappingContexts) {
1306 context->partition->addFromMapping(mappingContext.mapping);
1307 }
1308 for (const MappingContext &mappingContext : context->toMappingContexts) {
1309 context->partition->addToMapping(mappingContext.mapping);
1310 }
1311 }
1312 }
1313}
1314
1316{
1317 // sort meshContexts by name, for communication in right order.
1318 std::sort(_accessor->usedMeshContexts().begin(), _accessor->usedMeshContexts().end(),
1319 [](MeshContext const *const lhs, MeshContext const *const rhs) -> bool {
1320 return lhs->mesh->getName() < rhs->mesh->getName();
1321 });
1322
1323 for (MeshContext *meshContext : _accessor->usedMeshContexts()) {
1324 if (meshContext->provideMesh) // provided meshes need their bounding boxes already for the re-partitioning
1325 meshContext->mesh->computeBoundingBox();
1326
1327 meshContext->clearMappings();
1328 }
1329
1330 for (MeshContext *meshContext : _accessor->usedMeshContexts()) {
1331 meshContext->partition->compareBoundingBoxes();
1332 }
1333}
1334
1336{
1337 // We need to do this in two loops: First, communicate the mesh and later compute the partition.
1338 // Originally, this was done in one loop. This however gave deadlock if two meshes needed to be communicated cross-wise.
1339 // Both loops need a different sorting
1340
1341 auto &contexts = _accessor->usedMeshContexts();
1342
1343 std::sort(contexts.begin(), contexts.end(),
1344 [](MeshContext const *const lhs, MeshContext const *const rhs) -> bool {
1345 return lhs->mesh->getName() < rhs->mesh->getName();
1346 });
1347
1348 for (MeshContext *meshContext : contexts) {
1349 meshContext->partition->communicate();
1350 }
1351
1352 // for two-level initialization, there is also still communication in partition::compute()
1353 // therefore, we cannot resort here.
1354 // @todo this hacky solution should be removed as part of #633
1355 bool resort = true;
1356 for (auto &m2nPair : _m2ns) {
1357 if (m2nPair.second.m2n->usesTwoLevelInitialization()) {
1358 resort = false;
1359 break;
1360 }
1361 }
1362
1363 if (resort) {
1364 // pull provided meshes up front, to have them ready for the decomposition of the received meshes (for the mappings)
1365 std::stable_partition(contexts.begin(), contexts.end(),
1366 [](MeshContext const *const meshContext) -> bool {
1367 return meshContext->provideMesh;
1368 });
1369 }
1370
1371 for (MeshContext *meshContext : contexts) {
1372 meshContext->partition->compute();
1373 if (not meshContext->provideMesh) { // received mesh can only compute their bounding boxes here
1374 meshContext->mesh->computeBoundingBox();
1375 }
1376
1377 meshContext->mesh->allocateDataValues();
1378
1379 const auto requiredSize = meshContext->mesh->nVertices();
1380 for (auto &context : _accessor->writeDataContexts()) {
1381 if (context.getMeshName() == meshContext->mesh->getName()) {
1382 context.resizeBufferTo(requiredSize);
1383 }
1384 }
1385 }
1386}
1387
1389{
1390 PRECICE_TRACE();
1391 using namespace mapping;
1392 for (impl::MappingContext &context : contexts) {
1393 if (not context.mapping->hasComputedMapping()) {
1394 PRECICE_INFO_IF(context.configuredWithAliasTag,
1395 "Automatic RBF mapping alias from mesh \"{}\" to mesh \"{}\" in \"{}\" direction resolves to \"{}\" .",
1396 context.mapping->getInputMesh()->getName(), context.mapping->getOutputMesh()->getName(), mappingType, context.mapping->getName());
1397 PRECICE_INFO("Computing \"{}\" mapping from mesh \"{}\" to mesh \"{}\" in \"{}\" direction.",
1398 context.mapping->getName(), context.mapping->getInputMesh()->getName(), context.mapping->getOutputMesh()->getName(), mappingType);
1399 context.mapping->computeMapping();
1400 }
1401 }
1402}
1403
1405{
1406 PRECICE_TRACE();
1407 computeMappings(_accessor->writeMappingContexts(), "write");
1408 for (auto &context : _accessor->writeDataContexts()) {
1409 if (context.hasMapping()) {
1410 PRECICE_DEBUG("Map initial write data \"{}\" from mesh \"{}\"", context.getDataName(), context.getMeshName());
1411 _executedWriteMappings += context.mapData(std::nullopt, true);
1412 }
1413 }
1414}
1415
1417{
1418 PRECICE_TRACE();
1419 computeMappings(_accessor->writeMappingContexts(), "write");
1420 for (auto &context : _accessor->writeDataContexts()) {
1421 if (context.hasMapping()) {
1422 PRECICE_DEBUG("Map write data \"{}\" from mesh \"{}\"", context.getDataName(), context.getMeshName());
1423 _executedWriteMappings += context.mapData(after);
1424 }
1425 }
1426}
1427
1428void ParticipantImpl::trimReadMappedData(double startOfTimeWindow, bool isTimeWindowComplete, const cplscheme::ImplicitData &fromData)
1429{
1430 PRECICE_TRACE();
1431 for (auto &context : _accessor->readDataContexts()) {
1432 if (context.hasMapping()) {
1434 // For serial implicit second, we need to discard everything before startOfTimeWindow to preserve the time window start
1435 // For serial implicit first, we need to discard everything as everything is new
1436 // For parallel implicit, we need to discard everything as everything is new
1437 context.clearToDataFor(fromData);
1438 } else {
1439 context.trimToDataAfterFor(fromData, startOfTimeWindow);
1440 }
1441 }
1442 }
1443}
1444
1446{
1447 PRECICE_TRACE();
1448 computeMappings(_accessor->readMappingContexts(), "read");
1449 for (auto &context : _accessor->readDataContexts()) {
1450 if (context.hasMapping()) {
1451 PRECICE_DEBUG("Map initial read data \"{}\" to mesh \"{}\"", context.getDataName(), context.getMeshName());
1452 // We always ensure that all read data was mapped
1453 _executedReadMappings += context.mapData(std::nullopt, true);
1454 }
1455 }
1456}
1457
1459{
1460 PRECICE_TRACE();
1461 computeMappings(_accessor->readMappingContexts(), "read");
1462 for (auto &context : _accessor->readDataContexts()) {
1463 if (context.hasMapping()) {
1464 PRECICE_DEBUG("Map read data \"{}\" to mesh \"{}\"", context.getDataName(), context.getMeshName());
1465 // We always ensure that all read data was mapped
1466 _executedReadMappings += context.mapData();
1467 }
1468 }
1469}
1470
1472{
1473 PRECICE_TRACE();
1474 for (action::PtrAction &action : _accessor->actions()) {
1475 if (timings.find(action->getTiming()) != timings.end()) {
1476 action->performAction();
1477 }
1478 }
1479}
1480
1482{
1483 PRECICE_TRACE();
1484 PRECICE_DEBUG("Handle exports");
1486 exp.timewindow = _couplingScheme->getTimeWindows() - 1;
1487 exp.iteration = _numberAdvanceCalls;
1488 exp.complete = _couplingScheme->isTimeWindowComplete();
1489 exp.time = _couplingScheme->getTime();
1490 _accessor->exportIntermediate(exp);
1491}
1492
1494{
1495 PRECICE_TRACE();
1496 for (auto &context : _accessor->writeDataContexts()) {
1497 context.resetBuffer();
1498 }
1499}
1500
1502 const config::Configuration &config)
1503{
1504 const auto &partConfig = config.getParticipantConfiguration();
1505 for (const PtrParticipant &participant : partConfig->getParticipants()) {
1506 if (participant->getName() == _accessorName) {
1507 return participant;
1508 }
1509 }
1510 PRECICE_ERROR("This participant's name, which was specified in the constructor of the preCICE interface as \"{}\", "
1511 "is not defined in the preCICE configuration. "
1512 "Please double-check the correct spelling.",
1514}
1515
1526
1527void ParticipantImpl::syncTimestep(double computedTimeStepSize)
1528{
1531 utils::IntraComm::getCommunication()->send(computedTimeStepSize, 0);
1532 } else {
1534 for (Rank secondaryRank : utils::IntraComm::allSecondaryRanks()) {
1535 double dt;
1536 utils::IntraComm::getCommunication()->receive(dt, secondaryRank);
1537 PRECICE_CHECK(math::equals(dt, computedTimeStepSize),
1538 "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 {}.",
1539 secondaryRank, dt, computedTimeStepSize);
1540 }
1541 }
1542}
1543
1545{
1546 PRECICE_DEBUG("Advance coupling scheme");
1547 // Orchestrate local and remote mesh changes
1548 std::vector<MeshID> localChanges;
1549
1550 [[maybe_unused]] auto remoteChanges1 = _couplingScheme->firstSynchronization(localChanges);
1551 _couplingScheme->firstExchange();
1552 // Orchestrate remote mesh changes (local ones were handled in the first sync)
1553 [[maybe_unused]] auto remoteChanges2 = _couplingScheme->secondSynchronization();
1554 _couplingScheme->secondExchange();
1555}
1556
1558{
1559 // Optionally apply some final ping-pong to sync solver that run e.g. with a uni-directional coupling
1560 // afterwards close connections
1561 PRECICE_INFO("{} {}communication channels",
1562 (_waitInFinalize ? "Synchronize participants and close" : "Close"),
1563 (close == CloseChannels::Distributed ? "distributed " : ""));
1564 std::string ping = "ping";
1565 std::string pong = "pong";
1566 for (auto &iter : _m2ns) {
1567 auto bm2n = iter.second;
1569 PRECICE_DEBUG("Synchronizing primary rank with {}", bm2n.remoteName);
1570 if (bm2n.isRequesting) {
1571 bm2n.m2n->getPrimaryRankCommunication()->send(ping, 0);
1572 std::string receive = "init";
1573 bm2n.m2n->getPrimaryRankCommunication()->receive(receive, 0);
1574 PRECICE_ASSERT(receive == pong);
1575 } else {
1576 std::string receive = "init";
1577 bm2n.m2n->getPrimaryRankCommunication()->receive(receive, 0);
1578 PRECICE_ASSERT(receive == ping);
1579 bm2n.m2n->getPrimaryRankCommunication()->send(pong, 0);
1580 }
1581 }
1582 if (close == CloseChannels::Distributed) {
1583 PRECICE_DEBUG("Closing distributed communication with {}", bm2n.remoteName);
1584 bm2n.m2n->closeDistributedConnections();
1585 } else {
1586 PRECICE_DEBUG("Closing communication with {}", bm2n.remoteName);
1587 bm2n.m2n->closeConnection();
1588 }
1589 }
1590}
1591
1592const mesh::Mesh &ParticipantImpl::mesh(const std::string &meshName) const
1593{
1594 PRECICE_TRACE(meshName);
1595 return *_accessor->usedMeshContext(meshName).mesh;
1596}
1597
1605
1606} // namespace precice::impl
#define PRECICE_ERROR(...)
Definition LogMacros.hpp:15
#define PRECICE_WARN_IF(condition,...)
Definition LogMacros.hpp:21
#define PRECICE_DEBUG(...)
Definition LogMacros.hpp:64
#define PRECICE_TRACE(...)
Definition LogMacros.hpp:95
#define PRECICE_INFO_IF(condition,...)
Definition LogMacros.hpp:28
#define PRECICE_INFO(...)
Definition LogMacros.hpp:13
#define PRECICE_CHECK(check,...)
Definition LogMacros.hpp:35
unsigned int index
std::string name
#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(...)
Definition assertion.hpp:87
Main class for preCICE XML configuration tree.
const PtrParticipantConfiguration & getParticipantConfiguration() const
const mesh::PtrMeshConfiguration getMeshConfiguration() const
const m2n::M2NConfiguration::SharedPointer getM2NConfiguration() const
bool waitInFinalize() const
Returns whether participants wait for each other in finalize.
const cplscheme::PtrCouplingSchemeConfiguration getCouplingSchemeConfiguration() const
bool allowsExperimental() const
Returns whether experimental features are allowed or not.
xml::XMLTag & getXMLTag()
Returns root xml tag to start the automatic configuration process.
@ 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 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.
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.
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 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.
void configurePartitions(const m2n::M2NConfiguration::SharedPointer &m2nConfig)
Determines participants providing meshes to other participants.
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...
void closeCommunicationChannels(CloseChannels cc)
Syncs the primary ranks of all connected participants.
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.
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.
bool _accessRegionDefined
setMeshAccessRegion may only be called once
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.
void handleExports()
Exports meshes with data and watch point data.
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)
MappedSamples mappedSamples() const
Returns the amount of mapped read and write samples in the last call to advance.
void finalize()
Finalizes preCICE.
int _executedWriteMappings
Counts the amount of samples mapped in write mappings executed in the latest advance.
void configureM2Ns(const m2n::M2NConfiguration::SharedPointer &config)
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
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.
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 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.
std::unique_ptr< profiling::Event > _solverAdvanceEvent
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 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.
Stores one Data object with related mesh. Context stores data to be read from and potentially provide...
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.
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 writeValuesIntoDataBuffer(::precice::span< const VertexID > vertices, ::precice::span< const double > values)
Store values in _writeDataBuffer.
An M2N between participants with a configured direction.
Definition BoundM2N.hpp:11
std::string remoteName
Definition BoundM2N.hpp:30
std::string localName
Definition BoundM2N.hpp:29
An axis-aligned bounding box around a (partition of a) mesh.
Linear edge of a mesh, defined by two Vertex objects.
Definition Edge.hpp:16
Container and creator for meshes.
Definition Mesh.hpp:39
Triangle & createTriangle(Edge &edgeOne, Edge &edgeTwo, Edge &edgeThree)
Creates and initializes a Triangle object.
Definition Mesh.cpp:119
int getDimensions() const
Definition Mesh.cpp:98
const std::string & getName() const
Returns the name of the mesh, as set in the config file.
Definition Mesh.cpp:218
std::size_t nVertices() const
Returns the number of vertices.
Definition Mesh.cpp:63
bool isValidVertexID(VertexID vertexID) const
Returns true if the given vertexID is valid.
Definition Mesh.cpp:228
Vertex & createVertex(const Eigen::VectorXd &coords)
Creates and initializes a Vertex object.
Definition Mesh.cpp:103
void allocateDataValues()
Allocates memory for the vertex data values and corresponding gradient values.
Definition Mesh.cpp:233
Vertex of a mesh.
Definition Vertex.hpp:16
A partition that is provided by the participant.
A partition that is computed from a mesh received from another participant.
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.
Definition Event.cpp:37
Class that changes the prefix in its scope.
Definition Event.hpp:104
A C++ 11 implementation of the non-owning C++20 std::span type.
Definition span.hpp:284
constexpr pointer data() const noexcept
Definition span.hpp:500
PRECICE_SPAN_NODISCARD constexpr bool empty() const noexcept
Definition span.hpp:476
constexpr iterator begin() const noexcept
Definition span.hpp:503
constexpr iterator end() const noexcept
Definition span.hpp:505
constexpr size_type size() const noexcept
Definition span.hpp:469
static void barrier()
Synchronizes all ranks.
static bool isPrimary()
True if this process is running the primary rank.
Definition IntraComm.cpp:52
static auto allSecondaryRanks()
Returns an iterable range over salve ranks [1, _size)
Definition IntraComm.hpp:37
static bool isParallel()
True if this process is running in parallel.
Definition IntraComm.cpp:62
static bool isSecondary()
True if this process is running a secondary rank.
Definition IntraComm.cpp:57
static com::PtrCommunication & getCommunication()
Intra-participant communication.
Definition IntraComm.hpp:31
static void configure(Rank rank, int size)
Configures the intra-participant communication.
Definition IntraComm.cpp:31
void add(Key name, bool state)
Adds a lock with a given state.
Definition MultiLock.hpp:42
void clear() noexcept
Removes all known locks.
Definition MultiLock.hpp:94
void lockAll() noexcept
Locks all known locks.
Definition MultiLock.hpp:63
void unlock(const K &name)
Unlocks a given lock.
Definition MultiLock.hpp:75
static void finalizeOrCleanupMPI()
Finalized a managed MPI environment or cleans up after an non-managed session.
Definition Parallel.cpp:230
static CommStatePtr current()
Returns an owning pointer to the current CommState.
Definition Parallel.cpp:147
static void initializeOrDetectMPI(std::optional< Communicator > userProvided=std::nullopt)
Definition Parallel.cpp:190
static void finalize()
Finalizes Petsc environment.
Definition Petsc.cpp:98
T distance(T... args)
T empty(T... args)
T end(T... args)
T find(T... args)
T get(T... args)
std::string errorInvalidVertexID(int vid)
static constexpr auto errorInvalidVertexIDRange
void setMPIRank(int const rank)
void setParticipant(std::string const &participant)
ConvexityResult isConvexQuad(std::array< Eigen::VectorXd, 4 > coords)
Definition geometry.cpp:143
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...
Definition Utils.hpp:123
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.
Definition Utils.hpp:112
std::shared_ptr< Partition > PtrPartition
static constexpr FundamentalTag Fundamental
Convenience instance of the FundamentalTag.
Definition Event.hpp:19
static constexpr SynchronizeTag Synchronize
Convenience instance of the SynchronizeTag.
Definition Event.hpp:21
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.
bool contained(const ELEMENT_T &element, const std::vector< ELEMENT_T > &vec)
Returns true, if given element is in vector, otherwise false.
Definition Helpers.hpp:39
auto make_array(Elements &&... elements) -> std::array< typename std::common_type< Elements... >::type, sizeof...(Elements)>
Function that generates an array from given elements.
Definition algorithm.hpp:51
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={})
Definition algorithm.hpp:64
void configure(XMLTag &tag, const precice::xml::ConfigurationContext &context, std::string_view configurationFilename)
Configures the given configuration from file configurationFilename.
Definition XMLTag.cpp:395
int VertexID
Definition Types.hpp:13
int Rank
Definition Types.hpp:37
T has_value(T... args)
T reset(T... args)
T sort(T... args)
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.
Tightly coupled to the parameters of Participant()
Definition XMLTag.hpp:24
T value(T... args)