deal.II version GIT relicensing-6842-g793a97d2aa 2026-10-02 14:00: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_barycentric.h
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) 2021 - 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#ifndef dealii_simplex_barycentric_polynomials_h
15#define dealii_simplex_barycentric_polynomials_h
16
17#include <deal.II/base/config.h>
18
21#include <deal.II/base/mpi.h>
22#include <deal.II/base/point.h>
24#include <deal.II/base/table.h>
26#include <deal.II/base/tensor.h>
28
29#include <Kokkos_Macros.hpp>
30
31#include <algorithm>
32#include <array>
33#include <cstddef>
34#include <limits>
35#include <memory>
36#include <ostream>
37#include <string>
38#include <vector>
39
41
94template <int dim, typename Number = double>
96{
97public:
102
107 const Number coefficient);
108
113 monomial(const unsigned int d);
114
121 void
122 print(std::ostream &out) const;
123
128 degrees() const;
129
134 operator-() const;
135
139 template <typename Number2>
141 operator+(const Number2 &a) const;
142
146 template <typename Number2>
148 operator-(const Number2 &a) const;
149
153 template <typename Number2>
155 operator*(const Number2 &a) const;
156
160 template <typename Number2>
162 operator/(const Number2 &a) const;
163
169
175
180 operator*(const BarycentricPolynomial<dim, Number> &multiplicand) const;
181
186 barycentric_derivative(const unsigned int coordinate) const;
187
192 derivative(const unsigned int coordinate) const;
193
197 Number
198 value(const Point<dim> &point) const;
199
203 std::size_t
204 memory_consumption() const;
205
206protected:
211
221 index_to_indices(const std::size_t &index,
222 const TableIndices<dim + 1> &extents);
223};
224
228template <int dim>
230{
231public:
236
240 using GradType = std::array<PolyType, dim>;
241
245 using HessianType = std::array<GradType, dim>;
246
250 using ThirdDerivativesType = std::array<HessianType, dim>;
251
255 using FourthDerivativesType = std::array<ThirdDerivativesType, dim>;
256
260 static constexpr unsigned int dimension = dim;
261
266 get_fe_p_basis(const unsigned int degree);
267
272 const std::vector<BarycentricPolynomial<dim>> &polynomials);
273
277 // We need to define the destructor to work around a compiler bug with hipcc
278 // 6.4. Using default also triggers the error.
279 // NOLINTNEXTLINE(modernize-use-equals-default)
281
286 operator[](const std::size_t i) const;
287
291 void
292 evaluate(const Point<dim> &unit_point,
293 std::vector<double> &values,
294 std::vector<Tensor<1, dim>> &grads,
295 std::vector<Tensor<2, dim>> &grad_grads,
296 std::vector<Tensor<3, dim>> &third_derivatives,
297 std::vector<Tensor<4, dim>> &fourth_derivatives) const override;
298
302 double
303 compute_value(const unsigned int i, const Point<dim> &p) const override;
304
309 compute_1st_derivative(const unsigned int i,
310 const Point<dim> &p) const override;
311
316 compute_2nd_derivative(const unsigned int i,
317 const Point<dim> &p) const override;
318
323 compute_3rd_derivative(const unsigned int i,
324 const Point<dim> &p) const override;
325
330 compute_4th_derivative(const unsigned int i,
331 const Point<dim> &p) const override;
332
337 compute_grad(const unsigned int i, const Point<dim> &p) const override;
338
343 compute_grad_grad(const unsigned int i, const Point<dim> &p) const override;
344
348 virtual std::size_t
349 memory_consumption() const override;
350
354 std::string
355 name() const override;
356
360 virtual std::unique_ptr<ScalarPolynomialsBase<dim>>
361 clone() const override;
362
363protected:
364 std::vector<PolyType> polys;
365 std::vector<GradType> poly_grads;
366 std::vector<HessianType> poly_hessians;
367 std::vector<ThirdDerivativesType> poly_third_derivatives;
368 std::vector<FourthDerivativesType> poly_fourth_derivatives;
369};
370
371// non-member template functions for algebra
372
376template <int dim, typename Number1, typename Number2>
379{
380 return bp * Number1(a);
381}
382
386template <int dim, typename Number1, typename Number2>
389{
390 return bp + Number1(a);
391}
392
396template <int dim, typename Number1, typename Number2>
399{
400 return bp - Number1(a);
401}
402
406template <int dim, typename Number>
407std::ostream &
408operator<<(std::ostream &out, const BarycentricPolynomial<dim, Number> &bp)
409{
410 bp.print(out);
411 return out;
412}
413
414// Template function definitions
415
416// BarycentricPolynomial:
417template <int dim, typename Number>
419{
420 TableIndices<dim + 1> extents;
421 for (unsigned int d = 0; d < dim + 1; ++d)
422 extents[d] = 1;
423 coefficients.reinit(extents);
424
425 coefficients(TableIndices<dim + 1>{}) = Number();
426}
427
428
429
430template <int dim, typename Number>
432 const TableIndices<dim + 1> &powers,
433 const Number coefficient)
434{
435 TableIndices<dim + 1> extents;
436 for (unsigned int d = 0; d < dim + 1; ++d)
437 extents[d] = powers[d] + 1;
438 coefficients.reinit(extents);
439
440 coefficients(powers) = coefficient;
441}
442
443
444
445template <int dim, typename Number>
448{
449 AssertIndexRange(d, dim + 1);
450 TableIndices<dim + 1> indices;
451 indices[d] = 1;
452 return BarycentricPolynomial<dim, Number>(indices, Number(1));
453}
454
455
456
457template <int dim, typename Number>
458void
460{
461 const auto &coeffs = this->coefficients;
462 auto first = index_to_indices(0, coeffs.size());
463 bool print_plus = false;
464 if (coeffs(first) != Number())
465 {
466 out << coeffs(first);
467 print_plus = true;
468 }
469 for (std::size_t i = 1; i < coeffs.n_elements(); ++i)
470 {
471 const auto indices = index_to_indices(i, coeffs.size());
472 if (coeffs(indices) == Number())
473 continue;
474 if (print_plus)
475 out << " + ";
476 out << coeffs(indices);
477 for (unsigned int d = 0; d < dim + 1; ++d)
478 {
479 if (indices[d] != 0)
480 out << " * t" << d << '^' << indices[d];
481 }
482 print_plus = true;
483 }
484
485 if (!print_plus)
486 out << Number();
487}
488
489
490
491template <int dim, typename Number>
494{
495 auto deg = coefficients.size();
496 for (unsigned int d = 0; d < dim + 1; ++d)
497 deg[d] -= 1;
498 return deg;
499}
500
501
502
503template <int dim, typename Number>
506{
507 return *this * Number(-1);
508}
509
510
511
512template <int dim, typename Number>
513template <typename Number2>
516{
518 result.coefficients(index_to_indices(0, result.coefficients.size())) += a;
519
520 return result;
521}
522
523
524
525template <int dim, typename Number>
526template <typename Number2>
529{
530 return *this + (-a);
531}
532
533
534
535template <int dim, typename Number>
536template <typename Number2>
539{
540 if (a == Number2())
541 {
543 }
544
546 for (std::size_t i = 0; i < result.coefficients.n_elements(); ++i)
547 {
548 const auto index = index_to_indices(i, result.coefficients.size());
549 result.coefficients(index) *= a;
550 }
551
552 return result;
553}
554
555
556
557template <int dim, typename Number>
558template <typename Number2>
561{
562 Assert(a != Number2(), ExcDivideByZero());
563 return *this * (Number(1) / Number(a));
564}
565
566
567
568template <int dim, typename Number>
571 const BarycentricPolynomial<dim, Number> &augend) const
572{
574 for (unsigned int d = 0; d < dim + 1; ++d)
575 {
576 deg[d] = std::max(degrees()[d], augend.degrees()[d]);
577 }
578
579 BarycentricPolynomial<dim, Number> result(deg, Number());
580
581 auto add_coefficients = [&](const Table<dim + 1, Number> &in) {
582 for (std::size_t i = 0; i < in.n_elements(); ++i)
583 {
584 const auto index = index_to_indices(i, in.size());
585 result.coefficients(index) += in(index);
586 }
587 };
588
589 add_coefficients(this->coefficients);
590 add_coefficients(augend.coefficients);
591 return result;
592}
593
594
595
596template <int dim, typename Number>
599 const BarycentricPolynomial<dim, Number> &augend) const
600{
601 return *this + (-augend);
602}
603
604
605
606template <int dim, typename Number>
609 const BarycentricPolynomial<dim, Number> &multiplicand) const
610{
612 for (unsigned int d = 0; d < dim + 1; ++d)
613 {
614 deg[d] = multiplicand.degrees()[d] + degrees()[d];
615 }
616
617 BarycentricPolynomial<dim, Number> result(deg, Number());
618
619 const auto &coef_1 = this->coefficients;
620 const auto &coef_2 = multiplicand.coefficients;
621 auto &coef_out = result.coefficients;
622
623 for (std::size_t i1 = 0; i1 < coef_1.n_elements(); ++i1)
624 {
625 const auto index_1 = index_to_indices(i1, coef_1.size());
626 for (std::size_t i2 = 0; i2 < coef_2.n_elements(); ++i2)
627 {
628 const auto index_2 = index_to_indices(i2, coef_2.size());
629
630 TableIndices<dim + 1> index_out;
631 for (unsigned int d = 0; d < dim + 1; ++d)
632 index_out[d] = index_1[d] + index_2[d];
633 coef_out(index_out) += coef_1(index_1) * coef_2(index_2);
634 }
635 }
636
637 return result;
638}
639
640
641
642template <int dim, typename Number>
645 const unsigned int coordinate) const
646{
647 AssertIndexRange(coordinate, dim + 1);
648
649 if (degrees()[coordinate] == 0)
651
652 auto deg = degrees();
653 deg[coordinate] -= 1;
655 std::numeric_limits<Number>::max());
656 const auto &coeffs_in = coefficients;
657 auto &coeffs_out = result.coefficients;
658 for (std::size_t i = 0; i < coeffs_out.n_elements(); ++i)
659 {
660 const auto out_index = index_to_indices(i, coeffs_out.size());
661 auto input_index = out_index;
662 input_index[coordinate] += 1;
663
664 coeffs_out(out_index) = coeffs_in(input_index) * input_index[coordinate];
665 }
666
667 return result;
668}
669
670
671
672template <int dim, typename Number>
675 const unsigned int coordinate) const
676{
677 AssertIndexRange(coordinate, dim);
678 return -barycentric_derivative(0) + barycentric_derivative(coordinate + 1);
679}
680
681
682
683template <int dim, typename Number>
684Number
686{
687 // TODO: this is probably not numerically stable for higher order.
688 // We really need some version of Horner's method.
689 Number result = {};
690
691 // Begin by converting point (which is in Cartesian coordinates) to
692 // barycentric coordinates:
693 std::array<Number, dim + 1> b_point;
694 b_point[0] = 1.0;
695 for (unsigned int d = 0; d < dim; ++d)
696 {
697 b_point[0] -= point[d];
698 b_point[d + 1] = point[d];
699 }
700
701 // Now evaluate the polynomial at the computed barycentric point:
702 for (std::size_t i = 0; i < coefficients.n_elements(); ++i)
703 {
704 const auto indices = index_to_indices(i, coefficients.size());
705 const auto coef = coefficients(indices);
706 if (coef == Number())
707 continue;
708
709 auto temp = Number(1);
710 for (unsigned int d = 0; d < dim + 1; ++d)
711 temp *= Utilities::pow(b_point[d], indices[d]);
712 result += coef * temp;
713 }
714
715 return result;
716}
717
718
719
720template <int dim, typename Number>
721std::size_t
723{
724 return coefficients.memory_consumption();
725}
726
727
728
729template <int dim, typename Number>
732 const std::size_t &index,
733 const TableIndices<dim + 1> &extents)
734{
736 auto temp = index;
737
738 for (unsigned int n = 0; n < dim + 1; ++n)
739 {
740 std::size_t slice_size = 1;
741 for (unsigned int n2 = n + 1; n2 < dim + 1; ++n2)
742 slice_size *= extents[n2];
743 result[n] = temp / slice_size;
744 temp %= slice_size;
745 }
746 return result;
747}
748
749
750
751template <int dim>
754{
755 AssertIndexRange(i, polys.size());
756 return polys[i];
757}
758
760
761#endif
*  *  reference operator*() const
BarycentricPolynomial< dim, Number > operator*(const Number2 &a) const
std::size_t memory_consumption() const
BarycentricPolynomial< dim, Number > operator+(const Number2 &a) const
TableIndices< dim+1 > degrees() const
Table< dim+1, Number > coefficients
BarycentricPolynomial< dim, Number > barycentric_derivative(const unsigned int coordinate) const
Number value(const Point< dim > &point) const
static TableIndices< dim+1 > index_to_indices(const std::size_t &index, const TableIndices< dim+1 > &extents)
BarycentricPolynomial< dim, Number > operator/(const Number2 &a) const
BarycentricPolynomial< dim, Number > operator-() const
void print(std::ostream &out) const
static BarycentricPolynomial< dim, Number > monomial(const unsigned int d)
BarycentricPolynomial< dim, Number > derivative(const unsigned int coordinate) const
std::array< HessianType, dim > ThirdDerivativesType
Tensor< 1, dim > compute_grad(const unsigned int i, const Point< dim > &p) const override
std::array< PolyType, dim > GradType
virtual std::size_t memory_consumption() const override
Tensor< 2, dim > compute_grad_grad(const unsigned int i, const Point< dim > &p) const override
std::array< ThirdDerivativesType, dim > FourthDerivativesType
std::vector< GradType > poly_grads
std::string name() const override
Tensor< 3, dim > compute_3rd_derivative(const unsigned int i, const Point< dim > &p) const override
Tensor< 1, dim > compute_1st_derivative(const unsigned int i, const Point< dim > &p) const override
Tensor< 2, dim > compute_2nd_derivative(const unsigned int i, const Point< dim > &p) const override
static constexpr unsigned int dimension
std::vector< PolyType > polys
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
double compute_value(const unsigned int i, const Point< dim > &p) const override
const BarycentricPolynomial< dim > & operator[](const std::size_t i) const
std::vector< ThirdDerivativesType > poly_third_derivatives
std::array< GradType, dim > HessianType
virtual std::unique_ptr< ScalarPolynomialsBase< dim > > clone() const override
Tensor< 4, dim > compute_4th_derivative(const unsigned int i, const Point< dim > &p) const override
std::vector< HessianType > poly_hessians
static BarycentricPolynomials< dim > get_fe_p_basis(const unsigned int degree)
std::vector< FourthDerivativesType > poly_fourth_derivatives
Definition point.h:111
virtual unsigned int degree() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
Point< 2 > first
Definition grid_out.cc:4639
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcDivideByZero()
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
BarycentricPolynomial< dim, Number1 > operator-(const Number2 &a, const BarycentricPolynomial< dim, Number1 > &bp)
BarycentricPolynomial< dim, Number1 > operator+(const Number2 &a, const BarycentricPolynomial< dim, Number1 > &bp)
std::ostream & operator<<(std::ostream &out, const BarycentricPolynomial< dim, Number > &bp)