]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // Copyright Alain Miniussi 2014. |
2 | // Distributed under the Boost Software License, Version 1.0. | |
3 | // (See accompanying file LICENSE_1_0.txt or copy at | |
4 | // http://www.boost.org/LICENSE_1_0.txt) | |
5 | ||
6 | // Authors: Alain Miniussi | |
7 | ||
8 | #include <vector> | |
9 | #include <iostream> | |
10 | #include <sstream> | |
11 | #include <iterator> | |
12 | #include <algorithm> | |
13 | #include <functional> | |
14 | ||
15 | #include <boost/mpi/communicator.hpp> | |
16 | #include <boost/mpi/collectives.hpp> | |
17 | #include <boost/mpi/environment.hpp> | |
18 | #include <boost/mpi/cartesian_communicator.hpp> | |
19 | ||
92f5a8d4 TL |
20 | #define BOOST_TEST_MODULE mpi_cartesian_topolohy |
21 | #include <boost/test/included/unit_test.hpp> | |
11fdf7f2 TL |
22 | |
23 | namespace mpi = boost::mpi; | |
24 | ||
25 | struct topo_minimum { | |
26 | mpi::cartesian_dimension | |
27 | operator()(mpi::cartesian_dimension const& d1, | |
28 | mpi::cartesian_dimension const& d2 ) const { | |
29 | return mpi::cartesian_dimension(std::min(d1.size, d2.size), | |
30 | d1.periodic && d2.periodic); | |
31 | } | |
32 | }; | |
33 | ||
34 | std::string topology_description( mpi::cartesian_topology const& topo ) { | |
35 | std::ostringstream out; | |
36 | std::copy(topo.begin(), topo.end(), std::ostream_iterator<mpi::cartesian_dimension>(out, " ")); | |
37 | out << std::flush; | |
38 | return out.str(); | |
39 | } | |
40 | ||
41 | // Check that everyone agrees on the coordinates | |
42 | void test_coordinates_consistency( mpi::cartesian_communicator const& cc, | |
43 | std::vector<int> const& coords ) | |
44 | { | |
45 | cc.barrier(); // flush IOs for nice printing | |
46 | bool master = cc.rank() == 0; | |
47 | if (master) { | |
48 | std::cout << "Test coordinates consistency.\n"; | |
49 | } | |
50 | for(int p = 0; p < cc.size(); ++p) { | |
51 | std::vector<int> min(cc.ndims()); | |
52 | std::vector<int> local(cc.coordinates(p)); | |
53 | mpi::reduce(cc, &local.front(), local.size(), | |
54 | &(min[0]), mpi::minimum<int>(), p); | |
55 | cc.barrier(); | |
56 | if (p == cc.rank()) { | |
57 | BOOST_CHECK(std::equal(coords.begin(), coords.end(), min.begin())); | |
58 | std::ostringstream out; | |
59 | out << "proc " << p << " at ("; | |
60 | std::copy(min.begin(), min.end(), std::ostream_iterator<int>(out, " ")); | |
61 | out << ")\n"; | |
62 | std::cout << out.str(); | |
63 | } | |
64 | } | |
65 | } | |
66 | ||
67 | void test_shifted_coords( mpi::cartesian_communicator const& cc, int pos, mpi::cartesian_dimension desc, int dim ) | |
68 | { | |
69 | if (desc.periodic) { | |
70 | for (int i = -(desc.size); i < desc.size; ++i) { | |
71 | std::pair<int,int> rks = cc.shifted_ranks(dim, i); | |
72 | int src = cc.coordinates(rks.first)[dim]; | |
73 | int dst = cc.coordinates(rks.second)[dim]; | |
74 | if (pos == (dim/2)) { | |
75 | std::ostringstream out; | |
76 | out << "Rank " << cc.rank() << ", dim. " << dim << ", pos " << pos << ", in " << desc << ' '; | |
77 | out << "shifted pos: " << src << ", " << dst << '\n'; | |
78 | std::cout << out.str(); | |
79 | } | |
80 | } | |
81 | } | |
82 | } | |
83 | ||
84 | void test_shifted_coords( mpi::cartesian_communicator const& cc) | |
85 | { | |
86 | cc.barrier(); // flush IOs for nice printing | |
87 | std::vector<int> coords; | |
88 | mpi::cartesian_topology topo(cc.ndims()); | |
89 | cc.topology(topo, coords); | |
90 | bool master = cc.rank() == 0; | |
91 | if (master) { | |
92 | std::cout << "Testing shifts with topology " << topo << '\n'; | |
93 | } | |
94 | for(int i = 0; i < cc.ndims(); ++i) { | |
95 | if (master) { | |
96 | std::cout << " for dimension " << i << ": " << topo[i] << '\n'; | |
97 | } | |
98 | test_shifted_coords( cc, coords[i], topo[i], i ); | |
99 | } | |
100 | } | |
101 | ||
102 | void test_topology_consistency( mpi::cartesian_communicator const& cc) | |
103 | { | |
104 | cc.barrier(); // flush IOs for nice printing | |
105 | mpi::cartesian_topology itopo(cc.ndims()); | |
106 | mpi::cartesian_topology otopo(cc.ndims()); | |
107 | std::vector<int> coords(cc.ndims()); | |
108 | cc.topology(itopo, coords); | |
109 | bool master = cc.rank() == 0; | |
110 | if (master) { | |
111 | std::cout << "Test topology consistency of" << itopo << "(on master)\n"; | |
112 | std::cout << "Check that everyone agrees on the dimensions.\n"; | |
113 | } | |
114 | mpi::all_reduce(cc, | |
115 | &(itopo[0]), itopo.size(), &(otopo[0]), | |
116 | topo_minimum()); | |
117 | BOOST_CHECK(std::equal(itopo.begin(), itopo.end(), otopo.begin())); | |
118 | if (master) { | |
119 | std::cout << "We agree on " << topology_description(otopo) << '\n'; | |
120 | } | |
121 | test_coordinates_consistency( cc, coords ); | |
122 | } | |
123 | ||
124 | void test_cartesian_topology( mpi::cartesian_communicator const& cc) | |
125 | { | |
126 | BOOST_CHECK(cc.has_cartesian_topology()); | |
127 | for( int r = 0; r < cc.size(); ++r) { | |
128 | cc.barrier(); | |
129 | if (r == cc.rank()) { | |
130 | std::vector<int> coords = cc.coordinates(r); | |
131 | std::cout << "Process of cartesian rank " << cc.rank() | |
132 | << " has coordinates ("; | |
133 | std::copy(coords.begin(), coords.end(), std::ostream_iterator<int>(std::cout," ")); | |
134 | std::cout << ")\n"; | |
135 | } | |
136 | } | |
137 | test_topology_consistency(cc); | |
138 | test_shifted_coords(cc); | |
139 | std::vector<int> even; | |
140 | for(int i = 0; i < cc.ndims(); i += 2) { | |
141 | even.push_back(i); | |
142 | } | |
143 | cc.barrier(); | |
144 | mpi::cartesian_communicator cce(cc, even); | |
145 | } | |
146 | ||
147 | void test_cartesian_topology( mpi::communicator const& world, mpi::cartesian_topology const& topo) | |
148 | { | |
149 | mpi::cartesian_communicator cc(world, topo, true); | |
150 | if (cc) { | |
151 | BOOST_CHECK(cc.has_cartesian_topology()); | |
152 | BOOST_CHECK(cc.ndims() == int(topo.size())); | |
153 | if (cc.rank() == 0) { | |
154 | std::cout << "Asked topology " << topo << ", got " << cc.topology() << '\n'; | |
155 | } | |
156 | test_cartesian_topology(cc); | |
157 | } else { | |
158 | std::ostringstream out; | |
159 | out << world.rank() << " was left outside the cartesian grid\n"; | |
160 | std::cout << out.str(); | |
161 | } | |
162 | } | |
163 | ||
92f5a8d4 | 164 | BOOST_AUTO_TEST_CASE(cartesian_topology) |
11fdf7f2 | 165 | { |
92f5a8d4 | 166 | mpi::environment env; |
11fdf7f2 | 167 | mpi::communicator world; |
92f5a8d4 | 168 | |
11fdf7f2 TL |
169 | int const ndim = world.size() >= 24 ? 3 : 2; |
170 | mpi::cartesian_topology topo(ndim); | |
171 | typedef mpi::cartesian_dimension cd; | |
172 | if (topo.size() == 3) { | |
173 | topo[0] = cd(2,true); | |
174 | topo[1] = cd(3,false); | |
175 | topo[2] = cd(4, true); | |
176 | } else { | |
177 | if (world.size() >= 6) { | |
178 | topo[0] = cd(2,true); | |
179 | topo[1] = cd(3, false); | |
180 | } else { | |
181 | topo[0] = cd(1,true); | |
182 | topo[1] = cd(1, false); | |
183 | } | |
184 | } | |
185 | test_cartesian_topology( world, topo); | |
92f5a8d4 TL |
186 | #if !defined(BOOST_NO_CXX11_DEFAULTED_MOVES) |
187 | world.barrier(); | |
188 | if (world.rank()==0) { | |
189 | std::cout << "Testing move constructor.\n"; | |
190 | } | |
191 | test_cartesian_topology( world, std::move(topo)); | |
192 | #endif | |
11fdf7f2 | 193 | } |