libMesh
radial_basis_interpolation.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2024 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 // Local includes
21 #include "libmesh/radial_basis_interpolation.h"
22 
23 #include "libmesh/eigen_core_support.h"
24 #include "libmesh/int_range.h"
25 #include "libmesh/libmesh_logging.h"
26 #include "libmesh/mesh_tools.h" // BoundingBox
27 #include "libmesh/radial_basis_functions.h"
28 
29 #ifdef LIBMESH_HAVE_EIGEN
30 # include "libmesh/ignore_warnings.h"
31 # include <Eigen/Dense>
32 # include "libmesh/restore_warnings.h"
33 #endif
34 
35 // C++ includes
36 #include <iomanip>
37 
38 
39 namespace libMesh
40 {
41 //--------------------------------------------------------------------------------
42 // RadialBasisInterpolation methods
43 template <unsigned int KDDim, class RBF>
45 {
46  // Call base class clear method
48 }
49 
50 
51 
52 template <unsigned int KDDim, class RBF>
54 {
55  // Call base class methods for prep
58 
59 #ifndef LIBMESH_HAVE_EIGEN
60 
61  libmesh_error_msg("ERROR: this functionality presently requires Eigen!");
62 
63 #else
64  LOG_SCOPE ("prepare_for_use()", "RadialBasisInterpolation<>");
65 
66  // Construct a bounding box for our source points
67  _src_bbox.invalidate();
68 
69  const std::size_t n_src_pts = this->_src_pts.size();
70  const unsigned int n_vars = this->n_field_variables();
71  libmesh_assert_equal_to (this->_src_vals.size(), n_src_pts*this->n_field_variables());
72 
73  {
74  LOG_SCOPE ("prepare_for_use():bbox", "RadialBasisInterpolation<>");
75 
76  Point
77  &p_min(_src_bbox.min()),
78  &p_max(_src_bbox.max());
79 
80  for (std::size_t p=0; p<n_src_pts; p++)
81  {
82  const Point & p_src(_src_pts[p]);
83 
84  for (unsigned int d=0; d<LIBMESH_DIM; d++)
85  {
86  p_min(d) = std::min(p_min(d), p_src(d));
87  p_max(d) = std::max(p_max(d), p_src(d));
88  }
89  }
90  }
91 
92  // Debugging code
93  // libMesh::out << "bounding box is \n"
94  // << _src_bbox.min() << '\n'
95  // << _src_bbox.max() << std::endl;
96 
97 
98  // Construct the Radial Basis Function, giving it the size of the domain
99  if (_r_override < 0)
100  _r_bbox = (_src_bbox.max() - _src_bbox.min()).norm();
101  else
102  _r_bbox = _r_override;
103 
104  RBF rbf(_r_bbox);
105 
106  // libMesh::out << "bounding box is \n"
107  // << _src_bbox.min() << '\n'
108  // << _src_bbox.max() << '\n'
109  // << "r_bbox = " << _r_bbox << '\n'
110  // << "rbf(r_bbox/2) = " << rbf(_r_bbox/2) << std::endl;
111 
112 
113  // Construct the projection Matrix
114  typedef Eigen::Matrix<Number, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor> DynamicMatrix;
115  //typedef Eigen::Matrix<Number, Eigen::Dynamic, 1, Eigen::ColMajor> DynamicVector;
116 
117  DynamicMatrix A(n_src_pts, n_src_pts), x(n_src_pts,n_vars), b(n_src_pts,n_vars);
118 
119  {
120  LOG_SCOPE ("prepare_for_use():mat", "RadialBasisInterpolation<>");
121 
122  for (std::size_t i=0; i<n_src_pts; i++)
123  {
124  const Point & x_i (_src_pts[i]);
125 
126  // Diagonal
127  A(i,i) = rbf(0.);
128 
129  for (std::size_t j=i+1; j<n_src_pts; j++)
130  {
131  const Point & x_j (_src_pts[j]);
132 
133  const Real r_ij = (x_j - x_i).norm();
134 
135  A(i,j) = A(j,i) = rbf(r_ij);
136  }
137 
138  // set source data
139  for (unsigned int var=0; var<n_vars; var++)
140  b(i,var) = _src_vals[i*n_vars + var];
141  }
142  }
143 
144 
145  {
146  LOG_SCOPE ("prepare_for_use():solve", "RadialBasisInterpolation<>");
147 
148  // Solve the linear system
149  x = A.ldlt().solve(b);
150  //x = A.fullPivLu().solve(b);
151  }
152 
153  // save the weights for each variable
154  _weights.resize (this->_src_vals.size());
155 
156  for (std::size_t i=0; i<n_src_pts; i++)
157  for (unsigned int var=0; var<n_vars; var++)
158  _weights[i*n_vars + var] = x(i,var);
159 
160 #endif
161 
162 }
163 
164 
165 
166 template <unsigned int KDDim, class RBF>
167 void RadialBasisInterpolation<KDDim,RBF>::interpolate_field_data (const std::vector<std::string> & field_names,
168  const std::vector<Point> & tgt_pts,
169  std::vector<Number> & tgt_vals) const
170 {
171  LOG_SCOPE ("interpolate_field_data()", "RadialBasisInterpolation<>");
172 
173  libmesh_experimental();
174 
175  const unsigned int
176  n_vars = this->n_field_variables();
177 
178  const std::size_t
179  n_src_pts = this->_src_pts.size(),
180  n_tgt_pts = tgt_pts.size();
181 
182  libmesh_assert_equal_to (_weights.size(), this->_src_vals.size());
183  libmesh_assert_equal_to (field_names.size(), this->n_field_variables());
184 
185  // If we already have field variables, we assume we are appending.
186  // that means the names and ordering better be identical!
187  libmesh_error_msg_if(this->_names.size() != field_names.size(),
188  "ERROR: when adding field data to an existing list the \nvariable list must be the same!");
189 
190  for (auto v : index_range(this->_names))
191  libmesh_error_msg_if(_names[v] != field_names[v],
192  "ERROR: when adding field data to an existing list the \nvariable list must be the same!");
193 
194 
195  RBF rbf(_r_bbox);
196 
197  tgt_vals.resize (n_tgt_pts*n_vars); std::fill (tgt_vals.begin(), tgt_vals.end(), Number(0.));
198 
199  for (std::size_t tgt=0; tgt<n_tgt_pts; tgt++)
200  {
201  const Point & p (tgt_pts[tgt]);
202 
203  for (std::size_t i=0; i<n_src_pts; i++)
204  {
205  const Point & x_i(_src_pts[i]);
206  const Real
207  r_i = (p - x_i).norm(),
208  phi_i = rbf(r_i);
209 
210  for (unsigned int var=0; var<n_vars; var++)
211  tgt_vals[tgt*n_vars + var] += _weights[i*n_vars + var]*phi_i;
212  }
213  }
214 }
215 
216 
217 
218 // ------------------------------------------------------------
219 // Explicit Instantiations
220 template class LIBMESH_EXPORT RadialBasisInterpolation<3, WendlandRBF<3,0>>;
221 template class LIBMESH_EXPORT RadialBasisInterpolation<3, WendlandRBF<3,2>>;
222 template class LIBMESH_EXPORT RadialBasisInterpolation<3, WendlandRBF<3,4>>;
223 template class LIBMESH_EXPORT RadialBasisInterpolation<3, WendlandRBF<3,8>>;
224 
225 } // namespace libMesh
Radial Basis Function interpolation.
virtual void prepare_for_use() override
Prepares data structures for use.
virtual void interpolate_field_data(const std::vector< std::string > &field_names, const std::vector< Point > &tgt_pts, std::vector< Number > &tgt_vals) const override
Interpolate source data at target points.
The libMesh namespace provides an interface to certain functionality in the library.
unsigned int n_vars
virtual void construct_kd_tree()
Build & initialize the KD tree, if needed.
virtual void clear() override
Clears all internal data structures and restores to a pristine state.
virtual void clear() override
Clears all internal data structures and restores to a pristine state.
auto norm(const T &a) -> decltype(std::abs(a))
Definition: tensor_tools.h:74
virtual void prepare_for_use()
Prepares data structures for use.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:111