OpenFPM  5.2.0
Project that contain the implementation of distributed structures
DCPSE_op_Surface_tests.cpp
1 //
2 // Created by Abhinav Singh on 15.11.21.
3 //
4 // #define SE_CLASS1
5 
6 #include "config.h"
7 #ifdef HAVE_EIGEN
8 #ifdef HAVE_PETSC
9 
10 #define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
11 #define BOOST_MPL_LIMIT_VECTOR_SIZE 40
12 
13 #define BOOST_TEST_DYN_LINK
14 
15 #include "util/util_debug.hpp"
16 #include <boost/test/unit_test.hpp>
17 #include <iostream>
18 #include "../DCPSE_surface_op.hpp"
19 #include "../DCPSE_Solver.hpp"
20 #include "../../DcpseInterpolation.hpp"
21 #include "Operators/Vector/vector_dist_operators.hpp"
22 // #include "Vector/vector_dist_subset.hpp"
23 #include <iostream>
24 #include "util/SphericalHarmonics.hpp"
25 #include "Vector/vector_dist_multiphase_functions.hpp"
26 
27 BOOST_AUTO_TEST_SUITE(dcpse_op_suite_tests)
28  BOOST_AUTO_TEST_CASE(dcpse_surface_simple) {
29  double boxP1{-1.5}, boxP2{1.5};
30  double boxSize{boxP2 - boxP1};
31  size_t n=256;
32  size_t sz[2] = {n,n};
33  double grid_spacing{boxSize/(sz[0]-1)};
34  double rCut{3.9 * grid_spacing};
35 
36  Box<2,double> domain{{boxP1,boxP1},{boxP2,boxP2}};
37  size_t bc[2] = {NON_PERIODIC,NON_PERIODIC};
38  Ghost<2,double> ghost{rCut + grid_spacing/8.0};
39  auto &v_cl=create_vcluster();
40 
42  //Init_DCPSE(domain)
43  BOOST_TEST_MESSAGE("Init domain...");
44 
45  // 1. Particles on a line
46  if (v_cl.rank() == 0) {
47  for (int i = 0; i < n; ++i) {
48  double xp = -1.5+i*grid_spacing;
49  Sparticles.add();
50  Sparticles.getLastPos()[0] = xp;
51  Sparticles.getLastPos()[1] = 0;
52  Sparticles.getLastProp<3>() = std::sin(xp);
53  Sparticles.getLastProp<2>()[0] = 0;
54  Sparticles.getLastProp<2>()[1] = 1.0;
55  Sparticles.getLastProp<1>() = -std::sin(xp);//sin(theta)*exp(-finalT/(radius*radius));
56  Sparticles.getLastSubset(0);
57  }
58  }
59  Sparticles.map();
60 
61  BOOST_TEST_MESSAGE("Sync domain across processors...");
62 
63  Sparticles.ghost_get<0,3>();
64  //Sparticles.write("Sparticles");
65  //Here template parameters are Normal property no.
66  auto verletList = Sparticles.template getVerlet<VL_NON_SYMMETRIC|VL_SKIP_REF_PART>(rCut);
67 
68  SurfaceDerivative_xx<2,decltype(verletList)> SDxx(Sparticles, verletList, 2, rCut, grid_spacing, static_cast<unsigned int>(rCut/grid_spacing));
69  SurfaceDerivative_yy<2,decltype(verletList)> SDyy(Sparticles, verletList, 2, rCut, grid_spacing, static_cast<unsigned int>(rCut/grid_spacing));
70  //SurfaceDerivative_x<2,decltype(verletList)> SDx(Sparticles, 4, rCut, grid_spacing, rCut/grid_spacing);
71  //SurfaceDerivative_y<2,decltype(verletList)> SDy(Sparticles, 4, rCut, grid_spacing, rCut/grid_spacing);
72  auto INICONC = getV<3>(Sparticles);
73  auto CONC = getV<0>(Sparticles);
74  auto TEMP = getV<4>(Sparticles);
75  auto normal = getV<2>(Sparticles);
76  //auto ANASOL = getV<1>(domain);
77  CONC=SDxx(INICONC)+SDyy(INICONC);
78  //TEMP[0]=(-normal[0]*normal[0]+1.0) * SDx(INICONC) - normal[0]*normal[1] * SDy(INICONC);
79  //TEMP[1]=(-normal[1]*normal[1]+1.0) * SDy(INICONC) - normal[0]*normal[1] * SDx(INICONC);
80  //Sparticles.ghost_get<4>();
81  //CONC=SDxx(TEMP[0]) + SDyy(TEMP[1]);
82  auto it2 = Sparticles.getDomainIterator();
83  double worst = 0.0;
84  while (it2.isNext()) {
85  auto p = it2.get();
86  if (fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p)) > worst) {
87  worst = fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p));
88  }
89 
90  ++it2;
91  }
92  Sparticles.deleteGhost();
93  //std::cout<<v_cl.rank()<<":WORST:"<<worst<<std::endl;
94  //Sparticles.write("Sparticles");
95  BOOST_REQUIRE(worst < 0.03);
96 }
97  BOOST_AUTO_TEST_CASE(dcpse_surface_circle) {
98 
99  double boxP1{-1.5}, boxP2{1.5};
100  double boxSize{boxP2 - boxP1};
101  size_t n=512;
102  auto &v_cl=create_vcluster();
103  //std::cout<<v_cl.rank()<<":Enter res: "<<std::endl;
104  //std::cin>>n;
105  size_t sz[2] = {n,n};
106  double grid_spacing{boxSize/(sz[0]-1)};
107  double rCut{5.1 * grid_spacing};
108 
109  Box<2,double> domain{{boxP1,boxP1},{boxP2,boxP2}};
110  size_t bc[2] = {NON_PERIODIC,NON_PERIODIC};
111  Ghost<2,double> ghost{rCut + grid_spacing/8.0};
113  //Init_DCPSE(domain)
114  BOOST_TEST_MESSAGE("Init domain...");
115 
116  // Surface prameters
117  const double radius{1.0};
118  std::array<double,2> center{0.0,0.0};
119  Point<2,double> coord;
120  const double pi{3.14159265358979323846};
121 
122  // 1. Particles on surface
123  double theta{0.0};
124  double dtheta{2*pi/double(n)};
125  if (v_cl.rank() == 0) {
126  for (int i = 0; i < n; ++i) {
127  coord[0] = center[0] + radius * std::cos(theta);
128  coord[1] = center[1] + radius * std::sin(theta);
129  Sparticles.add();
130  Sparticles.getLastPos()[0] = coord[0];
131  Sparticles.getLastPos()[1] = coord[1];
132  Sparticles.getLastProp<3>() = std::sin(theta);
133  Sparticles.getLastProp<2>()[0] = std::cos(theta);
134  Sparticles.getLastProp<2>()[1] = std::sin(theta);
135  Sparticles.getLastProp<1>() = -std::sin(theta);;//sin(theta)*exp(-finalT/(radius*radius));
136  Sparticles.getLastSubset(0);
137  theta += dtheta;
138  }
139  }
140  Sparticles.map();
141 
142  BOOST_TEST_MESSAGE("Sync domain across processors...");
143 
144  Sparticles.ghost_get<0,3>();
145  Sparticles.ghost_get_subset();
146  //Sparticles.write("Sparticles");
147  //Here template parameters are Normal property no.
148  auto verletList = Sparticles.template getVerlet<VL_NON_SYMMETRIC|VL_SKIP_REF_PART>(rCut);
149 
150  SurfaceDerivative_xx<2,decltype(verletList)> SDxx(Sparticles, verletList, 2, rCut, grid_spacing, static_cast<unsigned int>(rCut/grid_spacing));
151  SurfaceDerivative_yy<2,decltype(verletList)> SDyy(Sparticles, verletList, 2, rCut, grid_spacing, static_cast<unsigned int>(rCut/grid_spacing));
152  //SurfaceDerivative_xy<2,decltype(verletList)> SDxy(Sparticles, 3, rCut, grid_spacing, rCut/grid_spacing);
153  //SurfaceDerivative_x<2,decltype(verletList)> SDx(Sparticles, 3, rCut, grid_spacing, rCut/grid_spacing);
154  //SurfaceDerivative_y<2,decltype(verletList)> SDy(Sparticles, 3, rCut, grid_spacing, rCut/grid_spacing);
155  auto INICONC = getV<3>(Sparticles);
156  auto CONC = getV<0>(Sparticles);
157  auto TEMP = getV<4>(Sparticles);
158  auto normal = getV<2>(Sparticles);
159 
160  CONC=SDxx(INICONC)+SDyy(INICONC);
161  //TEMP[0]=(-normal[0]*normal[0]+1.0) * SDx(INICONC) - normal[0]*normal[1] * SDy(INICONC);
162  //TEMP[1]=(-normal[1]*normal[1]+1.0) * SDy(INICONC) - normal[0]*normal[1] * SDx(INICONC);
163  //TEMP[0]=(-normal[0]*normal[0]+1.0);
164  //TEMP[1]=normal[0]*normal[1];
165  //Sparticles.ghost_get<2,4>();
166  //CONC=SDx(TEMP[0]) + SDy(TEMP[1]);
167  //CONC= (SDx(TEMP[0])*SDx(INICONC)+TEMP[0]*SDxx(INICONC)-(SDx(TEMP[1])*SDy(INICONC)+TEMP[1]*SDxy(INICONC)))+
168  // (SDy((-normal[1]*normal[1]+1.0))*SDy(INICONC)+(-normal[1]*normal[1]+1.0)*SDyy(INICONC)-(SDy(TEMP[1])*SDx(INICONC)+TEMP[1]*SDxy(INICONC)));
169  auto it2 = Sparticles.getDomainIterator();
170  double worst = 0.0;
171  while (it2.isNext()) {
172  auto p = it2.get();
173  Sparticles.getProp<5>(p) = fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p));
174  if (fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p)) > worst) {
175  worst = fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p));
176  }
177  ++it2;
178  }
179  Sparticles.deleteGhost();
180  //Sparticles.write("Sparticles");
181  //std::cout<<worst;
182  BOOST_REQUIRE(worst < 0.03);
183 }
184  BOOST_AUTO_TEST_CASE(dcpse_surface_solver_circle) {
185  double boxP1{-1.5}, boxP2{1.5};
186  double boxSize{boxP2 - boxP1};
187  size_t n=512,k=2;
188  auto &v_cl=create_vcluster();
189  /*if(v_cl.rank()==0)
190  std::cout<<v_cl.rank()<<":Enter res: "<<std::endl;
191  std::cin>>n;
192  if(v_cl.rank()==0)
193  std::cout<<v_cl.rank()<<":Enter Freq: "<<std::endl;
194  std::cin>>k;*/
195  size_t sz[2] = {n,n};
196  double grid_spacing{boxSize/(sz[0]-1)};
197  double rCut{3.9 * grid_spacing};
198 
199  Box<2,double> domain{{boxP1,boxP1},{boxP2,boxP2}};
200  size_t bc[2] = {NON_PERIODIC,NON_PERIODIC};
201  Ghost<2,double> ghost{rCut + grid_spacing/8.0};
203  //Init_DCPSE(domain)
204  BOOST_TEST_MESSAGE("Init domain...");
205 
206  // Surface prameters
207  const double radius{1.0};
208  std::array<double,2> center{0.0,0.0};
209  Point<2,double> coord;
210  const double pi{3.14159265358979323846};
211 
212  // 1. Particles on surface
213  double theta{0.0};
214  double dtheta{2*pi/double(n)};
215  if (v_cl.rank() == 0) {
216  for (int i = 0; i < n; ++i) {
217  coord[0] = center[0] + radius * std::cos(theta);
218  coord[1] = center[1] + radius * std::sin(theta);
219  Sparticles.add();
220  Sparticles.getLastPos()[0] = coord[0];
221  Sparticles.getLastPos()[1] = coord[1];
222  Sparticles.getLastProp<3>() = -openfpm::math::intpowlog(k,2)*std::sin(k*theta);
223  Sparticles.getLastProp<2>()[0] = std::cos(theta);
224  Sparticles.getLastProp<2>()[1] = std::sin(theta);
225  Sparticles.getLastProp<1>() = std::sin(k*theta);;//sin(theta)*exp(-finalT/(radius*radius));
226  Sparticles.getLastSubset(0);
227  if(coord[0]==1. && coord[1]==0.)
228  {Sparticles.getLastSubset(1);}
229  theta += dtheta;
230  }
231  }
232  Sparticles.map();
233 
234  BOOST_TEST_MESSAGE("Sync domain across processors...");
235 
236  Sparticles.ghost_get<0>();
237  //Sparticles.write("Sparticles");
240  auto & bulk=Sparticles_bulk.getIds();
241  auto & boundary=Sparticles_boundary.getIds();
242  //Here template parameters are Normal property no.
243  auto verletList = Sparticles.template getVerlet<VL_NON_SYMMETRIC|VL_SKIP_REF_PART>(rCut);
244 
245  SurfaceDerivative_xx<2,decltype(verletList)> SDxx(Sparticles, verletList, 2, rCut, grid_spacing, static_cast<unsigned int>(rCut/grid_spacing));
246  SurfaceDerivative_yy<2,decltype(verletList)> SDyy(Sparticles, verletList, 2, rCut, grid_spacing, static_cast<unsigned int>(rCut/grid_spacing));
247  auto INICONC = getV<3>(Sparticles);
248  auto CONC = getV<0>(Sparticles);
249  auto TEMP = getV<4>(Sparticles);
250  auto normal = getV<2>(Sparticles);
251  auto ANASOL = getV<1>(Sparticles);
252  DCPSE_scheme<equations2d1,decltype(Sparticles)> Solver(Sparticles);
253  Solver.impose(SDxx(CONC)+SDyy(CONC), bulk, INICONC);
254  Solver.impose(CONC, boundary, ANASOL);
255  Solver.solve(CONC);
256  auto it2 = Sparticles.getDomainIterator();
257  double worst = 0.0;
258  while (it2.isNext()) {
259  auto p = it2.get();
260  Sparticles.getProp<5>(p) = fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p));
261  if (fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p)) > worst) {
262  worst = fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p));
263  }
264  ++it2;
265  }
266  Sparticles.deleteGhost();
267  //Sparticles.write("Sparticles");
268  //std::cout<<worst;
269  BOOST_REQUIRE(worst < 0.03);
270 }
271 
272 BOOST_AUTO_TEST_CASE(dcpse_surface_sphere_copy) {
273  auto & v_cl = create_vcluster();
274  timer tt;
275  tt.start();
276  size_t n=10000;
277  size_t n_sp=n;
278  // Domain
279  double boxP1{-1.5}, boxP2{1.5};
280  double boxSize{boxP2 - boxP1};
281  size_t sz[3] = {n,n,n};
282  double grid_spacing{boxSize/(sz[0]-1)};
283  double grid_spacing_surf=std::sqrt(4.0*M_PI/n);//grid_spacing*30;
284  double rCut{2.5 * grid_spacing_surf};
285 
286  Box<3,double> domain{{boxP1,boxP1,boxP1},{boxP2,boxP2,boxP2}};
287  size_t bc[3] = {NON_PERIODIC,NON_PERIODIC,NON_PERIODIC};
288  Ghost<3,double> ghost{rCut + grid_spacing/8.0};
289 
290  constexpr int K = 1;
291  // particles
293  // 1. particles on the Spherical surface
294  double Golden_angle=M_PI * (3.0 - sqrt(5.0));
295  if (v_cl.rank() == 0) {
296  //std::vector<Vector3f> data;
297  //GenerateSphere(1,data);
298  for(int i=1;i<n_sp;i++)
299  {
300  double y = 1.0 - (i /double(n_sp - 1.0)) * 2.0;
301  double radius = sqrt(1 - y * y);
302  double Golden_theta = Golden_angle * i;
303  double x = cos(Golden_theta) * radius;
304  double z = sin(Golden_theta) * radius;
305  Sparticles.add();
306  Sparticles.getLastPos()[0] = x;
307  Sparticles.getLastPos()[1] = y;
308  Sparticles.getLastPos()[2] = z;
309  double rm=sqrt(x*x+y*y+z*z);
310  Sparticles.getLastProp<2>()[0] = x/rm;
311  Sparticles.getLastProp<2>()[1] = y/rm;
312  Sparticles.getLastProp<2>()[2] = z/rm;
313  Sparticles.getLastProp<4>()[0] = 1.0 ;
314  Sparticles.getLastProp<4>()[1] = std::atan2(sqrt(x*x+y*y),z);
315  Sparticles.getLastProp<4>()[2] = std::atan2(y,x);
316  if(i<=2*(K)+1)
317  {Sparticles.getLastSubset(1);}
318  else
319  {Sparticles.getLastSubset(0);}
320  }
321  //std::cout << "n: " << n << " - grid spacing: " << grid_spacing << " - rCut: " << rCut << "Surf Normal spacing" << grid_spacing<<std::endl;
322  }
323 
324  Sparticles.map();
325  Sparticles.ghost_get<3>();
326 
329  auto &bulkIds=Sparticles_bulk.getIds();
330  auto &bdrIds=Sparticles_boundary.getIds();
331  std::unordered_map<const lm,double,key_hash,key_equal> Alm;
332  //Setting max mode l_max
333  //Setting amplitudes to 1
334  for(int l=0;l<=K;l++){
335  for(int m=-l;m<=l;m++){
336  Alm[std::make_tuple(l,m)]=0;
337  }
338  }
339  Alm[std::make_tuple(1,0)]=1;
340  auto it2 = Sparticles.getDomainIterator();
341  while (it2.isNext()) {
342  auto p = it2.get();
343  Point<3, double> xP = Sparticles.getProp<4>(p);
344  /*double Sum=0;
345  for(int m=-spL;m<=spL;++m)
346  {
347  Sum+=openfpm::math::Y(spL,m,xP[1],xP[2]);
348  }*/
349  //Sparticles.getProp<ANADF>(p) = Sum;//openfpm::math::Y(K,K,xP[1],xP[2]);openfpm::math::sumY_Scalar<K>(xP[0],xP[1],xP[2],Alm);;
350  Sparticles.getProp<3>(p)=openfpm::math::sumY_Scalar<K>(xP[0],xP[1],xP[2],Alm);
351  Sparticles.getProp<1>(p)=2.0;//-(K)*(K+1)*openfpm::math::sumY_Scalar<K>(xP[0],xP[1],xP[2],Alm);
352  ++it2;
353  }
354  auto f=getV<2>(Sparticles);
355  auto Df=getV<0>(Sparticles);
356 
357  auto verletList = Sparticles.template getVerlet<VL_NON_SYMMETRIC|VL_SKIP_REF_PART>(rCut);
358 
359  SurfaceDerivative_x<2,decltype(verletList)> Sdx{Sparticles,verletList,2,rCut,grid_spacing_surf,static_cast<unsigned int>(rCut/grid_spacing_surf)};
360  SurfaceDerivative_y<2,decltype(verletList)> Sdy{Sparticles,verletList,2,rCut,grid_spacing_surf,static_cast<unsigned int>(rCut/grid_spacing_surf)};
361  SurfaceDerivative_z<2,decltype(verletList)> Sdz{Sparticles,verletList,2,rCut,grid_spacing_surf,static_cast<unsigned int>(rCut/grid_spacing_surf)};
362  //Laplace_Beltrami<2> SLap{Sparticles,2,rCut,grid_spacing_surf};
363  //Sdyy.DrawKernel<5>(Sparticles,0);
364  //Sdzz.DrawKernel<5>(Sparticles,0);
365 /* std::cout<<"SDXX:"<<std::endl;
366  Sdxx.checkMomenta(Sparticles);
367  std::cout<<"SDYY:"<<std::endl;
368  Sdyy.checkMomenta(Sparticles);
369  std::cout<<"SDZZ:"<<std::endl;
370  Sdzz.checkMomenta(Sparticles);*/
371 
372  Sparticles.ghost_get<3>();
373  Df=(Sdx(f[0])+Sdy(f[1])+Sdz(f[2]));
374  //Df=SLap(f);
375  auto it3 = Sparticles.getDomainIterator();
376  double worst = 0.0;
377  while (it3.isNext()) {
378  auto p = it3.get();
379  //Sparticles.getProp<5>(p) = fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p));
380  if (fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p)) > worst) {
381  worst = fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p));
382  }
383  ++it3;
384  }
385  Sparticles.deleteGhost();
386  //Sparticles.write("Sparticles");
387  std::cout<<worst;
388  BOOST_REQUIRE(worst < 0.03);
389 }
390 BOOST_AUTO_TEST_CASE(dcpse_surface_sphere) {
391  auto & v_cl = create_vcluster();
392  timer tt;
393  tt.start();
394  size_t n=40960;
395  size_t n_sp=n;
396  // Domain
397  double boxP1{-1.5}, boxP2{1.5};
398  double boxSize{boxP2 - boxP1};
399  size_t sz[3] = {n,n,n};
400  double grid_spacing{boxSize/(sz[0]-1)};
401  double grid_spacing_surf=std::sqrt(4.0*M_PI/n);//grid_spacing*30;
402  double rCut{2.5 * grid_spacing_surf};
403 
404  Box<3,double> domain{{boxP1,boxP1,boxP1},{boxP2,boxP2,boxP2}};
405  size_t bc[3] = {NON_PERIODIC,NON_PERIODIC,NON_PERIODIC};
406  Ghost<3,double> ghost{rCut + grid_spacing/8.0};
407 
408  constexpr int K = 1;
409  // particles
411  // 1. particles on the Spherical surface
412  double Golden_angle=M_PI * (3.0 - sqrt(5.0));
413  if (v_cl.rank() == 0) {
414  //std::vector<Vector3f> data;
415  //GenerateSphere(1,data);
416  for(int i=1;i<n_sp;i++)
417  {
418  double y = 1.0 - (i /double(n_sp - 1.0)) * 2.0;
419  double radius = sqrt(1 - y * y);
420  double Golden_theta = Golden_angle * i;
421  double x = cos(Golden_theta) * radius;
422  double z = sin(Golden_theta) * radius;
423  Sparticles.add();
424  Sparticles.getLastPos()[0] = x;
425  Sparticles.getLastPos()[1] = y;
426  Sparticles.getLastPos()[2] = z;
427  double rm=sqrt(x*x+y*y+z*z);
428  Sparticles.getLastProp<2>()[0] = x/rm;
429  Sparticles.getLastProp<2>()[1] = y/rm;
430  Sparticles.getLastProp<2>()[2] = z/rm;
431  Sparticles.getLastProp<4>()[0] = 1.0 ;
432  Sparticles.getLastProp<4>()[1] = std::atan2(sqrt(x*x+y*y),z);
433  Sparticles.getLastProp<4>()[2] = std::atan2(y,x);
434  if(i<=2*(K)+1)
435  {Sparticles.getLastSubset(1);}
436  else
437  {Sparticles.getLastSubset(0);}
438  }
439  //std::cout << "n: " << n << " - grid spacing: " << grid_spacing << " - rCut: " << rCut << "Surf Normal spacing" << grid_spacing<<std::endl;
440  }
441 
442  Sparticles.map();
443  Sparticles.ghost_get<3>();
444 
447  auto &bulkIds=Sparticles_bulk.getIds();
448  auto &bdrIds=Sparticles_boundary.getIds();
449  std::unordered_map<const lm,double,key_hash,key_equal> Alm;
450  //Setting max mode l_max
451  //Setting amplitudes to 1
452  for(int l=0;l<=K;l++){
453  for(int m=-l;m<=l;m++){
454  Alm[std::make_tuple(l,m)]=0;
455  }
456  }
457  Alm[std::make_tuple(1,0)]=1;
458  auto it2 = Sparticles.getDomainIterator();
459  while (it2.isNext()) {
460  auto p = it2.get();
461  Point<3, double> xP = Sparticles.getProp<4>(p);
462  /*double Sum=0;
463  for(int m=-spL;m<=spL;++m)
464  {
465  Sum+=openfpm::math::Y(spL,m,xP[1],xP[2]);
466  }*/
467  //Sparticles.getProp<ANADF>(p) = Sum;//openfpm::math::Y(K,K,xP[1],xP[2]);openfpm::math::sumY_Scalar<K>(xP[0],xP[1],xP[2],Alm);;
468  Sparticles.getProp<3>(p)=openfpm::math::sumY_Scalar<K>(xP[0],xP[1],xP[2],Alm);
469  Sparticles.getProp<1>(p)=-(K)*(K+1)*openfpm::math::sumY_Scalar<K>(xP[0],xP[1],xP[2],Alm);
470  ++it2;
471  }
472  auto f=getV<3>(Sparticles);
473  auto Df=getV<0>(Sparticles);
474 
475  auto verletList = Sparticles.template getVerlet<VL_NON_SYMMETRIC|VL_SKIP_REF_PART>(rCut);
476 
477  SurfaceDerivative_xx<2,decltype(verletList)> Sdxx{Sparticles,verletList,2,rCut,grid_spacing_surf,static_cast<unsigned int>(rCut/grid_spacing_surf)};
478  SurfaceDerivative_yy<2,decltype(verletList)> Sdyy{Sparticles,verletList,2,rCut,grid_spacing_surf,static_cast<unsigned int>(rCut/grid_spacing_surf)};
479  SurfaceDerivative_zz<2,decltype(verletList)> Sdzz{Sparticles,verletList,2,rCut,grid_spacing_surf,static_cast<unsigned int>(rCut/grid_spacing_surf)};
480  //Laplace_Beltrami<2> SLap{Sparticles,2,rCut,grid_spacing_surf,static_cast<unsigned int>(rCut/grid_spacing_surf)};
481  //Sdyy.DrawKernel<5>(Sparticles,0);
482  //Sdzz.DrawKernel<5>(Sparticles,0);
483 /* std::cout<<"SDXX:"<<std::endl;
484  Sdxx.checkMomenta(Sparticles);
485  std::cout<<"SDYY:"<<std::endl;
486  Sdyy.checkMomenta(Sparticles);
487  std::cout<<"SDZZ:"<<std::endl;
488  Sdzz.checkMomenta(Sparticles);*/
489 
490  Sparticles.ghost_get<3>();
491  Df=(Sdxx(f)+Sdyy(f)+Sdzz(f));
492  //Df=SLap(f);
493  auto it3 = Sparticles.getDomainIterator();
494  double worst = 0.0;
495  while (it3.isNext()) {
496  auto p = it3.get();
497  //Sparticles.getProp<5>(p) = fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p));
498  if (fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p)) > worst) {
499  worst = fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p));
500  }
501  ++it3;
502  }
503  Sparticles.deleteGhost();
504  //Sparticles.write("Sparticles");
505  std::cout<<worst;
506  BOOST_REQUIRE(worst < 0.03);
507 }
508 
509 
510 BOOST_AUTO_TEST_CASE(dcpse_surface_sphere_old) {
511  auto & v_cl = create_vcluster();
512  timer tt;
513  tt.start();
514  size_t n=512;
515  size_t n_sp=n;
516  // Domain
517  double boxP1{-1.5}, boxP2{1.5};
518  double boxSize{boxP2 - boxP1};
519  size_t sz[3] = {n,n,n};
520  double grid_spacing{boxSize/(sz[0]-1)};
521  double grid_spacing_surf=grid_spacing*30;
522  double rCut{2.5 * grid_spacing_surf};
523 
524  Box<3,double> domain{{boxP1,boxP1,boxP1},{boxP2,boxP2,boxP2}};
525  size_t bc[3] = {NON_PERIODIC,NON_PERIODIC,NON_PERIODIC};
526  Ghost<3,double> ghost{rCut + grid_spacing/8.0};
527 
528  constexpr int K = 1;
529  // particles
531  // 1. particles on the Spherical surface
532  double Golden_angle=M_PI * (3.0 - sqrt(5.0));
533  if (v_cl.rank() == 0) {
534  //std::vector<Vector3f> data;
535  //GenerateSphere(1,data);
536  std::unordered_map<const lm,double,key_hash,key_equal> Alm;
537  //Setting max mode l_max
538  //Setting amplitudes to 1
539  for(int l=0;l<=K;l++){
540  for(int m=-l;m<=l;m++){
541  Alm[std::make_tuple(l,m)]=0;
542  }
543  }
544  Alm[std::make_tuple(1,0)]=1;
545  for(int i=1;i<n_sp;i++)
546  {
547  double y = 1.0 - (i /double(n_sp - 1.0)) * 2.0;
548  double radius = sqrt(1 - y * y);
549  double Golden_theta = Golden_angle * i;
550  double x = cos(Golden_theta) * radius;
551  double z = sin(Golden_theta) * radius;
552  Sparticles.add();
553  Sparticles.getLastPos()[0] = x;
554  Sparticles.getLastPos()[1] = y;
555  Sparticles.getLastPos()[2] = z;
556  double rm=sqrt(x*x+y*y+z*z);
557  Sparticles.getLastProp<2>()[0] = x/rm;
558  Sparticles.getLastProp<2>()[1] = y/rm;
559  Sparticles.getLastProp<2>()[2] = z/rm;
560  Sparticles.getLastProp<4>()[0] = 1.0 ;
561  Sparticles.getLastProp<4>()[1] = std::atan2(sqrt(x*x+y*y),z);
562  Sparticles.getLastProp<4>()[2] = std::atan2(y,x);
563  double m1=openfpm::math::sumY_Scalar<K>(1.0,std::atan2(sqrt(x*x+y*y),z),std::atan2(y,x),Alm);
564  double m2=-(K)*(K+1)*openfpm::math::sumY_Scalar<K>(1.0,std::atan2(sqrt(x*x+y*y),z),std::atan2(y,x),Alm);
565  Sparticles.getLastProp<3>()=m1;
566  Sparticles.getLastProp<1>()=m2;
567  Sparticles.getLastSubset(0);
568  for(int j=1;j<=2;++j){
569  Sparticles.add();
570  Sparticles.getLastPos()[0] = x+j*grid_spacing_surf*x/rm;
571  Sparticles.getLastPos()[1] = y+j*grid_spacing_surf*y/rm;
572  Sparticles.getLastPos()[2] = z+j*grid_spacing_surf*z/rm;
573  Sparticles.getLastProp<3>()=m1;
574  Sparticles.getLastSubset(1);
575  //Sparticles.getLastProp<1>(p)=m2;
576  Sparticles.add();
577  Sparticles.getLastPos()[0] = x-j*grid_spacing_surf*x/rm;
578  Sparticles.getLastPos()[1] = y-j*grid_spacing_surf*y/rm;
579  Sparticles.getLastPos()[2] = z-j*grid_spacing_surf*z/rm;
580  Sparticles.getLastProp<3>()=m1;
581  Sparticles.getLastSubset(1);
582  //Sparticles.getLastProp<1>(p)=m2;
583  }
584  }
585  //std::cout << "n: " << n << " - grid spacing: " << grid_spacing << " - rCut: " << rCut << "Surf Normal spacing" << grid_spacing<<std::endl;
586  }
587 
588  Sparticles.map();
589  Sparticles.ghost_get<3>();
590  //Sparticles.write("SparticlesInit");
591 
594  auto &bulkIds=Sparticles_bulk.getIds();
595  auto &bdrIds=Sparticles_boundary.getIds();
596  /*auto it2 = Sparticles.getDomainIterator();
597  while (it2.isNext()) {
598  auto p = it2.get();
599  Point<3, double> xP = Sparticles.getProp<4>(p);
600  *//*double Sum=0;
601  for(int m=-spL;m<=spL;++m)
602  {
603  Sum+=openfpm::math::Y(spL,m,xP[1],xP[2]);
604  }*//*
605  //Sparticles.getProp<ANADF>(p) = Sum;//openfpm::math::Y(K,K,xP[1],xP[2]);openfpm::math::sumY_Scalar<K>(xP[0],xP[1],xP[2],Alm);;
606  Sparticles.getProp<3>(p)=openfpm::math::sumY_Scalar<K>(xP[0],xP[1],xP[2],Alm);
607  Sparticles.getProp<1>(p)=-(K)*(K+1)*openfpm::math::sumY_Scalar<K>(xP[0],xP[1],xP[2],Alm);
608  ++it2;
609  }*/
610  auto f=getV<3>(Sparticles);
611  auto Df=getV<0>(Sparticles);
612 
613  //SurfaceDerivative_xx<2,decltype(verletList)> Sdxx{Sparticles,2,rCut,grid_spacing_surf,static_cast<unsigned int>(rCut/grid_spacing_surf)};
614  //SurfaceDerivative_yy<2,decltype(verletList)> Sdyy{Sparticles,2,rCut,grid_spacing_surf,static_cast<unsigned int>(rCut/grid_spacing_surf)};
615  //SurfaceDerivative_zz<2,decltype(verletList)> Sdzz{Sparticles,2,rCut,grid_spacing_surf,static_cast<unsigned int>(rCut/grid_spacing_surf)};
616  auto verletList = Sparticles.template getVerlet<VL_NON_SYMMETRIC|VL_SKIP_REF_PART>(rCut);
617 
618  Derivative_xx<decltype(verletList)> Sdxx{Sparticles,verletList,2,rCut};
619  //std::cout<<"Dxx Done"<<std::endl;
620  Derivative_yy<decltype(verletList)> Sdyy{Sparticles,verletList,2,rCut};
621  //std::cout<<"Dyy Done"<<std::endl;
622  Derivative_zz<decltype(verletList)> Sdzz{Sparticles,verletList,2,rCut};
623  //std::cout<<"Dzz Done"<<std::endl;
624 
625  //Laplace_Beltrami<2> SLap{Sparticles,2,rCut,grid_spacing_surf,static_cast<unsigned int>(rCut/grid_spacing_surf)};
626  //SLap.DrawKernel<5>(Sparticles,73);
627  //Sdxx.DrawKernel<5>(Sparticles,0);
628  //Sdyy.DrawKernel<5>(Sparticles,0);
629  //Sdzz.DrawKernel<5>(Sparticles,0);
630 /* std::cout<<"SDXX:"<<std::endl;
631  Sdxx.checkMomenta(Sparticles);
632  std::cout<<"SDYY:"<<std::endl;
633  Sdyy.checkMomenta(Sparticles);
634  std::cout<<"SDZZ:"<<std::endl;
635  Sdzz.checkMomenta(Sparticles);*/
636 
637  Sparticles.ghost_get<3>();
638  Df=(Sdxx(f)+Sdyy(f)+Sdzz(f));
639  //Df=SLap(f);
640  //auto it3 = Sparticles_bulk.getDomainIterator();
641  double worst = 0.0;
642  for (int j = 0; j < bulkIds.size(); j++) {
643  auto p = bulkIds.get<0>(j);
644  //Sparticles.getProp<5>(p) = fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p));
645  if (fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p)) > worst) {
646  worst = fabs(Sparticles.getProp<1>(p) - Sparticles.getProp<0>(p));
647  }
648  }
649  Sparticles.deleteGhost();
650  //Sparticles.write("SparticlesNoo");
651  //std::cout<<"Worst: "<<worst<<std::endl;
652  BOOST_REQUIRE(worst < 0.03);
653 }
654 
655 BOOST_AUTO_TEST_CASE(dcpse_surface_adaptive_planeCart) {
656  auto & v_cl = create_vcluster();
657 
658  // lane in 2D, regular Cartesian distribution
660  openfpm::vector<std::string> propNames{"rCut","normal","function","derivative","analyt","err"};
661 
662  const int n{50}; // number of particles
663  size_t sz[3] = {n,n,n};
664  double spacing{0.02};
665 
666  Box<3,double> domain{{-0.3,-0.3,-1.5},{1.3,1.3,1.5}};
667  Ghost<3,double> ghost{spacing*2};
668  size_t bc[3] = {NON_PERIODIC,NON_PERIODIC,NON_PERIODIC};
669 
670  vector_type part{0,domain,bc,ghost};
671  part.setPropNames(propNames);
672 
673  if (v_cl.rank() == 0) {
674 
675  for (int i = 0; i < n; ++i) {
676  for (int j = 0; j < n; ++j) {
677  part.add();
678 
679  part.getLastPos()[0] = spacing*i;
680  part.getLastPos()[1] = spacing*j;
681  part.getLastPos()[2] = 0.0;
682 
683  part.getLastProp<1>()[0] = 0;
684  part.getLastProp<1>()[1] = 0;
685  part.getLastProp<1>()[2] = 1.0;
686 
687  part.getLastProp<2>() = std::sin(M_PI * part.getLastPos()[1]);
688  part.getLastProp<3>() = 0;
689  part.getLastProp<4>() = M_PI * std::cos(M_PI * part.getLastPos()[1]);
690  // rCut is always stored in the last property
691  part.getLastProp<0>() = 2*spacing;
692  }
693  }
694  }
695  part.addComputationCosts();
696  part.getDecomposition().decompose();
697  part.map();
698  part.ghost_get<0,1,2,3>();
699 
700  size_t total_n{part.size_local()};
701  v_cl.sum(total_n);
702  v_cl.execute();
703 
704 
705  std::cerr << "size local " << part.size_local() << std::endl;
706 
707  auto verletList = part.template getVerletAdaptRCut<>();
708 
709  SurfaceDerivative_y<1,decltype(verletList)> Sdy{part,verletList,2,0,0,2,support_options::ADAPTIVE}; // rCut is not used in the function
710  auto f = getV<2>(part);
711  auto Df = getV<3>(part);
712  Df = Sdy(f);
713 
714  // "rCut","normal","function","derivative","analyt","err"
715  // Computing error -------------------------------------------------------------------
716  {
717  double maxErr{0}, l2err{0}, maxRel_err{0}, l2rel_err{0};
718  double err, rel_err;
719  auto pit{part.getDomainIterator()};
720  while (pit.isNext()) {
721  auto key{pit.get()};
722 
723  err = std::abs(part.getProp<4>(key) - part.getProp<3>(key));
724  rel_err = err/std::abs(part.getProp<4>(key));
725  part.getProp<5>(key) = err;
726 
727  maxErr = std::max(maxErr,err);
728  maxRel_err = std::max(maxRel_err,rel_err);
729  l2err += err*err;
730  l2rel_err += rel_err*rel_err;
731 
732  ++pit;
733  }
734  v_cl.max(maxErr);
735  v_cl.max(maxRel_err);
736  v_cl.sum(l2err);
737  v_cl.sum(l2rel_err);
738  v_cl.execute();
739 
740  // L2 and Linf norms
741  double linf_norm{maxErr};
742  double l2_norm{std::sqrt(l2err/double(total_n))};
743 
744  double linf_rel_norm{maxRel_err};
745  double l2_rel_norm{std::sqrt(l2rel_err/double(total_n))};
746 
747  // if (v_cl.rank() == 0)
748  // std::cout << total_n << " " << std::setprecision(6) << std::scientific << " " << l2_norm << " " << linf_norm << " " << l2_rel_norm << " " << linf_rel_norm << std::endl;
749  BOOST_REQUIRE_CLOSE(l2_norm,8.657329e-02,0.1);
750  BOOST_REQUIRE_CLOSE(linf_norm,7.108664e-01,0.1);
751  }
752 }
753 
754 BOOST_AUTO_TEST_CASE(dcpse_surface_adaptive_unitSphere) {
755 
756  auto & v_cl = create_vcluster();
757 
759  openfpm::vector<std::string> propNames{"rCut","normal","function","lap_adaptive","lap_regular","analyt","err_adaptive","err_regular"};
760 
761  size_t n{2000};
762  double part_spacing{std::sqrt(4*3.14159265358979323846/n)};
763  Box<3,double> domain{{-1.5,-1.5,-1.5},{1.5,1.5,1.5}};
764  Ghost<3,double> ghost{2*part_spacing};
765  size_t bc[3] = {NON_PERIODIC,NON_PERIODIC,NON_PERIODIC};
766  std::array<double,3> center{0,0,0};
767 
768  vector_type part{0,domain,bc,ghost};
769  part.setPropNames(propNames);
770 
771  if (v_cl.rank() == 0) {
772 
773  // Created using the Fibonacci sphere algorithm
774  // const double M_PI{3.14159265358979323846};
775  const double golden_ang = M_PI*(3.0 - std::sqrt(5.0));
776  const double prefactor{std::sqrt(0.75/M_PI)};
777  double rad, theta, arg, thetaB, phi, phi_norm;
778  std::array<double,3> coord;
779 
780  for (int i = 0; i < n; ++i) {
781 
782  coord[1] = 1.0 - 2.0*(i/double(n-1));
783  rad = std::sqrt(1.0 - (coord[1]-center[1])*(coord[1]-center[1]));
784  theta = golden_ang * i;
785  coord[0] = std::cos(theta) * rad;
786  coord[2] = std::sin(theta) * rad;
787 
788  arg = (coord[0]-center[0]) * (coord[0]-center[0]) + (coord[1]-center[1]) * (coord[1]-center[1]);
789  thetaB = std::atan2(std::sqrt(arg),(coord[2]-center[2]));
790  phi = std::atan2((coord[1]-center[1]),(coord[0]-center[0]));
791 
792  part.add();
793  part.getLastPos()[0] = coord[0];
794  part.getLastPos()[1] = coord[1];
795  part.getLastPos()[2] = coord[2];
796 
797  // normal
798  part.getLastProp<1>()[0] = std::sin(thetaB)*std::cos(phi);
799  part.getLastProp<1>()[1] = std::sin(thetaB)*std::sin(phi);
800  part.getLastProp<1>()[2] = std::cos(thetaB);
801 
802  part.getLastProp<0>() = 2*part_spacing; // rcut
803  // rCut is always stored in the last property
804  part.getLastProp<2>() = 0.25*std::sqrt(5/M_PI) * (3 * std::cos(thetaB) * std::cos(thetaB) - 1); // function: Y_{20}
805  part.getLastProp<3>() = 0.0; // lap_adapt
806  part.getLastProp<4>() = 0.0; // lap_reg
807  part.getLastProp<5>() = -6 * part.getLastProp<2>(); // analyt
808 
809  }
810  }
811  part.map();
812  part.ghost_get<0,1,2>();
813 
814  size_t total_n{part.size_local()};
815  v_cl.sum(total_n);
816  v_cl.execute();
817 
818  // Verlet_reg
819  auto verletList_reg = part.template getVerlet<>(2*part_spacing);
820 
821  // Verlet_adapt
822  auto verletList_adapt = part.template getVerletAdaptRCut<>();
823 
824  // Lap_reg
825  SurfaceDerivative_xx<1,decltype(verletList_reg)> Sdxx_reg{part,verletList_reg,2,0,part_spacing,2};
826  SurfaceDerivative_yy<1,decltype(verletList_reg)> Sdyy_reg{part,verletList_reg,2,0,part_spacing,2};
827  SurfaceDerivative_zz<1,decltype(verletList_reg)> Sdzz_reg{part,verletList_reg,2,0,part_spacing,2};
828 
829  // Lap_adapt
830  SurfaceDerivative_xx<1,decltype(verletList_adapt)> Sdxx_adapt{part,verletList_adapt,2,0,0,2,support_options::ADAPTIVE};
831  SurfaceDerivative_yy<1,decltype(verletList_adapt)> Sdyy_adapt{part,verletList_adapt,2,0,0,2,support_options::ADAPTIVE};
832  SurfaceDerivative_zz<1,decltype(verletList_adapt)> Sdzz_adapt{part,verletList_adapt,2,0,0,2,support_options::ADAPTIVE};
833 
834  auto f{getV<2>(part)};
835  auto lap_reg{getV<4>(part)};
836  auto lap_adapt{getV<3>(part)};
837  lap_reg = Sdxx_reg(f) + Sdyy_reg(f)+ Sdzz_reg(f);
838  lap_adapt = Sdxx_adapt(f) + Sdyy_adapt(f)+ Sdzz_adapt(f);
839 
840  // Computing error -------------------------------------------------------------------
841  {
842  double maxErr_reg{0}, l2err_reg{0}, maxRel_err_reg{0}, l2rel_err_reg{0};
843  double err_reg, rel_err_reg;
844  double maxErr_adapt{0}, l2err_adapt{0}, maxRel_err_adapt{0}, l2rel_err_adapt{0};
845  double err_adapt, rel_err_adapt;
846  auto pit{part.getDomainIterator()};
847  while (pit.isNext()) {
848  auto key{pit.get()};
849 
850  err_reg = std::abs(part.getProp<4>(key) - part.getProp<5>(key));
851  rel_err_reg = err_reg/std::abs(part.getProp<5>(key));
852  part.getProp<7>(key) = err_reg;
853 
854  maxErr_reg = std::max(maxErr_reg,err_reg);
855  maxRel_err_reg = std::max(maxRel_err_reg,rel_err_reg);
856  l2err_reg += err_reg*err_reg;
857  l2rel_err_reg += rel_err_reg*rel_err_reg;
858 
859  err_adapt = std::abs(part.getProp<3>(key) - part.getProp<5>(key));
860  rel_err_adapt = err_adapt/std::abs(part.getProp<5>(key));
861  part.getProp<6>(key) = err_adapt;
862 
863  maxErr_adapt = std::max(maxErr_adapt,err_adapt);
864  maxRel_err_adapt = std::max(maxRel_err_adapt,rel_err_adapt);
865  l2err_adapt += err_adapt*err_adapt;
866  l2rel_err_adapt += rel_err_adapt*rel_err_adapt;
867 
868  ++pit;
869  }
870  v_cl.max(maxErr_reg);
871  v_cl.max(maxRel_err_reg);
872  v_cl.sum(l2err_reg);
873  v_cl.sum(l2rel_err_reg);
874  v_cl.max(maxErr_adapt);
875  v_cl.max(maxRel_err_adapt);
876  v_cl.sum(l2err_adapt);
877  v_cl.sum(l2rel_err_adapt);
878  v_cl.execute();
879 
880  // L2 and Linf norms
881  double linf_norm_reg{maxErr_reg};
882  double l2_norm_reg{std::sqrt(l2err_reg/double(total_n))};
883 
884  double linf_rel_norm_reg{maxRel_err_reg};
885  double l2_rel_norm_reg{std::sqrt(l2rel_err_reg/double(total_n))};
886 
887  double linf_norm_adapt{maxErr_adapt};
888  double l2_norm_adapt{std::sqrt(l2err_adapt/double(total_n))};
889 
890  double linf_rel_norm_adapt{maxRel_err_adapt};
891  double l2_rel_norm_adapt{std::sqrt(l2rel_err_adapt/double(total_n))};
892 
893  // In case of debugging
894  // if (v_cl.rank() == 0) {
895  // std::cout << "reg: " << total_n << " " << std::setprecision(6) << std::scientific << " " << l2_norm_reg << " " << linf_norm_reg << " " << l2_rel_norm_reg << " " << linf_rel_norm_reg << std::endl;
896  // std::cout << "adapt: " << total_n << " " << std::setprecision(6) << std::scientific << " " << l2_norm_adapt << " " << linf_norm_adapt << " " << l2_rel_norm_adapt << " " << linf_rel_norm_adapt << std::endl;
897  // }
898  // }
899  BOOST_REQUIRE_CLOSE(l2_norm_reg,l2_norm_adapt,0.001);
900  BOOST_REQUIRE_CLOSE(linf_norm_reg,linf_norm_adapt,0.001);
901  BOOST_REQUIRE_CLOSE(l2_rel_norm_reg,l2_rel_norm_adapt,0.001);
902  BOOST_REQUIRE_CLOSE(linf_rel_norm_reg,linf_rel_norm_adapt,0.001);
903  }
904 }
905 //
906 // BOOST_AUTO_TEST_CASE(dcpse_surface_adaptive_load) {
907 // // int rank;
908 // // MPI_Comm_rank(MPI_COMM_WORLD, &rank);
909 // const size_t sz[3] = {81,81,1};
910 // Box<3, double> box({0, 0,-5}, {0.5, 0.5,5});
911 // size_t bc[3] = {NON_PERIODIC, NON_PERIODIC,NON_PERIODIC};
912 // double spacing = box.getHigh(0) / (sz[0] - 1);
913 // Ghost<3, double> ghost(spacing * 3.1);
914 // double rCut = 3.1 * spacing;
915 // BOOST_TEST_MESSAGE("Init vector_dist...");
916 
917 // vector_dist<3, double, aggregate<double,double,double,double,double,double,double[3]>> domain(0, box, bc, ghost);
918 
919 
920 // //Init_DCPSE(domain)
921 // BOOST_TEST_MESSAGE("Init domain...");
922 
923 // auto it = domain.getGridIterator(sz);
924 // while (it.isNext()) {
925 // domain.add();
926 
927 // auto key = it.get();
928 // double x = key.get(0) * it.getSpacing(0);
929 // domain.getLastPos()[0] = x;
930 // double y = key.get(1) * it.getSpacing(1);
931 // domain.getLastPos()[1] = y;
932 
933 // domain.getLastPos()[2] = 0;
934 
935 // ++it;
936 // }
937 
938 // // Add multi res patch 1
939 
940 // {
941 // const size_t sz2[3] = {40,40,1};
942 // Box<3,double> bx({0.25 + it.getSpacing(0)/4.0,0.25 + it.getSpacing(0)/4.0,-0.5},{sz2[0]*it.getSpacing(0)/2.0 + 0.25 + it.getSpacing(0)/4.0, sz2[1]*it.getSpacing(0)/2.0 + 0.25 + it.getSpacing(0)/4.0,0.5});
943 // openfpm::vector<size_t> rem;
944 
945 // auto it = domain.getDomainIterator();
946 
947 // while (it.isNext())
948 // {
949 // auto k = it.get();
950 
951 // Point<3,double> xp = domain.getPos(k);
952 
953 // if (bx.isInside(xp) == true)
954 // {
955 // rem.add(k.getKey());
956 // }
957 
958 // ++it;
959 // }
960 
961 // domain.remove(rem);
962 
963 // auto it2 = domain.getGridIterator(sz2);
964 // while (it2.isNext()) {
965 // domain.add();
966 
967 // auto key = it2.get();
968 // double x = key.get(0) * spacing/2.0 + 0.25 + spacing/4.0;
969 // domain.getLastPos()[0] = x;
970 // double y = key.get(1) * spacing/2.0 + 0.25 + spacing/4.0;
971 // domain.getLastPos()[1] = y;
972 // domain.getLastPos()[2] = 0;
973 
974 // ++it2;
975 // }
976 // }
977 
978 // // Add multi res patch 2
979 
980 // {
981 // const size_t sz2[3] = {40,40,1};
982 // Box<3,double> bx({0.25 + 21.0*spacing/8.0,0.25 + 21.0*spacing/8.0,-5},{sz2[0]*spacing/4.0 + 0.25 + 21.0*spacing/8.0, sz2[1]*spacing/4.0 + 0.25 + 21*spacing/8.0,5});
983 // openfpm::vector<size_t> rem;
984 
985 // auto it = domain.getDomainIterator();
986 
987 // while (it.isNext())
988 // {
989 // auto k = it.get();
990 
991 // Point<3,double> xp = domain.getPos(k);
992 
993 // if (bx.isInside(xp) == true)
994 // {
995 // rem.add(k.getKey());
996 // }
997 
998 // ++it;
999 // }
1000 
1001 // domain.remove(rem);
1002 
1003 // auto it2 = domain.getGridIterator(sz2);
1004 // while (it2.isNext()) {
1005 // domain.add();
1006 
1007 // auto key = it2.get();
1008 // double x = key.get(0) * spacing/4.0 + 0.25 + 21*spacing/8.0;
1009 // domain.getLastPos()[0] = x;
1010 // double y = key.get(1) * spacing/4.0 + 0.25 + 21*spacing/8.0;
1011 // domain.getLastPos()[1] = y;
1012 // domain.getLastPos()[2] = 0;
1013 
1014 // ++it2;
1015 // }
1016 // }
1017 
1018 // ///////////////////////
1019 
1020 // BOOST_TEST_MESSAGE("Sync domain across processors...");
1021 
1022 // domain.map();
1023 // domain.ghost_get<0>();
1024 
1025 // openfpm::vector<aggregate<int>> bulk;
1026 // openfpm::vector<aggregate<int>> up_p;
1027 // openfpm::vector<aggregate<int>> dw_p;
1028 // openfpm::vector<aggregate<int>> l_p;
1029 // openfpm::vector<aggregate<int>> r_p;
1030 // openfpm::vector<aggregate<int>> ref_p;
1031 
1032 // auto v = getV<0>(domain);
1033 // auto RHS=getV<1>(domain);
1034 // auto sol = getV<2>(domain);
1035 // auto anasol = getV<3>(domain);
1036 // auto err = getV<4>(domain);
1037 // auto DCPSE_sol=getV<5>(domain);
1038 
1039 // // Here fill me
1040 
1041 // Box<3, double> up({box.getLow(0) - spacing / 2.0, box.getHigh(1) - spacing / 2.0,-5},
1042 // {box.getHigh(0) + spacing / 2.0, box.getHigh(1) + spacing / 2.0,5});
1043 
1044 // Box<3, double> down({box.getLow(0) - spacing / 2.0, box.getLow(1) - spacing / 2.0,-5},
1045 // {box.getHigh(0) + spacing / 2.0, box.getLow(1) + spacing / 2.0,5});
1046 
1047 // Box<3, double> left({box.getLow(0) - spacing / 2.0, box.getLow(1) + spacing / 2.0,-5},
1048 // {box.getLow(0) + spacing / 2.0, box.getHigh(1) - spacing / 2.0,5});
1049 
1050 // Box<3, double> right({box.getHigh(0) - spacing / 2.0, box.getLow(1) + spacing / 2.0,-5},
1051 // {box.getHigh(0) + spacing / 2.0, box.getHigh(1) - spacing / 2.0,5});
1052 
1053 // openfpm::vector<Box<3, double>> boxes;
1054 // boxes.add(up);
1055 // boxes.add(down);
1056 // boxes.add(left);
1057 // boxes.add(right);
1058 
1059 // // Create a writer and write
1060 // VTKWriter<openfpm::vector<Box<3, double>>, VECTOR_BOX> vtk_box;
1061 // vtk_box.add(boxes);
1062 // //vtk_box.write("vtk_box.vtk");
1063 
1064 
1065 // auto it2 = domain.getDomainIterator();
1066 
1067 // while (it2.isNext()) {
1068 // auto p = it2.get();
1069 // Point<3, double> xp = domain.getPos(p);
1070 // if (up.isInside(xp) == true) {
1071 // up_p.add();
1072 // up_p.last().get<0>() = p.getKey();
1073 // domain.getProp<1>(p) = -2*M_PI*M_PI*sin(M_PI*xp.get(0))*sin(M_PI*xp.get(1));
1074 // domain.getProp<3>(p) = sin(M_PI*xp.get(0))*sin(M_PI*xp.get(1));
1075 // } else if (down.isInside(xp) == true) {
1076 // dw_p.add();
1077 // dw_p.last().get<0>() = p.getKey();
1078 // domain.getProp<1>(p) = -2*M_PI*M_PI*sin(M_PI*xp.get(0))*sin(M_PI*xp.get(1));
1079 // domain.getProp<3>(p) = sin(M_PI*xp.get(0))*sin(M_PI*xp.get(1));
1080 
1081 // } else if (left.isInside(xp) == true) {
1082 // l_p.add();
1083 // l_p.last().get<0>() = p.getKey();
1084 // domain.getProp<1>(p) = -2*M_PI*M_PI*sin(M_PI*xp.get(0))*sin(M_PI*xp.get(1));
1085 // domain.getProp<3>(p) = sin(M_PI*xp.get(0))*sin(M_PI*xp.get(1));
1086 
1087 // } else if (right.isInside(xp) == true) {
1088 // r_p.add();
1089 // r_p.last().get<0>() = p.getKey();
1090 // domain.getProp<1>(p) = -2*M_PI*M_PI*sin(M_PI*xp.get(0))*sin(M_PI*xp.get(1));
1091 // domain.getProp<3>(p) = sin(M_PI*xp.get(0))*sin(M_PI*xp.get(1));
1092 
1093 // } else {
1094 // bulk.add();
1095 // bulk.last().get<0>() = p.getKey();
1096 // domain.getProp<1>(p) = -2*M_PI*M_PI*sin(M_PI*xp.get(0))*sin(M_PI*xp.get(1));
1097 // domain.getProp<3>(p) = sin(M_PI*xp.get(0))*sin(M_PI*xp.get(1));
1098 // }
1099 // domain.getProp<6>(p)[0] = 0;
1100 // domain.getProp<6>(p)[1] = 0;
1101 // domain.getProp<6>(p)[2] = 1;
1102 
1103 // ++it2;
1104 // }
1105 
1106 // domain.ghost_get<1,2,3>();
1107 
1108 // auto verletList = domain.template getVerlet<VL_NON_SYMMETRIC|VL_SKIP_REF_PART>(rCut);
1109 
1110 // SurfaceDerivative_xx<6,decltype(verletList)> Dxx(domain, verletList, 2, rCut, 3.9, static_cast<unsigned int>(rCut/spacing), support_options::LOAD);
1111 // SurfaceDerivative_yy<6,decltype(verletList)> Dyy(domain, verletList, 2, rCut, 3.9, static_cast<unsigned int>(rCut/spacing), support_options::LOAD);
1112 // SurfaceDerivative_zz<6,decltype(verletList)> Dzz(domain, verletList, 2, rCut, 3.9, static_cast<unsigned int>(rCut/spacing), support_options::LOAD);
1113 // Dxx.load(domain,"Sdxx_test");
1114 // Dyy.load(domain,"Sdyy_test");
1115 // Dzz.load(domain,"Sdzz_test");
1116 
1117 // domain.ghost_get<2>();
1118 // sol=Dxx(anasol)+Dyy(anasol)+Dzz(anasol);
1119 // domain.ghost_get<5>();
1120 
1121 // double worst1 = 0.0;
1122 
1123 // for(int j=0;j<bulk.size();j++)
1124 // { auto p=bulk.get<0>(j);
1125 // if (fabs(domain.getProp<1>(p) - domain.getProp<2>(p)) >= worst1) {
1126 // worst1 = fabs(domain.getProp<1>(p) - domain.getProp<2>(p));
1127 // }
1128 // domain.getProp<4>(p) = fabs(domain.getProp<1>(p) - domain.getProp<2>(p));
1129 
1130 // }
1131 // //std::cout << "Maximum Analytic Error: " << worst1 << std::endl;
1132 
1133 // //domain.ghost_get<4>();
1134 // //domain.write("Robin_anasol");
1135 // BOOST_REQUIRE(worst1 < 0.03);
1136 
1137 // }
1138 
1139 // Added by foggia on 08.03.2024
1140 BOOST_AUTO_TEST_CASE(dcpse_surface_tensor_gradient) {
1141 
1142  // DIM is 3
1143  Vcluster<> & v_cl = create_vcluster();
1144  constexpr int VEC{0}; // vector - [DIM]
1145  constexpr int NORMAL{1}; // vector - [DIM]
1146  constexpr int PROJMAT{2}; // matrix - [DIM]x[DIM]
1147  constexpr int EUCGRAD{3}; // matrix - [DIM]x[DIM]
1148  constexpr int SGRAD{4}; // matrix - [DIM]x[DIM]
1149  constexpr int DSGRAD{5}; // matrix - [DIM]x[DIM]x[DIM]
1150  constexpr int LAP{6}; // vector - [DIM]
1151  constexpr int ANALYTLAP{7}; // vector - [DIM]
1152 
1154  // vector field, normal field, projection matrix, euclidean gradient, surface gradient, derivative of surface gradient, surface laplacian, analytical surf laplacian
1155 
1156  openfpm::vector<std::string> propNames{"vector","normal","projmat","eucGrad","surfGrad","DSurfGrad","lap","analyt_lap"};
1158 
1159  size_t part_set_size[3] = {4000, 8000, 16000};
1160  double L2norms_conv[3] = {0,0,0};
1161  double Linfnorms_conv[3] = {0,0,0};
1162 
1163  // Test for three different configurations to check for convergence
1164  for (int ll = 0; ll < 3; ++ll) {
1165 
1166  size_t n_part{part_set_size[ll]};
1167  double rCut{3.1};
1168 
1169  size_t sz[3] = {n_part,n_part,n_part};
1170  double grid_spacing{0.8/((std::pow(sz[0],1/3.0)-1))};
1171  double grid_spacing_surf{grid_spacing};
1172 
1173  Box<3,double> domain{{-2,-2,-2},{2,2,2}};
1174  Ghost<3,double> ghost{rCut*grid_spacing + grid_spacing/8.0};
1175  size_t bc[3] = {NON_PERIODIC,NON_PERIODIC,NON_PERIODIC};
1176 
1177  vector_type part{0,domain,bc,ghost};
1178  part.setPropNames(propNames);
1179 
1180  std::array<double,3> center{0,0,0};
1181  std::array<double,3> coord;
1182 
1183  if (v_cl.rank() == 0) {
1184 
1185  // Created using the Fibonacci sphere algorithm
1186  const double pi{3.14159265358979323846};
1187  const double golden_ang = pi*(3.0 - std::sqrt(5.0));
1188  const double prefactor{std::sqrt(0.75/pi)};
1189  double rad, theta, arg, thetaB, phi, phi_norm;
1190 
1191  for (int i = 0; i < n_part; ++i) {
1192 
1193  coord[1] = 1.0 - 2.0*(i/double(n_part-1));
1194  rad = std::sqrt(1.0 - (coord[1]-center[1])*(coord[1]-center[1]));
1195  theta = golden_ang * i;
1196  coord[0] = std::cos(theta) * rad;
1197  coord[2] = std::sin(theta) * rad;
1198 
1199  arg = (coord[0]-center[0]) * (coord[0]-center[0]) + (coord[1]-center[1]) * (coord[1]-center[1]);
1200  thetaB = std::atan2(std::sqrt(arg),(coord[2]-center[2]));
1201  phi = std::atan2((coord[1]-center[1]),(coord[0]-center[0]));
1202 
1203  part.add();
1204  part.getLastPos()[0] = coord[0];
1205  part.getLastPos()[1] = coord[1];
1206  part.getLastPos()[2] = coord[2];
1207 
1208  // Vector field
1209  // \Phi_{30} = \hat{r} \times \nabla_S Y_{30}
1210  // \Phi_{30} = 3/4 * sqrt(7/pi) * (1 - 5*cos(theta)*cos(theta)) * sin(theta) \hat(e_phi or phi)
1211  part.getLastProp<VEC>()[0] = - 3.0/4.0 * std::sqrt(7.0/pi) * (1.0 - 5.0 * std::cos(thetaB) * std::cos(thetaB)) * std::sin(thetaB) * std::sin(phi);
1212  part.getLastProp<VEC>()[1] = 3.0/4.0 * std::sqrt(7.0/pi) * (1.0 - 5.0 * std::cos(thetaB) * std::cos(thetaB)) * std::sin(thetaB) * std::cos(phi);
1213  part.getLastProp<VEC>()[2] = 0.0;
1214 
1215  // \Phi_{10} = \hat{r} \times \nabla_S Y_{10} = -sqrt(3/4pi) sin(theta) \hat(e_phi or phi) --> normalized basis, convariant/contravariant
1216  // \Phi_{10} = -sqrt(3/4pi) \hat(phi) --> non-normalized basis, contravariant
1217  // part.getLastProp<VEC>()[0] = std::sqrt(3.0/(4.0*pi)) * std::sin(thetaB) * std::sin(phi);
1218  // part.getLastProp<VEC>()[1] = - std::sqrt(3.0/(4.0*pi)) * std::sin(thetaB) * std::cos(phi);
1219  // part.getLastProp<VEC>()[2] = 0;
1220 
1221  // Analytical solution
1222  part.getLastProp<ANALYTLAP>()[0] = 11.0 * 3.0/4.0 * std::sqrt(7.0/pi) * (1.0 - 5.0 * std::cos(thetaB) * std::cos(thetaB)) * std::sin(thetaB) * std::sin(phi);
1223  part.getLastProp<ANALYTLAP>()[1] = - 11.0 * 3.0/4.0 * std::sqrt(7.0/pi) * (1.0 - 5.0 * std::cos(thetaB) * std::cos(thetaB)) * std::sin(thetaB) * std::cos(phi);
1224  part.getLastProp<ANALYTLAP>()[2] = 0.0;
1225 
1226  // part.getLastProp<ANALYTLAP>()[0] = -1.0 * std::sqrt(3.0/(4.0*pi)) * std::sin(thetaB) * std::sin(phi);
1227  // part.getLastProp<ANALYTLAP>()[1] = -1.0 * (- std::sqrt(3.0/(4.0*pi)) * std::sin(thetaB) * std::cos(phi));
1228  // part.getLastProp<ANALYTLAP>()[2] = 0;
1229 
1230  // Normal field
1231  part.getLastProp<NORMAL>()[0] = std::sin(thetaB)*std::cos(phi);
1232  part.getLastProp<NORMAL>()[1] = std::sin(thetaB)*std::sin(phi);
1233  part.getLastProp<NORMAL>()[2] = std::cos(thetaB);
1234 
1235  // Projection matrix
1236  double ni, nj;
1237  for (int i = 0; i < 3; ++i) {
1238  ni = part.getLastProp<NORMAL>()[i];
1239  for (int j = 0; j < 3; ++j) {
1240  nj = part.getLastProp<NORMAL>()[j];
1241  part.getLastProp<PROJMAT>()[i][j] = (i==j)*(1-ni*nj) - !(i==j)*(ni*nj);
1242  }
1243  }
1244  } // particle creation loop
1245  } // v_cl.rank == 0
1246 
1247  part.map();
1248  part.ghost_get<VEC,PROJMAT,NORMAL>();
1249 
1250  // Create Surface DC-PSE operators
1251  auto verletList = part.template getVerlet<VL_NON_SYMMETRIC|VL_SKIP_REF_PART>(rCut*grid_spacing);
1252  SurfaceDerivative_x<NORMAL,decltype(verletList)> Sdx{part,verletList,3,rCut*grid_spacing,grid_spacing_surf,static_cast<unsigned int>(rCut*grid_spacing/grid_spacing_surf)};
1253  SurfaceDerivative_y<NORMAL,decltype(verletList)> Sdy{part,verletList,3,rCut*grid_spacing,grid_spacing_surf,static_cast<unsigned int>(rCut*grid_spacing/grid_spacing_surf)};
1254  SurfaceDerivative_z<NORMAL,decltype(verletList)> Sdz{part,verletList,3,rCut*grid_spacing,grid_spacing_surf,static_cast<unsigned int>(rCut*grid_spacing/grid_spacing_surf)};
1255 
1256  // Create expressions for fields
1257  auto vec{getV<VEC>(part)};
1258  auto projMat{getV<PROJMAT>(part)};
1259  auto eucGrad{getV<EUCGRAD>(part)};
1260  auto SGrad{getV<SGRAD>(part)};
1261  auto dSGrad{getV<DSGRAD>(part)};
1262  auto lap{getV<LAP>(part)};
1263 
1264  // Set LAP and SGRAD to zero
1265  SGrad[0][0] = 0;
1266  SGrad[0][1] = 0;
1267  SGrad[0][2] = 0;
1268 
1269  SGrad[1][0] = 0;
1270  SGrad[1][1] = 0;
1271  SGrad[1][2] = 0;
1272 
1273  SGrad[2][0] = 0;
1274  SGrad[2][1] = 0;
1275  SGrad[2][2] = 0;
1276 
1277  lap[0] = 0;
1278  lap[1] = 0;
1279  lap[2] = 0;
1280  part.template ghost_get<SGRAD,LAP>();
1281 
1282  // 1) Surface gradient
1283  eucGrad[0][0] = Sdx(vec[0]);
1284  eucGrad[0][1] = Sdy(vec[0]);
1285  eucGrad[0][2] = Sdz(vec[0]);
1286 
1287  eucGrad[1][0] = Sdx(vec[1]);
1288  eucGrad[1][1] = Sdy(vec[1]);
1289  eucGrad[1][2] = Sdz(vec[1]);
1290 
1291  eucGrad[2][0] = Sdx(vec[2]);
1292  eucGrad[2][1] = Sdy(vec[2]);
1293  eucGrad[2][2] = Sdz(vec[2]);
1294  part.template ghost_get<EUCGRAD>();
1295 
1296  for (int l = 0; l < 3; ++l)
1297  for (int k = 0; k < 3; ++k)
1298  for (int t = 0; t < 3; ++t)
1299  for (int h = 0; h < 3; ++h)
1300  SGrad[l][k] = projMat[l][t] * projMat[k][h] * eucGrad[t][h] + SGrad[l][k];
1301  part.template ghost_get<SGRAD>();
1302 
1303  {
1304  // Check if quantities involved (v) are tangent: n.v = 0? direction 1
1305  double dot_prod[3];
1306  auto it1{part.getDomainIterator()};
1307  while (it1.isNext()) {
1308  auto key{it1.get()};
1309 
1310  for (int d1 = 0; d1 < 3; ++d1) {
1311  dot_prod[d1] = 0.0;
1312  for (int d2 = 0; d2 < 3; ++d2)
1313  dot_prod[d1] += part.template getProp<SGRAD>(key)[d1][d2] * part.template getProp<NORMAL>(key)[d2];
1314 
1315  if (std::fabs(dot_prod[d1]) > 1e-14)
1316  std::cout << key.to_string() << " not tangent\n";
1317  }
1318 
1319  ++it1;
1320  }
1321  }
1322 
1323  {
1324  // Check if quantities involved (v) are tangent: n.v = 0? direction 2
1325  double dot_prod[3];
1326  auto it1{part.getDomainIterator()};
1327  while (it1.isNext()) {
1328  auto key{it1.get()};
1329 
1330  for (int d1 = 0; d1 < 3; ++d1) {
1331  dot_prod[d1] = 0.0;
1332  for (int d2 = 0; d2 < 3; ++d2)
1333  dot_prod[d1] += part.template getProp<SGRAD>(key)[d2][d1] * part.template getProp<NORMAL>(key)[d2];
1334 
1335  if (std::fabs(dot_prod[d1]) > 1e-14)
1336  std::cout << key.to_string() << " not tangent\n";
1337  }
1338 
1339  ++it1;
1340  }
1341  }
1342 
1343  // 2) Surface Laplacian
1344  for (int d1 = 0; d1 < 3; ++d1)
1345  for (int d2 = 0; d2 < 3; ++d2) {
1346  dSGrad[d1][d2][0] = Sdx(SGrad[d1][d2]);
1347  dSGrad[d1][d2][1] = Sdy(SGrad[d1][d2]);
1348  dSGrad[d1][d2][2] = Sdz(SGrad[d1][d2]);
1349  }
1350 
1351  // dSGrad[0][0][0] = Sdx(SGrad[0][0]);
1352  // dSGrad[0][0][1] = Sdy(SGrad[0][0]);
1353  // dSGrad[0][0][2] = Sdz(SGrad[0][0]);
1354 
1355  // dSGrad[0][1][0] = Sdx(SGrad[0][1]);
1356  // dSGrad[0][1][1] = Sdy(SGrad[0][1]);
1357  // dSGrad[0][1][2] = Sdz(SGrad[0][1]);
1358 
1359  // dSGrad[0][2][0] = Sdx(SGrad[0][2]);
1360  // dSGrad[0][2][1] = Sdy(SGrad[0][2]);
1361  // dSGrad[0][2][2] = Sdz(SGrad[0][2]);
1362 
1363 
1364  // dSGrad[1][0][0] = Sdx(SGrad[1][0]);
1365  // dSGrad[1][0][1] = Sdy(SGrad[1][0]);
1366  // dSGrad[1][0][2] = Sdz(SGrad[1][0]);
1367 
1368  // dSGrad[1][1][0] = Sdx(SGrad[1][1]);
1369  // dSGrad[1][1][1] = Sdy(SGrad[1][1]);
1370  // dSGrad[1][1][2] = Sdz(SGrad[1][1]);
1371 
1372  // dSGrad[1][2][0] = Sdx(SGrad[1][2]);
1373  // dSGrad[1][2][1] = Sdy(SGrad[1][2]);
1374  // dSGrad[1][2][2] = Sdz(SGrad[1][2]);
1375 
1376 
1377  // dSGrad[2][0][0] = Sdx(SGrad[2][0]);
1378  // dSGrad[2][0][1] = Sdy(SGrad[2][0]);
1379  // dSGrad[2][0][2] = Sdz(SGrad[2][0]);
1380 
1381  // dSGrad[2][1][0] = Sdx(SGrad[2][1]);
1382  // dSGrad[2][1][1] = Sdy(SGrad[2][1]);
1383  // dSGrad[2][1][2] = Sdz(SGrad[2][1]);
1384 
1385  // dSGrad[2][2][0] = Sdx(SGrad[2][2]);
1386  // dSGrad[2][2][1] = Sdy(SGrad[2][2]);
1387  // dSGrad[2][2][2] = Sdz(SGrad[2][2]);
1388  part.template ghost_get<DSGRAD>();
1389 
1390  for (int i = 0; i < 3; ++i)
1391  for (int l = 0; l < 3; ++l)
1392  for (int k = 0; k < 3; ++k)
1393  for (int m = 0; m < 3; ++m) {
1394  lap[i] = projMat[i][l] * projMat[k][m] * dSGrad[l][k][m] + lap[i];
1395  }
1396  part.template ghost_get<LAP>();
1397 
1398  {
1399  // Check if quantities involved (v) are tangent: n.v = 0?
1400  auto it1{part.getDomainIterator()};
1401  while (it1.isNext()) {
1402  double dot_prod{0};
1403  auto key{it1.get()};
1404  for (int d1 = 0; d1 < 3; ++d1)
1405  dot_prod += part.template getProp<LAP>(key)[d1] * part.template getProp<NORMAL>(key)[d1];
1406 
1407  if (std::fabs(dot_prod) > 1e-14)
1408  std::cout << key.to_string() << " not tangent\n";
1409 
1410  ++it1;
1411  }
1412  }
1413 
1414  // 2. Norm and angle with theta unit vector ------------------------------------------
1415  {
1416  double maxErr{0}, l2err{0};
1417  double err, abs_lap;
1418  auto pit{part.getDomainIterator()};
1419  while (pit.isNext()) {
1420  auto key{pit.get()};
1421 
1422  err = 0.0;
1423  abs_lap = 0;
1424  for (int d = 0; d < 3; ++d) {
1425  err += (part.getProp<ANALYTLAP>(key)[d] - part.getProp<LAP>(key)[d]) * (part.getProp<ANALYTLAP>(key)[d] - part.getProp<LAP>(key)[d]);
1426  abs_lap += part.getProp<LAP>(key)[d] * part.getProp<LAP>(key)[d];
1427  }
1428  l2err += err;
1429  err = std::sqrt(err);
1430  maxErr = std::max(maxErr,err);
1431 
1432  ++pit;
1433  }
1434  v_cl.max(maxErr);
1435  v_cl.sum(l2err);
1436  v_cl.execute();
1437 
1438  // L2 and Linf norms
1439  double linf_normLap{maxErr};
1440  double l2_normLap{std::sqrt(l2err/double(n_part))};
1441 
1442  L2norms_conv[ll] = l2_normLap;
1443  Linfnorms_conv[ll] = linf_normLap;
1444 
1445  if (v_cl.rank() == 0)
1446  std::cout << n_part << " " << std::setprecision(6) << std::scientific << grid_spacing << " " << l2_normLap << " " << linf_normLap << std::endl;
1447  }
1448 
1449  part.deleteGhost();
1450  part.write("tensor_surface_derivative_N" + std::to_string(n_part),VTK_WRITER);
1451  } // end ll loop to test forconvergence
1452 
1453  BOOST_TEST_MESSAGE("Test convergence of surface vector Laplacian");
1454  BOOST_TEST_MESSAGE("L2 error for N=4000 / L2 error for N=8000 = " + std::to_string(L2norms_conv[0]/L2norms_conv[1]));
1455  BOOST_TEST_MESSAGE("L2 error for N=8000 / L2 error for N=16000 = " + std::to_string(L2norms_conv[1]/L2norms_conv[2]));
1456  BOOST_REQUIRE(L2norms_conv[0]/L2norms_conv[1] > 2);
1457  BOOST_REQUIRE(L2norms_conv[1]/L2norms_conv[2] > 1.8);
1458 }
1459 
1460 
1461 BOOST_AUTO_TEST_CASE(dcpse_surface_p2p_interpolation_sphere_scalar) {
1462  auto & v_cl = create_vcluster();
1463  timer tt;
1464  tt.start();
1465  size_t n_from1=4096;
1466  size_t n_from2=8192;
1467  size_t n_to=256;
1468  // Domain
1469  double boxP1{-1.5}, boxP2{1.5};
1470  double boxSize{boxP2 - boxP1};
1471  size_t sz1[3] = {n_from1,n_from1,n_from1};
1472  size_t sz2[3] = {n_from2,n_from2,n_from2};
1473  size_t szTo[3] = {n_to,n_to,n_to};
1474  double grid_spacing1 = std::sqrt(4.0*M_PI/n_from1);//{0.8/(std::pow(sz1[0],1.0/3.0)-1.0)};
1475  double grid_spacing2 = std::sqrt(4.0*M_PI/n_from2);//{0.8/(std::pow(sz2[0],1.0/3.0)-1.0)};
1476  double grid_spacingTo = std::sqrt(4.0*M_PI/n_to);//{0.8/(std::pow(szTo[0],1.0/3.0)-1.0)};
1477  double grid_spacing_surf2=grid_spacing2;
1478  double grid_spacing_surf1=grid_spacing1;
1479  double grid_spacing_surfTo=grid_spacingTo;
1480  double cutoff_factor = 3.5;
1481  double rCut2{cutoff_factor * grid_spacing_surf2};
1482  double rCut1{cutoff_factor * grid_spacing_surf1};
1483  double rCutTo{cutoff_factor * grid_spacing_surfTo};
1484 
1485  Box<3,double> domain{{boxP1,boxP1,boxP1},{boxP2,boxP2,boxP2}};
1486  size_t bc[3] = {NON_PERIODIC,NON_PERIODIC,NON_PERIODIC};
1487  Ghost<3,double> ghost1{rCut1 + grid_spacing1/8.0};
1488  Ghost<3,double> ghost2{rCut2 + grid_spacing2/8.0};
1489  Ghost<3,double> ghostTo{rCutTo + grid_spacingTo/8.0};
1490  // particles
1491  vector_dist<3,double, aggregate<double,double[3]>> SparticlesFrom1(0,domain,bc,ghost1);
1492  vector_dist<3,double, aggregate<double,double[3]>> SparticlesFrom2(0,domain,bc,ghost2);
1493  // properties: scalar_qty, normal, error
1494  vector_dist<3,double, aggregate<double,double,double,double>> SparticlesTo(0,domain,bc,ghostTo);
1495  // properties: scalar obtained from interpolation from data with resolution 1,
1496  // scalar obtained from interpolation from data with resolution 2,
1497  // error of scalar 1, error of scalar 2
1498  // particles on the Spherical surface distributed with the Fibonacci sequence
1499  double Golden_angle=M_PI * (3.0 - sqrt(5.0));
1500  if (v_cl.rank() == 0) {
1501  // fill vector with resolution 1
1502  for(int i=0;i<n_from1;i++)
1503  {
1504  double y = 1.0 - (i /double(n_from1 - 1.0)) * 2.0;
1505  double radius = sqrt(1 - y * y);
1506  double Golden_theta = Golden_angle * i;
1507  double x = cos(Golden_theta) * radius;
1508  double z = sin(Golden_theta) * radius;
1509  SparticlesFrom1.add();
1510  SparticlesFrom1.getLastPos()[0] = x;
1511  SparticlesFrom1.getLastPos()[1] = y;
1512  SparticlesFrom1.getLastPos()[2] = z;
1513  double rm=sqrt(x*x+y*y+z*z);
1514  // fill unit surface normals
1515  SparticlesFrom1.getLastProp<1>()[0] = x/rm;
1516  SparticlesFrom1.getLastProp<1>()[1] = y/rm;
1517  SparticlesFrom1.getLastProp<1>()[2] = z/rm;
1518  // fill scalar field (spherical harmonic 2,0)
1519  //SparticlesFrom1.getLastProp<0>() = std::sqrt(5.0/(16.0*M_PI)) * (3*z*z - 1.0);
1520  // spherical harmonic 2,1
1521  //SparticlesFrom1.getLastProp<0>() = 0.5*std::sqrt(15.0/M_PI)*x*z;
1522  // spherical harmonic 2,2
1523  //SparticlesFrom1.getLastProp<0>() = 0.25*std::sqrt(15.0/M_PI)*(x*x - y*y);
1524  // spherical harmonic 3,2
1525  SparticlesFrom1.getLastProp<0>() = 0.25*std::sqrt(105.0/M_PI)*(x*x - y*y)*z;
1526  // spherical harmonic 0,0
1527  //SparticlesFrom1.getLastProp<0>() = 0.5/std::sqrt(M_PI);
1528  }
1529  // fill vector with resolution 2
1530  for(int i=0;i<n_from2;i++)
1531  {
1532  double y = 1.0 - (i /double(n_from2 - 1.0)) * 2.0;
1533  double radius = sqrt(1 - y * y);
1534  double Golden_theta = Golden_angle * i;
1535  double x = cos(Golden_theta) * radius;
1536  double z = sin(Golden_theta) * radius;
1537  SparticlesFrom2.add();
1538  SparticlesFrom2.getLastPos()[0] = x;
1539  SparticlesFrom2.getLastPos()[1] = y;
1540  SparticlesFrom2.getLastPos()[2] = z;
1541  double rm=sqrt(x*x+y*y+z*z);
1542  // fill unit surface normals
1543  SparticlesFrom2.getLastProp<1>()[0] = x/rm;
1544  SparticlesFrom2.getLastProp<1>()[1] = y/rm;
1545  SparticlesFrom2.getLastProp<1>()[2] = z/rm;
1546  // fill scalar field (spherical harmonic)
1547  //SparticlesFrom2.getLastProp<0>() = std::sqrt(5.0/(16.0*M_PI)) * (3*z*z - 1.0);
1548  // spherical harmonic 2,1
1549  //SparticlesFrom2.getLastProp<0>() = 0.5*std::sqrt(15.0/M_PI)*x*z;
1550  // spherical harmonic 2,2
1551  //SparticlesFrom2.getLastProp<0>() = 0.25*std::sqrt(15.0/M_PI)*(x*x - y*y);
1552  // spherical harmonic 3,2
1553  SparticlesFrom2.getLastProp<0>() = 0.25*std::sqrt(105.0/M_PI)*(x*x - y*y)*z;
1554  // spherical harmonic 0,0
1555  //SparticlesFrom2.getLastProp<0>() = 0.5/std::sqrt(M_PI);
1556  }
1557  // fill vector with positions at which surface interpolation is supposed to be performed
1558  for(int i=0;i<((int)(n_to-1));i++)
1559  {
1560  double y = 1.0 - (i /double(n_to - 1.0)) * 2.0;
1561  double radius = sqrt(1 - y * y);
1562  double Golden_theta = Golden_angle * i;
1563  double x = cos(Golden_theta) * radius;
1564  double z = sin(Golden_theta) * radius;
1565  SparticlesTo.add();
1566  SparticlesTo.getLastPos()[0] = x;
1567  SparticlesTo.getLastPos()[1] = y;
1568  SparticlesTo.getLastPos()[2] = z;
1569  double rm=sqrt(x*x+y*y+z*z);
1570  // initialize scalar fields as 0.0
1571  SparticlesTo.getLastProp<0>() = 0.0;//std::sqrt(3.0/(4.0*M_PI)) * z;
1572  SparticlesTo.getLastProp<1>() = 0.0;//std::sqrt(3.0/(4.0*M_PI)) * z;
1573  }
1574  }
1575 
1576  SparticlesFrom1.write("from1_before");
1577  SparticlesFrom2.write("from2_before");
1578  SparticlesTo.write("to_before");
1579 
1580  SparticlesFrom1.map();
1581  SparticlesFrom1.ghost_get<0,1>();
1582  SparticlesFrom2.map();
1583  SparticlesFrom2.ghost_get<0,1>();
1584  SparticlesTo.map();
1585  SparticlesTo.ghost_get<0>();
1586 
1587  const size_t oporder = 5;
1588 
1589  auto cellListSparticlesFrom1 = SparticlesFrom1.getCellList(rCut1);
1590  auto verletListSparticlesTo1 = createVerletTwoPhase(SparticlesTo,SparticlesFrom1,cellListSparticlesFrom1,rCut1);
1591 
1592  auto cellListSparticlesFrom2 = SparticlesFrom2.getCellList(rCut2);
1593  auto verletListSparticlesTo2 = createVerletTwoPhase(SparticlesTo,SparticlesFrom2,cellListSparticlesFrom2,rCut2);
1594 
1595  PPInterpolation<decltype(SparticlesFrom1),decltype(SparticlesTo), decltype(verletListSparticlesTo1), 1> ppSurface(SparticlesFrom1,SparticlesTo, verletListSparticlesTo1, oporder,rCut1,grid_spacing1,true,support_options::RADIUS);
1596  ppSurface.p2p<0,0>();
1597  PPInterpolation<decltype(SparticlesFrom2),decltype(SparticlesTo), decltype(verletListSparticlesTo2), 1> ppSurface2(SparticlesFrom2,SparticlesTo, verletListSparticlesTo2, oporder,rCut2,grid_spacing2,true,support_options::RADIUS);
1598  ppSurface2.p2p<0,1>();
1599 
1600  auto it = SparticlesTo.getDomainIterator();
1601  double worst = 0.0;
1602  double worst2 = 0.0;
1603  while (it.isNext()) {
1604  auto p = it.get();
1605 
1606  double x = SparticlesTo.getPos(p)[0];
1607  double y = SparticlesTo.getPos(p)[1];
1608  double z = SparticlesTo.getPos(p)[2];
1609 
1610  //double sphericalHarmonic = std::sqrt(5.0/(16.0*M_PI)) * (3*z*z - 1.0);
1611  // spherical harmonic 2,1
1612  // double sphericalHarmonic = 0.5*std::sqrt(15.0/M_PI)*x*z;
1613  // spherical harmonic 2,2
1614  //double sphericalHarmonic = 0.25*std::sqrt(15.0/M_PI)*(x*x - y*y);
1615  // spherical harmonic 3,2
1616  double sphericalHarmonic = 0.25*std::sqrt(105.0/M_PI)*(x*x - y*y)*z;
1617  //double sphericalHarmonic = 0.5/std::sqrt(M_PI);
1618 
1619  SparticlesTo.getProp<2>(p) = fabs(SparticlesTo.getProp<0>(p) - sphericalHarmonic); // error
1620  SparticlesTo.getProp<3>(p) = fabs(SparticlesTo.getProp<1>(p) - sphericalHarmonic); // error
1621 
1622  if (fabs(SparticlesTo.getProp<0>(p) - sphericalHarmonic) > worst) {
1623  worst = fabs(SparticlesTo.getProp<0>(p) - sphericalHarmonic);
1624  }
1625  if (fabs(SparticlesTo.getProp<1>(p) - sphericalHarmonic) > worst2) {
1626  worst2 = fabs(SparticlesTo.getProp<1>(p) - sphericalHarmonic);
1627  }
1628  ++it;
1629  }
1630 
1631  v_cl.max(worst);
1632  v_cl.max(worst2);
1633  v_cl.execute();
1634  std::cout<<"Linf interpolation error with h_from1=1/"<<n_from1<<" to h_to=1/"<<n_to<<" is: "<<worst<<std::endl;
1635  std::cout<<"Linf interpolation error with h_from2=1/"<<n_from2<<" to h_to=1/"<<n_to<<" is: "<<worst2<<std::endl;
1636  // for the covergence order, h is computed like h=sqrt(1/N), then the denominator is log10(h1/h2)=log10(sqrt((1/N1) / (1/N2))) = log10(sqrt(N2/N1))
1637  // with this the convergence order is log10(err1/err2) / log10(sqrt(N2/N1))
1638  std::cout<<"Convergence order is "<<std::log10(worst2/worst)/std::log10(std::sqrt((float)n_from1/(float)n_from2))<<std::endl;
1639  std::cout<<"Operator order = "<<oporder<<std::endl;
1640  SparticlesTo.deleteGhost();
1641  SparticlesFrom1.deleteGhost();
1642  SparticlesTo.write("SparticlesTo_after");
1643  SparticlesFrom1.write("SparticlesFrom1_after");
1644  BOOST_REQUIRE(worst < 0.03);
1645  BOOST_REQUIRE(worst2 < 0.03);
1646 }
1647 
1648 BOOST_AUTO_TEST_CASE(dcpse_surface_p2p_interpolation_plane_scalar) {
1649 
1650  auto & v_cl = create_vcluster();
1651 
1652  size_t n_from{10};
1653  size_t n_to{10};
1654  double rCut{3.1};
1655 
1656  // Domain and simulation parameters
1657  Box<3,double> domain{{-1,-1,-1},{1,1,1}};
1658  double grid_spacing_from{2.0/(n_from-1)};
1659  double grid_spacing_to{2.0/(n_to-1)};
1660  size_t bc[3] = {NON_PERIODIC,NON_PERIODIC,NON_PERIODIC};
1661 
1662  vector_dist<3,double,aggregate<double,double[3]>> part_from{0,domain,bc,rCut};
1664  // props: scalar_qty, normal, error
1665 
1666  // Create particles_from in a grid-like manner
1667  if (v_cl.rank() == 0) {
1668 
1669  for (int i = 0; i < n_from; ++i)
1670  for (int j = 0; j < n_from; ++j) {
1671 
1672  part_from.add();
1673 
1674  part_from.getLastPos()[0] = -1 + i*grid_spacing_from;
1675  part_from.getLastPos()[1] = -1 + j*grid_spacing_from;
1676  part_from.getLastPos()[2] = 0;
1677 
1678  part_from.getLastProp<0>() = std::fabs(part_from.getLastPos()[0]); // scalar_qty
1679  part_from.getLastProp<1>()[0] = 0; // normal_x
1680  part_from.getLastProp<1>()[1] = 0; // normal_y
1681  part_from.getLastProp<1>()[2] = 1; // normal_z
1682  }
1683  }
1684  part_from.map();
1685  part_from.ghost_get<0,1>();
1686 
1687  // Create particles_to in a grid-like manner + random noise
1688  std::random_device rd;
1689  std::mt19937 gen(rd());
1690  std::uniform_real_distribution<> dist_threshold{-1.0,1.0};
1691 
1692  if (v_cl.rank() == 0) {
1693 
1694  for (int i = 0; i < n_to; ++i)
1695  for (int j = 0; j < n_to; ++j) {
1696 
1697  part_to.add();
1698 
1699  part_to.getLastPos()[0] = -1 + i*grid_spacing_to;
1700  part_to.getLastPos()[1] = -1 + j*grid_spacing_to;
1701  // part_to.getLastPos()[0] = -0.9 + i*grid_spacing_to + dist_threshold(gen) * 0.07; // 7% noise
1702  // part_to.getLastPos()[1] = -0.9 + j*grid_spacing_to + dist_threshold(gen) * 0.07;
1703  part_to.getLastPos()[2] = 0;
1704 
1705  part_to.getLastProp<0>() = 0; // scalar_qty
1706  part_to.getLastProp<1>()[0] = 0; // normal_x
1707  part_to.getLastProp<1>()[1] = 0; // normal_y
1708  part_to.getLastProp<1>()[2] = 1; // normal_z
1709  part_to.getLastProp<2>() = 0; // error
1710  }
1711  }
1712  part_to.map();
1713  part_to.ghost_get<0,1>();
1714 
1715  // Interpolate
1716  auto cellList = part_from.getCellList(rCut);
1717  auto verletList = createVerletTwoPhase(part_to,part_from,cellList,rCut);
1718 
1719  PPInterpolation<decltype(part_from),decltype(part_to),decltype(verletList),1> ppSurface(part_from,part_to,verletList,2,rCut,grid_spacing_from,true);
1720  ppSurface.p2p<0,0>();
1721 
1722  // Compute maximum error
1723  auto it = part_to.getDomainIterator();
1724  double worst = 0.0;
1725  while (it.isNext()) {
1726  auto key{it.get()};
1727 
1728  part_to.getProp<2>(key) = std::fabs(part_to.getProp<0>(key) - std::fabs(part_to.getPos(key)[0])); // error
1729 
1730  if (part_to.getProp<2>(key) > worst)
1731  worst = part_to.getProp<2>(key);
1732  ++it;
1733  }
1734 
1735  v_cl.max(worst);
1736  v_cl.execute();
1737 
1738  // Write particles
1739  part_from.deleteGhost();
1740  part_from.write("surface_p2p_interp_plane_part_from");
1741  part_to.deleteGhost();
1742  part_to.write("surface_p2p_interp_plane_part_to");
1743 
1744  std::cout << "worst: " << worst << std::endl;
1745  // BOOST_REQUIRE(worst < 0.03);
1746 }
1747 
1748 BOOST_AUTO_TEST_CASE(dcpse_surface_p2p_interpolation_sphere_vector) {
1749 
1750  auto & v_cl = create_vcluster();
1751 
1752  timer tt;
1753  tt.start();
1754 
1755  size_t ni_from[3] = {2000,8000,16000};
1756  size_t ni_to[3] = {2000,4000,32000};
1757 
1758  // Domain
1759  double boxP1{-1.2}, boxP2{1.2};
1760  double boxSize{boxP2 - boxP1};
1761  Box<3,double> domain{{boxP1,boxP1,boxP1},{boxP2,boxP2,boxP2}};
1762  size_t bc[3] = {NON_PERIODIC,NON_PERIODIC,NON_PERIODIC};
1763 
1764  double cutoff_factor = 3.5;
1765  const size_t oporder = 5;
1766 
1767  double Linf[3][3] = {{0,0,0},{0,0,0},{0,0,0}};
1768 
1769  for (int ni = 0; ni < 3; ++ni)
1770  {
1771  // Particles_from
1772  double grid_spacing_from{std::sqrt(4.0*M_PI/ni_from[ni])};
1773  double rCut_from{cutoff_factor * grid_spacing_from};
1774  Ghost<3,double> ghost_from{rCut_from + grid_spacing_from/8.0};
1775  vector_dist<3,double, aggregate<double[3],double[3]>> Sparticles_from(0,domain,bc,ghost_from); // properties: normal, vector_qty
1776 
1777  if (v_cl.rank() == 0) {
1778 
1779  double Golden_angle{M_PI * (3.0 - sqrt(5.0))};
1780  double thetaB, phi, arg;
1781 
1782  for(int i = 0; i < ni_from[ni]; ++i)
1783  {
1784  double y = 1.0 - (i /double(ni_from[ni] - 1.0)) * 2.0;
1785  double radius = sqrt(1 - y * y);
1786  double Golden_theta = Golden_angle * i;
1787  double x = cos(Golden_theta) * radius;
1788  double z = sin(Golden_theta) * radius;
1789 
1790  arg = x*x+y*y;
1791  thetaB = std::atan2(std::sqrt(arg),z);
1792  phi = std::atan2(y,x);
1793 
1794  Sparticles_from.add();
1795  Sparticles_from.getLastPos()[0] = x;
1796  Sparticles_from.getLastPos()[1] = y;
1797  Sparticles_from.getLastPos()[2] = z;
1798 
1799  double rm = sqrt(x*x+y*y+z*z);
1800 
1801  // normal
1802  Sparticles_from.getLastProp<0>()[0] = x/rm;
1803  Sparticles_from.getLastProp<0>()[1] = y/rm;
1804  Sparticles_from.getLastProp<0>()[2] = z/rm;
1805 
1806  // vector_qty
1807  Sparticles_from.getLastProp<1>()[0] = - 3.0/4.0 * std::sqrt(7.0/M_PI) * (1.0 - 5.0 * std::cos(thetaB) * std::cos(thetaB)) * std::sin(thetaB) * std::sin(phi);
1808  Sparticles_from.getLastProp<1>()[1] = 3.0/4.0 * std::sqrt(7.0/M_PI) * (1.0 - 5.0 * std::cos(thetaB) * std::cos(thetaB)) * std::sin(thetaB) * std::cos(phi);
1809  Sparticles_from.getLastProp<1>()[2] = 0.0;
1810  }
1811  }
1812  Sparticles_from.map();
1813  Sparticles_from.ghost_get<0,1>();
1814  Sparticles_from.write("from_N" + std::to_string(ni_from[ni]) + "_before");
1815 
1816  // Particles_to
1817  for (int nj = 0; nj < 3; ++nj)
1818  {
1819  double grid_spacing_to{std::sqrt(4.0*M_PI/ni_to[nj])};
1820  double rCut_to{cutoff_factor * grid_spacing_to};
1821  Ghost<3,double> ghost_to{rCut_to + grid_spacing_to/8.0};
1822  vector_dist<3,double, aggregate<double[3],double[3],double>> Sparticles_to(0,domain,bc,ghost_to); // properties: interp_vector_qty, analyt_vector_qty, error
1823 
1824  if (v_cl.rank() == 0) {
1825 
1826  double Golden_angle{M_PI * (3.0 - sqrt(5.0))};
1827  double thetaB, phi, arg;
1828 
1829  for(int i = 0; i < ni_to[nj]; ++i)
1830  {
1831  double y = 1.0 - (i /double(ni_to[nj] - 1.0)) * 2.0;
1832  double radius = sqrt(1 - y * y);
1833  double Golden_theta = Golden_angle * i;
1834  double x = cos(Golden_theta) * radius;
1835  double z = sin(Golden_theta) * radius;
1836 
1837  arg = x*x+y*y;
1838  thetaB = std::atan2(std::sqrt(arg),z);
1839  phi = std::atan2(y,x);
1840 
1841  Sparticles_to.add();
1842  Sparticles_to.getLastPos()[0] = x;
1843  Sparticles_to.getLastPos()[1] = y;
1844  Sparticles_to.getLastPos()[2] = z;
1845 
1846  double rm=sqrt(x*x+y*y+z*z);
1847 
1848  for (int d = 0; d < 3; ++d)
1849  Sparticles_to.getLastProp<0>()[d] = 0.0; // interpolated prop
1850 
1851  // Analyt vector_qty
1852  Sparticles_to.getLastProp<1>()[0] = - 3.0/4.0 * std::sqrt(7.0/M_PI) * (1.0 - 5.0 * std::cos(thetaB) * std::cos(thetaB)) * std::sin(thetaB) * std::sin(phi);
1853  Sparticles_to.getLastProp<1>()[1] = 3.0/4.0 * std::sqrt(7.0/M_PI) * (1.0 - 5.0 * std::cos(thetaB) * std::cos(thetaB)) * std::sin(thetaB) * std::cos(phi);
1854  Sparticles_to.getLastProp<1>()[2] = 0.0;
1855 
1856  Sparticles_to.getLastProp<2>() = 0.0; // error
1857  }
1858  }
1859  Sparticles_to.map();
1860  Sparticles_to.ghost_get<0,1>();
1861  Sparticles_to.write("to_N" + std::to_string(ni_to[nj]) + "_before");
1862 
1863  // Interpolation
1864 
1865  auto cellList = Sparticles_from.getCellList(rCut_from);
1866  auto verletList = createVerletTwoPhase(Sparticles_to,Sparticles_from,cellList,rCut_from);
1867 
1868  PPInterpolation<decltype(Sparticles_from),decltype(Sparticles_to), decltype(verletList),0> ppSurface(Sparticles_from,Sparticles_to,verletList,oporder,rCut_from,grid_spacing_from,true);
1869  ppSurface.p2p<1,0,3>();
1870 
1871  // Error
1872  auto it = Sparticles_to.getDomainIterator();
1873  double worst = 0.0;
1874  while (it.isNext()) {
1875  auto p = it.get();
1876 
1877  double x = Sparticles_to.getPos(p)[0];
1878  double y = Sparticles_to.getPos(p)[1];
1879  double z = Sparticles_to.getPos(p)[2];
1880 
1881  double err{0};
1882  for (int d = 0; d < 3; ++d)
1883  err += (Sparticles_to.getProp<0>(p)[d] - Sparticles_to.getProp<1>(p)[d]) * (Sparticles_to.getProp<0>(p)[d] - Sparticles_to.getProp<1>(p)[d]);
1884 
1885  worst = std::max(worst,std::sqrt(err));
1886  ++it;
1887  }
1888 
1889  v_cl.max(worst);
1890  v_cl.execute();
1891  Linf[ni][nj] = worst;
1892 
1893  if (v_cl.rank() == 0)
1894  std::cout<<"Linf interpolation error with N_from: " << ni_from[ni] << " to N_to: " << ni_to[nj] << " is: " << worst << std::endl;
1895 
1896  Sparticles_from.deleteGhost();
1897  Sparticles_to.deleteGhost();
1898 
1899  Sparticles_from.write("from_N" + std::to_string(ni_to[nj]) + "_after");
1900  Sparticles_to.write("to_N" + std::to_string(ni_to[nj]) + "_after");
1901 
1902  BOOST_REQUIRE(worst < 0.03);
1903  } // nj loop
1904  } // ni loop
1905 
1906  if (v_cl.rank() == 0) {
1907  std::cout << "Operator order = " << oporder << std::endl;
1908 
1909  // for the covergence order, h is computed like h=sqrt(1/N), then the denominator is log10(h1/h2)=log10(sqrt((1/N1) / (1/N2))) = log10(sqrt(N2/N1))
1910  // with this the convergence order is log10(err1/err2) / log10(sqrt(N2/N1))
1911  std::cout << "Convergence order is " << std::log10(Linf[2][0]/Linf[1][0]) / std::log10(std::sqrt((float)ni_from[1]/(float)ni_from[2]))<<std::endl;
1912  std::cout << "Convergence order is " << std::log10(Linf[1][0]/Linf[0][0]) / std::log10(std::sqrt((float)ni_from[0]/(float)ni_from[1]))<<std::endl;
1913 
1914  std::cout << "Convergence order is " << std::log10(Linf[2][1]/Linf[1][1]) / std::log10(std::sqrt((float)ni_from[1]/(float)ni_from[2]))<<std::endl;
1915  std::cout << "Convergence order is " << std::log10(Linf[1][1]/Linf[0][1]) / std::log10(std::sqrt((float)ni_from[0]/(float)ni_from[1]))<<std::endl;
1916 
1917  std::cout << "Convergence order is " << std::log10(Linf[2][2]/Linf[1][2]) / std::log10(std::sqrt((float)ni_from[1]/(float)ni_from[2]))<<std::endl;
1918  std::cout << "Convergence order is " << std::log10(Linf[1][2]/Linf[0][2]) / std::log10(std::sqrt((float)ni_from[0]/(float)ni_from[1]))<<std::endl;
1919  }
1920 }
1921 
1922 BOOST_AUTO_TEST_SUITE_END()
1923 
1924 #endif
1925 #endif
This class represent an N-dimensional box.
Definition: Box.hpp:60
Definition: Ghost.hpp:40
Class to perform particle to particle interpolation using DC-PSE kernels.
void execute()
Execute all the requests.
size_t rank()
Get the process unit id.
void sum(T &num)
Sum the numbers across all processors and get the result.
void max(T &num)
Get the maximum number across all processors (or reduction with infinity norm)
Implementation of VCluster class.
Definition: VCluster.hpp:59
Class for cpu time benchmarking.
Definition: timer.hpp:28
void start()
Start the timer.
Definition: timer.hpp:90
Distributed vector.
KeyT const ValueT ValueT OffsetIteratorT OffsetIteratorT int
[in] The number of segments that comprise the sorting data
aggregate of properties, from a list of object if create a struct that follow the OPENFPM native stru...
Definition: aggregate.hpp:221
Specify the general characteristic of system to solve.
Definition: EqnsStruct.hpp:14