LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
uniform_scalar_fe_space.h
1#ifndef LF_FESPACE_H
2#define LF_FESPACE_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
17#include <lf/assemble/assemble.h>
18#include <lf/fe/scalar_fe_space.h>
19
20#include "lagr_fe.h"
21
22namespace lf::uscalfe {
23
49template <typename SCALAR>
51 public:
52 using Scalar = SCALAR;
53
56 UniformScalarFESpace &operator=(const UniformScalarFESpace &) = delete;
57 UniformScalarFESpace &operator=(UniformScalarFESpace &&) noexcept = default;
83 std::shared_ptr<const lf::mesh::Mesh> mesh_p,
84 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>
85 rfs_tria_p,
86 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>
87 rfs_quad_p,
88 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>
89 rfs_edge_p = nullptr,
90 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>
91 rfs_point_p = nullptr)
92 : lf::fe::ScalarFESpace<SCALAR>(),
93 rfs_tria_p_(std::move(rfs_tria_p)),
94 rfs_quad_p_(std::move(rfs_quad_p)),
95 rfs_edge_p_(std::move(rfs_edge_p)),
96 rfs_point_p_(std::move(rfs_point_p)),
97 dofh_(InitDofHandler(std::move(mesh_p))) {}
98
102 [[nodiscard]] std::shared_ptr<const lf::mesh::Mesh> Mesh() const override {
103 return dofh_.Mesh();
104 }
105
109 [[nodiscard]] const lf::assemble::DofHandler &LocGlobMap() const override {
110 LF_VERIFY_MSG(Mesh() != nullptr, "No valid FE space object: no mesh");
111 return dofh_;
112 }
113
118 ShapeFunctionLayout(const lf::mesh::Entity &entity) const override;
119
133 ShapeFunctionLayout(lf::base::RefEl ref_el_type) const;
134
138 [[nodiscard]] size_type NumRefShapeFunctions(
139 const lf::mesh::Entity &entity) const override;
140
144 [[nodiscard]] size_type NumRefShapeFunctions(
145 lf::base::RefEl ref_el_type) const;
146
148 ~UniformScalarFESpace() override = default;
149
150 private:
152 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>
155 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>
158 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>
161 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>
166
169
172 std::shared_ptr<const lf::mesh::Mesh> mesh_p);
174 [[nodiscard]] bool check_ptr() const {
175 LF_VERIFY_MSG(Mesh() != nullptr, "No valid FE space object: no mesh");
176 LF_VERIFY_MSG((rfs_quad_p_ != nullptr) && (rfs_quad_p_ != nullptr),
177 "No valid FE space object: no rsfs for cells");
178 return true;
179 }
180
181}; // end class definition UniformScalarFESpace
182
191const unsigned int kUniformScalarFESpaceOutMesh = 1;
192
199const unsigned int kUniformScalarFESpaceOutDofh = 2;
200
207const unsigned int kUniformScalarFESpaceOutRsfs = 4;
208
225template <class SCALAR>
226void PrintInfo(std::ostream &o, const UniformScalarFESpace<SCALAR> &fes,
227 unsigned int ctrl = 0);
228
234template <typename SCALAR>
235std::ostream &operator<<(std::ostream &o,
237
238// Initialization methods
239template <typename SCALAR>
241 std::shared_ptr<const lf::mesh::Mesh> mesh_p) {
242 // Check validity and consistency of mesh pointer
243 LF_VERIFY_MSG(mesh_p != nullptr, "Missing mesh!");
244 LF_VERIFY_MSG((rfs_quad_p_ != nullptr) || (rfs_tria_p_ != nullptr),
245 "Missing FE specification for cells");
246 LF_VERIFY_MSG((mesh_p->DimMesh() == 2), "Only for 2D meshes");
247
248 // Check whether all required finite element specifications are provided
249 LF_VERIFY_MSG(
250 (mesh_p->NumEntities(lf::base::RefEl::kTria()) == 0) ||
251 (rfs_tria_p_ != nullptr),
252 "Missing FE specification for triangles though mesh contains some");
253 LF_VERIFY_MSG((mesh_p->NumEntities(lf::base::RefEl::kQuad()) == 0) ||
254 (rfs_quad_p_ != nullptr),
255 "Missing FE specification for quads though mesh contains some");
256
257 // Compatibility checks and initialization of numbers of shape functions
258 // In particular only a single shape function may be associated to a node
259 // in the case of a SCALAR finite element space
260 if (rfs_tria_p_ != nullptr) {
261 // Probe local shape functions on a triangle
262 LF_VERIFY_MSG((*rfs_tria_p_).RefEl() == lf::base::RefEl::kTria(),
263 "Wrong type for triangle!");
264 LF_VERIFY_MSG((*rfs_tria_p_).NumRefShapeFunctions(2) <= 1,
265 "At most one shape function can be assigned to each vertex");
266 // Initialize numbers of shape functions associated to entities
267 num_rsf_node_ = (*rfs_tria_p_).NumRefShapeFunctions(2);
268 num_rsf_edge_ = (*rfs_tria_p_).NumRefShapeFunctions(1);
269 num_rsf_tria_ = (*rfs_tria_p_).NumRefShapeFunctions(0);
270 }
271 if (rfs_quad_p_ != nullptr) {
272 // Probe local shape functions for QUADs
273 LF_VERIFY_MSG((*rfs_quad_p_).RefEl() == lf::base::RefEl::kQuad(),
274 "Wrong type for quad!");
275 LF_VERIFY_MSG((*rfs_quad_p_).NumRefShapeFunctions(2) <= 1,
276 "At most one shape function can be assigned to each vertex");
277 // Initialize numbers of shape functions associated to entities
278 num_rsf_node_ = (*rfs_quad_p_).NumRefShapeFunctions(2);
279 num_rsf_edge_ = (*rfs_quad_p_).NumRefShapeFunctions(1);
280 num_rsf_quad_ = (*rfs_quad_p_).NumRefShapeFunctions(0);
281 }
282 if (rfs_edge_p_ != nullptr) {
283 LF_VERIFY_MSG((*rfs_edge_p_).RefEl() == lf::base::RefEl::kSegment(),
284 "Wrong type for edge!");
285 LF_VERIFY_MSG((*rfs_edge_p_).NumRefShapeFunctions(1) <= 1,
286 "At most one shape function can be assigned to each vertex");
287 num_rsf_node_ = (*rfs_edge_p_).NumRefShapeFunctions(1);
288 num_rsf_edge_ = (*rfs_edge_p_).NumRefShapeFunctions(0);
289 }
290
291 // Compatibility check for numbers of local shape functions associated with
292 // edges. Those must be the same for all reference shape function descriptions
293 // passed to the finite element space.
294 if ((rfs_tria_p_ != nullptr) && (rfs_quad_p_ != nullptr)) {
295 LF_ASSERT_MSG(((*rfs_tria_p_).NumRefShapeFunctions(2) ==
296 (*rfs_quad_p_).NumRefShapeFunctions(2)),
297 "#RSF mismatch on nodes "
298 << (*rfs_tria_p_).NumRefShapeFunctions(2) << " <-> "
299 << (*rfs_quad_p_).NumRefShapeFunctions(2));
300 LF_ASSERT_MSG(((*rfs_tria_p_).NumRefShapeFunctions(1) ==
301 (*rfs_quad_p_).NumRefShapeFunctions(1)),
302 "#RSF mismatch on edges "
303 << (*rfs_tria_p_).NumRefShapeFunctions(1) << " <-> "
304 << (*rfs_quad_p_).NumRefShapeFunctions(1));
305 }
306 if ((rfs_tria_p_ != nullptr) && (rfs_edge_p_ != nullptr)) {
307 LF_ASSERT_MSG(((*rfs_tria_p_).NumRefShapeFunctions(2) ==
308 (*rfs_edge_p_).NumRefShapeFunctions(1)),
309 "#RSF mismatch on nodes "
310 << (*rfs_tria_p_).NumRefShapeFunctions(2) << " <-> "
311 << (*rfs_edge_p_).NumRefShapeFunctions(1));
312 LF_ASSERT_MSG(((*rfs_tria_p_).NumRefShapeFunctions(1) ==
313 (*rfs_edge_p_).NumRefShapeFunctions(0)),
314 "#RSF mismatch on edges "
315 << (*rfs_tria_p_).NumRefShapeFunctions(1) << " <-> "
316 << (*rfs_edge_p_).NumRefShapeFunctions(0));
317 }
318 if ((rfs_quad_p_ != nullptr) && (rfs_edge_p_ != nullptr)) {
319 LF_ASSERT_MSG(((*rfs_quad_p_).NumRefShapeFunctions(2) ==
320 (*rfs_edge_p_).NumRefShapeFunctions(1)),
321 "#RSF mismatch on edges "
322 << (*rfs_quad_p_).NumRefShapeFunctions(2) << " <-> "
323 << (*rfs_edge_p_).NumRefShapeFunctions(1));
324 LF_ASSERT_MSG(((*rfs_quad_p_).NumRefShapeFunctions(1) ==
325 (*rfs_edge_p_).NumRefShapeFunctions(0)),
326 "#RSF mismatch on edges "
327 << (*rfs_quad_p_).NumRefShapeFunctions(1) << " <-> "
328 << (*rfs_edge_p_).NumRefShapeFunctions(0));
329 }
330
331 // Initialization of dof handler starting with collecting the number of
332 // interior reference shape functions
334 {lf::base::RefEl::kPoint(), num_rsf_node_},
335 {lf::base::RefEl::kSegment(), num_rsf_edge_},
336 {lf::base::RefEl::kTria(), num_rsf_tria_},
337 {lf::base::RefEl::kQuad(), num_rsf_quad_}};
338 return lf::assemble::UniformFEDofHandler(std::move(mesh_p), rsf_layout);
339}
340
341template <typename SCALAR>
344 const lf::mesh::Entity &entity) const {
345 return ShapeFunctionLayout(entity.RefEl());
346}
347
348template <typename SCALAR>
351 lf::base::RefEl ref_el_type) const {
352 // Retrieve specification of local shape functions
353 switch (ref_el_type) {
355 return rfs_point_p_.get();
356 }
358 // Null pointer valid return value: indicates that a shape function
359 // description for edges is missing.
360 // LF_ASSERT_MSG(rfs_edge_p_ != nullptr, "No RSF for edges!");
361 return rfs_edge_p_.get();
362 }
363 case lf::base::RefEl::kTria(): {
364 // Null pointer valid return value: indicates that a shape function
365 // description for triangular cells is missing.
366 // LF_ASSERT_MSG(rfs_tria_p_ != nullptr, "No RSF for triangles!");
367 return rfs_tria_p_.get();
368 }
369 case lf::base::RefEl::kQuad(): {
370 // Null pointer valid return value: indicates that a shape function
371 // description for quadrilaterals is missing.
372 // LF_ASSERT_MSG(rfs_quad_p_ != nullptr, "No RSF for quads!");
373 return rfs_quad_p_.get();
374 }
375 default: {
376 LF_VERIFY_MSG(false, "Illegal entity type");
377 }
378 }
379 return nullptr;
380}
381
382template <typename SCALAR>
384 const lf::mesh::Entity &entity) const {
385 return NumRefShapeFunctions(entity.RefEl());
386}
387
388/* number of _interior_ shape functions associated to entities of various types
389 */
390template <typename SCALAR>
392 lf::base::RefEl ref_el_type) const {
393 LF_ASSERT_MSG((rfs_quad_p_ != nullptr) && (rfs_quad_p_ != nullptr),
394 "No valid FE space object: no rsfs");
395 // Retrieve number of interior shape functions from rsf layouts
396 switch (ref_el_type) {
398 return num_rsf_node_;
399 }
401 return num_rsf_edge_;
402 }
403 case lf::base::RefEl::kTria(): {
404 return num_rsf_tria_;
405 }
406 case lf::base::RefEl::kQuad(): {
407 return num_rsf_quad_;
408 }
409 default: {
410 LF_VERIFY_MSG(false, "Illegal entity type");
411 }
412 }
413 return 0;
414}
415
416template <typename SCALAR>
417void PrintInfo(std::ostream &o, const UniformScalarFESpace<SCALAR> &fes,
418 unsigned ctrl) {
419 o << "Uniform scalar FE space, dim = " << fes.LocGlobMap().NumDofs()
420 << std::endl;
421
422 if ((ctrl & kUniformScalarFESpaceOutMesh) != 0) {
423 o << *fes.Mesh() << std::endl;
424 }
425 if ((ctrl & kUniformScalarFESpaceOutDofh) != 0) {
426 o << fes.LocGlobMap() << std::endl;
427 }
428 if ((ctrl & kUniformScalarFESpaceOutRsfs) != 0) {
429 o << fes.NumRefShapeFunctions(lf::base::RefEl::kPoint()) << " rsfs @ nodes"
430 << std::endl;
432 << " rsfs @ edges" << std::endl;
434 << " rsfs @ triangles" << std::endl;
435 o << fes.NumRefShapeFunctions(lf::base::RefEl::kQuad()) << " rsfs @ quads"
436 << std::endl;
437 }
438}
439
441template <typename SCALAR>
442std::ostream &operator<<(std::ostream &o,
443 const UniformScalarFESpace<SCALAR> &fes) {
444 fes.PrintInfo(o, 0);
445 return o;
446}
447
448} // namespace lf::uscalfe
449
450#endif
A general (interface) class for DOF handling, see Lecture Document Paragraph 2.7.4....
Definition: dofhandler.h:109
virtual size_type NumDofs() const =0
total number of dof's handled by the object
Dofhandler for uniform finite element spaces.
Definition: dofhandler.h:257
std::shared_ptr< const lf::mesh::Mesh > Mesh() const override
Acess to underlying mesh object.
Definition: dofhandler.h:345
std::map< lf::base::RefEl, base::size_type > dof_map_t
Construction from a map object.
Definition: dofhandler.h:274
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
static constexpr RefEl kPoint()
Returns the (0-dimensional) reference point.
Definition: ref_el.h:141
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
ScalarFESpace()=default
default constructor, needed by std::vector
Interface class for parametric scalar valued finite elements.
Interface class representing a topological entity in a cellular complex
Definition: entity.h:39
virtual base::RefEl RefEl() const =0
Describes the reference element type of this entity.
Space of scalar valued finite element functions on a hybrid 2D mesh
std::shared_ptr< const lf::fe::ScalarReferenceFiniteElement< SCALAR > > rfs_quad_p_
void PrintInfo(std::ostream &o, const UniformScalarFESpace< SCALAR > &fes, unsigned int ctrl=0)
Print information about a UniformScalarFESpace to the given stream object.
const lf::assemble::DofHandler & LocGlobMap() const override
access to associated local-to-global map
assemble::UniformFEDofHandler dofh_
std::shared_ptr< const lf::fe::ScalarReferenceFiniteElement< SCALAR > > rfs_point_p_
std::shared_ptr< const lf::fe::ScalarReferenceFiniteElement< SCALAR > > rfs_tria_p_
UniformScalarFESpace(const UniformScalarFESpace &)=delete
~UniformScalarFESpace() override=default
No special destructor.
UniformScalarFESpace(UniformScalarFESpace &&) noexcept=default
std::shared_ptr< const lf::mesh::Mesh > Mesh() const override
access to underlying mesh
size_type NumRefShapeFunctions(const lf::mesh::Entity &entity) const override
number of interior shape functions associated to entities of various types
std::shared_ptr< const lf::fe::ScalarReferenceFiniteElement< SCALAR > > rfs_edge_p_
lf::fe::ScalarReferenceFiniteElement< SCALAR > const * ShapeFunctionLayout(const lf::mesh::Entity &entity) const override
access to shape function layout for cells
assemble::UniformFEDofHandler InitDofHandler(std::shared_ptr< const lf::mesh::Mesh > mesh_p)
Collects data structures and algorithms designed for scalar finite element methods primarily meant fo...
const unsigned int kUniformScalarFESpaceOutDofh
information about the dof handler will be printed.
void PrintInfo(std::ostream &o, const UniformScalarFESpace< SCALAR > &fes, unsigned ctrl)
const unsigned int kUniformScalarFESpaceOutMesh
mesh information will be printed
lf::assemble::size_type size_type
Definition: lagr_fe.h:30
const unsigned int kUniformScalarFESpaceOutRsfs
information about the reference shape functions will be printed
std::ostream & operator<<(std::ostream &o, const UniformScalarFESpace< SCALAR > &fes)
Definition: assemble.h:30