28template <
typename RADIAL_BASIS_FUNCTION_T>
49 RADIAL_BASIS_FUNCTION_T function,
51 unsigned int verticesPerCluster,
52 double relativeOverlap,
67 void clear()
final override;
116template <
typename RADIAL_BASIS_FUNCTION_T>
120 RADIAL_BASIS_FUNCTION_T function,
122 unsigned int verticesPerCluster,
123 double relativeOverlap,
126 _basisFunction(function), _verticesPerCluster(verticesPerCluster), _relativeOverlap(relativeOverlap), _projectToInput(projectToInput), _polynomial(polynomial)
142template <
typename RADIAL_BASIS_FUNCTION_T>
150 PRECICE_ASSERT(!this->_hasComputedMapping,
"Please clear the mapping before recomputing.");
155 inMesh = this->output();
156 outMesh = this->input();
158 inMesh = this->input();
159 outMesh = this->output();
162 precice::profiling::Event eClusters(
"map.pou.computeMapping.createClustering.From" + this->input()->getName() +
"To" + this->output()->getName());
164 auto [clusterRadius, centerCandidates] =
impl::createClustering(inMesh, outMesh, _relativeOverlap, _verticesPerCluster, _projectToInput);
167 _clusterRadius = clusterRadius;
168 PRECICE_ASSERT(_clusterRadius > 0 || inMesh->nVertices() == 0 || outMesh->nVertices() == 0);
173 auto & meshVertices = centerMesh.
vertices();
175 meshVertices.
clear();
177 _clusters.reserve(centerCandidates.size());
178 for (
const auto &c : centerCandidates) {
181 const VertexID vertexID = meshVertices.size();
186 if (!cluster.
empty()) {
188 meshVertices.emplace_back(std::move(center));
189 _clusters.emplace_back(std::move(cluster));
193 e.
addData(
"n clusters", _clusters.size());
195 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());
197 if (_clusters.size() > 0) {
198 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());
199 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());
200 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());
216 for (
const auto &vertex : outMesh->vertices()) {
219 const auto localNumberOfClusters = clusterIDs.
size();
227 "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."
228 " 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),"
229 " or disable the option \"project-to-input\"."
230 "These options are only valid for the <mapping:rbf-pum-direct/> tag.",
231 vertex.getCoords(), outMesh->getName());
234 PRECICE_ASSERT(localNumberOfClusters > 0,
"No cluster found for vertex {}", vertex.getCoords());
238 std::transform(clusterIDs.cbegin(), clusterIDs.cend(), weights.
begin(), [&](
const auto &ids) { return _clusters[ids].computeWeight(vertex); });
242 if (weightSum <= 0) {
250 for (
unsigned int i = 0; i < localNumberOfClusters; ++i) {
251 PRECICE_ASSERT(clusterIDs[i] <
static_cast<int>(_clusters.size()));
252 _clusters[clusterIDs[i]].setNormalizedWeight(weights[i] / weightSum, vertex.getID());
260 this->_hasComputedMapping =
true;
263template <
typename RADIAL_BASIS_FUNCTION_T>
275 std::for_each(_clusters.begin(), _clusters.end(), [&](
auto &cluster) { cluster.mapConservative(inData, outData); });
278template <
typename RADIAL_BASIS_FUNCTION_T>
290 std::for_each(_clusters.begin(), _clusters.end(), [&](
auto &clusters) { clusters.mapConsistent(inData, outData); });
293template <
typename RADIAL_BASIS_FUNCTION_T>
299 filterMesh = this->output();
300 outMesh = this->input();
302 filterMesh = this->input();
303 outMesh = this->output();
306 if (outMesh->empty())
317 for (
const mesh::Vertex &vertex : filterMesh->vertices()) {
333 if (filterMesh->nVertices() < _verticesPerCluster &&
334 filterMesh->nVertices() <
static_cast<std::size_t>(filterMesh->getGlobalNumberOfVertices())) {
335 PRECICE_WARN(
"The repartitioning of the received mesh \"{}\" resulted in {} vertices on this "
336 "rank, which is less than the desired number of vertices per cluster configured "
337 "in the partition of unity mapping ({}). Consider increasing the safety-factor "
338 "or switching off the geometric filter (<receive-mesh: ... geometric-filter=\"no-filter\" .../>)",
339 filterMesh->getName(), filterMesh->nVertices(), _verticesPerCluster);
342 if (_clusterRadius == 0)
345 PRECICE_DEBUG(
"Cluster radius estimate: {}", _clusterRadius);
349 auto localBB = outMesh->getBoundingBox();
351 localBB.expandBy(2 * _clusterRadius);
354 auto verticesNew = filterMesh->index().getVerticesInsideBox(localBB);
356 std::for_each(verticesNew.begin(), verticesNew.end(), [&filterMesh](
VertexID v) { filterMesh->vertex(v).tag(); });
359template <
typename RADIAL_BASIS_FUNCTION_T>
365template <
typename RADIAL_BASIS_FUNCTION_T>
370 auto dataRadius = centerMesh.
createData(
"radius", 1, -1);
371 auto dataCardinality = centerMesh.
createData(
"number-of-vertices", 1, -1);
373 dataRadius->values().fill(_clusterRadius);
374 for (
unsigned int i = 0; i < _clusters.size(); ++i) {
375 dataCardinality->values()[i] =
static_cast<double>(_clusters[i].getNumberOfInputVertices());
382 int numberOfVertices = centerMesh.
nVertices();
394 vertexOffsets[0] = centerMesh.
nVertices();
398 int numberOfSecondaryRankVertices = -1;
401 vertexOffsets[secondaryRank] = numberOfSecondaryRankVertices + vertexOffsets[secondaryRank - 1];
414template <
typename RADIAL_BASIS_FUNCTION_T>
421 this->_hasComputedMapping =
false;
424template <
typename RADIAL_BASIS_FUNCTION_T>
427 return "partition-of-unity RBF";
#define PRECICE_WARN(...)
#define PRECICE_DEBUG(...)
#define PRECICE_TRACE(...)
#define PRECICE_CHECK(check,...)
#define PRECICE_ASSERT(...)
void doExport(const std::string &name, const std::string &location, const mesh::Mesh &mesh) override
Does export. Has to be implemented in subclass.
This class provides a lightweight logger.
Abstract base class for mapping of data from one mesh to another.
Constraint
Specifies additional constraints for a mapping.
int getDimensions() const
bool isScaledConsistent() const
Returns true if mapping is a form of scaled consistent mapping.
void setInputRequirement(MeshRequirement requirement)
Sets the mesh requirement for the input mesh.
void setOutputRequirement(MeshRequirement requirement)
Sets the mesh requirement for the output mesh.
InitialGuessRequirement
Specifies whether the mapping requires an initial guess.
void tagMeshSecondRound() final override
nothing to do here
void tagMeshFirstRound() final override
tag the vertices required for the mapping
Polynomial _polynomial
polynomial treatment of the RBF system
void exportClusterCentersAsVTU(mesh::Mesh ¢ers)
precice::logging::Logger _log
logger, as usual
const double _relativeOverlap
overlap of vertex clusters
std::vector< SphericalVertexCluster< RADIAL_BASIS_FUNCTION_T > > _clusters
main data container storing all the clusters, which need to be solved individually
const bool _projectToInput
toggles whether we project the cluster centers to the input mesh
std::string getName() const final override
name of the pum mapping
virtual void mapConsistent(const time::Sample &inData, Eigen::VectorXd &outData) override
Maps data using a consistent constraint.
double _clusterRadius
derived parameter based on the input above: the radius of each cluster
PartitionOfUnityMapping(Mapping::Constraint constraint, int dimension, RADIAL_BASIS_FUNCTION_T function, Polynomial polynomial, unsigned int verticesPerCluster, double relativeOverlap, bool projectToInput)
const unsigned int _verticesPerCluster
Input parameters provided by the user for the clustering algorithm:
RADIAL_BASIS_FUNCTION_T _basisFunction
Radial basis function type used in interpolation.
virtual void mapConservative(const time::Sample &inData, Eigen::VectorXd &outData) override
Maps data using a conservative constraint.
void computeMapping() final override
void clear() final override
Clears a computed mapping by deleting the content of the _clusters vector.
An axis-aligned bounding box around a (partition of a) mesh.
bool empty() const
Check if every dimension's length is equal to zero.
void expandBy(const BoundingBox &otherBB)
Expand bounding box using another bounding box.
Container and creator for meshes.
VertexContainer & vertices()
Returns modifieable container holding all vertices.
const std::string & getName() const
Returns the name of the mesh, as set in the config file.
static constexpr MeshID MESH_ID_UNDEFINED
Use if the id of the mesh is not necessary.
std::size_t nVertices() const
Returns the number of vertices.
PtrData & createData(const std::string &name, int dimension, DataID id, int waveformDegree=time::Time::DEFAULT_WAVEFORM_DEGREE)
Create only data for vertex.
const VertexOffsets & getVertexOffsets() const
void computeBoundingBox()
Computes the boundingBox for the vertices.
void setVertexOffsets(VertexOffsets vertexOffsets)
Only used for tests.
const BoundingBox & getBoundingBox() const
Returns the bounding box of the mesh.
void allocateDataValues()
Allocates memory for the vertex data values and corresponding gradient values.
VertexID getID() const
Returns the unique (among vertices of one mesh on one processor) ID of the vertex.
void stop()
Stops a running event.
void addData(std::string_view key, int value)
Adds named integer data, associated to an event.
Class to query the index trees of the mesh.
std::vector< VertexID > getVerticesInsideBox(const mesh::Vertex ¢erVertex, double radius)
Return all the vertices inside the box formed by vertex and radius (boundary exclusive)
static int getSize()
Number of ranks. This includes ranks from both participants, e.g. minimal size is 2.
static Rank getRank()
Current rank.
static bool isPrimary()
True if this process is running the primary rank.
static auto allSecondaryRanks()
Returns an iterable range over salve ranks [1, _size)
static bool isSecondary()
True if this process is running a secondary rank.
static com::PtrCommunication & getCommunication()
Intra-participant communication.
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...
Polynomial
How to handle the polynomial?
static constexpr SynchronizeTag Synchronize
Convenience instance of the SynchronizeTag.
Main namespace of the precice library.
bool syncMode
Enabled further inter- and intra-solver synchronisation.