OpenFPM_pdata  1.1.0
Project that contain the implementation of distributed structures
 All Data Structures Namespaces Functions Variables Typedefs Enumerations Friends Pages
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 
214  Ghost<1,double> gp(enlarge);
215  auto cl = vd.getCellList(12*eps,gp);
216 
217  // Maximum infinity norm
218  double linf = 0.0;
219 
220  //
221  // ### WIKI 8 ###
222  //
223  // For each particle get the neighborhood of each particle
224  //
225  // This cycle is literally the formula from PSE operator approximation
226  //
227  // \$ \frac{1}{\epsilon^{2}} h (u_{q} - u_{p}) \eta_{\epsilon}(x_q - x_p) \$
228  //
229 
230  auto it_p = vd.getDomainIterator();
231  while (it_p.isNext())
232  {
233  // double PSE integration accumulator
234  double pse = 0;
235 
236  // key
237  vect_dist_key_dx key = it_p.get();
238 
239  // Get the position of the particles
240  Point<1,double> p = vd.getPos(key);
241 
242  // We are not interested in calculating out the domain
243  // note added padding particle are considered domain particles
244  if (p.get(0) < 0.0 || p.get(0) >= 4.0)
245  {
246  ++it_p;
247  continue;
248  }
249 
250  // Get f(x) at the position of the particle
251  double prp_x = vd.template getProp<0>(key);
252 
253  // Get the neighborhood of the particles
254  auto NN = cl.template getNNIterator<NO_CHECK>(cl.getCell(p));
255  while(NN.isNext())
256  {
257  auto nnp = NN.get();
258 
259  // Calculate contribution given by the kernel value at position p,
260  // given by the Near particle
261  if (nnp != key.getKey())
262  {
263  // W(x-y)
264  double ker = lker.value(p,vd.getPos(nnp));
265 
266  // f(y)
267  double prp_y = vd.template getProp<0>(nnp);
268 
269  // 1.0/(eps)^2 [f(y)-f(x)]*W(x,y)*V_q
270  double prp = 1.0/eps/eps * (prp_y - prp_x) * spacing;
271  pse += prp * ker;
272  }
273 
274  // Next particle
275  ++NN;
276  }
277 
278  // Here we calculate the L_infinity norm or the maximum difference
279  // of the analytic solution from the PSE calculated
280 
281  double sol = Lapf_xex2(p);
282 
283  if (fabs(pse - sol) > linf)
284  linf = fabs(pse - sol);
285 
286  ++it_p;
287  }
288 
289  //
290  // ### WIKI 9 ###
291  //
292  // Calculate the maximum infinity norm across processors and
293  // print it
294  //
295 
296  v_cl.max(linf);
297  v_cl.execute();
298 
299  if (v_cl.getProcessUnitID() == 0)
300  std::cout << "Norm infinity: " << linf << "\n";
301 
302  //
303  // ### WIKI 10 ###
304  //
305  // Deinitialize the library
306  //
307  openfpm_finalize();
308 }
size_t getProcessUnitID()
Get the process unit id.
void execute()
Execute all the requests.
T getHigh(int i) const
get the high interval of the box
Definition: Box.hpp:490
void setHigh(int i, T val)
set the high interval of the box
Definition: Box.hpp:467
This class implement the point shape in an N-dimensional space.
Definition: Point.hpp:22
Grid key for a distributed grid.
void max(T &num)
Get the maximum number across all processors (or reduction with infinity norm)
Definition: Ghost.hpp:39
Implementation of the Laplacian kernels for PSE.
Definition: Kernels.hpp:25
Implementation of VCluster class.
Definition: VCluster.hpp:36
const T & get(size_t i) const
Get coordinate.
Definition: Point.hpp:142
size_t getKey() const
Get the key.
This class represent an N-dimensional box.
Definition: Box.hpp:56
This class is a trick to indicate the compiler a specific specialization pattern. ...
Definition: memory_c.hpp:201
Distributed vector.