You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
4.5 KiB
127 lines
4.5 KiB
#ifndef MEDUSA_BITS_APPROXIMATIONS_RBFFD_HPP_
|
|
#define MEDUSA_BITS_APPROXIMATIONS_RBFFD_HPP_
|
|
|
|
/**
|
|
* @file
|
|
* Implementation of Radial Basis Function Finite Difference approximation.
|
|
*/
|
|
|
|
#include "RBFFD_fwd.hpp"
|
|
#include <vector>
|
|
#include <medusa/bits/utils/numutils.hpp>
|
|
#include <Eigen/LU>
|
|
#include "RBFInterpolant.hpp"
|
|
|
|
namespace mm {
|
|
|
|
/// @cond
|
|
template <class RBFType, class vec_t, class scale_t, class solver_t>
|
|
Eigen::Matrix<typename vec_t::scalar_t, Eigen::Dynamic, Eigen::Dynamic>
|
|
RBFFD<RBFType, vec_t, scale_t, solver_t>::getMatrix(
|
|
const std::vector<vector_t>& local_support) const {
|
|
int n1 = local_support.size();
|
|
assert_msg(n1 > 0, "Cannot construct a RBFFD approximation with no stencil nodes. "
|
|
"Did you forget to cal findSupport?.");
|
|
int n2 = mon_.size();
|
|
int N = n1 + n2;
|
|
Eigen::Matrix<scalar_t, Eigen::Dynamic, Eigen::Dynamic> M(N, N);
|
|
// RBF part
|
|
for (int i = 0; i < n1; ++i) {
|
|
for (int j = 0; j < i; ++j) {
|
|
M(i, j) = M(j, i) = rbf_((local_support[i]-local_support[j]).squaredNorm());
|
|
}
|
|
M(i, i) = rbf_(0);
|
|
}
|
|
|
|
// Monomial part
|
|
for (int i = 0; i < n2; ++i) {
|
|
for (int j = 0; j < n1; ++j) {
|
|
M(n1+i, j) = M(j, n1+i) = mon_.eval(i, local_support[j], local_support);
|
|
}
|
|
}
|
|
M.bottomRightCorner(n2, n2).setZero();
|
|
return M;
|
|
}
|
|
|
|
template <class RBFType, class vec_t, class scale_t, class solver_t>
|
|
void RBFFD<RBFType, vec_t, scale_t, solver_t>::compute(
|
|
const vec_t& point, const std::vector<vec_t>& support) {
|
|
scale_ = scale_t::scale(point, support);
|
|
int n1 = support.size();
|
|
// Local scaled support
|
|
support_.resize(n1);
|
|
for (int i = 0; i < n1; ++i) {
|
|
support_[i] = (support[i] - point) / scale_;
|
|
}
|
|
Eigen::Matrix<typename vec_t::scalar_t, Eigen::Dynamic, Eigen::Dynamic> M = getMatrix(support_);
|
|
point_ = point;
|
|
solver_.compute(M);
|
|
}
|
|
|
|
template <class RBFType, class vec_t, class scale_t, class solver_t>
|
|
Eigen::Matrix<typename vec_t::scalar_t, Eigen::Dynamic, 1>
|
|
RBFFD<RBFType, vec_t, scale_t, solver_t>::getShape() const {
|
|
int n = support_.size();
|
|
Eigen::Matrix<scalar_t, Eigen::Dynamic, 1> rhs(n + mon_.size());
|
|
for (int i = 0; i < n; ++i) {
|
|
rhs(i) = rbf_(support_[i].squaredNorm());
|
|
}
|
|
for (int i = 0; i < mon_.size(); ++i) {
|
|
rhs(n+i) = mon_.evalAt0(i);
|
|
}
|
|
return getShapeFromRhs(rhs);
|
|
}
|
|
|
|
template <class RBFType, class vec_t, class scale_t, class solver_t>
|
|
template <class operator_t>
|
|
Eigen::Matrix<typename vec_t::scalar_t, Eigen::Dynamic, 1>
|
|
RBFFD<RBFType, vec_t, scale_t, solver_t>::getShape(const operator_t& op) const {
|
|
int n = support_.size();
|
|
Eigen::Matrix<scalar_t, Eigen::Dynamic, 1> rhs(n + mon_.size());
|
|
RBFBasis<RBFType, vec_t> rbf_basis(n, rbf_);
|
|
for (int i = 0; i < n; ++i) {
|
|
rhs(i) = rbf_basis.evalOpAt0(i, op, support_, scale_);
|
|
}
|
|
for (int i = 0; i < mon_.size(); ++i) {
|
|
rhs(n+i) = mon_.evalOpAt0(i, op, support_, scale_);
|
|
}
|
|
return getShapeFromRhs(rhs);
|
|
}
|
|
|
|
template <class RBFType, class vec_t, class scale_t, class solver_t>
|
|
template <typename Derived>
|
|
Eigen::Matrix<typename vec_t::scalar_t, Eigen::Dynamic, 1>
|
|
RBFFD<RBFType, vec_t, scale_t, solver_t>::getShapeFromRhs(
|
|
const Eigen::MatrixBase<Derived>& Lb) const {
|
|
return solver_.solve(Lb).head(support_.size());
|
|
}
|
|
|
|
template <class RBFType, class vec_t, class scale_t, class solver_t>
|
|
template <typename Derived>
|
|
RBFInterpolant<RBFType, vec_t>
|
|
RBFFD<RBFType, vec_t, scale_t, solver_t>::getApproximant(const vector_t& point,
|
|
const std::vector<vector_t>& support, const Eigen::MatrixBase<Derived>& values) const {
|
|
int n = support.size();
|
|
assert_msg(values.size() == n, "Number of given values %d must be equal to support size %d.",
|
|
values.size(), n);
|
|
double scale = scale_t::scale(point, support);
|
|
// Local scaled support
|
|
std::vector<vec_t> local_support(n);
|
|
for (int i = 0; i < n; ++i) {
|
|
local_support[i] = (support[i] - point) / scale;
|
|
}
|
|
Eigen::Matrix<typename vec_t::scalar_t, Eigen::Dynamic, Eigen::Dynamic> M =
|
|
getMatrix(local_support);
|
|
solver_t solver;
|
|
solver.compute(M);
|
|
Eigen::Matrix<scalar_t, Eigen::Dynamic, 1> rhs(n + mon_.size());
|
|
rhs.head(n) = values;
|
|
rhs.tail(mon_.size()).setZero();
|
|
Eigen::Matrix<scalar_t, Eigen::Dynamic, 1> coeff = solver.solve(rhs);
|
|
return RBFInterpolant<rbf_t, vec_t>(rbf_, mon_, point, support, scale, coeff);
|
|
}
|
|
/// @endcond
|
|
|
|
} // namespace mm
|
|
|
|
#endif // MEDUSA_BITS_APPROXIMATIONS_RBFFD_HPP_
|
|
|