OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
 
Loading...
Searching...
No Matches
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#include <cmath>
9#define BOOST_TEST_DYN_LINK
10#include <boost/test/unit_test.hpp>
11#include <iostream>
12#include "Grid/grid_dist_id.hpp"
13#include "data_type/aggregate.hpp"
14#include "VCluster/VCluster.hpp"
15#include "Vector/Vector.hpp"
16#include "FiniteDifference/util/common.hpp"
17#include "FiniteDifference/eq.hpp"
18#include "FiniteDifference/FD_op.hpp"
19#include "closest_point.hpp"
20
21constexpr int narrow_band_half_width = 5;
22
23typedef struct EllipseParameters{
24 double origin[3];
25 double radiusA;
26 double radiusB;
27 double radiusC;
28 double eccentricity;
30
31// Generate an ellipsoid initial levelset signed distance function
32template<size_t phi_field, typename grid_type>
33void initializeLSEllipsoid(grid_type &gd, const EllipseParams &params)
34{
35 auto it = gd.getDomainIterator();
36 while(it.isNext())
37 {
38 auto key = it.get();
40 double posx = coords.get(0);
41 double posy = coords.get(1);
42 double posz = coords.get(2);
43
44 // NOTE: Except for a sphere, this is not the SDF. It is just an implicit function whose zero contour is an ellipsoid.
45 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));
46 gd.template get<phi_field>(key) = phi_val;
47 ++it;
48 }
49}
50
51// Initialize a scalar field or grid points near the interface
52template<const unsigned int phi, const unsigned int field, typename grid_type>
53void initializeScalarField3D(grid_type &gd, double init_width)
54{
55 auto it = gd.getDomainIterator();
56
57 // Trying with a L_1 and L_2 spherical harmonics as initial condition for scalar_field
58 double prefactor_l1 = std::sqrt(2.0/(4.0*M_PI));
59 //double prefactor_l2 = std::sqrt(5.0/(16.0*M_PI));
60
61 while(it.isNext())
62 {
63 auto key = it.get();
64 if(gd.template get<phi>(key) < init_width)
65 {
66 auto coords = gd.getPos(key);
67 double posx = coords.get(0);
68 double posy = coords.get(1);
69 double posz = coords.get(2);
70
71 double theta = std::atan2(std::sqrt(posx*posx + posy*posy), posz);
72
73 gd.template get<field>(key) = prefactor_l1 * std::cos(theta);
74 //gd.template get<field>(key) = prefactor_l2 * (3.0 * std::cos(theta) * std::cos(theta) - 1.0);
75 }
76 ++it;
77 }
78
79}
80
81BOOST_AUTO_TEST_SUITE( closest_point_test )
82
83
84BOOST_AUTO_TEST_CASE( closest_point_unit_sphere )
85{
86
87 constexpr int SIM_DIM = 3; //> Spatial dimension
88 constexpr int POLY_ORDER = 5; //> Order of the polynomial for stencil interpolation
89 constexpr int SIM_GRID_SIZE = 128; //> Size of the simulation grid along each dimension
90
91 // Properties - phi, cp
93 using GridKey = grid_dist_key_dx<SIM_DIM>;
94
95 // Grid size on each dimension
96 const long int sz[SIM_DIM] = {SIM_GRID_SIZE, SIM_GRID_SIZE, SIM_GRID_SIZE};
97 const size_t szu[SIM_DIM] = {(size_t) sz[0], (size_t) sz[1], (size_t) sz[2]};
98
99 // 3D physical domain
100 Box<SIM_DIM,double> domain({-1.5,-1.5,-1.5},{1.5,1.5,1.5});
101
102 constexpr int x = 0;
103 constexpr int y = 1;
104 constexpr int z = 2;
105
106 // Alias for properties on the grid
107 constexpr int phi = 0;
108 constexpr int cp = 1;
109
110 double nb_gamma = 0.0;
111
112 periodicity<SIM_DIM> grid_bc = {NON_PERIODIC, NON_PERIODIC, NON_PERIODIC};
113 // Ghost in grid units.
114 Ghost <SIM_DIM, long int> grid_ghost(2*narrow_band_half_width);
115 GridDist gdist(szu, domain, grid_ghost, grid_bc);
116
117 // Parameters for initializing Ellipsoid level set function
118 EllipseParams params;
119 params.origin[x] = 0.0;
120 params.origin[y] = 0.0;
121 params.origin[z] = 0.0;
122 params.radiusA = 1.0;
123 params.radiusB = 1.0;
124 params.radiusC = 1.0;
125
126 // Width of the narrowband on one side of the interface
127 nb_gamma = narrow_band_half_width * gdist.spacing(0);
128
129 // Initializes the grid property 'phi' whose zero contour represents the ellipsoid
130 initializeLSEllipsoid<phi>(gdist, params);
131
132 // Updates the property 'cp' of the grid to the closest point coords (only done in the narrowband).
133 estimateClosestPoint<phi, cp, POLY_ORDER>(gdist, nb_gamma);
134
135 // Estimate error in closest point estimation
136 auto &patches = gdist.getLocalGridsInfo();
137 double max_error_cp = -1.0;
138 for(int i = 0; i < patches.size();i++)
139 {
140 // The coordinates of the two bounding points of grid patches.
141 auto p_xlo = patches.get(i).Dbox.getLow(0) + patches.get(i).origin[0];
142 auto p_xhi = patches.get(i).Dbox.getHigh(0) + patches.get(i).origin[0];
143 auto p_ylo = patches.get(i).Dbox.getLow(1) + patches.get(i).origin[1];
144 auto p_yhi = patches.get(i).Dbox.getHigh(1) + patches.get(i).origin[1];
145 auto p_zlo = patches.get(i).Dbox.getLow(2) + patches.get(i).origin[2];
146 auto p_zhi = patches.get(i).Dbox.getHigh(2) + patches.get(i).origin[2];
147
148 auto it = gdist.getSubDomainIterator({p_xlo, p_ylo, p_zlo}, {p_xhi, p_yhi, p_zhi});
149 while(it.isNext())
150 {
151 auto key = it.get();
152
153 if(std::abs(gdist.template get<phi>(key)) < nb_gamma)
154 {
155 // Computed closest point coordinates.
156 // Note: This is patch coordinates not the real one.
157 double cpx = gdist.template get<cp>(key)[x];
158 double cpy = gdist.template get<cp>(key)[y];
159 double cpz = gdist.template get<cp>(key)[z];
160
161 if(cpx == -100.0 && cpy == -100.0 && cpz == -100.0)
162 std::cout<<"ERROR: Requesting closest point where it was not computed."<<std::endl;
163
164 // Convert patch coords to real coordinates.
165 double estim_px = domain.getLow(x) + (p_xlo - algoim_padding)*gdist.spacing(x) + cpx;
166 double estim_py = domain.getLow(y) + (p_ylo - algoim_padding)*gdist.spacing(y) + cpy;
167 double estim_pz = domain.getLow(z) + (p_zlo - algoim_padding)*gdist.spacing(z) + cpz;
168
169 // Global coordinate of the selected grid point.
170 Point<GridDist::dims, double> coords = gdist.getPos(key);
171 double posx = coords.get(0);
172 double posy = coords.get(1);
173 double posz = coords.get(2);
174
175 double norm = sqrt(posx*posx + posy*posy + posz*posz);
176 // Analytically known closest point coordinate for unit sphere.
177 double exact_px = posx / norm;
178 double exact_py = posy / norm;
179 double exact_pz = posz / norm;
180
181 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});
182 }
183 ++it;
184 }
185 }
186 std::cout<<"Unit sphere closest_point error : "<<max_error_cp<<std::endl;
187 double tolerance = 1e-5;
188 bool check;
189 if (std::abs(max_error_cp) < tolerance)
190 check = true;
191 else
192 check = false;
193
194 BOOST_TEST( check );
195
196}
197
198BOOST_AUTO_TEST_CASE( reinitialization_unit_sphere )
199{
200
201 constexpr int SIM_DIM = 3;
202 constexpr int POLY_ORDER = 5;
203 constexpr int SIM_GRID_SIZE = 128;
204
205 // Fields - phi, cp
207 using GridKey = grid_dist_key_dx<SIM_DIM>;
208
209 // Grid size on each dimension
210 const long int sz[SIM_DIM] = {SIM_GRID_SIZE, SIM_GRID_SIZE, SIM_GRID_SIZE};
211 const size_t szu[SIM_DIM] = {(size_t) sz[0], (size_t) sz[1], (size_t) sz[2]};
212
213 // 3D physical domain
214 Box<SIM_DIM,double> domain({-1.5,-1.5,-1.5},{1.5,1.5,1.5});
215
216 constexpr int x = 0;
217 constexpr int y = 1;
218 constexpr int z = 2;
219
220 // Alias for properties on the grid
221 constexpr int phi = 0;
222 constexpr int cp = 1;
223
224 double nb_gamma = 0.0;
225
226 periodicity<SIM_DIM> grid_bc = {NON_PERIODIC, NON_PERIODIC, NON_PERIODIC};
227 // Ghost in grid units
228 Ghost <SIM_DIM, long int> grid_ghost(2*narrow_band_half_width);
229 GridDist gdist(szu, domain, grid_ghost, grid_bc);
230
231 EllipseParams params;
232 params.origin[x] = 0.0;
233 params.origin[y] = 0.0;
234 params.origin[z] = 0.0;
235 params.radiusA = 1.0;
236 params.radiusB = 1.0;
237 params.radiusC = 1.0;
238
239 nb_gamma = narrow_band_half_width * gdist.spacing(0);
240
241 initializeLSEllipsoid<phi>(gdist, params);
242
243 estimateClosestPoint<phi, cp, POLY_ORDER>(gdist, nb_gamma);
244
245 // Reinitialize the level set function stored in property 'phi' based on closest points in 'cp'
246 reinitializeLS<phi, cp>(gdist, nb_gamma);
247
248 // Estimate error in closest point estimation
249 auto &patches = gdist.getLocalGridsInfo();
250 double max_error = -1.0;
251 for(int i = 0; i < patches.size();i++)
252 {
253 auto p_xlo = patches.get(i).Dbox.getLow(0) + patches.get(i).origin[0];
254 auto p_xhi = patches.get(i).Dbox.getHigh(0) + patches.get(i).origin[0];
255 auto p_ylo = patches.get(i).Dbox.getLow(1) + patches.get(i).origin[1];
256 auto p_yhi = patches.get(i).Dbox.getHigh(1) + patches.get(i).origin[1];
257 auto p_zlo = patches.get(i).Dbox.getLow(2) + patches.get(i).origin[2];
258 auto p_zhi = patches.get(i).Dbox.getHigh(2) + patches.get(i).origin[2];
259
260 auto it = gdist.getSubDomainIterator({p_xlo, p_ylo, p_zlo}, {p_xhi, p_yhi, p_zhi});
261 while(it.isNext())
262 {
263 auto key = it.get();
264
265 if(std::abs(gdist.template get<phi>(key)) < nb_gamma)
266 {
267 // Global grid coordinate
268 Point<GridDist::dims, double> coords = gdist.getPos(key);
269 double posx = coords.get(0);
270 double posy = coords.get(1);
271 double posz = coords.get(2);
272
273 // Analytically computed signed distance
274 // NOTE: SDF convention here is positive inside and negative outside the sphere
275 double distance = 1.0 - sqrt(posx*posx + posy*posy + posz*posz);
276
277 max_error = std::max({std::abs(distance - gdist.template get<phi>(key)), max_error});
278 }
279 ++it;
280 }
281 }
282 std::cout<<"Reinitialization error : "<<max_error<<std::endl;
283 double tolerance = 1e-5;
284 bool check;
285 if (std::abs(max_error) < tolerance)
286 check = true;
287 else
288 check = false;
289
290 BOOST_TEST( check );
291
292}
293
294
295BOOST_AUTO_TEST_CASE( extension_unit_sphere )
296{
297
298 constexpr int SIM_DIM = 3;
299 constexpr int POLY_ORDER = 5;
300 constexpr int SIM_GRID_SIZE = 128;
301
302 // Fields - phi, cp, scalar_field, scalar_field_temp
304 using GridKey = grid_dist_key_dx<SIM_DIM>;
305
306 // Grid size on each dimension
307 const long int sz[SIM_DIM] = {SIM_GRID_SIZE, SIM_GRID_SIZE, SIM_GRID_SIZE};
308 const size_t szu[SIM_DIM] = {(size_t) sz[0], (size_t) sz[1], (size_t) sz[2]};
309
310 // 3D physical domain
311 Box<SIM_DIM,double> domain({-1.5,-1.5,-1.5},{1.5,1.5,1.5});
312
313 constexpr int x = 0;
314 constexpr int y = 1;
315 constexpr int z = 2;
316
317 // Alias for properties on the grid
318 constexpr int phi = 0;
319 constexpr int cp = 1;
320 constexpr int scalar_field = 2;
321 constexpr int scalar_field_temp = 3;
322
323 double nb_gamma = 0.0;
324
325 periodicity<SIM_DIM> grid_bc = {NON_PERIODIC, NON_PERIODIC, NON_PERIODIC};
326 // Ghost in grid units
327 Ghost <SIM_DIM, long int> grid_ghost(2*narrow_band_half_width);
328 GridDist gdist(szu, domain, grid_ghost, grid_bc);
329
330 EllipseParams params;
331 params.origin[x] = 0.0;
332 params.origin[y] = 0.0;
333 params.origin[z] = 0.0;
334 params.radiusA = 1.0;
335 params.radiusB = 1.0;
336 params.radiusC = 1.0;
337
338 nb_gamma = narrow_band_half_width * gdist.spacing(0);
339
340 initializeLSEllipsoid<phi>(gdist, params);
341
342 estimateClosestPoint<phi, cp, POLY_ORDER>(gdist, nb_gamma);
343
344 // Reinitialize the level set function stored in property 'phi' based on closest points in 'cp'
345 reinitializeLS<phi, cp>(gdist, nb_gamma);
346
347 // Initialize a scalar field close to interface
348 initializeScalarField3D<phi,scalar_field>(gdist, 4*gdist.spacing(0));
349
350 // Extension to the full narrow band
351 extendLSField<phi, cp, scalar_field, scalar_field_temp, -1>(gdist, nb_gamma);
352 double prefactor_l1 = std::sqrt(2.0/(4.0*M_PI));
353
354 // Estimate error in closest point estimation
355 auto &patches = gdist.getLocalGridsInfo();
356 double max_error = -1.0;
357 for(int i = 0; i < patches.size();i++)
358 {
359 auto p_xlo = patches.get(i).Dbox.getLow(0) + patches.get(i).origin[0];
360 auto p_xhi = patches.get(i).Dbox.getHigh(0) + patches.get(i).origin[0];
361 auto p_ylo = patches.get(i).Dbox.getLow(1) + patches.get(i).origin[1];
362 auto p_yhi = patches.get(i).Dbox.getHigh(1) + patches.get(i).origin[1];
363 auto p_zlo = patches.get(i).Dbox.getLow(2) + patches.get(i).origin[2];
364 auto p_zhi = patches.get(i).Dbox.getHigh(2) + patches.get(i).origin[2];
365
366 auto it = gdist.getSubDomainIterator({p_xlo, p_ylo, p_zlo}, {p_xhi, p_yhi, p_zhi});
367 while(it.isNext())
368 {
369 auto key = it.get();
370
371 if(std::abs(gdist.template get<phi>(key)) < nb_gamma)
372 {
373 // Global grid coordinate
374 auto coords = gdist.getPos(key);
375 double posx = coords.get(0);
376 double posy = coords.get(1);
377 double posz = coords.get(2);
378
379 double theta = std::atan2(std::sqrt(posx*posx + posy*posy), posz);
380 // Analytically computed signed distance
381 // NOTE: SDF convention here is positive inside and negative outside the sphere
382 double exact_val = prefactor_l1 * std::cos(theta);
383
384 max_error = std::max({std::abs(exact_val - gdist.template get<scalar_field>(key)), max_error});
385 }
386 ++it;
387 }
388 }
389 std::cout<<"Extension error : "<<max_error<<std::endl;
390 double tolerance = 1e-5;
391 bool check;
392 if (std::abs(max_error) < tolerance)
393 check = true;
394 else
395 check = false;
396
397 BOOST_TEST( check );
398
399}
400
401BOOST_AUTO_TEST_SUITE_END()
This class represent an N-dimensional box.
Definition Box.hpp:61
This class implement the point shape in an N-dimensional space.
Definition Point.hpp:28
__device__ __host__ const T & get(unsigned int i) const
Get coordinate.
Definition Point.hpp:172
This is a distributed grid.
Point< dim, St > getPos(const grid_dist_key_dx< dim, bg_key > &v1)
Get the reference of the selected element.
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)
Grid key for a distributed grid.
Functions for level set reinitialization and extension on OpenFPM grids based on closest point method...
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...
Boundary conditions.
Definition common.hpp:22