• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 #define BOOST_TEST_MODULE mpi_cartesian_topolohy
21 #include <boost/test/included/unit_test.hpp>
22 
23 namespace mpi = boost::mpi;
24 
25 struct topo_minimum {
26   mpi::cartesian_dimension
operator ()topo_minimum27   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 
topology_description(mpi::cartesian_topology const & topo)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
test_coordinates_consistency(mpi::cartesian_communicator const & cc,std::vector<int> const & coords)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 
test_shifted_coords(mpi::cartesian_communicator const & cc,int pos,mpi::cartesian_dimension desc,int dim)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 
test_shifted_coords(mpi::cartesian_communicator const & cc)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 
test_topology_consistency(mpi::cartesian_communicator const & cc)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 
test_cartesian_topology(mpi::cartesian_communicator const & cc)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 
test_cartesian_topology(mpi::communicator const & world,mpi::cartesian_topology const & topo)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 
BOOST_AUTO_TEST_CASE(cartesian_topology)164 BOOST_AUTO_TEST_CASE(cartesian_topology)
165 {
166   mpi::environment env;
167   mpi::communicator world;
168 
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);
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
193 }
194