deal.II version GIT relicensing-2165-gc91f007519 2024-11-20 01:40: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.cc
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 2001 - 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
22#include <deal.II/base/table.h>
24
25#include <deal.II/fe/fe_dgq.h>
26#include <deal.II/fe/fe_tools.h>
31
33#include <deal.II/grid/tria.h>
35
36#include <boost/container/small_vector.hpp>
37
38#include <algorithm>
39#include <array>
40#include <cmath>
41#include <limits>
42#include <memory>
43#include <numeric>
44
45
47
48
49template <int dim, int spacedim>
51 const unsigned int polynomial_degree)
52 : polynomial_degree(polynomial_degree)
53 , n_shape_functions(Utilities::fixed_power<dim>(polynomial_degree + 1))
54 , line_support_points(QGaussLobatto<1>(polynomial_degree + 1))
55 , tensor_product_quadrature(false)
56 , output_data(nullptr)
57{}
58
59
60
61template <int dim, int spacedim>
62std::size_t
76
77
78
79template <int dim, int spacedim>
80void
82 const Quadrature<dim> &quadrature)
83{
84 // store the flags in the internal data object so we can access them
85 // in fill_fe_*_values()
86 this->update_each = update_flags;
87
88 const unsigned int n_q_points = quadrature.size();
89
90 if (this->update_each & update_volume_elements)
91 volume_elements.resize(n_q_points);
92
93 tensor_product_quadrature = quadrature.is_tensor_product();
94
95 // use of MatrixFree only for higher order elements and with more than one
96 // point where tensor products do not make sense
97 if (polynomial_degree < 2 || n_q_points == 1)
98 tensor_product_quadrature = false;
99
100 if (dim > 1)
101 {
102 // find out if the one-dimensional formula is the same
103 // in all directions
104 if (tensor_product_quadrature)
105 {
106 const std::array<Quadrature<1>, dim> &quad_array =
107 quadrature.get_tensor_basis();
108 for (unsigned int i = 1; i < dim && tensor_product_quadrature; ++i)
109 {
110 if (quad_array[i - 1].size() != quad_array[i].size())
111 {
112 tensor_product_quadrature = false;
113 break;
114 }
115 else
116 {
117 const std::vector<Point<1>> &points_1 =
118 quad_array[i - 1].get_points();
119 const std::vector<Point<1>> &points_2 =
120 quad_array[i].get_points();
121 const std::vector<double> &weights_1 =
122 quad_array[i - 1].get_weights();
123 const std::vector<double> &weights_2 =
124 quad_array[i].get_weights();
125 for (unsigned int j = 0; j < quad_array[i].size(); ++j)
127 if (std::abs(points_1[j][0] - points_2[j][0]) > 1.e-10 ||
128 std::abs(weights_1[j] - weights_2[j]) > 1.e-10)
129 {
130 tensor_product_quadrature = false;
131 break;
132 }
134 }
135 }
136
137 if (tensor_product_quadrature)
138 {
139 // use a 1d FE_DGQ and adjust the hierarchic -> lexicographic
140 // numbering manually (building an FE_Q<dim> is relatively
141 // expensive due to constraints)
143 shape_info.reinit(quadrature.get_tensor_basis()[0], fe);
144 shape_info.lexicographic_numbering =
145 FETools::lexicographic_to_hierarchic_numbering<dim>(
147 shape_info.n_q_points = n_q_points;
148 shape_info.dofs_per_component_on_cell =
150 }
151 }
152 }
153}
154
155
156
157template <int dim, int spacedim>
158void
160 const UpdateFlags update_flags,
161 const Quadrature<dim> &quadrature,
162 const unsigned int n_original_q_points)
164 reinit(update_flags, quadrature);
165
166 quadrature_points = quadrature.get_points();
167
168 if (dim > 1 && tensor_product_quadrature)
170 constexpr unsigned int facedim = dim - 1;
172 shape_info.reinit(quadrature.get_tensor_basis()[0], fe);
173 shape_info.lexicographic_numbering =
174 FETools::lexicographic_to_hierarchic_numbering<facedim>(
176 shape_info.n_q_points = n_original_q_points;
177 shape_info.dofs_per_component_on_cell =
179 }
180
181 if (dim > 1)
182 {
183 if (this->update_each &
186 aux.resize(dim - 1);
187 aux[0].resize(n_original_q_points);
188 if (dim > 2)
189 aux[1].resize(n_original_q_points);
190
191 // Compute tangentials to the unit cell.
192 for (const unsigned int i : GeometryInfo<dim>::face_indices())
193 {
194 unit_tangentials[i].resize(n_original_q_points);
195 std::fill(unit_tangentials[i].begin(),
196 unit_tangentials[i].end(),
198 if (dim > 2)
200 unit_tangentials[GeometryInfo<dim>::faces_per_cell + i]
201 .resize(n_original_q_points);
202 std::fill(
203 unit_tangentials[GeometryInfo<dim>::faces_per_cell + i]
204 .begin(),
205 unit_tangentials[GeometryInfo<dim>::faces_per_cell + i]
206 .end(),
208 }
209 }
210 }
211 }
212}
214
215
216template <int dim, int spacedim>
220 QGaussLobatto<1>(this->polynomial_degree + 1).get_points())
222 Polynomials::generate_complete_Lagrange_basis(line_support_points))
224 FETools::lexicographic_to_hierarchic_numbering<dim>(p))
226 internal::MappingQImplementation::unit_support_points<dim>(
230 internal::MappingQImplementation::
231 compute_support_point_weights_perimeter_to_interior(
232 this->polynomial_degree,
233 dim))
235 internal::MappingQImplementation::compute_support_point_weights_cell<dim>(
236 this->polynomial_degree))
237{
238 Assert(p >= 1,
239 ExcMessage("It only makes sense to create polynomial mappings "
240 "with a polynomial degree greater or equal to one."));
241}
242
243
244
245template <int dim, int spacedim>
247 : polynomial_degree(mapping.polynomial_degree)
248 , line_support_points(mapping.line_support_points)
249 , polynomials_1d(mapping.polynomials_1d)
250 , renumber_lexicographic_to_hierarchic(
251 mapping.renumber_lexicographic_to_hierarchic)
252 , unit_cell_support_points(mapping.unit_cell_support_points)
253 , support_point_weights_perimeter_to_interior(
254 mapping.support_point_weights_perimeter_to_interior)
255 , support_point_weights_cell(mapping.support_point_weights_cell)
256{}
257
258
259
260template <int dim, int spacedim>
261std::unique_ptr<Mapping<dim, spacedim>>
263{
264 return std::make_unique<MappingQ<dim, spacedim>>(*this);
265}
266
267
268
269template <int dim, int spacedim>
270unsigned int
272{
273 return polynomial_degree;
274}
275
276
277
278template <int dim, int spacedim>
282 const Point<dim> &p) const
283{
284 if (polynomial_degree == 1)
285 {
286 const auto vertices = this->get_vertices(cell);
287 return Point<spacedim>(
289 }
290 else
292 polynomials_1d,
293 make_const_array_view(this->compute_mapping_support_points(cell)),
294 p,
295 polynomials_1d.size() == 2,
296 renumber_lexicographic_to_hierarchic));
297}
298
299
300// In the code below, GCC tries to instantiate MappingQ<3,4> when
301// seeing which of the overloaded versions of
302// do_transform_real_to_unit_cell_internal() to call. This leads to bad
303// error messages and, generally, nothing very good. Avoid this by ensuring
304// that this class exists, but does not have an inner InternalData
305// type, thereby ruling out the codim-1 version of the function
306// below when doing overload resolution.
307template <>
308class MappingQ<3, 4>
309{};
310
311
312
313// visual studio freaks out when trying to determine if
314// do_transform_real_to_unit_cell_internal with dim=3 and spacedim=4 is a good
315// candidate. So instead of letting the compiler pick the correct overload, we
316// use template specialization to make sure we pick up the right function to
317// call:
318
319template <int dim, int spacedim>
323 const Point<spacedim> &,
324 const Point<dim> &) const
325{
326 // default implementation (should never be called)
328 return {};
329}
330
331
332
333template <>
337 const Point<1> &p,
338 const Point<1> &initial_p_unit) const
339{
340 // dispatch to the various specializations for spacedim=dim,
341 // spacedim=dim+1, etc
342 if (polynomial_degree == 1)
343 {
344 const auto vertices = this->get_vertices(cell);
345 return internal::MappingQImplementation::
346 do_transform_real_to_unit_cell_internal<1>(
347 p,
348 initial_p_unit,
349 ArrayView<const Point<1>>(vertices.data(), vertices.size()),
350 polynomials_1d,
351 renumber_lexicographic_to_hierarchic);
352 }
353 else
354 return internal::MappingQImplementation::
355 do_transform_real_to_unit_cell_internal<1>(
356 p,
357 initial_p_unit,
358 make_const_array_view(this->compute_mapping_support_points(cell)),
359 polynomials_1d,
360 renumber_lexicographic_to_hierarchic);
361}
362
363
364
365template <>
369 const Point<2> &p,
370 const Point<2> &initial_p_unit) const
371{
372 if (polynomial_degree == 1)
373 {
374 const auto vertices = this->get_vertices(cell);
375 return internal::MappingQImplementation::
376 do_transform_real_to_unit_cell_internal<2>(
377 p,
378 initial_p_unit,
379 ArrayView<const Point<2>>(vertices.data(), vertices.size()),
380 polynomials_1d,
381 renumber_lexicographic_to_hierarchic);
382 }
383 else
384 return internal::MappingQImplementation::
385 do_transform_real_to_unit_cell_internal<2>(
386 p,
387 initial_p_unit,
388 make_const_array_view(this->compute_mapping_support_points(cell)),
389 polynomials_1d,
390 renumber_lexicographic_to_hierarchic);
391}
392
393
394
395template <>
399 const Point<3> &p,
400 const Point<3> &initial_p_unit) const
401{
402 if (polynomial_degree == 1)
403 {
404 const auto vertices = this->get_vertices(cell);
405 return internal::MappingQImplementation::
406 do_transform_real_to_unit_cell_internal<3>(
407 p,
408 initial_p_unit,
409 ArrayView<const Point<3>>(vertices.data(), vertices.size()),
410 polynomials_1d,
411 renumber_lexicographic_to_hierarchic);
412 }
413 else
414 return internal::MappingQImplementation::
415 do_transform_real_to_unit_cell_internal<3>(
416 p,
417 initial_p_unit,
418 make_const_array_view(this->compute_mapping_support_points(cell)),
419 polynomials_1d,
420 renumber_lexicographic_to_hierarchic);
421}
422
423
424
425template <>
429 const Point<2> &p,
430 const Point<1> &initial_p_unit) const
431{
432 const int dim = 1;
433 const int spacedim = 2;
434
435 const Quadrature<dim> point_quadrature(initial_p_unit);
436
438 if (spacedim > dim)
439 update_flags |= update_jacobian_grads;
440 auto mdata = Utilities::dynamic_unique_cast<InternalData>(
441 get_data(update_flags, point_quadrature));
442
443 mdata->mapping_support_points = this->compute_mapping_support_points(cell);
444
445 // dispatch to the various specializations for spacedim=dim,
446 // spacedim=dim+1, etc
447 return internal::MappingQImplementation::
448 do_transform_real_to_unit_cell_internal_codim1<1>(
449 p,
450 initial_p_unit,
451 make_const_array_view(mdata->mapping_support_points),
452 polynomials_1d,
453 renumber_lexicographic_to_hierarchic);
454}
455
456
458template <>
462 const Point<3> &p,
463 const Point<2> &initial_p_unit) const
464{
465 const int dim = 2;
466 const int spacedim = 3;
468 const Quadrature<dim> point_quadrature(initial_p_unit);
469
471 if (spacedim > dim)
472 update_flags |= update_jacobian_grads;
473 auto mdata = Utilities::dynamic_unique_cast<InternalData>(
474 get_data(update_flags, point_quadrature));
475
476 mdata->mapping_support_points = this->compute_mapping_support_points(cell);
477
478 // dispatch to the various specializations for spacedim=dim,
479 // spacedim=dim+1, etc
480 return internal::MappingQImplementation::
481 do_transform_real_to_unit_cell_internal_codim1<2>(
482 p,
483 initial_p_unit,
484 make_const_array_view(mdata->mapping_support_points),
485 polynomials_1d,
486 renumber_lexicographic_to_hierarchic);
487}
488
490
491template <>
501
502
503
504template <int dim, int spacedim>
508 const Point<spacedim> &p) const
509{
510 // Use an exact formula if one is available. this is only the case
511 // for Q1 mappings in 1d, and in 2d if dim==spacedim
512 if ((polynomial_degree == 1) &&
513 ((dim == 1) || ((dim == 2) && (dim == spacedim))))
514 {
515 // The dimension-dependent algorithms are much faster (about 25-45x in
516 // 2d) but fail most of the time when the given point (p) is not in the
517 // cell. The dimension-independent Newton algorithm given below is
518 // slower, but more robust (though it still sometimes fails). Therefore
519 // this function implements the following strategy based on the
520 // p's dimension:
521 //
522 // * In 1d this mapping is linear, so the mapping is always invertible
523 // (and the exact formula is known) as long as the cell has non-zero
524 // length.
525 // * In 2d the exact (quadratic) formula is called first. If either the
526 // exact formula does not succeed (negative discriminant in the
527 // quadratic formula) or succeeds but finds a solution outside of the
528 // unit cell, then the Newton solver is called. The rationale for the
529 // second choice is that the exact formula may provide two different
530 // answers when mapping a point outside of the real cell, but the
531 // Newton solver (if it converges) will only return one answer.
532 // Otherwise the exact formula successfully found a point in the unit
533 // cell and that value is returned.
534 // * In 3d there is no (known to the authors) exact formula, so the Newton
535 // algorithm is used.
536 const auto vertices_ = this->get_vertices(cell);
537
538 std::array<Point<spacedim>, GeometryInfo<dim>::vertices_per_cell>
539 vertices;
540 for (unsigned int i = 0; i < vertices.size(); ++i)
541 vertices[i] = vertices_[i];
542
543 try
544 {
545 switch (dim)
546 {
547 case 1:
548 {
549 // formula not subject to any issues in 1d
550 if (spacedim == 1)
552 vertices, p);
553 else
554 break;
555 }
556
557 case 2:
558 {
559 const Point<dim> point =
561 p);
562
563 // formula not guaranteed to work for points outside of
564 // the cell. only take the computed point if it lies
565 // inside the reference cell
566 const double eps = 1e-15;
567 if (-eps <= point[1] && point[1] <= 1 + eps &&
568 -eps <= point[0] && point[0] <= 1 + eps)
569 {
570 return point;
571 }
572 else
573 break;
574 }
575
576 default:
577 {
578 // we should get here, based on the if-condition at the top
580 }
581 }
582 }
583 catch (
585 {
586 // simply fall through and continue on to the standard Newton code
587 }
588 }
589 else
590 {
591 // we can't use an explicit formula,
592 }
593
594
595 // Find the initial value for the Newton iteration by a normal
596 // projection to the least square plane determined by the vertices
597 // of the cell
598 Point<dim> initial_p_unit;
599 if (this->preserves_vertex_locations())
600 {
601 initial_p_unit = cell->real_to_unit_cell_affine_approximation(p);
602 // in 1d with spacedim > 1 the affine approximation is exact
603 if (dim == 1 && polynomial_degree == 1)
604 return initial_p_unit;
605 }
606 else
607 {
608 // else, we simply use the mid point
609 for (unsigned int d = 0; d < dim; ++d)
610 initial_p_unit[d] = 0.5;
611 }
612
613 // perform the Newton iteration and return the result. note that this
614 // statement may throw an exception, which we simply pass up to the caller
615 const Point<dim> p_unit =
616 this->transform_real_to_unit_cell_internal(cell, p, initial_p_unit);
619 return p_unit;
620}
621
622
623
624template <int dim, int spacedim>
625void
628 const ArrayView<const Point<spacedim>> &real_points,
629 const ArrayView<Point<dim>> &unit_points) const
630{
631 // Go to base class functions for dim < spacedim because it is not yet
632 // implemented with optimized code.
633 if (dim < spacedim)
634 {
636 real_points,
637 unit_points);
638 return;
639 }
640
641 AssertDimension(real_points.size(), unit_points.size());
642 std::vector<Point<spacedim>> support_points_higher_order;
643 boost::container::small_vector<Point<spacedim>,
645 vertices;
646 if (polynomial_degree == 1)
647 vertices = this->get_vertices(cell);
648 else
649 support_points_higher_order = this->compute_mapping_support_points(cell);
650 const ArrayView<const Point<spacedim>> support_points(
651 polynomial_degree == 1 ? vertices.data() :
652 support_points_higher_order.data(),
653 Utilities::pow(polynomial_degree + 1, dim));
654
655 // From the given (high-order) support points, now only pick the first
656 // 2^dim points and construct an affine approximation from those.
658 inverse_approximation(support_points, unit_cell_support_points);
659
660 const unsigned int n_points = real_points.size();
661 const unsigned int n_lanes = VectorizedArray<double>::size();
662
663 // Use the more heavy VectorizedArray code path if there is more than
664 // one point left to compute
665 for (unsigned int i = 0; i < n_points; i += n_lanes)
666 if (n_points - i > 1)
667 {
669 for (unsigned int j = 0; j < n_lanes; ++j)
670 if (i + j < n_points)
671 for (unsigned int d = 0; d < spacedim; ++d)
672 p_vec[d][j] = real_points[i + j][d];
673 else
674 for (unsigned int d = 0; d < spacedim; ++d)
675 p_vec[d][j] = real_points[i][d];
676
678 internal::MappingQImplementation::
679 do_transform_real_to_unit_cell_internal<dim, spacedim>(
680 p_vec,
681 inverse_approximation.compute(p_vec),
682 support_points,
683 polynomials_1d,
684 renumber_lexicographic_to_hierarchic);
685
686 // If the vectorized computation failed, it could be that only some of
687 // the lanes failed but others would have succeeded if we had let them
688 // compute alone without interference (like negative Jacobian
689 // determinants) from other SIMD lanes. Repeat the computation in this
690 // unlikely case with scalar arguments.
691 for (unsigned int j = 0; j < n_lanes && i + j < n_points; ++j)
692 if (numbers::is_finite(unit_point[0][j]))
693 for (unsigned int d = 0; d < dim; ++d)
694 unit_points[i + j][d] = unit_point[d][j];
695 else
696 unit_points[i + j] = internal::MappingQImplementation::
697 do_transform_real_to_unit_cell_internal<dim, spacedim>(
698 real_points[i + j],
699 inverse_approximation.compute(real_points[i + j]),
700 support_points,
701 polynomials_1d,
702 renumber_lexicographic_to_hierarchic);
703 }
704 else
705 unit_points[i] = internal::MappingQImplementation::
706 do_transform_real_to_unit_cell_internal<dim, spacedim>(
707 real_points[i],
708 inverse_approximation.compute(real_points[i]),
709 support_points,
710 polynomials_1d,
711 renumber_lexicographic_to_hierarchic);
712}
713
714
715
716template <int dim, int spacedim>
719{
720 // add flags if the respective quantities are necessary to compute
721 // what we need. note that some flags appear in both the conditions
722 // and in subsequent set operations. this leads to some circular
723 // logic. the only way to treat this is to iterate. since there are
724 // 5 if-clauses in the loop, it will take at most 5 iterations to
725 // converge. do them:
726 UpdateFlags out = in;
727 for (unsigned int i = 0; i < 5; ++i)
728 {
729 // The following is a little incorrect:
730 // If not applied on a face,
731 // update_boundary_forms does not
732 // make sense. On the other hand,
733 // it is necessary on a
734 // face. Currently,
735 // update_boundary_forms is simply
736 // ignored for the interior of a
737 // cell.
740
741 if (out &
745
746 if (out &
751
752 // The contravariant transformation is used in the Piola
753 // transformation, which requires the determinant of the Jacobi
754 // matrix of the transformation. Because we have no way of
755 // knowing here whether the finite element wants to use the
756 // contravariant or the Piola transforms, we add the JxW values
757 // to the list of flags to be updated for each cell.
760
761 // the same is true when computing normal vectors: they require
762 // the determinant of the Jacobian
763 if (out & update_normal_vectors)
765 }
766
767 return out;
768}
769
770
771
772template <int dim, int spacedim>
773std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
775 const Quadrature<dim> &q) const
776{
777 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase> data_ptr =
778 std::make_unique<InternalData>(polynomial_degree);
779 data_ptr->reinit(update_flags, q);
780 return data_ptr;
781}
782
783
784
785template <int dim, int spacedim>
786std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
788 const UpdateFlags update_flags,
789 const hp::QCollection<dim - 1> &quadrature) const
790{
791 AssertDimension(quadrature.size(), 1);
792
793 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase> data_ptr =
794 std::make_unique<InternalData>(polynomial_degree);
795 auto &data = dynamic_cast<InternalData &>(*data_ptr);
796 data.initialize_face(this->requires_update_flags(update_flags),
798 ReferenceCells::get_hypercube<dim>(), quadrature[0]),
799 quadrature[0].size());
800
801 return data_ptr;
802}
803
804
805
806template <int dim, int spacedim>
807std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
809 const UpdateFlags update_flags,
810 const Quadrature<dim - 1> &quadrature) const
811{
812 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase> data_ptr =
813 std::make_unique<InternalData>(polynomial_degree);
814 auto &data = dynamic_cast<InternalData &>(*data_ptr);
815 data.initialize_face(this->requires_update_flags(update_flags),
817 ReferenceCells::get_hypercube<dim>(), quadrature),
818 quadrature.size());
819
820 return data_ptr;
821}
822
823
824
825template <int dim, int spacedim>
829 const CellSimilarity::Similarity cell_similarity,
830 const Quadrature<dim> &quadrature,
831 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
833 &output_data) const
834{
835 // ensure that the following static_cast is really correct:
836 Assert(dynamic_cast<const InternalData *>(&internal_data) != nullptr,
838 const InternalData &data = static_cast<const InternalData &>(internal_data);
839 data.output_data = &output_data;
840
841 const unsigned int n_q_points = quadrature.size();
842
843 // recompute the support points of the transformation of this
844 // cell. we tried to be clever here in an earlier version of the
845 // library by checking whether the cell is the same as the one we
846 // had visited last, but it turns out to be difficult to determine
847 // that because a cell for the purposes of a mapping is
848 // characterized not just by its (triangulation, level, index)
849 // triple, but also by the locations of its vertices, the manifold
850 // object attached to the cell and all of its bounding faces/edges,
851 // etc. to reliably test that the "cell" we are on is, therefore,
852 // not easily done
853 if (polynomial_degree == 1)
854 {
855 data.mapping_support_points.resize(GeometryInfo<dim>::vertices_per_cell);
856 const auto vertices = this->get_vertices(cell);
857 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
858 data.mapping_support_points[i] = vertices[i];
859 }
860 else
861 data.mapping_support_points = this->compute_mapping_support_points(cell);
862
863 data.cell_of_current_support_points = cell;
864
865 // if the order of the mapping is greater than 1, then do not reuse any cell
866 // similarity information. This is necessary because the cell similarity
867 // value is computed with just cell vertices and does not take into account
868 // cell curvature.
869 const CellSimilarity::Similarity computed_cell_similarity =
870 (polynomial_degree == 1 && this->preserves_vertex_locations() ?
871 cell_similarity :
873
874 if (dim > 1 && data.tensor_product_quadrature)
875 {
876 internal::MappingQImplementation::
877 maybe_update_q_points_Jacobians_and_grads_tensor<dim, spacedim>(
878 computed_cell_similarity,
879 data,
880 output_data.quadrature_points,
881 output_data.jacobians,
882 output_data.inverse_jacobians,
883 output_data.jacobian_grads);
884 }
885 else
886 {
888 computed_cell_similarity,
889 data,
890 make_array_view(quadrature.get_points()),
891 polynomials_1d,
892 renumber_lexicographic_to_hierarchic,
893 output_data.quadrature_points,
894 output_data.jacobians,
895 output_data.inverse_jacobians);
896
898 spacedim>(
899 computed_cell_similarity,
900 data,
901 make_array_view(quadrature.get_points()),
902 polynomials_1d,
903 renumber_lexicographic_to_hierarchic,
904 output_data.jacobian_grads);
905 }
906
908 dim,
909 spacedim>(computed_cell_similarity,
910 data,
911 make_array_view(quadrature.get_points()),
912 polynomials_1d,
913 renumber_lexicographic_to_hierarchic,
915
917 dim,
918 spacedim>(computed_cell_similarity,
919 data,
920 make_array_view(quadrature.get_points()),
921 polynomials_1d,
922 renumber_lexicographic_to_hierarchic,
923 output_data.jacobian_2nd_derivatives);
924
925 internal::MappingQImplementation::
926 maybe_update_jacobian_pushed_forward_2nd_derivatives<dim, spacedim>(
927 computed_cell_similarity,
928 data,
929 make_array_view(quadrature.get_points()),
930 polynomials_1d,
931 renumber_lexicographic_to_hierarchic,
933
935 dim,
936 spacedim>(computed_cell_similarity,
937 data,
938 make_array_view(quadrature.get_points()),
939 polynomials_1d,
940 renumber_lexicographic_to_hierarchic,
941 output_data.jacobian_3rd_derivatives);
942
943 internal::MappingQImplementation::
944 maybe_update_jacobian_pushed_forward_3rd_derivatives<dim, spacedim>(
945 computed_cell_similarity,
946 data,
947 make_array_view(quadrature.get_points()),
948 polynomials_1d,
949 renumber_lexicographic_to_hierarchic,
951
952 const UpdateFlags update_flags = data.update_each;
953 const std::vector<double> &weights = quadrature.get_weights();
954
955 // Multiply quadrature weights by absolute value of Jacobian determinants or
956 // the area element g=sqrt(DX^t DX) in case of codim > 0
957
958 if (update_flags & (update_normal_vectors | update_JxW_values))
959 {
960 Assert(!(update_flags & update_JxW_values) ||
961 (output_data.JxW_values.size() == n_q_points),
962 ExcDimensionMismatch(output_data.JxW_values.size(), n_q_points));
963
964 Assert(!(update_flags & update_normal_vectors) ||
965 (output_data.normal_vectors.size() == n_q_points),
966 ExcDimensionMismatch(output_data.normal_vectors.size(),
967 n_q_points));
968
969
970 if (computed_cell_similarity != CellSimilarity::translation)
971 for (unsigned int point = 0; point < n_q_points; ++point)
972 {
973 if (dim == spacedim)
974 {
975 const double det = data.volume_elements[point];
976
977 // check for distorted cells.
978
979 // TODO: this allows for anisotropies of up to 1e6 in 3d and
980 // 1e12 in 2d. might want to find a finer
981 // (dimension-independent) criterion
982 Assert(det >
983 1e-12 * Utilities::fixed_power<dim>(
984 cell->diameter() / std::sqrt(double(dim))),
986 cell->center(), det, point)));
987
988 output_data.JxW_values[point] = weights[point] * det;
989 }
990 // if dim==spacedim, then there is no cell normal to
991 // compute. since this is for FEValues (and not FEFaceValues),
992 // there are also no face normals to compute
993 else // codim>0 case
994 {
995 Tensor<1, spacedim> DX_t[dim];
996 for (unsigned int i = 0; i < spacedim; ++i)
997 for (unsigned int j = 0; j < dim; ++j)
998 DX_t[j][i] = output_data.jacobians[point][i][j];
999
1000 Tensor<2, dim> G; // First fundamental form
1001 for (unsigned int i = 0; i < dim; ++i)
1002 for (unsigned int j = 0; j < dim; ++j)
1003 G[i][j] = DX_t[i] * DX_t[j];
1004
1005 if (update_flags & update_JxW_values)
1006 output_data.JxW_values[point] =
1007 std::sqrt(determinant(G)) * weights[point];
1008
1009 if (computed_cell_similarity ==
1011 {
1012 // we only need to flip the normal
1013 if (update_flags & update_normal_vectors)
1014 output_data.normal_vectors[point] *= -1.;
1015 }
1016 else
1017 {
1018 if (update_flags & update_normal_vectors)
1019 {
1020 Assert(spacedim == dim + 1,
1021 ExcMessage(
1022 "There is no (unique) cell normal for " +
1024 "-dimensional cells in " +
1025 Utilities::int_to_string(spacedim) +
1026 "-dimensional space. This only works if the "
1027 "space dimension is one greater than the "
1028 "dimensionality of the mesh cells."));
1029
1030 if (dim == 1)
1031 output_data.normal_vectors[point] =
1032 cross_product_2d(-DX_t[0]);
1033 else // dim == 2
1034 output_data.normal_vectors[point] =
1035 cross_product_3d(DX_t[0], DX_t[1]);
1036
1037 output_data.normal_vectors[point] /=
1038 output_data.normal_vectors[point].norm();
1039
1040 if (cell->direction_flag() == false)
1041 output_data.normal_vectors[point] *= -1.;
1042 }
1043 }
1044 } // codim>0 case
1045 }
1046 }
1047
1048 return computed_cell_similarity;
1049}
1050
1051
1052
1053template <int dim, int spacedim>
1054void
1057 const unsigned int face_no,
1058 const hp::QCollection<dim - 1> &quadrature,
1059 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
1061 &output_data) const
1062{
1063 AssertDimension(quadrature.size(), 1);
1064
1065 // ensure that the following cast is really correct:
1066 Assert((dynamic_cast<const InternalData *>(&internal_data) != nullptr),
1068 const InternalData &data = static_cast<const InternalData &>(internal_data);
1069 data.output_data = &output_data;
1070
1071 // if necessary, recompute the support points of the transformation of this
1072 // cell (note that we need to first check the triangulation pointer, since
1073 // otherwise the second test might trigger an exception if the
1074 // triangulations are not the same)
1075 if ((data.mapping_support_points.empty()) ||
1076 (&cell->get_triangulation() !=
1077 &data.cell_of_current_support_points->get_triangulation()) ||
1078 (cell != data.cell_of_current_support_points))
1079 {
1080 if (polynomial_degree == 1)
1081 {
1082 data.mapping_support_points.resize(
1084 const auto vertices = this->get_vertices(cell);
1085 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell;
1086 ++i)
1087 data.mapping_support_points[i] = vertices[i];
1088 }
1089 else
1090 data.mapping_support_points =
1091 this->compute_mapping_support_points(cell);
1092 data.cell_of_current_support_points = cell;
1093 }
1094
1096 *this,
1097 cell,
1098 face_no,
1101 ReferenceCells::get_hypercube<dim>(),
1102 face_no,
1103 cell->face_orientation(face_no),
1104 cell->face_flip(face_no),
1105 cell->face_rotation(face_no),
1106 quadrature[0].size()),
1107 quadrature[0],
1108 data,
1109 polynomials_1d,
1110 renumber_lexicographic_to_hierarchic,
1111 output_data);
1112}
1113
1114
1115
1116template <int dim, int spacedim>
1117void
1120 const unsigned int face_no,
1121 const unsigned int subface_no,
1122 const Quadrature<dim - 1> &quadrature,
1123 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
1125 &output_data) const
1126{
1127 // ensure that the following cast is really correct:
1128 Assert((dynamic_cast<const InternalData *>(&internal_data) != nullptr),
1130 const InternalData &data = static_cast<const InternalData &>(internal_data);
1131 data.output_data = &output_data;
1132
1133 // if necessary, recompute the support points of the transformation of this
1134 // cell (note that we need to first check the triangulation pointer, since
1135 // otherwise the second test might trigger an exception if the
1136 // triangulations are not the same)
1137 if ((data.mapping_support_points.empty()) ||
1138 (&cell->get_triangulation() !=
1139 &data.cell_of_current_support_points->get_triangulation()) ||
1140 (cell != data.cell_of_current_support_points))
1141 {
1142 if (polynomial_degree == 1)
1143 {
1144 data.mapping_support_points.resize(
1146 const auto vertices = this->get_vertices(cell);
1147 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell;
1148 ++i)
1149 data.mapping_support_points[i] = vertices[i];
1150 }
1151 else
1152 data.mapping_support_points =
1153 this->compute_mapping_support_points(cell);
1154 data.cell_of_current_support_points = cell;
1155 }
1156
1158 *this,
1159 cell,
1160 face_no,
1161 subface_no,
1163 ReferenceCells::get_hypercube<dim>(),
1164 face_no,
1165 subface_no,
1166 cell->combined_face_orientation(face_no),
1167 quadrature.size(),
1168 cell->subface_case(face_no)),
1169 quadrature,
1170 data,
1171 polynomials_1d,
1172 renumber_lexicographic_to_hierarchic,
1173 output_data);
1174}
1175
1176
1177
1178template <int dim, int spacedim>
1179void
1183 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
1185 &output_data) const
1186{
1187 Assert(dim == spacedim, ExcNotImplemented());
1188
1189 // ensure that the following static_cast is really correct:
1190 Assert(dynamic_cast<const InternalData *>(&internal_data) != nullptr,
1192 const InternalData &data = static_cast<const InternalData &>(internal_data);
1193 data.output_data = &output_data;
1194
1195 const unsigned int n_q_points = quadrature.size();
1196
1197 if (polynomial_degree == 1)
1198 {
1199 data.mapping_support_points.resize(GeometryInfo<dim>::vertices_per_cell);
1200 const auto vertices = this->get_vertices(cell);
1201 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
1202 data.mapping_support_points[i] = vertices[i];
1203 }
1204 else
1205 data.mapping_support_points = this->compute_mapping_support_points(cell);
1206 data.cell_of_current_support_points = cell;
1207
1210 data,
1211 make_array_view(quadrature.get_points()),
1212 polynomials_1d,
1213 renumber_lexicographic_to_hierarchic,
1214 output_data.quadrature_points,
1215 output_data.jacobians,
1216 output_data.inverse_jacobians);
1217
1218 internal::MappingQImplementation::maybe_update_jacobian_grads<dim, spacedim>(
1220 data,
1221 make_array_view(quadrature.get_points()),
1222 polynomials_1d,
1223 renumber_lexicographic_to_hierarchic,
1224 output_data.jacobian_grads);
1225
1227 dim,
1228 spacedim>(CellSimilarity::none,
1229 data,
1230 make_array_view(quadrature.get_points()),
1231 polynomials_1d,
1232 renumber_lexicographic_to_hierarchic,
1233 output_data.jacobian_pushed_forward_grads);
1234
1236 dim,
1237 spacedim>(CellSimilarity::none,
1238 data,
1239 make_array_view(quadrature.get_points()),
1240 polynomials_1d,
1241 renumber_lexicographic_to_hierarchic,
1242 output_data.jacobian_2nd_derivatives);
1243
1244 internal::MappingQImplementation::
1245 maybe_update_jacobian_pushed_forward_2nd_derivatives<dim, spacedim>(
1247 data,
1248 make_array_view(quadrature.get_points()),
1249 polynomials_1d,
1250 renumber_lexicographic_to_hierarchic,
1252
1254 dim,
1255 spacedim>(CellSimilarity::none,
1256 data,
1257 make_array_view(quadrature.get_points()),
1258 polynomials_1d,
1259 renumber_lexicographic_to_hierarchic,
1260 output_data.jacobian_3rd_derivatives);
1261
1262 internal::MappingQImplementation::
1263 maybe_update_jacobian_pushed_forward_3rd_derivatives<dim, spacedim>(
1265 data,
1266 make_array_view(quadrature.get_points()),
1267 polynomials_1d,
1268 renumber_lexicographic_to_hierarchic,
1270
1271 const UpdateFlags update_flags = data.update_each;
1272 const std::vector<double> &weights = quadrature.get_weights();
1273
1274 if ((update_flags & (update_normal_vectors | update_JxW_values)) != 0u)
1275 {
1276 AssertDimension(output_data.JxW_values.size(), n_q_points);
1277
1278 Assert(!(update_flags & update_normal_vectors) ||
1279 (output_data.normal_vectors.size() == n_q_points),
1280 ExcDimensionMismatch(output_data.normal_vectors.size(),
1281 n_q_points));
1282
1283
1284 for (unsigned int point = 0; point < n_q_points; ++point)
1285 {
1286 const double det = data.volume_elements[point];
1287
1288 // check for distorted cells.
1289
1290 // TODO: this allows for anisotropies of up to 1e6 in 3d and
1291 // 1e12 in 2d. might want to find a finer
1292 // (dimension-independent) criterion
1293 Assert(det > 1e-12 * Utilities::fixed_power<dim>(
1294 cell->diameter() / std::sqrt(double(dim))),
1296 cell->center(), det, point)));
1297
1298 // The normals are n = J^{-T} * \hat{n} before normalizing.
1299 Tensor<1, spacedim> normal;
1300 for (unsigned int d = 0; d < spacedim; d++)
1301 normal[d] = output_data.inverse_jacobians[point].transpose()[d] *
1302 quadrature.normal_vector(point);
1303
1304 output_data.JxW_values[point] = weights[point] * det * normal.norm();
1305
1306 if ((update_flags & update_normal_vectors) != 0u)
1307 {
1308 normal /= normal.norm();
1309 output_data.normal_vectors[point] = normal;
1310 }
1311 }
1312 }
1313}
1314
1315
1316
1317template <int dim, int spacedim>
1318void
1321 const ArrayView<const Point<dim>> &unit_points,
1322 const UpdateFlags update_flags,
1324 &output_data) const
1325{
1326 if (update_flags == update_default)
1327 return;
1328
1329 Assert(update_flags & update_inverse_jacobians ||
1330 update_flags & update_jacobians ||
1331 update_flags & update_quadrature_points,
1333
1334 output_data.initialize(unit_points.size(), update_flags);
1335
1336 auto internal_data =
1337 this->get_data(update_flags,
1338 Quadrature<dim>(std::vector<Point<dim>>(unit_points.begin(),
1339 unit_points.end())));
1340 const InternalData &data = static_cast<const InternalData &>(*internal_data);
1341 data.output_data = &output_data;
1342 if (polynomial_degree == 1)
1343 {
1344 data.mapping_support_points.resize(GeometryInfo<dim>::vertices_per_cell);
1345 const auto vertices = this->get_vertices(cell);
1346 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
1347 data.mapping_support_points[i] = vertices[i];
1348 }
1349 else
1350 data.mapping_support_points = this->compute_mapping_support_points(cell);
1351
1354 data,
1355 unit_points,
1356 polynomials_1d,
1357 renumber_lexicographic_to_hierarchic,
1358 output_data.quadrature_points,
1359 output_data.jacobians,
1360 output_data.inverse_jacobians);
1361}
1362
1363
1364
1365template <int dim, int spacedim>
1366void
1369 const unsigned int face_no,
1370 const Quadrature<dim - 1> &face_quadrature,
1371 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
1373 &output_data) const
1374{
1375 if (face_quadrature.get_points().empty())
1376 return;
1377
1378 // ensure that the following static_cast is really correct:
1379 Assert(dynamic_cast<const InternalData *>(&internal_data) != nullptr,
1381 const InternalData &data = static_cast<const InternalData &>(internal_data);
1382
1383 if (polynomial_degree == 1)
1384 {
1386 const auto vertices = this->get_vertices(cell);
1387 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
1388 data.mapping_support_points[i] = vertices[i];
1389 }
1390 else
1391 data.mapping_support_points = this->compute_mapping_support_points(cell);
1392 data.output_data = &output_data;
1393
1395 *this,
1396 cell,
1397 face_no,
1400 face_quadrature,
1401 data,
1402 polynomials_1d,
1403 renumber_lexicographic_to_hierarchic,
1404 output_data);
1405}
1406
1407
1408
1409template <int dim, int spacedim>
1410void
1412 const ArrayView<const Tensor<1, dim>> &input,
1413 const MappingKind mapping_kind,
1414 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1415 const ArrayView<Tensor<1, spacedim>> &output) const
1416{
1418 mapping_kind,
1419 mapping_data,
1420 output);
1421}
1422
1423
1424
1425template <int dim, int spacedim>
1426void
1428 const ArrayView<const DerivativeForm<1, dim, spacedim>> &input,
1429 const MappingKind mapping_kind,
1430 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1431 const ArrayView<Tensor<2, spacedim>> &output) const
1432{
1434 mapping_kind,
1435 mapping_data,
1436 output);
1437}
1438
1439
1440
1441template <int dim, int spacedim>
1442void
1444 const ArrayView<const Tensor<2, dim>> &input,
1445 const MappingKind mapping_kind,
1446 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1447 const ArrayView<Tensor<2, spacedim>> &output) const
1448{
1449 switch (mapping_kind)
1450 {
1453 mapping_kind,
1454 mapping_data,
1455 output);
1456 return;
1457
1462 mapping_kind,
1463 mapping_data,
1464 output);
1465 return;
1466 default:
1468 }
1469}
1470
1471
1472
1473template <int dim, int spacedim>
1474void
1476 const ArrayView<const DerivativeForm<2, dim, spacedim>> &input,
1477 const MappingKind mapping_kind,
1478 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1479 const ArrayView<Tensor<3, spacedim>> &output) const
1480{
1481 AssertDimension(input.size(), output.size());
1482 Assert(dynamic_cast<const InternalData *>(&mapping_data) != nullptr,
1485 &data = *static_cast<const InternalData &>(mapping_data).output_data;
1486
1487 switch (mapping_kind)
1488 {
1490 {
1491 Assert(!data.inverse_jacobians.empty(),
1493 "update_covariant_transformation"));
1494
1495 for (unsigned int q = 0; q < output.size(); ++q)
1496 for (unsigned int i = 0; i < spacedim; ++i)
1497 for (unsigned int j = 0; j < spacedim; ++j)
1498 {
1499 double tmp[dim];
1500 const DerivativeForm<1, dim, spacedim> covariant =
1501 data.inverse_jacobians[q].transpose();
1502 for (unsigned int K = 0; K < dim; ++K)
1503 {
1504 tmp[K] = covariant[j][0] * input[q][i][0][K];
1505 for (unsigned int J = 1; J < dim; ++J)
1506 tmp[K] += covariant[j][J] * input[q][i][J][K];
1507 }
1508 for (unsigned int k = 0; k < spacedim; ++k)
1509 {
1510 output[q][i][j][k] = covariant[k][0] * tmp[0];
1511 for (unsigned int K = 1; K < dim; ++K)
1512 output[q][i][j][k] += covariant[k][K] * tmp[K];
1513 }
1514 }
1515 return;
1516 }
1517
1518 default:
1520 }
1521}
1522
1523
1524
1525template <int dim, int spacedim>
1526void
1528 const ArrayView<const Tensor<3, dim>> &input,
1529 const MappingKind mapping_kind,
1530 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1531 const ArrayView<Tensor<3, spacedim>> &output) const
1532{
1533 switch (mapping_kind)
1534 {
1539 mapping_kind,
1540 mapping_data,
1541 output);
1542 return;
1543 default:
1545 }
1546}
1547
1548
1549
1550template <int dim, int spacedim>
1551void
1554 std::vector<Point<spacedim>> &a) const
1555{
1556 // if we only need the midpoint, then ask for it.
1557 if (this->polynomial_degree == 2)
1558 {
1559 for (unsigned int line_no = 0;
1560 line_no < GeometryInfo<dim>::lines_per_cell;
1561 ++line_no)
1562 {
1564 (dim == 1 ?
1565 static_cast<
1567 cell->line(line_no));
1568
1569 const Manifold<dim, spacedim> &manifold =
1570 ((line->manifold_id() == numbers::flat_manifold_id) &&
1571 (dim < spacedim) ?
1572 cell->get_manifold() :
1573 line->get_manifold());
1574 a.push_back(manifold.get_new_point_on_line(line));
1575 }
1576 }
1577 else
1578 // otherwise call the more complicated functions and ask for inner points
1579 // from the manifold description
1580 {
1581 std::vector<Point<spacedim>> tmp_points;
1582 for (unsigned int line_no = 0;
1583 line_no < GeometryInfo<dim>::lines_per_cell;
1584 ++line_no)
1585 {
1587 (dim == 1 ?
1588 static_cast<
1590 cell->line(line_no));
1591
1592 const Manifold<dim, spacedim> &manifold =
1593 ((line->manifold_id() == numbers::flat_manifold_id) &&
1594 (dim < spacedim) ?
1595 cell->get_manifold() :
1596 line->get_manifold());
1597
1598 const auto reference_cell = ReferenceCells::get_hypercube<dim>();
1599 const std::array<Point<spacedim>, 2> vertices{
1600 {cell->vertex(reference_cell.line_to_cell_vertices(line_no, 0)),
1601 cell->vertex(reference_cell.line_to_cell_vertices(line_no, 1))}};
1602
1603 const std::size_t n_rows =
1604 support_point_weights_perimeter_to_interior[0].size(0);
1605 a.resize(a.size() + n_rows);
1606 auto a_view = make_array_view(a.end() - n_rows, a.end());
1607 manifold.get_new_points(
1608 make_array_view(vertices.begin(), vertices.end()),
1609 support_point_weights_perimeter_to_interior[0],
1610 a_view);
1611 }
1612 }
1613}
1614
1615
1616
1617template <>
1618void
1621 std::vector<Point<3>> &a) const
1622{
1623 const unsigned int faces_per_cell = GeometryInfo<3>::faces_per_cell;
1624
1625 // used if face quad at boundary or entirely in the interior of the domain
1626 std::vector<Point<3>> tmp_points;
1627
1628 // loop over all faces and collect points on them
1629 for (unsigned int face_no = 0; face_no < faces_per_cell; ++face_no)
1630 {
1631 const Triangulation<3>::face_iterator face = cell->face(face_no);
1632
1633#ifdef DEBUG
1634 const bool face_orientation = cell->face_orientation(face_no),
1635 face_flip = cell->face_flip(face_no),
1636 face_rotation = cell->face_rotation(face_no);
1637 const unsigned int vertices_per_face = GeometryInfo<3>::vertices_per_face,
1638 lines_per_face = GeometryInfo<3>::lines_per_face;
1639
1640 // some sanity checks up front
1641 for (unsigned int i = 0; i < vertices_per_face; ++i)
1642 Assert(face->vertex_index(i) ==
1643 cell->vertex_index(GeometryInfo<3>::face_to_cell_vertices(
1644 face_no, i, face_orientation, face_flip, face_rotation)),
1646
1647 // indices of the lines that bound a face are given by GeometryInfo<3>::
1648 // face_to_cell_lines
1649 for (unsigned int i = 0; i < lines_per_face; ++i)
1650 Assert(face->line(i) ==
1652 face_no, i, face_orientation, face_flip, face_rotation)),
1654#endif
1655 // extract the points surrounding a quad from the points
1656 // already computed. First get the 4 vertices and then the points on
1657 // the four lines
1658 boost::container::small_vector<Point<3>, 200> tmp_points(
1660 GeometryInfo<2>::lines_per_cell * (polynomial_degree - 1));
1661 for (const unsigned int v : GeometryInfo<2>::vertex_indices())
1662 tmp_points[v] = a[GeometryInfo<3>::face_to_cell_vertices(face_no, v)];
1663 if (polynomial_degree > 1)
1664 for (unsigned int line = 0; line < GeometryInfo<2>::lines_per_cell;
1665 ++line)
1666 for (unsigned int i = 0; i < polynomial_degree - 1; ++i)
1667 tmp_points[4 + line * (polynomial_degree - 1) + i] =
1669 (polynomial_degree - 1) *
1671 i];
1672
1673 const std::size_t n_rows =
1674 support_point_weights_perimeter_to_interior[1].size(0);
1675 a.resize(a.size() + n_rows);
1676 auto a_view = make_array_view(a.end() - n_rows, a.end());
1677 face->get_manifold().get_new_points(
1678 make_array_view(tmp_points.begin(), tmp_points.end()),
1679 support_point_weights_perimeter_to_interior[1],
1680 a_view);
1681 }
1682}
1683
1684
1685
1686template <>
1687void
1690 std::vector<Point<3>> &a) const
1691{
1692 std::array<Point<3>, GeometryInfo<2>::vertices_per_cell> vertices;
1693 for (const unsigned int i : GeometryInfo<2>::vertex_indices())
1694 vertices[i] = cell->vertex(i);
1695
1696 Table<2, double> weights(Utilities::fixed_power<2>(polynomial_degree - 1),
1698 for (unsigned int q = 0, q2 = 0; q2 < polynomial_degree - 1; ++q2)
1699 for (unsigned int q1 = 0; q1 < polynomial_degree - 1; ++q1, ++q)
1700 {
1701 Point<2> point(line_support_points[q1 + 1][0],
1702 line_support_points[q2 + 1][0]);
1703 for (const unsigned int i : GeometryInfo<2>::vertex_indices())
1704 weights(q, i) = GeometryInfo<2>::d_linear_shape_function(point, i);
1705 }
1706
1707 const std::size_t n_rows = weights.size(0);
1708 a.resize(a.size() + n_rows);
1709 auto a_view = make_array_view(a.end() - n_rows, a.end());
1710 cell->get_manifold().get_new_points(
1711 make_array_view(vertices.begin(), vertices.end()), weights, a_view);
1712}
1713
1714
1715
1716template <int dim, int spacedim>
1717void
1724
1725
1726
1727template <int dim, int spacedim>
1728std::vector<Point<spacedim>>
1730 const typename Triangulation<dim, spacedim>::cell_iterator &cell) const
1731{
1732 // get the vertices first
1733 std::vector<Point<spacedim>> a;
1734 a.reserve(Utilities::fixed_power<dim>(polynomial_degree + 1));
1735 for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
1736 a.push_back(cell->vertex(i));
1737
1738 if (this->polynomial_degree > 1)
1739 {
1740 // check if all entities have the same manifold id which is when we can
1741 // simply ask the manifold for all points. the transfinite manifold can
1742 // do the interpolation better than this class, so if we detect that we
1743 // do not have to change anything here
1744 Assert(dim <= 3, ExcImpossibleInDim(dim));
1745 bool all_manifold_ids_are_equal = (dim == spacedim);
1746 if (all_manifold_ids_are_equal &&
1748 &cell->get_manifold()) == nullptr)
1749 {
1750 for (auto f : GeometryInfo<dim>::face_indices())
1751 if (&cell->face(f)->get_manifold() != &cell->get_manifold())
1752 all_manifold_ids_are_equal = false;
1753
1754 if (dim == 3)
1755 for (unsigned int l = 0; l < GeometryInfo<dim>::lines_per_cell; ++l)
1756 if (&cell->line(l)->get_manifold() != &cell->get_manifold())
1757 all_manifold_ids_are_equal = false;
1758 }
1759
1760 if (all_manifold_ids_are_equal)
1761 {
1762 const std::size_t n_rows = support_point_weights_cell.size(0);
1763 a.resize(a.size() + n_rows);
1764 auto a_view = make_array_view(a.end() - n_rows, a.end());
1765 cell->get_manifold().get_new_points(make_array_view(a.begin(),
1766 a.end() - n_rows),
1767 support_point_weights_cell,
1768 a_view);
1769 }
1770 else
1771 switch (dim)
1772 {
1773 case 1:
1774 add_line_support_points(cell, a);
1775 break;
1776 case 2:
1777 // in 2d, add the points on the four bounding lines to the
1778 // exterior (outer) points
1779 add_line_support_points(cell, a);
1780
1781 // then get the interior support points
1782 if (dim != spacedim)
1783 add_quad_support_points(cell, a);
1784 else
1785 {
1786 const std::size_t n_rows =
1787 support_point_weights_perimeter_to_interior[1].size(0);
1788 a.resize(a.size() + n_rows);
1789 auto a_view = make_array_view(a.end() - n_rows, a.end());
1790 cell->get_manifold().get_new_points(
1791 make_array_view(a.begin(), a.end() - n_rows),
1792 support_point_weights_perimeter_to_interior[1],
1793 a_view);
1794 }
1795 break;
1796
1797 case 3:
1798 // in 3d also add the points located on the boundary faces
1799 add_line_support_points(cell, a);
1800 add_quad_support_points(cell, a);
1801
1802 // then compute the interior points
1803 {
1804 const std::size_t n_rows =
1805 support_point_weights_perimeter_to_interior[2].size(0);
1806 a.resize(a.size() + n_rows);
1807 auto a_view = make_array_view(a.end() - n_rows, a.end());
1808 cell->get_manifold().get_new_points(
1809 make_array_view(a.begin(), a.end() - n_rows),
1810 support_point_weights_perimeter_to_interior[2],
1811 a_view);
1812 }
1813 break;
1814
1815 default:
1817 break;
1818 }
1819 }
1820
1821 return a;
1822}
1823
1824
1825
1826template <int dim, int spacedim>
1829 const typename Triangulation<dim, spacedim>::cell_iterator &cell) const
1830{
1831 return BoundingBox<spacedim>(this->compute_mapping_support_points(cell));
1832}
1833
1834
1835
1836template <int dim, int spacedim>
1837bool
1839 const ReferenceCell &reference_cell) const
1840{
1841 Assert(dim == reference_cell.get_dimension(),
1842 ExcMessage("The dimension of your mapping (" +
1844 ") and the reference cell cell_type (" +
1845 Utilities::to_string(reference_cell.get_dimension()) +
1846 " ) do not agree."));
1847
1848 return reference_cell.is_hyper_cube();
1849}
1850
1851
1852
1853//--------------------------- Explicit instantiations -----------------------
1854#include "mapping_q.inst"
1855
1856
auto make_const_array_view(const Container &container) -> decltype(make_array_view(container))
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
DerivativeForm< 1, spacedim, dim, Number > transpose() const
virtual Point< spacedim > get_new_point_on_line(const typename Triangulation< dim, spacedim >::line_iterator &line) const
virtual void get_new_points(const ArrayView< const Point< spacedim > > &surrounding_points, const Table< 2, double > &weights, ArrayView< Point< spacedim > > new_points) const
virtual std::size_t memory_consumption() const override
Definition mapping_q.cc:63
std::vector< Point< spacedim > > mapping_support_points
Definition mapping_q.h:421
virtual void reinit(const UpdateFlags update_flags, const Quadrature< dim > &quadrature) override
Definition mapping_q.cc:81
internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > * output_data
Definition mapping_q.h:441
void initialize_face(const UpdateFlags update_flags, const Quadrature< dim > &quadrature, const unsigned int n_original_q_points)
Definition mapping_q.cc:159
InternalData(const unsigned int polynomial_degree)
Definition mapping_q.cc:50
const std::vector< unsigned int > renumber_lexicographic_to_hierarchic
Definition mapping_q.h:539
const Table< 2, double > support_point_weights_cell
Definition mapping_q.h:587
virtual std::vector< Point< spacedim > > compute_mapping_support_points(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
virtual std::unique_ptr< typename Mapping< dim, spacedim >::InternalDataBase > get_data(const UpdateFlags, const Quadrature< dim > &quadrature) const override
Definition mapping_q.cc:774
void fill_mapping_data_for_face_quadrature(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_number, const Quadrature< dim - 1 > &face_quadrature, const typename Mapping< dim, spacedim >::InternalDataBase &internal_data, internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data) const
virtual BoundingBox< spacedim > get_bounding_box(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const override
virtual std::unique_ptr< typename Mapping< dim, spacedim >::InternalDataBase > get_subface_data(const UpdateFlags flags, const Quadrature< dim - 1 > &quadrature) const override
Definition mapping_q.cc:808
virtual void fill_fe_subface_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const unsigned int subface_no, const Quadrature< dim - 1 > &quadrature, const typename Mapping< dim, spacedim >::InternalDataBase &internal_data, internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data) const override
virtual void transform(const ArrayView< const Tensor< 1, dim > > &input, const MappingKind kind, const typename Mapping< dim, spacedim >::InternalDataBase &internal, const ArrayView< Tensor< 1, spacedim > > &output) const override
virtual CellSimilarity::Similarity fill_fe_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const CellSimilarity::Similarity cell_similarity, const Quadrature< dim > &quadrature, const typename Mapping< dim, spacedim >::InternalDataBase &internal_data, internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data) const override
Definition mapping_q.cc:827
virtual void fill_fe_immersed_surface_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const NonMatching::ImmersedSurfaceQuadrature< dim > &quadrature, const typename Mapping< dim, spacedim >::InternalDataBase &internal_data, internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data) const override
const unsigned int polynomial_degree
Definition mapping_q.h:515
virtual void transform_points_real_to_unit_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const ArrayView< const Point< spacedim > > &real_points, const ArrayView< Point< dim > > &unit_points) const override
Definition mapping_q.cc:626
virtual std::unique_ptr< typename Mapping< dim, spacedim >::InternalDataBase > get_face_data(const UpdateFlags flags, const hp::QCollection< dim - 1 > &quadrature) const override
Definition mapping_q.cc:787
Point< dim > transform_real_to_unit_cell_internal(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< spacedim > &p, const Point< dim > &initial_p_unit) const
Definition mapping_q.cc:321
const std::vector< Table< 2, double > > support_point_weights_perimeter_to_interior
Definition mapping_q.h:573
void fill_mapping_data_for_generic_points(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const ArrayView< const Point< dim > > &unit_points, const UpdateFlags update_flags, internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data) const
const std::vector< Point< 1 > > line_support_points
Definition mapping_q.h:525
virtual Point< spacedim > transform_unit_to_real_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< dim > &p) const override
Definition mapping_q.cc:280
const std::vector< Polynomials::Polynomial< double > > polynomials_1d
Definition mapping_q.h:532
virtual std::unique_ptr< Mapping< dim, spacedim > > clone() const override
Definition mapping_q.cc:262
const std::vector< Point< dim > > unit_cell_support_points
Definition mapping_q.h:551
virtual Point< dim > transform_real_to_unit_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< spacedim > &p) const override
Definition mapping_q.cc:506
MappingQ(const unsigned int polynomial_degree)
Definition mapping_q.cc:217
virtual void add_line_support_points(const typename Triangulation< dim, spacedim >::cell_iterator &cell, std::vector< Point< spacedim > > &a) const
virtual void add_quad_support_points(const typename Triangulation< dim, spacedim >::cell_iterator &cell, std::vector< Point< spacedim > > &a) const
virtual UpdateFlags requires_update_flags(const UpdateFlags update_flags) const override
Definition mapping_q.cc:718
virtual void fill_fe_face_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const hp::QCollection< dim - 1 > &quadrature, const typename Mapping< dim, spacedim >::InternalDataBase &internal_data, internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data) const override
virtual bool is_compatible_with(const ReferenceCell &reference_cell) const override
unsigned int get_degree() const
Definition mapping_q.cc:271
Abstract base class for mapping classes.
Definition mapping.h:318
virtual void transform_points_real_to_unit_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const ArrayView< const Point< spacedim > > &real_points, const ArrayView< Point< dim > > &unit_points) const
const Tensor< 1, spacedim > & normal_vector(const unsigned int i) const
Definition point.h:111
bool is_tensor_product() const
const std::vector< double > & get_weights() const
const std::array< Quadrature< 1 >, dim > & get_tensor_basis() const
const std::vector< Point< dim > > & get_points() const
unsigned int size() const
numbers::NumberTraits< Number >::real_type norm() const
unsigned int size() const
Definition collection.h:315
std::vector< DerivativeForm< 1, spacedim, dim > > inverse_jacobians
void initialize(const unsigned int n_quadrature_points, const UpdateFlags flags)
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
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:498
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:499
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)
typename IteratorSelector::line_iterator line_iterator
Definition tria.h:1643
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_grads
Gradient of volume element.
@ update_normal_vectors
Normal vectors.
@ update_JxW_values
Transformed quadrature weights.
@ update_covariant_transformation
Covariant transformation.
@ update_jacobians
Volume element.
@ update_inverse_jacobians
Volume element.
@ update_quadrature_points
Transformed quadrature points.
@ update_default
No update.
@ update_jacobian_pushed_forward_3rd_derivatives
@ update_boundary_forms
Outer normal vector, not normalized.
const Manifold< dim, spacedim > & get_manifold(const types::manifold_id number) const
MappingKind
Definition mapping.h:79
@ mapping_covariant_gradient
Definition mapping.h:100
@ 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()
std::vector< index_type > data
Definition mpi.cc:735
std::size_t size
Definition mpi.cc:734
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:479
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:470
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 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)
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)
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)
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 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_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)
ProductTypeNoPoint< Number, Number2 >::type evaluate_tensor_product_value_linear(const Number *values, const Point< dim, Number2 > &p)
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
const types::manifold_id flat_manifold_id
Definition types.h:325
bool is_finite(const double x)
Definition numbers.h:533
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices()
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()
DEAL_II_HOST constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &)