OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
closest_point.hpp
Go to the documentation of this file.
1 
17 #ifndef __CLOSEST_POINT_HPP__
18 #define __CLOSEST_POINT_HPP__
19 
20 #include "algoim_hocp.hpp"
21 
22 // Width of extra padding around each grid patch needed to correctly construct kDTree in Algoim.
23 constexpr int algoim_padding = 4;
24 
35 template<typename grid_type, typename grid_key_type, unsigned int dim, size_t wrapping_field>
37 {
38  grid_type &gd;
39  int patch_id;
40  AlgoimWrapper(grid_type& ls_grid, const int pid) : gd(ls_grid), patch_id(pid) {}
41 
43  double operator() (const blitz::TinyVector<int,dim> idx) const
44  {
45  long int local_key[dim];
46 
47  auto ghost_offset = gd.getLocalGridsInfo().get(patch_id).Dbox.getKP1();
48 
49  for (int d = 0; d < dim; ++d)
50  local_key[d] = idx(d) - algoim_padding;
51 
52  // Generate OpenFPM grid_key object from local grid indices
53  grid_key_type grid_key(patch_id, grid_key_dx<dim> (local_key) + ghost_offset);
54 
55  return gd.template get<wrapping_field>(grid_key);
56  }
57 };
58 
71 template<typename grid_type, typename grid_key_type, unsigned int poly_order, size_t phi_field, size_t cp_field>
72 void estimateClosestPoint(grid_type &gd, const double nb_gamma)
73 {
74  const unsigned int dim = grid_type::dims;
75  // Stencil polynomial type
76  using Poly = typename Algoim::StencilPoly<dim, poly_order>::T_Poly;
77 
78  // Grid spacing along each dimension
79  blitz::TinyVector<double,dim> dx;
80  for(int d = 0; d < dim; ++d)
81  dx(d) = gd.spacing(d);
82 
83  auto &patches = gd.getLocalGridsInfo();
84 
85  grid_key_dx<dim> p_lo;
86  grid_key_dx<dim> p_hi;
87 
88  for(int i = 0; i < patches.size();i++)
89  {
90  for(int d = 0; d < dim; ++d)
91  {
92  p_lo.set_d(d, patches.get(i).Dbox.getLow(d) + patches.get(i).origin[d]);
93  p_hi.set_d(d, patches.get(i).Dbox.getHigh(d) + patches.get(i).origin[d]);
94  }
95 
97 
98  // Find all cells containing the interface and construct the high-order polynomials
99  std::vector<Algoim::detail::CellPoly<dim,Poly>> cells;
100 
101  blitz::TinyVector<int,dim> ext;
102 
103  for(int d = 0; d < dim; ++d)
104  ext(d) = static_cast<int>(p_hi.get(d) - p_lo.get(d) + 1 + 2*algoim_padding);
105 
106  Algoim::detail::createCellPolynomials(ext, phiwrap, dx, false, cells);
107 
108  std::vector<blitz::TinyVector<double,dim>> points;
109  std::vector<int> pointcells;
110  Algoim::detail::samplePolynomials<dim,Poly>(cells, 2, dx, 0.0, points, pointcells);
111 
112  Algoim::KDTree<double,dim> kdtree(points);
113 
114  // Pass everything to the closest point computation engine
115  Algoim::ComputeHighOrderCP<dim,Poly> hocp(nb_gamma < std::numeric_limits<double>::max() ? nb_gamma*nb_gamma : std::numeric_limits<double>::max(), // squared bandradius
116  0.5*blitz::max(dx), // amount that each polynomial overlaps / size of the bounding ball in Newton's method
117  Algoim::sqr(std::max(1.0e-14, std::pow(blitz::max(dx), Poly::order))), // tolerance to determine convergence
118  cells, kdtree, points, pointcells, dx, 0.0);
119 
120  auto it = gd.getSubDomainIterator(p_lo, p_hi);
121  while(it.isNext())
122  {
123  auto key = it.get();
124  if(std::abs(gd.template get<phi_field>(key)) <= nb_gamma)
125  {
126  auto key_g = gd.getGKey(key);
127  // NOTE: This is not the real grid coordinates, but internal coordinates for algoim
128  blitz::TinyVector<double,dim> patch_pos, cp;
129  for(int d = 0; d < dim; ++d)
130  patch_pos(d) = (key_g.get(d) - p_lo.get(d) + algoim_padding) * dx(d);
131 
132  if (hocp.compute(patch_pos, cp))
133  {
134  for(int d = 0; d < dim; ++d)
135  gd.template get<cp_field>(key)[d] = cp(d);
136  }
137  else
138  {
139  for(int d = 0; d < dim; ++d)
140  gd.template get<cp_field>(key)[d] = -100.0;
141  }
142  }
143  ++it;
144  }
145  }
146  return;
147 }
148 
163 template<typename grid_type, typename grid_key_type, unsigned int poly_order, size_t phi_field, size_t cp_field, size_t extend_field, size_t extend_field_temp>
164 void extendLSField(grid_type &gd, const double nb_gamma)
165 {
166  const unsigned int dim = grid_type::dims;
167  // Stencil polynomial object
168  using Poly = typename Algoim::StencilPoly<dim, poly_order>::T_Poly;
169  auto &patches = gd.getLocalGridsInfo();
170  blitz::TinyVector<double,dim> dx;
171  for(int d = 0; d < dim; ++d)
172  dx(d) = gd.spacing(d);
173 
174  grid_key_dx<dim> p_lo;
175  grid_key_dx<dim> p_hi;
176 
177  for(int i = 0; i < patches.size();i++)
178  {
179  for(int d = 0; d < dim; ++d)
180  {
181  p_lo.set_d(d, patches.get(i).Dbox.getLow(d) + patches.get(i).origin[d]);
182  p_hi.set_d(d, patches.get(i).Dbox.getHigh(d) + patches.get(i).origin[d]);
183  }
184 
185  auto it = gd.getSubDomainIterator(p_lo, p_hi);
186 
187  while(it.isNext())
188  {
189  auto key = it.get();
190  if(std::abs(gd.template get<phi_field>(key)) < nb_gamma)
191  {
192  blitz::TinyVector<int,dim> coord;
193  blitz::TinyVector<double,dim> pos;
194 
195  for(int d = 0; d < dim; ++d)
196  {
197  double cp_d = gd.template get<cp_field>(key)[d];
198  coord(d) = static_cast<int>(floor(cp_d / gd.spacing(d)));
199  pos(d) = cp_d - coord(d)*gd.spacing(d);
200  }
201 
203  Poly field_poly = Poly(coord, fieldwrap, dx);
204  // Extension is first done to the temporary field. Otherwise interpolation will be affected.
205  gd.template get<extend_field_temp>(key) = field_poly(pos);
206  }
207  ++it;
208  }
209  }
210 
211  // Copy the results to the actual variable
212  auto it = gd.getDomainIterator();
213  while(it.isNext())
214  {
215  auto key = it.get();
216  if(std::abs(gd.template get<phi_field>(key)) < nb_gamma)
217  gd.template get<extend_field>(key) = gd.template get<extend_field_temp>(key);
218  ++it;
219  }
220 }
221 
234 template<typename grid_type, typename grid_key_type, unsigned int poly_order, size_t phi_field, size_t cp_field>
235 void reinitializeLS(grid_type &gd, const double nb_gamma)
236 {
237  const unsigned int dim = grid_type::dims;
238  // Stencil polynomial object
239  using Poly = typename Algoim::StencilPoly<dim, poly_order>::T_Poly;
240  auto &patches = gd.getLocalGridsInfo();
241  blitz::TinyVector<double,dim> dx;
242  for(int d = 0; d < dim; ++d)
243  dx(d) = gd.spacing(d);
244 
245  grid_key_dx<dim> p_lo;
246  grid_key_dx<dim> p_hi;
247 
248  for(int i = 0; i < patches.size();i++)
249  {
250  for(int d = 0; d < dim; ++d)
251  {
252  p_lo.set_d(d, patches.get(i).Dbox.getLow(d) + patches.get(i).origin[d]);
253  p_hi.set_d(d, patches.get(i).Dbox.getHigh(d) + patches.get(i).origin[d]);
254  }
255 
256  auto it = gd.getSubDomainIterator(p_lo, p_hi);
257 
258  while(it.isNext())
259  {
260  auto key = it.get();
261  if(std::abs(gd.template get<phi_field>(key)) < nb_gamma)
262  {
263  // Preserve the current sign of the SDF
264  double sign_fn = (gd.template get<phi_field>(key) >= 0.0)?1.0:-1.0;
265  auto key_g = gd.getGKey(key);
266 
267  // Compute the Euclidean distance from gird coordinate to closest point coordinate
268  double distance = 0.0;
269  for(int d = 0; d < dim; ++d)
270  {
271  // NOTE: This is not the real grid coordinates, but internal coordinates used for algoim
272  double patch_pos = (key_g.get(d) - p_lo.get(d) + algoim_padding) * gd.spacing(d);
273  double cp_d = gd.template get<cp_field>(key)[d];
274  distance += ((patch_pos - cp_d)*(patch_pos - cp_d));
275  }
276  distance = sqrt(distance);
277 
278  gd.template get<phi_field>(key) = sign_fn*distance;
279  }
280  ++it;
281  }
282  }
283 }
284 
285 #endif //__CLOSEST_POINT_HPP__
static const unsigned int dims
Number of dimensions.
void extendLSField(grid_type &gd, const double nb_gamma)
Extends a (scalar) field to within nb_gamma from interface. The grid should have level set SDF and cl...
grid_key_dx< dim > getGKey(const grid_dist_key_dx< dim > &k) const
Convert a g_dist_key_dx into a global key.
void estimateClosestPoint(grid_type &gd, const double nb_gamma)
Computes the closest point coordinate for each grid point within nb_gamma from interface.
__device__ __host__ index_type get(index_type i) const
Get the i index.
Definition: grid_key.hpp:503
double operator()(const blitz::TinyVector< int, dim > idx) const
Call operator for the wrapper.
St spacing(size_t i) const
Get the spacing of the grid in direction i.
void reinitializeLS(grid_type &gd, const double nb_gamma)
Reinitializes the level set Phi field on a grid. The grid should have level set SDF and closest point...
grid_dist_iterator_sub< dim, device_grid > getSubDomainIterator(const grid_key_dx< dim > &start, const grid_key_dx< dim > &stop) const
It return an iterator that span the grid domain only in the specified part.
This is a distributed grid.
const openfpm::vector< GBoxes< device_grid::dims > > & getLocalGridsInfo()
It return the informations about the local grids.
grid_dist_iterator< dim, device_grid, decltype(device_grid::type_of_subiterator()), FREE > getDomainIterator() const
It return an iterator that span the full grid domain (each processor span its local domain)
__device__ __host__ void set_d(index_type i, index_type id)
Set the i index.
Definition: grid_key.hpp:516