libMesh
meshfree_interpolation.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 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 // C++ includes
21 #include <iomanip>
22 
23 // Local includes
24 #include "libmesh/point.h"
25 #include "libmesh/meshfree_interpolation.h"
26 #include "libmesh/libmesh_logging.h"
27 #include "libmesh/parallel.h"
28 #include "libmesh/parallel_algebra.h"
29 #include "libmesh/auto_ptr.h" // libmesh_make_unique
30 
31 namespace libMesh
32 {
33 
34 //--------------------------------------------------------------------------------
35 // MeshfreeInterpolation methods
36 void MeshfreeInterpolation::print_info (std::ostream & os) const
37 {
38  os << "MeshfreeInterpolation"
39  << "\n n_source_points()=" << _src_pts.size()
40  << "\n n_field_variables()=" << this->n_field_variables()
41  << "\n";
42 
43  if (this->n_field_variables())
44  {
45  os << " variables = ";
46  for (unsigned int v=0; v<this->n_field_variables(); v++)
47  os << _names[v] << " ";
48  os << std::endl;
49  }
50 
51 }
52 
53 
54 
55 std::ostream & operator << (std::ostream & os, const MeshfreeInterpolation & mfi)
56 {
57  mfi.print_info(os);
58  return os;
59 }
60 
61 
62 
64 {
65  _names.clear();
66  _src_pts.clear();
67  _src_vals.clear();
68 }
69 
70 
71 
72 void MeshfreeInterpolation::add_field_data (const std::vector<std::string> & field_names,
73  const std::vector<Point> & pts,
74  const std::vector<Number> & vals)
75 {
76  libmesh_experimental();
77  libmesh_assert_equal_to (field_names.size()*pts.size(), vals.size());
78 
79  // If we already have field variables, we assume we are appending.
80  // that means the names and ordering better be identical!
81  if (!_names.empty())
82  {
83  if (_names.size() != field_names.size())
84  libmesh_error_msg("ERROR: when adding field data to an existing list the \nvariable list must be the same!");
85 
86  for (std::size_t v=0; v<_names.size(); v++)
87  if (_names[v] != field_names[v])
88  libmesh_error_msg("ERROR: when adding field data to an existing list the \nvariable list must be the same!");
89  }
90 
91  // otherwise copy the names
92  else
93  _names = field_names;
94 
95  // append the data
96  _src_pts.insert (_src_pts.end(),
97  pts.begin(),
98  pts.end());
99 
100  _src_vals.insert (_src_vals.end(),
101  vals.begin(),
102  vals.end());
103 
104  libmesh_assert_equal_to (_src_vals.size(),
105  _src_pts.size()*this->n_field_variables());
106 }
107 
108 
109 
111 {
113  {
114  case SYNC_SOURCES:
115  this->gather_remote_data();
116  break;
117 
118  case INVALID_STRATEGY:
119  libmesh_error_msg("Invalid _parallelization_strategy = " << _parallelization_strategy);
120 
121  default:
122  // no preparation required for other strategies
123  break;
124  }
125 }
126 
127 
128 
130 {
131 #ifndef LIBMESH_HAVE_MPI
132 
133  // no MPI -- no-op
134  return;
135 
136 #else
137 
138  // This function must be run on all processors at once
139  parallel_object_only();
140 
141  LOG_SCOPE ("gather_remote_data()", "MeshfreeInterpolation");
142 
143  this->comm().allgather(_src_pts);
144  this->comm().allgather(_src_vals);
145 
146 #endif // LIBMESH_HAVE_MPI
147 }
148 
149 
150 
151 //--------------------------------------------------------------------------------
152 // InverseDistanceInterpolation methods
153 template <unsigned int KDDim>
155 {
156 #ifdef LIBMESH_HAVE_NANOFLANN
157 
158  LOG_SCOPE ("construct_kd_tree()", "InverseDistanceInterpolation<>");
159 
160  // Initialize underlying KD tree
161  if (_kd_tree.get() == nullptr)
162  _kd_tree = libmesh_make_unique<kd_tree_t>
163  (KDDim,
164  _point_list_adaptor,
165  nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */));
166 
167  libmesh_assert (_kd_tree.get() != nullptr);
168 
169  _kd_tree->buildIndex();
170 #endif
171 }
172 
173 
174 
175 template <unsigned int KDDim>
177 {
178 #ifdef LIBMESH_HAVE_NANOFLANN
179  // Delete the KD Tree and start fresh
180  if (_kd_tree.get())
181  _kd_tree.reset (nullptr);
182 #endif
183 
184  // Call base class clear method
186 }
187 
188 
189 
190 template <unsigned int KDDim>
191 void InverseDistanceInterpolation<KDDim>::interpolate_field_data (const std::vector<std::string> & field_names,
192  const std::vector<Point> & tgt_pts,
193  std::vector<Number> & tgt_vals) const
194 {
195  libmesh_experimental();
196 
197  // forcibly initialize, if needed
198 #ifdef LIBMESH_HAVE_NANOFLANN
199  if (_kd_tree.get() == nullptr)
201 #endif
202 
203  LOG_SCOPE ("interpolate_field_data()", "InverseDistanceInterpolation<>");
204 
205  libmesh_assert_equal_to (field_names.size(), this->n_field_variables());
206 
207  // If we already have field variables, we assume we are appending.
208  // that means the names and ordering better be identical!
209  if (_names.size() != field_names.size())
210  libmesh_error_msg("ERROR: when adding field data to an existing list the \nvariable list must be the same!");
211 
212  for (std::size_t v=0; v<_names.size(); v++)
213  if (_names[v] != field_names[v])
214  libmesh_error_msg("ERROR: when adding field data to an existing list the \nvariable list must be the same!");
215 
216  tgt_vals.resize (tgt_pts.size()*this->n_field_variables());
217 
218 #ifdef LIBMESH_HAVE_NANOFLANN
219  {
220  std::vector<Number>::iterator out_it = tgt_vals.begin();
221 
222  const size_t num_results = std::min((size_t) _n_interp_pts, _src_pts.size());
223 
224  std::vector<size_t> ret_index(num_results);
225  std::vector<Real> ret_dist_sqr(num_results);
226 
227  for (const auto & tgt : tgt_pts)
228  {
229  const Real query_pt[] = { tgt(0), tgt(1), tgt(2) };
230 
231  _kd_tree->knnSearch(query_pt, num_results, ret_index.data(), ret_dist_sqr.data());
232 
233  this->interpolate (tgt, ret_index, ret_dist_sqr, out_it);
234 
235  // libMesh::out << "knnSearch(): num_results=" << num_results << "\n";
236  // for (size_t i=0;i<num_results;i++)
237  // libMesh::out << "idx[" << i << "]="
238  // << std::setw(6) << ret_index[i]
239  // << "\t dist["<< i << "]=" << ret_dist_sqr[i]
240  // << "\t val[" << std::setw(6) << ret_index[i] << "]=" << _src_vals[ret_index[i]]
241  // << std::endl;
242  // libMesh::out << "\n";
243 
244  // libMesh::out << "ival=" << _vals[0] << '\n';
245  }
246  }
247 #else
248 
249  libmesh_error_msg("ERROR: This functionality requires the library to be configured with nanoflann support!");
250 
251 #endif
252 }
253 
254 template <unsigned int KDDim>
256  const std::vector<size_t> & src_indices,
257  const std::vector<Real> & src_dist_sqr,
258  std::vector<Number>::iterator & out_it) const
259 {
260  // We explicitly assume that the input source points are sorted from closest to
261  // farthest. assert that assumption in DEBUG mode.
262 #ifdef DEBUG
263  if (!src_dist_sqr.empty())
264  {
265  Real min_dist = src_dist_sqr.front();
266 
267  for (auto i : src_dist_sqr)
268  {
269  if (i < min_dist)
270  libmesh_error_msg(i << " was less than min_dist = " << min_dist);
271 
272  min_dist = i;
273  }
274  }
275 #endif
276 
277 
278  libmesh_assert_equal_to (src_dist_sqr.size(), src_indices.size());
279 
280 
281  // Compute the interpolation weights & interpolated value
282  const unsigned int n_fv = this->n_field_variables();
283  _vals.resize(n_fv); std::fill (_vals.begin(), _vals.end(), Number(0.));
284 
285  Real tot_weight = 0.;
286 
287  std::vector<Real>::const_iterator src_dist_sqr_it=src_dist_sqr.begin();
288  std::vector<size_t>::const_iterator src_idx_it=src_indices.begin();
289 
290  // Loop over source points
291  while ((src_dist_sqr_it != src_dist_sqr.end()) &&
292  (src_idx_it != src_indices.end()))
293  {
294  libmesh_assert_greater_equal (*src_dist_sqr_it, 0.);
295 
296  const Real
297  dist_sq = std::max(*src_dist_sqr_it, std::numeric_limits<Real>::epsilon()),
298  weight = 1./std::pow(dist_sq, _half_power);
299 
300  tot_weight += weight;
301 
302  const std::size_t src_idx = *src_idx_it;
303 
304  // loop over field variables
305  for (unsigned int v=0; v<n_fv; v++)
306  {
307  libmesh_assert_less (src_idx*n_fv+v, _src_vals.size());
308  _vals[v] += _src_vals[src_idx*n_fv+v]*weight;
309  }
310 
311  ++src_dist_sqr_it;
312  ++src_idx_it;
313  }
314 
315  // don't forget normalizing term & set the output buffer!
316  for (unsigned int v=0; v<n_fv; v++, ++out_it)
317  {
318  _vals[v] /= tot_weight;
319 
320  *out_it = _vals[v];
321  }
322 }
323 
324 
325 
326 // ------------------------------------------------------------
327 // Explicit Instantiations
328 template class InverseDistanceInterpolation<1>;
329 template class InverseDistanceInterpolation<2>;
330 template class InverseDistanceInterpolation<3>;
331 
332 } // namespace libMesh
libMesh::MeshfreeInterpolation::_names
std::vector< std::string > _names
Definition: meshfree_interpolation.h:168
libMesh::Number
Real Number
Definition: libmesh_common.h:195
libMesh::InverseDistanceInterpolation::clear
virtual void clear() override
Clears all internal data structures and restores to a pristine state.
Definition: meshfree_interpolation.C:176
libMesh::MeshfreeInterpolation::prepare_for_use
virtual void prepare_for_use()
Prepares data structures for use.
Definition: meshfree_interpolation.C:110
libMesh::MeshfreeInterpolation::gather_remote_data
virtual void gather_remote_data()
Gathers source points and values that have been added on other processors.
Definition: meshfree_interpolation.C:129
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::MeshfreeInterpolation::_parallelization_strategy
ParallelizationStrategy _parallelization_strategy
Definition: meshfree_interpolation.h:167
libMesh::operator<<
std::ostream & operator<<(std::ostream &os, const OrderWrapper &order)
Overload stream operators.
Definition: fe_type.h:164
libMesh::MeshfreeInterpolation::n_field_variables
unsigned int n_field_variables() const
The number of field variables.
Definition: meshfree_interpolation.h:103
libMesh::ParallelObject::comm
const Parallel::Communicator & comm() const
Definition: parallel_object.h:94
libMesh::MeshfreeInterpolation::_src_vals
std::vector< Number > _src_vals
Definition: meshfree_interpolation.h:170
libMesh::MeshfreeInterpolation::clear
virtual void clear()
Clears all internal data structures and restores to a pristine state.
Definition: meshfree_interpolation.C:63
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
std::pow
double pow(double a, int b)
Definition: libmesh_augment_std_namespace.h:58
libMesh::InverseDistanceInterpolation::construct_kd_tree
virtual void construct_kd_tree()
Build & initialize the KD tree, if needed.
Definition: meshfree_interpolation.C:154
libMesh::InverseDistanceInterpolation
Inverse distance interpolation.
Definition: meshfree_interpolation.h:179
libMesh::MeshfreeInterpolation::INVALID_STRATEGY
Definition: meshfree_interpolation.h:73
libMesh::MeshfreeInterpolation::_src_pts
std::vector< Point > _src_pts
Definition: meshfree_interpolation.h:169
libMesh::MeshfreeInterpolation::print_info
void print_info(std::ostream &os=libMesh::out) const
Prints information about this object, by default to libMesh::out.
Definition: meshfree_interpolation.C:36
libMesh::MeshfreeInterpolation::SYNC_SOURCES
Definition: meshfree_interpolation.h:72
libMesh::MeshfreeInterpolation::add_field_data
virtual void add_field_data(const std::vector< std::string > &field_names, const std::vector< Point > &pts, const std::vector< Number > &vals)
Sets source data at specified points.
Definition: meshfree_interpolation.C:72
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::InverseDistanceInterpolation::interpolate
virtual void interpolate(const Point &pt, const std::vector< size_t > &src_indices, const std::vector< Real > &src_dist_sqr, std::vector< Number >::iterator &out_it) const
Performs inverse distance interpolation at the input point from the specified points.
Definition: meshfree_interpolation.C:255
libMesh::InverseDistanceInterpolation::interpolate_field_data
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.
Definition: meshfree_interpolation.C:191
libMesh::MeshTools::weight
dof_id_type weight(const MeshBase &mesh, const processor_id_type pid)
Definition: mesh_tools.C:236
libMesh::MeshfreeInterpolation
Base class to support various mesh-free interpolation methods.
Definition: meshfree_interpolation.h:56