OpenFPM  5.2.0
Project that contain the implementation of distributed structures
main.cpp
1 /*
2  * ### WIKI 1 ###
3  *
4  * ## Simple example
5  *
6  * In this example we show 1D PSE derivative function approximation
7  *
8  * ### WIKI END ###
9  *
10  */
11 
12 #include "Vector/vector_dist.hpp"
13 #include "Decomposition/CartDecomposition.hpp"
14 #include "PSE/Kernels.hpp"
15 #include "data_type/aggregate.hpp"
16 #include <cmath>
17 
18 
19 /*
20  * ### WIKI 2 ###
21  *
22  * Here we define the function x*e^(-x*x) and its
23  * second derivative in analytic form
24  *
25  * 2x*(2*x-3)*e^(-x^2)
26  *
27  */
28 
29 double f_xex2(double x)
30 {
31  return x*exp(-x*x);
32 }
33 
34 double f_xex2(Point<1,double> & x)
35 {
36  return x.get(0)*exp(-x.get(0)*x.get(0));
37 }
38 
39 double Lapf_xex2(Point<1,double> & x)
40 {
41  return 2.0*x.get(0)*(2.0*x.get(0)*x.get(0) - 3.0)*exp(-x.get(0)*x.get(0));
42 }
43 
44 /*
45  *
46  * ### WIKI END ###
47  *
48  */
49 
50 int main(int argc, char* argv[])
51 {
52  //
53  // ### WIKI 3 ###
54  //
55  // Some useful parameters. Like
56  //
57  // * Number of particles
58  // * Minimum number of padding particles
59  // * The computational domain
60  // * The spacing
61  // * The mollification length
62  // * Second order Laplacian kernel in 1D
63  //
64 
65  // Number of particles
66  const size_t Npart = 125;
67 
68  // Number of padding particles (At least)
69  const size_t Npad = 40;
70 
71  // The domain
72  Box<1,double> box({0.0},{4.0});
73 
74  // Calculated spacing
75  double spacing = box.getHigh(0) / Npart;
76 
77  // Epsilon of the particle kernel
78  const double eps = 2*spacing;
79 
80  // Laplacian PSE kernel 1 dimension, on double, second order
81  Lap_PSE<1,double,2> lker(eps);
82 
83  //
84  // ### WIKI 2 ###
85  //
86  // Here we Initialize the library and we define Ghost size
87  // and non-periodic boundary conditions
88  //
89  openfpm_init(&argc,&argv);
90  Vcluster<> & v_cl = create_vcluster();
91 
92  size_t bc[1]={NON_PERIODIC};
93  Ghost<1,double> g(12*eps);
94 
95  //
96  // ### WIKI 3 ###
97  //
98  // Here we are creating a distributed vector defined by the following parameters
99  //
100  // we create a set of N+1 particles to have a fully covered domain of particles between 0.0 and 4.0
101  // Suppose we have a spacing given by 1.0 you need 4 +1 particles to cover your domain
102  //
103  vector_dist<1,double, aggregate<double> > vd(Npart+1,box,bc,g);
104 
105  //
106  // ### WIKI 4 ###
107  //
108  // We assign the position to the particles, the scalar property is set to
109  // the function x*e^(-x*x) value.
110  // Each processor has parts of the particles and fill part of the space, the
111  // position is assigned independently from the decomposition.
112  //
113  // In this case, if there are 1001 particles and 3 processors the in the
114  // domain from 0.0 to 4.0
115  //
116  // * processor 0 place particles from 0.0 to 1.332 (334 particles)
117  // * processor 1 place particles from 1.336 to 2.668 (334 particles)
118  // * processor 2 place particles from 2.672 to 4.0 (333 particles)
119  //
120 
121  // It return how many particles the processors with id < rank has in total
122  size_t base = vd.init_size_accum(Npart+1);
123  auto it2 = vd.getIterator();
124 
125  while (it2.isNext())
126  {
127  auto key = it2.get();
128 
129  // set the position of the particles
130  vd.getPos(key)[0] = (key.getKey() + base) * spacing;
131  //set the property of the particles
132  vd.template getProp<0>(key) = f_xex2((key.getKey() + base) * spacing);
133 
134  ++it2;
135  }
136 
137  //
138  // ### WIKI 5 ###
139  //
140  // Once defined the position, we distribute them across the processors
141  // following the decomposition, finally we get the ghost part
142  //
143  vd.map();
144  vd.ghost_get<0>();
145 
146  //
147  // ### WIKI 6 ###
148  //
149  // near the boundary we have two options, or we use one sided kernels,
150  // or we add additional particles, it is required that such particles
151  // produces a 2 time differentiable function. In order to obtain such
152  // result we extend for x < 0.0 and x > 4.0 with the test function xe^(-x*x).
153  //
154  // Note that for x < 0.0 such extension is equivalent to mirror the
155  // particles changing the sign of the strength
156  //
157  // \verbatim
158  //
159  // 0.6 -0.5 0.5 0.6 Strength
160  // +----+----*----*----*-
161  // 0.0 Position
162  //
163  // with * = real particle
164  // + = mirror particle
165  //
166  // \endverbatim
167  //
168  //
169  Box<1,double> m_pad({0.0},{0.1});
170  Box<1,double> m_pad2({3.9},{4.0});
171  double enlarge = 0.1;
172 
173  // Create a box
174  if (Npad * spacing > 0.1)
175  {
176  m_pad.setHigh(0,Npad * spacing);
177  m_pad2.setLow(0,4.0 - Npad*spacing);
178  enlarge = Npad * spacing;
179  }
180 
181  auto it = vd.getDomainIterator();
182 
183  while (it.isNext())
184  {
185  auto key = it.get();
186 
187  // set the position of the particles
188  if (m_pad.isInsideNB(vd.getPos(key)) == true)
189  {
190  vd.add();
191  vd.getLastPos()[0] = - vd.getPos(key)[0];
192  vd.template getLastProp<0>() = - vd.template getProp<0>(key);
193  }
194 
195  // set the position of the particles
196  if (m_pad2.isInsideNB(vd.getPos(key)) == true)
197  {
198  vd.add();
199  vd.getLastPos()[0] = 2.0 * box.getHigh(0) - vd.getPos(key)[0];
200  vd.template getLastProp<0>() = f_xex2(vd.getLastPos()[0]);
201  }
202 
203  ++it;
204  }
205 
206  //
207  // ### WIKI 7 ###
208  //
209  // We create a CellList with cell spacing 12 sigma
210  //
211 
212  // get and construct the Cell list
213  auto cl = vd.getCellList(12*eps, CL_NON_SYMMETRIC, false, enlarge);
214 
215  // Maximum infinity norm
216  double linf = 0.0;
217 
218  //
219  // ### WIKI 8 ###
220  //
221  // For each particle get the neighborhood of each particle
222  //
223  // This cycle is literally the formula from PSE operator approximation
224  //
225  // \$ \frac{1}{\epsilon^{2}} h (u_{q} - u_{p}) \eta_{\epsilon}(x_q - x_p) \$
226  //
227 
228  auto it_p = vd.getDomainIterator();
229  while (it_p.isNext())
230  {
231  // double PSE integration accumulator
232  double pse = 0;
233 
234  // key
235  vect_dist_key_dx key = it_p.get();
236 
237  // Get the position of the particles
238  Point<1,double> p = vd.getPos(key);
239 
240  // We are not interested in calculating out the domain
241  // note added padding particle are considered domain particles
242  if (p.get(0) < 0.0 || p.get(0) >= 4.0)
243  {
244  ++it_p;
245  continue;
246  }
247 
248  // Get f(x) at the position of the particle
249  double prp_x = vd.template getProp<0>(key);
250 
251  // Get the neighborhood of the particles
252  auto NN = cl.getNNIteratorBox(cl.getCell(p));
253  while(NN.isNext())
254  {
255  auto nnp = NN.get();
256 
257  // Calculate contribution given by the kernel value at position p,
258  // given by the Near particle
259  if (nnp != key.getKey())
260  {
261  // W(x-y)
262  double ker = lker.value(p,vd.getPos(nnp));
263 
264  // f(y)
265  double prp_y = vd.template getProp<0>(nnp);
266 
267  // 1.0/(eps)^2 [f(y)-f(x)]*W(x,y)*V_q
268  double prp = 1.0/eps/eps * (prp_y - prp_x) * spacing;
269  pse += prp * ker;
270  }
271 
272  // Next particle
273  ++NN;
274  }
275 
276  // Here we calculate the L_infinity norm or the maximum difference
277  // of the analytic solution from the PSE calculated
278 
279  double sol = Lapf_xex2(p);
280 
281  if (fabs(pse - sol) > linf)
282  linf = fabs(pse - sol);
283 
284  ++it_p;
285  }
286 
287  //
288  // ### WIKI 9 ###
289  //
290  // Calculate the maximum infinity norm across processors and
291  // print it
292  //
293 
294  v_cl.max(linf);
295  v_cl.execute();
296 
297  if (v_cl.getProcessUnitID() == 0)
298  std::cout << "Norm infinity: " << linf << "\n";
299 
300  //
301  // ### WIKI 10 ###
302  //
303  // Deinitialize the library
304  //
305  openfpm_finalize();
306 }
This class represent an N-dimensional box.
Definition: Box.hpp:60
__device__ __host__ T getHigh(int i) const
get the high interval of the box
Definition: Box.hpp:566
__device__ __host__ void setHigh(int i, T val)
set the high interval of the box
Definition: Box.hpp:543
Definition: Ghost.hpp:40
This class implement the point shape in an N-dimensional space.
Definition: Point.hpp:28
void execute()
Execute all the requests.
size_t getProcessUnitID()
Get the process unit id.
void max(T &num)
Get the maximum number across all processors (or reduction with infinity norm)
Implementation of VCluster class.
Definition: VCluster.hpp:59
Grid key for a distributed grid.
__device__ __host__ size_t getKey() const
Get the key.
Distributed vector.
Implementation of the Laplacian kernels for PSE.
Definition: Kernels.hpp:26