OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
closest_point_unit_tests.cpp
1 /* Unit tests for the closest point methods
2  * Date : 29 May 2021
3  * Author : sachin
4  */
5 
6 #include<iostream>
7 #include <boost/test/unit_test_log.hpp>
8 #define BOOST_TEST_DYN_LINK
9 #include <boost/test/unit_test.hpp>
10 #include <iostream>
11 #include "Grid/grid_dist_id.hpp"
12 #include "data_type/aggregate.hpp"
13 #include "VCluster/VCluster.hpp"
14 #include "Vector/Vector.hpp"
15 #include "FiniteDifference/util/common.hpp"
16 #include "FiniteDifference/eq.hpp"
17 #include "FiniteDifference/FD_op.hpp"
18 #include "closest_point.hpp"
19 
20 constexpr int narrow_band_half_width = 5;
21 
22 typedef struct EllipseParameters{
23  double origin[3];
24  double radiusA;
25  double radiusB;
26  double radiusC;
27  double eccentricity;
29 
30 // Generate an ellipsoid initial levelset signed distance function
31 template<typename grid_type, typename domain_type, size_t phi_field>
32 void initializeLSEllipsoid(grid_type &gd, const domain_type &domain, const EllipseParams &params)
33 {
34  auto it = gd.getDomainIterator();
35  double dx = gd.getSpacing()[0];
36  double dy = gd.getSpacing()[1];
37  double dz = gd.getSpacing()[2];
38  while(it.isNext())
39  {
40  auto key = it.get();
41  auto key_g = gd.getGKey(key);
42 
43  double posx = key_g.get(0)*dx + domain.getLow(0);
44  double posy = key_g.get(1)*dy + domain.getLow(1);
45  double posz = key_g.get(2)*dz + domain.getLow(2);
46 
47  // NOTE: Except for a sphere, this is not the SDF. It is just an implicit function whose zero contour is an ellipsoid.
48  double phi_val = 1.0 - sqrt(((posx - params.origin[0])/params.radiusA)*((posx - params.origin[0])/params.radiusA) + ((posy - params.origin[1])/params.radiusB)*((posy - params.origin[1])/params.radiusB) + ((posz - params.origin[2])/params.radiusC)*((posz - params.origin[2])/params.radiusC));
49  gd.template get<phi_field>(key) = phi_val;
50  ++it;
51  }
52 }
53 
54 BOOST_AUTO_TEST_SUITE( closest_point_test )
55 
56 
57 BOOST_AUTO_TEST_CASE( closest_point_unit_sphere )
58 {
59 
60  constexpr int SIM_DIM = 3; //> Spatial dimension
61  constexpr int POLY_ORDER = 5; //> Order of the polynomial for stencil interpolation
62  constexpr int SIM_GRID_SIZE = 128; //> Size of the simulation grid along each dimension
63 
64  // Properties - phi, cp
66  using GridKey = grid_dist_key_dx<SIM_DIM>;
67 
68  // Grid size on each dimension
69  const long int sz[SIM_DIM] = {SIM_GRID_SIZE, SIM_GRID_SIZE, SIM_GRID_SIZE};
70  const size_t szu[SIM_DIM] = {(size_t) sz[0], (size_t) sz[1], (size_t) sz[2]};
71 
72  // 3D physical domain
73  Box<SIM_DIM,double> domain({-1.5,-1.5,-1.5},{1.5,1.5,1.5});
74 
75  constexpr int x = 0;
76  constexpr int y = 1;
77  constexpr int z = 2;
78 
79  // Alias for properties on the grid
80  constexpr int phi = 0;
81  constexpr int cp = 1;
82 
83  double nb_gamma = 0.0;
84 
85  periodicity<SIM_DIM> grid_bc = {NON_PERIODIC, NON_PERIODIC, NON_PERIODIC};
86  // Ghost in grid units.
87  Ghost <SIM_DIM, long int> grid_ghost(2*narrow_band_half_width);
88  GridDist gdist(szu, domain, grid_ghost, grid_bc);
89 
90  // Parameters for initializing Ellipsoid level set function
91  EllipseParams params;
92  params.origin[x] = 0.0;
93  params.origin[y] = 0.0;
94  params.origin[z] = 0.0;
95  params.radiusA = 1.0;
96  params.radiusB = 1.0;
97  params.radiusC = 1.0;
98 
99  // Width of the narrowband on one side of the interface
100  nb_gamma = narrow_band_half_width * gdist.spacing(0);
101 
102  // Initializes the grid property 'phi' whose zero contour represents the ellipsoid
103  initializeLSEllipsoid<GridDist, Box<SIM_DIM,double>, phi>(gdist, domain, params);
104  gdist.template ghost_get<phi>();
105 
106  // Updates the property 'cp' of the grid to the closest point coords (only done in the narrowband).
107  estimateClosestPoint<GridDist, GridKey, POLY_ORDER, phi, cp>(gdist, nb_gamma);
108  gdist.template ghost_get<cp>();
109 
110  // Estimate error in closest point estimation
111  auto &patches = gdist.getLocalGridsInfo();
112  double max_error_cp = -1.0;
113  for(int i = 0; i < patches.size();i++)
114  {
115  // The coordinates of the two bounding points of grid patches.
116  auto p_xlo = patches.get(i).Dbox.getLow(0) + patches.get(i).origin[0];
117  auto p_xhi = patches.get(i).Dbox.getHigh(0) + patches.get(i).origin[0];
118  auto p_ylo = patches.get(i).Dbox.getLow(1) + patches.get(i).origin[1];
119  auto p_yhi = patches.get(i).Dbox.getHigh(1) + patches.get(i).origin[1];
120  auto p_zlo = patches.get(i).Dbox.getLow(2) + patches.get(i).origin[2];
121  auto p_zhi = patches.get(i).Dbox.getHigh(2) + patches.get(i).origin[2];
122 
123  auto it = gdist.getSubDomainIterator({p_xlo, p_ylo, p_zlo}, {p_xhi, p_yhi, p_zhi});
124  while(it.isNext())
125  {
126  auto key = it.get();
127 
128  if(std::abs(gdist.template get<phi>(key)) < nb_gamma)
129  {
130  auto key_g = gdist.getGKey(key);
131  // Computed closest point coordinates.
132  // Note: This is patch coordinates not the real one.
133  double cpx = gdist.template get<cp>(key)[x];
134  double cpy = gdist.template get<cp>(key)[y];
135  double cpz = gdist.template get<cp>(key)[z];
136 
137  if(cpx == -100.0 && cpy == -100.0 && cpz == -100.0)
138  std::cout<<"ERROR: Requesting closest point where it was not computed."<<std::endl;
139 
140  // Convert patch coords to real coordinates.
141  double estim_px = domain.getLow(x) + (p_xlo - algoim_padding)*gdist.spacing(x) + cpx;
142  double estim_py = domain.getLow(y) + (p_ylo - algoim_padding)*gdist.spacing(y) + cpy;
143  double estim_pz = domain.getLow(z) + (p_zlo - algoim_padding)*gdist.spacing(z) + cpz;
144 
145  // Global coordinate of the selected grid point.
146  double posx = key_g.get(0)*gdist.spacing(0) + domain.getLow(0);
147  double posy = key_g.get(1)*gdist.spacing(1) + domain.getLow(1);
148  double posz = key_g.get(2)*gdist.spacing(2) + domain.getLow(2);
149 
150  double norm = sqrt(posx*posx + posy*posy + posz*posz);
151  // Analytically known closest point coordinate for unit sphere.
152  double exact_px = posx / norm;
153  double exact_py = posy / norm;
154  double exact_pz = posz / norm;
155 
156  max_error_cp = std::max({std::abs(estim_px - exact_px), std::abs(estim_py - exact_py), std::abs(estim_pz - exact_pz), max_error_cp});
157  }
158  ++it;
159  }
160  }
161  std::cout<<"Unit sphere closest_point error : "<<max_error_cp<<std::endl;
162  double tolerance = 1e-5;
163  bool check;
164  if (std::abs(max_error_cp) < tolerance)
165  check = true;
166  else
167  check = false;
168 
169  BOOST_TEST( check );
170 
171 }
172 
173 BOOST_AUTO_TEST_CASE( reinitialization_unit_sphere )
174 {
175 
176  constexpr int SIM_DIM = 3;
177  constexpr int POLY_ORDER = 5;
178  constexpr int SIM_GRID_SIZE = 128;
179 
180  // Fields - phi, cp
182  using GridKey = grid_dist_key_dx<SIM_DIM>;
183 
184  // Grid size on each dimension
185  const long int sz[SIM_DIM] = {SIM_GRID_SIZE, SIM_GRID_SIZE, SIM_GRID_SIZE};
186  const size_t szu[SIM_DIM] = {(size_t) sz[0], (size_t) sz[1], (size_t) sz[2]};
187 
188  // 3D physical domain
189  Box<SIM_DIM,double> domain({-1.5,-1.5,-1.5},{1.5,1.5,1.5});
190 
191  constexpr int x = 0;
192  constexpr int y = 1;
193  constexpr int z = 2;
194 
195  // Alias for properties on the grid
196  constexpr int phi = 0;
197  constexpr int cp = 1;
198 
199  double nb_gamma = 0.0;
200 
201  periodicity<SIM_DIM> grid_bc = {NON_PERIODIC, NON_PERIODIC, NON_PERIODIC};
202  // Ghost in grid units
203  Ghost <SIM_DIM, long int> grid_ghost(2*narrow_band_half_width);
204  GridDist gdist(szu, domain, grid_ghost, grid_bc);
205 
206  EllipseParams params;
207  params.origin[x] = 0.0;
208  params.origin[y] = 0.0;
209  params.origin[z] = 0.0;
210  params.radiusA = 1.0;
211  params.radiusB = 1.0;
212  params.radiusC = 1.0;
213 
214  nb_gamma = narrow_band_half_width * gdist.spacing(0);
215 
216  initializeLSEllipsoid<GridDist, Box<SIM_DIM,double>, phi>(gdist, domain, params);
217  gdist.template ghost_get<phi>();
218 
219  estimateClosestPoint<GridDist, GridKey, POLY_ORDER, phi, cp>(gdist, nb_gamma);
220  gdist.template ghost_get<cp>();
221 
222  // Reinitialize the level set function stored in property 'phi' based on closest points in 'cp'
223  reinitializeLS<GridDist, GridKey, POLY_ORDER, phi, cp>(gdist, nb_gamma);
224  gdist.template ghost_get<phi>();
225 
226  // Estimate error in closest point estimation
227  auto &patches = gdist.getLocalGridsInfo();
228  double max_error = -1.0;
229  for(int i = 0; i < patches.size();i++)
230  {
231  auto p_xlo = patches.get(i).Dbox.getLow(0) + patches.get(i).origin[0];
232  auto p_xhi = patches.get(i).Dbox.getHigh(0) + patches.get(i).origin[0];
233  auto p_ylo = patches.get(i).Dbox.getLow(1) + patches.get(i).origin[1];
234  auto p_yhi = patches.get(i).Dbox.getHigh(1) + patches.get(i).origin[1];
235  auto p_zlo = patches.get(i).Dbox.getLow(2) + patches.get(i).origin[2];
236  auto p_zhi = patches.get(i).Dbox.getHigh(2) + patches.get(i).origin[2];
237 
238  auto it = gdist.getSubDomainIterator({p_xlo, p_ylo, p_zlo}, {p_xhi, p_yhi, p_zhi});
239  while(it.isNext())
240  {
241  auto key = it.get();
242 
243  if(std::abs(gdist.template get<phi>(key)) < nb_gamma)
244  {
245  auto key_g = gdist.getGKey(key);
246  // Global grid coordinate
247  double posx = key_g.get(0)*gdist.spacing(0) + domain.getLow(0);
248  double posy = key_g.get(1)*gdist.spacing(1) + domain.getLow(1);
249  double posz = key_g.get(2)*gdist.spacing(2) + domain.getLow(2);
250 
251  // Analytically computed signed distance
252  // NOTE: SDF convention here is positive inside and negative outside the sphere
253  double distance = 1.0 - sqrt(posx*posx + posy*posy + posz*posz);
254 
255  max_error = std::max({std::abs(distance - gdist.template get<phi>(key)), max_error});
256  }
257  ++it;
258  }
259  }
260  std::cout<<"Reinitialization error : "<<max_error<<std::endl;
261  double tolerance = 1e-5;
262  bool check;
263  if (std::abs(max_error) < tolerance)
264  check = true;
265  else
266  check = false;
267 
268  BOOST_TEST( check );
269 
270 }
271 
272 BOOST_AUTO_TEST_SUITE_END()
Point< dim, St > getSpacing()
Get the spacing on each dimension.
grid_key_dx< dim > getGKey(const grid_dist_key_dx< dim > &k) const
Convert a g_dist_key_dx into a global key.
__device__ __host__ index_type get(index_type i) const
Get the i index.
Definition: grid_key.hpp:503
Grid key for a distributed grid.
Definition: Ghost.hpp:39
Functions for level set reinitialization and extension on OpenFPM grids based on closest point method...
This is a distributed grid.
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)
This class represent an N-dimensional box.
Definition: Box.hpp:60
Boundary conditions.
Definition: common.hpp:21