OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
Distribution_unit_tests.hpp
1 /*
2  * Distribution_unit_tests.hpp
3  *
4  * Created on: Feb 27, 2016
5  * Author: i-bird
6  */
7 
8 #ifndef SRC_DECOMPOSITION_DISTRIBUTION_DISTRIBUTION_UNIT_TESTS_HPP_
9 #define SRC_DECOMPOSITION_DISTRIBUTION_DISTRIBUTION_UNIT_TESTS_HPP_
10 
11 #include "config.h"
12 #include "SpaceDistribution.hpp"
13 #include <unistd.h>
14 #include "BoxDistribution.hpp"
15 
26 template<unsigned int dim, typename Distribution> void setSphereComputationCosts(Distribution & dist, grid_sm<dim, void> & gr, Point<3, float> center, float radius, size_t max_l, size_t min_l)
27 {
28  float radius2 = radius * radius;
29  float eq;
30 
31  // Position structure for the single vertex
32  float pos[dim];
33 
34  for (size_t i = 0; i < dist.getNSubSubDomains(); i++)
35  {
36  dist.getSubSubDomainPosition(i, pos);
37 
38  eq = 0;
39  for (size_t j = 0; j < dim; j++)
40  eq += (pos[j] - center.get(j)) * (pos[j] - center.get(j));
41 
42  if (eq <= radius2)
43  {
44  dist.setComputationCost(i, max_l);
45  dist.setMigrationCost(i, max_l * 2);
46  }
47  else
48  {
49  dist.setComputationCost(i, min_l);
50  dist.setMigrationCost(i, min_l * 2);
51  }
52 
53  // set Migration cost and communication cost
54  for (size_t j = 0; j < dist.getNSubSubDomainNeighbors(i); j++)
55  dist.setCommunicationCost(i, j, 1);
56  }
57 }
58 
59 BOOST_AUTO_TEST_SUITE (Distribution_test)
60 
61 BOOST_AUTO_TEST_CASE( Metis_distribution_test)
62 {
63  Vcluster<> & v_cl = create_vcluster();
64 
65  if (v_cl.getProcessingUnits() != 3)
66  return;
67 
69 
70  MetisDistribution<3, float> met_dist(v_cl);
71 
72  // Cartesian grid
73  size_t sz[3] = { GS_SIZE, GS_SIZE, GS_SIZE };
74 
75  // Box
76  Box<3, float> box( { 0.0, 0.0, 0.0 }, { 1.0, 1.0, 1.0 });
77 
78  // Grid info
79  grid_sm<3, void> info(sz);
80 
81  // Set metis on test, It fix the seed (not required if we are not testing)
82  met_dist.onTest();
83 
84  // Initialize Cart graph and decompose
85 
86  met_dist.createCartGraph(info,box);
87  met_dist.decompose();
88 
89  BOOST_REQUIRE_EQUAL(met_dist.get_ndec(),1ul);
90 
92 
93  BOOST_REQUIRE(met_dist.getUnbalance() < 0.03);
94 
95  if (v_cl.getProcessUnitID() == 0)
96  {met_dist.write("vtk_metis_distribution");}
97 
98  size_t b = GS_SIZE * GS_SIZE * GS_SIZE / 5;
99 
101 
102  // Initialize the weights to 1.0
103  // not required, if we set ALL Computation,Migration,Communication cost
104 
105  // Change set some weight on the graph and re-decompose
106 
107  for (size_t k = 0; k < met_dist.getNOwnerSubSubDomains(); k++)
108  {
109  size_t i = met_dist.getOwnerSubSubDomain(k);
110 
111  if (i == 0 || i == b || i == 2*b || i == 3*b || i == 4*b)
112  met_dist.setComputationCost(i,10);
113  else
114  met_dist.setComputationCost(i,1);
115  }
116 
117  for (size_t i = 0 ; i < met_dist.getNSubSubDomains() ; i++)
118  {
119  // We also show how to set some Communication and Migration cost
120 
121  met_dist.setMigrationCost(i,1);
122 
123  for (size_t j = 0; j < met_dist.getNSubSubDomainNeighbors(i); j++)
124  met_dist.setCommunicationCost(i,j,1);
125  }
126 
127  met_dist.decompose();
128 
129  BOOST_REQUIRE_EQUAL(met_dist.get_ndec(),2ul);
130 
132 
133  BOOST_REQUIRE(met_dist.getUnbalance() < 0.06);
134 
135  if (v_cl.getProcessUnitID() == 0)
136  {met_dist.write("vtk_metis_distribution_red");}
137 
138  // check that match
139 
140  bool test;
141 
142  if (v_cl.getProcessUnitID() == 0)
143  {
144  #ifdef HAVE_OSX
145 
146  #ifndef __ARM_ARCH
147  test = compare("0_vtk_metis_distribution.vtk", "src/Decomposition/Distribution/test_data/vtk_metis_distribution_osx_test.vtk");
148  BOOST_REQUIRE_EQUAL(true,test);
149  test = compare("0_vtk_metis_distribution_red.vtk","src/Decomposition/Distribution/test_data/vtk_metis_distribution_red_osx_test.vtk");
150  BOOST_REQUIRE_EQUAL(true,test);
151  #endif
152 
153  #elif __GNUC__ == 6 && __GNUC_MINOR__ == 3
154 
155  test = compare("0_vtk_metis_distribution.vtk", "src/Decomposition/Distribution/test_data/vtk_metis_distribution_test.vtk");
156  BOOST_REQUIRE_EQUAL(true,test);
157  test = compare("0_vtk_metis_distribution_red.vtk","src/Decomposition/Distribution/test_data/vtk_metis_distribution_red_test.vtk");
158  BOOST_REQUIRE_EQUAL(true,test);
159 
160  #endif
161  }
162 
163  // Copy the Metis distribution
164 
165  MetisDistribution<3, float> met_dist2(v_cl);
166 
167  met_dist2 = met_dist;
168 
169  test = (met_dist2 == met_dist);
170 
171  BOOST_REQUIRE_EQUAL(test,true);
172 
173  // We fix the size of MetisDistribution if you are gointg to change this number
174  // please check the following
175  // duplicate functions
176  // swap functions
177  // Copy constructors
178  // operator= functions
179  // operator== functions
180 
181 // BOOST_REQUIRE_EQUAL(sizeof(MetisDistribution<3,float>),720ul);
182 }
183 
184 BOOST_AUTO_TEST_CASE( Parmetis_distribution_test)
185 {
186  Vcluster<> & v_cl = create_vcluster();
187 
188  if (v_cl.getProcessingUnits() != 3)
189  return;
190 
192 
193  ParMetisDistribution<3, float> pmet_dist(v_cl);
194 
195  // Physical domain
196  Box<3, float> box( { 0.0, 0.0, 0.0 }, { 10.0, 10.0, 10.0 });
197 
198  // Grid info
199  grid_sm<3, void> info( { GS_SIZE, GS_SIZE, GS_SIZE });
200 
201  // Initialize Cart graph and decompose
202  pmet_dist.createCartGraph(info,box);
203 
204  // First create the center of the weights distribution, check it is coherent to the size of the domain
205  Point<3, float> center( { 2.0, 2.0, 2.0 });
206 
207  // It produces a sphere of radius 2.0
208  // with high computation cost (5) inside the sphere and (1) outside
209  setSphereComputationCosts(pmet_dist, info, center, 2.0f, 5ul, 1ul);
210 
211  // first decomposition
212  pmet_dist.decompose();
213 
214  BOOST_REQUIRE_EQUAL(pmet_dist.get_ndec(),1ul);
215 
217 
218  if (v_cl.getProcessUnitID() == 0)
219  {
220  // write the first decomposition
221  pmet_dist.write("vtk_parmetis_distribution_0");
222 
223 #ifdef HAVE_OSX
224 
225  #ifndef __ARM_ARCH
226  bool test = compare(std::to_string(v_cl.getProcessUnitID()) + "_vtk_parmetis_distribution_0.vtk","src/Decomposition/Distribution/test_data/" + std::to_string(v_cl.getProcessUnitID()) + "_vtk_parmetis_distribution_0_osx_test.vtk");
227  BOOST_REQUIRE_EQUAL(true,test);
228  #endif
229 
230 #else
231 
232  bool test = compare(std::to_string(v_cl.getProcessUnitID()) + "_vtk_parmetis_distribution_0.vtk","src/Decomposition/Distribution/test_data/" + std::to_string(v_cl.getProcessUnitID()) + "_vtk_parmetis_distribution_0_test.vtk");
233  BOOST_REQUIRE_EQUAL(true,test);
234 
235 #endif
236  }
237 
239 
240  float stime = 0.0, etime = 10.0, tstep = 0.1;
241 
242  // Shift of the sphere at each iteration
243  Point<3, float> shift( { tstep, tstep, tstep });
244 
245  size_t iter = 1;
246  size_t n_dec = 1;
247 
248  for(float t = stime; t < etime; t = t + tstep, iter++)
249  {
250  if(t < etime/2)
251  center += shift;
252  else
253  center -= shift;
254 
255  setSphereComputationCosts(pmet_dist, info, center, 2.0f, 5, 1);
256 
257  // With some regularity refine and write the parmetis distribution
258  if ((size_t)iter % 10 == 0)
259  {
260  pmet_dist.refine();
261  n_dec++;
262  BOOST_REQUIRE_EQUAL(pmet_dist.get_ndec(),n_dec);
263 
264  if (v_cl.getProcessUnitID() == 0)
265  {
266  std::stringstream str;
267  str << "vtk_parmetis_distribution_" << iter;
268  pmet_dist.write(str.str());
269 
270 #ifdef HAVE_OSX
271 
272  #ifndef __ARM_ARCH
273  // Check
274  bool test = compare(std::to_string(v_cl.getProcessUnitID()) + "_" + str.str() + ".vtk", "src/Decomposition/Distribution/test_data/" + std::to_string(v_cl.getProcessUnitID()) + "_" + str.str() + "_osx_test.vtk");
275  BOOST_REQUIRE_EQUAL(true,test);
276  #endif
277 
278 #else
279 
280  // Check
281  bool test = compare(std::to_string(v_cl.getProcessUnitID()) + "_" + str.str() + ".vtk", "src/Decomposition/Distribution/test_data/" + std::to_string(v_cl.getProcessUnitID()) + "_" + str.str() + "_test.vtk");
282  BOOST_REQUIRE_EQUAL(true,test);
283 
284 #endif
285  }
286  }
287  }
288 
290 
291 // BOOST_REQUIRE_EQUAL(sizeof(ParMetisDistribution<3,float>),872ul);
292 }
293 
294 BOOST_AUTO_TEST_CASE( DistParmetis_distribution_test)
295 {
296  Vcluster<> & v_cl = create_vcluster();
297 
298  if (v_cl.getProcessingUnits() != 3)
299  return;
300 
302 
303  DistParMetisDistribution<3, float> pmet_dist(v_cl);
304 
305  // Physical domain
306  Box<3, float> box( { 0.0, 0.0, 0.0 }, { 10.0, 10.0, 10.0 });
307 
308  // Grid info
309  grid_sm<3, void> info( { GS_SIZE, GS_SIZE, GS_SIZE });
310 
311  // Initialize Cart graph and decompose
312  pmet_dist.createCartGraph(info,box);
313 
314  // First create the center of the weights distribution, check it is coherent to the size of the domain
315  Point<3, float> center( { 2.0, 2.0, 2.0 });
316 
317  // It produces a sphere of radius 2.0
318  // with high computation cost (5) inside the sphere and (1) outside
319  setSphereComputationCosts(pmet_dist, info, center, 2.0f, 5ul, 1ul);
320 
321  // first decomposition
322  pmet_dist.decompose();
323 
325 
326  // write the first decomposition
327  pmet_dist.write("vtk_dist_parmetis_distribution_0");
328 
329  // Check
330  if (v_cl.getProcessUnitID() == 0)
331  {
332 
333  #ifdef HAVE_OSX
334 
335  #ifndef __ARM_ARCH
336  bool test = compare("vtk_dist_parmetis_distribution_0.vtk","src/Decomposition/Distribution/test_data/vtk_dist_parmetis_distribution_0_osx_test.vtk");
337  BOOST_REQUIRE_EQUAL(true,test);
338  #endif
339 
340  #else
341 
342  bool test = compare("vtk_dist_parmetis_distribution_0.vtk","src/Decomposition/Distribution/test_data/vtk_dist_parmetis_distribution_0_test.vtk");
343  BOOST_REQUIRE_EQUAL(true,test);
344 
345  #endif
346 
347  }
348 
350 
351  float stime = 0.0, etime = 10.0, tstep = 0.1;
352 
353  // Shift of the sphere at each iteration
354  Point<3, float> shift( { tstep, tstep, tstep });
355 
356  size_t iter = 1;
357 
358  for(float t = stime; t < etime; t = t + tstep, iter++)
359  {
360  if(t < etime/2)
361  center += shift;
362  else
363  center -= shift;
364 
365  setSphereComputationCosts(pmet_dist, info, center, 2.0f, 5, 1);
366 
367  // With some regularity refine and write the parmetis distribution
368  if ((size_t)iter % 10 == 0)
369  {
370  pmet_dist.refine();
371 
372  std::stringstream str;
373  str << "vtk_dist_parmetis_distribution_" << iter;
374  pmet_dist.write(str.str());
375 
376  // Check
377  if (v_cl.getProcessUnitID() == 0)
378  {
379 #ifdef HAVE_OSX
380 
381  #ifndef __ARM_ARCH
382  bool test = compare(str.str() + ".vtk",std::string("src/Decomposition/Distribution/test_data/") + str.str() + "_osx_test.vtk");
383  BOOST_REQUIRE_EQUAL(true,test);
384  #endif
385 
386 #else
387 
388  bool test = compare(str.str() + ".vtk",std::string("src/Decomposition/Distribution/test_data/") + str.str() + "_test.vtk");
389  BOOST_REQUIRE_EQUAL(true,test);
390 
391 #endif
392 
393  }
394  }
395  }
396 
398 }
399 
400 BOOST_AUTO_TEST_CASE( Space_distribution_test)
401 {
402  Vcluster<> & v_cl = create_vcluster();
403 
404  if (v_cl.getProcessingUnits() != 3)
405  return;
406 
408 
409  SpaceDistribution<3, float> space_dist(v_cl);
410 
411  // Physical domain
412  Box<3, float> box( { 0.0, 0.0, 0.0 }, { 10.0, 10.0, 10.0 });
413 
414  // Grid info
415  grid_sm<3, void> info( { 17, 17, 17 });
416 
417  // Initialize Cart graph and decompose
418  space_dist.createCartGraph(info,box);
419 
420  // first decomposition
421  space_dist.decompose();
422 
424 
425  if (v_cl.getProcessUnitID() == 0)
426  {
427  // write the first decomposition
428  space_dist.write("vtk_dist_space_distribution_0");
429 
430  bool test = compare(std::to_string(v_cl.getProcessUnitID()) + "_vtk_dist_space_distribution_0.vtk","src/Decomposition/Distribution/test_data/" + std::to_string(v_cl.getProcessUnitID()) + + "_vtk_dist_space_distribution_0_test.vtk");
431  BOOST_REQUIRE_EQUAL(true,test);
432  }
433 
435 }
436 
437 
438 BOOST_AUTO_TEST_CASE( Box_distribution_test)
439 {
440  Vcluster<> & v_cl = create_vcluster();
441 
442  if (v_cl.size() > 16)
443  {return;}
444 
446 
447  BoxDistribution<3, float> box_dist(v_cl);
448 
449  // Physical domain
450  Box<3, float> box( { 0.0, 0.0, 0.0 }, { 10.0, 10.0, 10.0 });
451 
452  // Grid info
453  grid_sm<3, void> info( { GS_SIZE, GS_SIZE, GS_SIZE });
454 
455  // Initialize Cart graph and decompose
456  box_dist.createCartGraph(info,box);
457 
458  // First create the center of the weights distribution, check it is coherent to the size of the domain
459  Point<3, float> center( { 2.0, 2.0, 2.0 });
460 
461  // first decomposition
462  box_dist.decompose();
463 
464  BOOST_REQUIRE_EQUAL(box_dist.get_ndec(),0ul);
465 
466  auto & graph = box_dist.getGraph();
467 
468  for (int i = 0 ; i < graph.getNVertex() ; i++)
469  {
470  BOOST_REQUIRE(graph.vertex(i).template get<nm_v_proc_id>() < v_cl.size());
471  }
472 
473  size_t n_sub = box_dist.getNOwnerSubSubDomains();
474 
475  size_t n_sub_tot = info.size();
476  size_t n_sub_bal = n_sub_tot / v_cl.size();
477 
478  BOOST_REQUIRE( (((int)n_sub_bal - 64) <= (long int)n_sub) && (n_sub_bal + 64 >= n_sub) );
479 
481 
482 // BOOST_REQUIRE_EQUAL(sizeof(ParMetisDistribution<3,float>),872ul);
483 }
484 
485 BOOST_AUTO_TEST_SUITE_END()
486 
487 #endif /* SRC_DECOMPOSITION_DISTRIBUTION_DISTRIBUTION_UNIT_TESTS_HPP_ */
size_t getProcessUnitID()
Get the process unit id.
Class that distribute sub-sub-domains across processors using an hilbert curve to divide the space.
Implementation of VCluster class.
Definition: VCluster.hpp:58
Class that distribute sub-sub-domains across processors using ParMetis Library.
__device__ __host__ const T & get(unsigned int i) const
Get coordinate.
Definition: Point.hpp:172
size_t getProcessingUnits()
Get the total number of processors.
Class that distribute sub-sub-domains across processors using Metis Library.
size_t size()
Get the total number of processors.
Class that distribute sub-sub-domains across processors using Metis Library.