LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
fe_tools.h
1#ifndef LF_FETOOLS_H
2#define LF_FETOOLS_H
3/***************************************************************************
4 * LehrFEM++ - A simple C++ finite element libray for teaching
5 * Developed from 2018 at the Seminar of Applied Mathematics of ETH Zurich,
6 * lead developers Dr. R. Casagrande and Prof. R. Hiptmair
7 ***************************************************************************/
8
18#include <lf/assemble/assemble.h>
19#include <lf/mesh/utils/utils.h>
20#include <lf/quad/quad.h>
21
22#include "scalar_fe_space.h"
23
24namespace lf::fe {
25
26static const unsigned int kout_l2_qr = 1;
27static const unsigned int kout_l2_rsfvals = 2;
28
29namespace internal {
30
31// TODO(raffael) convert this method into a lambda function of
32// IntegrateMeshFunction() once
33// https://developercommunity.visualstudio.com/content/problem/200017/if-constexpr-in-lambda.html
34// is resolved.
35template <class MF, class QR_SELECTOR>
36auto LocalIntegral(const mesh::Entity &e, const QR_SELECTOR &qr_selector,
39 auto qr = qr_selector(e);
40 auto values = mf(e, qr.Points());
41 auto weights_ie =
42 (qr.Weights().cwiseProduct(e.Geometry()->IntegrationElement(qr.Points())))
43 .eval();
44 LF_ASSERT_MSG(values.size() == qr.NumPoints(),
45 "mf returns vector with wrong size.");
46 if constexpr (std::is_arithmetic_v<MfType>) { // NOLINT
47 auto value_m = Eigen::Map<Eigen::Matrix<MfType, 1, Eigen::Dynamic>>(
48 &values[0], 1, values.size());
49 return (value_m * weights_ie)(0);
50 }
51
52 if constexpr (base::is_eigen_matrix<MfType>) { // NOLINT
53 constexpr int size = MfType::SizeAtCompileTime;
54 if constexpr (size != Eigen::Dynamic) {
55 auto value_m = Eigen::Map<
56 Eigen::Matrix<typename MfType::Scalar, size, Eigen::Dynamic>>(
57 &values[0](0, 0), size, values.size());
58 MfType result;
59 auto result_m =
60 Eigen::Map<Eigen::Matrix<typename MfType::Scalar, size, 1>>(
61 &result(0, 0));
62 result_m = value_m * weights_ie;
63 return result;
64 }
65 }
66 // fallback: we cannot make any optimizations:
67 MfType temp = weights_ie(0) * values[0];
68 for (Eigen::Index i = 1; i < qr.NumPoints(); ++i) {
69 temp = temp + weights_ie(i) * values[i];
70 }
71 return temp;
72}
73}; // namespace internal
74
107template <class MF, class QR_SELECTOR,
108 class ENTITY_PREDICATE = base::PredicateTrue,
109 class = std::enable_if_t<
110 std::is_invocable_v<QR_SELECTOR, const mesh::Entity &>>>
111auto IntegrateMeshFunction(const lf::mesh::Mesh &mesh, const MF &mf,
112 const QR_SELECTOR &qr_selector,
113 const ENTITY_PREDICATE &ep = base::PredicateTrue{},
114 int codim = 0)
116 static_assert(mesh::utils::isMeshFunction<MF>);
118
119 auto entities = mesh.Entities(codim);
120 auto result = internal::LocalIntegral(**entities.begin(), qr_selector, mf);
121 for (const auto *i = entities.begin() + 1; i != entities.end(); ++i) {
122 if (!ep(**i)) {
123 continue;
124 }
125 result = result + internal::LocalIntegral(**i, qr_selector, mf);
126 }
127 return result;
128}
129
156template <class MF, class ENTITY_PREDICATE = base::PredicateTrue>
157auto IntegrateMeshFunction(const lf::mesh::Mesh &mesh, const MF &mf,
158 int quad_degree,
159 const ENTITY_PREDICATE &ep = base::PredicateTrue{},
160 int codim = 0) {
161 std::array<quad::QuadRule, 5> qrs;
162 for (auto ref_el :
164 qrs[ref_el.Id()] = quad::make_QuadRule(ref_el, quad_degree);
165 }
167 mesh, mf, [&](const mesh::Entity &e) { return qrs[e.RefEl().Id()]; }, ep,
168 codim);
169}
170
171// ******************************************************************************
172
198template <typename SCALAR, typename MF, typename SELECTOR = base::PredicateTrue>
200 SELECTOR &&pred = base::PredicateTrue{}) {
201 static_assert(mesh::utils::isMeshFunction<std::remove_reference_t<MF>>);
202 // choose scalar type so it can hold the scalar type of u as well as
203 // SCALAR
204 using scalarMF_t =
206 using scalar_t = decltype(SCALAR(0) * scalarMF_t(0));
207 // Return type, type for FE coefficient vector
208 using dof_vec_t = Eigen::Matrix<scalar_t, Eigen::Dynamic, 1>;
209
210 // Underlying mesh instance
211 const lf::mesh::Mesh &mesh{*fe_space.Mesh()};
212 // Fetch local-to-global index mapping for shape functions
213 const lf::assemble::DofHandler &dofh{fe_space.LocGlobMap()};
214
215 // Vector for returning expansion coefficients
216 dof_vec_t glob_dofvec(dofh.NumDofs());
217 glob_dofvec.setZero();
218
219 // Loop over all cells
220 for (const lf::mesh::Entity *cell : mesh.Entities(0)) {
221 if (!pred(*cell)) {
222 continue;
223 }
224 // Topological type of the cell
225 const lf::base::RefEl ref_el{cell->RefEl()};
226
227 // Information about local shape functions on reference element
228 auto ref_shape_fns = fe_space.ShapeFunctionLayout(*cell);
229 LF_ASSERT_MSG(ref_shape_fns, "reference shape function for "
230 << ref_el << " not available.");
231 // Obtain reference coordinates for evaluation nodes
232 const Eigen::MatrixXd ref_nodes(ref_shape_fns->EvaluationNodes());
233
234 // Collect values of function to be projected in a row vector
235 auto uvalvec = u(*cell, ref_nodes);
236
237 // Compute the resulting local degrees of freedom
238 auto dofvec(ref_shape_fns->NodalValuesToDofs(
239 Eigen::Map<Eigen::Matrix<scalar_t, 1, Eigen::Dynamic>>(
240 &uvalvec[0], 1, uvalvec.size())));
241
242 // Set the corresponing global degrees of freedom
243 // Note: "Setting", not "adding to"
244 // Number of local shape functions
245 const size_type num_loc_dofs = dofh.NumLocalDofs(*cell);
246 LF_ASSERT_MSG(
247 dofvec.size() == num_loc_dofs,
248 "Size mismatch: " << dofvec.size() << " <-> " << num_loc_dofs);
249 // Fetch global numbers of local shape functions
251 dofh.GlobalDofIndices(*cell));
252 // Insert dof values into the global coefficient vector
253 for (int j = 0; j < num_loc_dofs; ++j) {
254 glob_dofvec[ldof_gidx[j]] = dofvec[j];
255 }
256 }
257 return glob_dofvec;
258}
259
300template <typename SCALAR, typename EDGESELECTOR, typename FUNCTION>
301std::vector<std::pair<bool, SCALAR>> InitEssentialConditionFromFunction(
302 const lf::fe::ScalarFESpace<SCALAR> &fes, EDGESELECTOR &&esscondflag,
303 FUNCTION &&g) {
304 static_assert(mesh::utils::isMeshFunction<std::remove_reference_t<FUNCTION>>);
305 // static_assert(isMeshFunction<FUNCTION>, "g must by a MeshFunction object");
306
307 // *** I: Preprocessing ***
308
309 // Underlying mesh
310 const lf::mesh::Mesh &mesh{*fes.Mesh()};
311
312 // Vector for returning flags and fixed values for dofs
313 const size_type num_coeffs = fes.LocGlobMap().NumDofs();
314 std::vector<std::pair<bool, SCALAR>> flag_val_vec(num_coeffs,
315 {false, SCALAR{}});
316
317 // *** II: Local computations ****
318 // Visit all edges of the mesh (codim-1 entities)
319 for (const lf::mesh::Entity *edge : mesh.Entities(1)) {
320 // Check whether the current edge carries dofs to be imposed by the
321 // function g. The decision relies on the predicate `esscondflag`
322 if (esscondflag(*edge)) {
323 // retrieve reference finite element:
324 auto fe = fes.ShapeFunctionLayout(*edge);
325 LF_ASSERT_MSG(fe != nullptr,
326 "No ScalarReferenceFiniteElement for this edge!");
327 auto ref_eval_pts = fe->EvaluationNodes();
328
329 // Evaluate mesh function at several points specified by their
330 // reference coordinates.
331 auto g_vals = g(*edge, ref_eval_pts);
332
333 // Compute degrees of freedom from function values in evaluation
334 // points
335 auto dof_vals = fe->NodalValuesToDofs(
336 Eigen::Map<Eigen::Matrix<SCALAR, 1, Eigen::Dynamic>>(&g_vals[0], 1,
337 g_vals.size()));
338 LF_ASSERT_MSG(dof_vals.size() == fe->NumRefShapeFunctions(),
339 "Mismatch " << dof_vals.size() << " <-> "
340 << fe->NumRefShapeFunctions());
341 LF_ASSERT_MSG(fes.LocGlobMap().NumLocalDofs(*edge) == dof_vals.size(),
342 "Mismatch " << fes.LocGlobMap().NumLocalDofs(*edge)
343 << " <-> " << dof_vals.size());
344 // Fetch indices of global shape functions associated with current
345 // edge
346 auto gdof_indices{fes.LocGlobMap().GlobalDofIndices(*edge)};
347 int k = 0;
348 // Set flags and values; setting, no accumulation here!
349 for (const lf::assemble::gdof_idx_t gdof_idx : gdof_indices) {
350 flag_val_vec[gdof_idx] = {true, dof_vals[k++]};
351 }
352 }
353 }
354 return flag_val_vec;
355}
356
357} // namespace lf::fe
358
359#endif
A general (interface) class for DOF handling, see Lecture Document Paragraph 2.7.4....
Definition: dofhandler.h:109
virtual nonstd::span< const gdof_idx_t > GlobalDofIndices(const lf::mesh::Entity &entity) const =0
access to indices of global dof's belonging to an entity
virtual size_type NumLocalDofs(const lf::mesh::Entity &entity) const =0
tells the number of degrees of freedom subordinate/_belonging_ to to an entity
virtual size_type NumDofs() const =0
total number of dof's handled by the object
A Function Object that can be invoked with any arguments and that always returns the value true.
Represents a reference element with all its properties.
Definition: ref_el.h:106
static constexpr RefEl kSegment()
Returns the (1-dimensional) reference segment.
Definition: ref_el.h:150
constexpr RefEl(RefElType type) noexcept
Create a RefEl from a lf::base::RefElType enum.
Definition: ref_el.h:172
static constexpr RefEl kTria()
Returns the reference triangle.
Definition: ref_el.h:158
static constexpr RefEl kQuad()
Returns the reference quadrilateral.
Definition: ref_el.h:166
Space of scalar valued finite element functions on a hybrid 2D mesh
virtual ScalarReferenceFiniteElement< SCALAR > const * ShapeFunctionLayout(const lf::mesh::Entity &entity) const =0
access to shape function layout for mesh entities
virtual std::shared_ptr< const lf::mesh::Mesh > Mesh() const =0
acess to underlying mesh
virtual const lf::assemble::DofHandler & LocGlobMap() const =0
access to associated local-to-global map
virtual Eigen::VectorXd IntegrationElement(const Eigen::MatrixXd &local) const =0
The integration element (factor appearing in integral transformation formula, see below) at number of...
Interface class representing a topological entity in a cellular complex
Definition: entity.h:39
virtual const geometry::Geometry * Geometry() const =0
Describes the geometry of this entity.
Abstract interface for objects representing a single mesh.
virtual nonstd::span< const Entity *const > Entities(unsigned codim) const =0
All entities of a given codimension.
Eigen::Index gdof_idx_t
Collects data structures and algorithms designed for scalar finite element methods primarily meant fo...
Definition: fe.h:47
std::vector< std::pair< bool, SCALAR > > InitEssentialConditionFromFunction(const lf::fe::ScalarFESpace< SCALAR > &fes, EDGESELECTOR &&esscondflag, FUNCTION &&g)
Initialization of flags/values for dofs of a Scalar finite element space whose values are imposed by ...
Definition: fe_tools.h:301
auto NodalProjection(const lf::fe::ScalarFESpace< SCALAR > &fe_space, MF &&u, SELECTOR &&pred=base::PredicateTrue{})
Computes nodal projection of a mesh function and returns the finite element basis expansion coefficie...
Definition: fe_tools.h:199
static const unsigned int kout_l2_qr
Definition: fe_tools.h:26
lf::assemble::size_type size_type
Definition: fe.h:54
auto IntegrateMeshFunction(const lf::mesh::Mesh &mesh, const MF &mf, const QR_SELECTOR &qr_selector, const ENTITY_PREDICATE &ep=base::PredicateTrue{}, int codim=0) -> mesh::utils::MeshFunctionReturnType< MF >
Integrate a MeshFunction over a mesh (with quadrature rules)
Definition: fe_tools.h:111
static const unsigned int kout_l2_rsfvals
Definition: fe_tools.h:27
internal::VectorElement_t< internal::MeshFunctionReturnType_t< R > > MeshFunctionReturnType
Determine the type of objects returned by a MeshFunction.
QuadRule make_QuadRule(base::RefEl ref_el, unsigned degree)
Returns a QuadRule object for the given Reference Element and Degree.