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
16/*! \brief Set a sphere as high computation cost
17 *
18 * \param dist Distribution structure
19 * \param gr grid info
20 * \param center of the sphere
21 * \param radius radius of the sphere
22 * \param max_l maximum load of the processor
23 * \param min_l minimum load of the processor
24 *
25 */
26template<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
59BOOST_AUTO_TEST_SUITE (Distribution_test)
60
61BOOST_AUTO_TEST_CASE( Metis_distribution_test)
62{
63 Vcluster<> & v_cl = create_vcluster();
64
65 if (v_cl.getProcessingUnits() != 3)
66 return;
67
68 //! [Initialize a Metis Cartesian graph and decompose]
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
91 //! [Initialize a Metis Cartesian graph and decompose]
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
100 //! [Decomposition Metis with weights]
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
131 //! [Decomposition Metis with weights]
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 test = compare("0_vtk_metis_distribution.vtk", "src/Decomposition/Distribution/test_data/vtk_metis_distribution_osx_test.vtk");
147 BOOST_REQUIRE_EQUAL(true,test);
148 test = compare("0_vtk_metis_distribution_red.vtk","src/Decomposition/Distribution/test_data/vtk_metis_distribution_red_osx_test.vtk");
149 BOOST_REQUIRE_EQUAL(true,test);
150
151 #elif __GNUC__ == 6 && __GNUC_MINOR__ == 3
152
153 test = compare("0_vtk_metis_distribution.vtk", "src/Decomposition/Distribution/test_data/vtk_metis_distribution_test.vtk");
154 BOOST_REQUIRE_EQUAL(true,test);
155 test = compare("0_vtk_metis_distribution_red.vtk","src/Decomposition/Distribution/test_data/vtk_metis_distribution_red_test.vtk");
156 BOOST_REQUIRE_EQUAL(true,test);
157
158 #endif
159 }
160
161 // Copy the Metis distribution
162
163 MetisDistribution<3, float> met_dist2(v_cl);
164
165 met_dist2 = met_dist;
166
167 test = (met_dist2 == met_dist);
168
169 BOOST_REQUIRE_EQUAL(test,true);
170
171 // We fix the size of MetisDistribution if you are gointg to change this number
172 // please check the following
173 // duplicate functions
174 // swap functions
175 // Copy constructors
176 // operator= functions
177 // operator== functions
178
179// BOOST_REQUIRE_EQUAL(sizeof(MetisDistribution<3,float>),720ul);
180}
181
182BOOST_AUTO_TEST_CASE( Parmetis_distribution_test)
183{
184 Vcluster<> & v_cl = create_vcluster();
185
186 if (v_cl.getProcessingUnits() != 3)
187 return;
188
189 //! [Initialize a ParMetis Cartesian graph and decompose]
190
191 ParMetisDistribution<3, float> pmet_dist(v_cl);
192
193 // Physical domain
194 Box<3, float> box( { 0.0, 0.0, 0.0 }, { 10.0, 10.0, 10.0 });
195
196 // Grid info
197 grid_sm<3, void> info( { GS_SIZE, GS_SIZE, GS_SIZE });
198
199 // Initialize Cart graph and decompose
200 pmet_dist.createCartGraph(info,box);
201
202 // First create the center of the weights distribution, check it is coherent to the size of the domain
203 Point<3, float> center( { 2.0, 2.0, 2.0 });
204
205 // It produces a sphere of radius 2.0
206 // with high computation cost (5) inside the sphere and (1) outside
207 setSphereComputationCosts(pmet_dist, info, center, 2.0f, 5ul, 1ul);
208
209 // first decomposition
210 pmet_dist.decompose();
211
212 BOOST_REQUIRE_EQUAL(pmet_dist.get_ndec(),1ul);
213
214 //! [Initialize a ParMetis Cartesian graph and decompose]
215
216 if (v_cl.getProcessUnitID() == 0)
217 {
218 // write the first decomposition
219 pmet_dist.write("vtk_parmetis_distribution_0");
220
221#ifdef HAVE_OSX
222
223 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");
224 BOOST_REQUIRE_EQUAL(true,test);
225
226#else
227
228 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");
229 BOOST_REQUIRE_EQUAL(true,test);
230
231#endif
232 }
233
234 //! [refine with parmetis the decomposition]
235
236 float stime = 0.0, etime = 10.0, tstep = 0.1;
237
238 // Shift of the sphere at each iteration
239 Point<3, float> shift( { tstep, tstep, tstep });
240
241 size_t iter = 1;
242 size_t n_dec = 1;
243
244 for(float t = stime; t < etime; t = t + tstep, iter++)
245 {
246 if(t < etime/2)
247 center += shift;
248 else
249 center -= shift;
250
251 setSphereComputationCosts(pmet_dist, info, center, 2.0f, 5, 1);
252
253 // With some regularity refine and write the parmetis distribution
254 if ((size_t)iter % 10 == 0)
255 {
256 pmet_dist.refine();
257 n_dec++;
258 BOOST_REQUIRE_EQUAL(pmet_dist.get_ndec(),n_dec);
259
260 if (v_cl.getProcessUnitID() == 0)
261 {
262 std::stringstream str;
263 str << "vtk_parmetis_distribution_" << iter;
264 pmet_dist.write(str.str());
265
266#ifdef HAVE_OSX
267
268 // Check
269 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");
270 BOOST_REQUIRE_EQUAL(true,test);
271
272#else
273
274 // Check
275 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");
276 BOOST_REQUIRE_EQUAL(true,test);
277
278#endif
279 }
280 }
281 }
282
283 //! [refine with parmetis the decomposition]
284
285// BOOST_REQUIRE_EQUAL(sizeof(ParMetisDistribution<3,float>),872ul);
286}
287
288BOOST_AUTO_TEST_CASE( DistParmetis_distribution_test)
289{
290 Vcluster<> & v_cl = create_vcluster();
291
292 if (v_cl.getProcessingUnits() != 3)
293 return;
294
295 //! [Initialize a ParMetis Cartesian graph and decompose]
296
297 DistParMetisDistribution<3, float> pmet_dist(v_cl);
298
299 // Physical domain
300 Box<3, float> box( { 0.0, 0.0, 0.0 }, { 10.0, 10.0, 10.0 });
301
302 // Grid info
303 grid_sm<3, void> info( { GS_SIZE, GS_SIZE, GS_SIZE });
304
305 // Initialize Cart graph and decompose
306 pmet_dist.createCartGraph(info,box);
307
308 // First create the center of the weights distribution, check it is coherent to the size of the domain
309 Point<3, float> center( { 2.0, 2.0, 2.0 });
310
311 // It produces a sphere of radius 2.0
312 // with high computation cost (5) inside the sphere and (1) outside
313 setSphereComputationCosts(pmet_dist, info, center, 2.0f, 5ul, 1ul);
314
315 // first decomposition
316 pmet_dist.decompose();
317
318 //! [Initialize a ParMetis Cartesian graph and decompose]
319
320 // write the first decomposition
321 pmet_dist.write("vtk_dist_parmetis_distribution_0");
322
323 // Check
324 if (v_cl.getProcessUnitID() == 0)
325 {
326
327 #ifdef HAVE_OSX
328
329 bool test = compare("vtk_dist_parmetis_distribution_0.vtk","src/Decomposition/Distribution/test_data/vtk_dist_parmetis_distribution_0_osx_test.vtk");
330 BOOST_REQUIRE_EQUAL(true,test);
331
332 #else
333
334 bool test = compare("vtk_dist_parmetis_distribution_0.vtk","src/Decomposition/Distribution/test_data/vtk_dist_parmetis_distribution_0_test.vtk");
335 BOOST_REQUIRE_EQUAL(true,test);
336
337 #endif
338
339 }
340
341 //! [refine with dist_parmetis the decomposition]
342
343 float stime = 0.0, etime = 10.0, tstep = 0.1;
344
345 // Shift of the sphere at each iteration
346 Point<3, float> shift( { tstep, tstep, tstep });
347
348 size_t iter = 1;
349
350 for(float t = stime; t < etime; t = t + tstep, iter++)
351 {
352 if(t < etime/2)
353 center += shift;
354 else
355 center -= shift;
356
357 setSphereComputationCosts(pmet_dist, info, center, 2.0f, 5, 1);
358
359 // With some regularity refine and write the parmetis distribution
360 if ((size_t)iter % 10 == 0)
361 {
362 pmet_dist.refine();
363
364 std::stringstream str;
365 str << "vtk_dist_parmetis_distribution_" << iter;
366 pmet_dist.write(str.str());
367
368 // Check
369 if (v_cl.getProcessUnitID() == 0)
370 {
371#ifdef HAVE_OSX
372 bool test = compare(str.str() + ".vtk",std::string("src/Decomposition/Distribution/test_data/") + str.str() + "_osx_test.vtk");
373 BOOST_REQUIRE_EQUAL(true,test);
374
375#else
376
377 bool test = compare(str.str() + ".vtk",std::string("src/Decomposition/Distribution/test_data/") + str.str() + "_test.vtk");
378 BOOST_REQUIRE_EQUAL(true,test);
379
380#endif
381
382 }
383 }
384 }
385
386 //! [refine with dist_parmetis the decomposition]
387}
388
389BOOST_AUTO_TEST_CASE( Space_distribution_test)
390{
391 Vcluster<> & v_cl = create_vcluster();
392
393 if (v_cl.getProcessingUnits() != 3)
394 return;
395
396 //! [Initialize a Space Cartesian graph and decompose]
397
398 SpaceDistribution<3, float> space_dist(v_cl);
399
400 // Physical domain
401 Box<3, float> box( { 0.0, 0.0, 0.0 }, { 10.0, 10.0, 10.0 });
402
403 // Grid info
404 grid_sm<3, void> info( { 17, 17, 17 });
405
406 // Initialize Cart graph and decompose
407 space_dist.createCartGraph(info,box);
408
409 // first decomposition
410 space_dist.decompose();
411
412 //! [Initialize a Space Cartesian graph and decompose]
413
414 if (v_cl.getProcessUnitID() == 0)
415 {
416 // write the first decomposition
417 space_dist.write("vtk_dist_space_distribution_0");
418
419 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");
420 BOOST_REQUIRE_EQUAL(true,test);
421 }
422
423 //! [refine with dist_parmetis the decomposition]
424}
425
426
427BOOST_AUTO_TEST_CASE( Box_distribution_test)
428{
429 Vcluster<> & v_cl = create_vcluster();
430
431 if (v_cl.size() > 16)
432 {return;}
433
434 //! [Initialize a ParMetis Cartesian graph and decompose]
435
436 BoxDistribution<3, float> box_dist(v_cl);
437
438 // Physical domain
439 Box<3, float> box( { 0.0, 0.0, 0.0 }, { 10.0, 10.0, 10.0 });
440
441 // Grid info
442 grid_sm<3, void> info( { GS_SIZE, GS_SIZE, GS_SIZE });
443
444 // Initialize Cart graph and decompose
445 box_dist.createCartGraph(info,box);
446
447 // First create the center of the weights distribution, check it is coherent to the size of the domain
448 Point<3, float> center( { 2.0, 2.0, 2.0 });
449
450 // first decomposition
451 box_dist.decompose();
452
453 BOOST_REQUIRE_EQUAL(box_dist.get_ndec(),0ul);
454
455 auto & graph = box_dist.getGraph();
456
457 for (int i = 0 ; i < graph.getNVertex() ; i++)
458 {
459 BOOST_REQUIRE(graph.vertex(i).template get<nm_v_proc_id>() < v_cl.size());
460 }
461
462 size_t n_sub = box_dist.getNOwnerSubSubDomains();
463
464 size_t n_sub_tot = info.size();
465 size_t n_sub_bal = n_sub_tot / v_cl.size();
466
467 BOOST_REQUIRE( (((int)n_sub_bal - 64) <= (long int)n_sub) && (n_sub_bal + 64 >= n_sub) );
468
469 //! [refine with parmetis the decomposition]
470
471// BOOST_REQUIRE_EQUAL(sizeof(ParMetisDistribution<3,float>),872ul);
472}
473
474BOOST_AUTO_TEST_SUITE_END()
475
476#endif /* SRC_DECOMPOSITION_DISTRIBUTION_DISTRIBUTION_UNIT_TESTS_HPP_ */
477