OpenFPM  5.2.0
Project that contain the implementation of distributed structures
ellipsoid_helpfunctions.h
1 #include <math.h>
2 // This is a collection of helpfunctions that were used to run convergence tests and benchmarks for the ellipse/ellipsoid
3 // in the particle closest point draft. Computing the theoretical closest points and distances from a given query point
4 // is done using the first four functions which were adopted from David Eberly "Distance from a Point to an Ellipse, an
5 // Ellipsoid, or a Hyperellipsoid", 2013.
6 //
7 // Created by lschulze
8 double GetRoot (double r0, double z0, double z1, double g)
9  {
10  const int maxIter = 100;
11  double n0 = r0*z0;
12  double s0 = z1 - 1;
13  double s1 = ( g < 0 ? 0 : sqrt(n0*n0+z1*z1) - 1 ) ;
14  double s = 0;
15  for ( int i = 0; i < maxIter; ++i ){
16  if (i == (maxIter - 1)) std::cout<<"distance point ellipse algorithm did not converge."<<std::endl;
17  s = ( s0 + s1 ) / 2 ;
18  if ( s == s0 || s == s1 ) {break; }
19  double ratio0 = n0 /( s + r0 );
20  double ratio1 = z1 /( s + 1 );
21  g = ratio0*ratio0 + ratio1*ratio1 - 1 ;
22  if (g > 0) {s0 = s;} else if (g < 0) {s1 = s ;} else {break ;}
23  }
24  return s;
25  }
26 
27 double GetRoot(double r0, double r1, double z0, double z1, double z2, double g)
28 {
29  const int maxIter = 100;
30  double n0 = r0*z0;
31  double n1 = r1*z1;
32  double s0 = z2 - 1;
33  double s1 = (g < 0 ? 0 : sqrt(n0*n0 + n1*n1 + z2*z2) - 1) ;
34  double s = s;
35  for(int i = 0 ; i < maxIter ; ++i )
36  {
37  if (i == (maxIter - 1)) std::cout<<"distance point ellipse algorithm did not converge."<<std::endl;
38  s = ( s0 + s1 ) / 2 ;
39  if ( s == s0 || s == s1 ) {break; }
40  double ratio0 = n0 / ( s + r0 );
41  double ratio1 = n1 / ( s + r1 );
42  double ratio2 = z2 / ( s + 1 );
43  g = ratio0*ratio0 + ratio1*ratio1 +ratio2*ratio2 - 1;
44  if ( g > 0 ) { s0 = s ;}
45  else if ( g < 0 ) { s1 = s ; }
46  else {break;}
47  }
48  return (s);
49 }
50 
51 double DistancePointEllipse(double e0, double e1, double y0, double y1, double& x0, double& x1)
52  {
53  double distance;
54  if ( y1 > 0){
55  if ( y0 > 0){
56  double z0 = y0 / e0;
57  double z1 = y1 / e1;
58  double g = z0*z0+z1*z1 - 1;
59  if ( g != 0){
60  double r0 = (e0/e1)*(e0/e1);
61  double sbar = GetRoot(r0 , z0 , z1 , g);
62  x0 = r0 * y0 /( sbar + r0 );
63  x1 = y1 /( sbar + 1 );
64  distance = sqrt( (x0-y0)*(x0-y0) + (x1-y1)*(x1-y1) );
65  }else{
66  x0 = y0;
67  x1 = y1;
68  distance = 0;
69  }
70  }
71  else // y0 == 0
72  {x0 = 0 ; x1 = e1 ; distance = abs( y1 - e1 );}
73  }else{ // y1 == 0
74  double numer0 = e0*y0 , denom0 = e0*e0 - e1*e1;
75  if ( numer0 < denom0 ){
76  double xde0 = numer0/denom0;
77  x0 = e0*xde0 ; x1 = e1*sqrt(1 - xde0*xde0 );
78  distance = sqrt( (x0-y0)*(x0-y0) + x1*x1 );
79  }else{
80  x0 = e0;
81  x1 = 0;
82  distance = abs( y0 - e0 );
83  }
84  }
85  return distance;
86  }
87 
88 double DistancePointEllipsoid(double e0, double e1, double e2, double y0, double y1, double y2, double& x0, double& x1, double& x2)
89 {
90  double distance;
91  if( y2 > 0 )
92  {
93  if( y1 > 0 )
94  {
95  if( y0 > 0 )
96  {
97  double z0 = y0 / e0;
98  double z1 = y1 / e1;
99  double z2 = y2 / e2;
100  double g = z0*z0 + z1*z1 + z2*z2 - 1 ;
101  if( g != 0 )
102  {
103  double r0 = (e0/e2)*(e0/e2);
104  double r1 = (e1/e2)*(e1/e2);
105  double sbar = GetRoot ( r0 , r1 , z0 , z1 , z2 , g );
106  x0 = r0 *y0 / ( sbar + r0 );
107  x1 = r1 *y1 / ( sbar + r1 );
108  x2 = y2 / ( sbar + 1 );
109  distance = sqrt( (x0 - y0)*(x0 - y0) + (x1 - y1)*(x1 - y1) + (x2 - y2)*(x2 - y2));
110  }
111  else
112  {
113  x0 = y0;
114  x1 = y1;
115  x2 = y2;
116  distance = 0;
117  }
118  }
119  else // y0 == 0
120  {
121  x0 = 0;
122  distance = DistancePointEllipse( e1 , e2 , y1 , y2, x1, x2);
123  }
124  }
125  else // y1 == 0
126  {
127  if( y0 > 0 )
128  {
129  x1 = 0;
130  distance = DistancePointEllipse( e0 , e2 , y0 , y2, x0, x2);
131  }
132  else // y0 == 0
133  {
134  x0 = 0;
135  x1 = 0;
136  x2 = e2;
137  distance = abs(y2 - e2);
138  }
139  }
140  }
141  else // y2 == 0
142  {
143  double denom0 = e0*e0 - e2*e2;
144  double denom1 = e1*e1 - e2*e2;
145  double numer0 = e0*y0;
146  double numer1 = e1*y1;
147  bool computed = false;
148  if((numer0 < denom0) && (numer1 < denom1))
149  {
150  double xde0 = numer0/denom0;
151  double xde1 = numer1/denom1 ;
152  double xde0sqr = xde0 *xde0;
153  double xde1sqr = xde1 * xde1 ;
154  double discr = 1 - xde0sqr - xde1sqr;
155  if( discr > 0 )
156  {
157  x0 = e0*xde0;
158  x1 = e1*xde1;
159  x2 = e2*sqrt(discr);
160  distance = sqrt((x0 - y0)*(x0 - y0) + (x1 - y1)*(x1 - y1) + x2*x2);
161  computed = true;
162  }
163  }
164  if( !computed )
165  {
166  x2 = 0;
167  distance = DistancePointEllipse(e0 , e1 , y0 , y1, x0, x1);
168  }
169  }
170  return distance;
171 }
172 
173 constexpr unsigned int factorial(unsigned int x)
174 {
175  unsigned int fact = 1;
176  for(int i = 1; i < (x + 1); i++) fact = fact*i;
177  return(fact);
178 }
179 constexpr unsigned int minter_lp_degree_one_num_coeffs(unsigned int dims, unsigned int poly_degree)
180 {
181  return(factorial(dims + poly_degree)/(factorial(dims)*factorial(poly_degree)));
182 }
183 
184 int return_sign(double phi)
185 {
186  if (phi > 0) return 1;
187  if (phi < 0) return -1;
188  return 0;
189 }
190 
191 double randMinusOneToOne()
192 {
193  double temp = rand() / (RAND_MAX + 1.0);
194  //std::cout<<(2.0*temp - 1.0)<<std::endl;
195  return(2.0*temp - 1.0);
196 }
197 
198 template <typename particles_type> inline void perturb_pos(particles_type & vd, double dp, double factor)
199 {
200  const int dim = particles_type::dims;
201  auto part = vd.getDomainIterator();
202 
203  while(part.isNext())
204  {
205  auto a = part.get();
206 
207  for (int k = 0; k<dim; k++)
208  {
209  vd.getPos(a)[k] += factor*randMinusOneToOne()*dp;
210  //vd.getPos(a)[k] += factor*vd.template getProp<0>(a)*dp;
211  //vd.getPos(a)[k] += factor*dp;
212  }
213 
214  ++part;
215  }
216 }
217 
218 template <typename particles_type, int sdf, int sdf_analytical, int cp_theoretical> inline void update_sdfs(particles_type & vd, double A, double B, double C)
219 {
220  unsigned constexpr dim = particles_type::dims;
221  auto part = vd.getDomainIterator();
222  while (part.isNext())
223  {
224  auto a = part.get();
225  Point<dim, double> xa = vd.getPos(a);
226  if (dim == 2)
227  {
228  vd.template getProp<sdf>(a) = - 1.0 + sqrt((xa[0]/A)*(xa[0]/A) + (xa[1]/B)*(xa[1]/B));
229  //vd.template getProp<sdf>(a) = 10.0;
230  double xcp_analytical;
231  double ycp_analytical;
232  vd.template getProp<sdf_analytical>(a) = return_sign(vd.template getProp<sdf>(a))*DistancePointEllipse(A, B, abs(xa[0]), abs(xa[1]), xcp_analytical, ycp_analytical);
233  //debugging
234  //vd.template getProp<sdf_analytical>(a) = 1.0 - sqrt((xa[0]/A)*(xa[0]/A) + (xa[1]/B)*(xa[1]/B));
235  vd.template getProp<cp_theoretical>(a)[0] = return_sign(xa[0])*xcp_analytical;
236  vd.template getProp<cp_theoretical>(a)[1] = return_sign(xa[1])*ycp_analytical;
237  }
238  else if (dim == 3)
239  {
240  vd.template getProp<sdf>(a) = 1.0 - sqrt(pow(xa[0]/A, 2.0) + pow(xa[1]/B, 2.0) + pow(xa[2]/C, 2.0));
241  double xcp_analytical;
242  double ycp_analytical;
243  double zcp_analytical;
244  vd.template getProp<sdf_analytical>(a) = return_sign(vd.template getProp<sdf>(a))*DistancePointEllipsoid(A, B, C, abs(xa[0]), abs(xa[1]), abs(xa[2]), xcp_analytical, ycp_analytical, zcp_analytical);
245  vd.template getProp<cp_theoretical>(a)[0] = return_sign(xa[0])*xcp_analytical;
246  vd.template getProp<cp_theoretical>(a)[1] = return_sign(xa[1])*ycp_analytical;
247  vd.template getProp<cp_theoretical>(a)[2] = return_sign(xa[2])*zcp_analytical;
248  }
249  // binary distribution
250  //if ((- 1 + sqrt((x/A)*(x/A) + (y/B)*(y/B))) > 0) vd.getProp<sdf>(a) = dp;
251  //else vd.getProp<sdf>(a) = -dp;
252 
253  // Saye's initial configuration
254  //vd.getProp<sdf>(a) = (1 - exp(-(x-0.3)*(x-0.3)-(y-0.3)*(y-0.3)))*(sqrt(4*x*x+9*y*y)-1);
255  ++part;
256  }
257 }
258 
259 template <typename discretization_type, int sdf, int sdf_analytical> inline void get_interpol_error(discretization_type & vd, double narrow_band_half_width, double A, double B, double C)
260 {
261  static constexpr int dim = discretization_type::dims;
262  auto part = vd.getDomainIterator();
263  double err = 0.0;
264  double maxerr = 0.0;
265  double cumerror = 0.0;
266  int numparts = 0;
267  while(part.isNext())
268  {
269  auto a = part.get();
270  Point<dim, double> xa = vd.template getPos(a);
271  if (abs(vd.template getProp<sdf_analytical>(a)) > narrow_band_half_width)
272  {
273  ++part;
274  continue;
275  }
276  if (dim == 2) err = abs(vd.template getProp<sdf>(a) - (1.0 - sqrt((xa[0]/A)*(xa[0]/A) + (xa[1]/B)*(xa[1]/B))));
277  else if (dim == 3) err = abs(vd.template getProp<sdf>(a) - (1.0 - sqrt((xa[0]/A)*(xa[0]/A) + (xa[1]/B)*(xa[1]/B) + (xa[2]/C)*(xa[2]/C))));
278  else break;
279  if (err > maxerr) maxerr = err;
280  cumerror += err;
281  numparts++;
282  ++part;
283  }
284  //std::cout<<"Average interpolation error is "<<cumerror/numparts<<"\nMax interpolation error is "<<maxerr<<std::endl;
285  printf("%f, ",maxerr);
286 
287 }
288 
289 template <typename discretization_type, int sdf, int sdfgrad, int curvature, int cp, int sdf_analytical, int cp_theoretical> inline void get_max_error(discretization_type & vd, double narrow_band_half_width, double A, double B, double C)
290 {
291  static constexpr int dim = discretization_type::dims;
292  auto part = vd.getDomainIterator();
293  double err;
294  double maxerr = 0.0;
295  double errkappa;
296  double maxerrkappa = 0.0;
297  double errnorm;
298  double maxerrnorm = 0.0;
299  double errcp;
300  double maxerrcp = 0.0;
301  double errone;
302  double maxerrone = 0.0;
303  double kappa = 0.0;
304  double avgsdferr = 0.0;
305  int county = 0;
306 
307  while(part.isNext())
308  {
309  auto a = part.get();
310  // L infinity norm:
311  //errnorm = abs(nxa[0]);
312  //if (abs(nxa[1]) > errnorm) errnorm = abs(nxa[1]);
313  //if (abs(nxa[2]) > errnorm) errnorm = abs(nxa[2]);
314  if (abs(vd.template getProp<sdf_analytical>(a)) > narrow_band_half_width)
315  {
316  ++part;
317  continue;
318  }
319  Point<dim, double> norm_analytical;
320  Point<dim, double> norm_computed;
321  for (int k = 0; k < dim; k++) norm_computed[k] = vd.template getProp<sdfgrad>(a)[k];
322  Point<dim, double> cp_computed;
323  Point<dim, double> cp_theo;
324  for (int k = 0; k < dim; k++)
325  {
326  cp_computed[k] = vd.template getProp<cp>(a)[k];
327  cp_theo[k] = vd.template getProp<cp_theoretical>(a)[k];
328  }
329  err = abs(vd.template getProp<sdf>(a) - vd.template getProp<sdf_analytical>(a));
330  if (vd.template getProp<4>(a))
331  {
332  avgsdferr += err;
333  ++county;
334  }
335  errcp = norm(cp_computed - cp_theo);
336 
337  if (dim == 2)
338  {
339  norm_analytical[0] = 2*cp_theo[0]/(A*A);
340  norm_analytical[1] = 2*cp_theo[1]/(B*B);
341  double norm_norm_analytical = norm(norm_analytical);
342  for(int k = 0; k < dim; k++) norm_analytical[k] = return_sign(vd.template getProp<sdf>(a))*norm_analytical[k]/norm_norm_analytical;
343  errnorm = norm(norm_analytical - norm_computed);
344 
345  kappa = A*B/std::pow(B/A*B/A*cp_theo[0]*cp_theo[0] + A/B*A/B*cp_theo[1]*cp_theo[1], 1.5);
346  }
347  else if (dim == 3)
348  {
349  norm_analytical[0] = -2*cp_theo[0]/(A*A);
350  norm_analytical[1] = -2*cp_theo[1]/(B*B);
351  norm_analytical[2] = -2*cp_theo[2]/(C*C);
352  double norm_norm_analytical = norm(norm_analytical);
353  for(int k = 0; k < dim; k++) norm_analytical[k] = return_sign(vd.template getProp<sdf>(a))*norm_analytical[k]/norm_norm_analytical;
354  //std::cout<<norm(norm_analytical)<<std::endl;
355  errnorm = norm(norm_analytical - norm_computed);
356 
357  kappa = -(std::abs(cp_theo[0]*cp_theo[0] + cp_theo[1]*cp_theo[1] + cp_theo[2]*cp_theo[2] - A*A - B*B - C*C))/(2*A*A*B*B*C*C*std::pow(cp_theo[0]*cp_theo[0]/std::pow(A, 4) + cp_theo[1]*cp_theo[1]/std::pow(B, 4) + cp_theo[2]*cp_theo[2]/std::pow(C, 4), 1.5));
358  }
359  errkappa = abs(vd.template getProp<curvature>(a) - kappa);
360  if (err > maxerr) maxerr = err;
361  if (errkappa > maxerrkappa) maxerrkappa = errkappa;
362  if (errnorm > maxerrnorm) maxerrnorm = errnorm;
363  if (errcp > maxerrcp) maxerrcp = errcp;
364  ++part;
365  }
366  std::cout<<"Average error for sdf in narrow band is: "<<avgsdferr/county<<std::endl;
367  std::cout<<"Maximum error for sdf on processor is: "<<maxerr<<std::endl;
368  std::cout<<"Maximum error for surface normal on processor is: "<<maxerrnorm<<std::endl;
369  std::cout<<"Maximum error for curvature on processor is: "<<maxerrkappa<<std::endl;
370  std::cout<<"Maximum error for cp(xa) is: "<<maxerrcp<<std::endl;
371  //printf("%.20f,\n ", maxerr);
372 }
373 
This class implement the point shape in an N-dimensional space.
Definition: Point.hpp:28
Distributed vector.
static const unsigned int dims
template parameters typedefs
auto getPos(vect_dist_key_dx vec_key) -> decltype(vPos.template get< 0 >(vec_key.getKey()))
Get the position of an element.
vector_dist_iterator getDomainIterator() const
Get an iterator that traverse the particles in the domain.