1
2 // Copyright Alain Miniussi 2014.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6
7 // Authors: Alain Miniussi
8
9 #include <algorithm>
10 #include <cassert>
11
12 #include <boost/mpi/cartesian_communicator.hpp>
13 #include <boost/mpi/detail/antiques.hpp>
14
15 namespace boost { namespace mpi {
16
17 std::ostream&
operator <<(std::ostream & out,cartesian_dimension const & d)18 operator<<(std::ostream& out, cartesian_dimension const& d) {
19 out << '(' << d.size << ',';
20 if (d.periodic) {
21 out << "periodic";
22 } else {
23 out << "bounded";
24 }
25 out << ')';
26 return out;
27 }
28
29 std::ostream&
operator <<(std::ostream & out,cartesian_topology const & topo)30 operator<<(std::ostream& out, cartesian_topology const& topo) {
31 out << '{';
32 int const sz = topo.size();
33 for (int i = 0; i < sz; ++i) {
34 out << topo[i];
35 if ( i < (sz-1) ) {
36 out << ',';
37 }
38 }
39 out << '}';
40 return out;
41 }
42
cartesian_communicator(const communicator & comm,const cartesian_topology & topology,bool reorder)43 cartesian_communicator::cartesian_communicator(const communicator& comm,
44 const cartesian_topology& topology,
45 bool reorder )
46 : communicator(MPI_COMM_NULL, comm_attach)
47 {
48 std::vector<int> dims(topology.size());
49 std::vector<int> periodic(topology.size());
50 int tsz = topology.size();
51 for(int i = 0; i < tsz; ++i) {
52 dims[i] = topology[i].size;
53 periodic[i] = topology[i].periodic;
54 }
55 // Fill the gaps, if any
56 if (std::count(dims.begin(), dims.end(), 0) > 0) {
57 cartesian_dimensions(comm, dims);
58 }
59 MPI_Comm newcomm;
60 BOOST_MPI_CHECK_RESULT(MPI_Cart_create,
61 ((MPI_Comm)comm, dims.size(),
62 detail::c_data(dims), detail::c_data(periodic),
63 int(reorder), &newcomm));
64 if(newcomm != MPI_COMM_NULL) {
65 comm_ptr.reset(new MPI_Comm(newcomm), comm_free());
66 }
67 }
68
cartesian_communicator(const cartesian_communicator & comm,const std::vector<int> & keep)69 cartesian_communicator::cartesian_communicator(const cartesian_communicator& comm,
70 const std::vector<int>& keep )
71 : communicator(MPI_COMM_NULL, comm_attach)
72 {
73 int const max_dims = comm.ndims();
74 int const nbkept = keep.size();
75 assert(nbkept <= max_dims);
76 std::vector<int> bitset(max_dims, int(false));
77 for(int i = 0; i < nbkept; ++i) {
78 assert(keep[i] < max_dims);
79 bitset[keep[i]] = true;
80 }
81
82 MPI_Comm newcomm;
83 BOOST_MPI_CHECK_RESULT(MPI_Cart_sub,
84 ((MPI_Comm)comm, detail::c_data(bitset), &newcomm));
85 if(newcomm != MPI_COMM_NULL) {
86 comm_ptr.reset(new MPI_Comm(newcomm), comm_free());
87 }
88 }
89
90 int
ndims() const91 cartesian_communicator::ndims() const {
92 int n = -1;
93 BOOST_MPI_CHECK_RESULT(MPI_Cartdim_get,
94 (MPI_Comm(*this), &n));
95 return n;
96 }
97
98 int
rank(const std::vector<int> & coords) const99 cartesian_communicator::rank(const std::vector<int>& coords ) const {
100 int r = -1;
101 assert(int(coords.size()) == ndims());
102 BOOST_MPI_CHECK_RESULT(MPI_Cart_rank,
103 (MPI_Comm(*this), detail::c_data(const_cast<std::vector<int>&>(coords)),
104 &r));
105 return r;
106 }
107
108 std::pair<int, int>
shifted_ranks(int dim,int disp) const109 cartesian_communicator::shifted_ranks(int dim, int disp) const {
110 std::pair<int, int> r(-1,-1);
111 assert(0 <= dim && dim < ndims());
112 BOOST_MPI_CHECK_RESULT(MPI_Cart_shift,
113 (MPI_Comm(*this), dim, disp, &(r.first), &(r.second)));
114 return r;
115 }
116
117 std::vector<int>
coordinates(int rk) const118 cartesian_communicator::coordinates(int rk) const {
119 std::vector<int> cbuf(ndims());
120 BOOST_MPI_CHECK_RESULT(MPI_Cart_coords,
121 (MPI_Comm(*this), rk, cbuf.size(), detail::c_data(cbuf) ));
122 return cbuf;
123 }
124
125 void
topology(cartesian_topology & topo,std::vector<int> & coords) const126 cartesian_communicator::topology( cartesian_topology& topo,
127 std::vector<int>& coords ) const {
128 int ndims = this->ndims();
129 topo.resize(ndims);
130 coords.resize(ndims);
131 std::vector<int> cdims(ndims);
132 std::vector<int> cperiods(ndims);
133 BOOST_MPI_CHECK_RESULT(MPI_Cart_get,
134 (MPI_Comm(*this), ndims, detail::c_data(cdims), detail::c_data(cperiods), detail::c_data(coords)));
135 cartesian_topology res(cdims.begin(), cperiods.begin(), ndims);
136 topo.swap(res);
137 }
138
139 cartesian_topology
topology() const140 cartesian_communicator::topology() const {
141 cartesian_topology topo(ndims());
142 std::vector<int> coords;
143 topology(topo, coords);
144 return topo;
145 }
146
147 void
split(std::vector<int> & dims,std::vector<bool> & periodics) const148 cartesian_topology::split(std::vector<int>& dims, std::vector<bool>& periodics) const {
149 int ndims = size();
150 dims.resize(ndims);
151 periodics.resize(ndims);
152 for(int i = 0; i < ndims; ++i) {
153 cartesian_dimension const& d = (*this)[i];
154 dims[i] = d.size;
155 periodics[i] = d.periodic;
156 }
157 }
158
159 std::vector<int>&
cartesian_dimensions(int sz,std::vector<int> & dims)160 cartesian_dimensions(int sz, std::vector<int>& dims) {
161 int min = 1;
162 int const dimsz = dims.size();
163 for(int i = 0; i < dimsz; ++i) {
164 if (dims[i] > 0) {
165 min *= dims[i];
166 }
167 }
168 int leftover = sz % min;
169
170 BOOST_MPI_CHECK_RESULT(MPI_Dims_create,
171 (sz-leftover, dims.size(), detail::c_data(dims)));
172 return dims;
173 }
174
175 } } // end namespace boost::mpi
176