deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\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
polynomials_vector_anisotropic.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) 2005 - 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
18#include <iomanip>
19#include <iostream>
20#include <memory>
21
22
24
25
26namespace
27{
33 std::vector<std::vector<Point<1>>>
34 create_anisotropic_support_points(const unsigned int dim,
35 const unsigned int normal_degree,
36 const unsigned int tangential_degree)
37 {
38 Assert(dim > 0 && dim <= 3, ExcImpossibleInDim(dim));
39
40 std::vector<std::vector<Point<1>>> points_normal_tangential(dim);
41 points_normal_tangential[0] =
42 normal_degree == 0 ? QMidpoint<1>().get_points() :
43 QGaussLobatto<1>(normal_degree + 1).get_points();
44 for (unsigned int d = 1; d < dim; ++d)
45 {
46 points_normal_tangential[d] =
47 tangential_degree == 0 ?
48 QMidpoint<1>().get_points() :
49 QGaussLobatto<1>(tangential_degree + 1).get_points();
50 }
51 return points_normal_tangential;
52 }
53
54
55
56 // Create nodal anisotropic polynomials as the tensor product of Lagrange
57 // polynomials on Gauss-Lobatto points of the given degrees in the normal and
58 // tangential directions, respectively (we could also choose Lagrange
59 // polynomials on Gauss points but those are slightly more expensive to handle
60 // in classes).
61 std::vector<std::vector<Polynomials::Polynomial<double>>>
62 create_aniso_polynomials(const unsigned int dim,
63 const unsigned int normal_degree,
64 const unsigned int tangential_degree)
65 {
66 std::vector<std::vector<Point<1>>> points_aniso;
67 points_aniso =
68 create_anisotropic_support_points(dim, normal_degree, tangential_degree);
69 std::vector<std::vector<Polynomials::Polynomial<double>>> pols(dim);
70 pols[0] = Polynomials::generate_complete_Lagrange_basis(points_aniso[0]);
71 for (unsigned int d = 1; d < dim; ++d)
72 pols[d] = Polynomials::generate_complete_Lagrange_basis(points_aniso[d]);
73 return pols;
74 }
75} // namespace
76
77
78
79template <int dim>
81 const unsigned int normal_degree,
82 const unsigned int tangential_degree,
83 const std::vector<unsigned int> &polynomial_ordering)
84 : TensorPolynomialsBase<dim>(std::min(normal_degree, tangential_degree),
85 n_polynomials(normal_degree, tangential_degree))
86 , normal_degree(normal_degree)
87 , tangential_degree(tangential_degree)
88 , polynomial_space(
89 create_aniso_polynomials(dim, normal_degree, tangential_degree))
90 , lexicographic_to_hierarchic(polynomial_ordering)
91 , hierarchic_to_lexicographic(
92 Utilities::invert_permutation(lexicographic_to_hierarchic))
93{
94 // create renumbering of the unknowns from the lexicographic order to the
95 // actual order required by the finite element class with unknowns on
96 // faces placed first
97 const unsigned int n_pols = polynomial_space.n();
98
99 // since we only store an anisotropic polynomial for the first component,
100 // we set up a second numbering to switch out the actual coordinate
101 // direction
102 renumber_aniso[0].resize(n_pols);
103 for (unsigned int i = 0; i < n_pols; ++i)
104 renumber_aniso[0][i] = i;
105 if (dim == 2)
106 {
107 // switch x and y component (i and j loops)
108 renumber_aniso[1].resize(n_pols);
109 for (unsigned int j = 0; j < normal_degree + 1; ++j)
110 for (unsigned int i = 0; i < tangential_degree + 1; ++i)
111 renumber_aniso[1][j * (tangential_degree + 1) + i] =
112 j + i * (normal_degree + 1);
113 }
114 if (dim == 3)
115 {
116 // switch x, y, and z component (i, j, k) -> (j, k, i)
117 renumber_aniso[1].resize(n_pols);
118 for (unsigned int k = 0; k < tangential_degree + 1; ++k)
119 for (unsigned int j = 0; j < normal_degree + 1; ++j)
120 for (unsigned int i = 0; i < tangential_degree + 1; ++i)
121 renumber_aniso[1][(k * (normal_degree + 1) + j) *
122 (tangential_degree + 1) +
123 i] =
124 j + (normal_degree + 1) * (k + i * (tangential_degree + 1));
125
126 // switch x, y, and z component (i, j, k) -> (k, i, j)
127 renumber_aniso[2].resize(n_pols);
128 for (unsigned int k = 0; k < normal_degree + 1; ++k)
129 for (unsigned int j = 0; j < tangential_degree + 1; ++j)
130 for (unsigned int i = 0; i < tangential_degree + 1; ++i)
131 renumber_aniso[2][(k * (tangential_degree + 1) + j) *
132 (tangential_degree + 1) +
133 i] =
134 k + (normal_degree + 1) * (i + j * (tangential_degree + 1));
135 }
136}
137
138
139
140template <int dim>
141void
143 const Point<dim> &unit_point,
144 std::vector<Tensor<1, dim>> &values,
145 std::vector<Tensor<2, dim>> &grads,
146 std::vector<Tensor<3, dim>> &grad_grads,
147 std::vector<Tensor<4, dim>> &third_derivatives,
148 std::vector<Tensor<5, dim>> &fourth_derivatives) const
149{
150 Assert(values.size() == this->n() || values.empty(),
151 ExcDimensionMismatch(values.size(), this->n()));
152 Assert(grads.size() == this->n() || grads.empty(),
153 ExcDimensionMismatch(grads.size(), this->n()));
154 Assert(grad_grads.size() == this->n() || grad_grads.empty(),
155 ExcDimensionMismatch(grad_grads.size(), this->n()));
156 Assert(third_derivatives.size() == this->n() || third_derivatives.empty(),
157 ExcDimensionMismatch(third_derivatives.size(), this->n()));
158 Assert(fourth_derivatives.size() == this->n() || fourth_derivatives.empty(),
159 ExcDimensionMismatch(fourth_derivatives.size(), this->n()));
160
161 std::vector<double> p_values;
162 std::vector<Tensor<1, dim>> p_grads;
163 std::vector<Tensor<2, dim>> p_grad_grads;
164 std::vector<Tensor<3, dim>> p_third_derivatives;
165 std::vector<Tensor<4, dim>> p_fourth_derivatives;
166
167 const unsigned int n_sub = polynomial_space.n();
168 p_values.resize((values.empty()) ? 0 : n_sub);
169 p_grads.resize((grads.empty()) ? 0 : n_sub);
170 p_grad_grads.resize((grad_grads.empty()) ? 0 : n_sub);
171 p_third_derivatives.resize((third_derivatives.empty()) ? 0 : n_sub);
172 p_fourth_derivatives.resize((fourth_derivatives.empty()) ? 0 : n_sub);
173
174 for (unsigned int d = 0; d < dim; ++d)
175 {
176 // First we copy the point. The polynomial space for component d
177 // consists of polynomials of degree k in x_d and degree k+1 in the
178 // other variables. in order to simplify this, we use the same
179 // AnisotropicPolynomial space and simply rotate the coordinates
180 // through all directions.
181 Point<dim> p;
182 for (unsigned int c = 0; c < dim; ++c)
183 p[c] = unit_point[(c + d) % dim];
184
185 polynomial_space.evaluate(p,
186 p_values,
187 p_grads,
188 p_grad_grads,
189 p_third_derivatives,
190 p_fourth_derivatives);
191
192 for (unsigned int i = 0; i < p_values.size(); ++i)
193 {
194 // Only the d-th entry is non-zero, the others get the value zero
195 Tensor<1, dim> val;
196 val[d] = p_values[renumber_aniso[d][i]];
197 values[lexicographic_to_hierarchic[i + d * n_sub]] = val;
198 }
199
200 for (unsigned int i = 0; i < p_grads.size(); ++i)
201 {
202 Tensor<2, dim> out;
203 for (unsigned int d1 = 0; d1 < dim; ++d1)
204 out[d][(d1 + d) % dim] = p_grads[renumber_aniso[d][i]][d1];
205 grads[lexicographic_to_hierarchic[i + d * n_sub]] = out;
206 }
207
208 for (unsigned int i = 0; i < p_grad_grads.size(); ++i)
209 {
210 Tensor<3, dim> out;
211 for (unsigned int d1 = 0; d1 < dim; ++d1)
212 for (unsigned int d2 = 0; d2 < dim; ++d2)
213 out[d][(d1 + d) % dim][(d2 + d) % dim] =
214 p_grad_grads[renumber_aniso[d][i]][d1][d2];
215 grad_grads[lexicographic_to_hierarchic[i + d * n_sub]] = out;
216 }
217
218 for (unsigned int i = 0; i < p_third_derivatives.size(); ++i)
219 {
220 Tensor<4, dim> out;
221 for (unsigned int d1 = 0; d1 < dim; ++d1)
222 for (unsigned int d2 = 0; d2 < dim; ++d2)
223 for (unsigned int d3 = 0; d3 < dim; ++d3)
224 out[d][(d1 + d) % dim][(d2 + d) % dim][(d3 + d) % dim] =
225 p_third_derivatives[renumber_aniso[d][i]][d1][d2][d3];
226 third_derivatives[lexicographic_to_hierarchic[i + d * n_sub]] = 0;
227 }
228
229 for (unsigned int i = 0; i < p_fourth_derivatives.size(); ++i)
230 {
231 Tensor<5, dim> out;
232 for (unsigned int d1 = 0; d1 < dim; ++d1)
233 for (unsigned int d2 = 0; d2 < dim; ++d2)
234 for (unsigned int d3 = 0; d3 < dim; ++d3)
235 for (unsigned int d4 = 0; d4 < dim; ++d4)
236 out[d][(d1 + d) % dim][(d2 + d) % dim][(d3 + d) %
237 dim][(d4 + d) % dim] =
238 p_fourth_derivatives[renumber_aniso[d][i]][d1][d2][d3][d4];
239 fourth_derivatives[lexicographic_to_hierarchic[i + d * n_sub]] = out;
240 }
241 }
242}
243
244
245
246template <int dim>
247std::string
249{
250 return "VectorAnisotropic";
251}
252
253
254
255template <int dim>
256unsigned int
258 const unsigned int normal_degree,
259 const unsigned int tangential_degree)
260{
261 return dim * (normal_degree + 1) *
262 Utilities::pow(tangential_degree + 1, dim - 1);
263}
264
265
266
267template <int dim>
268unsigned int
270{
271 return tangential_degree;
272}
273
274
275
276template <int dim>
277unsigned int
279{
280 return normal_degree;
281}
282
283
284
285template <int dim>
286std::unique_ptr<TensorPolynomialsBase<dim>>
288{
289 return std::make_unique<PolynomialsVectorAnisotropic<dim>>(*this);
290}
291
292
293
294template <int dim>
295std::vector<Point<dim>>
297{
298 Assert(dim > 0 && dim <= 3, ExcImpossibleInDim(dim));
299 const std::vector<std::vector<Point<1>>> points_aniso =
300 create_anisotropic_support_points(dim, normal_degree, tangential_degree);
301 const unsigned int n_sub = polynomial_space.n();
302 std::vector<Point<dim>> points(dim * n_sub);
303 points.resize(n_polynomials(normal_degree, tangential_degree));
304 for (unsigned int d = 0; d < dim; ++d)
305 for (unsigned int i = 0; i < n_sub; ++i)
306 {
307 unsigned int renumbered_index = renumber_aniso[d][i];
308 std::array<unsigned int, dim> indices_points_anisotropic;
309 indices_points_anisotropic[0] = renumbered_index % (normal_degree + 1);
310 if (dim > 1)
311 {
312 renumbered_index /= (normal_degree + 1);
313 indices_points_anisotropic[1] =
314 renumbered_index % (tangential_degree + 1);
315 }
316 if (dim > 2)
317 indices_points_anisotropic[2] =
318 renumbered_index / (tangential_degree + 1);
319 for (unsigned int c = 0; c < dim; ++c)
320 {
321 points[lexicographic_to_hierarchic[i + d * n_sub]][(c + d) % dim] =
322 points_aniso[c][indices_points_anisotropic[c]][0];
323 }
324 }
325 return points;
326}
327
328
329
333
334
Definition point.h:111
std::array< std::vector< unsigned int >, dim > renumber_aniso
PolynomialsVectorAnisotropic(const unsigned int degree_normal, const unsigned int degree_tangential, const std::vector< unsigned int > &polynomial_ordering)
const AnisotropicPolynomials< dim > polynomial_space
std::vector< Point< dim > > get_polynomial_support_points() const
virtual std::unique_ptr< TensorPolynomialsBase< dim > > clone() const override
void evaluate(const Point< dim > &unit_point, std::vector< Tensor< 1, dim > > &values, std::vector< Tensor< 2, dim > > &grads, std::vector< Tensor< 3, dim > > &grad_grads, std::vector< Tensor< 4, dim > > &third_derivatives, std::vector< Tensor< 5, dim > > &fourth_derivatives) const override
static unsigned int n_polynomials(const unsigned int normal_degree, const unsigned int tangential_degree)
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
std::vector< Polynomial< double > > generate_complete_Lagrange_basis(const std::vector< Point< 1 > > &points)
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
STL namespace.