search_kdtree_nanoflann.h
Go to the documentation of this file.
1 /*
2 This file is part of the Ristra portage project.
3 Please see the license file at the root of this repository, or at:
4  https://github.com/laristra/portage/blob/master/LICENSE
5 */
6 
7 
8 #ifndef SEARCH_KDTREE_NANOFLANN_H
9 #define SEARCH_KDTREE_NANOFLANN_H
10 
11 #include <memory>
12 #include <vector>
13 #include <utility>
14 #include <cmath>
15 
16 #ifdef HAVE_NANOFLANN
17 #include "nanoflann.hpp" // KDTree search package NanoFlann
18 
20 
21 #include "portage/accumulate/accumulate.h" // For swarm::WeightCenter
22 // // Hope we can get rid of it
23 
24 using Wonton::Point;
25 
26 namespace Portage { namespace Meshfree {
27 
28 template <size_t D, class SwarmType>
29 class SwarmNanoflann {
30  public:
31  explicit SwarmNanoflann(SwarmType const& swarm) : swarm_(swarm) {}
32 
33  // Nanoflann + C++ is requiring us to provide the assignment operator
34  SwarmNanoflann & operator=(SwarmNanoflann const& inswarm) {
35  if (this != &inswarm)
36  swarm_ = inswarm.swarm_;
37  return *this;
38  }
39 
40  //
41  // METHODS REQUIRED BY NANOFLANN
42  //
43 
44  // How many points in the swarm?
45  inline size_t kdtree_get_point_count() const {
46  return swarm_.num_particles(Entity_type::ALL);
47  }
48 
49  // Square of Euclidean distance between query point and a point in the swarm
50  inline double kdtree_distance(double const *p1, size_t const idx, size_t /* size */) const {
51  double dist2 = 0.0;
52  Point<D> const& p2 = swarm_.get_particle_coordinates(idx);
53  for (int i = 0; i < D; i++)
54  dist2 += (p1[i]-p2[i])*(p1[i]-p2[i]);
55  return dist2;
56  }
57 
58  // get the d'th coordinate of a point
59  inline double kdtree_get_pt(size_t const idx, int d) const {
60  assert(d >= 0 && d < D);
61  Point<D> const& p = swarm_.get_particle_coordinates(idx);
62  return p[d];
63  }
64 
65  // Optional bounding-box computation; return false to default to a
66  // standard bbox computation loop
67  template<class BBOX>
68  bool kdtree_get_bbox(BBOX& /*bb*/) const {return false;}
69 
70 
71  //
72  // MORE EFFICIENT METHOD FOR GETTING POINT COORDINATES FOR OUR USE
73  //
74 
75  Point<D> get_point(size_t const idx) const {
76  return swarm_.get_particle_coordinates(idx);
77  }
78 
79  private:
80  SwarmType const& swarm_;
81 
82 }; // class SwarmNanoflann
83 
84 
85 
92 template <int D, class SourceSwarmType, class TargetSwarmType>
93 class Search_KDTree_Nanoflann {
94  public:
95 
96  // Particular kd-tree type based on nanoflann's offerings
97  typedef
98  nanoflann::KDTreeSingleIndexAdaptor<
99  nanoflann::L2_Simple_Adaptor<double, SwarmNanoflann<D, SourceSwarmType>>,
100  SwarmNanoflann<D, SourceSwarmType>,
101  D
102  > kdtree_t;
103 
105  Search_KDTree_Nanoflann() = delete;
106 
107  // Constructor with swarms and extents
118  Search_KDTree_Nanoflann(SourceSwarmType const& source_swarm,
119  TargetSwarmType const& target_swarm,
120  std::shared_ptr<std::vector<Point<D>>> source_extents,
121  std::shared_ptr<std::vector<Point<D>>> target_extents,
122  WeightCenter center = Gather) :
123  sourceSwarm_(source_swarm), targetSwarm_(target_swarm) {
124 
125  assert(center == Gather); // Our KDTree is built on source points
126 
127  int ntgt = target_swarm.num_owned_particles();
128  search_radii_.resize(ntgt);
129  for (int i = 0; i < ntgt; i++) {
130  double len = 0.0;
131  for (int d = 0; d < D; d++)
132  len += (*target_extents)[i][d]*(*target_extents)[i][d];
133  search_radii_[i] = sqrt(len);
134  }
135 
136  kdtree_ = std::make_shared<kdtree_t>(D, sourceSwarm_,
137  nanoflann::KDTreeSingleIndexAdaptorParams(10 /* maxleaf */));
138  kdtree_->buildIndex();
139  }
140 
150  std::vector<unsigned int> operator() (size_t pointId) const;
151 
152  private:
153  SwarmNanoflann<D, SourceSwarmType> const sourceSwarm_;
154  SwarmNanoflann<D, TargetSwarmType> const targetSwarm_;
155  std::vector<double> search_radii_;
156  std::shared_ptr<kdtree_t> kdtree_ = nullptr;
157 }; // class Search_KDTree_Nanoflann
158 
159 
160 template<int D, class SourceSwarmType, class TargetSwarmType>
161 std::vector<int>
162 Search_KDTree_Nanoflann<D, SourceSwarmType, TargetSwarmType>::operator() (size_t pointId) const {
163  std::vector<int> candidates;
164 
165  // find coordinates of target point
166  Point<D> tpcoord = targetSwarm_.get_point(pointId);
167 
168  double p[D];
169  for (int i = 0; i < D; i++)
170  p[i] = tpcoord[i];
171 
172  std::vector<std::pair<size_t, double>> matches;
173 
174  nanoflann::SearchParams params {};
175  // params.sorted = false; // one could make this true
176 
177  double radius = search_radii_[pointId];
178  const size_t nMatches = kdtree_->radiusSearch(p, radius, matches, params);
179 
180  for (auto const &idx_dist_pair : matches)
181  candidates.push_back(static_cast<int>(idx_dist_pair.first));
182 
183  return candidates;
184 } // Search_KDTree_Nanoflann::operator()
185 
186 }} // namespace Portage::Meshfree
187 
188 #endif // HAVE_NANOFLANN
189 
190 
191 #endif // SEARCH_KDTREE_NANOFLANN_H
std::vector< T > vector
Definition: portage.h:238
Definition: coredriver.h:42