Discontinuous Galerkin Library
#include "dg/algorithm.h"
Loading...
Searching...
No Matches
mpi_init.h
Go to the documentation of this file.
1#pragma once
2
3#include <iostream>
4#include <cassert>
5#include <thrust/host_vector.h>
6#include <thrust/device_vector.h> //declare THRUST_DEVICE_SYSTEM
7#include "config.h"
8#include "mpi_datatype.h"
9#include "mpi_cart.h"
10#include "../enums.h"
11
18namespace dg
19{
20
23
55inline void mpi_init( int *argc, char **argv[])
56{
57 // Interface rationale: MPI_Init can change argc and argv so we need
58 // to also have pointers in our interface
59 // https://stackoverflow.com/questions/2642996/why-does-mpi-init-accept-pointers-to-argc-and-argv
60#ifdef _OPENMP
61 int provided, error;
62 error = MPI_Init_thread(argc, argv, MPI_THREAD_FUNNELED, &provided);
63 assert( error == MPI_SUCCESS && "Threaded MPI lib required!\n");
64#else
65 MPI_Init(argc, argv);
66#endif
67#if THRUST_DEVICE_SYSTEM==THRUST_DEVICE_SYSTEM_CUDA
68 int rank;
69 MPI_Comm_rank( MPI_COMM_WORLD, &rank);
70 int num_devices=0;
71 cudaGetDeviceCount(&num_devices);
72 if(num_devices == 0)
73 {
74 std::cerr << "# No CUDA capable devices found on rank "<<rank<<std::endl;
75 MPI_Abort(MPI_COMM_WORLD, -1);
76 exit(-1);
77 }
78 // MW 10.9.25: This will fail if process pinning assigns ranks in non-contiguous fashion to nodes...
79 // We should better use
80 // https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/examples.html#example-2-one-device-per-process-or-thread
81 // even windows provides a gethostname function ...
82 int device = rank % num_devices; //assume # of gpus/node is fixed
83 cudaSetDevice( device);
84#endif//THRUST_DEVICE_SYSTEM==THRUST_DEVICE_SYSTEM_CUDA
85}
86
95template<class T>
96std::vector<T> mpi_read_as( unsigned num, MPI_Comm comm, std::istream& is = std::cin)
97{
98 int rank;
99 MPI_Comm_rank( comm, &rank);
100 std::vector<T> nums(num);
101 if( rank == 0)
102 {
103 for( unsigned u=0; u<num; u++)
104 is >> nums[u];
105 }
106 if( num > 0)
107 MPI_Bcast( &nums[0], num, getMPIDataType<T>(), 0, comm);
108 return nums;
109}
110
128inline void mpi_read_grid( unsigned& n, std::vector<unsigned>& N, MPI_Comm comm,
129 std::istream& is = std::cin, bool verbose = true, std::ostream& os = std::cout)
130{
131 int rank;
132 MPI_Comm_rank( comm, &rank);
133 const std::string Ns[6] = {"Nx", "Ny", "Nz", "Nu", "Nv", "Nw"};
134 unsigned ndims = N.size();
135 assert( ndims > 0);
136 if(rank == 0 and verbose)
137 {
138 os << "# Type n, "<<Ns[0];
139 for( unsigned u=1; u<ndims; u++)
140 os << " and "<< Ns[u];
141 os << std::endl;
142 }
143 auto vals = mpi_read_as<unsigned>( 1 + ndims, comm, is);
144 n = vals[0];
145 for( unsigned u=0; u<ndims; u++)
146 N[u] = vals[1+u];
147 if(rank == 0 and verbose)
148 {
149 os << "# On the grid "<<n;
150 for( unsigned u=0; u<ndims; u++)
151 os << " x "<< N[u];
152 os << std::endl;
153 }
154}
155
161inline void mpi_read_grid( unsigned& n, std::vector<unsigned*> N, MPI_Comm comm,
162 std::istream& is = std::cin, bool verbose = true, std::ostream& os = std::cout)
163{
164 std::vector<unsigned> Ns( N.size());
165 mpi_read_grid( n, Ns, comm, is, verbose, os);
166 for( unsigned u=0; u<Ns.size(); u++)
167 *N[u] = Ns[u];
168}
169
202inline MPI_Comm mpi_cart_create( MPI_Comm comm_old, std::vector<int> dims,
203 std::vector<int> periods, bool reorder = false)
204{
205 int size;
206 MPI_Comm_size( comm_old, &size);
207 assert( dims.size() == periods.size());
208 int ndims = dims.size();
209 int re = (int)reorder;
210 int err = MPI_Dims_create( size, ndims, &dims[0]);
211 if( err != MPI_SUCCESS)
212 throw Error(Message(_ping_)<<
213 "Cannot create Cartesian dimensions from given dimensions and size "<<size);
214 int reduce = 1;
215 for( int u=0; u<(int)ndims; u++)
216 reduce *= dims[u];
217 if( size != reduce)
218 {
219 throw Error(Message(_ping_)<<
220 "ERROR: Process partition needs to match total number of processes! "
221 <<size<< " vs "<<reduce);
222 }
223 MPI_Comm comm_cart;
224 err = dg::mpi_cart_create( comm_old, ndims, &dims[0], &periods[0], re, &comm_cart);
225 if( err != MPI_SUCCESS)
226 throw Error(Message(_ping_)<<
227 "Cannot create Cartesian comm from given communicator");
228 return comm_cart;
229}
230
262inline MPI_Comm mpi_cart_create(
263 std::vector<dg::bc> bcs,
264 std::istream& is = std::cin,
265 MPI_Comm comm_old = MPI_COMM_WORLD,
266 bool reorder = false,
267 bool verbose = true,
268 std::ostream& os = std::cout)
269{
270 int rank, size;
271 MPI_Comm_rank( comm_old, &rank);
272 MPI_Comm_size( comm_old, &size);
273 if(rank==0 && verbose)os << "# MPI v"<<MPI_VERSION<<"."<<MPI_SUBVERSION<<std::endl;
274 unsigned ndims = bcs.size();
275 assert( ndims != 0);
276 std::vector<int> periods( ndims);
277 for( unsigned u=0; u<ndims; u++)
278 {
279 if(bcs[u] == dg::PER)
280 periods[u] = true;
281 else
282 periods[u] = false;
283 }
284 if( rank == 0)
285 {
286 if(verbose)
287 {
288 const std::string nps[6] = {"npx", "npy", "npz", "npu", "npv", "npw"};
289 os << "# Type "<<nps[0];
290 for( unsigned u=1; u<ndims; u++)
291 os << " and "<< nps[u];
292 os << std::endl;
293 }
294 }
295 auto np = mpi_read_as<int>( ndims, comm_old, is);
296 if( rank == 0)
297 {
298 if(verbose)
299 {
300 int num_threads = 1;
301#ifdef _OPENMP
302 num_threads = omp_get_max_threads( );
303#endif //omp
304 os << "# Computing with "<<np[0];
305 for( unsigned u=1; u<ndims; u++)
306 os << " x " <<np[u];
307 os << " processes x " << num_threads<<" threads = "
308 << size*num_threads<<" total"<<std::endl;
309 }
310 }
311#if THRUST_DEVICE_SYSTEM==THRUST_DEVICE_SYSTEM_CUDA
312 int device=0;
313 cudaGetDevice( &device);
314 if( rank==0 and verbose)
315 {
316 std::cout << "# MPI is "
317 <<(nccl_mpi ? "using NCCL" : (cuda_aware_mpi ? "cuda-aware" : "NOT cuda-aware"))
318 <<"!\n";
319 }
320 if(verbose)std::cout << "# Rank "<<rank<<" computes with device "<<device<<" !"<<std::endl;
321#endif//THRUST_DEVICE_SYSTEM==THRUST_DEVICE_SYSTEM_CUDA
322 return dg::mpi_cart_create( comm_old, np, periods, reorder);
323}
324
325
326
335inline void mpi_init1d( dg::bc bcx, MPI_Comm& comm, std::istream& is =
336std::cin, bool verbose = true)
337{
338 comm = mpi_cart_create( {bcx}, is, MPI_COMM_WORLD, true, verbose,
339 std::cout);
340}
349inline void mpi_init2d( dg::bc bcx, dg::bc bcy, MPI_Comm& comm, std::istream&
350is = std::cin, bool verbose = true)
351{
352 comm = mpi_cart_create( {bcx, bcy}, is, MPI_COMM_WORLD, true, verbose,
353 std::cout);
354}
355
364inline void mpi_init3d( dg::bc bcx, dg::bc bcy, dg::bc bcz, MPI_Comm& comm,
365std::istream& is = std::cin, bool verbose = true )
366{
367 comm = mpi_cart_create( {bcx, bcy, bcz}, is, MPI_COMM_WORLD, true, verbose,
368 std::cout);
369}
370
382inline void mpi_init1d( dg::bc bcx, unsigned& n, unsigned& N, MPI_Comm& comm,
383std::istream& is = std::cin, bool verbose = true )
384{
385 comm = mpi_cart_create( {bcx}, is, MPI_COMM_WORLD, true, verbose,
386 std::cout);
387 mpi_read_grid( n, {&N}, comm, is, verbose, std::cout);
388}
389
401inline void mpi_init2d( dg::bc bcx, dg::bc bcy, unsigned& n, unsigned& Nx,
402unsigned& Ny, MPI_Comm& comm, std::istream& is = std::cin, bool verbose = true
403)
404{
405 comm = mpi_cart_create( {bcx, bcy}, is, MPI_COMM_WORLD, true, verbose,
406 std::cout);
407 mpi_read_grid( n, {&Nx, &Ny}, comm, is, verbose, std::cout);
408}
409
410
422inline void mpi_init3d( dg::bc bcx, dg::bc bcy, dg::bc bcz, unsigned& n,
423unsigned& Nx, unsigned& Ny, unsigned& Nz, MPI_Comm& comm, std::istream& is =
424std::cin, bool verbose = true )
425{
426 comm = mpi_cart_create( {bcx, bcy, bcz}, is, MPI_COMM_WORLD, true, verbose,
427 std::cout);
428 mpi_read_grid( n, {&Nx, &Ny, &Nz}, comm, is, verbose, std::cout);
429}
430
432
433} //namespace dg
class intended for the use in throw statements
Definition exceptions.h:83
small class holding a stringstream
Definition exceptions.h:29
enums
#define _ping_
Definition exceptions.h:12
bc
Switch between boundary conditions.
Definition enums.h:15
@ PER
periodic boundaries
Definition enums.h:16
void mpi_init3d(dg::bc bcx, dg::bc bcy, dg::bc bcz, MPI_Comm &comm, std::istream &is=std::cin, bool verbose=true)
DEPRECATED: Short for.
Definition mpi_init.h:364
void mpi_init1d(dg::bc bcx, MPI_Comm &comm, std::istream &is=std::cin, bool verbose=true)
DEPRECATED: Short for.
Definition mpi_init.h:335
void mpi_init2d(dg::bc bcx, dg::bc bcy, MPI_Comm &comm, std::istream &is=std::cin, bool verbose=true)
DEPRECATED: Short for.
Definition mpi_init.h:349
void mpi_read_grid(unsigned &n, std::vector< unsigned > &N, MPI_Comm comm, std::istream &is=std::cin, bool verbose=true, std::ostream &os=std::cout)
Read in grid sizes from is.
Definition mpi_init.h:128
void mpi_init(int *argc, char **argv[])
Convencience shortcut: Calls MPI_Init or MPI_Init_thread and inits CUDA devices.
Definition mpi_init.h:55
MPI_Comm mpi_cart_create(MPI_Comm comm_old, std::vector< int > dims, std::vector< int > periods, bool reorder=false)
Convenience call to MPI_Cart_create preceded by MPI_Dims_create.
Definition mpi_init.h:202
std::vector< T > mpi_read_as(unsigned num, MPI_Comm comm, std::istream &is=std::cin)
Read num values from is and broadcast to all processes as type T.
Definition mpi_init.h:96
dg::bc bcy
dg::bc bcx
const double n
This is the namespace for all functions and classes defined and used by the discontinuous Galerkin li...