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