Highly Efficient FFT for Exascale: HeFFTe v2.3
heffte_utils.h
1 /*
2  -- heFFTe --
3  Univ. of Tennessee, Knoxville
4  @date
5 */
6 
7 #ifndef HEFFTE_UTILS_H
8 #define HEFFTE_UTILS_H
9 
10 #include <algorithm>
11 #include <vector>
12 #include <complex>
13 #include <memory>
14 #include <numeric>
15 #include <algorithm>
16 #include <functional>
17 #include <cassert>
18 #include <utility>
19 #include <iostream>
20 #include <ostream>
21 #include <iomanip>
22 #include <string>
23 #include <deque>
24 #include <fstream>
25 #include <mpi.h>
26 
27 #include "heffte_config.h"
28 
29 namespace heffte {
30 
35 template<class T, class U = T>
36 T c11_exchange(T& obj, U&& new_value)
37 {
38  T old_value = std::move(obj);
39  obj = std::forward<U>(new_value);
40  return old_value;
41 }
42 
56 namespace mpi {
57 
78 inline int comm_rank(MPI_Comm const comm){
79  int me;
80  MPI_Comm_rank(comm, &me);
81  return me;
82 }
97 inline bool world_rank(int rank){ return (comm_rank(MPI_COMM_WORLD) == rank); }
104 inline int world_rank(){ return comm_rank(MPI_COMM_WORLD); }
105 
116 template<typename vector_like>
117 void dump(int me, vector_like const &x, std::string const &message){
118  if (me < 0 or world_rank(me)){
119  std::cout << message << "\n";
120  for(auto i : x) std::cout << i << " ";
121  std::cout << std::endl;
122  }
123 }
124 
135 inline int comm_size(MPI_Comm const comm){
136  int nprocs;
137  MPI_Comm_size(comm, &nprocs);
138  return nprocs;
139 }
151 inline MPI_Comm new_comm_from_group(std::vector<int> const &ranks, MPI_Comm const comm){
152  MPI_Group orig_group, new_group;
153  MPI_Comm_group(comm, &orig_group);
154  MPI_Group_incl(orig_group, (int) ranks.size(), ranks.data(), &new_group);
155  MPI_Comm result;
156  MPI_Comm_create(comm, new_group, &result);
157  MPI_Group_free(&orig_group);
158  MPI_Group_free(&new_group);
159  return result;
160 }
161 
174 inline void comm_free(MPI_Comm const comm){
175  if (MPI_Comm_free(const_cast<MPI_Comm*>(&comm)) != MPI_SUCCESS)
176  throw std::runtime_error("Could not free a communicator.");
177 }
178 
189 template<typename scalar> inline MPI_Datatype type_from(){
190  // note that "!std::is_same<scalar, scalar>::value" is always false,
191  // but will not be checked until the template is instantiated
192  static_assert(!std::is_same<scalar, scalar>::value, "The C++ type has unknown MPI equivalent.");
193  return MPI_BYTE; // some compilers complain about lack of return statement.
194 }
199 template<> inline MPI_Datatype type_from<int>(){ return MPI_INT; }
204 template<> inline MPI_Datatype type_from<float>(){ return MPI_FLOAT; }
209 template<> inline MPI_Datatype type_from<double>(){ return MPI_DOUBLE; }
214 template<> inline MPI_Datatype type_from<std::complex<float>>(){ return MPI_C_COMPLEX; }
219 template<> inline MPI_Datatype type_from<std::complex<double>>(){ return MPI_C_DOUBLE_COMPLEX; }
220 
221 }
222 
251 template<typename scalar_type> struct is_ccomplex : std::false_type{};
269 template<typename scalar_type> struct is_zcomplex : std::false_type{};
270 
275 template<> struct is_ccomplex<std::complex<float>> : std::true_type{};
280 template<> struct is_zcomplex<std::complex<double>> : std::true_type{};
281 
314 template<typename, typename = void> struct define_standard_type{};
315 
320 template<> struct define_standard_type<float, void>{
322  using type = float;
323 };
328 template<> struct define_standard_type<double, void>{
330  using type = double;
331 };
332 
337 template<typename scalar_type> struct define_standard_type<scalar_type, typename std::enable_if<is_ccomplex<scalar_type>::value>::type>{
339  using type = std::complex<float>;
340 };
345 template<typename scalar_type> struct define_standard_type<scalar_type, typename std::enable_if<is_zcomplex<scalar_type>::value>::type>{
347  using type = std::complex<double>;
348 };
349 
353 template<typename scalar_type>
355  return reinterpret_cast<typename define_standard_type<scalar_type>::type*>(input);
356 }
361 template<typename scalar_type>
362 typename define_standard_type<scalar_type>::type const* convert_to_standard(scalar_type const input[]){
363  return reinterpret_cast<typename define_standard_type<scalar_type>::type const*>(input);
364 }
365 
379 template<typename some_class>
380 int get_last_active(std::array<std::unique_ptr<some_class>, 4> const &shaper){
381  int last = -1;
382  for(int i=0; i<4; i++) if (shaper[i]) last = i;
383  return last;
384 }
385 
390 template<typename some_class>
391 int count_active(std::array<std::unique_ptr<some_class>, 4> const &shaper){
392  int num = 0;
393  for(int i=0; i<4; i++) if (shaper[i]) num++;
394  return num;
395 }
396 
401 template<typename some_class>
402 size_t get_max_box_size(std::array<some_class, 3> const &executors){
403  size_t max_size = (executors[0]) ? executors[0]->box_size() : 0;
404  max_size = std::max(max_size, (executors[1]) ? executors[1]->box_size() : static_cast<size_t>(0));
405  return std::max(max_size, (executors[2]) ? executors[2]->box_size() : static_cast<size_t>(0));
406 }
407 
412 template<typename some_class>
413 size_t get_max_box_size_r2c(std::array<some_class, 3> const &executors){
414  size_t max_size = (executors[0]) ? executors[0]->complex_size() : 0;
415  max_size = std::max(max_size, (executors[1]) ? executors[1]->box_size() : static_cast<size_t>(0));
416  return std::max(max_size, (executors[2]) ? executors[2]->box_size() : static_cast<size_t>(0));
417 }
422 template<typename some_class>
423 size_t get_max_work_size(std::array<some_class, 3> const &executors){
424  size_t max_size = (executors[0]) ? executors[0]->workspace_size() : 0;
425  max_size = std::max(max_size, (executors[1]) ? executors[1]->workspace_size() : static_cast<size_t>(0));
426  return std::max(max_size, (executors[2]) ? executors[2]->workspace_size() : static_cast<size_t>(0));
427 }
428 
433 template<typename some_class_r2c, typename some_class>
434 size_t get_max_work_size(some_class_r2c const &executors_r2c, std::array<some_class, 2> const &executors){
435  return std::max(executors_r2c->workspace_size(), std::max(executors[0]->workspace_size(), executors[1]->workspace_size()));
436 }
437 
438 }
439 
440 #endif /* HEFFTE_UTILS_H */
T c11_exchange(T &obj, U &&new_value)
Replace with the C++ 2014 std::exchange later.
Definition: heffte_utils.h:36
int get_last_active(std::array< std::unique_ptr< some_class >, 4 > const &shaper)
Return the index of the last active (non-null) unique_ptr.
Definition: heffte_utils.h:380
size_t get_max_box_size_r2c(std::array< some_class, 3 > const &executors)
Returns the max of the box_size() for each of the executors.
Definition: heffte_utils.h:413
size_t get_max_box_size(std::array< some_class, 3 > const &executors)
Returns the max of the box_size() for each of the executors.
Definition: heffte_utils.h:402
int count_active(std::array< std::unique_ptr< some_class >, 4 > const &shaper)
Return the number of active (non-null) unique_ptr.
Definition: heffte_utils.h:391
size_t get_max_work_size(std::array< some_class, 3 > const &executors)
Returns the max of the workspace_size() for each of the executors.
Definition: heffte_utils.h:423
MPI_Datatype type_from< float >()
Specialization to hand the float type.
Definition: heffte_utils.h:204
MPI_Datatype type_from< int >()
Specialization to hand the int type.
Definition: heffte_utils.h:199
bool world_rank(int rank)
Returns true if this process has the me rank within the MPI_COMM_WORLD (useful for debugging).
Definition: heffte_utils.h:97
int comm_rank(MPI_Comm const comm)
Returns the rank of this process within the specified comm.
Definition: heffte_utils.h:78
void comm_free(MPI_Comm const comm)
Calls free on the MPI comm.
Definition: heffte_utils.h:174
int comm_size(MPI_Comm const comm)
Returns the size of the specified communicator.
Definition: heffte_utils.h:135
MPI_Datatype type_from< double >()
Specialization to hand the double type.
Definition: heffte_utils.h:209
void dump(int me, vector_like const &x, std::string const &message)
Write the message and the data from the vector-like x, performed only on rank me (if positive),...
Definition: heffte_utils.h:117
MPI_Datatype type_from()
Returns the MPI equivalent of the scalar C++ type.
Definition: heffte_utils.h:189
MPI_Comm new_comm_from_group(std::vector< int > const &ranks, MPI_Comm const comm)
Creates a new sub-communicator from the provided processes in comm.
Definition: heffte_utils.h:151
Namespace containing all HeFFTe methods and classes.
Definition: heffte_backend_cuda.h:38
define_standard_type< scalar_type >::type * convert_to_standard(scalar_type input[])
Converts an array of some type to an array of the C++ equivalent type.
Definition: heffte_utils.h:354
double type
Double is equivalent to double.
Definition: heffte_utils.h:330
float type
Float is equivalent to float.
Definition: heffte_utils.h:322
std::complex< double > type
If heffte::is_ccomplex is true_type, then the type is equivalent to std::complex<double>.
Definition: heffte_utils.h:347
std::complex< float > type
If heffte::is_ccomplex is true_type, then the type is equivalent to std::complex<float>.
Definition: heffte_utils.h:339
Struct to specialize that returns the C++ equivalent of each type.
Definition: heffte_utils.h:314
Struct to specialize to allow HeFFTe to recognize custom single precision complex types.
Definition: heffte_utils.h:251
Struct to specialize to allow HeFFTe to recognize custom double precision complex types.
Definition: heffte_utils.h:269