deal.II version GIT relicensing-2289-g1e5549a87a 2024-12-21 21:30:00+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
mapping_q_internal.h
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 2020 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#ifndef dealii_mapping_q_internal_h
16#define dealii_mapping_q_internal_h
17
18#include <deal.II/base/config.h>
19
23#include <deal.II/base/point.h>
25#include <deal.II/base/table.h>
26#include <deal.II/base/tensor.h>
27
28#include <deal.II/fe/fe_tools.h>
32
34
41
42#include <array>
43#include <limits>
44
45
47
48namespace internal
49{
55 namespace MappingQ1
56 {
57 // These are left as templates on the spatial dimension (even though dim
58 // == spacedim must be true for them to make sense) because templates are
59 // expanded before the compiler eliminates code due to the 'if (dim ==
60 // spacedim)' statement (see the body of the general
61 // transform_real_to_unit_cell).
62 template <int spacedim>
63 inline Point<1>
66 &vertices,
67 const Point<spacedim> &p)
68 {
69 Assert(spacedim == 1, ExcInternalError());
70 return Point<1>((p[0] - vertices[0][0]) /
71 (vertices[1][0] - vertices[0][0]));
72 }
73
74
75
76 template <int spacedim>
77 inline Point<2>
80 &vertices,
81 const Point<spacedim> &p)
82 {
83 Assert(spacedim == 2, ExcInternalError());
84
85 // For accuracy reasons, we do all arithmetic in extended precision
86 // (long double). This has a noticeable effect on the hit rate for
87 // borderline cases and thus makes the algorithm more robust.
88 const long double x = p[0];
89 const long double y = p[1];
90
91 const long double x0 = vertices[0][0];
92 const long double x1 = vertices[1][0];
93 const long double x2 = vertices[2][0];
94 const long double x3 = vertices[3][0];
95
96 const long double y0 = vertices[0][1];
97 const long double y1 = vertices[1][1];
98 const long double y2 = vertices[2][1];
99 const long double y3 = vertices[3][1];
100
101 const long double a = (x1 - x3) * (y0 - y2) - (x0 - x2) * (y1 - y3);
102 const long double b = -(x0 - x1 - x2 + x3) * y + (x - 2 * x1 + x3) * y0 -
103 (x - 2 * x0 + x2) * y1 - (x - x1) * y2 +
104 (x - x0) * y3;
105 const long double c = (x0 - x1) * y - (x - x1) * y0 + (x - x0) * y1;
106
107 const long double discriminant = b * b - 4 * a * c;
108 // exit if the point is not in the cell (this is the only case where the
109 // discriminant is negative)
111 discriminant > 0.0,
113
114 long double eta1;
115 long double eta2;
116 const long double sqrt_discriminant = std::sqrt(discriminant);
117 // special case #1: if a is near-zero to make the discriminant exactly
118 // equal b, then use the linear formula
119 if (b != 0.0 && std::abs(b) == sqrt_discriminant)
120 {
121 eta1 = -c / b;
122 eta2 = -c / b;
123 }
124 // special case #2: a is zero for parallelograms and very small for
125 // near-parallelograms:
126 else if (std::abs(a) < 1e-8 * std::abs(b))
127 {
128 // if both a and c are very small then the root should be near
129 // zero: this first case will capture that
130 eta1 = 2 * c / (-b - sqrt_discriminant);
131 eta2 = 2 * c / (-b + sqrt_discriminant);
132 }
133 // finally, use the plain version:
134 else
135 {
136 eta1 = (-b - sqrt_discriminant) / (2 * a);
137 eta2 = (-b + sqrt_discriminant) / (2 * a);
138 }
139 // pick the one closer to the center of the cell.
140 const long double eta =
141 (std::abs(eta1 - 0.5) < std::abs(eta2 - 0.5)) ? eta1 : eta2;
142
143 /*
144 * There are two ways to compute xi from eta, but either one may have a
145 * zero denominator.
146 */
147 const long double subexpr0 = -eta * x2 + x0 * (eta - 1);
148 const long double xi_denominator0 = eta * x3 - x1 * (eta - 1) + subexpr0;
149 const long double max_x = std::max(std::max(std::abs(x0), std::abs(x1)),
150 std::max(std::abs(x2), std::abs(x3)));
151
152 if (std::abs(xi_denominator0) > 1e-10 * max_x)
153 {
154 const double xi = (x + subexpr0) / xi_denominator0;
155 return {xi, static_cast<double>(eta)};
156 }
157 else
158 {
159 const long double max_y =
161 std::max(std::abs(y2), std::abs(y3)));
162 const long double subexpr1 = -eta * y2 + y0 * (eta - 1);
163 const long double xi_denominator1 =
164 eta * y3 - y1 * (eta - 1) + subexpr1;
165 if (std::abs(xi_denominator1) > 1e-10 * max_y)
166 {
167 const double xi = (subexpr1 + y) / xi_denominator1;
168 return {xi, static_cast<double>(eta)};
169 }
170 else // give up and try Newton iteration
171 {
173 false,
174 (typename Mapping<spacedim,
175 spacedim>::ExcTransformationFailed()));
176 }
177 }
178 // bogus return to placate compiler. It should not be possible to get
179 // here.
181 return {std::numeric_limits<double>::quiet_NaN(),
182 std::numeric_limits<double>::quiet_NaN()};
183 }
184
185
186
187 template <int spacedim>
188 inline Point<3>
191 & /*vertices*/,
192 const Point<spacedim> & /*p*/)
193 {
194 // It should not be possible to get here
196 return {std::numeric_limits<double>::quiet_NaN(),
197 std::numeric_limits<double>::quiet_NaN(),
198 std::numeric_limits<double>::quiet_NaN()};
199 }
200 } // namespace MappingQ1
201
202
203
209 namespace MappingQImplementation
210 {
215 template <int dim>
216 std::vector<Point<dim>>
217 unit_support_points(const std::vector<Point<1>> &line_support_points,
218 const std::vector<unsigned int> &renumbering)
219 {
220 AssertDimension(Utilities::pow(line_support_points.size(), dim),
221 renumbering.size());
222 std::vector<Point<dim>> points(renumbering.size());
223 const unsigned int n1 = line_support_points.size();
224 for (unsigned int q2 = 0, q = 0; q2 < (dim > 2 ? n1 : 1); ++q2)
225 for (unsigned int q1 = 0; q1 < (dim > 1 ? n1 : 1); ++q1)
226 for (unsigned int q0 = 0; q0 < n1; ++q0, ++q)
227 {
228 points[renumbering[q]][0] = line_support_points[q0][0];
229 if (dim > 1)
230 points[renumbering[q]][1] = line_support_points[q1][0];
231 if (dim > 2)
232 points[renumbering[q]][2] = line_support_points[q2][0];
233 }
234 return points;
235 }
236
237
238
246 inline ::Table<2, double>
247 compute_support_point_weights_on_quad(const unsigned int polynomial_degree)
248 {
249 ::Table<2, double> loqvs;
250
251 // we are asked to compute weights for interior support points, but
252 // there are no interior points if degree==1
253 if (polynomial_degree == 1)
254 return loqvs;
255
256 const unsigned int M = polynomial_degree - 1;
257 const unsigned int n_inner_2d = M * M;
258 const unsigned int n_outer_2d = 4 + 4 * M;
259
260 // set the weights of transfinite interpolation
261 loqvs.reinit(n_inner_2d, n_outer_2d);
262 QGaussLobatto<2> gl(polynomial_degree + 1);
263 for (unsigned int i = 0; i < M; ++i)
264 for (unsigned int j = 0; j < M; ++j)
265 {
266 const Point<2> &p =
267 gl.point((i + 1) * (polynomial_degree + 1) + (j + 1));
268 const unsigned int index_table = i * M + j;
269 for (unsigned int v = 0; v < 4; ++v)
270 loqvs(index_table, v) =
272 loqvs(index_table, 4 + i) = 1. - p[0];
273 loqvs(index_table, 4 + i + M) = p[0];
274 loqvs(index_table, 4 + j + 2 * M) = 1. - p[1];
275 loqvs(index_table, 4 + j + 3 * M) = p[1];
276 }
277
278 // the sum of weights of the points at the outer rim should be one.
279 // check this
280 for (unsigned int unit_point = 0; unit_point < n_inner_2d; ++unit_point)
281 Assert(std::fabs(std::accumulate(loqvs[unit_point].begin(),
282 loqvs[unit_point].end(),
283 0.) -
284 1) < 1e-13 * polynomial_degree,
286
287 return loqvs;
288 }
289
290
291
298 inline ::Table<2, double>
299 compute_support_point_weights_on_hex(const unsigned int polynomial_degree)
300 {
301 ::Table<2, double> lohvs;
302
303 // we are asked to compute weights for interior support points, but
304 // there are no interior points if degree==1
305 if (polynomial_degree == 1)
306 return lohvs;
307
308 const unsigned int M = polynomial_degree - 1;
309
310 const unsigned int n_inner = Utilities::fixed_power<3>(M);
311 const unsigned int n_outer = 8 + 12 * M + 6 * M * M;
312
313 // set the weights of transfinite interpolation
314 lohvs.reinit(n_inner, n_outer);
315 QGaussLobatto<3> gl(polynomial_degree + 1);
316 for (unsigned int i = 0; i < M; ++i)
317 for (unsigned int j = 0; j < M; ++j)
318 for (unsigned int k = 0; k < M; ++k)
319 {
320 const Point<3> &p = gl.point((i + 1) * (M + 2) * (M + 2) +
321 (j + 1) * (M + 2) + (k + 1));
322 const unsigned int index_table = i * M * M + j * M + k;
323
324 // vertices
325 for (unsigned int v = 0; v < 8; ++v)
326 lohvs(index_table, v) =
328
329 // lines
330 {
331 constexpr std::array<unsigned int, 4> line_coordinates_y(
332 {{0, 1, 4, 5}});
333 const Point<2> py(p[0], p[2]);
334 for (unsigned int l = 0; l < 4; ++l)
335 lohvs(index_table, 8 + line_coordinates_y[l] * M + j) =
337 }
338
339 {
340 constexpr std::array<unsigned int, 4> line_coordinates_x(
341 {{2, 3, 6, 7}});
342 const Point<2> px(p[1], p[2]);
343 for (unsigned int l = 0; l < 4; ++l)
344 lohvs(index_table, 8 + line_coordinates_x[l] * M + k) =
346 }
347
348 {
349 constexpr std::array<unsigned int, 4> line_coordinates_z(
350 {{8, 9, 10, 11}});
351 const Point<2> pz(p[0], p[1]);
352 for (unsigned int l = 0; l < 4; ++l)
353 lohvs(index_table, 8 + line_coordinates_z[l] * M + i) =
355 }
356
357 // quads
358 lohvs(index_table, 8 + 12 * M + 0 * M * M + i * M + j) =
359 1. - p[0];
360 lohvs(index_table, 8 + 12 * M + 1 * M * M + i * M + j) = p[0];
361 lohvs(index_table, 8 + 12 * M + 2 * M * M + k * M + i) =
362 1. - p[1];
363 lohvs(index_table, 8 + 12 * M + 3 * M * M + k * M + i) = p[1];
364 lohvs(index_table, 8 + 12 * M + 4 * M * M + j * M + k) =
365 1. - p[2];
366 lohvs(index_table, 8 + 12 * M + 5 * M * M + j * M + k) = p[2];
367 }
368
369 // the sum of weights of the points at the outer rim should be one.
370 // check this
371 for (unsigned int unit_point = 0; unit_point < n_inner; ++unit_point)
372 Assert(std::fabs(std::accumulate(lohvs[unit_point].begin(),
373 lohvs[unit_point].end(),
374 0.) -
375 1) < 1e-13 * polynomial_degree,
377
378 return lohvs;
379 }
380
381
382
387 inline std::vector<::Table<2, double>>
389 const unsigned int polynomial_degree,
390 const unsigned int dim)
391 {
392 Assert(dim > 0 && dim <= 3, ExcImpossibleInDim(dim));
393 std::vector<::Table<2, double>> output(dim);
394 if (polynomial_degree <= 1)
395 return output;
396
397 // fill the 1d interior weights
398 QGaussLobatto<1> quadrature(polynomial_degree + 1);
399 output[0].reinit(polynomial_degree - 1,
401 for (unsigned int q = 0; q < polynomial_degree - 1; ++q)
402 for (const unsigned int i : GeometryInfo<1>::vertex_indices())
403 output[0](q, i) =
404 GeometryInfo<1>::d_linear_shape_function(quadrature.point(q + 1),
405 i);
406
407 if (dim > 1)
408 output[1] = compute_support_point_weights_on_quad(polynomial_degree);
409
410 if (dim > 2)
411 output[2] = compute_support_point_weights_on_hex(polynomial_degree);
412
413 return output;
414 }
415
416
417
421 template <int dim>
422 inline ::Table<2, double>
423 compute_support_point_weights_cell(const unsigned int polynomial_degree)
424 {
425 Assert(dim > 0 && dim <= 3, ExcImpossibleInDim(dim));
426 if (polynomial_degree <= 1)
427 return ::Table<2, double>();
428
429 QGaussLobatto<dim> quadrature(polynomial_degree + 1);
430 const std::vector<unsigned int> h2l =
431 FETools::hierarchic_to_lexicographic_numbering<dim>(polynomial_degree);
432
433 ::Table<2, double> output(quadrature.size() -
436 for (unsigned int q = 0; q < output.size(0); ++q)
437 for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
439 quadrature.point(h2l[q + GeometryInfo<dim>::vertices_per_cell]), i);
440
441 return output;
442 }
443
444
445
453 template <int dim, int spacedim>
454 inline Point<spacedim>
456 const typename ::MappingQ<dim, spacedim>::InternalData &data)
457 {
458 AssertDimension(data.shape_values.size(),
459 data.mapping_support_points.size());
460
461 // use now the InternalData to compute the point in real space.
462 Point<spacedim> p_real;
463 for (unsigned int i = 0; i < data.mapping_support_points.size(); ++i)
464 p_real += data.mapping_support_points[i] * data.shape(0, i);
465
466 return p_real;
467 }
468
469
470
475 template <int dim, int spacedim, typename Number>
476 inline Point<dim, Number>
479 const Point<dim, Number> &initial_p_unit,
480 const ArrayView<const Point<spacedim>> &points,
481 const std::vector<Polynomials::Polynomial<double>> &polynomials_1d,
482 const std::vector<unsigned int> &renumber,
483 const bool print_iterations_to_deallog = false)
484 {
485 if (print_iterations_to_deallog)
486 deallog << "Start MappingQ::do_transform_real_to_unit_cell for real "
487 << "point [ " << p << " ] " << std::endl;
488
489 AssertDimension(points.size(),
490 Utilities::pow(polynomials_1d.size(), dim));
491
492 // Newton iteration to solve
493 // f(x)=p(x)-p=0
494 // where we are looking for 'x' and p(x) is the forward transformation
495 // from unit to real cell. We solve this using a Newton iteration
496 // x_{n+1}=x_n-[f'(x)]^{-1}f(x)
497 // The start value is set to be the linear approximation to the cell
498
499 // The shape values and derivatives of the mapping at this point are
500 // previously computed.
501
502 Point<dim, Number> p_unit = initial_p_unit;
504 polynomials_1d, points, p_unit, polynomials_1d.size() == 2, renumber);
505
506 Tensor<1, spacedim, Number> f = p_real.first - p;
507
508 // early out if we already have our point in all SIMD lanes, i.e.,
509 // f.norm_square() < 1e-24 * p_real.second[0].norm_square(). To enable
510 // this step also for VectorizedArray where we do not have operator <,
511 // compare the result to zero which is defined for SIMD types
512 if (std::max(Number(0.),
513 f.norm_square() - 1e-24 * p_real.second[0].norm_square()) ==
514 Number(0.))
515 return p_unit;
516
517 // we need to compare the position of the computed p(x) against the
518 // given point 'p'. We will terminate the iteration and return 'x' if
519 // they are less than eps apart. The question is how to choose eps --
520 // or, put maybe more generally: in which norm we want these 'p' and
521 // 'p(x)' to be eps apart.
522 //
523 // the question is difficult since we may have to deal with very
524 // elongated cells where we may achieve 1e-12*h for the distance of
525 // these two points in the 'long' direction, but achieving this
526 // tolerance in the 'short' direction of the cell may not be possible
527 //
528 // what we do instead is then to terminate iterations if
529 // \| p(x) - p \|_A < eps
530 // where the A-norm is somehow induced by the transformation of the
531 // cell. in particular, we want to measure distances relative to the
532 // sizes of the cell in its principal directions.
533 //
534 // to define what exactly A should be, note that to first order we have
535 // the following (assuming that x* is the solution of the problem, i.e.,
536 // p(x*)=p):
537 // p(x) - p = p(x) - p(x*)
538 // = -grad p(x) * (x*-x) + higher order terms
539 // This suggest to measure with a norm that corresponds to
540 // A = {[grad p(x)]^T [grad p(x)]}^{-1}
541 // because then
542 // \| p(x) - p \|_A \approx \| x - x* \|
543 // Consequently, we will try to enforce that
544 // \| p(x) - p \|_A = \| f \| <= eps
545 //
546 // Note that using this norm is a bit dangerous since the norm changes
547 // in every iteration (A isn't fixed by depending on xk). However, if
548 // the cell is not too deformed (it may be stretched, but not twisted)
549 // then the mapping is almost linear and A is indeed constant or
550 // nearly so.
551 const double eps = 1.e-11;
552 const unsigned int newton_iteration_limit = 20;
553
554 Point<dim, Number> invalid_point;
555 invalid_point[0] = std::numeric_limits<double>::lowest();
556 bool tried_project_to_unit_cell = false;
557
558 unsigned int newton_iteration = 0;
559 Number f_weighted_norm_square = 1.;
560 Number last_f_weighted_norm_square = 1.;
561
562 do
563 {
564 if (print_iterations_to_deallog)
565 deallog << "Newton iteration " << newton_iteration
566 << " for unit point guess " << p_unit << std::endl;
567
568 // f'(x)
570 for (unsigned int d = 0; d < spacedim; ++d)
571 for (unsigned int e = 0; e < dim; ++e)
572 df[d][e] = p_real.second[e][d];
573
574 // Check determinant(df) > 0 on all SIMD lanes. The
575 // condition here is unreadable (but really corresponds to
576 // asking whether det(df) > 0 for all elements of the
577 // vector) because VectorizedArray does not have a member
578 // that can be used to check that all vector elements are
579 // positive. But VectorizedArray has a std::min() function,
580 // and operator==().
581 if (!(std::min(determinant(df),
582 Number(std::numeric_limits<double>::min())) ==
583 Number(std::numeric_limits<double>::min())))
584 {
585 // We allow to enter this function with an initial guess
586 // outside the unit cell. We might have run into invalid
587 // Jacobians due to that, so we should at least try once to go
588 // back to the unit cell and go on with the Newton iteration
589 // from there. Since the outside case is unlikely, we can
590 // afford spending the extra effort at this place.
591 if (tried_project_to_unit_cell == false)
592 {
595 polynomials_1d,
596 points,
597 p_unit,
598 polynomials_1d.size() == 2,
599 renumber);
600 f = p_real.first - p;
601 f_weighted_norm_square = 1.;
602 last_f_weighted_norm_square = 1;
603 tried_project_to_unit_cell = true;
604 continue;
605 }
606 else
607 return invalid_point;
608 }
609
610 // Solve [f'(x)]d=f(x)
611 const Tensor<2, spacedim, Number> df_inverse = invert(df);
612 const Tensor<1, spacedim, Number> delta = df_inverse * f;
613 last_f_weighted_norm_square = delta.norm_square();
614
615 if (print_iterations_to_deallog)
616 deallog << " delta=" << delta << std::endl;
617
618 // do a line search
619 double step_length = 1.0;
620 do
621 {
622 // update of p_unit. The spacedim-th component of transformed
623 // point is simply ignored in codimension one case. When this
624 // component is not zero, then we are projecting the point to
625 // the surface or curve identified by the cell.
626 Point<dim, Number> p_unit_trial = p_unit;
627 for (unsigned int i = 0; i < dim; ++i)
628 p_unit_trial[i] -= step_length * delta[i];
629
630 // shape values and derivatives at new p_unit point
631 const auto p_real_trial =
633 polynomials_1d,
634 points,
635 p_unit_trial,
636 polynomials_1d.size() == 2,
637 renumber);
638 const Tensor<1, spacedim, Number> f_trial =
639 p_real_trial.first - p;
640 f_weighted_norm_square = (df_inverse * f_trial).norm_square();
641
642 if (print_iterations_to_deallog)
643 {
644 deallog << " step_length=" << step_length << std::endl;
645 if (step_length == 1.0)
646 deallog << " ||f || =" << f.norm() << std::endl;
647 deallog << " ||f*|| =" << f_trial.norm() << std::endl
648 << " ||f*||_A ="
649 << std::sqrt(f_weighted_norm_square) << std::endl;
650 }
651
652 // See if we are making progress with the current step length
653 // and if not, reduce it by a factor of two and try again.
654 //
655 // Strictly speaking, we should probably use the same norm as we
656 // use for the outer algorithm. In practice, line search is just
657 // a crutch to find a "reasonable" step length, and so using the
658 // l2 norm is probably just fine.
659 //
660 // check f_trial.norm() < f.norm() in SIMD form. This is a bit
661 // more complicated because some SIMD lanes might not be doing
662 // any progress any more as they have already reached roundoff
663 // accuracy. We define that as the case of updates less than
664 // 1e-6. The tolerance might seem coarse but since we are
665 // dealing with a Newton iteration of a polynomial function we
666 // either converge quadratically or not any more. Thus, our
667 // selection is to terminate if either the norm of f is
668 // decreasing or that threshold of 1e-6 is reached.
669 if (std::max(f_weighted_norm_square - 1e-6 * 1e-6, Number(0.)) *
670 std::max(f_trial.norm_square() - f.norm_square(),
671 Number(0.)) ==
672 Number(0.))
673 {
674 p_real = p_real_trial;
675 p_unit = p_unit_trial;
676 f = f_trial;
677 break;
678 }
679 else if (step_length > 0.05)
680 step_length *= 0.5;
681 else
682 break;
683 }
684 while (true);
685
686 // In case we terminated the line search due to the step becoming
687 // too small, we give the iteration another try with the
688 // projection of the initial guess to the unit cell before we give
689 // up, just like for the negative determinant case.
690 if (step_length <= 0.05 && tried_project_to_unit_cell == false)
691 {
694 polynomials_1d,
695 points,
696 p_unit,
697 polynomials_1d.size() == 2,
698 renumber);
699 f = p_real.first - p;
700 f_weighted_norm_square = 1.;
701 last_f_weighted_norm_square = 1;
702 tried_project_to_unit_cell = true;
703 continue;
704 }
705 else if (step_length <= 0.05)
706 return invalid_point;
707
708 ++newton_iteration;
709 if (newton_iteration > newton_iteration_limit)
710 return invalid_point;
711 }
712 // Stop if f_weighted_norm_square <= eps^2 on all SIMD lanes or if the
713 // weighted norm is less than 1e-6 and the improvement against the
714 // previous step was less than a factor of 10 (in that regime, we
715 // either have quadratic convergence or roundoff errors due to a bad
716 // mapping)
717 while (
718 !(std::max(f_weighted_norm_square - eps * eps, Number(0.)) *
719 std::max(last_f_weighted_norm_square -
720 std::min(f_weighted_norm_square, Number(1e-6 * 1e-6)) *
721 100.,
722 Number(0.)) ==
723 Number(0.)));
724
725 if (print_iterations_to_deallog)
726 deallog << "Iteration converged for p_unit = [ " << p_unit
727 << " ] and iteration error "
728 << std::sqrt(f_weighted_norm_square) << std::endl;
729
730 return p_unit;
731 }
732
733
734
738 template <int dim>
739 inline Point<dim>
741 const Point<dim + 1> &p,
742 const Point<dim> &initial_p_unit,
743 const ArrayView<const Point<dim + 1>> &points,
744 const std::vector<Polynomials::Polynomial<double>> &polynomials_1d,
745 const std::vector<unsigned int> &renumber)
746 {
747 const unsigned int spacedim = dim + 1;
748
749 AssertDimension(points.size(),
750 Utilities::pow(polynomials_1d.size(), dim));
751
752 Point<dim> p_unit = initial_p_unit;
753
754 const double eps = 1.e-12;
755 const unsigned int loop_limit = 10;
756
757 unsigned int loop = 0;
758 double f_weighted_norm_square = 1.;
759
760 while (f_weighted_norm_square > eps * eps && loop++ < loop_limit)
761 {
762 const auto p_real =
764 polynomials_1d,
765 points,
766 p_unit,
767 polynomials_1d.size() == 2,
768 renumber);
769 Tensor<1, spacedim> p_minus_F = p - p_real.first;
770 const DerivativeForm<1, spacedim, dim> DF = p_real.second;
771
773 polynomials_1d, points, p_unit, renumber);
774 Point<dim> f;
776 for (unsigned int j = 0; j < dim; ++j)
777 {
778 f[j] = DF[j] * p_minus_F;
779 for (unsigned int l = 0; l < dim; ++l)
780 df[j][l] = -DF[j] * DF[l] + hessian[j][l] * p_minus_F;
781 }
782
783 // Solve [df(x)]d=f(x)
784 const Tensor<1, dim> d =
785 invert(df) * static_cast<const Tensor<1, dim> &>(f);
786 f_weighted_norm_square = d.norm_square();
787 p_unit -= d;
788 }
789
790
791 // Here we check that in the last execution of while the first
792 // condition was already wrong, meaning the residual was below
793 // eps. Only if the first condition failed, loop will have been
794 // increased and tested, and thus have reached the limit.
795 AssertThrow(loop < loop_limit,
797
798 return p_unit;
799 }
800
801
802
820 template <int dim, int spacedim>
822 {
823 public:
827 static constexpr unsigned int n_functions =
828 (spacedim == 1 ? 3 : (spacedim == 2 ? 6 : 10));
829
842 const ArrayView<const Point<spacedim>> &real_support_points,
843 const std::vector<Point<dim>> &unit_support_points)
844 : normalization_shift(real_support_points[0])
846 1. / real_support_points[0].distance(real_support_points[1]))
847 , is_affine(true)
848 {
849 AssertDimension(real_support_points.size(), unit_support_points.size());
850
851 // For the bi-/trilinear approximation, we cannot build a quadratic
852 // polynomial due to a lack of points (interpolation matrix would
853 // get singular). Similarly, it is not entirely clear how to gather
854 // enough information for the case dim < spacedim.
855 //
856 // In both cases we require the vector real_support_points to
857 // contain the vertex positions and fall back to an affine
858 // approximation:
859 Assert(dim == spacedim || real_support_points.size() ==
862 if (real_support_points.size() == GeometryInfo<dim>::vertices_per_cell)
863 {
864 const auto affine = GridTools::affine_cell_approximation<dim>(
865 make_array_view(real_support_points));
867 affine.first.covariant_form().transpose();
868
869 // The code for evaluation assumes an additional transformation of
870 // the form (x - normalization_shift) * normalization_length --
871 // account for this in the definition of the coefficients.
872 coefficients[0] =
873 apply_transformation(A_inv, normalization_shift - affine.second);
874 for (unsigned int d = 0; d < spacedim; ++d)
875 for (unsigned int e = 0; e < dim; ++e)
876 coefficients[1 + d][e] =
877 A_inv[e][d] * (1.0 / normalization_length);
878 is_affine = true;
879 return;
880 }
881
883 std::array<double, n_functions> shape_values;
884 for (unsigned int q = 0; q < unit_support_points.size(); ++q)
885 {
886 // Evaluate quadratic shape functions in point, with the
887 // normalization applied in order to avoid roundoff issues with
888 // scaling far away from 1.
889 shape_values[0] = 1.;
890 const Tensor<1, spacedim> p_scaled =
892 (real_support_points[q] - normalization_shift);
893 for (unsigned int d = 0; d < spacedim; ++d)
894 shape_values[1 + d] = p_scaled[d];
895 for (unsigned int d = 0, c = 0; d < spacedim; ++d)
896 for (unsigned int e = 0; e <= d; ++e, ++c)
897 shape_values[1 + spacedim + c] = p_scaled[d] * p_scaled[e];
898
899 // Build lower diagonal of least squares matrix and rhs, the
900 // essential part being that we construct the matrix with the
901 // real points and the right hand side by comparing to the
902 // reference point positions which sets up an inverse
903 // interpolation.
904 for (unsigned int i = 0; i < n_functions; ++i)
905 for (unsigned int j = 0; j < n_functions; ++j)
906 matrix[i][j] += shape_values[i] * shape_values[j];
907 for (unsigned int i = 0; i < n_functions; ++i)
908 coefficients[i] += shape_values[i] * unit_support_points[q];
909 }
910
911 // Factorize the matrix A = L * L^T in-place with the
912 // Cholesky-Banachiewicz algorithm. The implementation is similar to
913 // FullMatrix::cholesky() but re-implemented to avoid memory
914 // allocations and some unnecessary divisions which we can do here as
915 // we only need to solve with dim right hand sides.
916 for (unsigned int i = 0; i < n_functions; ++i)
917 {
918 double Lij_sum = 0;
919 for (unsigned int j = 0; j < i; ++j)
920 {
921 double Lik_Ljk_sum = 0;
922 for (unsigned int k = 0; k < j; ++k)
923 Lik_Ljk_sum += matrix[i][k] * matrix[j][k];
924 matrix[i][j] = matrix[j][j] * (matrix[i][j] - Lik_Ljk_sum);
925 Lij_sum += matrix[i][j] * matrix[i][j];
926 }
927 AssertThrow(matrix[i][i] - Lij_sum >= 0,
928 ExcMessage("Matrix of normal equations not positive "
929 "definite"));
930
931 // Store the inverse in the diagonal since that is the quantity
932 // needed later in the factorization as well as the forward and
933 // backward substitution, minimizing the number of divisions.
934 matrix[i][i] = 1. / std::sqrt(matrix[i][i] - Lij_sum);
935 }
936
937 // Solve lower triangular part, L * y = rhs.
938 for (unsigned int i = 0; i < n_functions; ++i)
939 {
940 Point<dim> sum = coefficients[i];
941 for (unsigned int j = 0; j < i; ++j)
942 sum -= matrix[i][j] * coefficients[j];
943 coefficients[i] = sum * matrix[i][i];
944 }
945
946 // Solve upper triangular part, L^T * x = y (i.e., x = A^{-1} * rhs)
947 for (unsigned int i = n_functions; i > 0;)
948 {
949 --i;
950 Point<dim> sum = coefficients[i];
951 for (unsigned int j = i + 1; j < n_functions; ++j)
952 sum -= matrix[j][i] * coefficients[j];
953 coefficients[i] = sum * matrix[i][i];
954 }
955
956 // Check whether the approximation is indeed affine, allowing to
957 // skip the quadratic terms.
958 is_affine = true;
959 for (unsigned int i = dim + 1; i < n_functions; ++i)
960 if (coefficients[i].norm_square() > 1e-20)
961 {
962 is_affine = false;
963 break;
964 }
965 }
966
971 default;
972
976 template <typename Number>
979 {
980 Point<dim, Number> result;
981 for (unsigned int d = 0; d < dim; ++d)
982 result[d] = coefficients[0][d];
983
984 // Apply the normalization to ensure a good conditioning. Since Number
985 // might be a vectorized array whereas the normalization is a point of
986 // doubles, we cannot use the overload of operator- and must instead
987 // loop over the components of the point.
989 for (unsigned int d = 0; d < spacedim; ++d)
990 p_scaled[d] = (p[d] - normalization_shift[d]) * normalization_length;
991
992 for (unsigned int d = 0; d < spacedim; ++d)
993 result += coefficients[1 + d] * p_scaled[d];
994
995 if (!is_affine)
996 {
997 Point<dim, Number> result_affine = result;
998 for (unsigned int d = 0, c = 0; d < spacedim; ++d)
999 for (unsigned int e = 0; e <= d; ++e, ++c)
1000 result +=
1001 coefficients[1 + spacedim + c] * (p_scaled[d] * p_scaled[e]);
1002
1003 // Check if the quadratic approximation ends up considerably
1004 // farther outside the unit cell on some or all SIMD lanes than
1005 // the affine approximation - in that case, we switch those
1006 // components back to the affine approximation. Note that the
1007 // quadratic approximation will grow more quickly away from the
1008 // unit cell. We make the selection for each SIMD lane with a
1009 // ternary operation.
1010 const Number distance_to_unit_cell = result.distance_square(
1012 const Number affine_distance_to_unit_cell =
1013 result_affine.distance_square(
1015 for (unsigned int d = 0; d < dim; ++d)
1016 result[d] = compare_and_apply_mask<SIMDComparison::greater_than>(
1017 distance_to_unit_cell,
1018 affine_distance_to_unit_cell + 0.5,
1019 result_affine[d],
1020 result[d]);
1021 }
1022 return result;
1023 }
1024
1025 private:
1034
1039
1043 std::array<Point<dim>, n_functions> coefficients;
1044
1051 };
1052
1053
1054
1060 template <int dim, int spacedim>
1061 inline void
1063 const CellSimilarity::Similarity cell_similarity,
1064 const typename ::MappingQ<dim, spacedim>::InternalData &data,
1065 std::vector<Point<spacedim>> &quadrature_points,
1066 std::vector<DerivativeForm<1, dim, spacedim>> &jacobians,
1067 std::vector<DerivativeForm<1, spacedim, dim>> &inverse_jacobians,
1068 std::vector<DerivativeForm<2, dim, spacedim>> &jacobian_grads)
1069 {
1070 const UpdateFlags update_flags = data.update_each;
1071
1072 using VectorizedArrayType =
1073 typename ::MappingQ<dim,
1074 spacedim>::InternalData::VectorizedArrayType;
1075 const unsigned int n_shape_values = data.n_shape_functions;
1076 const unsigned int n_q_points = data.shape_info.n_q_points;
1077 constexpr unsigned int n_lanes = VectorizedArrayType::size();
1078 constexpr unsigned int n_comp = 1 + (spacedim - 1) / n_lanes;
1079 constexpr unsigned int n_hessians = (dim * (dim + 1)) / 2;
1080
1081 // Since MappingQ::InternalData does not have separate arrays for the
1082 // covariant and contravariant transformations, but uses the arrays in
1083 // the `MappingRelatedData`, it can happen that vectors do not have the
1084 // right size
1085 if (update_flags & update_contravariant_transformation)
1086 jacobians.resize(n_q_points);
1087 if (update_flags & update_covariant_transformation)
1088 inverse_jacobians.resize(n_q_points);
1089
1090 EvaluationFlags::EvaluationFlags evaluation_flag =
1093 ((cell_similarity != CellSimilarity::translation) &&
1094 (update_flags & update_contravariant_transformation) ?
1097 ((cell_similarity != CellSimilarity::translation) &&
1098 (update_flags & update_jacobian_grads) ?
1101
1102 Assert(!(evaluation_flag & EvaluationFlags::values) || n_q_points > 0,
1104 Assert(!(evaluation_flag & EvaluationFlags::values) ||
1105 n_q_points == quadrature_points.size(),
1106 ExcDimensionMismatch(n_q_points, quadrature_points.size()));
1107 Assert(!(evaluation_flag & EvaluationFlags::gradients) ||
1108 data.n_shape_functions > 0,
1110 Assert(!(evaluation_flag & EvaluationFlags::hessians) ||
1111 n_q_points == jacobian_grads.size(),
1112 ExcDimensionMismatch(n_q_points, jacobian_grads.size()));
1113
1114 // shortcut in case we have an identity interpolation and only request
1115 // the quadrature points
1116 if (evaluation_flag == EvaluationFlags::values &&
1117 data.shape_info.element_type ==
1119 {
1120 for (unsigned int q = 0; q < n_q_points; ++q)
1121 quadrature_points[q] =
1122 data.mapping_support_points[data.shape_info
1123 .lexicographic_numbering[q]];
1124 return;
1125 }
1126
1128
1129 // prepare arrays
1130 if (evaluation_flag != EvaluationFlags::nothing)
1131 {
1132 eval.set_data_pointers(&data.scratch, n_comp);
1133
1134 // make sure to initialize on all lanes also when some are unused in
1135 // the code below
1136 for (unsigned int i = 0; i < n_shape_values * n_comp; ++i)
1137 eval.begin_dof_values()[i] = VectorizedArrayType();
1138
1139 const std::vector<unsigned int> &renumber_to_lexicographic =
1140 data.shape_info.lexicographic_numbering;
1141 for (unsigned int i = 0; i < n_shape_values; ++i)
1142 for (unsigned int d = 0; d < spacedim; ++d)
1143 {
1144 const unsigned int in_comp = d % n_lanes;
1145 const unsigned int out_comp = d / n_lanes;
1146 eval
1147 .begin_dof_values()[out_comp * n_shape_values + i][in_comp] =
1148 data.mapping_support_points[renumber_to_lexicographic[i]][d];
1149 }
1150
1151 // do the actual tensorized evaluation
1153 n_comp, evaluation_flag, eval.begin_dof_values(), eval);
1154 }
1155
1156 // do the postprocessing
1157 if (evaluation_flag & EvaluationFlags::values)
1158 {
1159 for (unsigned int out_comp = 0; out_comp < n_comp; ++out_comp)
1160 for (unsigned int i = 0; i < n_q_points; ++i)
1161 for (unsigned int in_comp = 0;
1162 in_comp < n_lanes && in_comp < spacedim - out_comp * n_lanes;
1163 ++in_comp)
1164 quadrature_points[i][out_comp * n_lanes + in_comp] =
1165 eval.begin_values()[out_comp * n_q_points + i][in_comp];
1166 }
1167
1168 if (evaluation_flag & EvaluationFlags::gradients)
1169 {
1170 // We need to reinterpret the data after evaluate has been applied.
1171 for (unsigned int out_comp = 0; out_comp < n_comp; ++out_comp)
1172 for (unsigned int point = 0; point < n_q_points; ++point)
1173 for (unsigned int in_comp = 0;
1174 in_comp < n_lanes && in_comp < spacedim - out_comp * n_lanes;
1175 ++in_comp)
1176 for (unsigned int j = 0; j < dim; ++j)
1177 {
1178 jacobians[point][out_comp * n_lanes + in_comp][j] =
1179 eval.begin_gradients()[(out_comp * n_q_points + point) *
1180 dim +
1181 j][in_comp];
1182 }
1183 }
1184
1185 if (update_flags & update_volume_elements)
1186 if (cell_similarity != CellSimilarity::translation)
1187 for (unsigned int point = 0; point < n_q_points; ++point)
1188 data.volume_elements[point] = jacobians[point].determinant();
1189
1190 // copy values from InternalData to vector given by reference
1191 if (update_flags & update_covariant_transformation)
1192 {
1193 AssertDimension(jacobians.size(), n_q_points);
1194 AssertDimension(inverse_jacobians.size(), n_q_points);
1195 if (cell_similarity != CellSimilarity::translation)
1196 for (unsigned int point = 0; point < n_q_points; ++point)
1197 inverse_jacobians[point] =
1198 jacobians[point].covariant_form().transpose();
1199 }
1200
1201 if (evaluation_flag & EvaluationFlags::hessians)
1202 {
1203 constexpr int desymmetrize_3d[6][2] = {
1204 {0, 0}, {1, 1}, {2, 2}, {0, 1}, {0, 2}, {1, 2}};
1205 constexpr int desymmetrize_2d[3][2] = {{0, 0}, {1, 1}, {0, 1}};
1206
1207 // We need to reinterpret the data after evaluate has been applied.
1208 for (unsigned int out_comp = 0; out_comp < n_comp; ++out_comp)
1209 for (unsigned int point = 0; point < n_q_points; ++point)
1210 for (unsigned int j = 0; j < n_hessians; ++j)
1211 for (unsigned int in_comp = 0;
1212 in_comp < n_lanes &&
1213 in_comp < spacedim - out_comp * n_lanes;
1214 ++in_comp)
1215 {
1216 const unsigned int total_number = point * n_hessians + j;
1217 const unsigned int new_point = total_number % n_q_points;
1218 const unsigned int new_hessian_comp =
1219 total_number / n_q_points;
1220 const unsigned int new_hessian_comp_i =
1221 dim == 2 ? desymmetrize_2d[new_hessian_comp][0] :
1222 desymmetrize_3d[new_hessian_comp][0];
1223 const unsigned int new_hessian_comp_j =
1224 dim == 2 ? desymmetrize_2d[new_hessian_comp][1] :
1225 desymmetrize_3d[new_hessian_comp][1];
1226 const double value =
1227 eval.begin_hessians()[(out_comp * n_q_points + point) *
1228 n_hessians +
1229 j][in_comp];
1230 jacobian_grads[new_point][out_comp * n_lanes + in_comp]
1231 [new_hessian_comp_i][new_hessian_comp_j] =
1232 value;
1233 jacobian_grads[new_point][out_comp * n_lanes + in_comp]
1234 [new_hessian_comp_j][new_hessian_comp_i] =
1235 value;
1236 }
1237 }
1238 }
1239
1240
1241
1242 template <int dim, int spacedim>
1243 inline void
1245 const CellSimilarity::Similarity cell_similarity,
1246 const typename ::MappingQ<dim, spacedim>::InternalData &data,
1247 const ArrayView<const Point<dim>> &unit_points,
1248 const std::vector<Polynomials::Polynomial<double>> &polynomials_1d,
1249 const std::vector<unsigned int> &renumber_lexicographic_to_hierarchic,
1250 std::vector<Point<spacedim>> &quadrature_points,
1251 std::vector<DerivativeForm<1, dim, spacedim>> &jacobians,
1252 std::vector<DerivativeForm<1, spacedim, dim>> &inverse_jacobians)
1253 {
1254 const UpdateFlags update_flags = data.update_each;
1255 const ArrayView<const Point<spacedim>> support_points(
1256 data.mapping_support_points);
1257
1258 const unsigned int n_points = unit_points.size();
1259 const unsigned int n_lanes = VectorizedArray<double>::size();
1260
1261 // Since MappingQ::InternalData does not have separate arrays for the
1262 // covariant and contravariant transformations, but uses the arrays in
1263 // the `MappingRelatedData`, it can happen that vectors do not have the
1264 // right size
1265 if (update_flags & update_contravariant_transformation)
1266 jacobians.resize(n_points);
1267 if (update_flags & update_covariant_transformation)
1268 inverse_jacobians.resize(n_points);
1269
1270 const bool is_translation =
1271 cell_similarity == CellSimilarity::translation;
1272
1273 const bool needs_gradient =
1274 !is_translation &&
1275 (update_flags &
1278
1279 // Use the more heavy VectorizedArray code path if there is more than
1280 // one point left to compute
1281 for (unsigned int i = 0; i < n_points; i += n_lanes)
1282 if (n_points - i > 1)
1283 {
1285 for (unsigned int j = 0; j < n_lanes; ++j)
1286 if (i + j < n_points)
1287 for (unsigned int d = 0; d < dim; ++d)
1288 p_vec[d][j] = unit_points[i + j][d];
1289 else
1290 for (unsigned int d = 0; d < dim; ++d)
1291 p_vec[d][j] = unit_points[i][d];
1292
1295 derivative;
1296 if (needs_gradient)
1297 {
1298 const auto result =
1300 polynomials_1d,
1301 support_points,
1302 p_vec,
1303 polynomials_1d.size() == 2,
1304 renumber_lexicographic_to_hierarchic);
1305
1306 value = result.first;
1307
1308 for (unsigned int d = 0; d < spacedim; ++d)
1309 for (unsigned int e = 0; e < dim; ++e)
1310 derivative[d][e] = result.second[e][d];
1311 }
1312 else
1314 polynomials_1d,
1315 support_points,
1316 p_vec,
1317 polynomials_1d.size() == 2,
1318 renumber_lexicographic_to_hierarchic);
1319
1320 if (update_flags & update_quadrature_points)
1321 for (unsigned int j = 0; j < n_lanes && i + j < n_points; ++j)
1322 for (unsigned int d = 0; d < spacedim; ++d)
1323 quadrature_points[i + j][d] = value[d][j];
1324
1325 if (is_translation)
1326 continue;
1327
1328 if (update_flags & update_contravariant_transformation)
1329 for (unsigned int j = 0; j < n_lanes && i + j < n_points; ++j)
1330 for (unsigned int d = 0; d < spacedim; ++d)
1331 for (unsigned int e = 0; e < dim; ++e)
1332 jacobians[i + j][d][e] = derivative[d][e][j];
1333
1334 if (update_flags & update_volume_elements)
1335 {
1336 const auto determinant = derivative.determinant();
1337 for (unsigned int j = 0; j < n_lanes && i + j < n_points; ++j)
1338 data.volume_elements[i + j] = determinant[j];
1339 }
1340
1341 if (update_flags & update_covariant_transformation)
1342 {
1343 const auto covariant = derivative.covariant_form();
1344 for (unsigned int j = 0; j < n_lanes && i + j < n_points; ++j)
1345 for (unsigned int d = 0; d < dim; ++d)
1346 for (unsigned int e = 0; e < spacedim; ++e)
1347 inverse_jacobians[i + j][d][e] = covariant[e][d][j];
1348 }
1349 }
1350 else
1351 {
1354 if (needs_gradient)
1355 {
1356 const auto result =
1358 polynomials_1d,
1359 support_points,
1360 unit_points[i],
1361 polynomials_1d.size() == 2,
1362 renumber_lexicographic_to_hierarchic);
1363
1364 value = result.first;
1365
1366 for (unsigned int d = 0; d < spacedim; ++d)
1367 for (unsigned int e = 0; e < dim; ++e)
1368 derivative[d][e] = result.second[e][d];
1369 }
1370 else
1372 polynomials_1d,
1373 support_points,
1374 unit_points[i],
1375 polynomials_1d.size() == 2,
1376 renumber_lexicographic_to_hierarchic);
1377
1378 if (update_flags & update_quadrature_points)
1379 quadrature_points[i] = value;
1380
1381 if (is_translation)
1382 continue;
1383
1384 if (dim == spacedim && update_flags & update_volume_elements)
1385 data.volume_elements[i] = derivative.determinant();
1386
1387 if (update_flags & update_contravariant_transformation)
1388 jacobians[i] = derivative;
1389
1390 if (update_flags & update_covariant_transformation)
1391 inverse_jacobians[i] = jacobians[i].covariant_form().transpose();
1392 }
1393 }
1394
1395
1396
1403 template <int dim, int spacedim>
1404 inline void
1406 const CellSimilarity::Similarity cell_similarity,
1407 const typename ::MappingQ<dim, spacedim>::InternalData &data,
1408 const ArrayView<const Point<dim>> &unit_points,
1409 const std::vector<Polynomials::Polynomial<double>> &polynomials_1d,
1410 const std::vector<unsigned int> &renumber_lexicographic_to_hierarchic,
1411 std::vector<DerivativeForm<2, dim, spacedim>> &jacobian_grads)
1412 {
1413 if (data.update_each & update_jacobian_grads)
1414 {
1415 const ArrayView<const Point<spacedim>> support_points(
1416 data.mapping_support_points);
1417 const unsigned int n_q_points = jacobian_grads.size();
1418
1419 if (cell_similarity != CellSimilarity::translation)
1420 for (unsigned int point = 0; point < n_q_points; ++point)
1421 {
1424 polynomials_1d,
1425 support_points,
1426 unit_points[point],
1427 renumber_lexicographic_to_hierarchic);
1428
1429 for (unsigned int i = 0; i < spacedim; ++i)
1430 for (unsigned int j = 0; j < dim; ++j)
1431 for (unsigned int l = 0; l < dim; ++l)
1432 jacobian_grads[point][i][j][l] = second[j][l][i];
1433 }
1434 }
1435 }
1436
1437
1438
1445 template <int dim, int spacedim>
1446 inline void
1448 const CellSimilarity::Similarity cell_similarity,
1449 const typename ::MappingQ<dim, spacedim>::InternalData &data,
1450 const ArrayView<const Point<dim>> &unit_points,
1451 const std::vector<Polynomials::Polynomial<double>> &polynomials_1d,
1452 const std::vector<unsigned int> &renumber_lexicographic_to_hierarchic,
1453 std::vector<Tensor<3, spacedim>> &jacobian_pushed_forward_grads)
1454 {
1456 {
1457 const ArrayView<const Point<spacedim>> support_points(
1458 data.mapping_support_points);
1459 const unsigned int n_q_points = jacobian_pushed_forward_grads.size();
1460
1461 if (cell_similarity != CellSimilarity::translation)
1462 {
1463 double tmp[spacedim][spacedim][spacedim];
1464 for (unsigned int point = 0; point < n_q_points; ++point)
1465 {
1468 polynomials_1d,
1469 support_points,
1470 unit_points[point],
1471 renumber_lexicographic_to_hierarchic);
1472 const DerivativeForm<1, dim, spacedim> covariant =
1473 data.output_data->inverse_jacobians[point].transpose();
1474
1475 // first push forward the j-components
1476 for (unsigned int i = 0; i < spacedim; ++i)
1477 for (unsigned int j = 0; j < spacedim; ++j)
1478 for (unsigned int l = 0; l < dim; ++l)
1479 {
1480 tmp[i][j][l] = second[0][l][i] * covariant[j][0];
1481 for (unsigned int jr = 1; jr < dim; ++jr)
1482 {
1483 tmp[i][j][l] +=
1484 second[jr][l][i] * covariant[j][jr];
1485 }
1486 }
1487
1488 // now, pushing forward the l-components
1489 for (unsigned int i = 0; i < spacedim; ++i)
1490 for (unsigned int j = 0; j < spacedim; ++j)
1491 for (unsigned int l = 0; l < spacedim; ++l)
1492 {
1493 jacobian_pushed_forward_grads[point][i][j][l] =
1494 tmp[i][j][0] * covariant[l][0];
1495 for (unsigned int lr = 1; lr < dim; ++lr)
1496 {
1497 jacobian_pushed_forward_grads[point][i][j][l] +=
1498 tmp[i][j][lr] * covariant[l][lr];
1499 }
1500 }
1501 }
1502 }
1503 }
1504 }
1505
1506
1507
1508 template <int dim, int spacedim, int length_tensor>
1511 const Tensor<1, length_tensor, Tensor<1, spacedim>> &compressed)
1512 {
1513 Assert(dim >= 1 && dim <= 3, ExcNotImplemented());
1515 for (unsigned int i = 0; i < spacedim; ++i)
1516 {
1517 if (dim == 1)
1518 result[i][0][0][0] = compressed[0][i];
1519 else if (dim >= 2)
1520 {
1521 for (unsigned int d = 0; d < 2; ++d)
1522 for (unsigned int e = 0; e < 2; ++e)
1523 for (unsigned int f = 0; f < 2; ++f)
1524 result[i][d][e][f] = compressed[d + e + f][i];
1525 if (dim == 3)
1526 {
1527 AssertDimension(length_tensor, 10);
1528
1529 // the derivatives are ordered in rows by increasing z
1530 // derivative, and in each row we have x^{(n-j)} y^{(j)} as
1531 // j walks through the columns
1532 for (unsigned int d = 0; d < 2; ++d)
1533 for (unsigned int e = 0; e < 2; ++e)
1534 {
1535 result[i][d][e][2] = compressed[4 + d + e][i];
1536 result[i][d][2][e] = compressed[4 + d + e][i];
1537 result[i][2][d][e] = compressed[4 + d + e][i];
1538 }
1539 for (unsigned int d = 0; d < 2; ++d)
1540 {
1541 result[i][d][2][2] = compressed[7 + d][i];
1542 result[i][2][d][2] = compressed[7 + d][i];
1543 result[i][2][2][d] = compressed[7 + d][i];
1544 }
1545 result[i][2][2][2] = compressed[9][i];
1546 }
1547 }
1548 }
1549 return result;
1550 }
1551
1552
1553
1560 template <int dim, int spacedim>
1561 inline void
1563 const CellSimilarity::Similarity cell_similarity,
1564 const typename ::MappingQ<dim, spacedim>::InternalData &data,
1565 const ArrayView<const Point<dim>> &unit_points,
1566 const std::vector<Polynomials::Polynomial<double>> &polynomials_1d,
1567 const std::vector<unsigned int> &renumber_lexicographic_to_hierarchic,
1568 std::vector<DerivativeForm<3, dim, spacedim>> &jacobian_2nd_derivatives)
1569 {
1570 if (data.update_each & update_jacobian_2nd_derivatives)
1571 {
1572 const ArrayView<const Point<spacedim>> support_points(
1573 data.mapping_support_points);
1574 const unsigned int n_q_points = jacobian_2nd_derivatives.size();
1575
1576 if (cell_similarity != CellSimilarity::translation)
1577 {
1578 for (unsigned int point = 0; point < n_q_points; ++point)
1579 {
1580 jacobian_2nd_derivatives[point] = expand_3rd_derivatives<dim>(
1581 internal::evaluate_tensor_product_higher_derivatives<3>(
1582 polynomials_1d,
1583 support_points,
1584 unit_points[point],
1585 renumber_lexicographic_to_hierarchic));
1586 }
1587 }
1588 }
1589 }
1590
1591
1592
1600 template <int dim, int spacedim>
1601 inline void
1603 const CellSimilarity::Similarity cell_similarity,
1604 const typename ::MappingQ<dim, spacedim>::InternalData &data,
1605 const ArrayView<const Point<dim>> &unit_points,
1606 const std::vector<Polynomials::Polynomial<double>> &polynomials_1d,
1607 const std::vector<unsigned int> &renumber_lexicographic_to_hierarchic,
1608 std::vector<Tensor<4, spacedim>> &jacobian_pushed_forward_2nd_derivatives)
1609 {
1611 {
1612 const ArrayView<const Point<spacedim>> support_points(
1613 data.mapping_support_points);
1614 const unsigned int n_q_points =
1615 jacobian_pushed_forward_2nd_derivatives.size();
1616
1617 if (cell_similarity != CellSimilarity::translation)
1618 {
1621 for (unsigned int point = 0; point < n_q_points; ++point)
1622 {
1624 expand_3rd_derivatives<dim>(
1625 internal::evaluate_tensor_product_higher_derivatives<3>(
1626 polynomials_1d,
1627 support_points,
1628 unit_points[point],
1629 renumber_lexicographic_to_hierarchic));
1630 const DerivativeForm<1, dim, spacedim> covariant =
1631 data.output_data->inverse_jacobians[point].transpose();
1632
1633 // push forward the j-coordinate
1634 for (unsigned int i = 0; i < spacedim; ++i)
1635 for (unsigned int j = 0; j < spacedim; ++j)
1636 for (unsigned int l = 0; l < dim; ++l)
1637 for (unsigned int m = 0; m < dim; ++m)
1638 {
1639 tmp[i][j][l][m] =
1640 third[i][0][l][m] * covariant[j][0];
1641 for (unsigned int jr = 1; jr < dim; ++jr)
1642 tmp[i][j][l][m] +=
1643 third[i][jr][l][m] * covariant[j][jr];
1644 }
1645
1646 // push forward the l-coordinate
1647 for (unsigned int i = 0; i < spacedim; ++i)
1648 for (unsigned int j = 0; j < spacedim; ++j)
1649 for (unsigned int l = 0; l < spacedim; ++l)
1650 for (unsigned int m = 0; m < dim; ++m)
1651 {
1652 tmp2[i][j][l][m] =
1653 tmp[i][j][0][m] * covariant[l][0];
1654 for (unsigned int lr = 1; lr < dim; ++lr)
1655 tmp2[i][j][l][m] +=
1656 tmp[i][j][lr][m] * covariant[l][lr];
1657 }
1658
1659 // push forward the m-coordinate
1660 for (unsigned int i = 0; i < spacedim; ++i)
1661 for (unsigned int j = 0; j < spacedim; ++j)
1662 for (unsigned int l = 0; l < spacedim; ++l)
1663 for (unsigned int m = 0; m < spacedim; ++m)
1664 {
1665 jacobian_pushed_forward_2nd_derivatives
1666 [point][i][j][l][m] =
1667 tmp2[i][j][l][0] * covariant[m][0];
1668 for (unsigned int mr = 1; mr < dim; ++mr)
1669 jacobian_pushed_forward_2nd_derivatives[point][i]
1670 [j][l]
1671 [m] +=
1672 tmp2[i][j][l][mr] * covariant[m][mr];
1673 }
1674 }
1675 }
1676 }
1677 }
1678
1679
1680
1681 template <int dim, int spacedim, int length_tensor>
1684 const Tensor<1, length_tensor, Tensor<1, spacedim>> &compressed)
1685 {
1686 Assert(dim >= 1 && dim <= 3, ExcNotImplemented());
1688 for (unsigned int i = 0; i < spacedim; ++i)
1689 {
1690 if (dim == 1)
1691 result[i][0][0][0][0] = compressed[0][i];
1692 else if (dim >= 2)
1693 {
1694 for (unsigned int d = 0; d < 2; ++d)
1695 for (unsigned int e = 0; e < 2; ++e)
1696 for (unsigned int f = 0; f < 2; ++f)
1697 for (unsigned int g = 0; g < 2; ++g)
1698 result[i][d][e][f][g] = compressed[d + e + f + g][i];
1699 if (dim == 3)
1700 {
1701 AssertDimension(length_tensor, 15);
1702
1703 // the derivatives are ordered in rows by increasing z
1704 // derivative, and in each row we have x^{(n-j)} y^{(j)} as
1705 // j walks through the columns
1706 for (unsigned int d = 0; d < 2; ++d)
1707 for (unsigned int e = 0; e < 2; ++e)
1708 for (unsigned int f = 0; f < 2; ++f)
1709 {
1710 result[i][d][e][f][2] = compressed[5 + d + e + f][i];
1711 result[i][d][e][2][f] = compressed[5 + d + e + f][i];
1712 result[i][d][2][e][f] = compressed[5 + d + e + f][i];
1713 result[i][2][d][e][f] = compressed[5 + d + e + f][i];
1714 }
1715 for (unsigned int d = 0; d < 2; ++d)
1716 for (unsigned int e = 0; e < 2; ++e)
1717 {
1718 result[i][d][e][2][2] = compressed[9 + d + e][i];
1719 result[i][d][2][e][2] = compressed[9 + d + e][i];
1720 result[i][d][2][2][e] = compressed[9 + d + e][i];
1721 result[i][2][d][e][2] = compressed[9 + d + e][i];
1722 result[i][2][d][2][e] = compressed[9 + d + e][i];
1723 result[i][2][2][d][e] = compressed[9 + d + e][i];
1724 }
1725 for (unsigned int d = 0; d < 2; ++d)
1726 {
1727 result[i][d][2][2][2] = compressed[12 + d][i];
1728 result[i][2][d][2][2] = compressed[12 + d][i];
1729 result[i][2][2][d][2] = compressed[12 + d][i];
1730 result[i][2][2][2][d] = compressed[12 + d][i];
1731 }
1732 result[i][2][2][2][2] = compressed[14][i];
1733 }
1734 }
1735 }
1736 return result;
1737 }
1738
1739
1740
1747 template <int dim, int spacedim>
1748 inline void
1750 const CellSimilarity::Similarity cell_similarity,
1751 const typename ::MappingQ<dim, spacedim>::InternalData &data,
1752 const ArrayView<const Point<dim>> &unit_points,
1753 const std::vector<Polynomials::Polynomial<double>> &polynomials_1d,
1754 const std::vector<unsigned int> &renumber_lexicographic_to_hierarchic,
1755 std::vector<DerivativeForm<4, dim, spacedim>> &jacobian_3rd_derivatives)
1756 {
1757 if (data.update_each & update_jacobian_3rd_derivatives)
1758 {
1759 const ArrayView<const Point<spacedim>> support_points(
1760 data.mapping_support_points);
1761 const unsigned int n_q_points = jacobian_3rd_derivatives.size();
1762
1763 if (cell_similarity != CellSimilarity::translation)
1764 {
1765 for (unsigned int point = 0; point < n_q_points; ++point)
1766 {
1767 jacobian_3rd_derivatives[point] = expand_4th_derivatives<dim>(
1768 internal::evaluate_tensor_product_higher_derivatives<4>(
1769 polynomials_1d,
1770 support_points,
1771 unit_points[point],
1772 renumber_lexicographic_to_hierarchic));
1773 }
1774 }
1775 }
1776 }
1777
1778
1779
1787 template <int dim, int spacedim>
1788 inline void
1790 const CellSimilarity::Similarity cell_similarity,
1791 const typename ::MappingQ<dim, spacedim>::InternalData &data,
1792 const ArrayView<const Point<dim>> &unit_points,
1793 const std::vector<Polynomials::Polynomial<double>> &polynomials_1d,
1794 const std::vector<unsigned int> &renumber_lexicographic_to_hierarchic,
1795 std::vector<Tensor<5, spacedim>> &jacobian_pushed_forward_3rd_derivatives)
1796 {
1798 {
1799 const ArrayView<const Point<spacedim>> support_points(
1800 data.mapping_support_points);
1801 const unsigned int n_q_points =
1802 jacobian_pushed_forward_3rd_derivatives.size();
1803
1804 if (cell_similarity != CellSimilarity::translation)
1805 {
1806 ::
1807 ndarray<double, spacedim, spacedim, spacedim, spacedim, dim>
1808 tmp;
1810 tmp2;
1811 for (unsigned int point = 0; point < n_q_points; ++point)
1812 {
1814 expand_4th_derivatives<dim>(
1815 internal::evaluate_tensor_product_higher_derivatives<4>(
1816 polynomials_1d,
1817 support_points,
1818 unit_points[point],
1819 renumber_lexicographic_to_hierarchic));
1820
1821 const DerivativeForm<1, dim, spacedim> covariant =
1822 data.output_data->inverse_jacobians[point].transpose();
1823
1824 // push-forward the j-coordinate
1825 for (unsigned int i = 0; i < spacedim; ++i)
1826 for (unsigned int j = 0; j < spacedim; ++j)
1827 for (unsigned int l = 0; l < dim; ++l)
1828 for (unsigned int m = 0; m < dim; ++m)
1829 for (unsigned int n = 0; n < dim; ++n)
1830 {
1831 tmp[i][j][l][m][n] =
1832 fourth[i][0][l][m][n] * covariant[j][0];
1833 for (unsigned int jr = 1; jr < dim; ++jr)
1834 tmp[i][j][l][m][n] +=
1835 fourth[i][jr][l][m][n] * covariant[j][jr];
1836 }
1837
1838 // push-forward the l-coordinate
1839 for (unsigned int i = 0; i < spacedim; ++i)
1840 for (unsigned int j = 0; j < spacedim; ++j)
1841 for (unsigned int l = 0; l < spacedim; ++l)
1842 for (unsigned int m = 0; m < dim; ++m)
1843 for (unsigned int n = 0; n < dim; ++n)
1844 {
1845 tmp2[i][j][l][m][n] =
1846 tmp[i][j][0][m][n] * covariant[l][0];
1847 for (unsigned int lr = 1; lr < dim; ++lr)
1848 tmp2[i][j][l][m][n] +=
1849 tmp[i][j][lr][m][n] * covariant[l][lr];
1850 }
1851
1852 // push-forward the m-coordinate
1853 for (unsigned int i = 0; i < spacedim; ++i)
1854 for (unsigned int j = 0; j < spacedim; ++j)
1855 for (unsigned int l = 0; l < spacedim; ++l)
1856 for (unsigned int m = 0; m < spacedim; ++m)
1857 for (unsigned int n = 0; n < dim; ++n)
1858 {
1859 tmp[i][j][l][m][n] =
1860 tmp2[i][j][l][0][n] * covariant[m][0];
1861 for (unsigned int mr = 1; mr < dim; ++mr)
1862 tmp[i][j][l][m][n] +=
1863 tmp2[i][j][l][mr][n] * covariant[m][mr];
1864 }
1865
1866 // push-forward the n-coordinate
1867 for (unsigned int i = 0; i < spacedim; ++i)
1868 for (unsigned int j = 0; j < spacedim; ++j)
1869 for (unsigned int l = 0; l < spacedim; ++l)
1870 for (unsigned int m = 0; m < spacedim; ++m)
1871 for (unsigned int n = 0; n < spacedim; ++n)
1872 {
1873 jacobian_pushed_forward_3rd_derivatives
1874 [point][i][j][l][m][n] =
1875 tmp[i][j][l][m][0] * covariant[n][0];
1876 for (unsigned int nr = 1; nr < dim; ++nr)
1877 jacobian_pushed_forward_3rd_derivatives[point]
1878 [i][j][l]
1879 [m][n] +=
1880 tmp[i][j][l][m][nr] * covariant[n][nr];
1881 }
1882 }
1883 }
1884 }
1885 }
1886
1887
1888
1898 template <int dim, int spacedim>
1899 inline void
1901 const ::MappingQ<dim, spacedim> &mapping,
1902 const typename ::Triangulation<dim, spacedim>::cell_iterator &cell,
1903 const unsigned int face_no,
1904 const unsigned int subface_no,
1905 const unsigned int n_q_points,
1906 const std::vector<double> &weights,
1907 const typename ::MappingQ<dim, spacedim>::InternalData &data,
1909 &output_data)
1910 {
1911 const UpdateFlags update_flags = data.update_each;
1912
1913 if (update_flags &
1915 {
1916 if (update_flags & update_boundary_forms)
1917 AssertDimension(output_data.boundary_forms.size(), n_q_points);
1918 if (update_flags & update_normal_vectors)
1919 AssertDimension(output_data.normal_vectors.size(), n_q_points);
1920 if (update_flags & update_JxW_values)
1921 AssertDimension(output_data.JxW_values.size(), n_q_points);
1922
1923 Assert(data.aux.size() + 1 >= dim, ExcInternalError());
1924
1925 // first compute some common data that is used for evaluating
1926 // all of the flags below
1927
1928 // map the unit tangentials to the real cell. checking for d!=dim-1
1929 // eliminates compiler warnings regarding unsigned int expressions <
1930 // 0.
1931 for (unsigned int d = 0; d != dim - 1; ++d)
1932 {
1933 const unsigned int vector_index =
1935 Assert(vector_index < data.unit_tangentials.size(),
1937 Assert(data.aux[d].size() <=
1938 data.unit_tangentials[vector_index].size(),
1940 mapping.transform(make_array_view(
1941 data.unit_tangentials[vector_index]),
1943 data,
1944 make_array_view(data.aux[d]));
1945 }
1946
1947 if (update_flags & update_boundary_forms)
1948 {
1949 // if dim==spacedim, we can use the unit tangentials to compute
1950 // the boundary form by simply taking the cross product
1951 if (dim == spacedim)
1952 {
1953 for (unsigned int i = 0; i < n_q_points; ++i)
1954 switch (dim)
1955 {
1956 case 1:
1957 // in 1d, we don't have access to any of the
1958 // data.aux fields (because it has only dim-1
1959 // components), but we can still compute the
1960 // boundary form by simply looking at the number of
1961 // the face
1962 output_data.boundary_forms[i][0] =
1963 (face_no == 0 ? -1 : +1);
1964 break;
1965 case 2:
1966 output_data.boundary_forms[i] =
1967 cross_product_2d(data.aux[0][i]);
1968 break;
1969 case 3:
1970 output_data.boundary_forms[i] =
1971 cross_product_3d(data.aux[0][i], data.aux[1][i]);
1972 break;
1973 default:
1975 }
1976 }
1977 else //(dim < spacedim)
1978 {
1979 // in the codim-one case, the boundary form results from the
1980 // cross product of all the face tangential vectors and the
1981 // cell normal vector
1982 //
1983 // to compute the cell normal, use the same method used in
1984 // fill_fe_values for cells above
1985 AssertDimension(data.output_data->jacobians.size(),
1986 n_q_points);
1987
1988 for (unsigned int point = 0; point < n_q_points; ++point)
1989 {
1990 const DerivativeForm<1, dim, spacedim> contravariant =
1991 data.output_data->jacobians[point];
1992 if (dim == 1)
1993 {
1994 // J is a tangent vector
1995 output_data.boundary_forms[point] =
1996 contravariant.transpose()[0];
1997 output_data.boundary_forms[point] /=
1998 (face_no == 0 ? -1. : +1.) *
1999 output_data.boundary_forms[point].norm();
2000 }
2001
2002 if (dim == 2)
2003 {
2005 contravariant.transpose();
2006
2007 Tensor<1, spacedim> cell_normal =
2008 cross_product_3d(DX_t[0], DX_t[1]);
2009 cell_normal /= cell_normal.norm();
2010
2011 // then compute the face normal from the face
2012 // tangent and the cell normal:
2013 output_data.boundary_forms[point] =
2014 cross_product_3d(data.aux[0][point], cell_normal);
2015 }
2016 }
2017 }
2018 }
2019
2020 if (update_flags & update_JxW_values)
2021 for (unsigned int i = 0; i < output_data.boundary_forms.size(); ++i)
2022 {
2023 output_data.JxW_values[i] =
2024 output_data.boundary_forms[i].norm() * weights[i];
2025
2026 if (subface_no != numbers::invalid_unsigned_int)
2027 {
2028 const double area_ratio = GeometryInfo<dim>::subface_ratio(
2029 cell->subface_case(face_no), subface_no);
2030 output_data.JxW_values[i] *= area_ratio;
2031 }
2032 }
2033
2034 if (update_flags & update_normal_vectors)
2035 for (unsigned int i = 0; i < output_data.normal_vectors.size(); ++i)
2036 output_data.normal_vectors[i] =
2037 Point<spacedim>(output_data.boundary_forms[i] /
2038 output_data.boundary_forms[i].norm());
2039 }
2040 }
2041
2042
2043
2050 template <int dim, int spacedim>
2051 inline void
2053 const ::MappingQ<dim, spacedim> &mapping,
2054 const typename ::Triangulation<dim, spacedim>::cell_iterator &cell,
2055 const unsigned int face_no,
2056 const unsigned int subface_no,
2057 const typename QProjector<dim>::DataSetDescriptor data_set,
2058 const Quadrature<dim - 1> &quadrature,
2059 const typename ::MappingQ<dim, spacedim>::InternalData &data,
2060 const std::vector<Polynomials::Polynomial<double>> &polynomials_1d,
2061 const std::vector<unsigned int> &renumber_lexicographic_to_hierarchic,
2063 &output_data)
2064 {
2065 const ArrayView<const Point<dim>> quadrature_points(
2066 &data.quadrature_points[data_set], quadrature.size());
2067 if (dim > 1 && data.tensor_product_quadrature)
2068 {
2069 maybe_update_q_points_Jacobians_and_grads_tensor<dim, spacedim>(
2071 data,
2072 output_data.quadrature_points,
2073 output_data.jacobians,
2074 output_data.inverse_jacobians,
2075 output_data.jacobian_grads);
2076 }
2077 else
2078 {
2082 data,
2083 quadrature_points,
2084 polynomials_1d,
2085 renumber_lexicographic_to_hierarchic,
2086 output_data.quadrature_points,
2087 output_data.jacobians,
2088 output_data.inverse_jacobians);
2089 maybe_update_jacobian_grads<dim, spacedim>(
2091 data,
2092 quadrature_points,
2093 polynomials_1d,
2094 renumber_lexicographic_to_hierarchic,
2095 output_data.jacobian_grads);
2096 }
2097 maybe_update_jacobian_pushed_forward_grads<dim, spacedim>(
2099 data,
2100 quadrature_points,
2101 polynomials_1d,
2102 renumber_lexicographic_to_hierarchic,
2103 output_data.jacobian_pushed_forward_grads);
2104 maybe_update_jacobian_2nd_derivatives<dim, spacedim>(
2106 data,
2107 quadrature_points,
2108 polynomials_1d,
2109 renumber_lexicographic_to_hierarchic,
2110 output_data.jacobian_2nd_derivatives);
2111 maybe_update_jacobian_pushed_forward_2nd_derivatives<dim, spacedim>(
2113 data,
2114 quadrature_points,
2115 polynomials_1d,
2116 renumber_lexicographic_to_hierarchic,
2118 maybe_update_jacobian_3rd_derivatives<dim, spacedim>(
2120 data,
2121 quadrature_points,
2122 polynomials_1d,
2123 renumber_lexicographic_to_hierarchic,
2124 output_data.jacobian_3rd_derivatives);
2125 maybe_update_jacobian_pushed_forward_3rd_derivatives<dim, spacedim>(
2127 data,
2128 quadrature_points,
2129 polynomials_1d,
2130 renumber_lexicographic_to_hierarchic,
2132
2134 cell,
2135 face_no,
2136 subface_no,
2137 quadrature.size(),
2138 quadrature.get_weights(),
2139 data,
2140 output_data);
2141 }
2142
2143
2144
2148 template <int dim, int spacedim, int rank>
2149 inline void
2151 const ArrayView<const Tensor<rank, dim>> &input,
2152 const MappingKind mapping_kind,
2153 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
2154 const ArrayView<Tensor<rank, spacedim>> &output)
2155 {
2156 AssertDimension(input.size(), output.size());
2157 Assert((dynamic_cast<
2158 const typename ::MappingQ<dim, spacedim>::InternalData *>(
2159 &mapping_data) != nullptr),
2161 const typename ::MappingQ<dim, spacedim>::InternalData &data =
2162 static_cast<
2163 const typename ::MappingQ<dim, spacedim>::InternalData &>(
2164 mapping_data);
2165
2166 switch (mapping_kind)
2167 {
2169 {
2172 "update_contravariant_transformation"));
2173
2174 for (unsigned int i = 0; i < output.size(); ++i)
2175 output[i] = apply_transformation(data.output_data->jacobians[i],
2176 input[i]);
2177
2178 return;
2179 }
2180
2181 case mapping_piola:
2182 {
2185 "update_contravariant_transformation"));
2186 Assert(data.update_each & update_volume_elements,
2188 "update_volume_elements"));
2189 Assert(rank == 1, ExcMessage("Only for rank 1"));
2190 if (rank != 1)
2191 return;
2192
2193 for (unsigned int i = 0; i < output.size(); ++i)
2194 {
2195 output[i] =
2196 apply_transformation(data.output_data->jacobians[i],
2197 input[i]);
2198 output[i] /= data.volume_elements[i];
2199 }
2200 return;
2201 }
2202 // We still allow this operation as in the
2203 // reference cell Derivatives are Tensor
2204 // rather than DerivativeForm
2205 case mapping_covariant:
2206 {
2209 "update_covariant_transformation"));
2210
2211 for (unsigned int i = 0; i < output.size(); ++i)
2212 output[i] = apply_transformation(
2213 data.output_data->inverse_jacobians[i].transpose(), input[i]);
2214
2215 return;
2216 }
2217
2218 default:
2220 }
2221 }
2222
2223
2224
2228 template <int dim, int spacedim, int rank>
2229 inline void
2231 const ArrayView<const Tensor<rank, dim>> &input,
2232 const MappingKind mapping_kind,
2233 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
2234 const ArrayView<Tensor<rank, spacedim>> &output)
2235 {
2236 AssertDimension(input.size(), output.size());
2237 Assert((dynamic_cast<
2238 const typename ::MappingQ<dim, spacedim>::InternalData *>(
2239 &mapping_data) != nullptr),
2241 const typename ::MappingQ<dim, spacedim>::InternalData &data =
2242 static_cast<
2243 const typename ::MappingQ<dim, spacedim>::InternalData &>(
2244 mapping_data);
2245
2246 switch (mapping_kind)
2247 {
2249 {
2252 "update_covariant_transformation"));
2255 "update_contravariant_transformation"));
2256 Assert(rank == 2, ExcMessage("Only for rank 2"));
2257
2258 for (unsigned int i = 0; i < output.size(); ++i)
2259 {
2261 apply_transformation(data.output_data->jacobians[i],
2262 transpose(input[i]));
2263 output[i] = apply_transformation(
2264 data.output_data->inverse_jacobians[i].transpose(),
2265 A.transpose());
2266 }
2267
2268 return;
2269 }
2270
2272 {
2275 "update_covariant_transformation"));
2276 Assert(rank == 2, ExcMessage("Only for rank 2"));
2277
2278 for (unsigned int i = 0; i < output.size(); ++i)
2279 {
2280 const DerivativeForm<1, dim, spacedim> covariant =
2281 data.output_data->inverse_jacobians[i].transpose();
2283 apply_transformation(covariant, transpose(input[i]));
2284 output[i] = apply_transformation(covariant, A.transpose());
2285 }
2286
2287 return;
2288 }
2289
2291 {
2294 "update_covariant_transformation"));
2297 "update_contravariant_transformation"));
2298 Assert(data.update_each & update_volume_elements,
2300 "update_volume_elements"));
2301 Assert(rank == 2, ExcMessage("Only for rank 2"));
2302
2303 for (unsigned int i = 0; i < output.size(); ++i)
2304 {
2305 const DerivativeForm<1, dim, spacedim> covariant =
2306 data.output_data->inverse_jacobians[i].transpose();
2308 apply_transformation(covariant, input[i]);
2309 const Tensor<2, spacedim> T =
2310 apply_transformation(data.output_data->jacobians[i],
2311 A.transpose());
2312
2313 output[i] = transpose(T);
2314 output[i] /= data.volume_elements[i];
2315 }
2316
2317 return;
2318 }
2319
2320 default:
2322 }
2323 }
2324
2325
2326
2330 template <int dim, int spacedim>
2331 inline void
2333 const ArrayView<const Tensor<3, dim>> &input,
2334 const MappingKind mapping_kind,
2335 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
2336 const ArrayView<Tensor<3, spacedim>> &output)
2337 {
2338 AssertDimension(input.size(), output.size());
2339 Assert((dynamic_cast<
2340 const typename ::MappingQ<dim, spacedim>::InternalData *>(
2341 &mapping_data) != nullptr),
2343 const typename ::MappingQ<dim, spacedim>::InternalData &data =
2344 static_cast<
2345 const typename ::MappingQ<dim, spacedim>::InternalData &>(
2346 mapping_data);
2347
2348 switch (mapping_kind)
2349 {
2351 {
2354 "update_covariant_transformation"));
2357 "update_contravariant_transformation"));
2358
2359 for (unsigned int q = 0; q < output.size(); ++q)
2360 {
2361 const DerivativeForm<1, dim, spacedim> covariant =
2362 data.output_data->inverse_jacobians[q].transpose();
2363 const DerivativeForm<1, dim, spacedim> contravariant =
2364 data.output_data->jacobians[q];
2365
2366 for (unsigned int i = 0; i < spacedim; ++i)
2367 {
2368 double tmp1[dim][dim];
2369 for (unsigned int J = 0; J < dim; ++J)
2370 for (unsigned int K = 0; K < dim; ++K)
2371 {
2372 tmp1[J][K] =
2373 contravariant[i][0] * input[q][0][J][K];
2374 for (unsigned int I = 1; I < dim; ++I)
2375 tmp1[J][K] +=
2376 contravariant[i][I] * input[q][I][J][K];
2377 }
2378 for (unsigned int j = 0; j < spacedim; ++j)
2379 {
2380 double tmp2[dim];
2381 for (unsigned int K = 0; K < dim; ++K)
2382 {
2383 tmp2[K] = covariant[j][0] * tmp1[0][K];
2384 for (unsigned int J = 1; J < dim; ++J)
2385 tmp2[K] += covariant[j][J] * tmp1[J][K];
2386 }
2387 for (unsigned int k = 0; k < spacedim; ++k)
2388 {
2389 output[q][i][j][k] = covariant[k][0] * tmp2[0];
2390 for (unsigned int K = 1; K < dim; ++K)
2391 output[q][i][j][k] += covariant[k][K] * tmp2[K];
2392 }
2393 }
2394 }
2395 }
2396 return;
2397 }
2398
2400 {
2403 "update_covariant_transformation"));
2404
2405 for (unsigned int q = 0; q < output.size(); ++q)
2406 {
2407 const DerivativeForm<1, dim, spacedim> covariant =
2408 data.output_data->inverse_jacobians[q].transpose();
2409
2410 for (unsigned int i = 0; i < spacedim; ++i)
2411 {
2412 double tmp1[dim][dim];
2413 for (unsigned int J = 0; J < dim; ++J)
2414 for (unsigned int K = 0; K < dim; ++K)
2415 {
2416 tmp1[J][K] = covariant[i][0] * input[q][0][J][K];
2417 for (unsigned int I = 1; I < dim; ++I)
2418 tmp1[J][K] += covariant[i][I] * input[q][I][J][K];
2419 }
2420 for (unsigned int j = 0; j < spacedim; ++j)
2421 {
2422 double tmp2[dim];
2423 for (unsigned int K = 0; K < dim; ++K)
2424 {
2425 tmp2[K] = covariant[j][0] * tmp1[0][K];
2426 for (unsigned int J = 1; J < dim; ++J)
2427 tmp2[K] += covariant[j][J] * tmp1[J][K];
2428 }
2429 for (unsigned int k = 0; k < spacedim; ++k)
2430 {
2431 output[q][i][j][k] = covariant[k][0] * tmp2[0];
2432 for (unsigned int K = 1; K < dim; ++K)
2433 output[q][i][j][k] += covariant[k][K] * tmp2[K];
2434 }
2435 }
2436 }
2437 }
2438
2439 return;
2440 }
2441
2443 {
2446 "update_covariant_transformation"));
2449 "update_contravariant_transformation"));
2450 Assert(data.update_each & update_volume_elements,
2452 "update_volume_elements"));
2453
2454 for (unsigned int q = 0; q < output.size(); ++q)
2455 {
2456 const DerivativeForm<1, dim, spacedim> covariant =
2457 data.output_data->inverse_jacobians[q].transpose();
2458 const DerivativeForm<1, dim, spacedim> contravariant =
2459 data.output_data->jacobians[q];
2460 for (unsigned int i = 0; i < spacedim; ++i)
2461 {
2462 double factor[dim];
2463 for (unsigned int I = 0; I < dim; ++I)
2464 factor[I] =
2465 contravariant[i][I] * (1. / data.volume_elements[q]);
2466 double tmp1[dim][dim];
2467 for (unsigned int J = 0; J < dim; ++J)
2468 for (unsigned int K = 0; K < dim; ++K)
2469 {
2470 tmp1[J][K] = factor[0] * input[q][0][J][K];
2471 for (unsigned int I = 1; I < dim; ++I)
2472 tmp1[J][K] += factor[I] * input[q][I][J][K];
2473 }
2474 for (unsigned int j = 0; j < spacedim; ++j)
2475 {
2476 double tmp2[dim];
2477 for (unsigned int K = 0; K < dim; ++K)
2478 {
2479 tmp2[K] = covariant[j][0] * tmp1[0][K];
2480 for (unsigned int J = 1; J < dim; ++J)
2481 tmp2[K] += covariant[j][J] * tmp1[J][K];
2482 }
2483 for (unsigned int k = 0; k < spacedim; ++k)
2484 {
2485 output[q][i][j][k] = covariant[k][0] * tmp2[0];
2486 for (unsigned int K = 1; K < dim; ++K)
2487 output[q][i][j][k] += covariant[k][K] * tmp2[K];
2488 }
2489 }
2490 }
2491 }
2492
2493 return;
2494 }
2495
2496 default:
2498 }
2499 }
2500
2501
2502
2507 template <int dim, int spacedim, int rank>
2508 inline void
2511 const MappingKind mapping_kind,
2512 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
2514 {
2515 AssertDimension(input.size(), output.size());
2516 Assert((dynamic_cast<
2517 const typename ::MappingQ<dim, spacedim>::InternalData *>(
2518 &mapping_data) != nullptr),
2520 const typename ::MappingQ<dim, spacedim>::InternalData &data =
2521 static_cast<
2522 const typename ::MappingQ<dim, spacedim>::InternalData &>(
2523 mapping_data);
2524
2525 switch (mapping_kind)
2526 {
2527 case mapping_covariant:
2528 {
2531 "update_covariant_transformation"));
2532
2533 for (unsigned int i = 0; i < output.size(); ++i)
2534 output[i] = apply_transformation(
2535 data.output_data->inverse_jacobians[i].transpose(), input[i]);
2536
2537 return;
2538 }
2539 default:
2541 }
2542 }
2543 } // namespace MappingQImplementation
2544} // namespace internal
2545
2547
2548#endif
ArrayView< std::remove_reference_t< typename std::iterator_traits< Iterator >::reference >, MemorySpaceType > make_array_view(const Iterator begin, const Iterator end)
Definition array_view.h:949
std::size_t size() const
Definition array_view.h:684
Number determinant() const
DerivativeForm< 1, dim, spacedim, Number > covariant_form() const
DerivativeForm< 1, spacedim, dim, Number > transpose() const
void set_data_pointers(AlignedVector< Number > *scratch_data, const unsigned int n_components)
const Number * begin_gradients() const
const Number * begin_values() const
const Number * begin_dof_values() const
const Number * begin_hessians() const
Abstract base class for mapping classes.
Definition mapping.h:318
Definition point.h:111
constexpr numbers::NumberTraits< Number >::real_type distance_square(const Point< dim, Number > &p) const
const std::vector< double > & get_weights() const
unsigned int size() const
numbers::NumberTraits< Number >::real_type norm() const
constexpr numbers::NumberTraits< Number >::real_type norm_square() const
std::vector< DerivativeForm< 1, spacedim, dim > > inverse_jacobians
std::vector< Tensor< 5, spacedim > > jacobian_pushed_forward_3rd_derivatives
std::vector< DerivativeForm< 4, dim, spacedim > > jacobian_3rd_derivatives
std::vector< DerivativeForm< 3, dim, spacedim > > jacobian_2nd_derivatives
std::vector< Tensor< 4, spacedim > > jacobian_pushed_forward_2nd_derivatives
std::vector< Tensor< 3, spacedim > > jacobian_pushed_forward_grads
std::vector< DerivativeForm< 2, dim, spacedim > > jacobian_grads
std::vector< DerivativeForm< 1, dim, spacedim > > jacobians
InverseQuadraticApproximation(const InverseQuadraticApproximation &)=default
Point< dim, Number > compute(const Point< spacedim, Number > &p) const
InverseQuadraticApproximation(const ArrayView< const Point< spacedim > > &real_support_points, const std::vector< Point< dim > > &unit_support_points)
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:498
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:499
DerivativeForm< 1, spacedim, dim, Number > transpose(const DerivativeForm< 1, dim, spacedim, Number > &DF)
Tensor< 1, spacedim, typename ProductType< Number1, Number2 >::type > apply_transformation(const DerivativeForm< 1, dim, spacedim, Number1 > &grad_F, const Tensor< 1, dim, Number2 > &d_x)
Point< 2 > second
Definition grid_out.cc:4630
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
#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)
UpdateFlags
@ update_jacobian_pushed_forward_2nd_derivatives
@ update_volume_elements
Determinant of the Jacobian.
@ update_contravariant_transformation
Contravariant transformation.
@ update_jacobian_pushed_forward_grads
@ update_jacobian_3rd_derivatives
@ update_jacobian_grads
Gradient of volume element.
@ update_normal_vectors
Normal vectors.
@ update_JxW_values
Transformed quadrature weights.
@ update_covariant_transformation
Covariant transformation.
@ update_quadrature_points
Transformed quadrature points.
@ update_jacobian_pushed_forward_3rd_derivatives
@ update_boundary_forms
Outer normal vector, not normalized.
@ update_jacobian_2nd_derivatives
MappingKind
Definition mapping.h:79
@ mapping_piola
Definition mapping.h:114
@ mapping_covariant_gradient
Definition mapping.h:100
@ mapping_covariant
Definition mapping.h:89
@ mapping_contravariant
Definition mapping.h:94
@ mapping_contravariant_hessian
Definition mapping.h:156
@ mapping_covariant_hessian
Definition mapping.h:150
@ mapping_contravariant_gradient
Definition mapping.h:106
@ mapping_piola_gradient
Definition mapping.h:120
@ mapping_piola_hessian
Definition mapping.h:162
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
LogStream deallog
Definition logstream.cc:36
std::vector< index_type > data
Definition mpi.cc:735
EvaluationFlags
The EvaluationFlags enum.
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
Point< 1 > transform_real_to_unit_cell(const std::array< Point< spacedim >, GeometryInfo< 1 >::vertices_per_cell > &vertices, const Point< spacedim > &p)
void maybe_update_jacobian_pushed_forward_2nd_derivatives(const CellSimilarity::Similarity cell_similarity, const typename ::MappingQ< dim, spacedim >::InternalData &data, const ArrayView< const Point< dim > > &unit_points, const std::vector< Polynomials::Polynomial< double > > &polynomials_1d, const std::vector< unsigned int > &renumber_lexicographic_to_hierarchic, std::vector< Tensor< 4, spacedim > > &jacobian_pushed_forward_2nd_derivatives)
Point< dim, Number > do_transform_real_to_unit_cell_internal(const Point< spacedim, Number > &p, const Point< dim, Number > &initial_p_unit, const ArrayView< const Point< spacedim > > &points, const std::vector< Polynomials::Polynomial< double > > &polynomials_1d, const std::vector< unsigned int > &renumber, const bool print_iterations_to_deallog=false)
DerivativeForm< 3, dim, spacedim > expand_3rd_derivatives(const Tensor< 1, length_tensor, Tensor< 1, spacedim > > &compressed)
inline ::Table< 2, double > compute_support_point_weights_cell(const unsigned int polynomial_degree)
void transform_differential_forms(const ArrayView< const DerivativeForm< rank, dim, spacedim > > &input, const MappingKind mapping_kind, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_data, const ArrayView< Tensor< rank+1, spacedim > > &output)
void maybe_update_jacobian_grads(const CellSimilarity::Similarity cell_similarity, const typename ::MappingQ< dim, spacedim >::InternalData &data, const ArrayView< const Point< dim > > &unit_points, const std::vector< Polynomials::Polynomial< double > > &polynomials_1d, const std::vector< unsigned int > &renumber_lexicographic_to_hierarchic, std::vector< DerivativeForm< 2, dim, spacedim > > &jacobian_grads)
void do_fill_fe_face_values(const ::MappingQ< dim, spacedim > &mapping, const typename ::Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const unsigned int subface_no, const typename QProjector< dim >::DataSetDescriptor data_set, const Quadrature< dim - 1 > &quadrature, const typename ::MappingQ< dim, spacedim >::InternalData &data, const std::vector< Polynomials::Polynomial< double > > &polynomials_1d, const std::vector< unsigned int > &renumber_lexicographic_to_hierarchic, internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data)
inline ::Table< 2, double > compute_support_point_weights_on_hex(const unsigned int polynomial_degree)
void transform_fields(const ArrayView< const Tensor< rank, dim > > &input, const MappingKind mapping_kind, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_data, const ArrayView< Tensor< rank, spacedim > > &output)
void maybe_update_jacobian_3rd_derivatives(const CellSimilarity::Similarity cell_similarity, const typename ::MappingQ< dim, spacedim >::InternalData &data, const ArrayView< const Point< dim > > &unit_points, const std::vector< Polynomials::Polynomial< double > > &polynomials_1d, const std::vector< unsigned int > &renumber_lexicographic_to_hierarchic, std::vector< DerivativeForm< 4, dim, spacedim > > &jacobian_3rd_derivatives)
void maybe_update_jacobian_pushed_forward_grads(const CellSimilarity::Similarity cell_similarity, const typename ::MappingQ< dim, spacedim >::InternalData &data, const ArrayView< const Point< dim > > &unit_points, const std::vector< Polynomials::Polynomial< double > > &polynomials_1d, const std::vector< unsigned int > &renumber_lexicographic_to_hierarchic, std::vector< Tensor< 3, spacedim > > &jacobian_pushed_forward_grads)
inline ::Table< 2, double > compute_support_point_weights_on_quad(const unsigned int polynomial_degree)
void maybe_update_q_points_Jacobians_generic(const CellSimilarity::Similarity cell_similarity, const typename ::MappingQ< dim, spacedim >::InternalData &data, const ArrayView< const Point< dim > > &unit_points, const std::vector< Polynomials::Polynomial< double > > &polynomials_1d, const std::vector< unsigned int > &renumber_lexicographic_to_hierarchic, std::vector< Point< spacedim > > &quadrature_points, std::vector< DerivativeForm< 1, dim, spacedim > > &jacobians, std::vector< DerivativeForm< 1, spacedim, dim > > &inverse_jacobians)
std::vector< Point< dim > > unit_support_points(const std::vector< Point< 1 > > &line_support_points, const std::vector< unsigned int > &renumbering)
void transform_gradients(const ArrayView< const Tensor< rank, dim > > &input, const MappingKind mapping_kind, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_data, const ArrayView< Tensor< rank, spacedim > > &output)
void maybe_update_q_points_Jacobians_and_grads_tensor(const CellSimilarity::Similarity cell_similarity, const typename ::MappingQ< dim, spacedim >::InternalData &data, std::vector< Point< spacedim > > &quadrature_points, std::vector< DerivativeForm< 1, dim, spacedim > > &jacobians, std::vector< DerivativeForm< 1, spacedim, dim > > &inverse_jacobians, std::vector< DerivativeForm< 2, dim, spacedim > > &jacobian_grads)
void transform_hessians(const ArrayView< const Tensor< 3, dim > > &input, const MappingKind mapping_kind, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_data, const ArrayView< Tensor< 3, spacedim > > &output)
void maybe_update_jacobian_pushed_forward_3rd_derivatives(const CellSimilarity::Similarity cell_similarity, const typename ::MappingQ< dim, spacedim >::InternalData &data, const ArrayView< const Point< dim > > &unit_points, const std::vector< Polynomials::Polynomial< double > > &polynomials_1d, const std::vector< unsigned int > &renumber_lexicographic_to_hierarchic, std::vector< Tensor< 5, spacedim > > &jacobian_pushed_forward_3rd_derivatives)
std::vector<::Table< 2, double > > compute_support_point_weights_perimeter_to_interior(const unsigned int polynomial_degree, const unsigned int dim)
DerivativeForm< 4, dim, spacedim > expand_4th_derivatives(const Tensor< 1, length_tensor, Tensor< 1, spacedim > > &compressed)
Point< spacedim > compute_mapped_location_of_point(const typename ::MappingQ< dim, spacedim >::InternalData &data)
Point< dim > do_transform_real_to_unit_cell_internal_codim1(const Point< dim+1 > &p, const Point< dim > &initial_p_unit, const ArrayView< const Point< dim+1 > > &points, const std::vector< Polynomials::Polynomial< double > > &polynomials_1d, const std::vector< unsigned int > &renumber)
void maybe_compute_face_data(const ::MappingQ< dim, spacedim > &mapping, const typename ::Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const unsigned int subface_no, const unsigned int n_q_points, const std::vector< double > &weights, const typename ::MappingQ< dim, spacedim >::InternalData &data, internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data)
void maybe_update_jacobian_2nd_derivatives(const CellSimilarity::Similarity cell_similarity, const typename ::MappingQ< dim, spacedim >::InternalData &data, const ArrayView< const Point< dim > > &unit_points, const std::vector< Polynomials::Polynomial< double > > &polynomials_1d, const std::vector< unsigned int > &renumber_lexicographic_to_hierarchic, std::vector< DerivativeForm< 3, dim, spacedim > > &jacobian_2nd_derivatives)
SymmetricTensor< 2, dim, typename ProductTypeNoPoint< Number, Number2 >::type > evaluate_tensor_product_hessian(const std::vector< Polynomials::Polynomial< double > > &poly, const ArrayView< const Number > &values, const Point< dim, Number2 > &p, const std::vector< unsigned int > &renumber={})
std::pair< typename ProductTypeNoPoint< Number, Number2 >::type, Tensor< 1, dim, typename ProductTypeNoPoint< Number, Number2 >::type > > evaluate_tensor_product_value_and_gradient(const std::vector< Polynomials::Polynomial< double > > &poly, const ArrayView< const Number > &values, const Point< dim, Number2 > &p, const bool d_linear=false, const std::vector< unsigned int > &renumber={})
ProductTypeNoPoint< Number, Number2 >::type evaluate_tensor_product_value(const std::vector< Polynomials::Polynomial< double > > &poly, const ArrayView< const Number > &values, const Point< dim, Number2 > &p, const bool d_linear=false, const std::vector< unsigned int > &renumber={})
static const unsigned int invalid_unsigned_int
Definition types.h:220
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
typename internal::ndarray::HelperArray< T, Ns... >::type ndarray
Definition ndarray.h:107
static double subface_ratio(const internal::SubfaceCase< dim > &subface_case, const unsigned int subface_no)
static Point< dim, Number > project_to_unit_cell(const Point< dim, Number > &p)
static double d_linear_shape_function(const Point< dim > &xi, const unsigned int i)
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > vertex_indices()
static void evaluate(const unsigned int n_components, const EvaluationFlags::EvaluationFlags evaluation_flag, const Number *values_dofs, FEEvaluationData< dim, Number, false > &fe_eval)
DEAL_II_HOST constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &)
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)