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_piecewise.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) 2013 - 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#include <deal.II/base/config.h>
14
18#include <deal.II/base/point.h>
21#include <deal.II/base/types.h>
22
23#include <Kokkos_Macros.hpp>
24
25#include <algorithm>
26#include <cstdlib>
27#include <string>
28#include <vector>
29
30
32
33
34
35namespace Polynomials
36{
37 template <typename number>
39 const Polynomial<number> &coefficients_on_interval,
40 const unsigned int n_intervals,
41 const unsigned int interval,
42 const bool spans_next_interval)
43 : polynomial(coefficients_on_interval)
44 , n_intervals(n_intervals)
45 , interval(interval)
46 , spans_two_intervals(spans_next_interval)
47 , index(numbers::invalid_unsigned_int)
48 {
49 Assert(n_intervals > 0, ExcMessage("No intervals given"));
51 }
52
53
54
55 template <typename number>
57 const std::vector<Point<1, number>> &points,
58 const unsigned int index)
59 : n_intervals(numbers::invalid_unsigned_int)
60 , interval(numbers::invalid_unsigned_int)
61 , spans_two_intervals(false)
62 , index(index)
63 {
64 Assert(points.size() > 1, ExcMessage("No enough points given!"));
66
67 this->points.resize(points.size());
68 for (unsigned int i = 0; i < points.size(); ++i)
69 this->points[i] = points[i][0];
70
71 this->one_over_lengths.resize(points.size() - 1);
72 for (unsigned int i = 0; i < points.size() - 1; ++i)
73 this->one_over_lengths[i] =
74 number(1.0) / (points[i + 1][0] - points[i][0]);
75 }
76
77
78
79 template <typename number>
80 void
82 std::vector<number> &values) const
83 {
84 Assert(values.size() > 0, ExcZero());
85
86 value(x, values.size() - 1, values.data());
87 }
88
89
90
91 template <typename number>
92 void
94 const unsigned int n_derivatives,
95 number *values) const
96 {
97 if (points.size() > 0)
98 {
99 if (x > points[index])
100 values[0] = std::max<number>(0.0,
101 1.0 - (x - points[index]) *
102 one_over_lengths[index]);
103 else if (x < points[index])
104 values[0] = std::max<number>(0.0,
105 0.0 + (x - points[index - 1]) *
106 one_over_lengths[index - 1]);
107 else
108 values[0] = 1.0;
109
110 if (n_derivatives >= 1)
111 {
112 if ((x > points[index]) && (points[index + 1] >= x))
113 values[1] = -1.0 * one_over_lengths[index];
114 else if ((x < points[index]) && (points[index - 1] <= x))
115 values[1] = +1.0 * one_over_lengths[index - 1];
116 else
117 values[1] = 0.0;
118 }
119
120 // all other derivatives are zero
121 for (unsigned int i = 2; i <= n_derivatives; ++i)
122 values[i] = 0.0;
123
124 return;
125 }
126
127 // shift polynomial if necessary
128 number y = x;
129 double derivative_change_sign = 1.;
130 if (n_intervals > 0)
131 {
132 const number step = 1. / n_intervals;
133 // polynomial spans over two intervals
134 if (spans_two_intervals)
135 {
136 const double offset = step * interval;
137 if (x < offset || x > offset + step + step)
138 {
139 for (unsigned int k = 0; k <= n_derivatives; ++k)
140 values[k] = 0;
141 return;
142 }
143 else if (x < offset + step)
144 y = x - offset;
145 else
146 {
147 derivative_change_sign = -1.;
148 y = offset + step + step - x;
149 }
150 }
151 else
152 {
153 const double offset = step * interval;
154 // ROCm 5.7 throws a floating point exception in debug mode when
155 // trying to evaluate (x < offset || x > offset + step). Separating
156 // the conditions fixes the issue.
157 if (x < offset)
158 {
159 for (unsigned int k = 0; k <= n_derivatives; ++k)
160 values[k] = 0;
161 return;
162 }
163 else if (x > offset + step)
164 {
165 for (unsigned int k = 0; k <= n_derivatives; ++k)
166 values[k] = 0;
167 return;
168 }
169 else
170 y = x - offset;
171 }
172
173 // on subinterval boundaries, cannot evaluate derivatives properly, so
174 // set them to zero
175 if ((std::abs(y) < 1e-14 &&
176 (interval > 0 || derivative_change_sign == -1.)) ||
177 (std::abs(y - step) < 1e-14 &&
178 (interval < n_intervals - 1 || derivative_change_sign == -1.)))
179 {
180 values[0] = value(x);
181 for (unsigned int d = 1; d <= n_derivatives; ++d)
182 values[d] = 0;
183 return;
184 }
185 }
186
187 polynomial.value(y, n_derivatives, values);
188
189 // change sign if necessary
190 for (unsigned int j = 1; j <= n_derivatives; j += 2)
191 values[j] *= derivative_change_sign;
192 }
193
194
195
196 template <typename number>
197 std::size_t
199 {
200 return (polynomial.memory_consumption() +
203 MemoryConsumption::memory_consumption(spans_two_intervals) +
206 }
207
208
209
210 std::vector<PiecewisePolynomial<double>>
212 const unsigned int n_subdivisions,
213 const unsigned int base_degree)
214 {
215 std::vector<Polynomial<double>> p_base =
217 for (auto &polynomial : p_base)
218 polynomial.scale(n_subdivisions);
219
220 std::vector<PiecewisePolynomial<double>> p;
221 p.reserve(n_subdivisions * base_degree + 1);
222
223 p.emplace_back(p_base[0], n_subdivisions, 0, false);
224 for (unsigned int s = 0; s < n_subdivisions; ++s)
225 for (unsigned int i = 0; i < base_degree; ++i)
226 p.emplace_back(p_base[i + 1],
227 n_subdivisions,
228 s,
229 i == (base_degree - 1) && s < n_subdivisions - 1);
230 return p;
231 }
232
233
234
235 std::vector<PiecewisePolynomial<double>>
237 const std::vector<Point<1>> &points)
238 {
239 std::vector<PiecewisePolynomial<double>> p;
240 p.reserve(points.size());
241
242 for (unsigned int s = 0; s < points.size(); ++s)
243 p.emplace_back(points, s);
244
245 return p;
246 }
247
248} // namespace Polynomials
249
250// ------------------ explicit instantiations --------------- //
251
252namespace Polynomials
253{
254 template class PiecewisePolynomial<float>;
255 template class PiecewisePolynomial<double>;
256 template class PiecewisePolynomial<long double>;
257} // namespace Polynomials
258
Definition point.h:111
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int degree)
PiecewisePolynomial(const Polynomial< number > &coefficients_on_interval, const unsigned int n_intervals, const unsigned int interval, const bool spans_next_interval)
number value(const number x) const
virtual std::size_t memory_consumption() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
static ::ExceptionBase & ExcZero()
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcMessage(std::string arg1)
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
std::vector< PiecewisePolynomial< double > > generate_complete_linear_basis_on_subdivisions(const std::vector< Point< 1 > > &points)
std::vector< PiecewisePolynomial< double > > generate_complete_Lagrange_basis_on_subdivisions(const unsigned int n_subdivisions, const unsigned int base_degree)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)