libMesh
parallel_eigen.h
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 #ifndef LIBMESH_PARALLEL_EIGEN_H
19 #define LIBMESH_PARALLEL_EIGEN_H
20 
21 // libMesh includes
22 #include "libmesh/libmesh_config.h"
23 #include "libmesh/libmesh_common.h"
24 #include "libmesh/int_range.h"
25 
26 // TIMPI includes
27 #include "timpi/packing.h"
28 
29 #ifdef LIBMESH_HAVE_EIGEN
30 
31 // libEigen includes
32 #include <Eigen/Core>
33 
34 namespace libMesh
35 {
36 
37  namespace Parallel
38  {
39  template<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
40  class Packing<Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>
41  {
42  public:
43  typedef unsigned int buffer_type;
44 
45  template <typename Context>
46  static unsigned int packable_size(const Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> &object,
47  const Context *context);
48 
49  template <typename BufferIter>
50  static unsigned int packed_size(BufferIter iter);
51 
52  template <typename OutputIter, typename Context>
53  static void pack(const Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> &object,
54  OutputIter data_out,
55  const Context *context);
56 
57  template <typename BufferIter, typename Context>
58  static Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> unpack(BufferIter in, Context *context);
59 
60  private:
61  template <typename T2>
62  static inline constexpr bool IsFixed = TIMPI::StandardType<T2>::is_fixed_type;
63  static std::size_t BufferCount(std::size_t n) { return (sizeof(Scalar) * n + sizeof(buffer_type) - 1) / sizeof(buffer_type); }
64  };
65 
66 
67 
68  template <typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
69  template <typename Context>
70  unsigned int
71  Packing<Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>::packable_size(const Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> &mtx,
72  const Context * context)
73  {
74  const auto rows = mtx.rows();
75  const auto cols = mtx.cols();
76 
77  // compute packable size of the underlying data
78  std::size_t ints_per_data;
79  if constexpr (IsFixed<Scalar>)
80  {
81  libmesh_ignore(context);
82  ints_per_data = BufferCount(rows * cols);
83  }
84  else
85  {
86  ints_per_data = 0;
87  for (const auto i : make_range(rows * cols))
88  ints_per_data += Packing<Scalar>::packable_size(mtx.data()[i], context);
89  }
90 
91  constexpr std::size_t header_size = (Rows == Eigen::Dynamic) + (Cols == Eigen::Dynamic);
92  return header_size + ints_per_data;
93  }
94 
95  template<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
96  template <typename BufferIter>
97  unsigned int
99  {
100  constexpr std::size_t header_size = (Rows == Eigen::Dynamic) + (Cols == Eigen::Dynamic);
101  const std::size_t rows = Rows == Eigen::Dynamic ? *in++ : Rows;
102  const std::size_t cols = Cols == Eigen::Dynamic ? *in++ : Cols;
103 
104  // compute packable size of the underlying data
105  std::size_t ints_per_data;
106  if constexpr (IsFixed<Scalar>)
107  ints_per_data = BufferCount(rows * cols);
108  else
109  {
110  ints_per_data = 0;
111  for (const auto i : make_range(rows * cols))
112  {
113  ints_per_data += Packing<Scalar>::packed_size(in + ints_per_data);
114  libmesh_ignore(i);
115  }
116  }
117 
118  return header_size + ints_per_data;
119  }
120 
121  template <typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
122  template <typename OutputIter, typename Context>
123  void
124  Packing<Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>::pack(const Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> &mtx,
125  OutputIter data_out,
126  const Context *context)
127  {
128  const auto rows = mtx.rows();
129  const auto cols = mtx.cols();
130 
131  // store dynamic dimensions
132  if constexpr (Rows == Eigen::Dynamic)
133  *data_out++ = rows;
134  if constexpr (Cols == Eigen::Dynamic)
135  *data_out++ = cols;
136 
137  // pack underlying data
138  if constexpr (IsFixed<Scalar>)
139  {
140  libmesh_ignore(context);
141  const auto *raw_data = reinterpret_cast<const buffer_type *>(mtx.data());
142  for (const auto i : make_range(BufferCount(rows * cols)))
143  *data_out++ = (raw_data[i]);
144  }
145  else
146  for (const auto i : make_range(rows * cols))
147  Packing<Scalar>::pack(mtx.data()[i], data_out, context);
148  }
149 
150  template<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
151  template <typename BufferIter, typename Context>
152  Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>
154  {
155  const std::size_t rows = Rows == Eigen::Dynamic ? *in++ : Rows;
156  const std::size_t cols = Cols == Eigen::Dynamic ? *in++ : Cols;
157  auto mtx = Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>(rows, cols);
158 
159  // unpack underlying data
160  if constexpr (IsFixed<Scalar>)
161  {
162  libmesh_ignore(context);
163  auto *raw_data = reinterpret_cast<buffer_type *>(mtx.data());
164  for (const auto i : make_range(BufferCount(rows * cols)))
165  raw_data[i] = *in++;
166  }
167  else
168  for (const auto i : make_range(rows * cols))
169  {
170  // unpack matrix entry and advance iterator
171  mtx.data()[i] = Packing<Scalar>::unpack(in, context);
173  }
174 
175  return mtx;
176  }
177 
178  } // namespace Parallel
179 } // namespace libMesh
180 
181 #endif // LIBMESH_HAVE_EIGEN
182 
183 #endif // LIBMESH_PARALLEL_EIGEN_H
The libMesh namespace provides an interface to certain functionality in the library.
static T unpack(BufferIter in, Context *ctx)
Definition: parallel_elem.h:90
static unsigned int packable_size(const T &object, const Context *context)
void libmesh_ignore(const Args &...)
static unsigned int packed_size(BufferIter iter)
static void pack(const T &object, OutputIter data_out, const Context *context)
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:140