25#include <boost/mpi/collectives/gather.hpp>
26#include <boost/mpi/collectives/scatter.hpp>
27#include <boost/mpi/communicator.hpp>
28#include <boost/multi_array.hpp>
29#include <boost/serialization/vector.hpp>
44template <
class>
struct is_optional_type :
public std::false_type {};
46struct is_optional_type<std::optional<T>> :
public std::true_type {};
48template <
class ArrayView,
typename T>
49void unflatten_grid(ArrayView &view, std::vector<T>
const &values) {
50 using array_type = boost::multi_array<T, 4>;
51 auto it = values.begin();
52 auto const dim_i =
static_cast<typename array_type::index
>(view.shape()[0]);
53 auto const dim_j =
static_cast<typename array_type::index
>(view.shape()[1]);
54 auto const dim_k =
static_cast<typename array_type::index
>(view.shape()[2]);
55 auto const dim_t =
static_cast<typename array_type::index
>(view.shape()[3]);
56 for (
typename array_type::index i = 0; i != dim_i; ++i) {
57 for (
typename array_type::index j = 0; j != dim_j; ++j) {
58 for (
typename array_type::index k = 0; k != dim_k; ++k) {
59 for (
typename array_type::index t = 0; t != dim_t; ++t) {
60 view[i][j][k][t] = *it;
68template <
class FieldSerializer,
class ArrayView,
typename T>
69void flatten_grid(ArrayView
const &view, std::vector<T> &out,
70 double units_conversion) {
71 using array_type = boost::multi_array<T, 4>;
72 out.reserve(view.num_elements());
73 auto const dim_i =
static_cast<typename array_type::index
>(view.shape()[0]);
74 auto const dim_j =
static_cast<typename array_type::index
>(view.shape()[1]);
75 auto const dim_k =
static_cast<typename array_type::index
>(view.shape()[2]);
76 auto const dim_t =
static_cast<typename array_type::index
>(view.shape()[3]);
77 for (
typename array_type::index i = 0; i != dim_i; ++i) {
78 for (
typename array_type::index j = 0; j != dim_j; ++j) {
79 for (
typename array_type::index k = 0; k != dim_k; ++k) {
80 for (
typename array_type::index t = 0; t != dim_t; ++t) {
81 if constexpr (std::is_floating_point_v<T>) {
82 out.emplace_back(view[i][j][k][t] * units_conversion);
83 }
else if constexpr (is_optional_type<T>{}) {
84 if (view[i][j][k][t]) {
85 out.emplace_back(*(view[i][j][k][t]) * units_conversion);
87 out.emplace_back(std::nullopt);
90 out.emplace_back(view[i][j][k][t]);
103 std::vector<Utils::Vector3i> nodes_lower_corners;
104 std::vector<Utils::Vector3i> nodes_upper_corners;
105 boost::mpi::gather(comm, local_lower_corner, nodes_lower_corners, 0);
106 boost::mpi::gather(comm, local_upper_corner, nodes_upper_corners, 0);
107 return std::make_tuple(nodes_lower_corners, nodes_upper_corners);
110template <
class FieldSerializer>
111template <
class LatticeModel,
typename T>
116 Utils::Vector3i const &) const,
117 double units_conversion) const {
118 auto const &comm = context()->get_comm();
119 auto const [slice_lower_corner, slice_upper_corner, local_lower_corner,
120 local_upper_corner] = get_slices_bounding_boxes();
121 auto const [nodes_lower_corners, nodes_upper_corners] =
123 auto const data_size = std::accumulate(data_dims.cbegin(), data_dims.cend(),
124 1, std::multiplies<>());
125 auto const local_values =
126 (lattice_model.*getter)(local_lower_corner, local_upper_corner);
127 std::vector<std::vector<T>> nodes_values;
128 boost::mpi::gather(comm, local_values, nodes_values, 0);
129 if (comm.rank() == 0) {
130 auto const dims = slice_upper_corner - slice_lower_corner;
131 using index_range = boost::multi_array_types::index_range;
132 using array_type = boost::multi_array<T, 4>;
133 array_type array(boost::extents[dims[0]][dims[1]][dims[2]][data_size]);
135 for (std::size_t rank = 0; rank < nodes_values.size(); ++rank) {
136 if (nodes_values[rank].empty()) {
139 auto const range_lower_corner =
140 nodes_lower_corners[rank] - slice_lower_corner;
141 auto const range_upper_corner =
142 nodes_upper_corners[rank] - slice_lower_corner;
143 auto const local_range = [&](
int j) {
144 return index_range(range_lower_corner[j], range_upper_corner[j]);
146 typename array_type::template array_view<4>::type view =
147 array[boost::indices[local_range(0)][local_range(1)][local_range(2)]
149 detail::unflatten_grid(view, nodes_values[rank]);
153 detail::flatten_grid<FieldSerializer>(array, out, units_conversion);
154 std::vector<int> shape = {m_shape.begin(), m_shape.end()};
155 if (data_dims.size() != 1ul or data_dims[0] != 1) {
156 shape.insert(shape.end(), data_dims.begin(), data_dims.end());
158 auto const variant = FieldSerializer::serialize(out);
159 return {std::vector<Variant>{{variant,
Variant{shape}}}};
164template <
class FieldSerializer>
165template <
class LatticeModel,
typename T>
170 Utils::Vector3i const &,
171 std::vector<T> const &),
172 double units_conversion) {
174 auto const [slice_lower_corner, slice_upper_corner, local_lower_corner,
175 local_upper_corner] = get_slices_bounding_boxes();
176 auto const [nodes_lower_corners, nodes_upper_corners] =
178 auto const data_size = std::accumulate(data_dims.cbegin(), data_dims.cend(),
179 1, std::multiplies<>());
180 auto const sentinel = get_sentinel_index(lattice_model.get_lattice());
181 std::vector<std::vector<T>> nodes_values(comm.size());
182 if (comm.rank() == 0) {
184 FieldSerializer::template deserialize<T>(
params.at(
"values"));
185 auto const dims = slice_upper_corner - slice_lower_corner;
186 using index_range = boost::multi_array_types::index_range;
187 using array_type = boost::multi_array<T, 4>;
188 array_type array(boost::extents[dims[0]][dims[1]][dims[2]][data_size]);
190 detail::unflatten_grid(array, values);
192 for (std::size_t rank = 0; rank < nodes_lower_corners.size(); ++rank) {
193 auto const range_lower = nodes_lower_corners[rank] - slice_lower_corner;
194 auto const range_upper = nodes_upper_corners[rank] - slice_lower_corner;
198 auto const local_range = [&](
int j) {
199 return index_range(range_lower[j], range_upper[j]);
201 typename array_type::template array_view<4>::type view =
202 array[boost::indices[local_range(0)][local_range(1)][local_range(2)]
204 detail::flatten_grid<FieldSerializer>(view, nodes_values[rank],
208 std::vector<T> local_values;
209 boost::mpi::scatter(comm, nodes_values, local_values, 0);
210 (lattice_model.*setter)(local_lower_corner, local_upper_corner, local_values);
211 lattice_model.ghost_communication();
Vector implementation and trait types for boost qvm interoperability.
virtual boost::mpi::communicator const & get_comm() const =0
Context * context() const
Responsible context.
Variant gather_3d(VariantMap const ¶ms, std::vector< int > const &data_dims, LatticeModel const &lattice_model, std::vector< T >(LatticeModel::*getter)(Utils::Vector3i const &, Utils::Vector3i const &) const, double units_conversion=1.) const
static DEVICE_QUALIFIER constexpr Vector< T, N > broadcast(typename Base::value_type const &value)
Create a vector that has all entries set to the same value.
auto gather_slices_topology(boost::mpi::communicator const &comm, Utils::Vector3i const &local_lower_corner, Utils::Vector3i const &local_upper_corner)
std::unordered_map< std::string, Variant > VariantMap
boost::make_recursive_variant< None, bool, int, std::size_t, double, std::string, ObjectRef, Utils::Vector3b, Utils::Vector3i, Utils::Vector2d, Utils::Vector3d, Utils::Vector4d, std::vector< int >, std::vector< double >, std::vector< boost::recursive_variant_ >, std::unordered_map< int, boost::recursive_variant_ >, std::unordered_map< std::string, boost::recursive_variant_ > >::type Variant
Possible types for parameters.
static SteepestDescentParameters params
Currently active steepest descent instance.