FML
Global.h
Go to the documentation of this file.
1#ifndef GLOBAL_HEADER
2#define GLOBAL_HEADER
3
4//===========================================================================
5//
6// Global information. Keep info about MPI/OMP parallelizations and the domain
7// decomposition, type information, macros etc.
8//
9// Compile time defines:
10// USE_MPI : Use MPI
11// NO_AUTO_FML_SETUP : Do not initialize FML/MPI/FFTW automatically
12// USE_OMP : Use OpenMP
13// USE_FFTW : Use FFTW (here its just for initialization for MPI/threads)
14// MEMORY_LOGGING : Log all (big) allocations with the standard container (see MemoryLogging.h)
15// MIN_BYTES_TO_LOG : How many bytes to enable logging of allocation
16// MAX_ALLOCATIONS_IN_MEMORY : Maximum number of allocations to keep (above which we give up)
17//
18//===========================================================================
19
20#include <algorithm>
21#include <cmath>
22#include <complex>
23#include <cstring>
24#include <iostream>
25#include <vector>
26
27#ifdef USE_MPI
28#include <mpi.h>
29#endif
30
31#ifdef USE_OMP
32#include <omp.h>
33#endif
34
35#ifdef MEMORY_LOGGING
37#endif
38
39#include <FML/Timing/Timings.h>
40
41namespace FML {
42
43 // MPI and OpenMP information
44 /// The MPI task number
45 extern int ThisTask;
46 /// Total number of MPI tasks
47 extern int NTasks;
48 /// Total number of threads availiable
49 extern int NThreads;
50 /// If MPI and threads can work together with FFTW
51 extern bool MPIThreadsOK; // Set by init_mpi
52 extern bool FFTWThreadsOK; // Set by init_fftw
53
54 /// The local extent of the domain (global domain goes from 0 to 1)
55 extern double xmin_domain;
56 /// The local extent of the domain (global domain goes from 0 to 1)
57 extern double xmax_domain;
58
59 // Global timer
61
62 auto uniform_random() -> double;
63
64 //================================================
65 // Allocator to allow for logging of memory
66 // usage
67 //================================================
68 template <class T>
69#ifdef MEMORY_LOGGING
71#else
72 using Allocator = std::allocator<T>;
73#endif
74
75 //================================================
76 // Standard container
77 //================================================
78 template <class T>
79 using Vector = std::vector<T, Allocator<T>>;
80
81 //================================================
82 // Integer type for array indices
83 //================================================
84 using IndexIntType = long long int;
85
86 //================================================
87 // MPI functions
88 //================================================
89 void init_mpi(int * argc, char *** argv);
90 void abort_mpi(int exit_code);
91 void finalize_mpi();
92 void printf_mpi(const char * fmt, ...);
93 void info();
94
95 //================================================
96 // Initialize the globals within FML
97 // Assumes MPI has been initialized
98 //================================================
99 void init_fml();
100
101 // Get the current and peak value of the resident set size (in bytes)
102 std::pair<double, double> get_system_memory_use();
103 // Print the min/max of the current and peak value of the resident set size
104 // over tasks
106
107 /// Gather a single value from all tasks. Value from task ThisTask is stored in values[ThisTask]
108 template <class T>
109 std::vector<T> GatherFromTasks(T * value) {
110 std::vector<T> values(FML::NTasks);
111#ifdef USE_MPI
112 MPI_Allgather(value, sizeof(T), MPI_BYTE, values.data(), sizeof(T), MPI_BYTE, MPI_COMM_WORLD);
113#else
114 values[0] = *value;
115#endif
116 return values;
117 }
118
119 /// Inplace max over tasks of a single value
120 template <class T>
121 void MaxOverTasks([[maybe_unused]] T * value) {
122 if (FML::NTasks == 1)
123 return;
124 std::vector<T> values = GatherFromTasks(value);
125 T maxvalue = *value;
126 for (auto v : values)
127 if (maxvalue < v)
128 maxvalue = v;
129 *value = maxvalue;
130 }
131
132 /// Inplace min over tasks of a single value
133 template <class T>
134 void MinOverTasks([[maybe_unused]] T * value) {
135 if (FML::NTasks == 1)
136 return;
137 std::vector<T> values = GatherFromTasks(value);
138 T minvalue = *value;
139 for (auto v : values)
140 if (minvalue > v)
141 minvalue = v;
142 *value = minvalue;
143 }
144
145 /// Inplace sum over tasks of a single value
146 template <class T>
147 void SumOverTasks([[maybe_unused]] T * value) {
148 if (FML::NTasks == 1)
149 return;
150 std::vector<T> values = GatherFromTasks(value);
151 T sum = 0;
152 for (auto v : values) {
153 sum += v;
154 }
155 *value = sum;
156 }
157
158 /// Inplace sum over tasks of a contigious array of values
159 template <class T>
160 void SumArrayOverTasks([[maybe_unused]] T * value, int n) {
161 if (FML::NTasks == 1)
162 return;
163 for(int i = 0; i < n; i++){
164 SumOverTasks(&value[i]);
165 }
166 }
167
168 //============================================
169 /// An assert function that calls MPI_Abort
170 /// instead of just abort to avoid deadlock
171 //============================================
172 constexpr void __assert_mpi(const char * expr_str, bool expr, const char * file, int line, const char * msg) {
173 if (not expr) {
174 std::cout << "[assert_mpi] Assertion failed: [" << expr_str << "], File: [" << file << "], Line: [" << line
175 << "], Message: [" << msg << "]" << std::endl;
176#ifdef USE_MPI
177 MPI_Abort(MPI_COMM_WORLD, 1);
178#endif
179 abort();
180 }
181 }
182#define assert_mpi(Expr, Msg) __assert_mpi(#Expr, Expr, __FILE__, __LINE__, Msg)
183
184 //============================================
185 /// Simple integer a^b power-function by squaring
186 //============================================
187 constexpr long long int power(int base, int exponent) {
188 return exponent == 0 ?
189 1 :
190 (exponent % 2 == 0 ?
191 power(base, exponent / 2) * power(base, exponent / 2) :
192 (long long int)(base)*power(base, (exponent - 1) / 2) * power(base, (exponent - 1) / 2));
193 }
194
195 //============================================
196 // Create a folder (only Task 0 is allowed
197 // to do this)
198 //============================================
199 bool create_folder(std::string foldername);
200
201 //============================================
202 // Overloads of arithmetic operations for the
203 // container plus elementary math functions
204 // using some simple macros
205 //============================================
206
207#define OPS(OP) \
208 template <class T> \
209 auto operator OP(const Vector<T> & lhs, const Vector<T> & rhs)->Vector<T> { \
210 const size_t nlhs = lhs.size(); \
211 const size_t nrhs = rhs.size(); \
212 if (nlhs != nrhs) \
213 throw std::runtime_error("Error vectors need to have the same size:"); \
214 Vector<T> y(nlhs); \
215 for (size_t i = 0; i < nlhs; i++) { \
216 y[i] = lhs[i] OP rhs[i]; \
217 } \
218 return y; \
219 }
221 OPS(-)
222 OPS(*)
223 OPS(/)
224#undef OPS
225
226#define OPS(OP) \
227 template <class T> \
228 auto operator OP(const Vector<T> & lhs, const double & rhs)->Vector<T> { \
229 const size_t nlhs = lhs.size(); \
230 Vector<T> y(nlhs); \
231 for (size_t i = 0; i < nlhs; i++) { \
232 y[i] = lhs[i] OP rhs; \
233 } \
234 return y; \
235 }
236 OPS(+)
237 OPS(-)
238 OPS(*)
239 OPS(/)
240#undef OPS
241
242#define OPS(OP) \
243 template <class T> \
244 auto operator OP(const double & lhs, const Vector<T> & rhs)->Vector<T> { \
245 const size_t nrhs = rhs.size(); \
246 Vector<T> y(nrhs); \
247 for (size_t i = 0; i < nrhs; i++) { \
248 y[i] = lhs OP rhs[i]; \
249 } \
250 return y; \
251 }
252 OPS(+)
253 OPS(-)
254 OPS(*)
255 OPS(/)
256#undef OPS
257
258 template <class T>
259 Vector<T> pow(const Vector<T> & x, const double exp) {
260 const size_t n = x.size();
262 for (size_t i = 0; i < n; i++) {
263 y[i] = std::pow(x[i], exp);
264 }
265 return y;
266 }
267
268#define FUNS(FUN) \
269 template <class T> \
270 auto FUN(const Vector<T> & x)->Vector<T> { \
271 auto op_##FUN = [](double x) -> Vector<T> { return std::FUN(x); }; \
272 Vector<T> y(x.size()); \
273 std::transform(x.begin(), x.end(), y.begin(), op_##FUN); \
274 return y; \
275 }
276 FUNS(exp)
277 FUNS(log)
278 FUNS(cos)
279 FUNS(sin)
280 FUNS(tan)
281 FUNS(fabs)
282 FUNS(atan)
283#undef FUNS
284} // namespace FML
285
286namespace FML {
287
288 //=============================================================
289 /// Singleton for initializing and finalizing MPI automatically on
290 /// startup and exit
291 //=============================================================
292 struct MPISetup {
293 static MPISetup & init(int * argc = nullptr, char *** argv = nullptr) {
294 static MPISetup instance(argc, argv);
295 return instance;
296 }
297
298 private:
299 MPISetup(int * argc = nullptr, char *** argv = nullptr) { init_mpi(argc, argv); }
300
301 ~MPISetup() { finalize_mpi(); }
302 };
303
304#ifdef USE_FFTW
305 namespace GRID {
307 void init_fftw(int * argc, char *** argv);
308 void finalize_fftw();
309 void set_fftw_nthreads(int nthreads);
310 } // namespace GRID
311
312 //=============================================================
313 /// Singleton for initializing and cleaning up FFTW
314 /// with MPI and threads automatically
315 //=============================================================
316 struct FFTWSetup {
317 static FFTWSetup & init(int * argc = nullptr, char *** argv = nullptr) {
318 static FFTWSetup instance(argc, argv);
319 return instance;
320 }
321
322 private:
323 FFTWSetup(int * argc, char *** argv) { FML::GRID::init_fftw(argc, argv); }
324
325 ~FFTWSetup() { FML::GRID::finalize_fftw(); }
326 };
327#endif
328
329 //=============================================================
330 /// Singleton for initializing and cleaning up FML
331 /// Takes care of automatically initializing MPI and FFTW
332 //=============================================================
333 struct FMLSetup {
334 static FMLSetup & init(int * argc = nullptr, char *** argv = nullptr) {
335 static FMLSetup instance(argc, argv);
336 return instance;
337 }
338
339 private:
340 FMLSetup(int * argc, char *** argv) {
341 // Initialize MPI
342 [[maybe_unused]] MPISetup & m = MPISetup::init(argc, argv);
343
344#ifdef USE_FFTW
345 // Initialize FFTW
346 [[maybe_unused]] FFTWSetup & f = FFTWSetup::init(argc, argv);
347#endif
348
349 // Initialize FML
350 init_fml();
351
352 // Show some info to see that all is ok
353 info();
354 }
355
356 ~FMLSetup() = default;
357 };
358} // namespace FML
359
360#endif
Class for performing timings of the code using std::chrono.
Definition: Timings.h:22
void finalize_fftw()
Definition: Global.cpp:293
void init_fftw(int *argc, char ***argv)
Definition: Global.cpp:279
void set_fftw_nthreads(int nthreads)
Definition: Global.cpp:300
Definition: CAMBReader.h:10
bool create_folder(std::string foldername)
Definition: Global.cpp:207
double xmax_domain
The local extent of the domain (global domain goes from 0 to 1)
Definition: Global.cpp:42
void MinOverTasks(T *value)
Inplace min over tasks of a single value.
Definition: Global.h:134
std::pair< double, double > get_system_memory_use()
Fetch the resident set size currently and the peak value so far of it.
Definition: Global.cpp:223
int NThreads
Total number of threads availiable.
Definition: Global.cpp:35
void SumArrayOverTasks(T *value, int n)
Inplace sum over tasks of a contigious array of values.
Definition: Global.h:160
bool MPIThreadsOK
If MPI and threads can work together with FFTW.
Definition: Global.cpp:38
void init_mpi(int *argc, char ***argv)
Initialize MPI.
Definition: Global.cpp:55
void MaxOverTasks(T *value)
Inplace max over tasks of a single value.
Definition: Global.h:121
constexpr long long int power(int base, int exponent)
Simple integer a^b power-function by squaring.
Definition: Global.h:187
return y
Definition: Global.h:265
void abort_mpi(int exit_code)
Definition: Global.cpp:170
OPS(+) OPS(-) OPS(*) OPS(/) OPS(+) OPS(-) OPS(*) OPS(/) OPS(+) OPS(-) OPS(*) OPS(/) template< class T > Vector< T > pow(const Vector< T > &x
int ThisTask
The MPI task number.
Definition: Global.cpp:33
void printf_mpi(const char *fmt,...)
Definition: Global.cpp:193
bool FFTWThreadsOK
Definition: Global.cpp:37
std::vector< T > GatherFromTasks(T *value)
Gather a single value from all tasks. Value from task ThisTask is stored in values[ThisTask].
Definition: Global.h:109
void finalize_mpi()
Definition: Global.cpp:180
long long int IndexIntType
Definition: Global.h:84
void print_system_memory_use()
Print the resident set size and the peak value of it so far.
Definition: Global.cpp:233
FML::UTILS::Timings global_timer
Definition: Global.cpp:18
double uniform_random()
Definition: Global.cpp:46
const double exp
Definition: Global.h:259
void info()
Show some info about FML.
Definition: Global.cpp:103
void SumOverTasks(T *value)
Inplace sum over tasks of a single value.
Definition: Global.h:147
double xmin_domain
The local extent of the domain (global domain goes from 0 to 1)
Definition: Global.cpp:41
std::vector< T, Allocator< T > > Vector
Definition: Global.h:79
int NTasks
Total number of MPI tasks.
Definition: Global.cpp:34
constexpr void __assert_mpi(const char *expr_str, bool expr, const char *file, int line, const char *msg)
An assert function that calls MPI_Abort instead of just abort to avoid deadlock.
Definition: Global.h:172
void init_fml()
Initialize the global variables within FML We here assume MPI has been initialized.
Definition: Global.cpp:71
x
Definition: test.py:18
Singleton for initializing and cleaning up FFTW with MPI and threads automatically.
Definition: Global.h:316
static FFTWSetup & init(int *argc=nullptr, char ***argv=nullptr)
Definition: Global.h:317
Singleton for initializing and cleaning up FML Takes care of automatically initializing MPI and FFTW.
Definition: Global.h:333
static FMLSetup & init(int *argc=nullptr, char ***argv=nullptr)
Definition: Global.h:334
Custom allocator that logs allocations.
Singleton for initializing and finalizing MPI automatically on startup and exit.
Definition: Global.h:292
static MPISetup & init(int *argc=nullptr, char ***argv=nullptr)
Definition: Global.h:293