opm-simulators
MPIPacker.hpp
1 /*
2  Copyright 2019 Equinor AS.
3 
4  This file is part of the Open Porous Media project (OPM).
5 
6  OPM is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  OPM is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OPM. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #ifndef MPI_PACKER_HPP
20 #define MPI_PACKER_HPP
21 
22 #include <opm/common/utility/TimeService.hpp>
23 #include <opm/simulators/utils/ParallelCommunication.hpp>
24 
25 #include <dune/common/parallel/mpitraits.hh>
26 
27 #include <bitset>
28 #include <cstddef>
29 #include <limits>
30 #include <string>
31 
32 
33 namespace Opm::Mpi {
34 
35 namespace detail {
36 
37 template <typename T>
38 constexpr bool is_pod_v = std::is_standard_layout_v<T> && std::is_trivial_v<T>;
39 
40 std::size_t mpi_buffer_size(const std::size_t bufsize, const std::size_t position);
41 
43 template <bool pod, class T>
44 struct Packing
45 {
46  static std::size_t packSize(const T&, Parallel::MPIComm);
47  static void pack(const T&, std::vector<char>&, std::size_t&, Parallel::MPIComm);
48  static void unpack(T&, const std::vector<char>&, std::size_t&, Parallel::MPIComm);
49 };
50 
52 template<class T>
53 struct Packing<true,T>
54 {
58  static std::size_t packSize(const T& data, Parallel::MPIComm comm)
59  {
60  return packSize(&data, 1, comm);
61  }
62 
67  static std::size_t packSize(const T*, std::size_t n, Parallel::MPIComm comm)
68  {
69  // For now we do not handle the situation where a a single call to packSize/pack/unpack
70  // is likely to require an MPI_Pack_size value larger than intmax
71  if (n*sizeof(T) > std::numeric_limits<int>::max())
72  throw std::invalid_argument("packSize will be larger than max integer - this is not supported.");
73  int size = 0;
74  MPI_Pack_size(n, Dune::MPITraits<T>::getType(), comm, &size);
75  return static_cast<std::size_t>(size);
76  }
77 
83  static void pack(const T& data,
84  std::vector<char>& buffer,
85  std::size_t& position,
86  Parallel::MPIComm comm)
87  {
88  pack(&data, 1, buffer, position, comm);
89  }
90 
97  static void pack(const T* data,
98  std::size_t n,
99  std::vector<char>& buffer,
100  std::size_t& position,
101  Parallel::MPIComm comm)
102  {
103  int int_position = 0;
104  MPI_Pack(data, n, Dune::MPITraits<T>::getType(), buffer.data()+position,
105  mpi_buffer_size(buffer.size(), position), &int_position, comm);
106  position += int_position;
107  }
108 
114  static void unpack(T& data,
115  const std::vector<char>& buffer,
116  std::size_t& position,
117  Parallel::MPIComm comm)
118  {
119  unpack(&data, 1, buffer, position, comm);
120  }
121 
128  static void unpack(T* data,
129  std::size_t n,
130  const std::vector<char>& buffer,
131  std::size_t& position,
132  Parallel::MPIComm comm)
133  {
134  int int_position = 0;
135  MPI_Unpack(buffer.data()+position, mpi_buffer_size(buffer.size(), position), &int_position, data, n,
136  Dune::MPITraits<T>::getType(), comm);
137  position += int_position;
138  }
139 };
140 
142 template<class T>
143 struct Packing<false,T>
144 {
145  static std::size_t packSize(const T&, Parallel::MPIComm)
146  {
147  static_assert(!std::is_same_v<T,T>, "Packing not supported for type");
148  return 0;
149  }
150 
151  static void pack(const T&, std::vector<char>&, std::size_t&,
152  Parallel::MPIComm)
153  {
154  static_assert(!std::is_same_v<T,T>, "Packing not supported for type");
155  }
156 
157  static void unpack(T&, const std::vector<char>&, std::size_t&,
158  Parallel::MPIComm)
159  {
160  static_assert(!std::is_same_v<T,T>, "Packing not supported for type");
161  }
162 };
163 
165 template <std::size_t Size>
166 struct Packing<false,std::bitset<Size>>
167 {
168  static std::size_t packSize(const std::bitset<Size>&, Opm::Parallel::MPIComm);
169  static void pack(const std::bitset<Size>&, std::vector<char>&, std::size_t&, Opm::Parallel::MPIComm);
170  static void unpack(std::bitset<Size>&, const std::vector<char>&,
171  std::size_t&, Opm::Parallel::MPIComm);
172 };
173 
174 #define ADD_PACK_SPECIALIZATION(T) \
175  template<> \
176  struct Packing<false,T> \
177  { \
178  static std::size_t packSize(const T&, Parallel::MPIComm); \
179  static void pack(const T&, std::vector<char>&, std::size_t&, Parallel::MPIComm); \
180  static void unpack(T&, const std::vector<char>&, std::size_t&, Parallel::MPIComm); \
181  };
182 
183 ADD_PACK_SPECIALIZATION(std::string)
184 ADD_PACK_SPECIALIZATION(time_point)
185 
186 #undef ADD_PACK_SPECIALIZATION
187 
188 }
189 
191 struct Packer
192 {
195  explicit Packer(Parallel::Communication comm)
196  : m_comm(comm)
197  {}
198 
202  template<class T>
203  std::size_t packSize(const T& data) const
204  {
205  return detail::Packing<detail::is_pod_v<T>,T>::packSize(data, m_comm);
206  }
207 
212  template<class T>
213  std::size_t packSize(const T* data, std::size_t n) const
214  {
215  static_assert(detail::is_pod_v<T>, "Array packing not supported for non-pod data");
216  return detail::Packing<true,T>::packSize(data, n, m_comm);
217  }
218 
224  template<class T>
225  void pack(const T& data,
226  std::vector<char>& buffer,
227  std::size_t& position) const
228  {
229  detail::Packing<detail::is_pod_v<T>,T>::pack(data, buffer, position, m_comm);
230  }
231 
238  template<class T>
239  void pack(const T* data,
240  std::size_t n,
241  std::vector<char>& buffer,
242  std::size_t& position) const
243  {
244  static_assert(detail::is_pod_v<T>, "Array packing not supported for non-pod data");
245  detail::Packing<true,T>::pack(data, n, buffer, position, m_comm);
246  }
247 
253  template<class T>
254  void unpack(T& data,
255  const std::vector<char>& buffer,
256  std::size_t& position) const
257  {
258  detail::Packing<detail::is_pod_v<T>,T>::unpack(data, buffer, position, m_comm);
259  }
260 
267  template<class T>
268  void unpack(T* data,
269  std::size_t n,
270  const std::vector<char>& buffer,
271  std::size_t& position) const
272  {
273  static_assert(detail::is_pod_v<T>, "Array packing not supported for non-pod data");
274  detail::Packing<true,T>::unpack(data, n, buffer, position, m_comm);
275  }
276 
277 private:
278  Parallel::Communication m_comm;
279 };
280 
281 } // end namespace Opm::Mpi
282 
283 #endif // MPI_PACKER_HPP
Abstract struct for packing which is (partially) specialized for specific types.
Definition: MPIPacker.hpp:44
static std::size_t packSize(const T &data, Parallel::MPIComm comm)
Calculates the pack size for a POD.
Definition: MPIPacker.hpp:58
void unpack(T &data, const std::vector< char > &buffer, std::size_t &position) const
Unpack a variable.
Definition: MPIPacker.hpp:254
std::size_t packSize(const T *data, std::size_t n) const
Calculates the pack size for an array.
Definition: MPIPacker.hpp:213
static std::size_t packSize(const T *, std::size_t n, Parallel::MPIComm comm)
Calculates the pack size for an array of POD.
Definition: MPIPacker.hpp:67
static void unpack(T &data, const std::vector< char > &buffer, std::size_t &position, Parallel::MPIComm comm)
Unpack a POD.
Definition: MPIPacker.hpp:114
Packer(Parallel::Communication comm)
Constructor.
Definition: MPIPacker.hpp:195
static void pack(const T *data, std::size_t n, std::vector< char > &buffer, std::size_t &position, Parallel::MPIComm comm)
Pack an array of POD.
Definition: MPIPacker.hpp:97
void pack(const T *data, std::size_t n, std::vector< char > &buffer, std::size_t &position) const
Pack an array.
Definition: MPIPacker.hpp:239
void pack(const T &data, std::vector< char > &buffer, std::size_t &position) const
Pack a variable.
Definition: MPIPacker.hpp:225
std::size_t packSize(const T &data) const
Calculates the pack size for a variable.
Definition: MPIPacker.hpp:203
static void unpack(T *data, std::size_t n, const std::vector< char > &buffer, std::size_t &position, Parallel::MPIComm comm)
Unpack an array of POD.
Definition: MPIPacker.hpp:128
static void pack(const T &data, std::vector< char > &buffer, std::size_t &position, Parallel::MPIComm comm)
Pack a POD.
Definition: MPIPacker.hpp:83
void unpack(T *data, std::size_t n, const std::vector< char > &buffer, std::size_t &position) const
Unpack an array.
Definition: MPIPacker.hpp:268
Struct handling packing of serialization for MPI communication.
Definition: MPIPacker.hpp:191