|
||||
File indexing completed on 2025-01-30 09:46:54
0001 // Copyright Alain Miniussi 2014. 0002 // Distributed under the Boost Software License, Version 1.0. 0003 // (See accompanying file LICENSE_1_0.txt or copy at 0004 // http://www.boost.org/LICENSE_1_0.txt) 0005 0006 // Authors: Alain Miniussi 0007 0008 /** @file cartesian_communicator.hpp 0009 * 0010 * This header defines facilities to support MPI communicators with 0011 * cartesian topologies. 0012 * If known at compiled time, the dimension of the implied grid 0013 * can be statically enforced, through the templatized communicator 0014 * class. Otherwise, a non template, dynamic, base class is provided. 0015 * 0016 */ 0017 #ifndef BOOST_MPI_CARTESIAN_COMMUNICATOR_HPP 0018 #define BOOST_MPI_CARTESIAN_COMMUNICATOR_HPP 0019 0020 #include <boost/mpi/communicator.hpp> 0021 0022 #include <vector> 0023 #include <utility> 0024 #include <iostream> 0025 #include <utility> 0026 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) 0027 #include <initializer_list> 0028 #endif // BOOST_NO_CXX11_HDR_INITIALIZER_LIST 0029 0030 // Headers required to implement cartesian topologies 0031 #include <boost/shared_array.hpp> 0032 #include <boost/assert.hpp> 0033 #include <boost/foreach.hpp> 0034 0035 namespace boost { namespace mpi { 0036 0037 /** 0038 * @brief Specify the size and periodicity of the grid in a single dimension. 0039 * 0040 * POD lightweight object. 0041 */ 0042 struct cartesian_dimension { 0043 /** The size of the grid n this dimension. */ 0044 int size; 0045 /** Is the grid periodic in this dimension. */ 0046 bool periodic; 0047 0048 cartesian_dimension(int sz = 0, bool p = false) : size(sz), periodic(p) {} 0049 0050 private: 0051 friend class boost::serialization::access; 0052 template<class Archive> 0053 void serialize(Archive & ar, const unsigned int version) 0054 { 0055 ar & size & periodic; 0056 } 0057 0058 }; 0059 0060 template <> 0061 struct is_mpi_datatype<cartesian_dimension> : mpl::true_ { }; 0062 0063 /** 0064 * @brief Test if the dimensions values are identical. 0065 */ 0066 inline 0067 bool 0068 operator==(cartesian_dimension const& d1, cartesian_dimension const& d2) { 0069 return &d1 == &d2 || (d1.size == d2.size && d1.periodic == d2.periodic); 0070 } 0071 0072 /** 0073 * @brief Test if the dimension values are different. 0074 */ 0075 inline 0076 bool 0077 operator!=(cartesian_dimension const& d1, cartesian_dimension const& d2) { 0078 return !(d1 == d2); 0079 } 0080 0081 /** 0082 * @brief Pretty printing of a cartesian dimension (size, periodic) 0083 */ 0084 std::ostream& operator<<(std::ostream& out, cartesian_dimension const& d); 0085 0086 /** 0087 * @brief Describe the topology of a cartesian grid. 0088 * 0089 * Behave mostly like a sequence of @c cartesian_dimension with the notable 0090 * exception that its size is fixed. 0091 * This is a lightweight object, so that any constructor that could be considered 0092 * missing could be replaced with a function (move constructor provided when supported). 0093 */ 0094 class BOOST_MPI_DECL cartesian_topology 0095 : private std::vector<cartesian_dimension> { 0096 friend class cartesian_communicator; 0097 typedef std::vector<cartesian_dimension> super; 0098 public: 0099 /** 0100 * Retrieve a specific dimension. 0101 */ 0102 using super::operator[]; 0103 /** 0104 * @brief Topology dimentionality. 0105 */ 0106 using super::size; 0107 using super::begin; 0108 using super::end; 0109 using super::swap; 0110 0111 #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) 0112 cartesian_topology() = delete; 0113 #endif 0114 #if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) 0115 cartesian_topology(cartesian_topology const&) = default; 0116 cartesian_topology& operator=(cartesian_topology const&) = default; 0117 // There is apparently no macro for checking the support of move constructor. 0118 // Assume that defaulted function is close enough. 0119 #if !defined(BOOST_NO_CXX11_DEFAULTED_MOVES) 0120 cartesian_topology(cartesian_topology&& other) : super(other) {} 0121 cartesian_topology& operator=(cartesian_topology&& other) { 0122 stl().swap(other.stl()); 0123 return *this; 0124 } 0125 #endif 0126 ~cartesian_topology() = default; 0127 #endif 0128 /** 0129 * @brief Create a N dimension space. 0130 * Each dimension is initialized as non periodic of size 0. 0131 */ 0132 cartesian_topology(int ndim) 0133 : super(ndim) {} 0134 0135 /** 0136 * @brief Use the provided dimensions specification as initial values. 0137 */ 0138 cartesian_topology(std::vector<cartesian_dimension> const& dims) 0139 : super(dims) {} 0140 0141 /** 0142 * @brief Use dimensions specification provided in the sequence container as initial values. 0143 * #param dims must be a sequence container. 0144 */ 0145 template<class InitArr> 0146 explicit cartesian_topology(InitArr dims) 0147 : super(0) { 0148 BOOST_FOREACH(cartesian_dimension const& d, dims) { 0149 push_back(d); 0150 } 0151 } 0152 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) 0153 /** 0154 * @brief Use dimensions specification provided in the initialization list as initial values. 0155 * #param dims can be of the form { dim_1, false}, .... {dim_n, true} 0156 */ 0157 explicit cartesian_topology(std::initializer_list<cartesian_dimension> dims) 0158 : super(dims) {} 0159 #endif 0160 /** 0161 * @brief Use dimensions specification provided in the array. 0162 * #param dims can be of the form { dim_1, false}, .... {dim_n, true} 0163 */ 0164 template<int NDIM> 0165 explicit cartesian_topology(cartesian_dimension (&dims)[NDIM]) 0166 : super(dims, dims+NDIM) {} 0167 0168 /** 0169 * @brief Use dimensions specification provided in the input ranges 0170 * The ranges do not need to be the same size. If the sizes are different, 0171 * the missing values will be complete with zeros of the dim and assumed non periodic. 0172 * @param dim_rg the dimensions, values must convert to integers. 0173 * @param period_rg the periodicities, values must convert to booleans. 0174 * #param dims can be of the form { dim_1, false}, .... {dim_n, true} 0175 */ 0176 template<class DimRg, class PerRg> 0177 cartesian_topology(DimRg const& dim_rg, PerRg const& period_rg) 0178 : super(0) { 0179 BOOST_FOREACH(int d, dim_rg) { 0180 super::push_back(cartesian_dimension(d)); 0181 } 0182 super::iterator it = begin(); 0183 BOOST_FOREACH(bool p, period_rg) { 0184 if (it < end()) { 0185 it->periodic = p; 0186 } else { 0187 push_back(cartesian_dimension(0,p)); 0188 } 0189 ++it; 0190 } 0191 } 0192 0193 0194 /** 0195 * @brief Iterator based initializer. 0196 * Will use the first n iterated values. 0197 * Both iterators can be single pass. 0198 * @param dit dimension iterator, value must convert to integer type. 0199 * @param pit periodicity iterator, value must convert to booleans.. 0200 */ 0201 template<class DimIter, class PerIter> 0202 cartesian_topology(DimIter dit, PerIter pit, int n) 0203 : super(n) { 0204 for(int i = 0; i < n; ++i) { 0205 (*this)[i] = cartesian_dimension(*dit++, *pit++); 0206 } 0207 } 0208 0209 /** 0210 * Export as an stl sequence. 0211 */ 0212 std::vector<cartesian_dimension>& stl() { return *this; } 0213 /** 0214 * Export as an stl sequence. 0215 */ 0216 std::vector<cartesian_dimension> const& stl() const{ return *this; } 0217 /** 0218 * Split the topology in two sequences of sizes and periodicities. 0219 */ 0220 void split(std::vector<int>& dims, std::vector<bool>& periodics) const; 0221 }; 0222 0223 inline 0224 bool 0225 operator==(cartesian_topology const& t1, cartesian_topology const& t2) { 0226 return t1.stl() == t2.stl(); 0227 } 0228 0229 inline 0230 bool 0231 operator!=(cartesian_topology const& t1, cartesian_topology const& t2) { 0232 return t1.stl() != t2.stl(); 0233 } 0234 0235 /** 0236 * @brief Pretty printing of a cartesian topology 0237 */ 0238 std::ostream& operator<<(std::ostream& out, cartesian_topology const& t); 0239 0240 /** 0241 * @brief An MPI communicator with a cartesian topology. 0242 * 0243 * A @c cartesian_communicator is a communicator whose topology is 0244 * expressed as a grid. Cartesian communicators have the same 0245 * functionality as (intra)communicators, but also allow one to query 0246 * the relationships among processes and the properties of the grid. 0247 */ 0248 class BOOST_MPI_DECL cartesian_communicator : public communicator 0249 { 0250 friend class communicator; 0251 0252 /** 0253 * INTERNAL ONLY 0254 * 0255 * Construct a cartesian communicator given a shared pointer to the 0256 * underlying MPI_Comm (which must have a cartesian topology). 0257 * This operation is used for "casting" from a communicator to 0258 * a cartesian communicator. 0259 */ 0260 explicit cartesian_communicator(const shared_ptr<MPI_Comm>& comm_ptr) 0261 : communicator() 0262 { 0263 this->comm_ptr = comm_ptr; 0264 BOOST_ASSERT(has_cartesian_topology()); 0265 } 0266 0267 public: 0268 /** 0269 * Build a new Boost.MPI cartesian communicator based on the MPI 0270 * communicator @p comm with cartesian topology. 0271 * 0272 * @p comm may be any valid MPI communicator. If @p comm is 0273 * MPI_COMM_NULL, an empty communicator (that cannot be used for 0274 * communication) is created and the @p kind parameter is 0275 * ignored. Otherwise, the @p kind parameter determines how the 0276 * Boost.MPI communicator will be related to @p comm: 0277 * 0278 * - If @p kind is @c comm_duplicate, duplicate @c comm to create 0279 * a new communicator. This new communicator will be freed when 0280 * the Boost.MPI communicator (and all copies of it) is 0281 * destroyed. This option is only permitted if the underlying MPI 0282 * implementation supports MPI 2.0; duplication of 0283 * intercommunicators is not available in MPI 1.x. 0284 * 0285 * - If @p kind is @c comm_take_ownership, take ownership of @c 0286 * comm. It will be freed automatically when all of the Boost.MPI 0287 * communicators go out of scope. 0288 * 0289 * - If @p kind is @c comm_attach, this Boost.MPI communicator 0290 * will reference the existing MPI communicator @p comm but will 0291 * not free @p comm when the Boost.MPI communicator goes out of 0292 * scope. This option should only be used when the communicator is 0293 * managed by the user. 0294 */ 0295 cartesian_communicator(const MPI_Comm& comm, comm_create_kind kind) 0296 : communicator(comm, kind) 0297 { 0298 BOOST_ASSERT(has_cartesian_topology()); 0299 } 0300 0301 /** 0302 * Create a new communicator whose topology is described by the 0303 * given cartesian. The indices of the vertices in the cartesian will be 0304 * assumed to be the ranks of the processes within the 0305 * communicator. There may be fewer vertices in the cartesian than 0306 * there are processes in the communicator; in this case, the 0307 * resulting communicator will be a NULL communicator. 0308 * 0309 * @param comm The communicator that the new, cartesian communicator 0310 * will be based on. 0311 * 0312 * @param dims the cartesian dimension of the new communicator. The size indicate 0313 * the number of dimension. Some dimensions be set to zero, in which case 0314 * the corresponding dimension value is left to the system. 0315 * 0316 * @param reorder Whether MPI is permitted to re-order the process 0317 * ranks within the returned communicator, to better optimize 0318 * communication. If false, the ranks of each process in the 0319 * returned process will match precisely the rank of that process 0320 * within the original communicator. 0321 */ 0322 cartesian_communicator(const communicator& comm, 0323 const cartesian_topology& dims, 0324 bool reorder = false); 0325 0326 /** 0327 * Create a new cartesian communicator whose topology is a subset of 0328 * an existing cartesian cimmunicator. 0329 * @param comm the original communicator. 0330 * @param keep and array containiing the dimension to keep from the existing 0331 * communicator. 0332 */ 0333 cartesian_communicator(const cartesian_communicator& comm, 0334 const std::vector<int>& keep ); 0335 0336 using communicator::rank; 0337 0338 /** 0339 * Retrive the number of dimension of the underlying toppology. 0340 */ 0341 int ndims() const; 0342 0343 /** 0344 * Return the rank of the process at the given coordinates. 0345 * @param coords the coordinates. the size must match the communicator's topology. 0346 */ 0347 int rank(const std::vector<int>& coords) const; 0348 /** 0349 * Return the rank of the source and target destination process through a shift. 0350 * @param dim the dimension in which the shift takes place. 0 <= dim <= ndim(). 0351 * @param disp the shift displacement, can be positive (upward) or negative (downward). 0352 */ 0353 std::pair<int, int> shifted_ranks(int dim, int disp) const; 0354 /** 0355 * Provides the coordinates of the process with the given rank. 0356 * @param rk the ranks in this communicator. 0357 * @returns the coordinates. 0358 */ 0359 std::vector<int> coordinates(int rk) const; 0360 /** 0361 * Retrieve the topology and coordinates of this process in the grid. 0362 * 0363 */ 0364 void topology( cartesian_topology& dims, std::vector<int>& coords ) const; 0365 /** 0366 * Retrieve the topology of the grid. 0367 * 0368 */ 0369 cartesian_topology topology() const; 0370 }; 0371 0372 /** 0373 * Given en number of processes, and a partially filled sequence 0374 * of dimension, try to complete the dimension sequence. 0375 * @param nb_proc the numer of mpi processes.fill a sequence of dimension. 0376 * @param dims a sequence of positive or null dimensions. Non zero dimension 0377 * will be left untouched. 0378 */ 0379 std::vector<int>& cartesian_dimensions(int nb_proc, std::vector<int>& dims); 0380 0381 } } // end namespace boost::mpi 0382 0383 #endif // BOOST_MPI_CARTESIAN_COMMUNICATOR_HPP
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |