Discontinuous Galerkin Library
#include "dg/algorithm.h"
Loading...
Searching...
No Matches
mpi_kron.h
Go to the documentation of this file.
1#pragma once
2#include <cassert>
3#include <vector>
4#include <algorithm> // std::copy_n
5#include <map>
6#include "mpi_cart.h"
7#include "exceptions.h"
8
9
10namespace dg
11{
20namespace detail{
21// I think the mpi registry should not be exposed to the User
22// It may be an idea to hint at it in the grid documentation
23// inline declared functions generate no warning about "defined but not used"...
24// and can be defined in multiple translation units
25struct MPICartInfo
26{
27 MPI_Comm root;
28 std::vector<int> remain_dims;
29 // std::vector<int> periods; // no need to track because the root and all the children have the same periods
30};
31//we keep track of communicators that were created in the past
32// inline variables have the same address in multiple translation units
33// and have external linkage by default
34inline std::map<MPI_Comm, MPICartInfo> mpi_cart_registry;
35
36inline void mpi_cart_registry_display( std::ostream& out = std::cout)
37{
38 out << "MPI Cart registry\n";
39 for ( auto pair : detail::mpi_cart_registry)
40 {
41 auto& re = pair.second.remain_dims;
42 out << "Comm "<<pair.first<<" Root "<<pair.second.root<<" Remains size "<<re.size();
43 out << " r:";
44 for( unsigned i=0; i<re.size(); i++)
45 out << " "<<re[i];
46 out << std::endl;
47 }
48}
49
50inline void mpi_cart_registry_clear( )
51{
52 mpi_cart_registry.clear();
53}
54
55inline void mpi_cart_register_cart( MPI_Comm comm)
56{
57 // Register Cartesian comm if not already there
58 auto it = detail::mpi_cart_registry.find( comm);
59 if( it == detail::mpi_cart_registry.end())
60 {
61 int ndims;
62 dg::mpi_cartdim_get( comm, &ndims);
63 std::vector<int> remain_dims( ndims, true);
64 detail::MPICartInfo info{ comm, remain_dims};
65 detail::mpi_cart_registry[comm] = info;
66 }
67}
68}
69
80inline void register_mpi_cart_sub( MPI_Comm comm, const int remain_dims[], MPI_Comm newcomm)
81{
82 // How should we handle row-major vs column-major issue?
83 detail::mpi_cart_register_cart( comm);
84 detail::MPICartInfo info = detail::mpi_cart_registry.at(comm);
85 unsigned ndims = info.remain_dims.size();
86 for( unsigned u=0; u<ndims; u++)
87 info.remain_dims[u] = remain_dims[u];
88 detail::mpi_cart_registry[newcomm] = info;
89}
90// Can't decide whether to make register_mpi_cart_sub public ...
94
116inline MPI_Comm mpi_cart_sub( MPI_Comm comm, std::vector<int> remain_dims, bool
117 duplicate = false)
118{
119 int ndims;
120 dg::mpi_cartdim_get( comm, &ndims);
121 assert( (unsigned) ndims == remain_dims.size());
122
123 detail::mpi_cart_register_cart( comm);
124 detail::MPICartInfo info = detail::mpi_cart_registry.at(comm);
125 // info.remain_dims may be larger than remain_dims because comm may have a parent
126 // but exactly remain_dims.size() entries are true
127 int counter =0;
128 for( unsigned u=0; u<info.remain_dims.size(); u++)
129 if( info.remain_dims[u])
130 {
131 info.remain_dims[u] = remain_dims[counter];
132 counter ++;
133 }
134 assert( counter == (int)remain_dims.size());
135 if( not duplicate)
136 {
137 for (auto it = detail::mpi_cart_registry.begin(); it !=
138 detail::mpi_cart_registry.end(); ++it)
139 {
140// int comp_root;
141// MPI_Comm_compare( it->second.root, info.root, &comp_root);
142// if( (comp_root == MPI_IDENT or comp_root == MPI_CONGRUENT) and
143// it->second.remain_dims == info.remain_dims)
144 if( it->second.root == info.root && it->second.remain_dims ==
145 info.remain_dims)
146 {
147 return it->first;
148 }
149 }
150 }
151 MPI_Comm newcomm;
152 int err = dg::mpi_cart_sub( comm, &remain_dims[0], &newcomm);
153 if( err != MPI_SUCCESS)
154 throw Error(Message(_ping_)<<
155 "Cannot create Cartesian sub comm from given communicator");
156 register_mpi_cart_sub( comm, &remain_dims[0], newcomm);
157 return newcomm;
158}
159
184inline MPI_Comm mpi_cart_kron( std::vector<MPI_Comm> comms)
185{
186 // This non-template interface must exist so compiler can deduce call
187 // mpi_cart_kron( {comm0, comm1});
188 if ( comms.empty())
189 return MPI_COMM_NULL;
190 if( comms.size() == 1)
191 return comms[0];
192
193 std::vector<detail::MPICartInfo> infos(comms.size());
194
195 for( unsigned u=0; u<comms.size(); u++)
196 {
197 try{
198 infos [u] = detail::mpi_cart_registry.at(comms[u]);
199 }catch( std::exception& e)
200 {
201 std::cerr << "Did not find "<<comms[u]<<" in Registry!\n";
202 detail::mpi_cart_registry_display();
203 throw e;
204
205 }
206 }
207 MPI_Comm root = infos[0].root;
208 for( unsigned u=0; u<comms.size(); u++)
209 if( infos[u].root != root)
210 throw Error(Message(_ping_)<<
211 "In mpi_cart_kron all comms must have same root comm "
212 <<root<<" Offending comm number "<<u<<" with root "
213 <<infos[u].root);
214 auto root_info = detail::mpi_cart_registry.at(root);
215 size_t ndims = root_info.remain_dims.size();
216 std::vector<int> remain_dims( ndims, false) ;
217 unsigned current_free_k=0;
218 for( unsigned u=0; u<comms.size(); u++)
219 {
220 for( unsigned k=0; k<ndims; k++)
221 if( infos[u].remain_dims[k])
222 {
223 if( remain_dims[k])
224 throw Error(Message(_ping_)<<
225 "Cannot form kronecker product with given communicators as remaining dims must be orthogonal ");
226 if( k < current_free_k)
227 throw Error(Message(_ping_)<<
228 "Cannot form kronecker product with communicators in reverse order compared to original ");
229 remain_dims[k] = infos[u].remain_dims[k];
230 current_free_k = k+1;
231 }
232 }
233 return dg::mpi_cart_sub( root_info.root, remain_dims, false);
234}
235
240template<class Vector>
241MPI_Comm mpi_cart_kron( const Vector& comms)
242{
243 return mpi_cart_kron( std::vector<MPI_Comm>(comms.begin(), comms.end()));
244}
245
246
256inline std::vector<MPI_Comm> mpi_cart_split( MPI_Comm comm)
257{
258 // Check that there is a Comm that was already split
259 int ndims;
260 dg::mpi_cartdim_get( comm, &ndims);
261
262 std::vector<MPI_Comm> comms(ndims);
263 for( int u=0; u<ndims; u++)
264 {
265 std::vector<int> remain_dims(ndims, 0);
266 remain_dims[u] = 1;
267 comms[u] = mpi_cart_sub( comm, remain_dims, false);
268 }
269 return comms;
270}
281template<size_t Nd>
282std::array<MPI_Comm, Nd> mpi_cart_split_as( MPI_Comm comm)
283{
284 auto split = mpi_cart_split( comm);
285 std::array<MPI_Comm, Nd> arr;
286 std::copy_n( split.begin(), Nd, arr.begin());
287 return arr;
288}
289
290
291
292// Need to think about those again
293// /*! @brief unregister a communicator
294// * For example if a communicator was freed
295// * @param comm delete associated registry entry
296// */
297//void unregister_mpi_comm( MPI_Comm comm)
298//{
299// detail::mpi_cart_registry.erase( comm);
300//}
301//
302// /*! @brief call \c MPI_Comm_free(comm) followed by \c dg::unregister_mpi_comm(comm)
303// * @param comm free communicator and delete associated registry entry
304// */
305//void mpi_comm_free( MPI_Comm * comm)
306//{
307// MPI_Comm_free(comm);
308// unregister_mpi_comm( *comm);
309//}
310
312
313
314}
class intended for the use in throw statements
Definition exceptions.h:83
small class holding a stringstream
Definition exceptions.h:29
Error classes or the dg library.
#define _ping_
Definition exceptions.h:12
std::array< MPI_Comm, Nd > mpi_cart_split_as(MPI_Comm comm)
Same as mpi_cart_split but different return type.
Definition mpi_kron.h:282
std::vector< MPI_Comm > mpi_cart_split(MPI_Comm comm)
Split a Cartesian communicator along each dimensions.
Definition mpi_kron.h:256
MPI_Comm mpi_cart_sub(MPI_Comm comm, std::vector< int > remain_dims, bool duplicate=false)
Call and register a call to MPI_Cart_sub with the dg library.
Definition mpi_kron.h:116
MPI_Comm mpi_cart_kron(std::vector< MPI_Comm > comms)
Form a (transposed) Kronecker product among Cartesian communicators.
Definition mpi_kron.h:184
void split(SharedContainer &in, std::vector< View< SharedContainer > > &out, const aRealTopology3d< real_type > &grid)
Split a vector into planes along the last dimension (fast version)
Definition split_and_join.h:32
This is the namespace for all functions and classes defined and used by the discontinuous Galerkin li...