mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
to limit the overload party, we put packing details for specific types in separate structs. emit compiler error if unsupported type is given, better to detect this on compile time rather than runtime
267 lines
8.9 KiB
C++
267 lines
8.9 KiB
C++
/*
|
|
Copyright 2019 Equinor AS.
|
|
|
|
This file is part of the Open Porous Media project (OPM).
|
|
|
|
OPM is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
OPM is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#ifndef MPI_SERIALIZER_HPP
|
|
#define MPI_SERIALIZER_HPP
|
|
|
|
#include <opm/common/utility/TimeService.hpp>
|
|
#include <opm/simulators/utils/ParallelCommunication.hpp>
|
|
|
|
#include <dune/common/parallel/mpitraits.hh>
|
|
|
|
#include <bitset>
|
|
#include <cstddef>
|
|
#include <string>
|
|
|
|
namespace Opm {
|
|
namespace Mpi {
|
|
namespace detail {
|
|
|
|
//! \brief Abstract struct for packing which is (partially) specialized for specific types.
|
|
template <bool pod, class T>
|
|
struct Packing
|
|
{
|
|
static std::size_t packSize(const T&, Parallel::MPIComm);
|
|
static void pack(const T&, std::vector<char>&, int&, Parallel::MPIComm);
|
|
static void unpack(T&, std::vector<char>&, int&, Parallel::MPIComm);
|
|
};
|
|
|
|
//! \brief Packaging for pod data.
|
|
template<class T>
|
|
struct Packing<true,T>
|
|
{
|
|
//! \brief Calculates the pack size for a POD.
|
|
//! \param data The data to pack
|
|
//! \param comm The communicator to use
|
|
static std::size_t packSize(const T& data, Parallel::MPIComm comm)
|
|
{
|
|
return packSize(&data, 1, comm);
|
|
}
|
|
|
|
//! \brief Calculates the pack size for an array of POD.
|
|
//! \param data The array to pack
|
|
//! \param n Length of array
|
|
//! \param comm The communicator to use
|
|
static std::size_t packSize(const T*, std::size_t n, Parallel::MPIComm comm)
|
|
{
|
|
int size = 0;
|
|
MPI_Pack_size(n, Dune::MPITraits<T>::getType(), comm, &size);
|
|
return size;
|
|
}
|
|
|
|
//! \brief Pack a POD.
|
|
//! \param data The variable to pack
|
|
//! \param buffer Buffer to pack into
|
|
//! \param position Position in buffer to use
|
|
//! \param comm The communicator to use
|
|
static void pack(const T& data,
|
|
std::vector<char>& buffer,
|
|
int& position,
|
|
Parallel::MPIComm comm)
|
|
{
|
|
pack(&data, 1, buffer, position, comm);
|
|
}
|
|
|
|
//! \brief Pack an array of POD.
|
|
//! \param data The array to pack
|
|
//! \param n Length of array
|
|
//! \param buffer Buffer to pack into
|
|
//! \param position Position in buffer to use
|
|
//! \param comm The communicator to use
|
|
static void pack(const T* data,
|
|
std::size_t n,
|
|
std::vector<char>& buffer,
|
|
int& position,
|
|
Parallel::MPIComm comm)
|
|
{
|
|
MPI_Pack(data, n, Dune::MPITraits<T>::getType(), buffer.data(),
|
|
buffer.size(), &position, comm);
|
|
}
|
|
|
|
//! \brief Unpack a POD.
|
|
//! \param data The variable to unpack
|
|
//! \param buffer Buffer to unpack from
|
|
//! \param position Position in buffer to use
|
|
//! \param comm The communicator to use
|
|
static void unpack(T& data,
|
|
std::vector<char>& buffer,
|
|
int& position,
|
|
Parallel::MPIComm comm)
|
|
{
|
|
unpack(&data, 1, buffer, position, comm);
|
|
}
|
|
|
|
//! \brief Unpack an array of POD.
|
|
//! \param data The array to unpack
|
|
//! \param n Length of array
|
|
//! \param buffer Buffer to unpack from
|
|
//! \param position Position in buffer to use
|
|
//! \param comm The communicator to use
|
|
static void unpack(T* data,
|
|
std::size_t n,
|
|
std::vector<char>& buffer,
|
|
int& position,
|
|
Parallel::MPIComm comm)
|
|
{
|
|
MPI_Unpack(buffer.data(), buffer.size(), &position, data, n,
|
|
Dune::MPITraits<T>::getType(), comm);
|
|
}
|
|
};
|
|
|
|
//! \brief Default handling for unsupported types.
|
|
template<class T>
|
|
struct Packing<false,T>
|
|
{
|
|
static std::size_t packSize(const T&, Parallel::MPIComm)
|
|
{
|
|
static_assert(!std::is_same_v<T,T>, "Packing not supported for type");
|
|
return 0;
|
|
}
|
|
|
|
static void pack(const T&, std::vector<char>&, int&,
|
|
Parallel::MPIComm)
|
|
{
|
|
static_assert(!std::is_same_v<T,T>, "Packing not supported for type");
|
|
}
|
|
|
|
static void unpack(T&, std::vector<char>&, int&,
|
|
Parallel::MPIComm)
|
|
{
|
|
static_assert(!std::is_same_v<T,T>, "Packing not supported for type");
|
|
}
|
|
};
|
|
|
|
//! \brief Specialization for std::bitset
|
|
template <std::size_t Size>
|
|
struct Packing<false,std::bitset<Size>>
|
|
{
|
|
static std::size_t packSize(const std::bitset<Size>&, Opm::Parallel::MPIComm);
|
|
static void pack(const std::bitset<Size>&, std::vector<char>&, int&, Opm::Parallel::MPIComm);
|
|
static void unpack(std::bitset<Size>&, std::vector<char>&, int&, Opm::Parallel::MPIComm);
|
|
};
|
|
|
|
#define ADD_PACK_SPECIALIZATION(T) \
|
|
template<> \
|
|
struct Packing<false,T> \
|
|
{ \
|
|
static std::size_t packSize(const T&, Parallel::MPIComm); \
|
|
static void pack(const T&, std::vector<char>&, int&, Parallel::MPIComm); \
|
|
static void unpack(T&, std::vector<char>&, int&, Parallel::MPIComm); \
|
|
};
|
|
|
|
ADD_PACK_SPECIALIZATION(std::string)
|
|
ADD_PACK_SPECIALIZATION(time_point)
|
|
|
|
}
|
|
|
|
//! \brief Struct handling packing of serialization for MPI communication.
|
|
struct Packer {
|
|
//! \brief Calculates the pack size for a variable.
|
|
//! \tparam T The type of the data to be packed
|
|
//! \param data The data to pack
|
|
//! \param comm The communicator to use
|
|
template<class T>
|
|
static std::size_t packSize(const T& data, Parallel::MPIComm comm)
|
|
{
|
|
return detail::Packing<std::is_pod_v<T>,T>::packSize(data,comm);
|
|
}
|
|
|
|
//! \brief Calculates the pack size for an array.
|
|
//! \tparam T The type of the data to be packed
|
|
//! \param data The array to pack
|
|
//! \param n Length of array
|
|
//! \param comm The communicator to use
|
|
template<class T>
|
|
static std::size_t packSize(const T* data, std::size_t n, Parallel::MPIComm comm)
|
|
{
|
|
static_assert(std::is_pod_v<T>, "Array packing not supported for non-pod data");
|
|
return detail::Packing<true,T>::packSize(data,n,comm);
|
|
}
|
|
|
|
//! \brief Pack a variable.
|
|
//! \tparam T The type of the data to be packed
|
|
//! \param data The variable to pack
|
|
//! \param buffer Buffer to pack into
|
|
//! \param position Position in buffer to use
|
|
//! \param comm The communicator to use
|
|
template<class T>
|
|
static void pack(const T& data,
|
|
std::vector<char>& buffer,
|
|
int& position,
|
|
Parallel::MPIComm comm)
|
|
{
|
|
detail::Packing<std::is_pod_v<T>,T>::pack(data, buffer, position, comm);
|
|
}
|
|
|
|
//! \brief Pack an array.
|
|
//! \tparam T The type of the data to be packed
|
|
//! \param data The array to pack
|
|
//! \param n Length of array
|
|
//! \param buffer Buffer to pack into
|
|
//! \param position Position in buffer to use
|
|
//! \param comm The communicator to use
|
|
template<class T>
|
|
static void pack(const T* data,
|
|
std::size_t n,
|
|
std::vector<char>& buffer,
|
|
int& position,
|
|
Parallel::MPIComm comm)
|
|
{
|
|
static_assert(std::is_pod_v<T>, "Array packing not supported for non-pod data");
|
|
detail::Packing<true,T>::pack(data, n, buffer, position, comm);
|
|
}
|
|
|
|
//! \brief Unpack a variable.
|
|
//! \tparam T The type of the data to be unpacked
|
|
//! \param data The variable to unpack
|
|
//! \param buffer Buffer to unpack from
|
|
//! \param position Position in buffer to use
|
|
//! \param comm The communicator to use
|
|
template<class T>
|
|
static void unpack(T& data,
|
|
std::vector<char>& buffer,
|
|
int& position,
|
|
Parallel::MPIComm comm)
|
|
{
|
|
detail::Packing<std::is_pod_v<T>,T>::unpack(data, buffer, position, comm);
|
|
}
|
|
|
|
//! \brief Unpack an array.
|
|
//! \tparam T The type of the data to be unpacked
|
|
//! \param data The array to unpack
|
|
//! \param n Length of array
|
|
//! \param buffer Buffer to unpack from
|
|
//! \param position Position in buffer to use
|
|
//! \param comm The communicator to use
|
|
template<class T>
|
|
static void unpack(T* data,
|
|
std::size_t n,
|
|
std::vector<char>& buffer,
|
|
int& position,
|
|
Parallel::MPIComm comm)
|
|
{
|
|
static_assert(std::is_pod_v<T>, "Array packing not supported for non-pod data");
|
|
detail::Packing<true,T>::unpack(data, n, buffer, position, comm);
|
|
}
|
|
};
|
|
|
|
} // end namespace Mpi
|
|
} // end namespace Opm
|
|
|
|
#endif // MPI_SERIALIZER_HPP
|