preCICE v3.2.0
Loading...
Searching...
No Matches
PartitionOfUnityMapping.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <Eigen/Core>
4#include <numeric>
5
7#include "io/ExportVTU.hpp"
11#include "mesh/Filter.hpp"
13#include "profiling/Event.hpp"
14#include "query/Index.hpp"
15#include "utils/IntraComm.hpp"
16
17namespace precice {
18extern bool syncMode;
19
20namespace mapping {
21
29template <typename RADIAL_BASIS_FUNCTION_T>
31public:
48 Mapping::Constraint constraint,
49 int dimension,
50 RADIAL_BASIS_FUNCTION_T function,
51 Polynomial polynomial,
52 unsigned int verticesPerCluster,
53 double relativeOverlap,
54 bool projectToInput);
55
65 void computeMapping() final override;
66
68 void clear() final override;
69
71 void tagMeshFirstRound() final override;
72
74 void tagMeshSecondRound() final override;
75
77 std::string getName() const final override;
78
79 void mapConsistentAt(const Eigen::Ref<const Eigen::MatrixXd> &coordinates, const impl::MappingDataCache &cache, Eigen::Ref<Eigen::MatrixXd> values) final override;
80
82 void mapConservativeAt(const Eigen::Ref<const Eigen::MatrixXd> &coordinates, const Eigen::Ref<const Eigen::MatrixXd> &source, impl::MappingDataCache &cache, Eigen::Ref<Eigen::MatrixXd> target) final override;
83
84 void updateMappingDataCache(impl::MappingDataCache &cache, const Eigen::Ref<const Eigen::VectorXd> &in) final override;
85
86 void completeJustInTimeMapping(impl::MappingDataCache &cache, Eigen::Ref<Eigen::MatrixXd> buffer) final override;
87
88 void initializeMappingDataCache(impl::MappingDataCache &cache) final override;
89
90private:
92 precice::logging::Logger _log{"mapping::PartitionOfUnityMapping"};
93
96
98 RADIAL_BASIS_FUNCTION_T _basisFunction;
99
101
103 const unsigned int _verticesPerCluster;
104
106 const double _relativeOverlap;
107
109 const bool _projectToInput;
110
112 double _clusterRadius = 0;
113
116
118
120 void mapConservative(const time::Sample &inData, Eigen::VectorXd &outData) override;
121
123 void mapConsistent(const time::Sample &inData, Eigen::VectorXd &outData) override;
124
129
133};
134
135template <typename RADIAL_BASIS_FUNCTION_T>
137 Mapping::Constraint constraint,
138 int dimension,
139 RADIAL_BASIS_FUNCTION_T function,
140 Polynomial polynomial,
141 unsigned int verticesPerCluster,
142 double relativeOverlap,
143 bool projectToInput)
144 : Mapping(constraint, dimension, false, Mapping::InitialGuessRequirement::None),
145 _basisFunction(function), _verticesPerCluster(verticesPerCluster), _relativeOverlap(relativeOverlap), _projectToInput(projectToInput), _polynomial(polynomial)
146{
147 PRECICE_ASSERT(this->getDimensions() <= 3);
148 PRECICE_ASSERT(_polynomial != Polynomial::ON, "Integrated polynomial is not supported for partition of unity data mappings.");
149 PRECICE_ASSERT(_relativeOverlap < 1, "The relative overlap has to be smaller than one.");
150 PRECICE_ASSERT(_verticesPerCluster > 0, "The number of vertices per cluster has to be greater zero.");
151
152 if (isScaledConsistent()) {
155 } else {
158 }
159}
160
161template <typename RADIAL_BASIS_FUNCTION_T>
163{
165
166 precice::profiling::Event e("map.pou.computeMapping.From" + this->input()->getName() + "To" + this->output()->getName(), profiling::Synchronize);
167
168 // Recompute the whole clustering
169 PRECICE_ASSERT(!this->_hasComputedMapping, "Please clear the mapping before recomputing.");
170
171 mesh::PtrMesh inMesh;
172 mesh::PtrMesh outMesh;
174 inMesh = this->output();
175 outMesh = this->input();
176 } else { // Consistent or scaled consistent
177 inMesh = this->input();
178 outMesh = this->output();
179 }
180
181 precice::profiling::Event eClusters("map.pou.computeMapping.createClustering.From" + this->input()->getName() + "To" + this->output()->getName());
182 // Step 1: get a tentative clustering consisting of centers and a radius from one of the available algorithms
183 auto [clusterRadius, centerCandidates] = impl::createClustering(inMesh, outMesh, _relativeOverlap, _verticesPerCluster, _projectToInput);
184 eClusters.stop();
185
186 _clusterRadius = clusterRadius;
187 PRECICE_ASSERT(_clusterRadius > 0 || inMesh->nVertices() == 0 || outMesh->nVertices() == 0);
188
189 // Step 2: check, which of the resulting clusters are non-empty and register the cluster centers in a mesh
190 // Here, the VertexCluster computes the matrix decompositions directly in case the cluster is non-empty
191 _centerMesh = std::make_unique<mesh::Mesh>("pou-centers-" + inMesh->getName(), this->getDimensions(), mesh::Mesh::MESH_ID_UNDEFINED);
192 auto &meshVertices = _centerMesh->vertices();
193
194 meshVertices.clear();
195 _clusters.clear();
196 _clusters.reserve(centerCandidates.size());
197 for (const auto &c : centerCandidates) {
198 // We cannot simply copy the vertex from the container in order to fill the vertices of the centerMesh, as the vertexID of each center needs to match the index
199 // of the cluster within the _clusters vector. That's required for the indexing further down and asserted below
200 const VertexID vertexID = meshVertices.size();
201 mesh::Vertex center(c.getCoords(), vertexID);
203
204 // Consider only non-empty clusters (more of a safeguard here)
205 if (!cluster.empty()) {
206 PRECICE_ASSERT(center.getID() == static_cast<int>(_clusters.size()), center.getID(), _clusters.size());
207 meshVertices.emplace_back(std::move(center));
208 _clusters.emplace_back(std::move(cluster));
209 }
210 }
211
212 e.addData("n clusters", _clusters.size());
213 // Log the average number of resulting clusters
214 PRECICE_DEBUG("Partition of unity data mapping between mesh \"{}\" and mesh \"{}\": mesh \"{}\" on rank {} was decomposed into {} clusters.", this->input()->getName(), this->output()->getName(), inMesh->getName(), utils::IntraComm::getRank(), _clusters.size());
215
216 if (_clusters.size() > 0) {
217 PRECICE_DEBUG("Average number of vertices per cluster {}", std::accumulate(_clusters.begin(), _clusters.end(), static_cast<unsigned int>(0), [](auto &acc, auto &val) { return acc += val.getNumberOfInputVertices(); }) / _clusters.size());
218 PRECICE_DEBUG("Maximum number of vertices per cluster {}", std::max_element(_clusters.begin(), _clusters.end(), [](auto &v1, auto &v2) { return v1.getNumberOfInputVertices() < v2.getNumberOfInputVertices(); })->getNumberOfInputVertices());
219 PRECICE_DEBUG("Minimum number of vertices per cluster {}", std::min_element(_clusters.begin(), _clusters.end(), [](auto &v1, auto &v2) { return v1.getNumberOfInputVertices() < v2.getNumberOfInputVertices(); })->getNumberOfInputVertices());
220 }
221
222 precice::profiling::Event eWeights("map.pou.computeMapping.computeWeights");
223 // Log a bounding box of the center mesh
224 _centerMesh->computeBoundingBox();
225 PRECICE_DEBUG("Bounding Box of the cluster centers {}", _centerMesh->getBoundingBox());
226
227 // Step 3: Determine PU weights
228 PRECICE_DEBUG("Computing cluster-vertex association");
229 for (const auto &vertex : outMesh->vertices()) {
230 // we use a helper function, as we need the same functionality for just-in-time mapping
231 auto [clusterIDs, normalizedWeights] = computeNormalizedWeight(vertex, outMesh->getName());
232 // Step 4: store the normalized weight in all associated clusters
233 for (unsigned int i = 0; i < clusterIDs.size(); ++i) {
234 PRECICE_ASSERT(clusterIDs[i] < static_cast<int>(_clusters.size()));
235 _clusters[clusterIDs[i]].setNormalizedWeight(normalizedWeights[i], vertex.getID());
236 }
237 }
238 eWeights.stop();
239
240 // Uncomment to add a VTK export of the cluster center distribution for visualization purposes
241 // exportClusterCentersAsVTU(*_centerMesh);
242
243 // we need the center mesh index data structure
244 if (!outMesh->isJustInTime()) {
245 _centerMesh.reset();
246 }
247
248 this->_hasComputedMapping = true;
249}
250
251template <typename RADIAL_BASIS_FUNCTION_T>
253{
254
255 // Step 1: index the clusters / the center mesh in order to define the output vertex -> cluster ownership
256 // the ownership is required to compute the normalized partition of unity weights (Step 2)
257 // query::Index clusterIndex(*_centerMesh.get());
259 query::Index &clusterIndex = _centerMesh->index();
260
261 // Step 2: find all clusters the output vertex lies in, i.e., find all cluster centers which have the distance of a cluster radius from the given output vertex
262 // Here, we do this using the RTree on the centerMesh: VertexID (queried from the centersMesh) == clusterID, by construction above. The loop uses
263 // the vertices to compute the weights required for the partition of unity data mapping.
264 // Note: this could also be done on-the-fly in the map data phase for dynamic queries, which would require to make the mesh as well as the indexTree member variables.
265
266 // Step 2a: get the relevant clusters for the output vertex
267 auto clusterIDs = clusterIndex.getVerticesInsideBox(vertex, _clusterRadius);
268 const auto localNumberOfClusters = clusterIDs.size();
269
270 // Consider the case where we didn't find any cluster (meshes don't match very well)
271 //
272 // In principle, we could assign the vertex to the closest cluster using clusterIDs.emplace_back(clusterIndex.getClosestVertex(vertex.getCoords()).index);
273 // However, this leads to a conflict with weights already set in the corresponding cluster, since we insert the ID and, later on, map the ID to a local weight index
274 // Of course, we could rearrange the weights, but we want to avoid the case here anyway, i.e., prefer to abort.
275 PRECICE_CHECK(localNumberOfClusters > 0,
276 "Output vertex {} of mesh \"{}\" could not be assigned to any cluster in the rbf-pum mapping. This probably means that the meshes do not match well geometry-wise: Visualize the exported preCICE meshes to confirm."
277 " If the meshes are fine geometry-wise, you can try to increase the number of \"vertices-per-cluster\" (default is 50), the \"relative-overlap\" (default is 0.15),"
278 " or disable the option \"project-to-input\"."
279 "These options are only valid for the <mapping:rbf-pum-direct/> tag.",
280 vertex.getCoords(), mesh);
281
282 // Next we compute the normalized weights of each output vertex for each partition
283 PRECICE_ASSERT(localNumberOfClusters > 0, "No cluster found for vertex {}", vertex.getCoords());
284
285 // Step 2b: compute the weight in each partition individually and store them in 'weights'
286 std::vector<double> weights(localNumberOfClusters);
287 std::transform(clusterIDs.cbegin(), clusterIDs.cend(), weights.begin(), [&](const auto &ids) { return _clusters[ids].computeWeight(vertex); });
288 double weightSum = std::accumulate(weights.begin(), weights.end(), static_cast<double>(0.));
289 // TODO: This covers the edge case of vertices being at the edge of (several) clusters
290 // In case the sum is equal to zero, we assign equal weights for all clusters
291 if (weightSum <= 0) {
292 PRECICE_ASSERT(weights.size() > 0);
293 std::for_each(weights.begin(), weights.end(), [&weights](auto &w) { w = 1. / weights.size(); });
294 weightSum = 1;
295 }
296 PRECICE_ASSERT(weightSum > 0);
297
298 // Step 2c: Normalize weights
299 std::transform(weights.begin(), weights.end(), weights.begin(), [weightSum](double w) { return w / weightSum; });
300
301 // Return both the cluster IDs and the normalized weights
302 return {clusterIDs, weights};
303}
304
305template <typename RADIAL_BASIS_FUNCTION_T>
307{
309
310 precice::profiling::Event e("map.pou.mapData.From" + input()->getName() + "To" + output()->getName(), profiling::Synchronize);
311
312 // Execute the actual mapping evaluation in all clusters
313 // 1. Assert that all output data values were reset, as we accumulate data in all clusters independently
314 PRECICE_ASSERT(outData.isZero());
315
316 // 2. Iterate over all clusters and accumulate the result in the output data
317 std::for_each(_clusters.begin(), _clusters.end(), [&](auto &cluster) { cluster.mapConservative(inData, outData); });
318}
319
320template <typename RADIAL_BASIS_FUNCTION_T>
322{
324
325 precice::profiling::Event e("map.pou.mapData.From" + input()->getName() + "To" + output()->getName(), profiling::Synchronize);
326
327 // Execute the actual mapping evaluation in all clusters
328 // 1. Assert that all output data values were reset, as we accumulate data in all clusters independently
329 PRECICE_ASSERT(outData.isZero());
330
331 // 2. Execute the actual mapping evaluation in all vertex clusters and accumulate the data
332 std::for_each(_clusters.begin(), _clusters.end(), [&](auto &clusters) { clusters.mapConsistent(inData, outData); });
333}
334
335template <typename RADIAL_BASIS_FUNCTION_T>
336void PartitionOfUnityMapping<RADIAL_BASIS_FUNCTION_T>::mapConservativeAt(const Eigen::Ref<const Eigen::MatrixXd> &coordinates, const Eigen::Ref<const Eigen::MatrixXd> &source,
337 impl::MappingDataCache &cache, Eigen::Ref<Eigen::MatrixXd>)
338{
339 precice::profiling::Event e("map.pou.mapConservativeAt.From" + input()->getName());
340 // @todo: it would most probably be more efficient to first group the vertices we receive here according to the clusters and then compute the solution
341
344 PRECICE_ASSERT(cache.p.size() == _clusters.size());
346
347 mesh::Vertex vertex(coordinates.col(0), -1);
348 for (Eigen::Index v = 0; v < coordinates.cols(); ++v) {
349 vertex.setCoords(coordinates.col(v));
350 auto [clusterIDs, normalizedWeights] = computeNormalizedWeight(vertex, this->input()->getName());
351 // Use the weight to interpolate the solution
352 for (std::size_t i = 0; i < clusterIDs.size(); ++i) {
353 PRECICE_ASSERT(clusterIDs[i] < static_cast<int>(_clusters.size()));
354 auto id = clusterIDs[i];
355 // the input mesh refers here to a consistent constraint
356 Eigen::VectorXd res = normalizedWeights[i] * source.col(v);
357 _clusters[id].addWriteDataToCache(vertex, res, cache.polynomialContributions[id], cache.p[id], *this->output().get());
358 }
359 }
360}
361
362template <typename RADIAL_BASIS_FUNCTION_T>
364{
366 PRECICE_ASSERT(!cache.p.empty());
368 precice::profiling::Event e("map.pou.completeJustInTimeMapping.From" + input()->getName());
369
370 for (std::size_t c = 0; c < _clusters.size(); ++c) {
371 // If there is no contribution, we don't have to evaluate
372 if (cache.p[c].squaredNorm() > 0) {
373 _clusters[c].evaluateConservativeCache(cache.polynomialContributions[c], cache.p[c], buffer);
374 }
375 }
376}
377
378template <typename RADIAL_BASIS_FUNCTION_T>
380{
383 cache.p.resize(_clusters.size());
385 for (std::size_t c = 0; c < _clusters.size(); ++c) {
386 _clusters[c].initializeCacheData(cache.polynomialContributions[c], cache.p[c], cache.getDataDimensions());
387 }
388}
389
390template <typename RADIAL_BASIS_FUNCTION_T>
392{
393 // We cannot synchronize this event, as the call to this function is rank-local only
394 precice::profiling::Event e("map.pou.updateMappingDataCache.From" + input()->getName());
395 PRECICE_ASSERT(cache.p.size() == _clusters.size());
397 Eigen::Map<const Eigen::MatrixXd> inMatrix(in.data(), cache.getDataDimensions(), in.size() / cache.getDataDimensions());
398 for (std::size_t c = 0; c < _clusters.size(); ++c) {
399 _clusters[c].computeCacheData(inMatrix, cache.polynomialContributions[c], cache.p[c]);
400 }
401}
402
403template <typename RADIAL_BASIS_FUNCTION_T>
404void PartitionOfUnityMapping<RADIAL_BASIS_FUNCTION_T>::mapConsistentAt(const Eigen::Ref<const Eigen::MatrixXd> &coordinates, const impl::MappingDataCache &cache, Eigen::Ref<Eigen::MatrixXd> values)
405{
406 precice::profiling::Event e("map.pou.mapConsistentAt.From" + input()->getName());
407 // @todo: it would most probably be more efficient to first group the vertices we receive here according to the clusters and then compute the solution
410
411 // First, make sure that everything is reset before we start
412 values.setZero();
413
414 mesh::Vertex vertex(coordinates.col(0), -1);
415 for (Eigen::Index v = 0; v < values.cols(); ++v) {
416 vertex.setCoords(coordinates.col(v));
417 auto [clusterIDs, normalizedWeights] = computeNormalizedWeight(vertex, this->output()->getName());
418 // Use the weight to interpolate the solution
419 for (std::size_t i = 0; i < clusterIDs.size(); ++i) {
420 PRECICE_ASSERT(clusterIDs[i] < static_cast<int>(_clusters.size()));
421 auto id = clusterIDs[i];
422 // the input mesh refers here to a consistent constraint
423 Eigen::VectorXd localRes = normalizedWeights[i] * _clusters[id].interpolateAt(vertex, cache.polynomialContributions[id], cache.p[id], *this->input().get());
424 values.col(v) += localRes;
425 }
426 }
427}
428
429template <typename RADIAL_BASIS_FUNCTION_T>
431{
433 mesh::PtrMesh filterMesh, outMesh;
435 filterMesh = this->output(); // remote
436 outMesh = this->input(); // local
437 } else {
438 filterMesh = this->input(); // remote
439 outMesh = this->output(); // local
440 }
441
442 if (outMesh->empty())
443 return; // Ranks not at the interface should never hold interface vertices
444
445 // The geometric filter of the repartitioning is always disabled for the PU-RBF.
446 // The main rationale: if we use only a fraction of the mesh then we might end up
447 // with too few vertices per rank and we cannot prevent too few vertices from being
448 // tagged, if we have filtered too much vertices beforehand. When using the filtering,
449 // the user could increase the safety-factor or disable the filtering, but that's
450 // a bit hard to understand for users. When no geometric filter is applid,
451 // vertices().size() is here the same as getGlobalNumberOfVertices. Hence, it is much
452 // safer to make use of the unfiltered mesh for the parallel tagging.
453 //
454 // Drawback: the "estimateClusterRadius" below makes use of the mesh R* index tree, and
455 // constructing the tree on the (unfiltered) global mesh is computationally expensive (O( N logN)).
456 // We could pre-filter the global mesh to a local fraction (using our own geometric filtering,
457 // maybe with an increased safety margin or even an iterative increase of the safety margin),
458 // but then there is again the question on how to do this in a safe way, without risking
459 // failures depending on the partitioning. So we stick here to the computationally more
460 // demanding, but safer version.
461 // See also https://github.com/precice/precice/pull/1912#issuecomment-2551143620
462
463 // Get the local bounding boxes
464 auto localBB = outMesh->getBoundingBox();
465 // we cannot check for empty'ness here, as a single output mesh vertex
466 // would lead to a 0D box with zero volume (considered empty). Thus, we
467 // simply check here for default'ness, which is equivalent to outMesh->empty()
468 // further above
469 PRECICE_ASSERT(!localBB.isDefault());
470
471 if (_clusterRadius == 0)
473
474 PRECICE_DEBUG("Cluster radius estimate: {}", _clusterRadius);
476
477 // Now we extend the bounding box by the radius
478 localBB.expandBy(2 * _clusterRadius);
479
480 // ... and tag all affected vertices
481 auto verticesNew = filterMesh->index().getVerticesInsideBox(localBB);
482
483 std::for_each(verticesNew.begin(), verticesNew.end(), [&filterMesh](VertexID v) { filterMesh->vertex(v).tag(); });
484}
485
486template <typename RADIAL_BASIS_FUNCTION_T>
488{
489 // Nothing to be done here. There is no global ownership for matrix entries required and we tag all potentially locally relevant vertices already in the first round.
490}
491
492template <typename RADIAL_BASIS_FUNCTION_T>
494{
496
497 auto dataRadius = centerMesh.createData("radius", 1, -1);
498 auto dataCardinality = centerMesh.createData("number-of-vertices", 1, -1);
499 centerMesh.allocateDataValues();
500 dataRadius->values().fill(_clusterRadius);
501 for (unsigned int i = 0; i < _clusters.size(); ++i) {
502 dataCardinality->values()[i] = static_cast<double>(_clusters[i].getNumberOfInputVertices());
503 }
504
505 // We have to create the global offsets in order to export things in parallel
507 // send number of vertices
508 PRECICE_DEBUG("Send number of vertices: {}", centerMesh.nVertices());
509 int numberOfVertices = centerMesh.nVertices();
510 utils::IntraComm::getCommunication()->send(numberOfVertices, 0);
511
512 // receive vertex offsets
513 mesh::Mesh::VertexOffsets vertexOffsets;
514 utils::IntraComm::getCommunication()->broadcast(vertexOffsets, 0);
515 PRECICE_DEBUG("Vertex offsets: {}", vertexOffsets);
516 PRECICE_ASSERT(centerMesh.getVertexOffsets().empty());
517 centerMesh.setVertexOffsets(std::move(vertexOffsets));
518 } else if (utils::IntraComm::isPrimary()) {
519
521 vertexOffsets[0] = centerMesh.nVertices();
522
523 // receive number of secondary vertices and fill vertex offsets
524 for (int secondaryRank : utils::IntraComm::allSecondaryRanks()) {
525 int numberOfSecondaryRankVertices = -1;
526 utils::IntraComm::getCommunication()->receive(numberOfSecondaryRankVertices, secondaryRank);
527 PRECICE_ASSERT(numberOfSecondaryRankVertices >= 0);
528 vertexOffsets[secondaryRank] = numberOfSecondaryRankVertices + vertexOffsets[secondaryRank - 1];
529 }
530
531 // broadcast vertex offsets
532 PRECICE_DEBUG("Vertex offsets: {}", centerMesh.getVertexOffsets());
533 utils::IntraComm::getCommunication()->broadcast(vertexOffsets);
534 centerMesh.setVertexOffsets(std::move(vertexOffsets));
535 }
536
537 dataRadius->setSampleAtTime(0, time::Sample{1, dataRadius->values()});
538 dataCardinality->setSampleAtTime(0, time::Sample{1, dataCardinality->values()});
540 exporter.doExport(0, 0.0);
541}
542
543template <typename RADIAL_BASIS_FUNCTION_T>
545{
547 _clusters.clear();
548 // TODO: Don't reset this here
549 _clusterRadius = 0;
550 this->_hasComputedMapping = false;
551}
552
553template <typename RADIAL_BASIS_FUNCTION_T>
555{
556 return "partition-of-unity RBF";
557}
558} // namespace mapping
559} // namespace precice
#define PRECICE_DEBUG(...)
Definition LogMacros.hpp:61
#define PRECICE_TRACE(...)
Definition LogMacros.hpp:92
#define PRECICE_CHECK(check,...)
Definition LogMacros.hpp:32
T accumulate(T... args)
#define PRECICE_ASSERT(...)
Definition assertion.hpp:85
T begin(T... args)
void doExport(int index, double time) final override
Export the mesh and writes files.
Definition ExportXML.cpp:33
mesh::PtrMesh output() const
Returns pointer to output mesh.
Definition Mapping.cpp:92
Constraint
Specifies additional constraints for a mapping.
Definition Mapping.hpp:30
Mapping(Constraint constraint, int dimensions, bool requiresGradientData, InitialGuessRequirement initialGuessRequirement)
Constructor, takes mapping constraint.
Definition Mapping.cpp:12
mesh::PtrMesh input() const
Returns pointer to input mesh.
Definition Mapping.cpp:87
bool _hasComputedMapping
Flag to indicate whether computeMapping() has been called.
Definition Mapping.hpp:307
bool isScaledConsistent() const
Returns true if mapping is a form of scaled consistent mapping.
Definition Mapping.cpp:258
void setInputRequirement(MeshRequirement requirement)
Sets the mesh requirement for the input mesh.
Definition Mapping.cpp:97
void setOutputRequirement(MeshRequirement requirement)
Sets the mesh requirement for the output mesh.
Definition Mapping.cpp:103
virtual bool hasConstraint(const Constraint &constraint) const
Checks whether the mapping has the given constraint or not.
Definition Mapping.cpp:248
InitialGuessRequirement
Specifies whether the mapping requires an initial guess.
Definition Mapping.hpp:64
std::pair< std::vector< int >, std::vector< double > > computeNormalizedWeight(const mesh::Vertex &v, std::string_view mesh)
void initializeMappingDataCache(impl::MappingDataCache &cache) final override
void mapConservativeAt(const Eigen::Ref< const Eigen::MatrixXd > &coordinates, const Eigen::Ref< const Eigen::MatrixXd > &source, impl::MappingDataCache &cache, Eigen::Ref< Eigen::MatrixXd > target) final override
std::vector< SphericalVertexCluster< RBF > > _clusters
std::string getName() const final override
void mapConsistent(const time::Sample &inData, Eigen::VectorXd &outData) override
Maps data using a consistent constraint.
PartitionOfUnityMapping(Mapping::Constraint constraint, int dimension, RADIAL_BASIS_FUNCTION_T function, Polynomial polynomial, unsigned int verticesPerCluster, double relativeOverlap, bool projectToInput)
void mapConsistentAt(const Eigen::Ref< const Eigen::MatrixXd > &coordinates, const impl::MappingDataCache &cache, Eigen::Ref< Eigen::MatrixXd > values) final override
void mapConservative(const time::Sample &inData, Eigen::VectorXd &outData) override
Maps data using a conservative constraint.
void updateMappingDataCache(impl::MappingDataCache &cache, const Eigen::Ref< const Eigen::VectorXd > &in) final override
void completeJustInTimeMapping(impl::MappingDataCache &cache, Eigen::Ref< Eigen::MatrixXd > buffer) final override
Container and creator for meshes.
Definition Mesh.hpp:38
static constexpr MeshID MESH_ID_UNDEFINED
Use if the id of the mesh is not necessary.
Definition Mesh.hpp:57
std::size_t nVertices() const
Returns the number of vertices.
Definition Mesh.cpp:65
PtrData & createData(const std::string &name, int dimension, DataID id, int waveformDegree=time::Time::DEFAULT_WAVEFORM_DEGREE)
Create only data for vertex.
Definition Mesh.cpp:153
const VertexOffsets & getVertexOffsets() const
Definition Mesh.hpp:251
std::vector< int > VertexOffsets
Definition Mesh.hpp:54
void setVertexOffsets(VertexOffsets vertexOffsets)
Only used for tests.
Definition Mesh.hpp:260
void allocateDataValues()
Allocates memory for the vertex data values and corresponding gradient values.
Definition Mesh.cpp:235
Vertex of a mesh.
Definition Vertex.hpp:16
VertexID getID() const
Returns the unique (among vertices of one mesh on one processor) ID of the vertex.
Definition Vertex.hpp:109
void setCoords(const VECTOR_T &coordinates)
Sets the coordinates of the vertex.
Definition Vertex.hpp:101
Eigen::VectorXd getCoords() const
Returns the coordinates of the vertex.
Definition Vertex.hpp:114
void stop()
Stops a running event.
Definition Event.cpp:51
void addData(std::string_view key, int value)
Adds named integer data, associated to an event.
Definition Event.cpp:62
Class to query the index trees of the mesh.
Definition Index.hpp:64
std::vector< VertexID > getVerticesInsideBox(const mesh::Vertex &centerVertex, double radius)
Return all the vertices inside the box formed by vertex and radius (boundary exclusive)
Definition Index.cpp:223
static int getSize()
Number of ranks. This includes ranks from both participants, e.g. minimal size is 2.
Definition IntraComm.cpp:47
static Rank getRank()
Current rank.
Definition IntraComm.cpp:42
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 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
T empty(T... args)
T end(T... args)
T for_each(T... args)
T make_unique(T... args)
T max_element(T... args)
T min_element(T... args)
contains the logging framework.
std::tuple< double, Vertices > createClustering(mesh::PtrMesh inMesh, mesh::PtrMesh outMesh, double relativeOverlap, unsigned int verticesPerCluster, bool projectClustersToInput)
Creates a clustering as a collection of Vertices (representing the cluster centers) and a cluster rad...
double estimateClusterRadius(unsigned int verticesPerCluster, mesh::PtrMesh inMesh, const mesh::BoundingBox &bb)
Computes an estimate for the cluster radius, which results in approximately verticesPerCluster vertic...
contains data mapping from points to meshes.
Polynomial
How to handle the polynomial?
provides Mesh, Data and primitives.
std::shared_ptr< Mesh > PtrMesh
static constexpr SynchronizeTag Synchronize
Convenience instance of the SynchronizeTag.
Definition Event.hpp:21
Main namespace of the precice library.
int VertexID
Definition Types.hpp:13
bool syncMode
Enabled further inter- and intra-solver synchronisation.
STL namespace.
T resize(T... args)
T size(T... args)
std::vector< Eigen::MatrixXd > polynomialContributions
int getDataDimensions() const
Returns the number of data components.
T transform(T... args)