deal.II version GIT relicensing-2287-g6548a49e0a 2024-12-20 18: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.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 not get here, based on the if-condition at the
579 // top
581 }
582 }
583 }
584 catch (
586 {
587 // simply fall through and continue on to the standard Newton code
588 }
589 }
590 else
591 {
592 // we can't use an explicit formula,
593 }
594
595
596 // Find the initial value for the Newton iteration by a normal
597 // projection to the least square plane determined by the vertices
598 // of the cell
599 Point<dim> initial_p_unit;
600 if (this->preserves_vertex_locations())
601 {
602 initial_p_unit = cell->real_to_unit_cell_affine_approximation(p);
603 // in 1d with spacedim > 1 the affine approximation is exact
604 if (dim == 1 && polynomial_degree == 1)
605 return initial_p_unit;
606 }
607 else
608 {
609 // else, we simply use the mid point
610 for (unsigned int d = 0; d < dim; ++d)
611 initial_p_unit[d] = 0.5;
612 }
613
614 // perform the Newton iteration and return the result. note that this
615 // statement may throw an exception, which we simply pass up to the caller
616 const Point<dim> p_unit =
617 this->transform_real_to_unit_cell_internal(cell, p, initial_p_unit);
618 AssertThrow(p_unit[0] != std::numeric_limits<double>::lowest(),
620 return p_unit;
621}
622
623
624
625template <int dim, int spacedim>
626void
629 const ArrayView<const Point<spacedim>> &real_points,
630 const ArrayView<Point<dim>> &unit_points) const
631{
632 // Go to base class functions for dim < spacedim because it is not yet
633 // implemented with optimized code.
634 if (dim < spacedim)
635 {
637 real_points,
638 unit_points);
639 return;
640 }
641
642 AssertDimension(real_points.size(), unit_points.size());
643 std::vector<Point<spacedim>> support_points_higher_order;
644 boost::container::small_vector<Point<spacedim>,
646 vertices;
647 if (polynomial_degree == 1)
648 vertices = this->get_vertices(cell);
649 else
650 support_points_higher_order = this->compute_mapping_support_points(cell);
651 const ArrayView<const Point<spacedim>> support_points(
652 polynomial_degree == 1 ? vertices.data() :
653 support_points_higher_order.data(),
654 Utilities::pow(polynomial_degree + 1, dim));
655
656 // From the given (high-order) support points, now only pick the first
657 // 2^dim points and construct an affine approximation from those.
659 inverse_approximation(support_points, unit_cell_support_points);
660
661 const unsigned int n_points = real_points.size();
662 const unsigned int n_lanes = VectorizedArray<double>::size();
663
664 // Use the more heavy VectorizedArray code path if there is more than
665 // one point left to compute
666 for (unsigned int i = 0; i < n_points; i += n_lanes)
667 if (n_points - i > 1)
668 {
670 for (unsigned int j = 0; j < n_lanes; ++j)
671 if (i + j < n_points)
672 for (unsigned int d = 0; d < spacedim; ++d)
673 p_vec[d][j] = real_points[i + j][d];
674 else
675 for (unsigned int d = 0; d < spacedim; ++d)
676 p_vec[d][j] = real_points[i][d];
677
679 internal::MappingQImplementation::
680 do_transform_real_to_unit_cell_internal<dim, spacedim>(
681 p_vec,
682 inverse_approximation.compute(p_vec),
683 support_points,
684 polynomials_1d,
685 renumber_lexicographic_to_hierarchic);
686
687 // If the vectorized computation failed, it could be that only some of
688 // the lanes failed but others would have succeeded if we had let them
689 // compute alone without interference (like negative Jacobian
690 // determinants) from other SIMD lanes. Repeat the computation in this
691 // unlikely case with scalar arguments.
692 for (unsigned int j = 0; j < n_lanes && i + j < n_points; ++j)
693 if (unit_point[0][j] != std::numeric_limits<double>::lowest())
694 for (unsigned int d = 0; d < dim; ++d)
695 unit_points[i + j][d] = unit_point[d][j];
696 else
697 unit_points[i + j] = internal::MappingQImplementation::
698 do_transform_real_to_unit_cell_internal<dim, spacedim>(
699 real_points[i + j],
700 inverse_approximation.compute(real_points[i + j]),
701 support_points,
702 polynomials_1d,
703 renumber_lexicographic_to_hierarchic);
704 }
705 else
706 unit_points[i] = internal::MappingQImplementation::
707 do_transform_real_to_unit_cell_internal<dim, spacedim>(
708 real_points[i],
709 inverse_approximation.compute(real_points[i]),
710 support_points,
711 polynomials_1d,
712 renumber_lexicographic_to_hierarchic);
713}
714
715
716
717template <int dim, int spacedim>
720{
721 // add flags if the respective quantities are necessary to compute
722 // what we need. note that some flags appear in both the conditions
723 // and in subsequent set operations. this leads to some circular
724 // logic. the only way to treat this is to iterate. since there are
725 // 5 if-clauses in the loop, it will take at most 5 iterations to
726 // converge. do them:
727 UpdateFlags out = in;
728 for (unsigned int i = 0; i < 5; ++i)
729 {
730 // The following is a little incorrect:
731 // If not applied on a face,
732 // update_boundary_forms does not
733 // make sense. On the other hand,
734 // it is necessary on a
735 // face. Currently,
736 // update_boundary_forms is simply
737 // ignored for the interior of a
738 // cell.
741
742 if (out &
746
747 if (out &
752
753 // The contravariant transformation is used in the Piola
754 // transformation, which requires the determinant of the Jacobi
755 // matrix of the transformation. Because we have no way of
756 // knowing here whether the finite element wants to use the
757 // contravariant or the Piola transforms, we add the JxW values
758 // to the list of flags to be updated for each cell.
761
762 // the same is true when computing normal vectors: they require
763 // the determinant of the Jacobian
764 if (out & update_normal_vectors)
766 }
767
768 return out;
769}
770
771
772
773template <int dim, int spacedim>
774std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
776 const Quadrature<dim> &q) const
777{
778 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase> data_ptr =
779 std::make_unique<InternalData>(polynomial_degree);
780 data_ptr->reinit(update_flags, q);
781 return data_ptr;
782}
783
784
785
786template <int dim, int spacedim>
787std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
789 const UpdateFlags update_flags,
790 const hp::QCollection<dim - 1> &quadrature) const
791{
792 AssertDimension(quadrature.size(), 1);
793
794 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase> data_ptr =
795 std::make_unique<InternalData>(polynomial_degree);
796 auto &data = dynamic_cast<InternalData &>(*data_ptr);
797 data.initialize_face(this->requires_update_flags(update_flags),
799 ReferenceCells::get_hypercube<dim>(), quadrature[0]),
800 quadrature[0].size());
801
802 return data_ptr;
803}
804
805
806
807template <int dim, int spacedim>
808std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
810 const UpdateFlags update_flags,
811 const Quadrature<dim - 1> &quadrature) const
812{
813 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase> data_ptr =
814 std::make_unique<InternalData>(polynomial_degree);
815 auto &data = dynamic_cast<InternalData &>(*data_ptr);
816 data.initialize_face(this->requires_update_flags(update_flags),
818 ReferenceCells::get_hypercube<dim>(), quadrature),
819 quadrature.size());
820
821 return data_ptr;
822}
823
824
825
826template <int dim, int spacedim>
830 const CellSimilarity::Similarity cell_similarity,
831 const Quadrature<dim> &quadrature,
832 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
834 &output_data) const
835{
836 // ensure that the following static_cast is really correct:
837 Assert(dynamic_cast<const InternalData *>(&internal_data) != nullptr,
839 const InternalData &data = static_cast<const InternalData &>(internal_data);
840 data.output_data = &output_data;
841
842 const unsigned int n_q_points = quadrature.size();
843
844 // recompute the support points of the transformation of this
845 // cell. we tried to be clever here in an earlier version of the
846 // library by checking whether the cell is the same as the one we
847 // had visited last, but it turns out to be difficult to determine
848 // that because a cell for the purposes of a mapping is
849 // characterized not just by its (triangulation, level, index)
850 // triple, but also by the locations of its vertices, the manifold
851 // object attached to the cell and all of its bounding faces/edges,
852 // etc. to reliably test that the "cell" we are on is, therefore,
853 // not easily done
854 if (polynomial_degree == 1)
855 {
856 data.mapping_support_points.resize(GeometryInfo<dim>::vertices_per_cell);
857 const auto vertices = this->get_vertices(cell);
858 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
859 data.mapping_support_points[i] = vertices[i];
860 }
861 else
862 data.mapping_support_points = this->compute_mapping_support_points(cell);
863
864 data.cell_of_current_support_points = cell;
865
866 // if the order of the mapping is greater than 1, then do not reuse any cell
867 // similarity information. This is necessary because the cell similarity
868 // value is computed with just cell vertices and does not take into account
869 // cell curvature.
870 const CellSimilarity::Similarity computed_cell_similarity =
871 (polynomial_degree == 1 && this->preserves_vertex_locations() ?
872 cell_similarity :
874
875 if (dim > 1 && data.tensor_product_quadrature)
876 {
877 internal::MappingQImplementation::
878 maybe_update_q_points_Jacobians_and_grads_tensor<dim, spacedim>(
879 computed_cell_similarity,
880 data,
881 output_data.quadrature_points,
882 output_data.jacobians,
883 output_data.inverse_jacobians,
884 output_data.jacobian_grads);
885 }
886 else
887 {
889 computed_cell_similarity,
890 data,
891 make_array_view(quadrature.get_points()),
892 polynomials_1d,
893 renumber_lexicographic_to_hierarchic,
894 output_data.quadrature_points,
895 output_data.jacobians,
896 output_data.inverse_jacobians);
897
899 spacedim>(
900 computed_cell_similarity,
901 data,
902 make_array_view(quadrature.get_points()),
903 polynomials_1d,
904 renumber_lexicographic_to_hierarchic,
905 output_data.jacobian_grads);
906 }
907
909 dim,
910 spacedim>(computed_cell_similarity,
911 data,
912 make_array_view(quadrature.get_points()),
913 polynomials_1d,
914 renumber_lexicographic_to_hierarchic,
916
918 dim,
919 spacedim>(computed_cell_similarity,
920 data,
921 make_array_view(quadrature.get_points()),
922 polynomials_1d,
923 renumber_lexicographic_to_hierarchic,
924 output_data.jacobian_2nd_derivatives);
925
926 internal::MappingQImplementation::
927 maybe_update_jacobian_pushed_forward_2nd_derivatives<dim, spacedim>(
928 computed_cell_similarity,
929 data,
930 make_array_view(quadrature.get_points()),
931 polynomials_1d,
932 renumber_lexicographic_to_hierarchic,
934
936 dim,
937 spacedim>(computed_cell_similarity,
938 data,
939 make_array_view(quadrature.get_points()),
940 polynomials_1d,
941 renumber_lexicographic_to_hierarchic,
942 output_data.jacobian_3rd_derivatives);
943
944 internal::MappingQImplementation::
945 maybe_update_jacobian_pushed_forward_3rd_derivatives<dim, spacedim>(
946 computed_cell_similarity,
947 data,
948 make_array_view(quadrature.get_points()),
949 polynomials_1d,
950 renumber_lexicographic_to_hierarchic,
952
953 const UpdateFlags update_flags = data.update_each;
954 const std::vector<double> &weights = quadrature.get_weights();
955
956 // Multiply quadrature weights by absolute value of Jacobian determinants or
957 // the area element g=sqrt(DX^t DX) in case of codim > 0
958
959 if (update_flags & (update_normal_vectors | update_JxW_values))
960 {
961 Assert(!(update_flags & update_JxW_values) ||
962 (output_data.JxW_values.size() == n_q_points),
963 ExcDimensionMismatch(output_data.JxW_values.size(), n_q_points));
964
965 Assert(!(update_flags & update_normal_vectors) ||
966 (output_data.normal_vectors.size() == n_q_points),
967 ExcDimensionMismatch(output_data.normal_vectors.size(),
968 n_q_points));
969
970
971 if (computed_cell_similarity != CellSimilarity::translation)
972 for (unsigned int point = 0; point < n_q_points; ++point)
973 {
974 if (dim == spacedim)
975 {
976 const double det = data.volume_elements[point];
977
978 // check for distorted cells.
979
980 // TODO: this allows for anisotropies of up to 1e6 in 3d and
981 // 1e12 in 2d. might want to find a finer
982 // (dimension-independent) criterion
983 Assert(det >
984 1e-12 * Utilities::fixed_power<dim>(
985 cell->diameter() / std::sqrt(double(dim))),
987 cell->center(), det, point)));
988
989 output_data.JxW_values[point] = weights[point] * det;
990 }
991 // if dim==spacedim, then there is no cell normal to
992 // compute. since this is for FEValues (and not FEFaceValues),
993 // there are also no face normals to compute
994 else // codim>0 case
995 {
996 Tensor<1, spacedim> DX_t[dim];
997 for (unsigned int i = 0; i < spacedim; ++i)
998 for (unsigned int j = 0; j < dim; ++j)
999 DX_t[j][i] = output_data.jacobians[point][i][j];
1000
1001 Tensor<2, dim> G; // First fundamental form
1002 for (unsigned int i = 0; i < dim; ++i)
1003 for (unsigned int j = 0; j < dim; ++j)
1004 G[i][j] = DX_t[i] * DX_t[j];
1005
1006 if (update_flags & update_JxW_values)
1007 output_data.JxW_values[point] =
1008 std::sqrt(determinant(G)) * weights[point];
1009
1010 if (computed_cell_similarity ==
1012 {
1013 // we only need to flip the normal
1014 if (update_flags & update_normal_vectors)
1015 output_data.normal_vectors[point] *= -1.;
1016 }
1017 else
1018 {
1019 if (update_flags & update_normal_vectors)
1020 {
1021 Assert(spacedim == dim + 1,
1022 ExcMessage(
1023 "There is no (unique) cell normal for " +
1025 "-dimensional cells in " +
1026 Utilities::int_to_string(spacedim) +
1027 "-dimensional space. This only works if the "
1028 "space dimension is one greater than the "
1029 "dimensionality of the mesh cells."));
1030
1031 if (dim == 1)
1032 output_data.normal_vectors[point] =
1033 cross_product_2d(-DX_t[0]);
1034 else // dim == 2
1035 output_data.normal_vectors[point] =
1036 cross_product_3d(DX_t[0], DX_t[1]);
1037
1038 output_data.normal_vectors[point] /=
1039 output_data.normal_vectors[point].norm();
1040
1041 if (cell->direction_flag() == false)
1042 output_data.normal_vectors[point] *= -1.;
1043 }
1044 }
1045 } // codim>0 case
1046 }
1047 }
1048
1049 return computed_cell_similarity;
1050}
1051
1052
1053
1054template <int dim, int spacedim>
1055void
1058 const unsigned int face_no,
1059 const hp::QCollection<dim - 1> &quadrature,
1060 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
1062 &output_data) const
1063{
1064 AssertDimension(quadrature.size(), 1);
1065
1066 // ensure that the following cast is really correct:
1067 Assert((dynamic_cast<const InternalData *>(&internal_data) != nullptr),
1069 const InternalData &data = static_cast<const InternalData &>(internal_data);
1070 data.output_data = &output_data;
1071
1072 // if necessary, recompute the support points of the transformation of this
1073 // cell (note that we need to first check the triangulation pointer, since
1074 // otherwise the second test might trigger an exception if the
1075 // triangulations are not the same)
1076 if ((data.mapping_support_points.empty()) ||
1077 (&cell->get_triangulation() !=
1078 &data.cell_of_current_support_points->get_triangulation()) ||
1079 (cell != data.cell_of_current_support_points))
1080 {
1081 if (polynomial_degree == 1)
1082 {
1083 data.mapping_support_points.resize(
1085 const auto vertices = this->get_vertices(cell);
1086 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell;
1087 ++i)
1088 data.mapping_support_points[i] = vertices[i];
1089 }
1090 else
1091 data.mapping_support_points =
1092 this->compute_mapping_support_points(cell);
1093 data.cell_of_current_support_points = cell;
1094 }
1095
1097 *this,
1098 cell,
1099 face_no,
1102 ReferenceCells::get_hypercube<dim>(),
1103 face_no,
1104 cell->face_orientation(face_no),
1105 cell->face_flip(face_no),
1106 cell->face_rotation(face_no),
1107 quadrature[0].size()),
1108 quadrature[0],
1109 data,
1110 polynomials_1d,
1111 renumber_lexicographic_to_hierarchic,
1112 output_data);
1113}
1114
1115
1116
1117template <int dim, int spacedim>
1118void
1121 const unsigned int face_no,
1122 const unsigned int subface_no,
1123 const Quadrature<dim - 1> &quadrature,
1124 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
1126 &output_data) const
1127{
1128 // ensure that the following cast is really correct:
1129 Assert((dynamic_cast<const InternalData *>(&internal_data) != nullptr),
1131 const InternalData &data = static_cast<const InternalData &>(internal_data);
1132 data.output_data = &output_data;
1133
1134 // if necessary, recompute the support points of the transformation of this
1135 // cell (note that we need to first check the triangulation pointer, since
1136 // otherwise the second test might trigger an exception if the
1137 // triangulations are not the same)
1138 if ((data.mapping_support_points.empty()) ||
1139 (&cell->get_triangulation() !=
1140 &data.cell_of_current_support_points->get_triangulation()) ||
1141 (cell != data.cell_of_current_support_points))
1142 {
1143 if (polynomial_degree == 1)
1144 {
1145 data.mapping_support_points.resize(
1147 const auto vertices = this->get_vertices(cell);
1148 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell;
1149 ++i)
1150 data.mapping_support_points[i] = vertices[i];
1151 }
1152 else
1153 data.mapping_support_points =
1154 this->compute_mapping_support_points(cell);
1155 data.cell_of_current_support_points = cell;
1156 }
1157
1159 *this,
1160 cell,
1161 face_no,
1162 subface_no,
1164 ReferenceCells::get_hypercube<dim>(),
1165 face_no,
1166 subface_no,
1167 cell->combined_face_orientation(face_no),
1168 quadrature.size(),
1169 cell->subface_case(face_no)),
1170 quadrature,
1171 data,
1172 polynomials_1d,
1173 renumber_lexicographic_to_hierarchic,
1174 output_data);
1175}
1176
1177
1178
1179template <int dim, int spacedim>
1180void
1184 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
1186 &output_data) const
1187{
1188 Assert(dim == spacedim, ExcNotImplemented());
1189
1190 // ensure that the following static_cast is really correct:
1191 Assert(dynamic_cast<const InternalData *>(&internal_data) != nullptr,
1193 const InternalData &data = static_cast<const InternalData &>(internal_data);
1194 data.output_data = &output_data;
1195
1196 const unsigned int n_q_points = quadrature.size();
1197
1198 if (polynomial_degree == 1)
1199 {
1200 data.mapping_support_points.resize(GeometryInfo<dim>::vertices_per_cell);
1201 const auto vertices = this->get_vertices(cell);
1202 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
1203 data.mapping_support_points[i] = vertices[i];
1204 }
1205 else
1206 data.mapping_support_points = this->compute_mapping_support_points(cell);
1207 data.cell_of_current_support_points = cell;
1208
1211 data,
1212 make_array_view(quadrature.get_points()),
1213 polynomials_1d,
1214 renumber_lexicographic_to_hierarchic,
1215 output_data.quadrature_points,
1216 output_data.jacobians,
1217 output_data.inverse_jacobians);
1218
1219 internal::MappingQImplementation::maybe_update_jacobian_grads<dim, spacedim>(
1221 data,
1222 make_array_view(quadrature.get_points()),
1223 polynomials_1d,
1224 renumber_lexicographic_to_hierarchic,
1225 output_data.jacobian_grads);
1226
1228 dim,
1229 spacedim>(CellSimilarity::none,
1230 data,
1231 make_array_view(quadrature.get_points()),
1232 polynomials_1d,
1233 renumber_lexicographic_to_hierarchic,
1234 output_data.jacobian_pushed_forward_grads);
1235
1237 dim,
1238 spacedim>(CellSimilarity::none,
1239 data,
1240 make_array_view(quadrature.get_points()),
1241 polynomials_1d,
1242 renumber_lexicographic_to_hierarchic,
1243 output_data.jacobian_2nd_derivatives);
1244
1245 internal::MappingQImplementation::
1246 maybe_update_jacobian_pushed_forward_2nd_derivatives<dim, spacedim>(
1248 data,
1249 make_array_view(quadrature.get_points()),
1250 polynomials_1d,
1251 renumber_lexicographic_to_hierarchic,
1253
1255 dim,
1256 spacedim>(CellSimilarity::none,
1257 data,
1258 make_array_view(quadrature.get_points()),
1259 polynomials_1d,
1260 renumber_lexicographic_to_hierarchic,
1261 output_data.jacobian_3rd_derivatives);
1262
1263 internal::MappingQImplementation::
1264 maybe_update_jacobian_pushed_forward_3rd_derivatives<dim, spacedim>(
1266 data,
1267 make_array_view(quadrature.get_points()),
1268 polynomials_1d,
1269 renumber_lexicographic_to_hierarchic,
1271
1272 const UpdateFlags update_flags = data.update_each;
1273 const std::vector<double> &weights = quadrature.get_weights();
1274
1275 if ((update_flags & (update_normal_vectors | update_JxW_values)) != 0u)
1276 {
1277 AssertDimension(output_data.JxW_values.size(), n_q_points);
1278
1279 Assert(!(update_flags & update_normal_vectors) ||
1280 (output_data.normal_vectors.size() == n_q_points),
1281 ExcDimensionMismatch(output_data.normal_vectors.size(),
1282 n_q_points));
1283
1284
1285 for (unsigned int point = 0; point < n_q_points; ++point)
1286 {
1287 const double det = data.volume_elements[point];
1288
1289 // check for distorted cells.
1290
1291 // TODO: this allows for anisotropies of up to 1e6 in 3d and
1292 // 1e12 in 2d. might want to find a finer
1293 // (dimension-independent) criterion
1294 Assert(det > 1e-12 * Utilities::fixed_power<dim>(
1295 cell->diameter() / std::sqrt(double(dim))),
1297 cell->center(), det, point)));
1298
1299 // The normals are n = J^{-T} * \hat{n} before normalizing.
1300 Tensor<1, spacedim> normal;
1301 for (unsigned int d = 0; d < spacedim; d++)
1302 normal[d] = output_data.inverse_jacobians[point].transpose()[d] *
1303 quadrature.normal_vector(point);
1304
1305 output_data.JxW_values[point] = weights[point] * det * normal.norm();
1306
1307 if ((update_flags & update_normal_vectors) != 0u)
1308 {
1309 normal /= normal.norm();
1310 output_data.normal_vectors[point] = normal;
1311 }
1312 }
1313 }
1314}
1315
1316
1317
1318template <int dim, int spacedim>
1319void
1322 const ArrayView<const Point<dim>> &unit_points,
1323 const UpdateFlags update_flags,
1325 &output_data) const
1326{
1327 if (update_flags == update_default)
1328 return;
1329
1330 Assert(update_flags & update_inverse_jacobians ||
1331 update_flags & update_jacobians ||
1332 update_flags & update_quadrature_points,
1334
1335 output_data.initialize(unit_points.size(), update_flags);
1336
1337 auto internal_data =
1338 this->get_data(update_flags,
1339 Quadrature<dim>(std::vector<Point<dim>>(unit_points.begin(),
1340 unit_points.end())));
1341 const InternalData &data = static_cast<const InternalData &>(*internal_data);
1342 data.output_data = &output_data;
1343 if (polynomial_degree == 1)
1344 {
1345 data.mapping_support_points.resize(GeometryInfo<dim>::vertices_per_cell);
1346 const auto vertices = this->get_vertices(cell);
1347 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
1348 data.mapping_support_points[i] = vertices[i];
1349 }
1350 else
1351 data.mapping_support_points = this->compute_mapping_support_points(cell);
1352
1355 data,
1356 unit_points,
1357 polynomials_1d,
1358 renumber_lexicographic_to_hierarchic,
1359 output_data.quadrature_points,
1360 output_data.jacobians,
1361 output_data.inverse_jacobians);
1362}
1363
1364
1365
1366template <int dim, int spacedim>
1367void
1370 const unsigned int face_no,
1371 const Quadrature<dim - 1> &face_quadrature,
1372 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
1374 &output_data) const
1375{
1376 if (face_quadrature.get_points().empty())
1377 return;
1378
1379 // ensure that the following static_cast is really correct:
1380 Assert(dynamic_cast<const InternalData *>(&internal_data) != nullptr,
1382 const InternalData &data = static_cast<const InternalData &>(internal_data);
1383
1384 if (polynomial_degree == 1)
1385 {
1387 const auto vertices = this->get_vertices(cell);
1388 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
1389 data.mapping_support_points[i] = vertices[i];
1390 }
1391 else
1392 data.mapping_support_points = this->compute_mapping_support_points(cell);
1393 data.output_data = &output_data;
1394
1396 *this,
1397 cell,
1398 face_no,
1401 face_quadrature,
1402 data,
1403 polynomials_1d,
1404 renumber_lexicographic_to_hierarchic,
1405 output_data);
1406}
1407
1408
1409
1410template <int dim, int spacedim>
1411void
1413 const ArrayView<const Tensor<1, dim>> &input,
1414 const MappingKind mapping_kind,
1415 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1416 const ArrayView<Tensor<1, spacedim>> &output) const
1417{
1419 mapping_kind,
1420 mapping_data,
1421 output);
1422}
1423
1424
1425
1426template <int dim, int spacedim>
1427void
1429 const ArrayView<const DerivativeForm<1, dim, spacedim>> &input,
1430 const MappingKind mapping_kind,
1431 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1432 const ArrayView<Tensor<2, spacedim>> &output) const
1433{
1435 mapping_kind,
1436 mapping_data,
1437 output);
1438}
1439
1440
1441
1442template <int dim, int spacedim>
1443void
1445 const ArrayView<const Tensor<2, dim>> &input,
1446 const MappingKind mapping_kind,
1447 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1448 const ArrayView<Tensor<2, spacedim>> &output) const
1449{
1450 switch (mapping_kind)
1451 {
1454 mapping_kind,
1455 mapping_data,
1456 output);
1457 return;
1458
1463 mapping_kind,
1464 mapping_data,
1465 output);
1466 return;
1467 default:
1469 }
1470}
1471
1472
1473
1474template <int dim, int spacedim>
1475void
1477 const ArrayView<const DerivativeForm<2, dim, spacedim>> &input,
1478 const MappingKind mapping_kind,
1479 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1480 const ArrayView<Tensor<3, spacedim>> &output) const
1481{
1482 AssertDimension(input.size(), output.size());
1483 Assert(dynamic_cast<const InternalData *>(&mapping_data) != nullptr,
1486 &data = *static_cast<const InternalData &>(mapping_data).output_data;
1487
1488 switch (mapping_kind)
1489 {
1491 {
1492 Assert(!data.inverse_jacobians.empty(),
1494 "update_covariant_transformation"));
1495
1496 for (unsigned int q = 0; q < output.size(); ++q)
1497 for (unsigned int i = 0; i < spacedim; ++i)
1498 for (unsigned int j = 0; j < spacedim; ++j)
1499 {
1500 double tmp[dim];
1501 const DerivativeForm<1, dim, spacedim> covariant =
1502 data.inverse_jacobians[q].transpose();
1503 for (unsigned int K = 0; K < dim; ++K)
1504 {
1505 tmp[K] = covariant[j][0] * input[q][i][0][K];
1506 for (unsigned int J = 1; J < dim; ++J)
1507 tmp[K] += covariant[j][J] * input[q][i][J][K];
1508 }
1509 for (unsigned int k = 0; k < spacedim; ++k)
1510 {
1511 output[q][i][j][k] = covariant[k][0] * tmp[0];
1512 for (unsigned int K = 1; K < dim; ++K)
1513 output[q][i][j][k] += covariant[k][K] * tmp[K];
1514 }
1515 }
1516 return;
1517 }
1518
1519 default:
1521 }
1522}
1523
1524
1525
1526template <int dim, int spacedim>
1527void
1529 const ArrayView<const Tensor<3, dim>> &input,
1530 const MappingKind mapping_kind,
1531 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1532 const ArrayView<Tensor<3, spacedim>> &output) const
1533{
1534 switch (mapping_kind)
1535 {
1540 mapping_kind,
1541 mapping_data,
1542 output);
1543 return;
1544 default:
1546 }
1547}
1548
1549
1550
1551template <int dim, int spacedim>
1552void
1555 std::vector<Point<spacedim>> &a) const
1556{
1557 // if we only need the midpoint, then ask for it.
1558 if (this->polynomial_degree == 2)
1559 {
1560 for (unsigned int line_no = 0;
1561 line_no < GeometryInfo<dim>::lines_per_cell;
1562 ++line_no)
1563 {
1565 (dim == 1 ?
1566 static_cast<
1568 cell->line(line_no));
1569
1570 const Manifold<dim, spacedim> &manifold =
1571 ((line->manifold_id() == numbers::flat_manifold_id) &&
1572 (dim < spacedim) ?
1573 cell->get_manifold() :
1574 line->get_manifold());
1575 a.push_back(manifold.get_new_point_on_line(line));
1576 }
1577 }
1578 else
1579 // otherwise call the more complicated functions and ask for inner points
1580 // from the manifold description
1581 {
1582 std::vector<Point<spacedim>> tmp_points;
1583 for (unsigned int line_no = 0;
1584 line_no < GeometryInfo<dim>::lines_per_cell;
1585 ++line_no)
1586 {
1588 (dim == 1 ?
1589 static_cast<
1591 cell->line(line_no));
1592
1593 const Manifold<dim, spacedim> &manifold =
1594 ((line->manifold_id() == numbers::flat_manifold_id) &&
1595 (dim < spacedim) ?
1596 cell->get_manifold() :
1597 line->get_manifold());
1598
1599 const auto reference_cell = ReferenceCells::get_hypercube<dim>();
1600 const std::array<Point<spacedim>, 2> vertices{
1601 {cell->vertex(reference_cell.line_to_cell_vertices(line_no, 0)),
1602 cell->vertex(reference_cell.line_to_cell_vertices(line_no, 1))}};
1603
1604 const std::size_t n_rows =
1605 support_point_weights_perimeter_to_interior[0].size(0);
1606 a.resize(a.size() + n_rows);
1607 auto a_view = make_array_view(a.end() - n_rows, a.end());
1608 manifold.get_new_points(
1609 make_array_view(vertices.begin(), vertices.end()),
1610 support_point_weights_perimeter_to_interior[0],
1611 a_view);
1612 }
1613 }
1614}
1615
1616
1617
1618template <>
1619void
1622 std::vector<Point<3>> &a) const
1623{
1624 const unsigned int faces_per_cell = GeometryInfo<3>::faces_per_cell;
1625
1626 // used if face quad at boundary or entirely in the interior of the domain
1627 std::vector<Point<3>> tmp_points;
1628
1629 // loop over all faces and collect points on them
1630 for (unsigned int face_no = 0; face_no < faces_per_cell; ++face_no)
1631 {
1632 const Triangulation<3>::face_iterator face = cell->face(face_no);
1633
1634#ifdef DEBUG
1635 const bool face_orientation = cell->face_orientation(face_no),
1636 face_flip = cell->face_flip(face_no),
1637 face_rotation = cell->face_rotation(face_no);
1638 const unsigned int vertices_per_face = GeometryInfo<3>::vertices_per_face,
1639 lines_per_face = GeometryInfo<3>::lines_per_face;
1640
1641 // some sanity checks up front
1642 for (unsigned int i = 0; i < vertices_per_face; ++i)
1643 Assert(face->vertex_index(i) ==
1644 cell->vertex_index(GeometryInfo<3>::face_to_cell_vertices(
1645 face_no, i, face_orientation, face_flip, face_rotation)),
1647
1648 // indices of the lines that bound a face are given by GeometryInfo<3>::
1649 // face_to_cell_lines
1650 for (unsigned int i = 0; i < lines_per_face; ++i)
1651 Assert(face->line(i) ==
1653 face_no, i, face_orientation, face_flip, face_rotation)),
1655#endif
1656 // extract the points surrounding a quad from the points
1657 // already computed. First get the 4 vertices and then the points on
1658 // the four lines
1659 boost::container::small_vector<Point<3>, 200> tmp_points(
1661 GeometryInfo<2>::lines_per_cell * (polynomial_degree - 1));
1662 for (const unsigned int v : GeometryInfo<2>::vertex_indices())
1663 tmp_points[v] = a[GeometryInfo<3>::face_to_cell_vertices(face_no, v)];
1664 if (polynomial_degree > 1)
1665 for (unsigned int line = 0; line < GeometryInfo<2>::lines_per_cell;
1666 ++line)
1667 for (unsigned int i = 0; i < polynomial_degree - 1; ++i)
1668 tmp_points[4 + line * (polynomial_degree - 1) + i] =
1670 (polynomial_degree - 1) *
1672 i];
1673
1674 const std::size_t n_rows =
1675 support_point_weights_perimeter_to_interior[1].size(0);
1676 a.resize(a.size() + n_rows);
1677 auto a_view = make_array_view(a.end() - n_rows, a.end());
1678 face->get_manifold().get_new_points(
1679 make_array_view(tmp_points.begin(), tmp_points.end()),
1680 support_point_weights_perimeter_to_interior[1],
1681 a_view);
1682 }
1683}
1684
1685
1686
1687template <>
1688void
1691 std::vector<Point<3>> &a) const
1692{
1693 std::array<Point<3>, GeometryInfo<2>::vertices_per_cell> vertices;
1694 for (const unsigned int i : GeometryInfo<2>::vertex_indices())
1695 vertices[i] = cell->vertex(i);
1696
1697 Table<2, double> weights(Utilities::fixed_power<2>(polynomial_degree - 1),
1699 for (unsigned int q = 0, q2 = 0; q2 < polynomial_degree - 1; ++q2)
1700 for (unsigned int q1 = 0; q1 < polynomial_degree - 1; ++q1, ++q)
1701 {
1702 Point<2> point(line_support_points[q1 + 1][0],
1703 line_support_points[q2 + 1][0]);
1704 for (const unsigned int i : GeometryInfo<2>::vertex_indices())
1705 weights(q, i) = GeometryInfo<2>::d_linear_shape_function(point, i);
1706 }
1707
1708 const std::size_t n_rows = weights.size(0);
1709 a.resize(a.size() + n_rows);
1710 auto a_view = make_array_view(a.end() - n_rows, a.end());
1711 cell->get_manifold().get_new_points(
1712 make_array_view(vertices.begin(), vertices.end()), weights, a_view);
1713}
1714
1715
1716
1717template <int dim, int spacedim>
1718void
1725
1726
1727
1728template <int dim, int spacedim>
1729std::vector<Point<spacedim>>
1731 const typename Triangulation<dim, spacedim>::cell_iterator &cell) const
1732{
1733 // get the vertices first
1734 std::vector<Point<spacedim>> a;
1735 a.reserve(Utilities::fixed_power<dim>(polynomial_degree + 1));
1736 for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
1737 a.push_back(cell->vertex(i));
1738
1739 if (this->polynomial_degree > 1)
1740 {
1741 // check if all entities have the same manifold id which is when we can
1742 // simply ask the manifold for all points. the transfinite manifold can
1743 // do the interpolation better than this class, so if we detect that we
1744 // do not have to change anything here
1745 Assert(dim <= 3, ExcImpossibleInDim(dim));
1746 bool all_manifold_ids_are_equal = (dim == spacedim);
1747 if (all_manifold_ids_are_equal &&
1749 &cell->get_manifold()) == nullptr)
1750 {
1751 for (auto f : GeometryInfo<dim>::face_indices())
1752 if (&cell->face(f)->get_manifold() != &cell->get_manifold())
1753 all_manifold_ids_are_equal = false;
1754
1755 if (dim == 3)
1756 for (unsigned int l = 0; l < GeometryInfo<dim>::lines_per_cell; ++l)
1757 if (&cell->line(l)->get_manifold() != &cell->get_manifold())
1758 all_manifold_ids_are_equal = false;
1759 }
1760
1761 if (all_manifold_ids_are_equal)
1762 {
1763 const std::size_t n_rows = support_point_weights_cell.size(0);
1764 a.resize(a.size() + n_rows);
1765 auto a_view = make_array_view(a.end() - n_rows, a.end());
1766 cell->get_manifold().get_new_points(make_array_view(a.begin(),
1767 a.end() - n_rows),
1768 support_point_weights_cell,
1769 a_view);
1770 }
1771 else
1772 switch (dim)
1773 {
1774 case 1:
1775 add_line_support_points(cell, a);
1776 break;
1777 case 2:
1778 // in 2d, add the points on the four bounding lines to the
1779 // exterior (outer) points
1780 add_line_support_points(cell, a);
1781
1782 // then get the interior support points
1783 if (dim != spacedim)
1784 add_quad_support_points(cell, a);
1785 else
1786 {
1787 const std::size_t n_rows =
1788 support_point_weights_perimeter_to_interior[1].size(0);
1789 a.resize(a.size() + n_rows);
1790 auto a_view = make_array_view(a.end() - n_rows, a.end());
1791 cell->get_manifold().get_new_points(
1792 make_array_view(a.begin(), a.end() - n_rows),
1793 support_point_weights_perimeter_to_interior[1],
1794 a_view);
1795 }
1796 break;
1797
1798 case 3:
1799 // in 3d also add the points located on the boundary faces
1800 add_line_support_points(cell, a);
1801 add_quad_support_points(cell, a);
1802
1803 // then compute the interior points
1804 {
1805 const std::size_t n_rows =
1806 support_point_weights_perimeter_to_interior[2].size(0);
1807 a.resize(a.size() + n_rows);
1808 auto a_view = make_array_view(a.end() - n_rows, a.end());
1809 cell->get_manifold().get_new_points(
1810 make_array_view(a.begin(), a.end() - n_rows),
1811 support_point_weights_perimeter_to_interior[2],
1812 a_view);
1813 }
1814 break;
1815
1816 default:
1818 break;
1819 }
1820 }
1821
1822 return a;
1823}
1824
1825
1826
1827template <int dim, int spacedim>
1830 const typename Triangulation<dim, spacedim>::cell_iterator &cell) const
1831{
1832 return BoundingBox<spacedim>(this->compute_mapping_support_points(cell));
1833}
1834
1835
1836
1837template <int dim, int spacedim>
1838bool
1840 const ReferenceCell &reference_cell) const
1841{
1842 Assert(dim == reference_cell.get_dimension(),
1843 ExcMessage("The dimension of your mapping (" +
1845 ") and the reference cell cell_type (" +
1846 Utilities::to_string(reference_cell.get_dimension()) +
1847 " ) do not agree."));
1848
1849 return reference_cell.is_hyper_cube();
1850}
1851
1852
1853
1854//--------------------------- Explicit instantiations -----------------------
1855#include "mapping_q.inst"
1856
1857
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:775
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:809
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:828
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:627
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:788
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:719
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
::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 > &)