OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
FD_Solver_test.cpp
1 #include "config.h"
2 #ifdef HAVE_EIGEN
3 #ifdef HAVE_PETSC
4 
5 #define BOOST_TEST_DYN_LINK
6 #include <boost/test/unit_test.hpp>
7 
8 #include "FD_Solver.hpp"
9 #include "Solvers/petsc_solver.hpp"
10 #include "Solvers/umfpack_solver.hpp"
11 #include "FD_expressions.hpp"
12 #include "FD_op.hpp"
13 #include "Grid/staggered_dist_grid.hpp"
14 #include "util/EqnsStructFD.hpp"
15 
16 
17 BOOST_AUTO_TEST_SUITE( FD_Solver_test )
18 
19 
20 BOOST_AUTO_TEST_CASE(solver_check_diagonal)
21 {
22  const size_t sz[2] = {81,81};
23  Box<2, double> box({0, 0}, {1, 1});
24  periodicity<2> bc = {NON_PERIODIC, NON_PERIODIC};
25  Ghost<2,long int> ghost(1);
26 
28 
29 
30  auto it = domain.getDomainIterator();
31  while (it.isNext())
32  {
33  auto key = it.get();
34  auto gkey = it.getGKey(key);
35  double x = gkey.get(0) * domain.spacing(0);
36  double y = gkey.get(1) * domain.spacing(1);
37  domain.get<1>(key) = x+y;
38 
39  ++it;
40  }
41 
42  domain.ghost_get<0>();
43  petsc_solver<double> pet_sol;
44  pet_sol.setPreconditioner(PCNONE);
45 
46  auto v = FD::getV<0>(domain);
47  auto RHS= FD::getV<1>(domain);
48  auto sol= FD::getV<2>(domain);
49  FD::LInfError LInfError;
50  FD_scheme<equations2d1,decltype(domain)> Solver(ghost,domain);
51  Solver.impose(5.0*v,{0,0},{80,80}, prop_id<1>());
52  Solver.solve_with_solver(pet_sol,sol);
53  v=1/5.0*RHS;
54  auto linferror = LInfError(v, sol);
55 
56  /* std::cout << "L2 error: " << l2error << std::endl;
57  std::cout << "L∞ Error: " << linferror << std::endl;*/
58  BOOST_REQUIRE(linferror < 1e-5);
59 
60  //domain.write("FDSOLVER_Lap_test");
61 
62  //domain.write("basic_test");
63 }
64 
65 
66  BOOST_AUTO_TEST_CASE(solver_Lap)
67  {
68  const size_t sz[2] = {82,82};
69  Box<2, double> box({0, 0}, {1, 1});
70  periodicity<2> bc = {NON_PERIODIC, NON_PERIODIC};
71  Ghost<2,long int> ghost(1);
72 
74 
75 
76  auto it = domain.getDomainIterator();
77  while (it.isNext())
78  {
79  auto key = it.get();
80  auto gkey = it.getGKey(key);
81  double x = gkey.get(0) * domain.spacing(0);
82  double y = gkey.get(1) * domain.spacing(1);
83  domain.get<0>(key) = sin(M_PI*x)*sin(M_PI*y);
84  domain.get<1>(key) = -2*M_PI*M_PI*sin(M_PI*x)*sin(M_PI*y);
85  ++it;
86  }
87 
88  domain.ghost_get<0>();
91  auto v = FD::getV<0>(domain);
92  auto RHS= FD::getV<1>(domain);
93  auto sol= FD::getV<2>(domain);
94 
95 
96  FD_scheme<equations2d1,decltype(domain)> Solver(ghost,domain);
97  FD::Lap Lap;
98  FD::LInfError LInfError;
99 
100 /* Solver.impose(Lap(v),{1,1},{79,79}, prop_id<1>());
101  Solver.impose(v,{0,0},{80,0}, prop_id<0>());
102  Solver.impose(v,{0,1},{0,79}, prop_id<0>());
103  Solver.impose(v,{0,80},{80,80}, prop_id<0>());
104  Solver.impose(v,{80,1},{80,79}, prop_id<0>());
105  Solver.solve(sol);*/
106 
107  Solver.impose(Lap(v),{1,1},{80,80}, prop_id<1>());
108  Solver.impose(v,{0,0},{81,0}, prop_id<0>());
109  Solver.impose(v,{0,1},{0,80}, prop_id<0>());
110  Solver.impose(v,{0,81},{81,81}, prop_id<0>());
111  Solver.impose(v,{81,1},{81,80}, prop_id<0>());
112  /*auto A=Solver.getA();
113  A.write("Lap_Matrix");*/
114  petsc_solver<double> pet_sol;
115  pet_sol.setPreconditioner(PCNONE);
116  Solver.solve_with_solver(pet_sol,sol);
117 
118  auto linferror = LInfError(v, sol);
119  BOOST_REQUIRE(linferror < 1e-3);
120  //std::cout << "L∞ Error: " << linferror << std::endl;
121 
122  //domain.write("FDSOLVER_Lap_test");
123  }
124 
125  BOOST_AUTO_TEST_CASE(solver_Lap_stag)
126  {
127  const size_t sz[2] = {82,82};
128  Box<2, double> box({0, 0}, {1, 1});
129  periodicity<2> bc = {NON_PERIODIC, NON_PERIODIC};
130  Ghost<2,long int> ghost(1);
131 
133 
134 
135  auto it = domain.getDomainIterator();
136  while (it.isNext())
137  {
138  auto key = it.get();
139  auto gkey = it.getGKey(key);
140  double x = gkey.get(0) * domain.spacing(0);
141  double y = gkey.get(1) * domain.spacing(1);
142  domain.get<0>(key) = sin(M_PI*x)*sin(M_PI*y);
143  domain.get<1>(key) = -2*M_PI*M_PI*sin(M_PI*x)*sin(M_PI*y);
144  ++it;
145  }
146 
147  domain.ghost_get<0>();
148  FD::Derivative_x Dx;
149  FD::Derivative_y Dy;
150  auto v = FD::getV<0>(domain);
151  auto RHS= FD::getV<1>(domain);
152  auto sol= FD::getV<2>(domain);
153 
154 
155  FD_scheme<equations2d1_stag,decltype(domain)> Solver(ghost,domain);
156  FD::Lap Lap;
157 
158 /* Solver.impose(Lap(v),{1,1},{79,79}, prop_id<1>());
159  Solver.impose(v,{0,0},{80,0}, prop_id<0>());
160  Solver.impose(v,{0,1},{0,79}, prop_id<0>());
161  Solver.impose(v,{0,80},{80,80}, prop_id<0>());
162  Solver.impose(v,{80,1},{80,79}, prop_id<0>());
163  Solver.solve(sol);*/
164 
165  Solver.impose(Lap(v),{1,1},{80,80}, prop_id<1>());
166  Solver.impose(v,{0,0},{81,0}, prop_id<0>());
167  Solver.impose(v,{0,1},{0,80}, prop_id<0>());
168  Solver.impose(v,{0,81},{81,81}, prop_id<0>());
169  Solver.impose(v,{81,1},{81,80}, prop_id<0>());
170  /*auto A=Solver.getA();
171  A.write("Lap_Matrix");*/
172 
173  Solver.solve(sol);
174 
175  auto it2 = domain.getDomainIterator();
176  double worst = 0.0;
177  while (it2.isNext()) {
178  auto p = it2.get();
179 
180  if (fabs(domain.getProp<0>(p) - domain.getProp<2>(p)) > worst) {
181  worst = fabs(domain.getProp<0>(p) - domain.getProp<2>(p));
182  }
183 
184  ++it2;
185  }
186  BOOST_REQUIRE(worst < 1e-3);
187  //std::cout << "Maximum Error: " << worst << std::endl;
188  //domain.write("FDSOLVER_Lap_test");
189  }
190  // Test failing for cores>=3
191  /*BOOST_AUTO_TEST_CASE(Lid_driven_PC)
192  { using namespace FD;
193  timer tt2;
194  tt2.start();
195  size_t gd_sz = 81;
196  double Re=100;
197  double V_err_eps = 1e-2;
198  double alpha=0.01;
199  constexpr int x = 0;
200  constexpr int y = 1;
201  const size_t szu[2] = {gd_sz,gd_sz};
202  int sz[2]={int(gd_sz),int(gd_sz)};
203  Box<2, double> box({0, 0}, {1,1});
204  periodicity<2> bc = {NON_PERIODIC, NON_PERIODIC};
205  double spacing;
206  spacing = 1.0 / (sz[0] - 1);
207  Ghost<2,long int> ghost(1);
208  auto &v_cl = create_vcluster();
209  //szu[0] = (size_t)sz[0];
210  //szu[1] = (size_t)sz[1];
211  typedef aggregate<double, VectorS<2, double>, VectorS<2, double>,VectorS<2, double>,double,VectorS<2, double>,double,double> LidCavity;
212  grid_dist_id<2, double, LidCavity> domain(szu, box,ghost,bc);
213  double x0, y0, x1, y1;
214  x0 = box.getLow(0);
215  y0 = box.getLow(1);
216  x1 = box.getHigh(0);
217  y1 = box.getHigh(1);
218  auto it = domain.getDomainIterator();
219  while (it.isNext())
220  {
221  auto key = it.get();
222  auto gkey = it.getGKey(key);
223  double x = gkey.get(0) * domain.spacing(0);
224  double y = gkey.get(1) * domain.spacing(1);
225  if (y==1)
226  {domain.get<1>(key) = 1.0;}
227  else
228  {domain.get<1>(key) = 0.0;}
229 
230  ++it;
231  }
232  domain.ghost_get<0>();
233  Derivative_x Dx;
234  Derivative_y Dy;
235  Derivative_xx Dxx;
236  Derivative_yy Dyy;
237  auto P = getV<0>(domain);
238  auto V = getV<1>(domain);
239  auto RHS = getV<2>(domain);
240  auto dV = getV<3>(domain);
241  auto div = getV<4>(domain);
242  auto V_star = getV<5>(domain);
243  auto H = getV<6>(domain);
244  auto dP = getV<7>(domain);
245 
246  //0 doesnt work
247  P = 0.0;
248  int n = 0, nmax = 50, ctr = 0, errctr=1, Vreset = 0;
249  double V_err=1;
250  if (Vreset == 1) {
251  Vreset = 0;
252  }
253  eq_id vx,vy;
254  vx.setId(0);
255  vy.setId(1);
256 
257  double sum, sum1, sum_k,V_err_old;
258  auto StokesX=(V[x]*Dx(V_star[x])+V[y]*Dy(V_star[x]))-(1.0/Re)*(Dxx(V_star[x])+Dyy(V_star[x]));
259  auto StokesY=(V[x]*Dx(V_star[y])+V[y]*Dy(V_star[y]))-(1.0/Re)*(Dxx(V_star[y])+Dyy(V_star[y]));
260  petsc_solver<double> solverPetsc;
261  solverPetsc.setSolver(KSPGMRES);
262 
263  RHS=0;
264  dV=0;
265 
266  timer tt;
267  while (V_err >= V_err_eps && n <= nmax) {
268  if (n%5==0){
269  domain.ghost_get<0,1 >(SKIP_LABELLING);
270  domain.write_frame("LID",n,BINARY);
271  domain.ghost_get<0>();
272  }
273  tt.start();
274  domain.ghost_get<0>(SKIP_LABELLING);
275  RHS[x] = -Dx(P);
276  RHS[y] = -Dy(P);
277  FD_scheme<equations2d2,decltype(domain)> Solver(ghost,domain);
278  Solver.impose(StokesX, {1,1},{sz[0]-2,sz[1]-2}, RHS[x], vx);
279  Solver.impose(StokesY, {1,1},{sz[0]-2,sz[1]-2}, RHS[y], vy);
280  Solver.impose(V_star[x], {0,sz[1]-1},{sz[0]-1,sz[1]-1}, 1.0, vx);
281  Solver.impose(V_star[y], {0,sz[1]-1},{sz[0]-1,sz[1]-1}, 0.0, vy);
282  Solver.impose(V_star[x], {0,1},{0,sz[1]-2}, 0.0, vx);
283  Solver.impose(V_star[y], {0,1},{0,sz[1]-2}, 0.0, vy);
284  Solver.impose(V_star[x], {sz[0]-1,1},{sz[0]-1,sz[1]-2}, 0.0, vx);
285  Solver.impose(V_star[y], {sz[0]-1,1},{sz[0]-1,sz[1]-2}, 0.0, vy);
286  Solver.impose(V_star[x], {0,0},{sz[0]-1,0}, 0.0, vx);
287  Solver.impose(V_star[y], {0,0},{sz[0]-1,0}, 0.0, vy);
288  //auto A=Solver.getA();
289  //A.write("Matrix");
290  Solver.solve(V_star[x], V_star[y]);
291  //return;
292  //Solver.solve_with_solver(solverPetsc,V_star[x], V_star[y]);
293 
294  domain.ghost_get<5>(SKIP_LABELLING);
295  div = (Dx(V_star[x]) + Dy(V_star[y]));
296 
297  FD_scheme<equations2d1E,decltype(domain)> SolverH(ghost,domain);
298  auto Helmholtz = Dxx(H)+Dyy(H);
299  SolverH.impose(Helmholtz,{1,1},{sz[0]-2,sz[1]-2},div);
300  SolverH.impose(Dy(H), {0,sz[0]-1},{sz[0]-1,sz[1]-1},0);
301  SolverH.impose(Dx(H), {sz[0]-1,1},{sz[0]-1,sz[1]-2},0);
302  SolverH.impose(Dx(H), {0,0},{sz[0]-1,0},0,vx,true);
303  SolverH.impose(H, {0,0},{0,0},0);
304  SolverH.impose(Dy(H), {0,1},{0,sz[1]-2},0);
305  //SolverH.solve_with_solver(solverPetsc2,H);
306  SolverH.solve(H);
307  //dP_bulk=Bulk_Lap(H);
308  domain.ghost_get<1,4,6>(SKIP_LABELLING);
309  P = P - alpha*(div-0.5*(V[x]*Dx(H)+V[y]*Dy(H)));
310  //dV[x]=Dx(H);
311  //dV[y]=Dy(H);
312  V_star[0] = V_star[0] - Dx(H);
313  V_star[1] = V_star[1] - Dy(H);
314  sum = 0;
315  sum1 = 0;
316  auto it2 = domain.getDomainIterator();
317  while (it2.isNext()) {
318  auto p = it2.get();
319  sum += (domain.getProp<5>(p)[0] - domain.getProp<1>(p)[0]) *
320  (domain.getProp<5>(p)[0] - domain.getProp<1>(p)[0]) +
321  (domain.getProp<5>(p)[1] - domain.getProp<1>(p)[1]) *
322  (domain.getProp<5>(p)[1] - domain.getProp<1>(p)[1]);
323  sum1 += domain.getProp<5>(p)[0] * domain.getProp<5>(p)[0] +
324  domain.getProp<5>(p)[1] * domain.getProp<5>(p)[1];
325  ++it2;
326  }
327 
328  V[x] = V_star[x];
329  V[y] = V_star[y];
330  v_cl.sum(sum);
331  v_cl.sum(sum1);
332  v_cl.execute();
333  sum = sqrt(sum);
334  sum1 = sqrt(sum1);
335  V_err_old = V_err;
336  V_err = sum / sum1;
337  if (V_err > V_err_old || abs(V_err_old - V_err) < 1e-8) {
338  errctr++;
339  //alpha_P -= 0.1;
340  } else {
341  errctr = 0;
342  }
343  if (n > 3) {
344  if (errctr > 5) {
345  //std::cout << "CONVERGENCE LOOP BROKEN DUE TO INCREASE/VERY SLOW DECREASE IN ERROR" << std::endl;
346  std::cout << "Alpha Halfed DUE TO INCREASE/VERY SLOW DECREASE IN ERROR" << std::endl;
347  //alpha=alpha/2;
348  Vreset = 1;
349  errctr=0;
350  //break;
351  } else {
352  Vreset = 0;
353  }
354  }
355  n++;
356  tt.stop();
357  if (v_cl.rank() == 0) {
358  std::cout << "Rel l2 cgs err in V = " << V_err << " at " << n << " and took " <<tt.getwct() <<"("<<tt.getcputime()<<") seconds(CPU)." << std::endl;
359  }
360  }
361  double worst1 = 0.0;
362  double worst2 = 0.0;
363 
364  domain.write("LID_final");
365  tt2.stop();
366  if (v_cl.rank() == 0) {
367  std::cout << "The simulation took " << tt2.getcputime() << "(CPU) ------ " << tt2.getwct()
368  << "(Wall) Seconds.";
369  }
370  }*/
371 
372 
373 
374 
375 
376 
377  /*
378 In 3D we use exact solution:
379 
380 Vx = x^2 + y^2
381 Vy = y^2 + z^2
382 Vz = x^2 + y^2 - 2(x+y)z
383 p = x + y + z - 3/2
384 f_x = f_y = f_z = 3
385 
386 -\Delta u + \nabla p + f = <-4, -4, -4> + <1, 1, 1> + <3, 3, 3> = 0
387 \nabla \cdot u = 2x + 2y - 2(x + y) = 0
388 */
389 
390  struct lid_nn_stag
391  {
392  // dimensionaly of the equation (2D problem 3D problem ...)
393  static const unsigned int dims = 2;
394 
395  // number of fields in the system v_x, v_y, P so a total of 3
396  static const unsigned int nvar = 3;
397 
398  // boundary conditions PERIODIC OR NON_PERIODIC
399  static const bool boundary[];
400 
401  // type of space float, double, ...
402  typedef float stype;
403 
404  // type of base grid, it is the distributed grid that will store the result
405  // Note the first property is a 2D vector (velocity), the second is a scalar (Pressure)
407 
408  // type of SparseMatrix, for the linear system, this parameter is bounded by the solver
409  // that you are using, in case of umfpack it is the only possible choice
410  typedef SparseMatrix<double,int> SparseMatrix_type;
411 
412  // type of Vector for the linear system, this parameter is bounded by the solver
413  // that you are using, in case of umfpack it is the only possible choice
414  typedef Vector<double> Vector_type;
415 
416  typedef umfpack_solver<double> solver_type;
417  };
418 
419  const bool lid_nn_stag::boundary[] = {NON_PERIODIC,NON_PERIODIC};
420 
421  BOOST_AUTO_TEST_CASE(solver_Lid_driven_cavity_stag)
422  {
423  Vcluster<> & v_cl = create_vcluster();
424 
425  if (v_cl.getProcessingUnits() > 3)
426  return;
427 
429 
430  // velocity in the grid is the property 0, pressure is the property 1
431  constexpr int velocity = 0;
432  constexpr int pressure = 1;
433 
434  constexpr int x = 0;
435  constexpr int y = 1;
436 
437  // Domain, a rectangle
438  Box<2,float> domain({0.0,0.0},{3.0,1.0});
439 
440  // Ghost (Not important in this case but required)
441  //Ghost<2,float> g(0.01); // suited for particles
442  Ghost<2,long int> g(1); //better for grids
443  // Grid points on x=256 and y=64
444  long int sz[] = {256,64};
445  size_t szu[2];
446  szu[0] = (size_t)sz[0];
447  szu[1] = (size_t)sz[1];
448 
449  // We need one more point on the left and down part of the domain
450  // This is given by the boundary conditions that we impose, the
451  // reason is mathematical in order to have a well defined system
452  // and cannot be discussed here
453  Padding<2> pd({1,1},{0,0});
454 
455  // Distributed grid that store the solution
456  staggered_grid_dist<2,float,aggregate<Point<2,float>,float,Point<2,float>,float>> g_dist(szu,domain,g);
457  grid_dist_id<2,float,aggregate<Point<2,float>,float,Point<2,float>,float>> g_dist_normal(g_dist.getDecomposition(),szu,g);
458 
460  cmb_v.add({0,-1});
461  cmb_v.add({-1,0});
462 
463  g_dist.setDefaultStagPosition();
464  g_dist.setStagPosition<0>(cmb_v);
465 
466  // It is the maximum extension of the stencil
467  Ghost<2,long int> stencil_max(1);
468 
469  // Finite difference scheme
470  FD_scheme<lid_nn_stag,decltype(g_dist)> fd(pd,stencil_max,g_dist);
471 
472  auto P = FD::getV_stag<1>(g_dist);
473  auto v = FD::getV_stag<0>(g_dist);
474  auto RHS = FD::getV_stag<2>(g_dist);
475  //auto RHSy = FD::getV_stag<3>(g_dist);
476 
477 
478  v.setVarId(0);
479  P.setVarId(2);
480 
483  FD::Lap Lap;
484 
485  double nu = 1.0;
486 
487  auto Stokes_vx = nu * Lap(v[x]) - Dx(P);
488  auto Stokes_vy = nu * Lap(v[y]) - Dy(P);
489 
490  auto incompressibility = Dx(v[x]) + Dy(v[y]);
491 
492  eq_id ic,vx,vy;
493 
494  ic.setId(2);
495  vx.setId(0);
496  vy.setId(1);
497 
498  comb<2> center_cell({0,0});
499  comb<2> left_cell({0,-1});
500  comb<2> bottom_cell({-1,0});
501  comb<2> corner_right({-1,1});
502  comb<2> corner_dw({-1,-1});
503  comb<2> corner_up({1,-1});
504 
505  auto it = g_dist.getDomainIterator();
506  while (it.isNext())
507  {
508  auto key = it.get();
509  auto gkey = it.getGKey(key);
510  double xg = gkey.get(0) * g_dist.spacing(0);
511  double yg = gkey.get(1) * g_dist.spacing(1);
512  if (xg==3.0){
513  //v[y].value(key,bottom_cell)=1.0;
514  g_dist.getProp<2>(key)[1] = 1.0;
515  g_dist.getProp<3>(key) = 1.0;
516  //std::cout<<it.getGKey(key).get(0)<<","<<it.getGKey(key).get(1)<<":"<<g_dist.getProp<3>(key)<<std::endl;
517  }
518  ++it;
519  }
520 
521  // Here we impose the equation, we start from the incompressibility Eq imposed in the bulk with the
522  // exception of the first point {0,0} and than we set P = 0 in {0,0}, why we are doing this is again
523  // mathematical to have a well defined system, an intuitive explanation is that P and P + c are both
524  // solution for the incompressibility equation, this produce an ill-posed problem to make it well posed
525  // we set one point in this case {0,0} the pressure to a fixed constant for convenience P = 0
526 
527  fd.impose(incompressibility, {0,0},{sz[0]-2,sz[1]-2}, 0.0,ic,true);
528  fd.impose(P, {0,0},{0,0},0.0,ic);
529 
530  // Here we impose the Eq1 and Eq2
531  fd.impose(Stokes_vx, {1,0},{sz[0]-2,sz[1]-2},0.0,vx,left_cell);
532  fd.impose(Stokes_vy, {0,1},{sz[0]-2,sz[1]-2},0.0,vy,bottom_cell);
533 
534  // Staggering pattern in the domain
535  // +--Vy-+
536  // | |
537  // Vx P Vx
538  // | |
539  // 0--Vy-+
540  //
541  // Imposing B1
542  // Left Wall Vx without touching top wall and with specified location in the cell ("left_cell").
543  fd.impose(v[x], {0,0},{0,sz[1]-2},0.0,vx,left_cell);
544  // Left Wall Vy without touching top wall
545  // (Starts at -1 index since Vy is on top of the cell and needs special boundary treatment "corner_dw")
546  // cells in the Domain near 0,0 look like:
547  //
548  // | |
549  // Vx P(0,0)
550  // | |
551  // Vy---Vy--+
552  // :
553  // "corner_right of -1" specified by starting at -1,0
554  fd.impose(v[y], {-1,0},{-1,sz[1]-1},0.0,vy,corner_right);
555 
556  //Imposing B2
557  // Similarly Right Wall (Also need "corner_dw" treatment for Vy, hence +1 in the y index)
558  fd.impose(v[x],{sz[0]-1,0},{sz[0]-1,sz[1]-2},0.0,vx,left_cell);
559  fd.impose(v[y],{sz[0]-1,0},{sz[0]-1,sz[1]-1},prop_id<3>(),vy,corner_dw);
560 
561  // Imposing B3
562  // Similarly Bottom Wall (needs "corner_up" treatment for Vx, hence -1 in the x index)
563  fd.impose(v[x], {0,-1},{sz[0]-1,-1},0.0,vx,corner_up);
564  fd.impose(v[y], {0,0},{sz[0]-2,0},0.0,vy,bottom_cell);
565  // Imposing B4
566  // Similarly Top Wall (needs "corner_dw" treatment for Vx, hence +1 in the x index)
567  fd.impose(v[x],{0,sz[1]-1},{sz[0]-1,sz[1]-1},0.0,vx,corner_dw);
568  fd.impose(v[y],{0,sz[1]-1},{sz[0]-2,sz[1]-1},0.0,vy,bottom_cell);
569 
570  // When we pad the grid, there are points of the grid that are not
571  // touched by the previous condition. Mathematically this lead
572  // to have too many variables for the conditions that we are imposing.
573  // Here we are imposing variables that we do not touch to zero
574  //
575 
576  // Padding pressure
577  fd.impose(P, {-1,-1},{sz[0]-1,-1},0.0,ic);
578  fd.impose(P, {-1,sz[1]-1},{sz[0]-1,sz[1]-1},0.0,ic);
579  fd.impose(P, {-1,0},{-1,sz[1]-2},0.0,ic);
580  fd.impose(P, {sz[0]-1,0},{sz[0]-1,sz[1]-2},0.0,ic);
581 
582  // Impose v_x Padding Impose v_y padding
583  fd.impose(v[x], {-1,-1},{-1,sz[1]-1},0.0,vx,left_cell);
584  fd.impose(v[y], {-1,-1},{sz[0]-1,-1},0.0,vy,bottom_cell);
585 
586  fd.solve(v[x],v[y],P);
587 
588  // auto it5 = g_dist.getSubDomainIterator({1,1},{(int)g_dist.size(0)-1,(int)g_dist.size(1)-1});
589 
590  // while (it5.isNext())
591  // {
592  // auto key2 = it5.get();
593 
594  // std::cout << g_dist.template getProp<0>(key2)[0] << " " << std::endl;
595 
596  // ++it5;
597  // }
598 
599  g_dist.template ghost_get<0,1>();
600 
601  // Carefull we cannot interpolate on the border
602 
603  auto it3 = g_dist_normal.getSubDomainIterator({1,1},{(int)g_dist_normal.size(0)-1,(int)g_dist_normal.size(1)-1});
604  auto it4 = g_dist.getSubDomainIterator({1,1},{(int)g_dist.size(0)-1,(int)g_dist.size(1)-1});
605 
606  while (it3.isNext())
607  {
608  auto key = it3.get();
609  auto key2 = it4.get();
610 
611  g_dist_normal.template getProp<0>(key)[0] = v[x].value(key2,corner_dw);
612  g_dist_normal.template getProp<0>(key)[1] = v[y].value(key2,corner_dw);;
613 
614  g_dist_normal.template getProp<1>(key) = P.value(key2,corner_dw);
615  g_dist_normal.template getProp<2>(key)[x] = RHS[x].value(key2,corner_dw);
616  g_dist_normal.template getProp<2>(key)[y] = RHS[y].value(key2,corner_dw);
617 
618 
619  ++it3;
620  ++it4;
621  }
622 
623 #if !(defined(SE_CLASS3) || defined(TEST_COVERAGE_MODE))
624 
625  // Initialize openfpm
626  grid_dist_id<2,float,aggregate<float[2],float>> g_dist2(g_dist.getDecomposition(),szu,g);
627  g_dist2.load("test/lid_driven_cavity_reference.hdf5");
628 
629  auto it2 = g_dist2.getSubDomainIterator({1,1},{(int)g_dist2.size(0)-1,(int)g_dist2.size(1)-1});
630 
631  bool test = true;
632  while (it2.isNext())
633  {
634  auto p = it2.get();
635 
636  test &= fabs(g_dist2.template getProp<velocity>(p)[0] - g_dist_normal.template getProp<velocity>(p)[0]) < 3.5e-3;
637  test &= fabs(g_dist2.template getProp<velocity>(p)[1] - g_dist_normal.template getProp<velocity>(p)[1]) < 3.5e-3;
638 
639  test &= fabs(g_dist2.template getProp<pressure>(p) - g_dist_normal.template getProp<pressure>(p)) < 3.0;
640 
641  if (test == false)
642  {
643  std::cout << g_dist2.template getProp<velocity>(p)[0] << " " << g_dist_normal.template getProp<velocity>(p)[0] << std::endl;
644  std::cout << g_dist2.template getProp<velocity>(p)[1] << " " << g_dist_normal.template getProp<velocity>(p)[1] << std::endl;
645 
646  std::cout << g_dist2.template getProp<pressure>(p) << " " << g_dist_normal.template getProp<pressure>(p) << std::endl;
647 
648  //g_dist_normal.template getProp<0>(p)[1] = v[y].value(p,corner_dw);
649 
650  g_dist_normal.template getProp<1>(p) = P.value(p,corner_dw);
651 
652  break;
653  }
654 
655  ++it2;
656  }
657 
658  BOOST_REQUIRE_EQUAL(test,true);
659 
660 #endif
661  }
662 
663 
664  struct ana_nn_stag
665  {
666  // dimensionaly of the equation (2D problem 3D problem ...)
667  static const unsigned int dims = 2;
668 
669  // number of fields in the system v_x, v_y, P so a total of 3
670  static const unsigned int nvar = 3;
671 
672  // boundary conditions PERIODIC OR NON_PERIODIC
673  static const bool boundary[];
674 
675  // type of space float, double, ...
676  typedef float stype;
677 
678  // type of base grid, it is the distributed grid that will store the result
679  // Note the first property is a 2D vector (velocity), the second is a scalar (Pressure)
681 
682  // type of SparseMatrix, for the linear system, this parameter is bounded by the solver
683  // that you are using, in case of umfpack it is the only possible choice
684  // typedef SparseMatrix<double,int> SparseMatrix_type;
685  // // typedef SparseMatrix<double, int, PETSC_BASE> SparseMatrix_type;
686 
687  // // type of Vector for the linear system, this parameter is bounded by the solver
688  // // that you are using, in case of umfpack it is the only possible choice
689  // typedef Vector<double> Vector_type;
690  // // typedef Vector<double, PETSC_BASE> Vector_type;
691 
692  // typedef umfpack_solver<double> solver_type;
693  // // typedef petsc_solver<double> solver_type;
695  typedef SparseMatrix<double, int, PETSC_BASE> SparseMatrix_type;
696 
698  typedef Vector<double, PETSC_BASE> Vector_type;
699 
700  typedef petsc_solver<double> solver_type;
701  };
702 
703  const bool ana_nn_stag::boundary[] = {NON_PERIODIC,NON_PERIODIC};
704 
705  /*
706  In 2D we use exact solution:
707 
708  u = x^2 + y^2
709  v = 2 x^2 - 2xy
710  p = x + y - 1
711  f_x = f_y = 3
712 
713  so that
714 
715  -\Delta u + \nabla p + f = <-4, -4> + <1, 1> + <3, 3> = 0
716  \Delta u - \nabla p = +f
717  \nabla \cdot u = 2x - 2x = 0
718  */
719 #if 0
720  //These tests need development and checks
721  BOOST_AUTO_TEST_CASE(solver_ana_stag)
722  {
723  Vcluster<> & v_cl = create_vcluster();
724 
725  if (v_cl.getProcessingUnits() > 3)
726  return;
727 
728  // velocity in the grid is the property 0, pressure is the property 1
729  constexpr int velocity = 0;
730  constexpr int pressure = 1;
731 
732  constexpr int x = 0;
733  constexpr int y = 1;
734 
735  // Domain, a rectangle
736  Box<2,float> domain({0.0,0.0},{1.0,1.0});
737 
738  // Grid points on x=256 and y=256
739  long int sz[] = {256,256};
740  // Ghost (Not important in this case but required)
741  Ghost<2,float> g(domain.getHigh(0)/sz[0]);
742 
743  size_t szu[2];
744  szu[0] = (size_t)sz[0];
745  szu[1] = (size_t)sz[1];
746 
747  Padding<2> pd({1,1},{0,0});
748 
749  // Distributed grid that store the solution
750  staggered_grid_dist<2,float,aggregate<Point<2,float>,float,Point<2,float>,float,float,float>> g_dist(szu,domain,g);
751  grid_dist_id<2,float,aggregate<Point<2,float>,float,Point<2,float>,float,float,float>> g_dist_normal(g_dist.getDecomposition(),szu,g);
752 
753  double hx = g_dist.spacing(0);
754  double hy = g_dist.spacing(1);
755 
757  cmb_v.add({0,-1});
758  cmb_v.add({-1,0});
759 
760  g_dist.setDefaultStagPosition();
761  g_dist.setStagPosition<0>(cmb_v);
762 
763  // It is the maximum extension of the stencil
764  Ghost<2,long int> stencil_max(1);
765 
766  // Finite difference scheme
767  FD_scheme<lid_nn_stag,decltype(g_dist)> fd(pd,stencil_max,g_dist);
768 
769  auto P = FD::getV_stag<1>(g_dist);
770  auto v = FD::getV_stag<0>(g_dist);
771  auto Ana_v = FD::getV_stag<2>(g_dist);
772  auto Ana_P = FD::getV_stag<3>(g_dist);
773 
774  v.setVarId(0);
775  P.setVarId(2);
776 
779  FD::Lap Lap;
780 
781  auto Stokes_vx = Lap(v[x]) - Dx(P);
782  auto Stokes_vy = Lap(v[y]) - Dy(P);
783 
784  auto incompressibility = Dx(v[x]) + Dy(v[y]);
785 
786  eq_id ic,vx,vy;
787 
788  ic.setId(2);
789  vx.setId(0);
790  vy.setId(1);
791 
792  comb<2> center_cell({0,0});
793  comb<2> left_cell({0,-1});
794  comb<2> bottom_cell({-1,0});
795  comb<2> corner_right({-1,1});
796  comb<2> corner_dw({-1,-1});
797  comb<2> corner_up({1,-1});
798 
799  auto fu = [](double x, double y) { return x*x + y*y; };
800  auto fv = [](double x, double y) { return 2.0*x*x - 2.0*x*y; };
801 
802  // Staggering pattern in the domain
803  // +--Vy-+
804  // | |
805  // Vx P Vx
806  // | |
807  // 0--Vy-+
808  //
809 
810  fd.impose(incompressibility, {0,0},{sz[0]-2,sz[1]-2}, 0.0,ic,true);
811  fd.impose(P, {0,0},{0,0},(hx+hy)/2-1.0,ic);
812 
813  fd.impose(Stokes_vx, {1,0},{sz[0]-2,sz[1]-2},3.0,vx,left_cell);
814  fd.impose(Stokes_vy, {0,1},{sz[0]-2,sz[1]-2},3.0,vy,bottom_cell);
815 
816  // Imposing B1 Left Wall
817  fd.impose(v[x], {0,0},{0,sz[1]-2},fu,vx,left_cell);
818  fd.impose(v[y], {-1,0},{-1,sz[1]-1},fv,vy,corner_right);
819 
820  // //Imposing B2 Right Wall
821  fd.impose(v[x],{sz[0]-1,0},{sz[0]-1,sz[1]-2},fu,vx,left_cell);
822  fd.impose(v[y],{sz[0]-1,0},{sz[0]-1,sz[1]-1},fv,vy,corner_dw);
823 
824  // Imposing B3 Bottom Wall
825  fd.impose(v[x],{0,-1},{sz[0]-1,-1},fu,vx,corner_up);
826  fd.impose(v[y], {0,0},{sz[0]-2,0},fv,vy,bottom_cell);
827 
828  // Imposing B4 Top Wall
829  fd.impose(v[x],{0,sz[1]-1},{sz[0]-1,sz[1]-1},fu,vx,corner_dw);
830  fd.impose(v[y],{0,sz[1]-1},{sz[0]-2,sz[1]-1},fv,vy,bottom_cell);
831 
832  // Padding pressure
833  fd.impose(P, {-1,-1},{sz[0]-1,-1},0.0,ic);
834  fd.impose(P, {-1,sz[1]-1},{sz[0]-1,sz[1]-1},0.0,ic);
835  fd.impose(P, {-1,0},{-1,sz[1]-2},0.0,ic);
836  fd.impose(P, {sz[0]-1,0},{sz[0]-1,sz[1]-2},0.0,ic);
837 
838  // Impose v_x Padding Impose v_y padding
839  fd.impose(v[x], {-1,-1},{-1,sz[1]-1},0.0,vx,left_cell);
840  fd.impose(v[y], {-1,-1},{sz[0]-1,-1},0.0,vy,bottom_cell);
841 
842  fd.solve(v[x],v[y],P);
843 
844  auto it2 = g_dist_normal.getDomainIterator();
845 
846  while (it2.isNext())
847  {
848  auto key = it2.get();
849  auto gkey = it2.getGKey(key);
850  double x = gkey.get(0) * g_dist_normal.spacing(0);
851  double y = gkey.get(1) * g_dist_normal.spacing(1);
852 
853  g_dist_normal.template getProp<0>(key)[0] = v[0].value(key,left_cell);
854  g_dist_normal.template getProp<0>(key)[1] = v[1].value(key,bottom_cell);
855 
856  g_dist_normal.template getProp<1>(key) = P.value(key,center_cell);
857 
858  g_dist_normal.template getProp<2>(key)[0] = x*x + y*y;
859  g_dist_normal.template getProp<2>(key)[1] = 2*x*x - 2*x*y;
860  g_dist_normal.template getProp<3>(key) = x + y - 1;
861  ++it2;
862  }
863 
864  g_dist_normal.write("ana_stokes");
865 
867 
868  //g_dist.write("ana_stokes")
869  }
870 
871 #endif
872 
873 
874 BOOST_AUTO_TEST_SUITE_END()
875 #endif //Have Eigen
876 #endif //Have Petsc
void setPreconditioner(PCType type)
Set the preconditioner of the linear solver.
Finite Differences.
Definition: FD_Solver.hpp:127
Specify the general characteristic of system to solve.
Position of the element of dimension d in the hyper-cube of dimension dim.
Definition: comb.hpp:34
Sparse Matrix implementation stub object when OpenFPM is compiled with no linear algebra support.
Definition: Vector.hpp:39
Specify the general characteristic of system to solve.
Definition: EqnsStruct.hpp:13
Class that contain Padding information on each direction positive and Negative direction.
Definition: Ghost.hpp:126
This class implement the point shape in an N-dimensional space.
Definition: Point.hpp:27
St spacing(size_t i) const
Get the spacing of the grid in direction i.
stub when library compiled without eigen
Definition: Ghost.hpp:39
Implementation of VCluster class.
Definition: VCluster.hpp:58
This class decompose a space into sub-sub-domains and distribute them across processors.
Sparse Matrix implementation.
This is a distributed grid.
Implementation of the staggered grid.
This class is able to do Matrix inversion in parallel with PETSC solvers.
KeyT const ValueT ValueT OffsetIteratorT OffsetIteratorT int
[in] The number of segments that comprise the sorting data
size_t getProcessingUnits()
Get the total number of processors.
Laplacian second order on h (spacing)
Definition: Laplacian.hpp:22
This class represent an N-dimensional box.
Definition: Box.hpp:60
Test structure used for several test.
Definition: Point_test.hpp:105
Implementation of 1-D std::vector like structure.
Definition: map_vector.hpp:202
void load(const std::string &filename)
Reload the grid from HDF5 file.
Boundary conditions.
Definition: common.hpp:21