LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
mesh_function_unary.h
1
9#ifndef __b9b63bcccec548419a52fe0b06ffb3fc
10#define __b9b63bcccec548419a52fe0b06ffb3fc
11
12#include <lf/mesh/mesh.h>
13
14namespace lf::mesh::utils {
15
38template <class OP, class MF>
40 public:
41 MeshFunctionUnary(OP op, MF mf) : op_(std::move(op)), mf_(std::move(mf)) {}
42
43 auto operator()(const mesh::Entity& e, const Eigen::MatrixXd& local) const {
44 return op_(mf_(e, local), 0);
45 }
46
47 private:
48 OP op_;
49 MF mf_;
50};
51
52namespace internal {
53struct UnaryOpMinus {
54 // minus in front of a scalar type
55 template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
56 auto operator()(const std::vector<U>& u, int /*unused*/) const {
57 Eigen::Map<const Eigen::Matrix<U, 1, Eigen::Dynamic>> um(&u[0], 1,
58 u.size());
59 std::vector<U> result(u.size());
60 Eigen::Map<Eigen::Matrix<U, 1, Eigen::Dynamic>> rm(&result[0], 1, u.size());
61 rm = -um;
62 return result;
63 }
64
65 // minus in front of a Eigen::Matrix
66 template <class S, int R, int C, int O, int MR, int MC>
67 auto operator()(const std::vector<Eigen::Matrix<S, R, C, O, MR, MC>>& u,
68 int /*unused*/) const {
69 if constexpr (R == 0 || C == 0) { // NOLINT
70 // result vector is empty
71 return u;
72 }
73 if constexpr (R != Eigen::Dynamic && C != Eigen::Dynamic) {
74 // matrix size is known at compile time
75 Eigen::Map<const Eigen::Matrix<S, 1, Eigen::Dynamic>> um(
76 &u[0](0, 0), 1, u.size() * R * C);
77 std::vector<Eigen::Matrix<S, R, C, O, MR, MC>> result(u.size());
78 Eigen::Map<Eigen::Matrix<S, 1, Eigen::Dynamic>> rm(&result[0](0, 0), 1,
79 u.size() * R * C);
80 rm = -um;
81 return result;
82 } else {
83 // matrix size is dynamic
84 std::vector<Eigen::Matrix<S, R, C, O, MR, MC>> result(u.size());
85 for (int i = 0; i < u.size(); ++i) {
86 result[i] = -u[i];
87 }
88 return result;
89 }
90 }
91
92 // minus in front of a Eigen::Array
93 template <class S, int R, int C, int O, int MR, int MC>
94 auto operator()(const std::vector<Eigen::Array<S, R, C, O, MR, MC>>& u,
95 int /*unused*/) const {
96 if constexpr (R == 0 || C == 0) {
97 // result array is empty
98 return u;
99 }
100 if constexpr (R != Eigen::Dynamic && C != Eigen::Dynamic) {
101 // array size is known at compile time
102 Eigen::Map<const Eigen::Array<S, 1, Eigen::Dynamic>> um(&u[0](0, 0), 1,
103 u.size() * R * C);
104 std::vector<Eigen::Array<S, R, C, O, MR, MC>> result(u.size());
105 Eigen::Map<Eigen::Array<S, 1, Eigen::Dynamic>> rm(&result[0](0, 0), 1,
106 u.size() * R * C);
107 rm = -um;
108 return result;
109 } else {
110 // array size is dynamic
111 std::vector<Eigen::Array<S, R, C, O, MR, MC>> result(u.size());
112 for (int i = 0; i < u.size(); ++i) {
113 result[i] = -u[i];
114 }
115 return result;
116 }
117 }
118
119 // minus in front of any object that supports the unary operator-
120 template <class T>
121 auto operator()(const std::vector<T>& u, long /*unused*/) const {
122 std::vector<T> result(u.size());
123 for (int i = 0; i < u.size(); ++i) {
124 result[i] = -u[i];
125 }
126 return result;
127 }
128};
129
130struct UnaryOpSquaredNorm {
131 // squared norm of a scalar type
132 template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
133 auto operator()(const std::vector<U>& u, int /*unused*/) const {
134 Eigen::Map<const Eigen::Matrix<U, 1, Eigen::Dynamic>> um(&u[0], 1,
135 u.size());
136 std::vector<U> result(u.size());
137 Eigen::Map<Eigen::Matrix<U, 1, Eigen::Dynamic>> rm(&result[0], 1, u.size());
138 rm = um.cwiseAbs2();
139 return result;
140 }
141
142 // squared norm of a eigen matrix
143 template <class S, int R, int C, int O, int MR, int MC>
144 auto operator()(const std::vector<Eigen::Matrix<S, R, C, O, MR, MC>>& u,
145 int /*unused*/) const {
146 std::vector<double> result(u.size());
147 if constexpr (R != Eigen::Dynamic && C != Eigen::Dynamic) { // NOLINT
148 static_assert(
149 R > 0 && C > 0,
150 "squaredNorm only supported for matrices with at least 1 row "
151 "and column");
152 if constexpr (C == 1) { // NOLINT
153 Eigen::Map<const Eigen::Matrix<S, R, Eigen::Dynamic>> um(&u[0](0, 0), R,
154 u.size());
155 Eigen::Map<Eigen::Matrix<S, 1, Eigen::Dynamic>> rm(&result[0], 1,
156 u.size());
157 rm = um.cwiseAbs2().colwise().sum();
158 } else if constexpr (R == 1) { // NOLINT
159 Eigen::Map<const Eigen::Matrix<S, Eigen::Dynamic, C, Eigen::RowMajor>>
160 um(&u[0](0, 0), u.size(), C);
161 Eigen::Map<Eigen::Matrix<S, Eigen::Dynamic, 1>> rm(&result[0], u.size(),
162 1);
163 rm = um.cwiseAbs2().rowwise().sum();
164 }
165 } else { // NOLINT
166 for (std::size_t i = 0; i < u.size(); ++i) {
167 result[i] = u[i].squaredNorm();
168 }
169 }
170 return result;
171 }
172};
173
174struct UnaryOpTranspose {
175 // transpose the eigen matrix
176 template <class S, int R, int C, int O, int MR, int MC>
177 auto operator()(const std::vector<Eigen::Matrix<S, R, C, O, MR, MC>>& u,
178 int /*unused*/) const {
179 std::vector<Eigen::Matrix<S, C, R>> result(u.size());
180 for (std::size_t i = 0; i < u.size(); ++i) {
181 result[i] = u[i].transpose();
182 }
183 return result;
184 }
185
186 // transpose the eigen array
187 template <class S, int R, int C, int O, int MR, int MC>
188 auto operator()(const std::vector<Eigen::Array<S, R, C, O, MR, MC>>& u,
189 int /*unused*/) const {
190 std::vector<Eigen::Array<S, C, R>> result(u.size());
191 for (std::size_t i = 0; i < u.size(); ++i) {
192 result[i] = u[i].transpose();
193 }
194 return result;
195 }
196};
197
198struct UnaryOpAdjoint {
199 // adjoint of eigen matrix
200 template <class S, int R, int C, int O, int MR, int MC>
201 auto operator()(const std::vector<Eigen::Matrix<S, R, C, O, MR, MC>>& u,
202 int /*unused*/) const {
203 std::vector<Eigen::Matrix<S, C, R>> result(u.size());
204 for (std::size_t i = 0; i < u.size(); ++i) {
205 result[i] = u[i].adjoint();
206 }
207 return result;
208 }
209};
210
211struct UnaryOpConjugate {
212 // conjugate of scalar type
213 template <class U, class = std::enable_if_t<base::is_scalar<U>>>
214 auto operator()(const std::vector<U>& u, int /*unused*/) const {
215 Eigen::Map<const Eigen::Matrix<U, 1, Eigen::Dynamic>> um(&u[0], 1,
216 u.size());
217 std::vector<U> result(u.size());
218 Eigen::Map<Eigen::Matrix<U, 1, Eigen::Dynamic>> rm(&result[0], 1, u.size());
219 rm = um.conjugate();
220 return result;
221 }
222
223 // conjugate of eigen matrix
224 template <class S, int R, int C, int O, int MR, int MC>
225 auto operator()(const std::vector<Eigen::Matrix<S, R, C, O, MR, MC>>& u,
226 int /*unused*/) const {
227 std::vector<Eigen::Matrix<S, R, C>> result(u.size());
228 for (std::size_t i = 0; i < u.size(); ++i) {
229 result[i] = u[i].conjugate();
230 }
231 return result;
232 }
233
234 // conjugate of eigen array
235 template <class S, int R, int C, int O, int MR, int MC>
236 auto operator()(const std::vector<Eigen::Array<S, R, C, O, MR, MC>>& u,
237 int /*unused*/) const {
238 std::vector<Eigen::Array<S, R, C>> result(u.size());
239 for (std::size_t i = 0; i < u.size(); ++i) {
240 result[i] = u[i].conjugate();
241 }
242 return result;
243 }
244};
245
246} // namespace internal
247
259template <class A, class = std::enable_if_t<isMeshFunction<A>>>
260auto operator-(const A& a) {
261 return MeshFunctionUnary(internal::UnaryOpMinus{}, a);
262}
263
274template <class A, class = std::enable_if_t<isMeshFunction<A>>>
275auto squaredNorm(const A& a) {
276 return MeshFunctionUnary(internal::UnaryOpSquaredNorm{}, a);
277}
278
286template <class A, class = std::enable_if_t<isMeshFunction<A>>>
287auto transpose(const A& a) {
288 static_assert(base::is_eigen_matrix<MeshFunctionReturnType<A>> ||
289 base::is_eigen_array<MeshFunctionReturnType<A>>,
290 "transpose() only supported for Eigen::Matrix and Eigen::Array "
291 "valued mesh functions");
292 return MeshFunctionUnary(internal::UnaryOpTranspose{}, a);
293}
294
303template <class A, class = std::enable_if_t<isMeshFunction<A>>>
304auto adjoint(const A& a) {
305 using returnType_t = MeshFunctionReturnType<A>;
306 static_assert(base::is_eigen_matrix<returnType_t>,
307 "adjoint only supported for Eigen::Matrix valued mesh "
308 "functions.");
309 return MeshFunctionUnary(internal::UnaryOpAdjoint{}, a);
310}
311
320template <class A, class = std::enable_if_t<isMeshFunction<A>>>
321auto conjugate(const A& a) {
322 using returnType_t = MeshFunctionReturnType<A>;
323 static_assert(
324 base::is_eigen_matrix<returnType_t> ||
325 base::is_eigen_array<returnType_t> || base::is_scalar<returnType_t>,
326 "conjugate() supports only Eigen::Matrix, Eigen::Array or Scalar valued "
327 "mesh functions.");
328 return MeshFunctionUnary(internal::UnaryOpConjugate{}, a);
329}
330
331} // namespace lf::mesh::utils
332
333#endif // __b9b63bcccec548419a52fe0b06ffb3fc
Interface class representing a topological entity in a cellular complex
Definition: entity.h:39
A mesh function representing another mesh function under a pointwise, unary operation.
auto operator()(const mesh::Entity &e, const Eigen::MatrixXd &local) const
auto adjoint(const A &a)
Pointwise adjoint of an Eigen::Matrix, i.e. the conjugate transposed of the matrix.
auto squaredNorm(const A &a)
Pointwise squared norm of another mesh function.
auto transpose(const A &a)
Pointwise transpose of an Eigen::Matrix or Eigen::Array
auto conjugate(const A &a)
Pointwise conjuagte of an Eigen::Matrix, Eigen::Array or scalar valued mesh function.
auto operator-(const A &a)
Applies the unary minus operator to a mesh function.
Contains helper functions and classes that all operate on the interface classes defined in lf::mesh.
internal::VectorElement_t< internal::MeshFunctionReturnType_t< R > > MeshFunctionReturnType
Determine the type of objects returned by a MeshFunction.