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_simplex.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) 2020 - 2026 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
14#include <deal.II/base/config.h>
15
18#include <deal.II/base/mpi.h>
20#include <deal.II/base/point.h>
25#include <deal.II/base/table.h>
26#include <deal.II/base/tensor.h>
28
30
31#include <Kokkos_Macros.hpp>
32
33#include <algorithm>
34#include <cmath>
35#include <cstdlib>
36#include <memory>
37#include <string>
38#include <vector>
39
41
42
43template <int dim>
45 const unsigned int degree,
46 const std::vector<Point<dim>> &support_points)
47 : ScalarPolynomialsVandermondeBase<dim>(degree, support_points.size())
48{
49 if constexpr (dim == 1)
50 AssertDimension(degree + 1, support_points.size());
51 else if constexpr (dim == 2)
52 {
53 const unsigned int n_dofs = (degree + 1) * (degree + 2) / 2;
54 AssertDimension(n_dofs, support_points.size());
55 }
56 else if constexpr (dim == 3)
57 {
58 const unsigned int n_dofs =
59 (degree + 1) * (degree + 2) * (degree + 3) / 6;
60 AssertDimension(n_dofs, support_points.size());
61 }
62 else
64
65 this->reinit(support_points);
66}
67
68
69
70template <int dim>
71double
73 dim>::evaluate_orthogonal_basis_function_by_degree(const unsigned int i,
74 const unsigned int j,
75 const unsigned int k,
76 const Point<dim> &p) const
77{
78 AssertIndexRange(i + j + k, this->degree() + 1);
79
80 if constexpr (dim == 1)
81 Assert(j == 0 && k == 0, ExcInternalError());
82 else if constexpr (dim == 2)
83 Assert(k == 0, ExcInternalError());
84 else if constexpr (dim == 3)
85 {
86 // nothing to assert
87 }
88 else
90
91 const double x = p[0];
92 const double y = dim > 1 ? p[1] : 0.0;
93 const double z = dim > 2 ? p[2] : 0.0;
94
95 // the basis function looks like
96 // P_i^{0,0}(2x/(1-y-z)-1) * (1-y-z)^i
97 // P_j^{2*i+1,0}(2*y/(1-z)-1)*(1-z)^j
98 // P_k^{2 (i+j)+2,0}(2 z - 1)
99 // like in 2d use the homogenized Jacobi polynomials
100 // define t = 1 - y - z and s = 1 - z
101 // the first term becomes
102 // Q_i^{0,0}(x,t) = P_i^{0,0}(2x/(1-y-z)-1) * (1-y-z)^i
103 // and the second
104 // Q_j^{2i+1,0}(y,s) = P_j^{2i+1,0}(2y/(1-z)-1) * (1-z)^j
105
106 // in 1D it holds that j,k = 0, such the (homogenized) Jacobi polynomials
107 // describing the y and z contributions just equal to 1
108 // in 2D it holds that k = 0, again this multiplies by 1
109
110 const double s = 1 - z;
111 const double t = 1 - y - z;
112
113 const double Qi =
114 Polynomials::jacobi_polynomial_homogenized_value<double>(i, 0, 0, x, t);
115
116 const double Qj = Polynomials::jacobi_polynomial_homogenized_value<double>(
117 j, 2 * i + 1, 0, y, s);
118
119 const double Pk = Polynomials::jacobi_polynomial_value<double>(
120 k, 2 * (i + j) + 2, 0, z, true);
121
122 const double phi = Qi * Qj * Pk;
123
124 if (std::fabs(phi) < 1e-14)
125 return 0.0;
126
127 return phi;
128}
129
130
131
132template <int dim>
133double
135 const unsigned int i,
136 const Point<dim> &p) const
137{
138 AssertIndexRange(i, this->n());
139
140 if constexpr (dim == 1)
141 {
142 // return the value of the orthogonal basis
143 return evaluate_orthogonal_basis_function_by_degree(i, 0, 0, p);
144 }
145 else if constexpr (dim == 2)
146 {
147 // find corresponding entry to i
148 // it holds 0 <= j + k <= degree
149 for (unsigned int j = 0, counter = 0; j < this->degree() + 1; ++j)
150 for (unsigned int k = 0; k < this->degree() + 1 - j; ++k, ++counter)
151 if (counter == i)
152 return evaluate_orthogonal_basis_function_by_degree(j, k, 0, p);
153 }
154 else if constexpr (dim == 3)
155 {
156 // find corresponding entry to i
157 // it holds 0 <= j + k + l <= degree
158 for (unsigned int j = 0, counter = 0; j < this->degree() + 1; ++j)
159 for (unsigned int k = 0; k < this->degree() + 1 - j; ++k)
160 for (unsigned int l = 0; l < this->degree() + 1 - j - k;
161 ++l, ++counter)
162 if (counter == i)
163 return evaluate_orthogonal_basis_function_by_degree(j, k, l, p);
164 }
165
167 return 0;
168}
169
170
171
172template <int dim>
176 const unsigned int j,
177 const unsigned int k,
178 const Point<dim> &p) const
179{
180 AssertIndexRange(i + j + k, this->degree() + 1);
181
182 if constexpr (dim == 1)
183 Assert(j == 0 && k == 0, ExcInternalError());
184 else if constexpr (dim == 2)
185 Assert(k == 0, ExcInternalError());
186 else if constexpr (dim == 3)
187 {
188 // nothing to assert
189 }
190 else
192
193 Tensor<1, dim> grad;
194
195 const double x = p[0];
196 const double y = dim > 1 ? p[1] : 0.0;
197 const double z = dim > 2 ? p[2] : 0.0;
198
199 // define t = 1 - y - z and s = 1 - z then
200 // P_i^{0,0}(2x/t-1) * t^i
201 // P_j^{2*i+1,0}(2*y/s-1)*s^j
202 // P_k^{2 (i+j)+2,0}(2 z - 1)
203 // =
204 // Q_i^{0,0}(x,t)
205 // Q_j^{2*i+1,0}(y,s)
206 // P_k^{2*(i+j)+2,0}(2 z - 1)
207
208 // The 1D (2D) cases are again covered by having j,k = 0 (k = 0) such that
209 // the contributions to the value equal to one and the contributions to the
210 // derivative equal to zero
211
212 // get the derivatives over the product rule
213 const double s = 1 - z;
214 const double ds_dz = -1.0;
215
216 const double t = 1 - y - z;
217 const double dt_dy = -1.0;
218 const double dt_dz = -1.0;
219
220 const double Qi =
221 Polynomials::jacobi_polynomial_homogenized_value<double>(i, 0, 0, x, t);
222 const double Qj = Polynomials::jacobi_polynomial_homogenized_value<double>(
223 j, 2 * i + 1, 0, y, s);
224 const double Pk = Polynomials::jacobi_polynomial_value<double>(
225 k, 2 * (i + j) + 2, 0, z, true);
226
227 const double dQi_dx =
228 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
229 1, 0, i, 0, 0, x, t);
230 const double dQi_dt =
231 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
232 0, 1, i, 0, 0, x, t);
233
234 const double dQj_dy =
235 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
236 1, 0, j, 2 * i + 1, 0, y, s);
237 const double dQj_ds =
238 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
239 0, 1, j, 2 * i + 1, 0, y, s);
240
241 const auto dPk_dz = Polynomials::jacobi_polynomial_derivative<double>(
242 k, 2 * (i + j) + 2, 0, z, true);
243
244
245 grad[0] = dQi_dx * Qj * Pk;
246 if constexpr (dim > 1)
247 grad[1] = dQi_dt * dt_dy * Qj * Pk + Qi * dQj_dy * Pk;
248 if constexpr (dim > 2)
249 grad[2] =
250 dQi_dt * dt_dz * Qj * Pk + Qi * dQj_ds * ds_dz * Pk + Qi * Qj * dPk_dz;
251
252 for (unsigned int d = 0; d < dim; ++d)
253 if (std::fabs(grad[d]) < 1e-14)
254 grad[d] = 0.0;
255
256 return grad;
257}
258
259
260
261template <int dim>
264 const unsigned int i,
265 const Point<dim> &p) const
266{
267 AssertIndexRange(i, this->n());
268
269 if constexpr (dim == 1)
270 {
271 // entrance to i corresponse to degree
272 return evaluate_orthogonal_basis_derivative_by_degree(i, 0, 0, p);
273 }
274 else if constexpr (dim == 2)
275 {
276 // find corresponding entrance to i
277 // it holds 0 <= j + k <= degree
278 for (unsigned int j = 0, counter = 0; j < this->degree() + 1; ++j)
279 for (unsigned int k = 0; k < this->degree() + 1 - j; ++k, ++counter)
280 if (counter == i)
281 return evaluate_orthogonal_basis_derivative_by_degree(j, k, 0, p);
282 }
283 else if constexpr (dim == 3)
284 {
285 // find corresponding entrance to i
286 // it holds 0 <= j + k + l <= degree
287 for (unsigned int j = 0, counter = 0; j < this->degree() + 1; ++j)
288 for (unsigned int k = 0; k < this->degree() + 1 - j; ++k)
289 for (unsigned int l = 0; l < this->degree() + 1 - j - k;
290 ++l, ++counter)
291 if (counter == i)
292 return evaluate_orthogonal_basis_derivative_by_degree(j, k, l, p);
293 }
294
296 return Tensor<1, dim>();
297}
298
299
300
301template <int dim>
305 const unsigned int j,
306 const unsigned int k,
307 const Point<dim> &p) const
308{
309 AssertIndexRange(i + j + k, this->degree() + 1);
310
311 if constexpr (dim == 1)
312 Assert(j == 0 && k == 0, ExcInternalError());
313 else if constexpr (dim == 2)
314 Assert(k == 0, ExcInternalError());
315 else if constexpr (dim == 3)
316 {
317 // nothing to assert
318 }
319 else
321
322 Tensor<2, dim> deriv;
323
324 const double x = p[0];
325 const double y = dim > 1 ? p[1] : 0.0;
326 const double z = dim > 2 ? p[2] : 0.0;
327
328 // define t = 1 - y - z and s = 1 - z then
329 // P_i^{0,0}(2x/t-1) * t^i
330 // P_j^{2*i+1,0}(2*y/s-1)*s^j
331 // P_k^{2 (i+j)+2,0}(2 z - 1)
332 // =
333 // Q_i^{0,0}(x,t)
334 // Q_j^{2*i+1,0}(y,s)
335 // P_k^{2*(i+j)+2,0}(2 z - 1)
336
337 // The 1D (2D) cases are again covered by having j,k = 0 (k = 0) such that
338 // the contributions to the value equal to one and the contributions to the
339 // derivatives equal to zero
340
341 // get the second derivatives over the product rule
342 const double s = 1 - z;
343 const double ds_dz = -1.0;
344
345 const double t = 1 - y - z;
346 const double dt_dy = -1.0;
347 const double dt_dz = -1.0;
348
349 // get the values of each polynomial
350 const double Qi =
351 Polynomials::jacobi_polynomial_homogenized_value<double>(i, 0, 0, x, t);
352 const double Qj = Polynomials::jacobi_polynomial_homogenized_value<double>(
353 j, 2 * i + 1, 0, y, s);
354 const double Pk = Polynomials::jacobi_polynomial_value<double>(
355 k, 2 * (i + j) + 2, 0, z, true);
356
357 // get the first derivatives of Qi
358 const double dQi_dx =
359 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
360 1, 0, i, 0, 0, x, t);
361 const double dQi_dt =
362 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
363 0, 1, i, 0, 0, x, t);
364
365 // get the first derivatives of Qj
366 const double dQj_dy =
367 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
368 1, 0, j, 2 * i + 1, 0, y, s);
369 const double dQj_ds =
370 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
371 0, 1, j, 2 * i + 1, 0, y, s);
372
373 // get the first derivative of Pk
374 const double dPk_dz = Polynomials::jacobi_polynomial_derivative<double>(
375 k, 2 * (i + j) + 2, 0, z, true);
376
377 // get the second and mixed derivatives of Qi
378 const double dQi_dx_dx =
379 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
380 2, 0, i, 0, 0, x, t);
381 const double dQi_dx_dt =
382 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
383 1, 1, i, 0, 0, x, t);
384 const double dQi_dt_dt =
385 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
386 0, 2, i, 0, 0, x, t);
387
388 // get the second and mixed derivatives of Qj
389 const double dQj_dy_dy =
390 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
391 2, 0, j, 2 * i + 1, 0, y, s);
392 const double dQj_dy_ds =
393 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
394 1, 1, j, 2 * i + 1, 0, y, s);
395 const double dQj_ds_ds =
396 Polynomials::jacobi_polynomial_homogenized_derivative<double>(
397 0, 2, j, 2 * i + 1, 0, y, s);
398
399 // get the second derivative of Pk
400 const double dPk_dz_dz =
401 Polynomials::jacobi_polynomial_kth_derivative<double>(
402 2, k, 2 * (i + j) + 2, 0, z, true);
403
404 // now compute the entries
405 deriv[0][0] = dQi_dx_dx * Qj * Pk;
406
407 if constexpr (dim > 1)
408 {
409 deriv[0][1] = dQi_dx_dt * dt_dy * Qj * Pk + dQi_dx * dQj_dy * Pk;
410 deriv[1][0] = deriv[0][1];
411 deriv[1][1] = dQi_dt_dt * Qj * Pk + dQi_dt * dt_dy * dQj_dy * Pk * 2.0 +
412 Qi * dQj_dy_dy * Pk;
413
414 if constexpr (dim > 2)
415 {
416 deriv[1][2] =
417 dQi_dt_dt * Qj * Pk + dQi_dt * dt_dy * dQj_ds * ds_dz * Pk +
418 dQi_dt * dt_dy * Qj * dPk_dz + dQi_dt * dt_dy * dQj_dy * Pk +
419 Qi * dQj_dy_ds * ds_dz * Pk + Qi * dQj_dy * dPk_dz;
420 deriv[2][1] = deriv[1][2];
421
422 deriv[2][0] = dQi_dx_dt * dt_dz * Qj * Pk +
423 dQi_dx * dQj_ds * ds_dz * Pk + dQi_dx * Qj * dPk_dz;
424 deriv[0][2] = deriv[2][0];
425
426 deriv[2][2] =
427 dQi_dt_dt * Qj * Pk + 2.0 * dQi_dt * dt_dz * dQj_ds * ds_dz * Pk +
428 2.0 * dQi_dt * dt_dz * Qj * dPk_dz + Qi * dQj_ds_ds * Pk +
429 2.0 * Qi * dQj_ds * ds_dz * dPk_dz + Qi * Qj * dPk_dz_dz;
430 }
431 }
432
433 for (unsigned int d = 0; d < dim; ++d)
434 for (unsigned int e = 0; e < dim; ++e)
435 if (std::fabs(deriv[d][e]) < 1e-14)
436 deriv[d][e] = 0.0;
437
438 return deriv;
439}
440
441
442
443template <int dim>
446 const unsigned int i,
447 const Point<dim> &p) const
448{
449 AssertIndexRange(i, this->n());
450
451 if constexpr (dim == 1)
452 {
453 // entrance to i corresponse to degree
454 return evaluate_orthogonal_basis_2nd_derivative_by_degree(i, 0, 0, p);
455 }
456 else if constexpr (dim == 2)
457 {
458 // find corresponding entrance to i
459 // it holds 0 <= j + k <= degree
460 for (unsigned int j = 0, counter = 0; j < this->degree() + 1; ++j)
461 for (unsigned int k = 0; k < this->degree() + 1 - j; ++k, ++counter)
462 if (counter == i)
463 return evaluate_orthogonal_basis_2nd_derivative_by_degree(j,
464 k,
465 0,
466 p);
467 }
468 else if constexpr (dim == 3)
469 {
470 // find corresponding entrance to i
471 // it holds 0 <= j + k + l <= degree
472 for (unsigned int j = 0, counter = 0; j < this->degree() + 1; ++j)
473 for (unsigned int k = 0; k < this->degree() + 1 - j; ++k)
474 for (unsigned int l = 0; l < this->degree() + 1 - j - k;
475 ++l, ++counter)
476 if (counter == i)
477 return evaluate_orthogonal_basis_2nd_derivative_by_degree(j,
478 k,
479 l,
480 p);
481 }
482
484 return Tensor<2, dim>();
485}
486
487
488
489template <int dim>
490void
492 const Point<dim> &unit_point,
493 std::vector<double> &values,
494 std::vector<Tensor<1, dim>> &grads,
495 std::vector<Tensor<2, dim>> &grad_grads,
496 std::vector<Tensor<3, dim>> &third_derivatives,
497 std::vector<Tensor<4, dim>> &fourth_derivatives) const
498{
499 (void)third_derivatives;
500 (void)fourth_derivatives;
501
502 if (values.size() == this->n())
503 for (unsigned int i = 0; i < this->n(); ++i)
504 values[i] = this->compute_value(i, unit_point);
505
506 if (grads.size() == this->n())
507 for (unsigned int i = 0; i < this->n(); ++i)
508 grads[i] = this->compute_grad(i, unit_point);
509
510 if (grad_grads.size() == this->n())
511 for (unsigned int i = 0; i < this->n(); ++i)
512 grad_grads[i] = this->compute_grad_grad(i, unit_point);
513}
514
515
516
517template <int dim>
518std::string
520{
521 return "ScalarLagrangePolynomialSimplex";
522}
523
524
525
526template <int dim>
527std::unique_ptr<ScalarPolynomialsBase<dim>>
529{
530 return std::make_unique<ScalarLagrangePolynomialSimplex<dim>>(*this);
531}
532
533
534
538
Definition point.h:111
ScalarLagrangePolynomialSimplex(const unsigned int degree, const std::vector< Point< dim > > &support_points)
Tensor< 1, dim > evaluate_orthogonal_basis_derivative_by_degree(const unsigned int i, const unsigned int j, const unsigned int k, const Point< dim > &p) const override
virtual std::unique_ptr< ScalarPolynomialsBase< dim > > clone() const override
std::string name() const override
Tensor< 1, dim > evaluate_orthogonal_basis_derivative(const unsigned int i, const Point< dim > &p) const override
void evaluate(const Point< dim > &unit_point, std::vector< double > &values, std::vector< Tensor< 1, dim > > &grads, std::vector< Tensor< 2, dim > > &grad_grads, std::vector< Tensor< 3, dim > > &third_derivatives, std::vector< Tensor< 4, dim > > &fourth_derivatives) const override
virtual Tensor< 2, dim > evaluate_orthogonal_basis_2nd_derivative_by_degree(const unsigned int i, const unsigned int j, const unsigned int k, const Point< dim > &p) const override
virtual Tensor< 2, dim > evaluate_orthogonal_basis_2nd_derivative(const unsigned int i, const Point< dim > &p) const override
double evaluate_orthogonal_basis_function(const unsigned int i, const Point< dim > &p) const override
virtual unsigned int degree() const
void reinit(const std::vector< Point< dim > > &support_points)
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
std::size_t size
Definition mpi.cc:733