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 | */ |
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 | |
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 | |
182 | BOOST_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 | |
288 | BOOST_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 | |
389 | BOOST_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 | |
427 | BOOST_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 | |
474 | BOOST_AUTO_TEST_SUITE_END() |
475 | |
476 | #endif /* SRC_DECOMPOSITION_DISTRIBUTION_DISTRIBUTION_UNIT_TESTS_HPP_ */ |
477 | |