LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
product_fe_space.h
1#ifndef PROJECTS_DPG_PRODUCT_FE_SPACE_H
2#define PROJECTS_DPG_PRODUCT_FE_SPACE_H
3
12#include <lf/base/base.h>
13#include <lf/fe/fe.h>
14#include <lf/uscalfe/uscalfe.h>
15
16#include <vector>
17
18#include "dpg.h"
19#include "product_dofhandler.h"
20
21namespace projects::dpg {
22
57template <typename SCALAR>
59 public:
60 using scalar = SCALAR;
61
68 ProductUniformFESpace &operator=(const ProductUniformFESpace &) = delete;
69 ProductUniformFESpace &operator=(ProductUniformFESpace &&) noexcept = default;
70
93 std::shared_ptr<const lf::mesh::Mesh> mesh_p,
94 std::vector<
95 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>>
96 rfs_tria_v,
97 std::vector<
98 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>>
99 rfs_quad_v,
100 std::vector<
101 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>>
102 rfs_edge_v,
103 std::vector<
104 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>>
105 rfs_point_v)
106 : mesh_p_(std::move(mesh_p)),
107 rfs_tria_v_(std::move(rfs_tria_v)),
108 rfs_quad_v_(std::move(rfs_quad_v)),
109 rfs_edge_v_(std::move(rfs_edge_v)),
110 rfs_point_v_(std::move(rfs_point_v)) {
112 init();
113 }
114
118 [[nodiscard]] std::shared_ptr<const lf::mesh::Mesh> Mesh() const {
119 LF_ASSERT_MSG(mesh_p_ != nullptr, "Invalid FE space, no mesh");
120 return mesh_p_;
121 }
122
126 [[nodiscard]] const ProductUniformFEDofHandler &LocGlobMap() const {
127 LF_ASSERT_MSG(mesh_p_ != nullptr, "Invalid FE space, no mesh");
128 LF_ASSERT_MSG(dofh_p_ != nullptr, "Invalid FE space, no dofhandler");
129 return *dofh_p_;
130 }
131
144 lf::base::RefEl ref_el_type, size_type component) const;
145
148 [[nodiscard]] size_type NumRefShapeFunctions(lf::base::RefEl ref_el_type,
149 size_type component) const;
150
152 [[nodiscard]] size_type NumComponents() const { return numComponents_; }
153
162 std::shared_ptr<const lf::uscalfe::UniformScalarFESpace<SCALAR>>
163 ComponentFESpace(size_type component) const {
164 return std::make_shared<lf::uscalfe::UniformScalarFESpace<SCALAR>>(
165 mesh_p_, rfs_tria_v_[component], rfs_quad_v_[component],
166 rfs_edge_v_[component], rfs_point_v_[component]);
167 }
168
170 virtual ~ProductUniformFESpace() = default;
171
172 private:
174 std::shared_ptr<const lf::mesh::Mesh> mesh_p_;
175
178 std::vector<
179 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>>
181 std::vector<
182 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>>
184 std::vector<
185 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>>
187 std::vector<
188 std::shared_ptr<const lf::fe::ScalarReferenceFiniteElement<SCALAR>>>
190
193 std::vector<size_type> num_rsf_node_;
194 std::vector<size_type> num_rsf_edge_;
195 std::vector<size_type> num_rsf_tria_;
196 std::vector<size_type> num_rsf_quad_;
197
199 std::unique_ptr<ProductUniformFEDofHandler> dofh_p_;
200
203
205 void init();
206};
207
208// Initialization method.
209template <typename SCALAR>
211 // check validity and consistency of mesh pointer:
212 LF_ASSERT_MSG(mesh_p_ != nullptr, "No mesh");
213 LF_ASSERT_MSG(mesh_p_->DimMesh() == 2, "Only 2D cells");
214
215 // we do not check, wheter a specification of reference finite elements
216 // for cells (triangles and quadrilaterals) is given, since this may not
217 // be desired necessary for some components in a dpg method (fluxes)
218
219 // check validity and consistency of the number of components:
220 LF_ASSERT_MSG(numComponents_ != 0, "0 components FE space.");
221 LF_ASSERT_MSG(numComponents_ == rfs_tria_v_.size() &&
222 numComponents_ == rfs_quad_v_.size() &&
223 numComponents_ == rfs_edge_v_.size() &&
224 numComponents_ == rfs_point_v_.size(),
225 "Missmatch in number of shape functions passed for different "
226 "entity tpyes.");
227
228 // resize vectors saving the number of loal shape functions for each
229 // component:
230 num_rsf_tria_.resize(numComponents_);
231 num_rsf_quad_.resize(numComponents_);
232 num_rsf_edge_.resize(numComponents_);
233 num_rsf_node_.resize(numComponents_);
234
235 // compatibility checks and initialization of number of shape functions:
236 for (size_type component = 0; component < numComponents_; component++) {
237 num_rsf_tria_[component] = 0;
238 num_rsf_quad_[component] = 0;
239 num_rsf_edge_[component] = 0;
240 num_rsf_node_[component] = 0;
241
242 if (rfs_tria_v_[component] != nullptr) {
243 // probe reference finite element
244 LF_ASSERT_MSG(rfs_tria_v_[component]->RefEl() == lf::base::RefEl::kTria(),
245 "wrong type for triangle in component" << component);
246 // initialize number of shape functions associated to entitites.
247 num_rsf_node_[component] =
248 rfs_tria_v_[component]->NumRefShapeFunctions(2);
249 num_rsf_edge_[component] =
250 rfs_tria_v_[component]->NumRefShapeFunctions(1);
251 num_rsf_tria_[component] =
252 rfs_tria_v_[component]->NumRefShapeFunctions(0);
253 }
254 if (rfs_quad_v_[component] != nullptr) {
255 // probe reference finite element for quads.
256 LF_ASSERT_MSG(rfs_quad_v_[component]->RefEl() == lf::base::RefEl::kQuad(),
257 "Wrong type for quad in component " << component);
258 // initialize number of shape functions associated to entitites.
259 num_rsf_node_[component] =
260 rfs_quad_v_[component]->NumRefShapeFunctions(2);
261 num_rsf_edge_[component] =
262 rfs_quad_v_[component]->NumRefShapeFunctions(1);
263 num_rsf_quad_[component] =
264 rfs_quad_v_[component]->NumRefShapeFunctions(0);
265 }
266 if (rfs_edge_v_[component] != nullptr) {
267 LF_ASSERT_MSG(
268 rfs_edge_v_[component]->RefEl() == lf::base::RefEl::kSegment(),
269 "Wrong type for edge in component " << component);
270 num_rsf_node_[component] =
271 rfs_edge_v_[component]->NumRefShapeFunctions(1);
272 num_rsf_edge_[component] =
273 rfs_edge_v_[component]->NumRefShapeFunctions(0);
274 }
275
276 // Compatibility check for numbers of local shape functions associated with
277 // edges. Those must be the same for all reference shape function
278 // descriptions in a component passed to the finite element space.
279 if ((rfs_tria_v_[component] != nullptr) &&
280 (rfs_quad_v_[component] != nullptr)) {
281 LF_ASSERT_MSG((rfs_tria_v_[component]->NumRefShapeFunctions(2)) ==
282 (rfs_quad_v_[component]->NumRefShapeFunctions(2)),
283 "#RSF missmatch on nodes in component"
284 << component << ": "
285 << rfs_tria_v_[component]->NumRefShapeFunctions(2)
286 << "<->"
287 << rfs_quad_v_[component]->NumRefShapeFunctions(2));
288 LF_ASSERT_MSG((rfs_tria_v_[component]->NumRefShapeFunctions(1)) ==
289 (rfs_quad_v_[component]->NumRefShapeFunctions(1)),
290 "#RSF missmatch on edges in component"
291 << component << ": "
292 << rfs_tria_v_[component]->NumRefShapeFunctions(1)
293 << "<->"
294 << rfs_quad_v_[component]->NumRefShapeFunctions(1));
295 }
296 if ((rfs_tria_v_[component] != nullptr) &&
297 (rfs_edge_v_[component] != nullptr)) {
298 LF_ASSERT_MSG((rfs_tria_v_[component]->NumRefShapeFunctions(2)) ==
299 (rfs_edge_v_[component]->NumRefShapeFunctions(1)),
300 "#RSF missmatch on nodes in component"
301 << component << ": "
302 << rfs_tria_v_[component]->NumRefShapeFunctions(2)
303 << "<->"
304 << rfs_edge_v_[component]->NumRefShapeFunctions(1));
305 LF_ASSERT_MSG((rfs_tria_v_[component]->NumRefShapeFunctions(1)) ==
306 (rfs_edge_v_[component]->NumRefShapeFunctions(0)),
307 "#RSF missmatch on edges in component"
308 << component << ": "
309 << rfs_tria_v_[component]->NumRefShapeFunctions(1)
310 << "<->"
311 << rfs_edge_v_[component]->NumRefShapeFunctions(0));
312 }
313 if ((rfs_quad_v_[component] != nullptr) &&
314 (rfs_edge_v_[component] != nullptr)) {
315 LF_ASSERT_MSG((rfs_quad_v_[component]->NumRefShapeFunctions(2)) ==
316 (rfs_edge_v_[component]->NumRefShapeFunctions(1)),
317 "#RSF missmatch on nodes in component"
318 << component << ": "
319 << rfs_quad_v_[component]->NumRefShapeFunctions(2)
320 << "<->"
321 << rfs_edge_v_[component]->NumRefShapeFunctions(1));
322 LF_ASSERT_MSG((rfs_quad_v_[component]->NumRefShapeFunctions(1)) ==
323 (rfs_edge_v_[component]->NumRefShapeFunctions(0)),
324 "#RSF missmatch on edges in component"
325 << component << ": "
326 << rfs_quad_v_[component]->NumRefShapeFunctions(1)
327 << "<->"
328 << rfs_edge_v_[component]->NumRefShapeFunctions(0));
329 }
330 }
331
332 // initialization of dof handler
333 // collect the number of interior reference shape functions for all
334 // components
335 std::vector<dof_map_t> rsf_layouts(numComponents_);
336 for (size_type component = 0; component < numComponents_; component++) {
337 rsf_layouts[component] = {
338 {lf::base::RefEl::kPoint(), num_rsf_node_[component]},
339 {lf::base::RefEl::kSegment(), num_rsf_edge_[component]},
340 {lf::base::RefEl::kTria(), num_rsf_tria_[component]},
341 {lf::base::RefEl::kQuad(), num_rsf_quad_[component]}};
342 }
343 dofh_p_ = std::make_unique<ProductUniformFEDofHandler>(mesh_p_, rsf_layouts);
344}
345
346template <typename SCALAR>
349 size_type component) const {
350 // Retrive specification of local shape functions for
351 // a certain component.
352 switch (ref_el_type) {
354 return rfs_point_v_[component].get();
355 }
357 // Null pointer valid return value:
358 // indicates that a shape function description for edges is missing
359 return rfs_edge_v_[component].get();
360 }
361 case lf::base::RefEl::kTria(): {
362 // Null pointer valid return value:
363 // indicates that a shape function description for triangles is missing.
364 return rfs_tria_v_[component].get();
365 }
366 case lf::base::RefEl::kQuad(): {
367 // Null pointer valid return value:
368 // indicates that a shape function description for quadrilaterals is
369 // missing.
370 return rfs_quad_v_[component].get();
371 }
372 default: {
373 LF_ASSERT_MSG(false, "Illegal entity type");
374 }
375 }
376 return nullptr;
377}
378
379template <typename SCALAR>
381 lf::base::RefEl ref_el_type, size_type component) const {
382 // Retrieve number of interior shape functions from rsf layouts
383 // for a certain component.
384 switch (ref_el_type) {
386 return num_rsf_node_[component];
387 }
389 return num_rsf_edge_[component];
390 }
391 case lf::base::RefEl::kTria(): {
392 return num_rsf_tria_[component];
393 }
394 case lf::base::RefEl::kQuad(): {
395 return num_rsf_quad_[component];
396 }
397 dafault : { LF_ASSERT_MSG(false, "Illegal entity type"); }
398 }
399 return 0;
400}
401
402} // namespace projects::dpg
403
404#endif // PROJECTS_DPG_PRODUCT_FE_SPACE_H
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
Interface class for parametric scalar valued finite elements.
Dofhandler for uniform finite element spaces that discretizes a cartesian/product space.
cartesian/prodcut space of finite element functions on a hybrid 2D mesh.
size_type NumComponents() const
number of components of the product space
std::shared_ptr< const lf::uscalfe::UniformScalarFESpace< SCALAR > > ComponentFESpace(size_type component) const
Constructs a lf::uscalfe::UniformScalarFESpace that describes the finite element space associated to ...
lf::fe::ScalarReferenceFiniteElement< SCALAR > const * ShapeFunctionLayout(lf::base::RefEl ref_el_type, size_type component) const
access to shape function layout
size_type NumRefShapeFunctions(lf::base::RefEl ref_el_type, size_type component) const
number of interior shape functions associated to entities of various types for a given component
std::vector< std::shared_ptr< const lf::fe::ScalarReferenceFiniteElement< SCALAR > > > rfs_point_v_
std::vector< std::shared_ptr< const lf::fe::ScalarReferenceFiniteElement< SCALAR > > > rfs_tria_v_
std::unique_ptr< ProductUniformFEDofHandler > dofh_p_
virtual ~ProductUniformFESpace()=default
no special destructor
ProductUniformFESpace(ProductUniformFESpace &&) noexcept=default
const ProductUniformFEDofHandler & LocGlobMap() const
access to associated local-to-global map
std::vector< size_type > num_rsf_tria_
std::vector< size_type > num_rsf_edge_
std::shared_ptr< const lf::mesh::Mesh > mesh_p_
std::shared_ptr< const lf::mesh::Mesh > Mesh() const
acess to underlying mesh
ProductUniformFESpace(const ProductUniformFESpace &)=delete
std::vector< std::shared_ptr< const lf::fe::ScalarReferenceFiniteElement< SCALAR > > > rfs_edge_v_
std::vector< size_type > num_rsf_node_
std::vector< size_type > num_rsf_quad_
std::vector< std::shared_ptr< const lf::fe::ScalarReferenceFiniteElement< SCALAR > > > rfs_quad_v_
Definition: assemble.h:30
Contains functionality for the implementation of DPG methods.
Definition: primal_dpg.h:33
lf::uscalfe::size_type size_type
Type for vector length/matrix sizes.
Definition: dpg.h:17