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
polynomial_space.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) 2002 - 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
17#include <deal.II/base/mpi.h>
18#include <deal.II/base/point.h>
22#include <deal.II/base/table.h>
24#include <deal.II/base/tensor.h>
25#include <deal.II/base/types.h>
27
28#include <boost/container/small_vector.hpp>
29
30#include <Kokkos_Macros.hpp>
31
32#include <array>
33#include <memory>
34#include <vector>
35
37
38
39template <int dim>
40unsigned int
42{
43 unsigned int n_pols = n;
44 for (unsigned int i = 1; i < dim; ++i)
45 {
46 n_pols *= (n + i);
47 n_pols /= (i + 1);
48 }
49 return n_pols;
50}
51
52
53template <>
54unsigned int
56{
57 return 0;
58}
59
60
61template <>
62std::array<unsigned int, 1>
63PolynomialSpace<1>::compute_index(const unsigned int i) const
64{
65 AssertIndexRange(i, index_map.size());
66 return {{index_map[i]}};
67}
68
69
70
71template <>
72std::array<unsigned int, 2>
73PolynomialSpace<2>::compute_index(const unsigned int i) const
74{
75 AssertIndexRange(i, index_map.size());
76 const unsigned int n = index_map[i];
77 // there should be a better way to
78 // write this function (not
79 // linear in n_1d), someone
80 // should think about this...
81 const unsigned int n_1d = polynomials.size();
82 unsigned int k = 0;
83 for (unsigned int iy = 0; iy < n_1d; ++iy)
84 if (n < k + n_1d - iy)
85 {
86 return {{n - k, iy}};
87 }
88 else
89 k += n_1d - iy;
90
93}
94
95
96
97template <>
98std::array<unsigned int, 3>
99PolynomialSpace<3>::compute_index(const unsigned int i) const
100{
101 AssertIndexRange(i, index_map.size());
102 const unsigned int n = index_map[i];
103 // there should be a better way to
104 // write this function (not
105 // quadratic in n_1d), someone
106 // should think about this...
107 //
108 // (ah, and yes: the original
109 // algorithm was even cubic!)
110 const unsigned int n_1d = polynomials.size();
111 unsigned int k = 0;
112 for (unsigned int iz = 0; iz < n_1d; ++iz)
113 for (unsigned int iy = 0; iy < n_1d - iz; ++iy)
114 if (n < k + n_1d - iy - iz)
115 {
116 return {{n - k, iy, iz}};
117 }
118 else
119 k += n_1d - iy - iz;
120
123}
124
125
126template <int dim>
127void
128PolynomialSpace<dim>::set_numbering(const std::vector<unsigned int> &renumber)
129{
130 Assert(renumber.size() == index_map.size(),
131 ExcDimensionMismatch(renumber.size(), index_map.size()));
132
133 index_map = renumber;
134 for (unsigned int i = 0; i < index_map.size(); ++i)
135 index_map_inverse[index_map[i]] = i;
136}
137
138
139
140template <int dim>
141double
143 const Point<dim> &p) const
144{
145 const auto ix = compute_index(i);
146 // take the product of the
147 // polynomials in the various space
148 // directions
149 double result = 1.;
150 for (unsigned int d = 0; d < dim; ++d)
151 result *= polynomials[ix[d]].value(p[d]);
152 return result;
153}
154
155
157template <int dim>
160 const Point<dim> &p) const
161{
162 const auto ix = compute_index(i);
163
164 Tensor<1, dim> result;
165 for (unsigned int d = 0; d < dim; ++d)
166 result[d] = 1.;
167
168 // get value and first derivative
169 std::vector<double> v(2);
170 for (unsigned int d = 0; d < dim; ++d)
171 {
172 polynomials[ix[d]].value(p[d], v);
173 result[d] *= v[1];
174 for (unsigned int d1 = 0; d1 < dim; ++d1)
175 if (d1 != d)
176 result[d1] *= v[0];
177 }
178 return result;
179}
180
181
182template <int dim>
185 const Point<dim> &p) const
186{
187 const auto ix = compute_index(i);
188
189 Tensor<2, dim> result;
190 for (unsigned int d = 0; d < dim; ++d)
191 for (unsigned int d1 = 0; d1 < dim; ++d1)
192 result[d][d1] = 1.;
193
194 // get value, first and second
195 // derivatives
196 std::vector<double> v(3);
197 for (unsigned int d = 0; d < dim; ++d)
198 {
199 polynomials[ix[d]].value(p[d], v);
200 result[d][d] *= v[2];
201 for (unsigned int d1 = 0; d1 < dim; ++d1)
202 {
203 if (d1 != d)
204 {
205 result[d][d1] *= v[1];
206 result[d1][d] *= v[1];
207 for (unsigned int d2 = 0; d2 < dim; ++d2)
208 if (d2 != d)
209 result[d1][d2] *= v[0];
210 }
211 }
212 }
213 return result;
215
216
217template <int dim>
218void
220 const Point<dim> &p,
221 std::vector<double> &values,
222 std::vector<Tensor<1, dim>> &grads,
223 std::vector<Tensor<2, dim>> &grad_grads,
224 std::vector<Tensor<3, dim>> &third_derivatives,
225 std::vector<Tensor<4, dim>> &fourth_derivatives) const
226{
227 const unsigned int n_1d = polynomials.size();
228
229 Assert(values.size() == this->n() || values.empty(),
230 ExcDimensionMismatch2(values.size(), this->n(), 0));
231 Assert(grads.size() == this->n() || grads.empty(),
232 ExcDimensionMismatch2(grads.size(), this->n(), 0));
233 Assert(grad_grads.size() == this->n() || grad_grads.empty(),
234 ExcDimensionMismatch2(grad_grads.size(), this->n(), 0));
235 Assert(third_derivatives.size() == this->n() || third_derivatives.empty(),
236 ExcDimensionMismatch2(third_derivatives.size(), this->n(), 0));
237 Assert(fourth_derivatives.size() == this->n() || fourth_derivatives.empty(),
238 ExcDimensionMismatch2(fourth_derivatives.size(), this->n(), 0));
239
240 unsigned int v_size = 0;
241 bool update_values = false, update_grads = false, update_grad_grads = false;
242 bool update_3rd_derivatives = false, update_4th_derivatives = false;
243 if (values.size() == this->n())
244 {
245 update_values = true;
246 v_size = 1;
247 }
248 if (grads.size() == this->n())
249 {
250 update_grads = true;
251 v_size = 2;
252 }
253 if (grad_grads.size() == this->n())
254 {
255 update_grad_grads = true;
256 v_size = 3;
257 }
258 if (third_derivatives.size() == this->n())
259 {
261 v_size = 4;
262 }
263 if (fourth_derivatives.size() == this->n())
264 {
265 update_4th_derivatives = true;
266 v_size = 5;
267 }
268
269 // Store data in a single
270 // object. Access is by
271 // v[d][n][o]
272 // d: coordinate direction
273 // n: number of 1d polynomial
274 // o: order of derivative
275 //
276 // Our rule-of-thumb for stack arrays is 200 elements in a small_vector. Here,
277 // we have (in 3d) 3 * 14 * 5 = 210 elements, in which 5 is the maximum number
278 // derivatives (4) plus one value.
279 std::array<boost::container::small_vector<std::array<double, 5>, 14>, dim> v;
280 for (unsigned int d = 0; d < dim; ++d)
281 {
282 v[d].resize(n_1d);
283 for (unsigned int i = 0; i < n_1d; ++i)
284 {
285 Assert(v_size > 0, ExcInternalError());
286 Assert(v_size <= v[d][i].size(), ExcInternalError());
287 if constexpr (running_in_debug_mode())
288 v[d][i].fill(std::numeric_limits<double>::signaling_NaN());
289 polynomials[i].value(p[d], v_size - 1, v[d][i].data());
290 }
291 }
292
293 if (update_values)
294 {
295 unsigned int k = 0;
296
297 for (unsigned int iz = 0; iz < ((dim > 2) ? n_1d : 1); ++iz)
298 for (unsigned int iy = 0; iy < ((dim > 1) ? n_1d - iz : 1); ++iy)
299 for (unsigned int ix = 0; ix < n_1d - iy - iz; ++ix)
300 values[index_map_inverse[k++]] = v[0][ix][0] *
301 ((dim > 1) ? v[1][iy][0] : 1.) *
302 ((dim > 2) ? v[2][iz][0] : 1.);
303 }
304
305 if (update_grads)
306 {
307 unsigned int k = 0;
308
309 for (unsigned int iz = 0; iz < ((dim > 2) ? n_1d : 1); ++iz)
310 for (unsigned int iy = 0; iy < ((dim > 1) ? n_1d - iz : 1); ++iy)
311 for (unsigned int ix = 0; ix < n_1d - iy - iz; ++ix)
312 {
313 const unsigned int k2 = index_map_inverse[k++];
314 for (unsigned int d = 0; d < dim; ++d)
315 grads[k2][d] = v[0][ix][(d == 0) ? 1 : 0] *
316 ((dim > 1) ? v[1][iy][(d == 1) ? 1 : 0] : 1.) *
317 ((dim > 2) ? v[2][iz][(d == 2) ? 1 : 0] : 1.);
318 }
319 }
320
321 if (update_grad_grads)
322 {
323 unsigned int k = 0;
324
325 for (unsigned int iz = 0; iz < ((dim > 2) ? n_1d : 1); ++iz)
326 for (unsigned int iy = 0; iy < ((dim > 1) ? n_1d - iz : 1); ++iy)
327 for (unsigned int ix = 0; ix < n_1d - iy - iz; ++ix)
328 {
329 const unsigned int k2 = index_map_inverse[k++];
330 for (unsigned int d1 = 0; d1 < dim; ++d1)
331 for (unsigned int d2 = 0; d2 < dim; ++d2)
332 {
333 // Derivative
334 // order for each
335 // direction
336 const unsigned int j0 =
337 ((d1 == 0) ? 1 : 0) + ((d2 == 0) ? 1 : 0);
338 const unsigned int j1 =
339 ((d1 == 1) ? 1 : 0) + ((d2 == 1) ? 1 : 0);
340 const unsigned int j2 =
341 ((d1 == 2) ? 1 : 0) + ((d2 == 2) ? 1 : 0);
342
343 grad_grads[k2][d1][d2] = v[0][ix][j0] *
344 ((dim > 1) ? v[1][iy][j1] : 1.) *
345 ((dim > 2) ? v[2][iz][j2] : 1.);
346 }
347 }
348 }
349
351 {
352 unsigned int k = 0;
353
354 for (unsigned int iz = 0; iz < ((dim > 2) ? n_1d : 1); ++iz)
355 for (unsigned int iy = 0; iy < ((dim > 1) ? n_1d - iz : 1); ++iy)
356 for (unsigned int ix = 0; ix < n_1d - iy - iz; ++ix)
357 {
358 const unsigned int k2 = index_map_inverse[k++];
359 for (unsigned int d1 = 0; d1 < dim; ++d1)
360 for (unsigned int d2 = 0; d2 < dim; ++d2)
361 for (unsigned int d3 = 0; d3 < dim; ++d3)
362 {
363 // Derivative
364 // order for each
365 // direction
366 std::array<unsigned int, dim> deriv_order{};
367 for (unsigned int x = 0; x < dim; ++x)
368 {
369 if (d1 == x)
370 ++deriv_order[x];
371 if (d2 == x)
372 ++deriv_order[x];
373 if (d3 == x)
374 ++deriv_order[x];
375 }
376
377 third_derivatives[k2][d1][d2][d3] =
378 v[0][ix][deriv_order[0]] *
379 ((dim > 1) ? v[1][iy][deriv_order[1]] : 1.) *
380 ((dim > 2) ? v[2][iz][deriv_order[2]] : 1.);
381 }
382 }
383 }
384
385 if (update_4th_derivatives)
386 {
387 unsigned int k = 0;
388
389 for (unsigned int iz = 0; iz < ((dim > 2) ? n_1d : 1); ++iz)
390 for (unsigned int iy = 0; iy < ((dim > 1) ? n_1d - iz : 1); ++iy)
391 for (unsigned int ix = 0; ix < n_1d - iy - iz; ++ix)
392 {
393 const unsigned int k2 = index_map_inverse[k++];
394 for (unsigned int d1 = 0; d1 < dim; ++d1)
395 for (unsigned int d2 = 0; d2 < dim; ++d2)
396 for (unsigned int d3 = 0; d3 < dim; ++d3)
397 for (unsigned int d4 = 0; d4 < dim; ++d4)
398 {
399 // Derivative
400 // order for each
401 // direction
402 std::array<unsigned int, dim> deriv_order{};
403 for (unsigned int x = 0; x < dim; ++x)
404 {
405 if (d1 == x)
406 ++deriv_order[x];
407 if (d2 == x)
408 ++deriv_order[x];
409 if (d3 == x)
410 ++deriv_order[x];
411 if (d4 == x)
412 ++deriv_order[x];
413 }
414
415 fourth_derivatives[k2][d1][d2][d3][d4] =
416 v[0][ix][deriv_order[0]] *
417 ((dim > 1) ? v[1][iy][deriv_order[1]] : 1.) *
418 ((dim > 2) ? v[2][iz][deriv_order[2]] : 1.);
419 }
420 }
421 }
422}
423
424
425
426template <int dim>
427std::unique_ptr<ScalarPolynomialsBase<dim>>
429{
430 return std::make_unique<PolynomialSpace<dim>>(*this);
431}
432
433
434template class PolynomialSpace<1>;
435template class PolynomialSpace<2>;
436template class PolynomialSpace<3>;
437
Definition point.h:111
double compute_value(const unsigned int i, const Point< dim > &p) const override
Tensor< 1, dim > compute_grad(const unsigned int i, const Point< dim > &p) const override
void set_numbering(const std::vector< unsigned int > &renumber)
static unsigned int n_polynomials(const unsigned int n)
std::array< unsigned int, dim > compute_index(const unsigned int n) const
Tensor< 2, dim > compute_grad_grad(const unsigned int i, const Point< dim > &p) const override
virtual std::unique_ptr< ScalarPolynomialsBase< dim > > clone() 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
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ASSERT_UNREACHABLE()
#define Assert(cond, exc)
static ::ExceptionBase & ExcDimensionMismatch2(std::size_t arg1, std::size_t arg2, std::size_t arg3)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
@ update_values
Shape function values.
@ update_3rd_derivatives
Third derivatives of shape functions.
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
constexpr unsigned int invalid_unsigned_int
Definition types.h:228