deal.II version 9.8.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
fe_nedelec_nodal.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13
17
19
20#include <deal.II/fe/fe.h>
22#include <deal.II/fe/fe_nedelec.templates.h>
24#include <deal.II/fe/fe_tools.h>
25#include <deal.II/fe/mapping.h>
26
27#include <deal.II/matrix_free/shape_info.templates.h>
28
29#include <memory>
30#include <sstream>
31
32
34
35
36// ---------------- polynomial class for FE_NedelecNodal ---------------
37
38namespace
39{
40 // Return a vector of "dofs per object" where the components of the returned
41 // vector refer to:
42 // 0 = vertex
43 // 1 = edge
44 // 2 = face (which is a cell in 2d)
45 // 3 = cell.
46 std::vector<unsigned int>
47 get_nedelec_dpo_vector(const unsigned int dim, const unsigned int degree)
48 {
49 std::vector<unsigned int> dpo(dim + 1);
50 dpo[0] = 0;
51 dpo[1] = degree + 1;
52 unsigned int dofs_per_face_component = degree + 1;
53 for (unsigned int d = 2; d < dim; ++d)
54 dofs_per_face_component *= degree;
55 dpo[dim - 1] = (dim - 1) * dofs_per_face_component;
56 dpo[dim] = dim * degree * dofs_per_face_component;
57
58 return dpo;
59 }
60
61} // namespace
62
63
64
65// --------------------- actual implementation of element --------------------
66
67template <int dim>
69 : FE_PolyTensor<dim>(
71 degree + 1,
73 FiniteElementData<dim>(get_nedelec_dpo_vector(dim, degree),
74 dim,
75 degree + 1,
77 std::vector<bool>(
78 PolynomialsVectorAnisotropic<dim>::n_polynomials(degree, degree + 1),
79 true),
80 std::vector<ComponentMask>(
81 PolynomialsVectorAnisotropic<dim>::n_polynomials(degree, degree + 1),
82 std::vector<bool>(dim, true)))
83{
84 Assert(dim >= 2, ExcImpossibleInDim(dim));
85
86 const std::vector<unsigned int> &renumber =
92
94 this->n_dofs_per_cell());
95
96 PolynomialsVectorAnisotropic<dim> polynomials(degree, degree + 1, renumber);
97 QMidpoint<1> gauss;
99 this->unit_support_points.resize(this->dofs_per_cell);
100
101 const unsigned int n_pols = polynomials.n() / dim;
102 for (unsigned int k = 0; k < (dim > 2 ? degree + 2 : 1); ++k)
103 for (unsigned int j = 0; j < (dim > 1 ? degree + 2 : 1); ++j)
104 for (unsigned int i = 0; i < degree + 1; ++i)
105 {
107 [renumber[(k * (degree + 2) + j) * (degree + 1) + i]][0] =
108 (degree == 0 ? gauss.point(i)[0] : gl.point(i)[0]);
109 if (dim > 1)
111 [renumber[(k * (degree + 2) + j) * (degree + 1) + i]][1] =
112 gl.point(j)[0];
113 if (dim > 2)
115 [renumber[(k * (degree + 2) + j) * (degree + 1) + i]][2] =
116 gl.point(k)[0];
117 }
118 if (dim > 1)
119 for (unsigned int k = 0; k < (dim > 2 ? degree + 2 : 1); ++k)
120 for (unsigned int j = 0; j < degree + 1; ++j)
121 for (unsigned int i = 0; i < degree + 2; ++i)
122 {
124 [renumber[n_pols + (k * (degree + 1) + j) * (degree + 2) + i]]
125 [0] = gl.point(i)[0];
127 [renumber[n_pols + (k * (degree + 1) + j) * (degree + 2) + i]]
128 [1] = (degree == 0 ? gauss.point(j)[0] : gl.point(j)[0]);
129 if (dim > 2)
131 [renumber[n_pols + (k * (degree + 1) + j) * (degree + 2) + i]]
132 [2] = gl.point(k)[0];
133 }
134 if (dim > 2)
135 for (unsigned int k = 0; k < degree + 1; ++k)
136 for (unsigned int j = 0; j < degree + 2; ++j)
137 for (unsigned int i = 0; i < degree + 2; ++i)
138 {
140 [renumber[2 * n_pols + (k * (degree + 2) + j) * (degree + 2) + i]]
141 [0] = gl.point(i)[0];
143 [renumber[2 * n_pols + (k * (degree + 2) + j) * (degree + 2) + i]]
144 [1] = gl.point(j)[0];
146 [renumber[2 * n_pols + (k * (degree + 2) + j) * (degree + 2) + i]]
147 [2] = (degree == 0 ? gauss.point(k)[0] : gl.point(k)[0]);
148 }
149}
150
151
152
153template <int dim>
154std::string
156{
157 /*Note, that the FETools::get_fe_by_name function depends on the particular
158 format of the string this function returns. So, they have to be kept in
159 sync.*/
160
161 // Note, that this->degree is the maximal polynomial degree and is thus one
162 // higher than the argument given to the constructor.
163 return "FE_NedelecNodal<" + std::to_string(dim) + ">(" +
164 std::to_string(this->degree - 1) + ")";
165}
166
167
168template <int dim>
169std::unique_ptr<FiniteElement<dim, dim>>
171{
172 return std::make_unique<FE_NedelecNodal<dim>>(*this);
173}
174
175template <int dim>
176void
178 const std::vector<Vector<double>> &support_point_values,
179 std::vector<double> &nodal_values) const
180{
181 Assert(support_point_values.size() == this->generalized_support_points.size(),
182 ExcDimensionMismatch(support_point_values.size(),
183 this->generalized_support_points.size()));
184 Assert(nodal_values.size() == this->n_dofs_per_cell(),
185 ExcDimensionMismatch(nodal_values.size(), this->n_dofs_per_cell()));
186 Assert(support_point_values[0].size() == this->n_components(),
187 ExcDimensionMismatch(support_point_values[0].size(),
188 this->n_components()));
189
190 // First do interpolation on lines. The component evaluated there depends
191 // on the face direction and orientation.
192 unsigned int base = 0;
193 for (unsigned int l = 0; l < GeometryInfo<dim>::lines_per_cell;
194 ++l, base += this->n_dofs_per_line())
195 {
196 for (unsigned int i = 0; i < this->n_dofs_per_line(); ++i)
197 {
198 nodal_values[base + i] =
199 support_point_values[base + i](l < 8 ? ((l % 4) / 2) ^ 1 : 2);
200 }
201 }
202
203 if (dim == 3)
204 {
205 std::vector<unsigned int> componentFreq(dim,
206 this->n_dofs_per_quad(0) / 2);
207 unsigned int index = -1;
208 for (unsigned int f = 0; f < GeometryInfo<dim>::faces_per_cell; ++f)
209 {
211 componentFreq[index] = 0;
212 for (unsigned int compInd = 0; compInd < dim; ++compInd)
213 {
214 for (unsigned int compQuant = 0;
215 compQuant < componentFreq[compInd];
216 ++compQuant)
217 {
218 nodal_values[base + compQuant] =
219 support_point_values[base + compQuant](compInd);
220 }
221 base += componentFreq[compInd];
222 }
223 componentFreq[index] = this->n_dofs_per_quad(f) / 2;
224 }
225 }
226 // The remaining points form dim chunks, one for each component.
227 const unsigned int istep = (this->n_dofs_per_cell() - base) / dim;
228 Assert((this->n_dofs_per_cell() - base) % dim == 0, ExcInternalError());
229
230 int f = 0;
231 while (base < this->n_dofs_per_cell())
232 {
233 for (unsigned int i = 0; i < istep; ++i)
234 {
235 nodal_values[base + i] = support_point_values[base + i](f);
236 }
237 base += istep;
238 ++f;
239 }
240 Assert(base == this->n_dofs_per_cell(), ExcInternalError());
241}
242
243
244
245template <int dim>
246std::vector<unsigned int>
248 const unsigned int degree) const
249{
250 const unsigned int n_dofs_edges =
251 (dim == 2) ? 4 * (degree + 1) : 12 * (degree + 1);
252 const unsigned int n_dofs_faces_3D = 2 * 6 * (degree * (degree + 1));
253 const unsigned n_dofs_per_component_face = degree * (degree + 1);
254 const unsigned int n_dofs_D_1 =
255 (dim == 2) ? n_dofs_edges : n_dofs_edges + n_dofs_faces_3D;
256 std::vector<unsigned int> lexicographic_renumbering(
257 (dim == 2) ? 2 * (degree + 1) * (degree + 2) :
258 3 * (degree + 1) * (degree + 2) * (degree + 2));
259 unsigned int ind_lex_numbering = 0;
260
261 // Component 1
262 for (unsigned int i = 2 * (degree + 1); i < 3 * (degree + 1); ++i)
263 lexicographic_renumbering[ind_lex_numbering++] = i;
264 const unsigned int n_dofs_before =
265 n_dofs_edges + ((dim == 3) ? 8 * n_dofs_per_component_face : 0);
266 for (unsigned int i = n_dofs_before;
267 i < n_dofs_before + n_dofs_per_component_face;
268 ++i)
269 lexicographic_renumbering[ind_lex_numbering++] = i;
270 for (unsigned int i = 3 * (degree + 1); i < 4 * (degree + 1); ++i)
271 lexicographic_renumbering[ind_lex_numbering++] = i;
272 if (dim == 3)
273 {
274 for (unsigned int i = 0; i < degree; ++i)
275 {
276 for (unsigned int j = 0; j < degree + 1; ++j)
277 lexicographic_renumbering[ind_lex_numbering++] =
278 n_dofs_edges + 4 * n_dofs_per_component_face + i * (degree + 1) +
279 j;
280 for (unsigned int j = 0; j < n_dofs_per_component_face; ++j)
281 lexicographic_renumbering[ind_lex_numbering++] =
282 n_dofs_D_1 + i * n_dofs_per_component_face + j;
283 for (unsigned int j = 0; j < degree + 1; ++j)
284 lexicographic_renumbering[ind_lex_numbering++] =
285 n_dofs_edges + 6 * n_dofs_per_component_face + i * (degree + 1) +
286 j;
287 }
288 for (unsigned int i = 6 * (degree + 1); i < 7 * (degree + 1); ++i)
289 lexicographic_renumbering[ind_lex_numbering++] = i;
290 for (unsigned int i = n_dofs_edges + 10 * n_dofs_per_component_face;
291 i < n_dofs_edges + 11 * n_dofs_per_component_face;
292 ++i)
293 lexicographic_renumbering[ind_lex_numbering++] = i;
294 for (unsigned int i = 7 * (degree + 1); i < 8 * (degree + 1); ++i)
295 lexicographic_renumbering[ind_lex_numbering++] = i;
296 }
297
298 // Component 2
299 unsigned int n_dofs_faces_before =
300 n_dofs_edges + ((dim == 3) ? 9 : 1) * n_dofs_per_component_face;
301 for (unsigned int i = 0; i < degree + 1; ++i)
302 {
303 lexicographic_renumbering[ind_lex_numbering++] = i;
304 for (unsigned int j = n_dofs_faces_before + i * degree;
305 j < n_dofs_faces_before + (i + 1) * degree;
306 ++j)
307 {
308 lexicographic_renumbering[ind_lex_numbering++] = j;
309 }
310 lexicographic_renumbering[ind_lex_numbering++] = (degree + 1) + i;
311 }
312
313 if (dim == 3)
314 {
315 for (unsigned int i = 0; i < n_dofs_per_component_face; ++i)
316 {
317 lexicographic_renumbering[ind_lex_numbering++] = n_dofs_edges + i;
318 for (unsigned int j = 0; j < degree; j++)
319 {
320 lexicographic_renumbering[ind_lex_numbering++] =
321 n_dofs_D_1 + n_dofs_per_component_face * degree + i * degree +
322 j;
323 }
324 lexicographic_renumbering[ind_lex_numbering++] =
325 n_dofs_edges + 2 * n_dofs_per_component_face + i;
326 }
327 unsigned int n_dofs_before = n_dofs_edges + 11 * degree * (degree + 1);
328 for (unsigned int i = 0; i < degree + 1; i++)
329 {
330 lexicographic_renumbering[ind_lex_numbering++] = 4 * (degree + 1) + i;
331 for (unsigned int j = 0; j < degree; j++)
332 {
333 lexicographic_renumbering[ind_lex_numbering++] =
334 n_dofs_before + i * degree + j;
335 }
336 lexicographic_renumbering[ind_lex_numbering++] = 5 * (degree + 1) + i;
337 }
338 }
339 // Component 3
340 if (dim == 3)
341 {
342 for (unsigned int i = 0; i < degree + 1; i++)
343 {
344 lexicographic_renumbering[ind_lex_numbering++] = 8 * (degree + 1) + i;
345 unsigned int n_dofs_before =
346 n_dofs_edges + 5 * n_dofs_per_component_face;
347 for (unsigned int j = 0; j < degree; j++)
348 {
349 lexicographic_renumbering[ind_lex_numbering++] =
350 n_dofs_before + i * degree + j;
351 }
352 lexicographic_renumbering[ind_lex_numbering++] = 9 * (degree + 1) + i;
353 for (unsigned int j = 0; j < degree; ++j)
354 {
355 lexicographic_renumbering[ind_lex_numbering++] =
356 n_dofs_edges + n_dofs_per_component_face + i * degree + j;
357 n_dofs_before = n_dofs_D_1 +
358 2 * degree * n_dofs_per_component_face +
359 i * degree * degree + j * degree;
360 for (unsigned int k = 0; k < degree; k++)
361 {
362 lexicographic_renumbering[ind_lex_numbering++] =
363 n_dofs_before + k;
364 }
365 lexicographic_renumbering[ind_lex_numbering++] =
366 n_dofs_edges + 3 * n_dofs_per_component_face + i * degree + j;
367 }
368 lexicographic_renumbering[ind_lex_numbering++] =
369 10 * (degree + 1) + i;
370 for (unsigned int j = 0; j < degree; j++)
371 {
372 lexicographic_renumbering[ind_lex_numbering++] =
373 n_dofs_edges + 7 * n_dofs_per_component_face + i * degree + j;
374 }
375 lexicographic_renumbering[ind_lex_numbering++] =
376 11 * (degree + 1) + i;
377 }
378 }
379 return lexicographic_renumbering;
380}
381
382
383template <int dim>
386 const unsigned int codim) const
387{
388 Assert(codim <= dim, ExcImpossibleInDim(dim));
389 (void)codim;
390
391 // vertex/line/face/cell domination
392 // --------------------------------
393 if (const FE_NedelecNodal<dim> *fe_nedelec_nodal_other =
394 dynamic_cast<const FE_NedelecNodal<dim> *>(&fe_other))
395 {
396 if (this->degree < fe_nedelec_nodal_other->degree)
398 else if (this->degree == fe_nedelec_nodal_other->degree)
400 else
402 }
403 else if (const FE_Nothing<dim> *fe_nothing =
404 dynamic_cast<const FE_Nothing<dim> *>(&fe_other))
405 {
406 if (fe_nothing->is_dominating())
408 else
409 // the FE_Nothing has no degrees of freedom and it is typically used
410 // in a context where we don't require any continuity along the
411 // interface
413 }
414
417}
418
419
420// explicit instantiations
421#include "fe/fe_nedelec_nodal.inst"
422
423
424
virtual std::unique_ptr< FiniteElement< dim, dim > > clone() const override
std::vector< unsigned int > get_lexicographic_numbering(const unsigned int degree) const
virtual void convert_generalized_support_point_values_to_dof_values(const std::vector< Vector< double > > &support_point_values, std::vector< double > &nodal_values) const override
virtual FiniteElementDomination::Domination compare_for_domination(const FiniteElement< dim > &fe_other, const unsigned int codim=0) const override final
virtual std::string get_name() const override
FE_NedelecNodal(const unsigned int p)
std::vector< MappingKind > mapping_kind
FE_PolyTensor(const TensorPolynomialsBase< dim > &polynomials, const FiniteElementData< dim > &fe_data, const std::vector< bool > &restriction_is_additive_flags, const std::vector< ComponentMask > &nonzero_components)
const unsigned int degree
Definition fe_data.h:450
unsigned int n_dofs_per_cell() const
unsigned int n_dofs_per_line() const
unsigned int n_components() const
unsigned int n_dofs_per_quad(unsigned int face_no=0) const
const unsigned int dofs_per_cell
Definition fe_data.h:434
FiniteElementData(const std::vector< unsigned int > &dofs_per_object, const unsigned int n_components, const unsigned int degree, const Conformity conformity=unknown, const BlockIndices &block_indices=BlockIndices())
Definition fe_data.cc:112
FiniteElement(const FiniteElementData< dim > &fe_data, const std::vector< bool > &restriction_is_additive_flags, const std::vector< ComponentMask > &nonzero_components)
std::vector< Point< dim > > unit_support_points
Definition fe.h:2585
std::vector< Point< dim > > generalized_support_points
Definition fe.h:2598
std::vector< Point< dim > > get_polynomial_support_points() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
#define AssertDimension(dim1, dim2)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
@ mapping_nedelec
Definition mapping.h:129
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
STL namespace.
static constexpr std::array< unsigned int, faces_per_cell > unit_normal_direction