15 #include "libmesh/int_range.h" 16 #include "libmesh/nanoflann.hpp" 46 ValueCache(std::size_t in_dim, std::size_t max_leaf_size = 10);
49 ValueCache(
const std::string & file_name, std::size_t in_dim, std::size_t max_leaf_size = 10);
55 void insert(
const std::vector<Real> & in_val,
const T & out_val);
58 std::tuple<const std::vector<Real> &,
const T &,
Real>
62 std::vector<std::tuple<const std::vector<Real> &,
const T &,
Real>>
63 getNeighbors(
const std::vector<Real> & in_val,
const std::size_t k);
83 nanoflann::KDTreeSingleIndexDynamicAdaptor<nanoflann::L2_Simple_Adaptor<Real, ValueCache<T>>,
99 std::vector<std::pair<Real, Real>>
_bbox;
101 friend void dataStore<T>(std::ostream & stream,
ValueCache<T> & c,
void * context);
102 friend void dataLoad<T>(std::istream & stream,
ValueCache<T> & c,
void * context);
105 template <
typename T>
107 : _kd_tree(nullptr), _in_dim(in_dim), _max_leaf_size(max_leaf_size), _max_subtrees(100)
111 template <
typename T>
114 std::size_t max_leaf_size)
131 template <
typename T>
135 if (_persistent_storage_file.has_value())
137 std::ofstream out_file(_persistent_storage_file->c_str());
139 mooseWarning(
"Failed to open '", *_persistent_storage_file,
"' for writing.");
144 template <
typename T>
148 mooseAssert(in_val.size() == _in_dim,
"Key dimensions do not match cache dimensions");
151 _location_data.emplace_back(in_val, out_val);
157 _bbox.resize(_in_dim);
159 _bbox[i] = {in_val[i], in_val[i]};
163 _bbox[i] = {
std::min(_bbox[i].first, in_val[i]),
std::max(_bbox[i].second, in_val[i])};
166 if (_kd_tree && _kd_tree->getAllIndices().size() > _max_subtrees)
172 _kd_tree = std::make_unique<KdTreeT>(_in_dim, *
this, _max_leaf_size);
173 mooseAssert(_kd_tree !=
nullptr,
"KDTree was not properly initialized.");
176 _kd_tree->addPoints(
id,
id);
182 template <
typename T>
183 std::tuple<const std::vector<Real> &,
const T &,
Real>
187 if (_location_data.empty())
188 throw std::runtime_error(
"Attempting to retrieve a neighbor from an empty ValueCache.");
191 nanoflann::KNNResultSet<Real> result_set(1);
192 std::size_t return_index;
196 result_set.init(&return_index, &
distance);
197 _kd_tree->findNeighbors(result_set, in_val.data());
199 const auto & [location, data] = _location_data[return_index];
200 return {std::cref(location), std::cref(data),
distance};
207 template <
typename T>
208 std::vector<std::tuple<const std::vector<Real> &,
const T &,
Real>>
212 if (_location_data.empty())
216 nanoflann::KNNResultSet<Real> result_set(
std::min(k, size()));
217 std::vector<std::size_t> return_indices(
std::min(k, size()));
218 std::vector<Real> distances(
std::min(k, size()));
221 result_set.init(return_indices.data(), distances.data());
222 _kd_tree->findNeighbors(result_set, in_val.data());
225 std::vector<std::tuple<const std::vector<Real> &,
const T &,
Real>> nearest_neighbors;
228 const auto & [location, data] = _location_data[return_indices[i]];
229 nearest_neighbors.emplace_back(std::cref(location), std::cref(data), distances[i]);
231 return nearest_neighbors;
234 template <
typename T>
238 return kdtree_get_point_count();
241 template <
typename T>
245 _location_data.clear();
249 template <
typename T>
253 if (_location_data.empty())
257 _bbox.resize(_in_dim);
258 const auto & location0 = _location_data[0].first;
260 _bbox[i] = {location0[i], location0[i]};
262 for (
const auto & pair : _location_data)
264 const auto & location = pair.first;
266 _bbox[i] = {
std::min(_bbox[i].first, location[i]),
std::max(_bbox[i].second, location[i])};
270 _kd_tree = std::make_unique<KdTreeT>(_in_dim, *
this, _max_leaf_size);
271 mooseAssert(_kd_tree !=
nullptr,
"KDTree was not properly initialized.");
274 template <
typename T>
278 return _location_data.size();
281 template <
typename T>
285 return _location_data[
idx].first[
dim];
288 template <
typename T>
289 template <
class BBOX>
293 if (_location_data.empty())
298 bb[i] = {_bbox[i].first, _bbox[i].second};
302 template <
typename T>
309 template <
typename T>
std::tuple< const std::vector< Real > &, const T &, Real > getNeighbor(const std::vector< Real > &in_val)
get a single neighbor of in_val along with stored values and distances
bool kdtree_get_bbox(BBOX &bb) const
friend void dataLoad(std::istream &stream, ValueCache< T > &c, void *context)
std::size_t size()
return the number of cache entries
std::optional< std::string > _persistent_storage_file
file name for persistent store/restore of the cache
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
ValueCache is a generic helper template to implement an unstructured data cache, where arbitrary resu...
ValueCache(std::size_t in_dim, std::size_t max_leaf_size=10)
Construct a ValueCache with indices in in_dim dimensions.
Real distance(const Point &p)
const std::size_t _in_dim
auto max(const L &left, const R &right)
void storeHelper(std::ostream &stream, P &data, void *context)
Scalar helper routine.
nanoflann::KDTreeSingleIndexDynamicAdaptor< nanoflann::L2_Simple_Adaptor< Real, ValueCache< T > >, ValueCache< T >, -1, std::size_t > KdTreeT
std::vector< std::tuple< const std::vector< Real > &, const T &, Real > > getNeighbors(const std::vector< Real > &in_val, const std::size_t k)
get a list of up to k neighbors of in_val along with stored values and distances
void insert(const std::vector< Real > &in_val, const T &out_val)
insert a new value out_value at the position in_val
bool checkFileReadable(const std::string &filename, bool check_line_endings=false, bool throw_on_unreadable=true, bool check_for_git_lfs_pointer=true)
Checks to see if a file is readable (exists and permissions)
void clear()
remove all data from the cache
const std::size_t _max_subtrees
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::size_t kdtree_get_point_count() const
Nanoflann interface functions.
std::vector< std::pair< Real, Real > > _bbox
bounding box (updated upon insertion)
Real kdtree_get_pt(const std::size_t idx, const std::size_t dim) const
std::unique_ptr< KdTreeT > _kd_tree
const std::size_t _max_leaf_size
IntRange< T > make_range(T beg, T end)
void rebuildTree()
rebuild the kd-tree from scratch and update the bounding box
~ValueCache()
Object destructor. If the cache was constructed with a file name, it gets written here...
void dataStore(std::ostream &stream, ValueCache< T > &c, void *context)
void dataLoad(std::istream &stream, ValueCache< T > &c, void *context)
auto min(const L &left, const R &right)
void loadHelper(std::istream &stream, P &data, void *context)
Scalar helper routine.
auto index_range(const T &sizable)
std::vector< std::pair< std::vector< Real >, T > > _location_data