TRIQS/mpi 1.3.0
C++ interface to MPI
Loading...
Searching...
No Matches
datatypes.hpp
Go to the documentation of this file.
1// Copyright (c) 2024 Simons Foundation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0.txt
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Authors: Thomas Hahn, Alexander Hampel, Olivier Parcollet, Nils Wentzell
16
22#pragma once
23
24#include "./utils.hpp"
25
26#include <mpi.h>
27
28#include <algorithm>
29#include <array>
30#include <complex>
31#include <cstdlib>
32#include <tuple>
33#include <type_traits>
34#include <utility>
35
36namespace mpi {
37
57 template <typename T> struct mpi_type {};
58
59#define D(T, MPI_TY) \
60 \
61 template <> struct mpi_type<T> { \
62 [[nodiscard]] static MPI_Datatype get() noexcept { return MPI_TY; } \
63 }
64
65 // mpi_type specialization for various built-in types
66 D(bool, MPI_C_BOOL);
67 D(char, MPI_CHAR);
68 D(int, MPI_INT);
69 D(long, MPI_LONG);
70 D(long long, MPI_LONG_LONG);
71 D(double, MPI_DOUBLE);
72 D(float, MPI_FLOAT);
73 D(std::complex<double>, MPI_C_DOUBLE_COMPLEX);
74 D(unsigned long, MPI_UNSIGNED_LONG);
75 D(unsigned int, MPI_UNSIGNED);
76 D(unsigned long long, MPI_UNSIGNED_LONG_LONG);
77#undef D
78
83 template <typename T> struct mpi_type<const T> : mpi_type<T> {};
84
89 template <typename T, typename = void> constexpr bool has_mpi_type = false;
90
95 template <typename T> constexpr bool has_mpi_type<T, std::void_t<decltype(mpi_type<T>::get())>> = true;
96
109 template <typename... Ts> [[nodiscard]] MPI_Datatype get_mpi_type(std::tuple<Ts...> tup) {
110 static constexpr int N = sizeof...(Ts);
111 std::array<MPI_Datatype, N> types = {mpi_type<std::remove_reference_t<Ts>>::get()...};
112
113 // the number of elements per type (we want 1 per type)
114 std::array<int, N> blocklen;
115 for (int i = 0; i < N; ++i) { blocklen[i] = 1; }
116
117 // displacements of the blocks in bytes w.r.t. to the memory address of the first block
118 std::array<MPI_Aint, N> disp;
119 // initialize displacement array from the tuple element addresses
120 []<size_t... Is>(std::index_sequence<Is...>, auto &t, MPI_Aint *d) {
121 ((d[Is] = (char *)&std::get<Is>(t) - (char *)&std::get<0>(t)), ...);
122 // account for non-trivial memory layouts of the tuple elements
123 auto min_el = *std::min_element(d, d + sizeof...(Ts));
124 ((d[Is] -= min_el), ...);
125 }(std::index_sequence_for<Ts...>{}, tup, disp.data());
126
127 // create and return MPI datatype
128 MPI_Datatype cty{};
129 check_mpi_call(MPI_Type_create_struct(N, blocklen.data(), disp.data(), types.data(), &cty), "MPI_Type_create_struct");
130 check_mpi_call(MPI_Type_commit(&cty), "MPI_Type_commit");
131 return cty;
132 }
133
138 template <typename... T> struct mpi_type<std::tuple<T...>> {
139 [[nodiscard]] static MPI_Datatype get() noexcept { return get_mpi_type(std::tuple<T...>{}); }
140 };
141
166 template <typename T> struct mpi_type_from_tie {
167 [[nodiscard]] static MPI_Datatype get() noexcept { return get_mpi_type(tie_data(T{})); }
168 };
169
172} // namespace mpi
MPI_Datatype get_mpi_type(std::tuple< Ts... > tup)
Create a new MPI_Datatype from a tuple.
constexpr bool has_mpi_type
Type trait to check if a type T has a corresponding MPI datatype, i.e. if mpi::mpi_type has been spec...
Definition datatypes.hpp:89
void check_mpi_call(int errcode, const std::string &mpi_routine)
Check the success of an MPI call.
Definition utils.hpp:72
Create an MPI_Datatype from some struct.
Map C++ datatypes to the corresponding MPI datatypes.
Definition datatypes.hpp:57
Provides general utilities related to MPI.