LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
dofhandler.cc
1/***************************************************************************
2 * LehrFEM++ - A simple C++ finite element libray for teaching
3 * Developed from 2018 at the Seminar of Applied Mathematics of ETH Zurich,
4 * lead developers Dr. R. Casagrande and Prof. R. Hiptmair
5 ***************************************************************************/
6
15#include "dofhandler.h"
16
17namespace lf::assemble {
18
19// Implementation of output operator for interface class
20std::ostream &operator<<(std::ostream &o, const DofHandler &dof_handler) {
21 PrintInfo(o, dof_handler, 0);
22 return o;
23}
24
25void PrintInfo(std::ostream &stream, const DofHandler &dof_handler,
26 unsigned ctrl) {
27 // Obtain pointer to the underlying mesh
28 auto mesh = dof_handler.Mesh();
29 // Number of degrees of freedom managed by the DofHandler object
30 const lf::assemble::size_type N_dofs(dof_handler.NumDofs());
31
32 stream << "DofHandler(" << dof_handler.NumDofs() << " dofs)";
33 if (ctrl > 0) {
34 // More detailed output
35 stream << std::endl;
36 if (ctrl % 2 == 0) {
37 for (lf::base::dim_t codim = 0; codim <= mesh->DimMesh(); codim++) {
38 // Visit all entities of a specific codimension
39 for (const lf::mesh::Entity *e : mesh->Entities(codim)) {
40 // Fetch unique index of current entity supplied by mesh object
41 const lf::base::glb_idx_t e_idx = mesh->Index(*e);
42 // Number of shape functions covering current entity
43 const lf::assemble::size_type no_dofs(dof_handler.NumLocalDofs(*e));
44 // Obtain global indices of those shape functions ...
46 dof_handler.GlobalDofIndices(*e));
47 // and print them
48 stream << *e << ' ' << e_idx << ": " << no_dofs << " dofs = [";
49 for (const lf::assemble::gdof_idx_t &dof : doflist) {
50 stream << dof << ' ';
51 }
52 stream << ']';
53 if (ctrl % 5 == 0) {
54 // Also output indices of interior shape functions
56 dof_handler.InteriorGlobalDofIndices(*e));
57 stream << " int = [";
58 for (lf::assemble::gdof_idx_t int_dof : intdoflist) {
59 stream << int_dof << ' ';
60 }
61 stream << ']';
62 }
63 stream << std::endl;
64 }
65 }
66 }
67 if (ctrl % 3 == 0) {
68 // List entities associated wit the dofs managed by the current
69 // DofHandler object
70 for (lf::assemble::gdof_idx_t dof_idx = 0; dof_idx < N_dofs; dof_idx++) {
71 const lf::mesh::Entity &e(dof_handler.Entity(dof_idx));
72 stream << "dof " << dof_idx << " -> " << e << " " << mesh->Index(e)
73 << std::endl;
74 }
75 }
76 }
77}
78
79// ----------------------------------------------------------------------
80// Implementation UniformFEDofHandler
81// ----------------------------------------------------------------------
82
84 std::shared_ptr<const lf::mesh::Mesh> mesh, dof_map_t dofmap)
85 : mesh_(std::move(mesh)), num_dofs_() {
86 LF_ASSERT_MSG((mesh_->DimMesh() == 2), "Can handle 2D meshes only");
87
88 // For checking whether a key was found
89 auto map_end = dofmap.end();
90
91 // Get no of interior dof specified for nodes
92 auto map_el_pt = dofmap.find(lf::base::RefEl::kPoint());
93 if (map_el_pt != map_end) {
94 num_loc_dof_point_ = map_el_pt->second;
95 }
96
97 // Get no of interior dof specified for edges
98 auto map_el_ed = dofmap.find(lf::base::RefEl::kSegment());
99 if (map_el_ed != map_end) {
100 num_loc_dof_segment_ = map_el_ed->second;
101 }
102
103 // Get no of interior dof specified for triangles
104 auto map_el_tr = dofmap.find(lf::base::RefEl::kTria());
105 if (map_el_tr != map_end) {
106 num_loc_dof_tria_ = map_el_tr->second;
107 }
108
109 // Get no of interior dof specified for quads
110 auto map_el_qd = dofmap.find(lf::base::RefEl::kQuad());
111 if (map_el_qd != map_end) {
112 num_loc_dof_quad_ = map_el_qd->second;
113 }
114
115 // If an entity type is not represented in the map, we assume that
116 // no shape functions are attached to those entities
117
118 // Initialize total number of shape functions covering an entity.
120
121 // Initializatin of dof index arrays
123}
124
133}
134
136 // This method assumes a proper initialization
137 // of the data in no_loc_dof_* and num_dofs_, num_dof_tria, num_dofs_quad_
138 gdof_idx_t dof_idx = 0;
139
140 // Step I: Set indices for shape functions on nodes
141 // Total number of degrees of freedom on nodes (entities of co-dim = 2)
142 const size_type no_nodes = mesh_->NumEntities(2);
143 const size_type num_dofs_nodes = no_nodes * num_dofs_[kNodeOrd];
144 dofs_[kNodeOrd].resize(num_dofs_nodes);
145 // Run through nodes in the order given by their numbering
146 for (glb_idx_t node_idx = 0; node_idx < no_nodes; node_idx++) {
147 const mesh::Entity *node_p{mesh_->EntityByIndex(2, node_idx)};
148 LF_ASSERT_MSG(mesh_->Index(*node_p) == node_idx, "Node index mismatch");
149 // Beginning of section for concrete node in the dof index vector
150 // for entities of co-dimension 2
151 glb_idx_t node_dof_offset = node_idx * num_dofs_[kNodeOrd];
152 for (unsigned j = 0; j < num_loc_dof_point_; j++) {
153 dofs_[kNodeOrd][node_dof_offset++] = dof_idx;
154 dof_entities_.push_back(node_p); // Store entity for current dof
155 dof_idx++; // Move on to next index
156 }
157 }
158
159 // Step II: Set indices for shape functions on edges
160 // Total number of degrees of freedom belonging to edges (entities of co-dim =
161 // 1)
162 const size_type no_edges = mesh_->NumEntities(1);
163 const size_type num_dofs_edges = no_edges * num_dofs_[kEdgeOrd];
164 dofs_[kEdgeOrd].resize(num_dofs_edges);
165 // Visit all edges
166 // Old implementation, see remarks above
167 // for (const lf::mesh::Entity &edge : mesh_->Entities(1)) {
168 for (glb_idx_t edge_idx = 0; edge_idx < no_edges; edge_idx++) {
169 // Obtain pointer to edge entity
170 const mesh::Entity *edge_p{mesh_->EntityByIndex(1, edge_idx)};
171 LF_ASSERT_MSG(mesh_->Index(*edge_p) == edge_idx, "Edge index mismatch");
172 // Beginning of section for concrete edge in the dof index vector
173 // for entities of co-dimension 1
174 glb_idx_t edge_dof_offset = edge_idx * num_dofs_[kEdgeOrd];
175
176 // Obtain indices for basis functions sitting at endpoints
177 for (const lf::mesh::Entity *endpoint : edge_p->SubEntities(1)) {
178 const glb_idx_t ep_idx(mesh_->Index(*endpoint));
179 glb_idx_t ep_dof_offset = ep_idx * num_dofs_[kNodeOrd];
180 // Copy indices of shape functions from nodes to edge
181 for (unsigned j = 0; j < num_dofs_[kNodeOrd]; j++) {
182 dofs_[kEdgeOrd][edge_dof_offset++] = dofs_[kNodeOrd][ep_dof_offset++];
183 }
184 }
185 // Set indices for interior edge degrees of freedom
186 for (unsigned j = 0; j < num_loc_dof_segment_; j++) {
187 dofs_[kEdgeOrd][edge_dof_offset++] = dof_idx;
188 dof_entities_.push_back(edge_p);
189 dof_idx++;
190 }
191 }
192
193 // Step III: Set indices for shape functions on cells
194 const size_type no_cells = mesh_->NumEntities(0);
195 const size_type max_num_dof_cells = no_cells * num_dofs_[kCellOrd];
196 dofs_[kCellOrd].resize(max_num_dof_cells);
197
198 // Number of (non-)interior shape functins for edges
199 const size_type no_int_dof_edge = num_loc_dof_segment_;
200 const size_type num_ext_dof_edge = num_dofs_[kEdgeOrd] - no_int_dof_edge;
201
202 // Visit all cells
203 // Old implementation without strong link between cell
204 // indices and ordering of global shape functions
205 // for (const lf::mesh::Entity &cell : mesh_->Entities(0)) {
206 for (glb_idx_t cell_idx = 0; cell_idx < no_cells; cell_idx++) {
207 // Obtain pointer to current ell
208 const mesh::Entity *cell_p{mesh_->EntityByIndex(0, cell_idx)};
209 LF_ASSERT_MSG(cell_idx == mesh_->Index(*cell_p), "cell index mismatch");
210 // Offset for cell dof indices in large dof index vector
211 glb_idx_t cell_dof_offset = cell_idx * num_dofs_[kCellOrd];
212
213 // Obtain indices for basis functions in vertices
214 for (const lf::mesh::Entity *vertex : cell_p->SubEntities(2)) {
215 const glb_idx_t vt_idx(mesh_->Index(*vertex));
216 glb_idx_t vt_dof_offset = vt_idx * num_dofs_[kNodeOrd];
217 // Copy indices of shape functions from nodes to cell
218 for (unsigned j = 0; j < num_dofs_[kNodeOrd]; j++) {
219 dofs_[kCellOrd][cell_dof_offset++] = dofs_[kNodeOrd][vt_dof_offset++];
220 }
221 }
222
223 // Collect indices of interior shape functions of edges
224 // Internal ordering will depend on the orientation of the edge
225 auto edge_orientations = cell_p->RelativeOrientations();
226 auto edges = cell_p->SubEntities(1);
227 // Loop over edges
228 const size_type no_edges_cell = cell_p->RefEl().NumSubEntities(1);
229 for (int ed_sub_idx = 0; ed_sub_idx < no_edges_cell; ed_sub_idx++) {
230 const glb_idx_t edge_idx = mesh_->Index(*edges[ed_sub_idx]);
231 glb_idx_t edge_int_dof_offset =
232 edge_idx * num_dofs_[kEdgeOrd] + num_ext_dof_edge;
233 // Copy indices of shape functions from edges to cell
234 // The order, in which they are copied depends on the relative orientation
235 // of the edge w.r.t. the cell
236 switch (edge_orientations[ed_sub_idx]) {
238 for (int j = 0; j < no_int_dof_edge; j++) {
239 dofs_[kCellOrd][cell_dof_offset++] =
240 dofs_[kEdgeOrd][edge_int_dof_offset + j];
241 }
242 break;
243 }
245 for (int j = static_cast<int>(no_int_dof_edge - 1); j >= 0; j--) {
246 dofs_[kCellOrd][cell_dof_offset++] =
247 dofs_[kEdgeOrd][edge_int_dof_offset + j];
248 }
249 break;
250 }
251 } // end switch
252 }
253
254 // Set indices for interior cell degrees of freedom depending on the type of
255 // cell. Here we add new degrees of freedom
256 size_type num_int_dofs_cell;
257 if (cell_p->RefEl() == lf::base::RefEl::kTria()) {
258 num_int_dofs_cell = num_loc_dof_tria_;
259 } else if (cell_p->RefEl() == lf::base::RefEl::kQuad()) {
260 num_int_dofs_cell = num_loc_dof_quad_;
261 } else {
262 LF_ASSERT_MSG(
263 false, "Illegal cell type; only triangles and quads are supported");
264 }
265
266 // enlist new interior cell-associated dofs
267 for (unsigned j = 0; j < num_int_dofs_cell; j++) {
268 dofs_[kCellOrd][cell_dof_offset++] = dof_idx;
269 dof_entities_.push_back(cell_p);
270 dof_idx++;
271 }
272 }
273 // Finally store total number of shape functions on the mesh.
274 num_dof_ = dof_idx;
275} // end constructor
276
278 lf::base::RefEl ref_el_type, glb_idx_t entity_index) const {
279 // Co-dimension of entity in a 2D mesh
280 const dim_t codim = 2 - ref_el_type.Dimension();
281 const size_type no_covered_dofs = NumCoveredDofs(ref_el_type);
282
283 LF_ASSERT_MSG((mesh_->NumEntities(codim) > entity_index),
284 "Index " << entity_index << " out of range");
285 // Pointers to range of dof indices
286 const gdof_idx_t *begin =
287 dofs_[codim].data() + (num_dofs_[codim] * entity_index);
288 const gdof_idx_t *end = begin + no_covered_dofs;
289 return {begin, end};
290}
291
293 const lf::mesh::Entity &entity) const {
294 return GlobalDofIndices(entity.RefEl(), mesh_->Index(entity));
295}
296
298 lf::base::RefEl ref_el_type, glb_idx_t entity_index) const {
299 // Co-dimension of entity in a 2D mesh
300 const dim_t codim = 2 - ref_el_type.Dimension();
301 const size_type no_covered_dofs = NumCoveredDofs(ref_el_type);
302 const size_type no_loc_dofs = NumInteriorDofs(ref_el_type);
303
304 LF_ASSERT_MSG((mesh_->NumEntities(codim) > entity_index),
305 "Index " << entity_index << " out of range");
306 // Pointers to range of dof indices
307 const gdof_idx_t *begin =
308 dofs_[codim].data() + (num_dofs_[codim] * entity_index);
309 const gdof_idx_t *end = begin + no_covered_dofs;
310 begin += (no_covered_dofs - no_loc_dofs);
311 return {begin, end};
312}
313
315 const lf::mesh::Entity &entity) const {
316 return InteriorGlobalDofIndices(entity.RefEl(), mesh_->Index(entity));
317}
318
320 const lf::mesh::Entity &entity) const {
321 return GetNumLocalDofs(entity.RefEl(), 0);
322}
323
325 const lf::mesh::Entity &entity) const {
326 return NumInteriorDofs(entity.RefEl());
327}
328
329// ----------------------------------------------------------------------
330// Implementation DynamicFEDofHandler
331// ----------------------------------------------------------------------
332
334 const lf::mesh::Entity &entity) const {
335 // Topological type
336 const lf::base::RefEl ref_el_type = entity.RefEl();
337 // Co-dimension of entity in a 2D mesh
338 const dim_t codim = 2 - ref_el_type.Dimension();
339 // Index of current mesh entity
340 const glb_idx_t entity_index = mesh_p_->Index(entity);
341 // Offset of dof indices for current entity
342 const size_type idx_offset = offsets_[codim][entity_index];
343 // Number of shape functions covering current entity
344 const size_type no_covered_dofs =
345 offsets_[codim][entity_index + 1] - idx_offset;
346 // Pointers to range of dof indices
347 const gdof_idx_t *begin = dofs_[codim].data() + idx_offset;
348 const gdof_idx_t *end = begin + no_covered_dofs;
349 return {begin, end};
350}
351
353 const lf::mesh::Entity &entity) const {
354 // Topological type
355 const lf::base::RefEl ref_el_type = entity.RefEl();
356 // Co-dimension of entity in a 2D mesh
357 const dim_t codim = 2 - ref_el_type.Dimension();
358 // Index of current mesh entity
359 const glb_idx_t entity_index = mesh_p_->Index(entity);
360 // Offset of indices for current entity
361 const size_type idx_offset = offsets_[codim][entity_index];
362 // Number of shape functions covering current entity
363 const size_type no_covered_dofs =
364 offsets_[codim][entity_index + 1] - idx_offset;
365 // Number of shape functions associated with the current entity
366 const size_type no_loc_dofs = num_int_dofs_[codim][entity_index];
367 // Pointers to range of dof indices
368 const gdof_idx_t *begin = dofs_[codim].data() + idx_offset;
369 const gdof_idx_t *end = begin + no_covered_dofs;
370 // Move pointer to location of indices for interior dofs
371 // This is the only difference to GlobalDofIndices()
372 begin += (no_covered_dofs - no_loc_dofs);
373 return {begin, end};
374}
375
377 const lf::mesh::Entity &entity) const {
378 const lf::base::RefEl ref_el_type = entity.RefEl();
379 const dim_t codim = 2 - ref_el_type.Dimension();
380 const glb_idx_t entity_index = mesh_p_->Index(entity);
381 return (offsets_[codim][entity_index + 1] - offsets_[codim][entity_index]);
382}
383
385 const lf::mesh::Entity &entity) const {
386 const lf::base::RefEl ref_el_type = entity.RefEl();
387 const dim_t codim = 2 - ref_el_type.Dimension();
388 const glb_idx_t entity_index = mesh_p_->Index(entity);
389 const size_type no_loc_dofs = num_int_dofs_[codim][entity_index];
390 return no_loc_dofs;
391}
392
393} // namespace lf::assemble
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.
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 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 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
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
std::shared_ptr< const lf::mesh::Mesh > mesh_p_
Definition: dofhandler.h:722
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
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
std::array< std::vector< size_type >, 3 > num_int_dofs_
Definition: dofhandler.h:739
void initIndexArrays()
initialization of internal index arrays
Definition: dofhandler.cc:135
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
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
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
void InitTotalNumDofs()
compute number of shape functions covering an entity type
Definition: dofhandler.cc:125
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
constexpr dim_t Dimension() const
Return the dimension of this reference element.
Definition: ref_el.h:201
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!...
virtual base::RefEl RefEl() const =0
Describes the reference element type of this entity.
unsigned int dim_t
type for dimensions and co-dimensions and numbers derived from them
Definition: base.h:36
unsigned int glb_idx_t
type for global index of mesh entities (nodes, edges, cells)
Definition: base.h:28
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
void PrintInfo(std::ostream &stream, const DofHandler &dof_handler, unsigned ctrl)
Definition: dofhandler.cc:25
std::ostream & operator<<(std::ostream &o, const COOMatrix< SCALARTYPE > &mat)
Definition: coomatrix.h:229
lf::base::dim_t dim_t