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