2#ifndef PRECICE_NO_PETSC
14#include "precice/impl/versions.hpp"
26inline PetscErrorCode PRECICE_VecFilter(Vec v, PetscReal tol)
28#if ((PETSC_MAJOR > 3) || (PETSC_MAJOR == 3 && PETSC_MINOR >= 20))
29 return VecFilter(v, tol);
31 return VecChop(v, tol);
37class PetRadialBasisFctMappingTest;
50template <
typename RADIAL_BASIS_FUNCTION_T>
68 const RADIAL_BASIS_FUNCTION_T &function,
70 double solverRtol = 1e-9,
95 mutable
logging::Logger
_log{
"mapping::PetRadialBasisFctMapping"};
168template <
typename RADIAL_BASIS_FUNCTION_T>
172 const RADIAL_BASIS_FUNCTION_T &function,
193template <
typename RADIAL_BASIS_FUNCTION_T>
199template <
typename RADIAL_BASIS_FUNCTION_T>
214 int const dimensions = this->
input()->getDimensions();
219 outMesh = this->
input();
221 inMesh = this->
input();
238 auto n = myIndizes.
size();
240 auto outputSize = outMesh->nVertices();
242 PetscErrorCode ierr = 0;
243 PRECICE_DEBUG(
"inMesh->nVertices() = {}", inMesh->nVertices());
244 PRECICE_DEBUG(
"outMesh->nVertices() = {}", outMesh->nVertices());
250 _matrixC.init(n, n, PETSC_DETERMINE, PETSC_DETERMINE, MATSBAIJ);
252 ierr = MatSetOption(
_matrixC, MAT_SYMMETRIC, PETSC_TRUE);
254 ierr = MatSetOption(
_matrixC, MAT_SYMMETRY_ETERNAL, PETSC_TRUE);
266 _matrixA.init(outputSize, n, PETSC_DETERMINE, PETSC_DETERMINE, MATAIJ);
267 PRECICE_DEBUG(
"Set matrix A to local size {} x {}", outputSize, n);
269 eCreateMatrices.
stop();
272 auto const ownerRangeABegin =
_matrixA.ownerRange().first;
273 auto const ownerRangeAEnd =
_matrixA.ownerRange().second;
281 Eigen::VectorXd distance(dimensions);
301 for (
const mesh::Vertex &inVertex : inMesh->vertices()) {
302 if (not inVertex.isOwner())
309 colIdx[colNum] = colNum;
310 rowVals[colNum++] = 1;
312 for (
int dim = 0; dim < dimensions; dim++) {
314 colIdx[colNum] = colNum;
315 rowVals[colNum++] = inVertex.coord(dim);
321 ierr = MatSetValues(
_matrixC, colNum, colIdx.
data(), 1, &row, rowVals.
data(), INSERT_VALUES);
324 ierr = MatSetValues(
_matrixQ, 1, &row, colNum, colIdx.
data(), rowVals.
data(), INSERT_VALUES);
332 auto const &rowVertices = vertexData[preallocRow];
333 for (
const auto &vertex : rowVertices) {
335 colIdx[colNum++] = vertex.first;
341 ierr = MatSetValues(
_matrixC, 1, &row, colNum, colIdx.
data(), rowVals.
data(), INSERT_VALUES);
350 _matrixC.assemble(MAT_FLUSH_ASSEMBLY);
352 VecZeroEntries(zeros);
355 MatDiagonalSet(
_matrixC, zeros, ADD_VALUES);
358 ierr = MatAssemblyBegin(
_matrixC, MAT_FINAL_ASSEMBLY);
360 ierr = MatAssemblyBegin(
_matrixQ, MAT_FINAL_ASSEMBLY);
374 for (PetscInt row = ownerRangeABegin; row < ownerRangeAEnd; ++row) {
382 colIdx[colNum] = colNum;
383 rowVals[colNum++] = 1;
385 for (
int dim = 0; dim < dimensions; dim++) {
387 colIdx[colNum] = colNum;
388 rowVals[colNum++] = oVertex.
coord(dim);
391 ierr = MatSetValues(*m, 1, &row, colNum, colIdx.
data(), rowVals.
data(), INSERT_VALUES);
399 auto const &rowVertices = vertexData[row - ownerRangeABegin];
400 for (
const auto &vertex : rowVertices) {
402 colIdx[colNum++] = vertex.first;
407 ierr = MatSetValues(
_matrixA, 1, &row, colNum, colIdx.
data(), rowVals.
data(), INSERT_VALUES);
416 ierr = MatAssemblyBegin(
_matrixA, MAT_FINAL_ASSEMBLY);
419 ierr = MatAssemblyEnd(
_matrixC, MAT_FINAL_ASSEMBLY);
421 ierr = MatAssemblyEnd(
_matrixQ, MAT_FINAL_ASSEMBLY);
423 ierr = MatAssemblyEnd(
_matrixA, MAT_FINAL_ASSEMBLY);
435 PCSetType(pc, PCNONE);
453 KSPSetInitialGuessNonzero(
_solver, PETSC_TRUE);
455 KSPSetOptionsPrefix(
_solver,
"solverC_");
496 PRECICE_DEBUG(
"Non-zeros allocated / used / unused for matrix C = {} / {} / {}",
497 _matrixC.getInfo(MAT_LOCAL).nz_allocated,
_matrixC.getInfo(MAT_LOCAL).nz_used,
_matrixC.getInfo(MAT_LOCAL).nz_unneeded);
499 PRECICE_DEBUG(
"Non-zeros allocated / used / unused for matrix A = {} / {} / {}",
500 _matrixA.getInfo(MAT_LOCAL).nz_allocated,
_matrixA.getInfo(MAT_LOCAL).nz_used,
_matrixA.getInfo(MAT_LOCAL).nz_unneeded);
503template <
typename RADIAL_BASIS_FUNCTION_T>
519template <
typename RADIAL_BASIS_FUNCTION_T>
522 return "global-iterative RBF";
525template <
typename RADIAL_BASIS_FUNCTION_T>
529 if (destination.
getSize() == 0) {
533 auto totalSize = sizePerDim * allDimensions;
537 this->
initialGuess() = Eigen::VectorXd::Zero(totalSize);
541 auto offset = dimension * sizePerDim;
546template <
typename RADIAL_BASIS_FUNCTION_T>
557 auto offset = dimension * sizePerDim;
562template <
typename RADIAL_BASIS_FUNCTION_T>
568 PetscErrorCode ierr = 0;
569 auto const &inValues = inData.
values;
570 auto &outValues = outData;
572 int const valueDim = inData.
dataDims;
579 PetscScalar
const *vecArray;
582 for (
int dim = 0; dim < valueDim; dim++) {
590 for (
size_t i = 0; i < this->
input()->nVertices(); ++i) {
591 if (not this->
input()->vertex(i).isOwner())
596 ierr = VecSetValues(in, inIdx.
size(), inIdx.
data(), inVals.
data(), INSERT_VALUES);
603 PRECICE_DEBUG(
"The polynomial QR system of the RBF mapping from mesh {} to mesh {} converged. {}",
607 PRECICE_WARN(
"The polynomial QR system of the RBF mapping from mesh {} to mesh {} has not converged. "
608 "This means most probably that the mapping problem is not well-posed or your relative tolerance is too conservative. "
609 "Please check if your coupling meshes are correct. "
610 "Maybe you need to fix axis-aligned mapping setups by marking perpendicular axes as dead? {}",
614 KSPView(
_QRsolver, PETSC_VIEWER_STDOUT_WORLD);
615 PRECICE_ERROR(
"The polynomial QR system of the RBF mapping from mesh {} to mesh {} has diverged. "
616 "This means most probably that the mapping problem is not well-posed. "
617 "Please check if your coupling meshes are correct. "
618 "Maybe you need to fix axis-aligned mapping setups by marking perpendicular axes as dead? {}",
632 const auto solverResult =
_solver.solve(in, p);
638 switch (solverResult) {
640 PRECICE_DEBUG(
"The linear system of the RBF mapping from mesh {} to mesh {} converged. {}",
644 PRECICE_WARN(
"The linear system of the RBF mapping from mesh {} to mesh {} has not converged. "
645 "This means most probably that the mapping problem is not well-posed or your relative tolerance is too conservative. "
646 "Please check if your coupling meshes are correct. "
647 "Maybe you need to fix axis-aligned mapping setups by marking perpendicular axes as dead? {}",
651 KSPView(
_solver, PETSC_VIEWER_STDOUT_WORLD);
652 PRECICE_ERROR(
"The linear system of the RBF mapping from mesh {} to mesh {} has diverged. "
653 "This means most probably that the mapping problem is not well-posed. "
654 "Please check if your coupling meshes are correct. "
655 "Maybe you need to fix axis-aligned mapping setups by marking perpendicular axes as dead? {}",
670 ierr = VecScale(a, -1);
672 ierr = MatMultAdd(
_matrixV, a, out, out);
675 PRECICE_VecFilter(out, 1e-9);
678 ierr = VecGetArrayRead(out, &vecArray);
680 int size = out.getLocalSize();
681 for (
int i = 0; i < size; i++) {
682 outValues[i * valueDim + dim] = vecArray[i];
685 VecRestoreArrayRead(out, &vecArray);
689template <
typename RADIAL_BASIS_FUNCTION_T>
695 PetscErrorCode ierr = 0;
696 auto const &inValues = inData.
values;
697 auto &outValues = outData;
699 int const valueDim = inData.
dataDims;
704 int inRangeStart, inRangeEnd;
705 std::tie(inRangeStart, inRangeEnd) = in.ownerRange();
706 for (
int dim = 0; dim < valueDim; dim++) {
710 for (
size_t i = 0; i < this->
input()->nVertices(); i++) {
711 auto const globalIndex = this->
input()->vertex(i).getGlobalIndex();
712 if (globalIndex >= inRangeStart and globalIndex < inRangeEnd)
713 ierr = VecSetValue(in, globalIndex, inValues[i * valueDim + dim], INSERT_VALUES);
724 ierr = MatMultTranspose(
_matrixV, in, epsilon);
727 ierr = MatMultTranspose(
_matrixA, in, eta);
733 VecScale(epsilon, -1);
736 ierr = MatMultTransposeAdd(
_matrixQ, mu, epsilon, tau);
740 switch (
_QRsolver.solveTranspose(tau, sigma)) {
742 PRECICE_DEBUG(
"The polynomial linear system of the RBF mapping from mesh {} to mesh {} converged. {}",
746 PRECICE_WARN(
"The polynomial linear system of the RBF mapping from mesh {} to mesh {} has not converged. "
747 "This means most probably that the mapping problem is not well-posed or your relative tolerance is too conservative. "
748 "Please check if your coupling meshes are correct. "
749 "Maybe you need to fix axis-aligned mapping setups by marking perpendicular axes as dead? {}",
753 KSPView(
_QRsolver, PETSC_VIEWER_STDOUT_WORLD);
754 PRECICE_ERROR(
"The polynomial linear system of the RBF mapping from mesh {} to mesh {} "
755 "has diverged. This means most probably that the mapping problem is not well-posed. "
756 "Please check if your coupling meshes are correct. "
757 "Maybe you need to fix axis-aligned mapping setups by marking perpendicular axes as dead? {}",
762 VecWAXPY(out, -1, sigma, mu);
764 ierr = MatMultTranspose(
_matrixA, in, au);
770 const auto solverResult =
_solver.solve(au, out);
776 switch (solverResult) {
778 PRECICE_DEBUG(
"The linear system of the RBF mapping from mesh {} to mesh {} converged. {}",
782 PRECICE_WARN(
"The linear system of the RBF mapping from mesh {} to mesh {} has not converged. "
783 "This means most probably that the mapping problem is not well-posed or your relative tolerance is too conservative. "
784 "Please check if your coupling meshes are correct. "
785 "Maybe you need to fix axis-aligned mapping setups by marking perpendicular axes as dead? {}",
789 KSPView(
_solver, PETSC_VIEWER_STDOUT_WORLD);
790 PRECICE_ERROR(
"The linear system of the RBF mapping from mesh {} to mesh {} "
791 "has diverged. This means most probably that the mapping problem is not well-posed. "
792 "Please check if your coupling meshes are correct. "
793 "Maybe you need to fix axis-aligned mapping setups by marking perpendicular axes as dead? {}",
799 PRECICE_VecFilter(out, 1e-9);
802 const PetscScalar *outArray;
803 VecGetArrayRead(out, &outArray);
805 int count = 0, ownerCount = 0;
807 if (vertex.isOwner()) {
808 outValues[count * valueDim + dim] = outArray[ownerCount +
localPolyparams];
815 VecRestoreArrayRead(out, &outArray);
819template <
typename RADIAL_BASIS_FUNCTION_T>
824 constraintName =
"consistent";
826 constraintName =
"scaled-consistent-surface";
828 constraintName =
"scaled-consistent-volume";
830 constraintName =
"conservative";
836 PRECICE_INFO(
"Mapping {} for dimension {} with polynomial set to {}",
837 constraintName, dim, polynomialName);
840template <
typename RADIAL_BASIS_FUNCTION_T>
844 PRECICE_INFO(
"Using tree-based preallocation for matrix C");
851 const double supportRadius = this->
_basisFunction.getSupportRadius();
853 const int dimensions = this->
input()->getDimensions();
854 Eigen::VectorXd distance(dimensions);
856 PetscInt colOwnerRangeCBegin, colOwnerRangeCEnd;
857 std::tie(colOwnerRangeCBegin, colOwnerRangeCEnd) =
_matrixC.ownerRangeColumn();
861 size_t local_row = 0;
865 d_nnz[local_row] = colOwnerRangeCEnd - colOwnerRangeCBegin;
866 o_nnz[local_row] =
_matrixC.getSize().first - d_nnz[local_row];
870 for (
const mesh::Vertex &inVertex : inMesh->vertices()) {
871 if (not inVertex.isOwner())
875 PetscInt
const global_row = local_row +
_matrixC.ownerRange().first;
876 d_nnz[local_row] = 0;
877 o_nnz[local_row] = 0;
881 for (
auto const i : inMesh->index().getVerticesInsideBox(inVertex, supportRadius)) {
885 AOApplicationToPetsc(
_AOmapping, 1, &mappedCol);
887 if (global_row > mappedCol)
890 distance = inVertex.getCoords() - vj.
getCoords();
891 for (
int d = 0; d < dimensions; d++)
895 double const norm = distance.norm();
896 if (supportRadius > norm or col == global_row) {
898 if (mappedCol >= colOwnerRangeCBegin and mappedCol < colOwnerRangeCEnd)
909 MatSeqSBAIJSetPreallocation(
_matrixC,
_matrixC.blockSize(), 0, d_nnz.data());
913 MatSetOption(
_matrixC, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
920template <
typename RADIAL_BASIS_FUNCTION_T>
924 PRECICE_INFO(
"Using tree-based preallocation for matrix A");
927 PetscInt ownerRangeABegin, ownerRangeAEnd, colOwnerRangeABegin, colOwnerRangeAEnd;
928 PetscInt
const outputSize =
_matrixA.getLocalSize().first;
929 double const supportRadius = this->
_basisFunction.getSupportRadius();
932 std::tie(colOwnerRangeABegin, colOwnerRangeAEnd) =
_matrixA.ownerRangeColumn();
933 const int dimensions = this->
input()->getDimensions();
936 Eigen::VectorXd distance(dimensions);
941 for (
int localRow = 0; localRow < ownerRangeAEnd - ownerRangeABegin; ++localRow) {
945 mesh::Vertex const &oVertex = outMesh->vertex(localRow);
950 if (col >= colOwnerRangeABegin and col < colOwnerRangeAEnd)
956 for (
int dim = 0; dim < dimensions; dim++) {
958 if (col >= colOwnerRangeABegin and col < colOwnerRangeAEnd)
968 for (
auto i : inMesh->index().getVerticesInsideBox(oVertex, supportRadius)) {
972 for (
int d = 0; d < dimensions; d++)
976 double const norm = distance.norm();
977 if (supportRadius > norm) {
982 if (col >= colOwnerRangeABegin and col < colOwnerRangeAEnd)
990 MatSeqAIJSetPreallocation(
_matrixA, 0, d_nnz.data());
992 MatMPIAIJSetPreallocation(
_matrixA, 0, d_nnz.data(), 0, o_nnz.
data());
994 MatSetOption(
_matrixA, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
#define PRECICE_ERROR(...)
#define PRECICE_WARN(...)
#define PRECICE_DEBUG(...)
#define PRECICE_DEBUG_IF(condition,...)
#define PRECICE_TRACE(...)
#define PRECICE_INFO(...)
#define PRECICE_ASSERT(...)
Utility class for managing MPI operations.
Abstract base class for mapping of data from one mesh to another.
mesh::PtrMesh output() const
Returns pointer to output mesh.
Constraint
Specifies additional constraints for a mapping.
@ SCALED_CONSISTENT_VOLUME
@ SCALED_CONSISTENT_SURFACE
int getDimensions() const
mesh::PtrMesh input() const
Returns pointer to input mesh.
bool _hasComputedMapping
Flag to indicate whether computeMapping() has been called.
bool isScaledConsistent() const
Returns true if mapping is a form of scaled consistent mapping.
bool hasInitialGuess() const
True if initialGuess().size() == 0.
const Eigen::VectorXd & initialGuess() const
Return the provided initial guess of a mapping using an initialGuess.
virtual bool hasConstraint(const Constraint &constraint) const
Checks whether the mapping has the given constraint or not.
InitialGuessRequirement
Specifies whether the mapping requires an initial guess.
void mapConservative(const time::Sample &inData, Eigen::VectorXd &outData) final override
VertexData bgPreallocationMatrixC(const mesh::PtrMesh inMesh)
Preallocate matrix C and saves the coefficients using a boost::geometry spatial tree for neighbor sea...
void printMappingInfo(int dim) const
Prints an INFO about the current mapping.
void mapConsistent(const time::Sample &inData, Eigen::VectorXd &outData) final override
PetRadialBasisFctMapping(Mapping::Constraint constraint, int dimensions, const RADIAL_BASIS_FUNCTION_T &function, std::array< bool, 3 > deadAxis, double solverRtol=1e-9, Polynomial polynomial=Polynomial::SEPARATE)
Constructor.
~PetRadialBasisFctMapping() override
Deletes the PETSc objects and the _deadAxis array.
void computeMapping() final override
Computes the mapping coefficients from the in- and output mesh.
std::string getName() const final override
void clear() final override
VertexData bgPreallocationMatrixA(const mesh::PtrMesh inMesh, const mesh::PtrMesh outMesh)
void loadInitialGuessForDim(int dimension, int allDimensions, petsc::Vector &destination)
petsc::KSPSolver _QRsolver
std::vector< std::vector< std::pair< int, double > > > VertexData
void storeInitialGuessForDim(int dimension, int allDimensions, petsc::Vector &source)
utils::Parallel::CommStatePtr _commState
petsc::Vector oneInterpolant
RadialBasisFctBaseMapping(Constraint constraint, int dimensions, const RADIAL_BASIS_FUNCTION_T &function, std::array< bool, 3 > deadAxis, InitialGuessRequirement mappingType)
Constructor.
int getPolynomialParameters() const
Computes the number of polynomial degrees of freedom based on the problem dimension and the dead axis...
std::vector< bool > _deadAxis
true if the mapping along some axis should be ignored
RADIAL_BASIS_FUNCTION_T _basisFunction
Radial basis function type used in interpolation.
double coord(int index) const
Returns a coordinate of a vertex.
Eigen::VectorXd getCoords() const
Returns the coordinates of the vertex.
int getGlobalIndex() const
Globally unique index.
void stop()
Stops a running event.
void addData(std::string_view key, int value)
Adds named integer data, associated to an event.
std::shared_ptr< CommState > CommStatePtr
@ Diverged
The solver diverged.
@ Stopped
The solver reached the maximum iterations.
@ Converged
The solver converged.
Vector & copyTo(precice::span< double > destination)
PetscInt getLocalSize() const
static Vector allocate(const std::string &name="")
Allocates a new vector on the given MPI communicator.
Vector & copyFrom(precice::span< const double > source)
T emplace_back(T... args)
contains the logging framework.
contains data mapping from points to meshes.
Polynomial
How to handle the polynomial?
std::shared_ptr< Mesh > PtrMesh
static constexpr SynchronizeTag Synchronize
Convenience instance of the SynchronizeTag.
contains the time interpolation logic.
void destroy(ISLocalToGlobalMapping *IS)
Destroys an ISLocalToGlobalMapping, if IS is not null and PetscIsInitialized.
contains precice-related utilities.
int dataDims
The dimensionality of the data.