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
tensor_product_polynomials.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) 2000 - 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
16#include <deal.II/base/table.h>
18
19#include <boost/container/small_vector.hpp>
20
21#include <array>
22#include <memory>
23
25
26
27
28/* ------------------- TensorProductPolynomials -------------- */
29
30
31namespace internal
32{
33 namespace
34 {
35 void
36 compute_tensor_index(const unsigned int n,
37 const unsigned int,
38 const unsigned int,
39 std::array<unsigned int, 1> &indices)
40 {
41 indices[0] = n;
42 }
43
44 void
45 compute_tensor_index(const unsigned int n,
46 const unsigned int n_pols_0,
47 const unsigned int,
48 std::array<unsigned int, 2> &indices)
49 {
50 indices[0] = n % n_pols_0;
51 indices[1] = n / n_pols_0;
52 }
53
54 void
55 compute_tensor_index(const unsigned int n,
56 const unsigned int n_pols_0,
57 const unsigned int n_pols_1,
58 std::array<unsigned int, 3> &indices)
59 {
60 indices[0] = n % n_pols_0;
61 indices[1] = (n / n_pols_0) % n_pols_1;
62 indices[2] = n / (n_pols_0 * n_pols_1);
63 }
64 } // namespace
65} // namespace internal
66
67
68
69template <int dim, typename PolynomialType>
70void
72 const unsigned int i,
73 std::array<unsigned int, dim> &indices) const
74{
75 if constexpr (dim == 0)
76 {
77 (void)i;
78 (void)indices;
80 }
81 else
82 {
83 Assert(i < Utilities::fixed_power<dim>(polynomials.size()),
85 internal::compute_tensor_index(index_map[i],
86 polynomials.size(),
87 polynomials.size(),
88 indices);
89 }
90}
91
92
93
94template <int dim, typename PolynomialType>
95void
97 std::ostream &out) const
98{
99 if constexpr (dim == 0)
100 {
101 (void)out;
103 }
104 else
105 {
106 std::array<unsigned int, dim> ix;
107 for (unsigned int i = 0; i < this->n(); ++i)
108 {
109 compute_index(i, ix);
110 out << i << "\t";
111 for (unsigned int d = 0; d < dim; ++d)
112 out << ix[d] << " ";
113 out << std::endl;
114 }
115 }
116}
117
118
119
120template <int dim>
121const std::vector<unsigned int> &
123{
124 return index_map;
125}
126
127
128
129template <int dim>
130const std::vector<unsigned int> &
132{
133 return index_map_inverse;
134}
135
136
137
138template <int dim>
139void
141 const std::vector<unsigned int> &renumber)
142{
143 Assert(renumber.size() == index_map.size(),
144 ExcDimensionMismatch(renumber.size(), index_map.size()));
145
146 index_map = renumber;
147 for (unsigned int i = 0; i < index_map.size(); ++i)
148 index_map_inverse[index_map[i]] = i;
150
151
152
153template <>
154void
155AnisotropicPolynomials<0>::set_numbering(const std::vector<unsigned int> &)
156{
157 AssertThrow(false, ExcNotImplemented("This function does not work in 0-d!"));
158}
159
160
161
162template <int dim, typename PolynomialType>
163void
165 const std::vector<unsigned int> &renumber)
166{
167 Assert(renumber.size() == index_map.size(),
168 ExcDimensionMismatch(renumber.size(), index_map.size()));
169
170 index_map = renumber;
171 for (unsigned int i = 0; i < index_map.size(); ++i)
172 index_map_inverse[index_map[i]] = i;
173}
174
175
176
177template <>
178void
180 const std::vector<unsigned int> &)
181{
182 AssertThrow(false, ExcNotImplemented("This function does not work in 0-d!"));
183}
184
185
186
187template <int dim, typename PolynomialType>
188double
190 const unsigned int i,
191 const Point<dim> &p) const
192{
193 if constexpr (dim == 0)
194 {
195 (void)i;
196 (void)p;
198 return 0;
199 }
200 else
201 {
202 std::array<unsigned int, dim> indices;
203 compute_index(i, indices);
204
205 double value = 1.;
206 for (unsigned int d = 0; d < dim; ++d)
207 value *= polynomials[indices[d]].value(p[d]);
208
209 return value;
211}
212
213
214
215template <int dim, typename PolynomialType>
218 const unsigned int i,
219 const Point<dim> &p) const
220{
221 if constexpr (dim == 0)
222 {
223 (void)i;
224 (void)p;
226 return {};
227 }
228 else
229 {
230 std::array<unsigned int, dim> indices;
231 compute_index(i, indices);
232
233 // compute values and
234 // uni-directional derivatives at
235 // the given point in each
236 // coordinate direction
238 {
239 std::vector<double> tmp(2);
240 for (unsigned int d = 0; d < dim; ++d)
241 {
242 polynomials[indices[d]].value(p[d], tmp);
243 v[d][0] = tmp[0];
244 v[d][1] = tmp[1];
245 }
246 }
247
248 Tensor<1, dim> grad;
249 for (unsigned int d = 0; d < dim; ++d)
251 grad[d] = 1.;
252 for (unsigned int x = 0; x < dim; ++x)
253 grad[d] *= v[x][d == x];
254 }
255
256 return grad;
257 }
258}
259
260
261
262template <int dim, typename PolynomialType>
265 const unsigned int i,
266 const Point<dim> &p) const
267{
268 if constexpr (dim == 0)
269 {
270 (void)i;
271 (void)p;
273 return {};
274 }
275 else
276 {
277 std::array<unsigned int, dim> indices;
278 compute_index(i, indices);
279
281 {
282 std::vector<double> tmp(3);
283 for (unsigned int d = 0; d < dim; ++d)
284 {
285 polynomials[indices[d]].value(p[d], tmp);
286 v[d][0] = tmp[0];
287 v[d][1] = tmp[1];
288 v[d][2] = tmp[2];
289 }
290 }
291
292 Tensor<2, dim> grad_grad;
293 for (unsigned int d1 = 0; d1 < dim; ++d1)
294 for (unsigned int d2 = 0; d2 < dim; ++d2)
295 {
296 grad_grad[d1][d2] = 1.;
297 for (unsigned int x = 0; x < dim; ++x)
298 {
299 unsigned int derivative = 0;
300 if (d1 == x || d2 == x)
301 {
302 if (d1 == d2)
303 derivative = 2;
304 else
305 derivative = 1;
306 }
307 grad_grad[d1][d2] *= v[x][derivative];
308 }
309 }
310
311 return grad_grad;
312 }
313}
314
315
316
317namespace internal
318{
320 {
321 // This function computes the tensor product of some tabulated
322 // one-dimensional polynomials (also the anisotropic case is supported)
323 // with tensor product indices of all dimensions except the first one
324 // tabulated in the 'indices' array; the first dimension is manually
325 // iterated through because these are possibly performance-critical loops,
326 // so we want to avoid indirect addressing.
327 template <int dim, std::size_t dim1>
328 void
330 const unsigned int n_derivatives,
331 const boost::container::small_vector<::ndarray<double, 5, dim>, 10>
332 &values_1d,
333 const unsigned int size_x,
334 const boost::container::small_vector<std::array<unsigned int, dim1>, 64>
335 &indices,
336 const std::vector<unsigned int> &index_map,
337 std::vector<double> &values,
338 std::vector<Tensor<1, dim>> &grads,
339 std::vector<Tensor<2, dim>> &grad_grads,
340 std::vector<Tensor<3, dim>> &third_derivatives,
341 std::vector<Tensor<4, dim>> &fourth_derivatives)
342 {
343 const bool update_values = (values.size() == indices.size() * size_x);
344 const bool update_grads = (grads.size() == indices.size() * size_x);
345 const bool update_grad_grads =
346 (grad_grads.size() == indices.size() * size_x);
347 const bool update_3rd_derivatives =
348 (third_derivatives.size() == indices.size() * size_x);
349 const bool update_4th_derivatives =
350 (fourth_derivatives.size() == indices.size() * size_x);
351
352 // For values, 1st and 2nd derivatives use a more lengthy code that
353 // minimizes the number of arithmetic operations and memory accesses
354 if (n_derivatives == 0)
355 for (unsigned int i = 0, i1 = 0; i1 < indices.size(); ++i1)
356 {
357 double value_outer = 1.;
358 if constexpr (dim > 1)
359 for (unsigned int d = 1; d < dim; ++d)
360 value_outer *= values_1d[indices[i1][d - 1]][0][d];
361 if (index_map.empty())
362 for (unsigned int ix = 0; ix < size_x; ++ix, ++i)
363 values[i] = value_outer * values_1d[ix][0][0];
364 else
365 for (unsigned int ix = 0; ix < size_x; ++ix, ++i)
366 values[index_map[i]] = value_outer * values_1d[ix][0][0];
367 }
368 else
369 for (unsigned int iy = 0, i1 = 0; i1 < indices.size(); ++i1)
370 {
371 // prepare parts of products in y (and z) directions
372 std::array<double, dim + (dim * (dim - 1)) / 2> value_outer;
373 value_outer[0] = 1.;
374 if constexpr (dim > 1)
375 {
376 for (unsigned int x = 1; x < dim; ++x)
377 value_outer[0] *= values_1d[indices[i1][x - 1]][0][x];
378 for (unsigned int d = 1; d < dim; ++d)
379 {
380 value_outer[d] = values_1d[indices[i1][d - 1]][1][d];
381 for (unsigned int x = 1; x < dim; ++x)
382 if (x != d)
383 value_outer[d] *= values_1d[indices[i1][x - 1]][0][x];
384 }
385 for (unsigned int d1 = 1, count = dim; d1 < dim; ++d1)
386 for (unsigned int d2 = d1; d2 < dim; ++d2, ++count)
387 {
388 value_outer[count] = 1.;
389 for (unsigned int x = 1; x < dim; ++x)
390 {
391 unsigned int derivative = 0;
392 if (d1 == x)
393 ++derivative;
394 if (d2 == x)
395 ++derivative;
396
397 value_outer[count] *=
398 values_1d[indices[i1][x - 1]][derivative][x];
399 }
400 }
401 }
402
403 // now run the loop over x and multiply by the values/derivatives
404 // in x direction
405 for (unsigned int ix = 0, i = iy; ix < size_x; ++ix, ++i)
406 {
407 std::array<double, 3> val_x{{values_1d[ix][0][0],
408 values_1d[ix][1][0],
409 values_1d[ix][2][0]}};
410 const unsigned int index =
411 (index_map.empty() ? i : index_map[i]);
412
413 if (update_values)
414 values[index] = value_outer[0] * val_x[0];
415
416 if (update_grads)
417 {
418 grads[index][0] = value_outer[0] * val_x[1];
419 if constexpr (dim > 1)
420 for (unsigned int d = 1; d < dim; ++d)
421 grads[index][d] = value_outer[d] * val_x[0];
422 }
423
424 if (update_grad_grads)
425 {
426 grad_grads[index][0][0] = value_outer[0] * val_x[2];
427 if constexpr (dim > 1)
428 {
429 for (unsigned int d = 1; d < dim; ++d)
430 grad_grads[index][0][d] = grad_grads[index][d][0] =
431 value_outer[d] * val_x[1];
432 for (unsigned int d1 = 1, count = dim; d1 < dim; ++d1)
433 for (unsigned int d2 = d1; d2 < dim; ++d2, ++count)
434 grad_grads[index][d1][d2] =
435 grad_grads[index][d2][d1] =
436 value_outer[count] * val_x[0];
437 }
438 }
439 }
440
441 // Use slower code for 3rd and 4th derivatives
443 for (unsigned int ix = 0, i = iy; ix < size_x; ++ix, ++i)
444 {
445 const unsigned int index =
446 (index_map.empty() ? i : index_map[i]);
447 std::array<unsigned int, dim> my_indices;
448 my_indices[0] = ix;
449 if constexpr (dim > 1)
450 for (unsigned int d = 1; d < dim; ++d)
451 my_indices[d] = indices[i1][d - 1];
452 for (unsigned int d1 = 0; d1 < dim; ++d1)
453 for (unsigned int d2 = 0; d2 < dim; ++d2)
454 for (unsigned int d3 = 0; d3 < dim; ++d3)
455 {
456 double der3 = 1.;
457 for (unsigned int x = 0; x < dim; ++x)
458 {
459 unsigned int derivative = 0;
460 if (d1 == x)
461 ++derivative;
462 if (d2 == x)
463 ++derivative;
464 if (d3 == x)
465 ++derivative;
466
467 der3 *= values_1d[my_indices[x]][derivative][x];
468 }
469 third_derivatives[index][d1][d2][d3] = der3;
470 }
471 }
472
473 if (update_4th_derivatives)
474 for (unsigned int ix = 0, i = iy; ix < size_x; ++ix, ++i)
475 {
476 const unsigned int index =
477 (index_map.empty() ? i : index_map[i]);
478 std::array<unsigned int, dim> my_indices;
479 my_indices[0] = ix;
480 if constexpr (dim > 1)
481 for (unsigned int d = 1; d < dim; ++d)
482 my_indices[d] = indices[i1][d - 1];
483 for (unsigned int d1 = 0; d1 < dim; ++d1)
484 for (unsigned int d2 = 0; d2 < dim; ++d2)
485 for (unsigned int d3 = 0; d3 < dim; ++d3)
486 for (unsigned int d4 = 0; d4 < dim; ++d4)
487 {
488 double der4 = 1.;
489 for (unsigned int x = 0; x < dim; ++x)
490 {
491 unsigned int derivative = 0;
492 if (d1 == x)
493 ++derivative;
494 if (d2 == x)
495 ++derivative;
496 if (d3 == x)
497 ++derivative;
498 if (d4 == x)
499 ++derivative;
500
501 der4 *= values_1d[my_indices[x]][derivative][x];
502 }
503 fourth_derivatives[index][d1][d2][d3][d4] = der4;
504 }
505 }
506
507 iy += size_x;
508 }
509 }
510 } // namespace TensorProductPolynomials
511} // namespace internal
512
513
514
515template <int dim, typename PolynomialType>
516void
518 const Point<dim> &p,
519 std::vector<double> &values,
520 std::vector<Tensor<1, dim>> &grads,
521 std::vector<Tensor<2, dim>> &grad_grads,
522 std::vector<Tensor<3, dim>> &third_derivatives,
523 std::vector<Tensor<4, dim>> &fourth_derivatives) const
524{
525 if constexpr (dim == 0)
526 {
527 (void)p;
528 (void)values;
529 (void)grads;
530 (void)grad_grads;
531 (void)third_derivatives;
532 (void)fourth_derivatives;
534 }
535 else
536 {
537 Assert(dim <= 3, ExcNotImplemented());
538 Assert(values.size() == this->n() || values.empty(),
539 ExcDimensionMismatch2(values.size(), this->n(), 0));
540 Assert(grads.size() == this->n() || grads.empty(),
541 ExcDimensionMismatch2(grads.size(), this->n(), 0));
542 Assert(grad_grads.size() == this->n() || grad_grads.empty(),
543 ExcDimensionMismatch2(grad_grads.size(), this->n(), 0));
544 Assert(third_derivatives.size() == this->n() || third_derivatives.empty(),
545 ExcDimensionMismatch2(third_derivatives.size(), this->n(), 0));
546 Assert(fourth_derivatives.size() == this->n() ||
547 fourth_derivatives.empty(),
548 ExcDimensionMismatch2(fourth_derivatives.size(), this->n(), 0));
549
550 // check how many values/derivatives we have to compute
551 unsigned int n_derivatives = 0;
552 if (values.size() == this->n())
553 n_derivatives = 0;
554 if (grads.size() == this->n())
555 n_derivatives = 1;
556 if (grad_grads.size() == this->n())
557 n_derivatives = 2;
558 if (third_derivatives.size() == this->n())
559 n_derivatives = 3;
560 if (fourth_derivatives.size() == this->n())
561 n_derivatives = 4;
562
563 // Compute the values (and derivatives, if necessary) of all 1d
564 // polynomials at this evaluation point. We can use the more optimized
565 // values_of_array function to compute 'dim' polynomials at once
566 const unsigned int n_polynomials = polynomials.size();
567 boost::container::small_vector<ndarray<double, 5, dim>, 10> values_1d(
568 n_polynomials);
569 if constexpr (std::is_same_v<PolynomialType,
571 {
572 std::array<double, dim> point_array;
573 for (unsigned int d = 0; d < dim; ++d)
574 point_array[d] = p[d];
575 for (unsigned int i = 0; i < n_polynomials; ++i)
576 polynomials[i].values_of_array(point_array,
577 n_derivatives,
578 values_1d[i].data());
579 }
580 else
581 for (unsigned int i = 0; i < n_polynomials; ++i)
582 for (unsigned int d = 0; d < dim; ++d)
583 {
584 std::array<double, 5> derivatives;
585 polynomials[i].value(p[d], n_derivatives, derivatives.data());
586 for (unsigned int j = 0; j <= n_derivatives; ++j)
587 values_1d[i][j][d] = derivatives[j];
588 }
589
590 // Unroll the tensor product indices of all but the first dimension in
591 // arbitrary dimension
592 constexpr unsigned int dim1 = dim > 1 ? dim - 1 : 1;
593 boost::container::small_vector<std::array<unsigned int, dim1>, 64>
594 indices(1);
595 if constexpr (dim > 1)
596 for (unsigned int d = 1; d < dim; ++d)
597 {
598 const unsigned int size = indices.size();
599 for (unsigned int i = 1; i < n_polynomials; ++i)
600 for (unsigned int j = 0; j < size; ++j)
601 {
602 std::array<unsigned int, dim1> next_index = indices[j];
603 next_index[d - 1] = i;
604 indices.push_back(next_index);
605 }
606 }
607 AssertDimension(indices.size(), Utilities::pow(n_polynomials, dim - 1));
608
609 internal::TensorProductPolynomials::evaluate_tensor_product<dim>(
610 n_derivatives,
611 values_1d,
612 n_polynomials,
613 indices,
614 index_map_inverse,
615 values,
616 grads,
617 grad_grads,
618 third_derivatives,
619 fourth_derivatives);
620 }
621}
622
623
624
625template <int dim, typename PolynomialType>
626std::unique_ptr<ScalarPolynomialsBase<dim>>
628{
629 return std::make_unique<TensorProductPolynomials<dim, PolynomialType>>(*this);
630}
631
632
633
634template <int dim, typename PolynomialType>
635std::size_t
642
643
644
645template <int dim, typename PolynomialType>
646std::vector<PolynomialType>
652
653
654
655/* ------------------- AnisotropicPolynomials -------------- */
656
657
658template <int dim>
660 const std::vector<std::vector<Polynomials::Polynomial<double>>> &pols)
661 : ScalarPolynomialsBase<dim>(1, get_n_tensor_pols(pols))
662 , polynomials(pols)
663 , index_map(this->n())
664 , index_map_inverse(this->n())
665{
666 Assert(pols.size() == dim, ExcDimensionMismatch(pols.size(), dim));
667 for (const auto &pols_d : pols)
668 {
669 (void)pols_d;
670 Assert(pols_d.size() > 0,
671 ExcMessage("The number of polynomials must be larger than zero "
672 "for all coordinate directions."));
673 }
674
675 // per default set this index map to identity. This map can be changed by
676 // the user through the set_numbering() function
677 for (unsigned int i = 0; i < this->n(); ++i)
678 {
679 index_map[i] = i;
680 index_map_inverse[i] = i;
681 }
682}
683
684
685
686template <int dim>
687void
689 const unsigned int i,
690 std::array<unsigned int, dim> &indices) const
691{
692 if constexpr (dim == 0)
693 {
694 (void)i;
695 (void)indices;
697 }
698 else
699 {
700 if constexpr (running_in_debug_mode())
701 {
702 unsigned int n_poly = 1;
703 for (unsigned int d = 0; d < dim; ++d)
704 n_poly *= polynomials[d].size();
705 Assert(i < n_poly, ExcInternalError());
706 }
707
708 if (dim == 0)
709 {
710 }
711 else if (dim == 1)
712 internal::compute_tensor_index(index_map[i],
713 polynomials[0].size(),
714 0 /*not used*/,
715 indices);
716 else
717 internal::compute_tensor_index(index_map[i],
718 polynomials[0].size(),
719 polynomials[1].size(),
720 indices);
721 }
722}
723
724
725
726template <int dim>
727double
729 const Point<dim> &p) const
730{
731 if constexpr (dim == 0)
732 {
733 (void)i;
734 (void)p;
736 return {};
737 }
738 else
739 {
740 std::array<unsigned int, dim> indices;
741 compute_index(i, indices);
742
743 double value = 1.;
744 for (unsigned int d = 0; d < dim; ++d)
745 value *= polynomials[d][indices[d]].value(p[d]);
746
747 return value;
748 }
749}
750
751
752
753template <int dim>
756 const Point<dim> &p) const
757{
758 if constexpr (dim == 0)
759 {
760 (void)i;
761 (void)p;
763 return {};
764 }
765 else
766 {
767 std::array<unsigned int, dim> indices;
768 compute_index(i, indices);
769
770 // compute values and
771 // uni-directional derivatives at
772 // the given point in each
773 // coordinate direction
775 for (unsigned int d = 0; d < dim; ++d)
776 polynomials[d][indices[d]].value(p[d], 1, v[d].data());
777
778 Tensor<1, dim> grad;
779 for (unsigned int d = 0; d < dim; ++d)
780 {
781 grad[d] = 1.;
782 for (unsigned int x = 0; x < dim; ++x)
783 grad[d] *= v[x][d == x];
784 }
785
786 return grad;
787 }
788}
789
790
791
792template <int dim>
795 const Point<dim> &p) const
796{
797 if constexpr (dim == 0)
798 {
799 (void)i;
800 (void)p;
802 return {};
803 }
804 else
805 {
806 std::array<unsigned int, dim> indices;
807 compute_index(i, indices);
808
810 for (unsigned int d = 0; d < dim; ++d)
811 polynomials[d][indices[d]].value(p[d], 2, v[d].data());
812
813 Tensor<2, dim> grad_grad;
814 for (unsigned int d1 = 0; d1 < dim; ++d1)
815 for (unsigned int d2 = 0; d2 < dim; ++d2)
816 {
817 grad_grad[d1][d2] = 1.;
818 for (unsigned int x = 0; x < dim; ++x)
819 {
820 unsigned int derivative = 0;
821 if (d1 == x || d2 == x)
822 {
823 if (d1 == d2)
824 derivative = 2;
825 else
826 derivative = 1;
827 }
828 grad_grad[d1][d2] *= v[x][derivative];
829 }
830 }
831
832 return grad_grad;
833 }
834}
835
836
837
838template <int dim>
839void
841 const Point<dim> &p,
842 std::vector<double> &values,
843 std::vector<Tensor<1, dim>> &grads,
844 std::vector<Tensor<2, dim>> &grad_grads,
845 std::vector<Tensor<3, dim>> &third_derivatives,
846 std::vector<Tensor<4, dim>> &fourth_derivatives) const
847{
848 if constexpr (dim == 0)
849 {
850 (void)p;
851 (void)values;
852 (void)grads;
853 (void)grad_grads;
854 (void)third_derivatives;
855 (void)fourth_derivatives;
857 }
858 else
859 {
860 Assert(values.size() == this->n() || values.empty(),
861 ExcDimensionMismatch2(values.size(), this->n(), 0));
862 Assert(grads.size() == this->n() || grads.empty(),
863 ExcDimensionMismatch2(grads.size(), this->n(), 0));
864 Assert(grad_grads.size() == this->n() || grad_grads.empty(),
865 ExcDimensionMismatch2(grad_grads.size(), this->n(), 0));
866 Assert(third_derivatives.size() == this->n() || third_derivatives.empty(),
867 ExcDimensionMismatch2(third_derivatives.size(), this->n(), 0));
868 Assert(fourth_derivatives.size() == this->n() ||
869 fourth_derivatives.empty(),
870 ExcDimensionMismatch2(fourth_derivatives.size(), this->n(), 0));
871
872 // check how many values/derivatives we have to compute
873 unsigned int n_derivatives = 0;
874 if (values.size() == this->n())
875 n_derivatives = 0;
876 if (grads.size() == this->n())
877 n_derivatives = 1;
878 if (grad_grads.size() == this->n())
879 n_derivatives = 2;
880 if (third_derivatives.size() == this->n())
881 n_derivatives = 3;
882 if (fourth_derivatives.size() == this->n())
883 n_derivatives = 4;
884
885 // compute the values (and derivatives, if necessary) of all polynomials
886 // at this evaluation point
887 std::size_t max_n_polynomials = 0;
888 for (unsigned int d = 0; d < dim; ++d)
889 max_n_polynomials = std::max(max_n_polynomials, polynomials[d].size());
890
891 // 5 is enough to store values and derivatives in all supported cases
892 boost::container::small_vector<ndarray<double, 5, dim>, 10> values_1d(
893 max_n_polynomials);
894 if (n_derivatives == 0)
895 for (unsigned int d = 0; d < dim; ++d)
896 for (unsigned int i = 0; i < polynomials[d].size(); ++i)
897 values_1d[i][0][d] = polynomials[d][i].value(p[d]);
898 else
899 for (unsigned int d = 0; d < dim; ++d)
900 for (unsigned int i = 0; i < polynomials[d].size(); ++i)
901 {
902 // The isotropic tensor product function wants us to use a
903 // different innermost index, so we cannot pass the values_1d
904 // array into the function directly
905 std::array<double, 5> derivatives;
906 polynomials[d][i].value(p[d], n_derivatives, derivatives.data());
907 for (unsigned int j = 0; j <= n_derivatives; ++j)
908 values_1d[i][j][d] = derivatives[j];
909 }
910
911 // Unroll the tensor product indices in arbitrary dimension
912 constexpr unsigned int dim1 = dim > 1 ? dim - 1 : 1;
913 boost::container::small_vector<std::array<unsigned int, dim1>, 64>
914 indices(1);
915 for (unsigned int d = 1; d < dim; ++d)
916 {
917 const unsigned int size = indices.size();
918 for (unsigned int i = 1; i < polynomials[d].size(); ++i)
919 for (unsigned int j = 0; j < size; ++j)
920 {
921 std::array<unsigned int, dim1> next_index = indices[j];
922 next_index[d - 1] = i;
923 indices.push_back(next_index);
924 }
925 }
926
927 internal::TensorProductPolynomials::evaluate_tensor_product<dim>(
928 n_derivatives,
929 values_1d,
930 polynomials[0].size(),
931 indices,
932 index_map_inverse,
933 values,
934 grads,
935 grad_grads,
936 third_derivatives,
937 fourth_derivatives);
938 }
939}
940
941
942
943template <int dim>
944unsigned int
946 const std::vector<std::vector<Polynomials::Polynomial<double>>> &pols)
947{
948 if constexpr (dim == 0)
949 {
950 (void)pols;
952 return {};
953 }
954 else
955 {
956 unsigned int y = 1;
957 for (unsigned int d = 0; d < dim; ++d)
958 y *= pols[d].size();
959 return y;
960 }
961}
962
963
964
965template <int dim>
966std::unique_ptr<ScalarPolynomialsBase<dim>>
968{
969 return std::make_unique<AnisotropicPolynomials<dim>>(*this);
970}
971
972
973
974/* ------------------- explicit instantiations -------------- */
979
980template class TensorProductPolynomials<
981 1,
983template class TensorProductPolynomials<
984 2,
986template class TensorProductPolynomials<
987 3,
989
990template class AnisotropicPolynomials<0>;
991template class AnisotropicPolynomials<1>;
992template class AnisotropicPolynomials<2>;
993template class AnisotropicPolynomials<3>;
994
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
void set_numbering(const std::vector< unsigned int > &renumber)
AnisotropicPolynomials(const std::vector< std::vector< Polynomials::Polynomial< double > > > &base_polynomials)
static unsigned int get_n_tensor_pols(const std::vector< std::vector< Polynomials::Polynomial< double > > > &pols)
std::vector< unsigned int > index_map
void compute_index(const unsigned int i, std::array< unsigned int, dim > &indices) const
Tensor< 2, dim > compute_grad_grad(const unsigned int i, const Point< dim > &p) const override
const std::vector< unsigned int > & get_numbering() const
Tensor< 1, dim > compute_grad(const unsigned int i, const Point< dim > &p) const override
std::vector< unsigned int > index_map_inverse
const std::vector< unsigned int > & get_numbering_inverse() const
virtual std::unique_ptr< ScalarPolynomialsBase< dim > > clone() const override
Definition point.h:111
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
void output_indices(std::ostream &out) const
void compute_index(const unsigned int i, std::array< unsigned int, dim > &indices) const
double compute_value(const unsigned int i, const Point< dim > &p) const override
virtual std::size_t memory_consumption() const override
Tensor< 1, dim > compute_grad(const unsigned int i, const Point< dim > &p) const override
virtual std::unique_ptr< ScalarPolynomialsBase< dim > > clone() const override
std::vector< PolynomialType > get_underlying_polynomials() const
void set_numbering(const std::vector< unsigned int > &renumber)
Tensor< 2, dim > compute_grad_grad(const unsigned int i, const Point< dim > &p) 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_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcDimensionMismatch2(std::size_t arg1, std::size_t arg2, std::size_t arg3)
#define AssertDimension(dim1, dim2)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
@ 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
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
void evaluate_tensor_product(const unsigned int n_derivatives, const boost::container::small_vector<::ndarray< double, 5, dim >, 10 > &values_1d, const unsigned int size_x, const boost::container::small_vector< std::array< unsigned int, dim1 >, 64 > &indices, const std::vector< unsigned int > &index_map, 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)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
typename internal::ndarray::HelperArray< T, Ns... >::type ndarray
Definition ndarray.h:105