LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
dofhandler.h
1#ifndef _LF_DOFHD_H
2#define _LF_DOFHD_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/mesh/mesh.h>
18
19#include <map>
20
21#include "assembly_types.h"
22
23namespace lf::assemble {
110 protected:
114 DofHandler() = default;
115
120 DofHandler(const DofHandler &) = default;
121 DofHandler(DofHandler &&) = default;
122 DofHandler &operator=(const DofHandler &) = default;
125 public:
127 virtual ~DofHandler() = default;
128
132 [[nodiscard]] virtual size_type NumDofs() const = 0;
133
144 [[nodiscard]] virtual size_type NumLocalDofs(
145 const lf::mesh::Entity &entity) const = 0;
146
157 [[nodiscard]] virtual size_type NumInteriorDofs(
158 const lf::mesh::Entity &entity) const = 0;
159
182 const lf::mesh::Entity &entity) const = 0;
183
202 const lf::mesh::Entity &entity) const = 0;
203
216 [[nodiscard]] virtual const lf::mesh::Entity &Entity(
217 gdof_idx_t dofnum) const = 0;
218
224 [[nodiscard]] virtual std::shared_ptr<const lf::mesh::Mesh> Mesh() const = 0;
225};
226
228std::ostream &operator<<(std::ostream &o, const DofHandler &dof_handler);
229
245void PrintInfo(std::ostream &stream, const DofHandler &dof_handler,
246 unsigned int ctrl = 0);
247
248/* ====================================================================== */
249
258 public:
274 using dof_map_t = std::map<lf::base::RefEl, base::size_type>;
275 UniformFEDofHandler(std::shared_ptr<const lf::mesh::Mesh> mesh,
276 dof_map_t dofmap);
283
288
293
298
302 ~UniformFEDofHandler() override = default;
303
304 [[nodiscard]] size_type NumDofs() const override { return num_dof_; }
305
310 [[nodiscard]] size_type NumLocalDofs(
311 const lf::mesh::Entity &entity) const override;
312
317 [[nodiscard]] size_type NumInteriorDofs(
318 const lf::mesh::Entity &entity) const override;
319
324 const lf::mesh::Entity &entity) const override;
325
330 const lf::mesh::Entity &entity) const override;
331
336 [[nodiscard]] const lf::mesh::Entity &Entity(
337 gdof_idx_t dofnum) const override {
338 LF_VERIFY_MSG(dofnum < dof_entities_.size(),
339 "Illegal dof index " << dofnum << ", max = " << num_dof_);
340 return *dof_entities_[dofnum];
341 }
342
345 [[nodiscard]] std::shared_ptr<const lf::mesh::Mesh> Mesh() const override {
346 return mesh_;
347 }
348
349 private:
353 void initIndexArrays();
362 void InitTotalNumDofs();
363
364 // Access method to numbers and values of indices of shape functions
366 lf::base::RefEl ref_el_type, glb_idx_t entity_index) const;
367
369 lf::base::RefEl ref_el_type, glb_idx_t entity_index) const;
370
371 [[nodiscard]] size_type GetNumLocalDofs(lf::base::RefEl ref_el_type,
372 glb_idx_t /*unused*/) const {
373 return NumCoveredDofs(ref_el_type);
374 }
375
384 [[nodiscard]] size_type NumCoveredDofs(lf::base::RefEl ref_el_type) const {
385 size_type no_covered_dofs;
386 switch (ref_el_type) {
388 no_covered_dofs = num_dofs_[kNodeOrd];
389 break;
390 }
392 no_covered_dofs = num_dofs_[kEdgeOrd];
393 break;
394 }
395 case lf::base::RefEl::kTria(): {
396 no_covered_dofs = num_dofs_tria_;
397 break;
398 }
399 case lf::base::RefEl::kQuad(): {
400 no_covered_dofs = num_dofs_quad_;
401 break;
402 }
403 default: {
404 LF_VERIFY_MSG(false, "Illegal entity type");
405 break;
406 }
407 } // end switch
408 return no_covered_dofs;
409 }
410
412 [[nodiscard]] size_type NumInteriorDofs(lf::base::RefEl ref_el_type) const {
413 size_type no_loc_dofs;
414 switch (ref_el_type) {
416 no_loc_dofs = num_loc_dof_point_;
417 break;
418 }
420 no_loc_dofs = num_loc_dof_segment_;
421 break;
422 }
423 case lf::base::RefEl::kTria(): {
424 no_loc_dofs = num_loc_dof_tria_;
425 break;
426 }
427 case lf::base::RefEl::kQuad(): {
428 no_loc_dofs = num_loc_dof_quad_;
429 break;
430 }
431 default: {
432 LF_VERIFY_MSG(false, "Illegal entity type");
433 break;
434 }
435 } // end switch
436 return no_loc_dofs;
437 }
438
440 std::shared_ptr<const lf::mesh::Mesh> mesh_;
444 std::vector<const lf::mesh::Entity *> dof_entities_;
447 std::array<std::vector<gdof_idx_t>, 3> dofs_;
449 std::array<size_type, 3> num_dofs_;
461};
462
463/* ====================================================================== */
464
473 public:
478
483
488
493
497 ~DynamicFEDofHandler() override = default;
498
522 template <typename LOCALDOFINFO>
523 DynamicFEDofHandler(std::shared_ptr<const lf::mesh::Mesh> mesh_p,
524 LOCALDOFINFO &&locdof)
525 : mesh_p_(std::move(mesh_p)) {
526 LF_ASSERT_MSG((mesh_p_->DimMesh() == 2), "Can handle 2D meshes only");
527
528 // Index counter for global shape functions = global dof
529 gdof_idx_t dof_idx = 0;
530
531 // Step I: Set indices for shape functions on nodes
532 // Run through node indices (entities of co-dimension 2)
533 const size_type no_nodes = mesh_p_->NumEntities(2);
534 num_int_dofs_[2].resize(no_nodes, 0);
535 offsets_[2].resize(no_nodes + 1, 0);
536 // Traverse nodes (co-dimension-2 entities) based on indices
537 for (glb_idx_t node_idx = 0; node_idx < no_nodes; node_idx++) {
538 // Obtain pointer to node entity
539 const mesh::Entity *node_p{mesh_p_->EntityByIndex(2, node_idx)};
540 LF_ASSERT_MSG(mesh_p_->Index(*node_p) == node_idx, "Node index mismatch");
541 // Offset for indices of node in index vector
542 glb_idx_t node_dof_offset = dof_idx;
543 offsets_[2][node_idx] = node_dof_offset;
544 // Request number of local shape functions associated with the node
545 size_type no_int_dof_node = locdof(*node_p);
546 num_int_dofs_[2][node_idx] = no_int_dof_node;
547
548 // Store dof indices in array
549 for (unsigned j = 0; j < no_int_dof_node; j++) {
550 dofs_[2].push_back(dof_idx);
551 dof_entities_.push_back(node_p); // Store entity for current dof
552 dof_idx++; // Move on to next index
553 }
554 }
555 // Set sentinel
556 offsets_[2][no_nodes] = dof_idx;
557
558 // Step II: Set indices for shape functions on edges (co-dimension = 1)
559 const size_type no_edges = mesh_p_->NumEntities(1);
560 // Set length of edge-related index vectors
561 num_int_dofs_[1].resize(no_edges, 0);
562 offsets_[1].resize(no_edges + 1, 0);
563 // points to the position of the current dof index
564 size_type edge_dof_offset = 0;
565 for (glb_idx_t edge_idx = 0; edge_idx < no_edges; edge_idx++) {
566 // Obtain pointer to edge entity
567 const mesh::Entity *edge{mesh_p_->EntityByIndex(1, edge_idx)};
568 LF_ASSERT_MSG(mesh_p_->Index(*edge) == edge_idx, "Edge index mismatch");
569 // Offset for indices of edge dof in index vector
570 offsets_[1][edge_idx] = edge_dof_offset;
571 size_type no_int_dof_edge = locdof(*edge);
572 num_int_dofs_[1][edge_idx] = no_int_dof_edge;
573
574 // Obtain indices for basis functions sitting at endpoints
575 // Endpoints are mesh entities with co-dimension = 2
576 for (const lf::mesh::Entity *endpoint : edge->SubEntities(1)) {
577 const glb_idx_t ep_idx(mesh_p_->Index(*endpoint));
578 glb_idx_t ep_dof_offset = offsets_[2][ep_idx];
579 size_type no_int_dofs_ep = num_int_dofs_[2][ep_idx];
580 // Copy indices of shape functions from nodes to edge
581 for (unsigned j = 0; j < no_int_dofs_ep; j++) {
582 dofs_[1].push_back(dofs_[2][ep_dof_offset + j]);
583 edge_dof_offset++;
584 }
585 }
586 // Set indices for interior edge degrees of freedom
587 for (unsigned j = 0; j < no_int_dof_edge; j++) {
588 dofs_[1].push_back(dof_idx);
589 edge_dof_offset++;
590 dof_entities_.push_back(edge);
591 dof_idx++;
592 }
593 }
594 // Set sentinel
595 offsets_[1][no_edges] = edge_dof_offset;
596
597 // Step III: Set indices for shape functions on cells (co-dimension = 0)
598 const size_type no_cells = mesh_p_->NumEntities(0);
599 // Set length of cell-related index vectors
600 num_int_dofs_[0].resize(no_cells, 0);
601 offsets_[0].resize(no_cells + 1, 0);
602 // points to the position of the current dof index
603 size_type cell_dof_offset = 0;
604 for (glb_idx_t cell_idx = 0; cell_idx < no_cells; cell_idx++) {
605 // Obtain pointer to current ell
606 const mesh::Entity *cell{mesh_p_->EntityByIndex(0, cell_idx)};
607 // Offset for indices of cell dof in index vector
608 offsets_[0][cell_idx] = cell_dof_offset;
609 size_type no_int_dof_cell = locdof(*cell);
610 num_int_dofs_[0][cell_idx] = no_int_dof_cell;
611
612 // Obtain indices for basis functions in vertices
613 for (const lf::mesh::Entity *vertex : cell->SubEntities(2)) {
614 const glb_idx_t vt_idx(mesh_p_->Index(*vertex));
615 glb_idx_t vt_dof_offset = offsets_[2][vt_idx];
616 size_type no_int_dofs_vt = num_int_dofs_[2][vt_idx];
617 // Copy indices of shape functions from nodes to cell
618 for (unsigned j = 0; j < no_int_dofs_vt; j++) {
619 dofs_[0].push_back(dofs_[2][vt_dof_offset + j]);
620 cell_dof_offset++;
621 }
622 }
623
624 // Collect indices of interior shape functions of edges
625 // Internal ordering will depend on the orientation of the edge
626 auto edge_orientations = cell->RelativeOrientations();
627 auto edges = cell->SubEntities(1);
628 // Loop over edges
629 for (int ed_sub_idx = 0; ed_sub_idx < cell->RefEl().NumSubEntities(1);
630 ed_sub_idx++) {
631 const glb_idx_t edge_idx = mesh_p_->Index(*edges[ed_sub_idx]);
632 const size_type no_int_dof_edge = num_int_dofs_[1][edge_idx];
633 const glb_idx_t edge_int_dof_offset =
634 offsets_[1][edge_idx + 1] - no_int_dof_edge;
635
636 // Copy indices of shape functions from edges to cell
637 // The order, in which they are copied depends on the relative
638 // orientation of the edge w.r.t. the cell
639 switch (edge_orientations[ed_sub_idx]) {
641 for (int j = 0; j < no_int_dof_edge; j++) {
642 dofs_[0].push_back(dofs_[1][edge_int_dof_offset + j]);
643 cell_dof_offset++;
644 }
645 break;
646 }
648 for (int j = static_cast<int>(no_int_dof_edge - 1); j >= 0; j--) {
649 dofs_[0].push_back(dofs_[1][edge_int_dof_offset + j]);
650 cell_dof_offset++;
651 }
652 break;
653 }
654 } // end switch
655 } // end loop over edges
656
657 // Set indices for interior shape functions of the cell
658 for (unsigned j = 0; j < no_int_dof_cell; j++) {
659 dofs_[0].push_back(dof_idx);
660 cell_dof_offset++;
661 dof_entities_.push_back(cell);
662 dof_idx++;
663 } // end loop over interior dof of cell
664 } // end loop over cells
665 // Set sentinel
666 offsets_[0][no_cells] = cell_dof_offset;
667
668 // Finally set number of global shape functions
669 num_dof_ = dof_idx;
670 } // end constructor
671
675 [[nodiscard]] size_type NumDofs() const override { return num_dof_; }
676
681 [[nodiscard]] size_type NumInteriorDofs(
682 const lf::mesh::Entity &entity) const override;
683
688 [[nodiscard]] size_type NumLocalDofs(
689 const lf::mesh::Entity &entity) const override;
690
695 const lf::mesh::Entity &entity) const override;
696
701 const lf::mesh::Entity &entity) const override;
702
707 [[nodiscard]] const lf::mesh::Entity &Entity(
708 gdof_idx_t dofnum) const override {
709 LF_VERIFY_MSG(dofnum < dof_entities_.size(),
710 "Illegal dof index " << dofnum << ", max = " << num_dof_);
711 return *dof_entities_[dofnum];
712 }
713
716 [[nodiscard]] std::shared_ptr<const lf::mesh::Mesh> Mesh() const override {
717 return mesh_p_;
718 }
719
720 private:
722 std::shared_ptr<const lf::mesh::Mesh> mesh_p_;
726 std::vector<const lf::mesh::Entity *> dof_entities_;
739 std::array<std::vector<size_type>, 3> num_int_dofs_;
741 std::array<std::vector<size_type>, 3> offsets_;
744 std::array<std::vector<gdof_idx_t>, 3> dofs_;
746};
747
748} // namespace lf::assemble
749
750#endif
A general (interface) class for DOF handling, see Lecture Document Paragraph 2.7.4....
Definition: dofhandler.h:109
virtual std::shared_ptr< const lf::mesh::Mesh > Mesh() const =0
Acess to underlying mesh object.
void PrintInfo(std::ostream &stream, const DofHandler &dof_handler, unsigned int ctrl=0)
Output information about the given dof handler to the given stream object.
DofHandler(DofHandler &&)=default
DofHandler & operator=(DofHandler &&)=default
virtual nonstd::span< const gdof_idx_t > InteriorGlobalDofIndices(const lf::mesh::Entity &entity) const =0
global indices of shape functions associated with an entity_
virtual size_type NumInteriorDofs(const lf::mesh::Entity &entity) const =0
provides number of shape functions associated with an entity
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
DofHandler()=default
Default constructor, can only be called from derived class.
DofHandler(const DofHandler &)=default
virtual const lf::mesh::Entity & Entity(gdof_idx_t dofnum) const =0
retrieve unique entity at which a basis function is located
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
virtual ~DofHandler()=default
virtual Destructor
DofHandler & operator=(const DofHandler &)=default
Dof handler allowing variable local dof layouts.
Definition: dofhandler.h:472
std::vector< const lf::mesh::Entity * > dof_entities_
Definition: dofhandler.h:726
nonstd::span< const gdof_idx_t > InteriorGlobalDofIndices(const lf::mesh::Entity &entity) const override
global indices of shape functions associated with an entity_
Definition: dofhandler.cc:352
size_type NumInteriorDofs(const lf::mesh::Entity &entity) const override
provides number of shape functions associated with an entity
Definition: dofhandler.cc:384
DynamicFEDofHandler & operator=(const DynamicFEDofHandler &)=delete
Copy assignment is forbidden.
std::shared_ptr< const lf::mesh::Mesh > mesh_p_
Definition: dofhandler.h:722
DynamicFEDofHandler(DynamicFEDofHandler &&)=default
A DynamicFEDofHandler can be move constructed.
DynamicFEDofHandler & operator=(DynamicFEDofHandler &&)=default
A DynamicFEDofHandler can be moved into.
nonstd::span< const gdof_idx_t > GlobalDofIndices(const lf::mesh::Entity &entity) const override
access to indices of global dof's belonging to an entity
Definition: dofhandler.cc:333
DynamicFEDofHandler(std::shared_ptr< const lf::mesh::Mesh > mesh_p, LOCALDOFINFO &&locdof)
Set-up of dof handler.
Definition: dofhandler.h:523
std::array< std::vector< size_type >, 3 > offsets_
Definition: dofhandler.h:741
size_type NumLocalDofs(const lf::mesh::Entity &entity) const override
tells the number of degrees of freedom subordinate/_belonging_ to to an entity
Definition: dofhandler.cc:376
std::array< std::vector< gdof_idx_t >, 3 > dofs_
Definition: dofhandler.h:744
const lf::mesh::Entity & Entity(gdof_idx_t dofnum) const override
retrieve unique entity at which a basis function is located
Definition: dofhandler.h:707
std::shared_ptr< const lf::mesh::Mesh > Mesh() const override
Acess to underlying mesh object.
Definition: dofhandler.h:716
~DynamicFEDofHandler() override=default
Virtual destructor.
std::array< std::vector< size_type >, 3 > num_int_dofs_
Definition: dofhandler.h:739
DynamicFEDofHandler(const DynamicFEDofHandler &)=delete
It doesn't make much sense to copy construct a DynamicFEDofHandler.
size_type NumDofs() const override
total number of dof's handled by the object
Definition: dofhandler.h:675
Dofhandler for uniform finite element spaces.
Definition: dofhandler.h:257
~UniformFEDofHandler() override=default
Virtual Destructor.
void initIndexArrays()
initialization of internal index arrays
Definition: dofhandler.cc:135
UniformFEDofHandler(UniformFEDofHandler &&)=default
UniformFEDofHandler can be moved.
UniformFEDofHandler(std::shared_ptr< const lf::mesh::Mesh > mesh, dof_map_t dofmap)
Definition: dofhandler.cc:83
size_type GetNumLocalDofs(lf::base::RefEl ref_el_type, glb_idx_t) const
Definition: dofhandler.h:371
std::array< size_type, 3 > num_dofs_
Definition: dofhandler.h:449
std::array< std::vector< gdof_idx_t >, 3 > dofs_
Definition: dofhandler.h:447
nonstd::span< const gdof_idx_t > GlobalDofIndices(const lf::mesh::Entity &entity) const override
access to indices of global dof's belonging to an entity
Definition: dofhandler.cc:292
size_type NumInteriorDofs(const lf::mesh::Entity &entity) const override
provides number of shape functions associated with an entity
Definition: dofhandler.cc:324
size_type NumLocalDofs(const lf::mesh::Entity &entity) const override
tells the number of degrees of freedom subordinate/_belonging_ to to an entity
Definition: dofhandler.cc:319
UniformFEDofHandler(const UniformFEDofHandler &)=delete
Copy Construction doesn't make much sense for UniformFEDofHandler.
std::shared_ptr< const lf::mesh::Mesh > Mesh() const override
Acess to underlying mesh object.
Definition: dofhandler.h:345
const lf::mesh::Entity & Entity(gdof_idx_t dofnum) const override
retrieve unique entity at which a basis function is located
Definition: dofhandler.h:336
std::shared_ptr< const lf::mesh::Mesh > mesh_
Definition: dofhandler.h:440
nonstd::span< const gdof_idx_t > InteriorGlobalDofIndices(const lf::mesh::Entity &entity) const override
global indices of shape functions associated with an entity_
Definition: dofhandler.cc:314
size_type NumInteriorDofs(lf::base::RefEl ref_el_type) const
Definition: dofhandler.h:412
UniformFEDofHandler & operator=(UniformFEDofHandler &&)=default
Uniform FEDofHandler can be move assigned to.
std::map< lf::base::RefEl, base::size_type > dof_map_t
Construction from a map object.
Definition: dofhandler.h:274
std::vector< const lf::mesh::Entity * > dof_entities_
Definition: dofhandler.h:444
size_type NumDofs() const override
total number of dof's handled by the object
Definition: dofhandler.h:304
void InitTotalNumDofs()
compute number of shape functions covering an entity type
Definition: dofhandler.cc:125
UniformFEDofHandler & operator=(const UniformFEDofHandler &)=delete
Copy assigning a UniformFEDofHandler doesn't make much sense.
size_type NumCoveredDofs(lf::base::RefEl ref_el_type) const
Definition: dofhandler.h:384
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 representing a topological entity in a cellular complex
Definition: entity.h:39
virtual nonstd::span< const Entity *const > SubEntities(unsigned rel_codim) const =0
Return all sub entities of this entity that have the given codimension (w.r.t. this entity!...
D.o.f. index mapping and assembly facilities.
Definition: assemble.h:30
lf::base::size_type size_type
lf::base::glb_idx_t glb_idx_t
Eigen::Index gdof_idx_t
std::ostream & operator<<(std::ostream &o, const COOMatrix< SCALARTYPE > &mat)
Definition: coomatrix.h:229