diff options
Diffstat (limited to 'src/boost/libs/mpi/src/cartesian_communicator.cpp')
-rw-r--r-- | src/boost/libs/mpi/src/cartesian_communicator.cpp | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/boost/libs/mpi/src/cartesian_communicator.cpp b/src/boost/libs/mpi/src/cartesian_communicator.cpp new file mode 100644 index 00000000..a46f0bc2 --- /dev/null +++ b/src/boost/libs/mpi/src/cartesian_communicator.cpp @@ -0,0 +1,179 @@ + +// Copyright Alain Miniussi 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Authors: Alain Miniussi + +#include <algorithm> +#include <cassert> + +#include <boost/mpi/cartesian_communicator.hpp> + +namespace boost { namespace mpi { + +namespace { + template <typename T, typename A> + T* c_data(std::vector<T,A>& v) { return &(v[0]); } +} + +std::ostream& +operator<<(std::ostream& out, cartesian_dimension const& d) { + out << '(' << d.size << ','; + if (d.periodic) { + out << "periodic"; + } else { + out << "bounded"; + } + out << ')'; + return out; +} + +std::ostream& +operator<<(std::ostream& out, cartesian_topology const& topo) { + out << '{'; + int const sz = topo.size(); + for (int i = 0; i < sz; ++i) { + out << topo[i]; + if ( i < (sz-1) ) { + out << ','; + } + } + out << '}'; + return out; +} + +cartesian_communicator::cartesian_communicator(const communicator& comm, + const cartesian_topology& topology, + bool reorder ) + : communicator(MPI_COMM_NULL, comm_attach) +{ + std::vector<int> dims(topology.size()); + std::vector<int> periodic(topology.size()); + int tsz = topology.size(); + for(int i = 0; i < tsz; ++i) { + dims[i] = topology[i].size; + periodic[i] = topology[i].periodic; + } + // Fill the gaps, if any + if (std::count(dims.begin(), dims.end(), 0) > 0) { + cartesian_dimensions(comm, dims); + } + MPI_Comm newcomm; + BOOST_MPI_CHECK_RESULT(MPI_Cart_create, + ((MPI_Comm)comm, dims.size(), + c_data(dims), c_data(periodic), + int(reorder), &newcomm)); + if(newcomm != MPI_COMM_NULL) { + comm_ptr.reset(new MPI_Comm(newcomm), comm_free()); + } +} + +cartesian_communicator::cartesian_communicator(const cartesian_communicator& comm, + const std::vector<int>& keep ) + : communicator(MPI_COMM_NULL, comm_attach) +{ + int const max_dims = comm.ndims(); + int const nbkept = keep.size(); + assert(nbkept <= max_dims); + std::vector<int> bitset(max_dims, int(false)); + for(int i = 0; i < nbkept; ++i) { + assert(keep[i] < max_dims); + bitset[keep[i]] = true; + } + + MPI_Comm newcomm; + BOOST_MPI_CHECK_RESULT(MPI_Cart_sub, + ((MPI_Comm)comm, c_data(bitset), &newcomm)); + if(newcomm != MPI_COMM_NULL) { + comm_ptr.reset(new MPI_Comm(newcomm), comm_free()); + } +} + +int +cartesian_communicator::ndims() const { + int n = -1; + BOOST_MPI_CHECK_RESULT(MPI_Cartdim_get, + (MPI_Comm(*this), &n)); + return n; +} + +int +cartesian_communicator::rank(const std::vector<int>& coords ) const { + int r = -1; + assert(int(coords.size()) == ndims()); + BOOST_MPI_CHECK_RESULT(MPI_Cart_rank, + (MPI_Comm(*this), c_data(const_cast<std::vector<int>&>(coords)), + &r)); + return r; +} + +std::pair<int, int> +cartesian_communicator::shifted_ranks(int dim, int disp) const { + std::pair<int, int> r(-1,-1); + assert(0 <= dim && dim < ndims()); + BOOST_MPI_CHECK_RESULT(MPI_Cart_shift, + (MPI_Comm(*this), dim, disp, &(r.first), &(r.second))); + return r; +} + +std::vector<int> +cartesian_communicator::coordinates(int rk) const { + std::vector<int> cbuf(ndims()); + BOOST_MPI_CHECK_RESULT(MPI_Cart_coords, + (MPI_Comm(*this), rk, cbuf.size(), c_data(cbuf) )); + return cbuf; +} + +void +cartesian_communicator::topology( cartesian_topology& topo, + std::vector<int>& coords ) const { + int ndims = this->ndims(); + topo.resize(ndims); + coords.resize(ndims); + std::vector<int> cdims(ndims); + std::vector<int> cperiods(ndims); + BOOST_MPI_CHECK_RESULT(MPI_Cart_get, + (MPI_Comm(*this), ndims, c_data(cdims), c_data(cperiods), c_data(coords))); + cartesian_topology res(cdims.begin(), cperiods.begin(), ndims); + topo.swap(res); +} + +cartesian_topology +cartesian_communicator::topology() const { + cartesian_topology topo(ndims()); + std::vector<int> coords; + topology(topo, coords); + return topo; +} + +void +cartesian_topology::split(std::vector<int>& dims, std::vector<bool>& periodics) const { + int ndims = size(); + dims.resize(ndims); + periodics.resize(ndims); + for(int i = 0; i < ndims; ++i) { + cartesian_dimension const& d = (*this)[i]; + dims[i] = d.size; + periodics[i] = d.periodic; + } +} + +std::vector<int>& +cartesian_dimensions(int sz, std::vector<int>& dims) { + int min = 1; + int const dimsz = dims.size(); + for(int i = 0; i < dimsz; ++i) { + if (dims[i] > 0) { + min *= dims[i]; + } + } + int leftover = sz % min; + + BOOST_MPI_CHECK_RESULT(MPI_Dims_create, + (sz-leftover, dims.size(), c_data(dims))); + return dims; +} + +} } // end namespace boost::mpi |