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_manifold.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) 2016 - 2025 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
21
23
24#include <deal.II/fe/fe.h>
25#include <deal.II/fe/fe_tools.h>
29
31#include <deal.II/grid/tria.h>
33
35
36#include <algorithm>
37#include <array>
38#include <cmath>
39#include <memory>
40#include <numeric>
41
42
44
45template <int dim, int spacedim>
46std::size_t
63
64
65
66template <int dim, int spacedim>
67void
69 const UpdateFlags update_flags,
70 const Quadrature<dim> &q)
71{
72 // store the flags in the internal data object so we can access them
73 // in fill_fe_*_values()
74 this->update_each = update_flags;
75
76 const unsigned int n_q_points = q.size();
77
78 // Store the quadrature
79 this->quad.initialize(q.get_points(), q.get_weights());
80
81 // see if we need the (transformation) shape function values
82 // and/or gradients and resize the necessary arrays
83 if (this->update_each &
85 compute_manifold_quadrature_weights(q);
86
87 if (this->update_each & update_covariant_transformation)
88 covariant.resize(n_q_points);
89
90 if (this->update_each & update_contravariant_transformation)
91 contravariant.resize(n_q_points);
92
93 if (this->update_each & update_volume_elements)
94 volume_elements.resize(n_q_points);
95}
96
97
98
99template <int dim, int spacedim>
100void
102 const UpdateFlags update_flags,
103 const Quadrature<dim> &q,
104 const unsigned int n_original_q_points)
105{
106 reinit(update_flags, q);
107
108 // Set to the size of a single quadrature object for faces, as the size set
109 // in in reinit() is for all points
110 if (this->update_each & update_covariant_transformation)
111 covariant.resize(n_original_q_points);
112
113 if (this->update_each & update_contravariant_transformation)
114 contravariant.resize(n_original_q_points);
115
116 if (this->update_each & update_volume_elements)
117 volume_elements.resize(n_original_q_points);
118
119 if (dim > 1)
120 {
121 if (this->update_each & update_boundary_forms)
122 {
123 aux.resize(dim - 1,
124 std::vector<Tensor<1, spacedim>>(n_original_q_points));
125
126 // Compute tangentials to the unit cell.
127 for (const unsigned int i : GeometryInfo<dim>::face_indices())
128 {
129 unit_tangentials[i].resize(n_original_q_points);
130 std::fill(unit_tangentials[i].begin(),
131 unit_tangentials[i].end(),
133 if (dim > 2)
134 {
135 unit_tangentials[GeometryInfo<dim>::faces_per_cell + i]
136 .resize(n_original_q_points);
137 std::fill(
138 unit_tangentials[GeometryInfo<dim>::faces_per_cell + i]
139 .begin(),
140 unit_tangentials[GeometryInfo<dim>::faces_per_cell + i]
141 .end(),
143 }
144 }
145 }
146 }
147}
148
149
150
151template <int dim, int spacedim>
152void
154 const typename Triangulation<dim, spacedim>::cell_iterator &cell) const
155{
156 for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
157 vertices[i] = cell->vertex(i);
158 this->cell = cell;
159}
160
161
162
163template <int dim, int spacedim>
164void
167{
168 cell_manifold_quadrature_weights.resize(quad.size());
169 for (unsigned int q = 0; q < quad.size(); ++q)
170 {
171 for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
172 {
173 cell_manifold_quadrature_weights[q][i] =
175 }
176 }
177}
178
179
180
181template <int dim, int spacedim>
185
186
187
188template <int dim, int spacedim>
189std::unique_ptr<Mapping<dim, spacedim>>
191{
192 return std::make_unique<MappingManifold<dim, spacedim>>(*this);
193}
194
195
196
197template <int dim, int spacedim>
206
207
208
209template <int dim, int spacedim>
213 const Point<dim> &p) const
214{
215 std::array<Point<spacedim>, GeometryInfo<dim>::vertices_per_cell> vertices;
216 std::array<double, GeometryInfo<dim>::vertices_per_cell> weights;
217
218 for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
219 {
220 vertices[v] = cell->vertex(v);
222 }
223 return cell->get_manifold().get_new_point(
224 make_array_view(vertices.begin(), vertices.end()),
225 make_array_view(weights.begin(), weights.end()));
226}
227
228
229
230// In the code below, GCC tries to instantiate MappingManifold<3,4> when
231// seeing which of the overloaded versions of
232// do_transform_real_to_unit_cell_internal() to call. This leads to bad
233// error messages and, generally, nothing very good. Avoid this by ensuring
234// that this class exists, but does not have an inner InternalData
235// type, thereby ruling out the codim-1 version of the function
236// below when doing overload resolution.
237template <>
239{};
240
241
242
243template <int dim, int spacedim>
246 const UpdateFlags in) const
247{
248 // add flags if the respective quantities are necessary to compute
249 // what we need. note that some flags appear in both the conditions
250 // and in subsequent set operations. this leads to some circular
251 // logic. the only way to treat this is to iterate. since there are
252 // 5 if-clauses in the loop, it will take at most 5 iterations to
253 // converge. do them:
254 UpdateFlags out = in;
255 for (unsigned int i = 0; i < 5; ++i)
256 {
257 // The following is a little incorrect:
258 // If not applied on a face,
259 // update_boundary_forms does not
260 // make sense. On the other hand,
261 // it is necessary on a
262 // face. Currently,
263 // update_boundary_forms is simply
264 // ignored for the interior of a
265 // cell.
268
273
274 if (out &
279
280 // The contravariant transformation used in the Piola
281 // transformation, which requires the determinant of the Jacobi
282 // matrix of the transformation. Because we have no way of
283 // knowing here whether the finite elements wants to use the
284 // contravariant of the Piola transforms, we add the JxW values
285 // to the list of flags to be updated for each cell.
287 out |= update_JxW_values;
288
289 if (out & update_normal_vectors)
290 out |= update_JxW_values;
291 }
292
293 // Now throw an exception if we stumble upon something that was not
294 // implemented yet
299
300 return out;
301}
302
303
304
305template <int dim, int spacedim>
306std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
308 const Quadrature<dim> &q) const
309{
310 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase> data_ptr =
311 std::make_unique<InternalData>();
312 data_ptr->reinit(this->requires_update_flags(update_flags), q);
313
314 return data_ptr;
315}
316
317
318
319template <int dim, int spacedim>
320std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
322 const UpdateFlags update_flags,
323 const hp::QCollection<dim - 1> &quadrature) const
324{
325 AssertDimension(quadrature.size(), 1);
326
327 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase> data_ptr =
328 std::make_unique<InternalData>();
329 auto &data = dynamic_cast<InternalData &>(*data_ptr);
330 data.initialize_face(this->requires_update_flags(update_flags),
332 ReferenceCells::get_hypercube<dim>(), quadrature[0]),
333 quadrature[0].size());
334
335 return data_ptr;
336}
337
338
339
340template <int dim, int spacedim>
341std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
343 const UpdateFlags update_flags,
344 const Quadrature<dim - 1> &quadrature) const
345{
346 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase> data_ptr =
347 std::make_unique<InternalData>();
348 auto &data = dynamic_cast<InternalData &>(*data_ptr);
349 data.initialize_face(this->requires_update_flags(update_flags),
351 ReferenceCells::get_hypercube<dim>(), quadrature),
352 quadrature.size());
353
354 return data_ptr;
355}
356
357
358
359namespace internal
360{
361 namespace MappingManifoldImplementation
362 {
363 namespace
364 {
371 template <int dim, int spacedim>
372 void
373 maybe_compute_q_points(
374 const typename QProjector<dim>::DataSetDescriptor data_set,
375 const typename ::MappingManifold<dim, spacedim>::InternalData
376 &data,
377 std::vector<Point<spacedim>> &quadrature_points)
378 {
379 const UpdateFlags update_flags = data.update_each;
380
381 if (update_flags & update_quadrature_points)
382 {
383 for (unsigned int point = 0; point < quadrature_points.size();
384 ++point)
385 {
386 quadrature_points[point] = data.manifold->get_new_point(
387 make_array_view(data.vertices),
389 data.cell_manifold_quadrature_weights[point + data_set]));
390 }
391 }
392 }
393
394
395
402 template <int dim, int spacedim>
403 void
404 maybe_update_Jacobians(
405 const typename ::QProjector<dim>::DataSetDescriptor data_set,
406 const typename ::MappingManifold<dim, spacedim>::InternalData
407 &data)
408 {
409 const UpdateFlags update_flags = data.update_each;
410
411 if (update_flags & update_contravariant_transformation)
412 {
413 const unsigned int n_q_points = data.contravariant.size();
414
415 std::fill(data.contravariant.begin(),
416 data.contravariant.end(),
418
419 for (unsigned int point = 0; point < n_q_points; ++point)
420 {
421 // Start by figuring out how to compute the direction in
422 // the reference space:
423 const Point<dim> &p = data.quad.point(point + data_set);
424
425 // And get its image on the manifold:
426 const Point<spacedim> P = data.manifold->get_new_point(
427 make_array_view(data.vertices),
429 data.cell_manifold_quadrature_weights[point + data_set]));
430
431 // To compute the Jacobian, we choose dim points aligned
432 // with the dim reference axes, which are still in the
433 // given cell, and ask for the tangent vector in these
434 // directions. Choosing the points is somewhat arbitrary,
435 // so we try to be smart and we pick points which are
436 // on the opposite quadrant w.r.t. the evaluation
437 // point.
438 for (unsigned int i = 0; i < dim; ++i)
439 {
441 const double pi = p[i];
442 Assert(pi >= 0 && pi <= 1.0,
444 "Was expecting a quadrature point "
445 "inside the unit reference element."));
446
447 // In the length L, we store also the direction sign,
448 // which is positive, if the coordinate is < .5,
449 const double L = pi > .5 ? -pi : 1 - pi;
450
451 const Point<dim> np(p + L * ei);
452
453 // Get the weights to compute the np point in real space
454 for (const unsigned int j :
456 data.vertex_weights[j] =
458
459 const Point<spacedim> NP = data.manifold->get_new_point(
460 make_array_view(data.vertices),
461 make_array_view(data.vertex_weights));
462
463 const Tensor<1, spacedim> T =
464 data.manifold->get_tangent_vector(P, NP);
465
466 for (unsigned int d = 0; d < spacedim; ++d)
467 data.contravariant[point][d][i] = T[d] / L;
468 }
469 }
470
471 if (update_flags & update_covariant_transformation)
472 {
473 const unsigned int n_q_points = data.contravariant.size();
474 for (unsigned int point = 0; point < n_q_points; ++point)
475 {
476 data.covariant[point] =
477 (data.contravariant[point]).covariant_form();
478 }
479 }
480
481 if (update_flags & update_volume_elements)
482 {
483 const unsigned int n_q_points = data.contravariant.size();
484 for (unsigned int point = 0; point < n_q_points; ++point)
485 data.volume_elements[point] =
486 data.contravariant[point].determinant();
487 }
488 }
489 }
490 } // namespace
491 } // namespace MappingManifoldImplementation
492} // namespace internal
493
494
495
496template <int dim, int spacedim>
501 const Quadrature<dim> &quadrature,
502 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
504 &output_data) const
505{
506 // ensure that the following static_cast is really correct:
507 Assert(dynamic_cast<const InternalData *>(&internal_data) != nullptr,
509 const InternalData &data = static_cast<const InternalData &>(internal_data);
510
511 const unsigned int n_q_points = quadrature.size();
512
513 data.store_vertices(cell);
514 data.manifold = &(cell->get_manifold());
515
516 internal::MappingManifoldImplementation::maybe_compute_q_points<dim,
517 spacedim>(
519 data,
520 output_data.quadrature_points);
521
522 internal::MappingManifoldImplementation::maybe_update_Jacobians<dim,
523 spacedim>(
525
526 const UpdateFlags update_flags = data.update_each;
527 const std::vector<double> &weights = quadrature.get_weights();
528
529 // Multiply quadrature weights by absolute value of Jacobian determinants or
530 // the area element g=sqrt(DX^t DX) in case of codim > 0
531
532 if (update_flags & (update_normal_vectors | update_JxW_values))
533 {
534 AssertDimension(output_data.JxW_values.size(), n_q_points);
535
536 Assert(!(update_flags & update_normal_vectors) ||
537 (output_data.normal_vectors.size() == n_q_points),
538 ExcDimensionMismatch(output_data.normal_vectors.size(),
539 n_q_points));
540
541
542 for (unsigned int point = 0; point < n_q_points; ++point)
543 {
544 if (dim == spacedim)
545 {
546 const double det = data.contravariant[point].determinant();
547
548 // check for distorted cells.
549
550 // TODO: this allows for anisotropies of up to 1e6 in 3d and
551 // 1e12 in 2d. might want to find a finer
552 // (dimension-independent) criterion
553 Assert(det > 1e-12 * Utilities::fixed_power<dim>(
554 cell->diameter() / std::sqrt(double(dim))),
556 cell->center(), det, point)));
557
558 output_data.JxW_values[point] = weights[point] * det;
559 }
560 // if dim==spacedim, then there is no cell normal to
561 // compute. since this is for FEValues (and not FEFaceValues),
562 // there are also no face normals to compute
563 else // codim>0 case
564 {
565 Tensor<1, spacedim> DX_t[dim];
566 for (unsigned int i = 0; i < spacedim; ++i)
567 for (unsigned int j = 0; j < dim; ++j)
568 DX_t[j][i] = data.contravariant[point][i][j];
569
570 Tensor<2, dim> G; // First fundamental form
571 for (unsigned int i = 0; i < dim; ++i)
572 for (unsigned int j = 0; j < dim; ++j)
573 G[i][j] = DX_t[i] * DX_t[j];
574
575 output_data.JxW_values[point] =
576 std::sqrt(determinant(G)) * weights[point];
577
578 if (update_flags & update_normal_vectors)
579 {
580 Assert(spacedim == dim + 1,
582 "There is no (unique) cell normal for " +
584 "-dimensional cells in " +
585 Utilities::int_to_string(spacedim) +
586 "-dimensional space. This only works if the "
587 "space dimension is one greater than the "
588 "dimensionality of the mesh cells."));
589
590 if (dim == 1)
591 output_data.normal_vectors[point] =
592 cross_product_2d(-DX_t[0]);
593 else // dim == 2
594 output_data.normal_vectors[point] =
595 cross_product_3d(DX_t[0], DX_t[1]);
596
597 output_data.normal_vectors[point] /=
598 output_data.normal_vectors[point].norm();
599
600 if (cell->direction_flag() == false)
601 output_data.normal_vectors[point] *= -1.;
602 }
603 } // codim>0 case
604 }
605 }
606
607
608
609 // copy values from InternalData to vector given by reference
610 if (update_flags & update_jacobians)
611 {
612 AssertDimension(output_data.jacobians.size(), n_q_points);
613 for (unsigned int point = 0; point < n_q_points; ++point)
614 output_data.jacobians[point] = data.contravariant[point];
615 }
616
617 // copy values from InternalData to vector given by reference
618 if (update_flags & update_inverse_jacobians)
619 {
620 AssertDimension(output_data.inverse_jacobians.size(), n_q_points);
621 for (unsigned int point = 0; point < n_q_points; ++point)
622 output_data.inverse_jacobians[point] =
623 data.covariant[point].transpose();
624 }
625
627}
628
629
630
631namespace internal
632{
633 namespace MappingManifoldImplementation
634 {
635 namespace
636 {
646 template <int dim, int spacedim>
647 void
648 maybe_compute_face_data(
649 const ::MappingManifold<dim, spacedim> &mapping,
650 const typename ::Triangulation<dim, spacedim>::cell_iterator
651 &cell,
652 const unsigned int face_no,
653 const unsigned int subface_no,
654 const unsigned int n_q_points,
655 const std::vector<double> &weights,
656 const typename ::MappingManifold<dim, spacedim>::InternalData
657 &data,
659 &output_data)
660 {
661 const UpdateFlags update_flags = data.update_each;
662
663 if (update_flags & update_boundary_forms)
664 {
665 AssertDimension(output_data.boundary_forms.size(), n_q_points);
666 if (update_flags & update_normal_vectors)
667 AssertDimension(output_data.normal_vectors.size(), n_q_points);
668 if (update_flags & update_JxW_values)
669 AssertDimension(output_data.JxW_values.size(), n_q_points);
670
671 // map the unit tangentials to the real cell. checking for d!=dim-1
672 // eliminates compiler warnings regarding unsigned int expressions <
673 // 0.
674 for (unsigned int d = 0; d != dim - 1; ++d)
675 {
677 data.unit_tangentials.size(),
679 Assert(
680 data.aux[d].size() <=
681 data
682 .unit_tangentials[face_no +
684 .size(),
686
687 mapping.transform(
689 data
690 .unit_tangentials[face_no +
693 data,
694 make_array_view(data.aux[d]));
695 }
696
697 // if dim==spacedim, we can use the unit tangentials to compute the
698 // boundary form by simply taking the cross product
699 if (dim == spacedim)
700 {
701 for (unsigned int i = 0; i < n_q_points; ++i)
702 switch (dim)
703 {
704 case 1:
705 // in 1d, we don't have access to any of the data.aux
706 // fields (because it has only dim-1 components), but we
707 // can still compute the boundary form by simply
708 // looking at the number of the face
709 output_data.boundary_forms[i][0] =
710 (face_no == 0 ? -1 : +1);
711 break;
712 case 2:
713 output_data.boundary_forms[i] =
714 cross_product_2d(data.aux[0][i]);
715 break;
716 case 3:
717 output_data.boundary_forms[i] =
718 cross_product_3d(data.aux[0][i], data.aux[1][i]);
719 break;
720 default:
722 }
723 }
724 else //(dim < spacedim)
725 {
726 // in the codim-one case, the boundary form results from the
727 // cross product of all the face tangential vectors and the cell
728 // normal vector
729 //
730 // to compute the cell normal, use the same method used in
731 // fill_fe_values for cells above
732 AssertDimension(data.contravariant.size(), n_q_points);
733
734 for (unsigned int point = 0; point < n_q_points; ++point)
735 {
736 switch (dim)
737 {
738 case 1:
739 {
740 // J is a tangent vector
741 output_data.boundary_forms[point] =
742 data.contravariant[point].transpose()[0];
743 output_data.boundary_forms[point] /=
744 (face_no == 0 ? -1. : +1.) *
745 output_data.boundary_forms[point].norm();
746
747 break;
748 }
749
750 case 2:
751 {
753 data.contravariant[point].transpose();
754
755 Tensor<1, spacedim> cell_normal =
756 cross_product_3d(DX_t[0], DX_t[1]);
757 cell_normal /= cell_normal.norm();
758
759 // then compute the face normal from the face
760 // tangent and the cell normal:
761 output_data.boundary_forms[point] =
762 cross_product_3d(data.aux[0][point], cell_normal);
763
764 break;
765 }
766
767 default:
769 }
770 }
771 }
772
773 if (update_flags & (update_normal_vectors | update_JxW_values))
774 for (unsigned int i = 0; i < output_data.boundary_forms.size();
775 ++i)
776 {
777 if (update_flags & update_JxW_values)
778 {
779 output_data.JxW_values[i] =
780 output_data.boundary_forms[i].norm() * weights[i];
781
782 if (subface_no != numbers::invalid_unsigned_int)
783 {
784 const double area_ratio =
786 cell->subface_case(face_no), subface_no);
787 output_data.JxW_values[i] *= area_ratio;
788 }
789 }
790
791 if (update_flags & update_normal_vectors)
792 output_data.normal_vectors[i] =
793 Point<spacedim>(output_data.boundary_forms[i] /
794 output_data.boundary_forms[i].norm());
795 }
796
797 if (update_flags & update_jacobians)
798 for (unsigned int point = 0; point < n_q_points; ++point)
799 output_data.jacobians[point] = data.contravariant[point];
800
801 if (update_flags & update_inverse_jacobians)
802 for (unsigned int point = 0; point < n_q_points; ++point)
803 output_data.inverse_jacobians[point] =
804 data.covariant[point].transpose();
805 }
806 }
807
808
815 template <int dim, int spacedim>
816 void
818 const ::MappingManifold<dim, spacedim> &mapping,
819 const typename ::Triangulation<dim, spacedim>::cell_iterator
820 &cell,
821 const unsigned int face_no,
822 const unsigned int subface_no,
823 const typename QProjector<dim>::DataSetDescriptor data_set,
824 const Quadrature<dim - 1> &quadrature,
825 const typename ::MappingManifold<dim, spacedim>::InternalData
826 &data,
828 &output_data)
829 {
830 data.store_vertices(cell);
831
832 data.manifold = &cell->face(face_no)->get_manifold();
833
834 maybe_compute_q_points<dim, spacedim>(data_set,
835 data,
836 output_data.quadrature_points);
837 maybe_update_Jacobians<dim, spacedim>(data_set, data);
838
840 cell,
841 face_no,
842 subface_no,
843 quadrature.size(),
844 quadrature.get_weights(),
845 data,
846 output_data);
847 }
848
849 template <int dim, int spacedim, int rank>
850 void
852 const ArrayView<const Tensor<rank, dim>> &input,
853 const MappingKind mapping_kind,
854 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
855 const ArrayView<Tensor<rank, spacedim>> &output)
856 {
857 AssertDimension(input.size(), output.size());
858 Assert((dynamic_cast<const typename ::
859 MappingManifold<dim, spacedim>::InternalData *>(
860 &mapping_data) != nullptr),
862 const typename ::MappingManifold<dim, spacedim>::InternalData
863 &data =
864 static_cast<const typename ::MappingManifold<dim, spacedim>::
865 InternalData &>(mapping_data);
866
867 switch (mapping_kind)
868 {
870 {
871 Assert(
874 "update_contravariant_transformation"));
875
876 for (unsigned int i = 0; i < output.size(); ++i)
877 output[i] =
878 apply_transformation(data.contravariant[i], input[i]);
879
880 return;
881 }
882
883 case mapping_piola:
884 {
885 Assert(
888 "update_contravariant_transformation"));
889 Assert(
890 data.update_each & update_volume_elements,
892 "update_volume_elements"));
893 Assert(rank == 1, ExcMessage("Only for rank 1"));
894 if (rank != 1)
895 return;
896
897 for (unsigned int i = 0; i < output.size(); ++i)
898 {
899 output[i] =
900 apply_transformation(data.contravariant[i], input[i]);
901 output[i] /= data.volume_elements[i];
902 }
903 return;
904 }
905 // We still allow this operation as in the
906 // reference cell Derivatives are Tensor
907 // rather than DerivativeForm
909 {
910 Assert(
913 "update_covariant_transformation"));
914
915 for (unsigned int i = 0; i < output.size(); ++i)
916 output[i] = apply_transformation(data.covariant[i], input[i]);
917
918 return;
919 }
920
921 default:
923 }
924 }
925
926
927 template <int dim, int spacedim, int rank>
928 void
930 const ArrayView<const Tensor<rank, dim>> &input,
931 const MappingKind mapping_kind,
932 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
933 const ArrayView<Tensor<rank, spacedim>> &output)
934 {
935 AssertDimension(input.size(), output.size());
936 Assert((dynamic_cast<const typename ::
937 MappingManifold<dim, spacedim>::InternalData *>(
938 &mapping_data) != nullptr),
940 const typename ::MappingManifold<dim, spacedim>::InternalData
941 &data =
942 static_cast<const typename ::MappingManifold<dim, spacedim>::
943 InternalData &>(mapping_data);
944
945 switch (mapping_kind)
946 {
948 {
949 Assert(
952 "update_covariant_transformation"));
953 Assert(
956 "update_contravariant_transformation"));
957 Assert(rank == 2, ExcMessage("Only for rank 2"));
958
959 for (unsigned int i = 0; i < output.size(); ++i)
960 {
962 apply_transformation(data.contravariant[i],
963 transpose(input[i]));
964 output[i] =
965 apply_transformation(data.covariant[i], A.transpose());
966 }
967
968 return;
969 }
970
972 {
973 Assert(
976 "update_covariant_transformation"));
977 Assert(rank == 2, ExcMessage("Only for rank 2"));
978
979 for (unsigned int i = 0; i < output.size(); ++i)
980 {
982 apply_transformation(data.covariant[i],
983 transpose(input[i]));
984 output[i] =
985 apply_transformation(data.covariant[i], A.transpose());
986 }
987
988 return;
989 }
990
992 {
993 Assert(
996 "update_covariant_transformation"));
997 Assert(
1000 "update_contravariant_transformation"));
1001 Assert(
1002 data.update_each & update_volume_elements,
1004 "update_volume_elements"));
1005 Assert(rank == 2, ExcMessage("Only for rank 2"));
1006
1007 for (unsigned int i = 0; i < output.size(); ++i)
1008 output[i] =
1010 data.contravariant[i],
1011 data.volume_elements[i],
1012 input[i]);
1013
1014 return;
1015 }
1016
1017 default:
1019 }
1020 }
1021
1022
1023
1024 template <int dim, int spacedim>
1025 void
1027 const ArrayView<const Tensor<3, dim>> &input,
1028 const MappingKind mapping_kind,
1029 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1030 const ArrayView<Tensor<3, spacedim>> &output)
1031 {
1032 AssertDimension(input.size(), output.size());
1033 Assert((dynamic_cast<const typename ::
1034 MappingManifold<dim, spacedim>::InternalData *>(
1035 &mapping_data) != nullptr),
1037 const typename ::MappingManifold<dim, spacedim>::InternalData
1038 &data =
1039 static_cast<const typename ::MappingManifold<dim, spacedim>::
1040 InternalData &>(mapping_data);
1041
1042 switch (mapping_kind)
1043 {
1045 {
1046 Assert(
1049 "update_covariant_transformation"));
1050 Assert(
1053 "update_contravariant_transformation"));
1054
1055 for (unsigned int q = 0; q < output.size(); ++q)
1056 output[q] =
1058 data.contravariant[q],
1059 input[q]);
1060
1061 return;
1062 }
1063
1065 {
1066 Assert(
1069 "update_covariant_transformation"));
1070
1071 for (unsigned int q = 0; q < output.size(); ++q)
1072 output[q] =
1074 input[q]);
1075
1076 return;
1077 }
1078
1080 {
1081 Assert(
1084 "update_covariant_transformation"));
1085 Assert(
1088 "update_contravariant_transformation"));
1089 Assert(
1090 data.update_each & update_volume_elements,
1092 "update_volume_elements"));
1093
1094 for (unsigned int q = 0; q < output.size(); ++q)
1095 output[q] =
1097 data.contravariant[q],
1098 data.volume_elements[q],
1099 input[q]);
1100
1101 return;
1102 }
1103
1104 default:
1106 }
1107 }
1108
1109
1110
1111 template <int dim, int spacedim, int rank>
1112 void
1115 const MappingKind mapping_kind,
1116 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1118 {
1119 AssertDimension(input.size(), output.size());
1120 Assert((dynamic_cast<const typename ::
1121 MappingManifold<dim, spacedim>::InternalData *>(
1122 &mapping_data) != nullptr),
1124 const typename ::MappingManifold<dim, spacedim>::InternalData
1125 &data =
1126 static_cast<const typename ::MappingManifold<dim, spacedim>::
1127 InternalData &>(mapping_data);
1128
1129 switch (mapping_kind)
1130 {
1131 case mapping_covariant:
1132 {
1133 Assert(
1136 "update_covariant_transformation"));
1137
1138 for (unsigned int i = 0; i < output.size(); ++i)
1139 output[i] = apply_transformation(data.covariant[i], input[i]);
1140
1141 return;
1142 }
1143 default:
1145 }
1146 }
1147 } // namespace
1148 } // namespace MappingManifoldImplementation
1149} // namespace internal
1150
1151
1152
1153template <int dim, int spacedim>
1154void
1157 const unsigned int face_no,
1158 const hp::QCollection<dim - 1> &quadrature,
1159 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
1161 &output_data) const
1162{
1163 AssertDimension(quadrature.size(), 1);
1164
1165 // ensure that the following cast is really correct:
1166 Assert((dynamic_cast<const InternalData *>(&internal_data) != nullptr),
1168 const InternalData &data = static_cast<const InternalData &>(internal_data);
1169
1170 internal::MappingManifoldImplementation::do_fill_fe_face_values(
1171 *this,
1172 cell,
1173 face_no,
1176 ReferenceCells::get_hypercube<dim>(),
1177 face_no,
1178 cell->combined_face_orientation(face_no),
1179 quadrature[0].size()),
1180 quadrature[0],
1181 data,
1182 output_data);
1183}
1184
1185
1186
1187template <int dim, int spacedim>
1188void
1191 const unsigned int face_no,
1192 const unsigned int subface_no,
1193 const Quadrature<dim - 1> &quadrature,
1194 const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
1196 &output_data) const
1197{
1198 // ensure that the following cast is really correct:
1199 Assert((dynamic_cast<const InternalData *>(&internal_data) != nullptr),
1201 const InternalData &data = static_cast<const InternalData &>(internal_data);
1202
1203 internal::MappingManifoldImplementation::do_fill_fe_face_values(
1204 *this,
1205 cell,
1206 face_no,
1207 subface_no,
1209 ReferenceCells::get_hypercube<dim>(),
1210 face_no,
1211 subface_no,
1212 cell->combined_face_orientation(face_no),
1213 quadrature.size(),
1214 cell->subface_case(face_no)),
1215 quadrature,
1216 data,
1217 output_data);
1218}
1219
1220
1221
1222template <int dim, int spacedim>
1223void
1225 const ArrayView<const Tensor<1, dim>> &input,
1226 const MappingKind mapping_kind,
1227 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1228 const ArrayView<Tensor<1, spacedim>> &output) const
1229{
1230 internal::MappingManifoldImplementation::transform_fields(input,
1231 mapping_kind,
1232 mapping_data,
1233 output);
1234}
1235
1236
1237
1238template <int dim, int spacedim>
1239void
1241 const ArrayView<const DerivativeForm<1, dim, spacedim>> &input,
1242 const MappingKind mapping_kind,
1243 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1244 const ArrayView<Tensor<2, spacedim>> &output) const
1245{
1246 internal::MappingManifoldImplementation::transform_differential_forms(
1247 input, mapping_kind, mapping_data, output);
1248}
1249
1250
1251
1252template <int dim, int spacedim>
1253void
1255 const ArrayView<const Tensor<2, dim>> &input,
1256 const MappingKind mapping_kind,
1257 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1258 const ArrayView<Tensor<2, spacedim>> &output) const
1259{
1260 switch (mapping_kind)
1261 {
1263 internal::MappingManifoldImplementation::transform_fields(input,
1264 mapping_kind,
1265 mapping_data,
1266 output);
1267 return;
1268
1272 internal::MappingManifoldImplementation::transform_gradients(
1273 input, mapping_kind, mapping_data, output);
1274 return;
1275 default:
1277 }
1278}
1279
1280
1281
1282template <int dim, int spacedim>
1283void
1285 const ArrayView<const DerivativeForm<2, dim, spacedim>> &input,
1286 const MappingKind mapping_kind,
1287 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1288 const ArrayView<Tensor<3, spacedim>> &output) const
1289{
1290 AssertDimension(input.size(), output.size());
1291 Assert(dynamic_cast<const InternalData *>(&mapping_data) != nullptr,
1293 const InternalData &data = static_cast<const InternalData &>(mapping_data);
1294
1295 switch (mapping_kind)
1296 {
1298 {
1301 "update_covariant_transformation"));
1302
1303 for (unsigned int q = 0; q < output.size(); ++q)
1304 output[q] =
1305 internal::apply_covariant_gradient(data.covariant[q], input[q]);
1306
1307 return;
1308 }
1309
1310 default:
1312 }
1313}
1314
1315
1316
1317template <int dim, int spacedim>
1318void
1320 const ArrayView<const Tensor<3, dim>> &input,
1321 const MappingKind mapping_kind,
1322 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1323 const ArrayView<Tensor<3, spacedim>> &output) const
1324{
1325 switch (mapping_kind)
1326 {
1330 internal::MappingManifoldImplementation::transform_hessians(
1331 input, mapping_kind, mapping_data, output);
1332 return;
1333 default:
1335 }
1336}
1337
1338//--------------------------- Explicit instantiations -----------------------
1339#include "fe/mapping_manifold.inst"
1340
1341
*  iterator end()
*  *  iterator begin()
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
void store_vertices(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
std::vector< double > volume_elements
std::array< std::vector< Tensor< 1, dim > >, GeometryInfo< dim >::faces_per_cell *(dim - 1)> unit_tangentials
std::vector< DerivativeForm< 1, dim, spacedim > > contravariant
std::array< Point< spacedim >, GeometryInfo< dim >::vertices_per_cell > vertices
std::vector< std::array< double, GeometryInfo< dim >::vertices_per_cell > > cell_manifold_quadrature_weights
std::vector< std::vector< Tensor< 1, spacedim > > > aux
virtual std::size_t memory_consumption() const override
void initialize_face(const UpdateFlags update_flags, const Quadrature< dim > &quadrature, const unsigned int n_original_q_points)
virtual void reinit(const UpdateFlags update_flags, const Quadrature< dim > &quadrature) override
ObserverPointer< const Manifold< dim, spacedim > > manifold
std::array< double, GeometryInfo< dim >::vertices_per_cell > vertex_weights
void compute_manifold_quadrature_weights(const Quadrature< dim > &quadrature)
std::vector< DerivativeForm< 1, dim, spacedim > > covariant
Triangulation< dim, spacedim >::cell_iterator cell
virtual Point< spacedim > transform_unit_to_real_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< dim > &p) const override
MappingManifold()=default
virtual std::unique_ptr< typename Mapping< dim, spacedim >::InternalDataBase > get_face_data(const UpdateFlags, const hp::QCollection< dim - 1 > &quadrature) const override
virtual Point< dim > transform_real_to_unit_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< spacedim > &p) 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 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 std::unique_ptr< typename Mapping< dim, spacedim >::InternalDataBase > get_subface_data(const UpdateFlags, const Quadrature< dim - 1 > &quadrature) const override
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 UpdateFlags requires_update_flags(const UpdateFlags update_flags) const override
virtual std::unique_ptr< typename Mapping< dim, spacedim >::InternalDataBase > get_data(const UpdateFlags, const Quadrature< dim > &quadrature) const override
virtual std::unique_ptr< Mapping< dim, spacedim > > clone() 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
Abstract base class for mapping classes.
Definition mapping.h:318
Definition point.h:111
static constexpr Point< dim, Number > unit_vector(const unsigned int i)
Class storing the offset index into a Quadrature rule created by project_to_all_faces() or project_to...
Definition qprojector.h:204
static DataSetDescriptor cell()
Definition qprojector.h:314
Class which transforms dim - 1-dimensional quadrature rules to dim-dimensional face quadratures.
Definition qprojector.h:68
const Point< dim > & point(const unsigned int i) const
const std::vector< double > & get_weights() 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
std::vector< DerivativeForm< 1, dim, spacedim > > jacobians
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
DerivativeForm< 1, spacedim, dim, Number > transpose(const DerivativeForm< 1, dim, spacedim, Number > &DF)
Tensor< 1, spacedim, typename ProductType< Number1, Number2 >::type > apply_transformation(const DerivativeForm< 1, dim, spacedim, Number1 > &grad_F, const Tensor< 1, dim, Number2 > &d_x)
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
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_jacobian_pushed_forward_3rd_derivatives
@ update_boundary_forms
Outer normal vector, not normalized.
MappingKind
Definition mapping.h:79
@ mapping_piola
Definition mapping.h:114
@ mapping_covariant_gradient
Definition mapping.h:100
@ mapping_covariant
Definition mapping.h:89
@ mapping_contravariant
Definition mapping.h:94
@ mapping_contravariant_hessian
Definition mapping.h:156
@ mapping_covariant_hessian
Definition mapping.h:150
@ mapping_contravariant_gradient
Definition mapping.h:106
@ mapping_piola_gradient
Definition mapping.h:120
@ mapping_piola_hessian
Definition mapping.h:162
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
constexpr char A
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition utilities.cc:210
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:464
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 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 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_compute_face_data(const ::MappingQ< dim, spacedim > &mapping, const typename ::Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const unsigned int subface_no, const unsigned int n_q_points, const std::vector< double > &weights, const typename ::MappingQ< dim, spacedim >::InternalData &data, internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data)
Tensor< 3, spacedim, Number > apply_contravariant_hessian(const DerivativeForm< 1, dim, spacedim, Number > &covariant, const DerivativeForm< 1, dim, spacedim, Number > &contravariant, const Tensor< 3, dim, Number > &input)
Tensor< 3, spacedim, Number > apply_piola_hessian(const DerivativeForm< 1, dim, spacedim, Number > &covariant, const DerivativeForm< 1, dim, spacedim, Number > &contravariant, const Number &volume_element, const Tensor< 3, dim, Number > &input)
Tensor< 2, spacedim, Number > apply_piola_gradient(const DerivativeForm< 1, dim, spacedim, Number > &covariant, const DerivativeForm< 1, dim, spacedim, Number > &contravariant, const Number &volume_element, const Tensor< 2, dim, Number > &input)
Tensor< 3, spacedim, Number > apply_covariant_gradient(const DerivativeForm< 1, dim, spacedim, Number > &covariant, const DerivativeForm< 2, dim, spacedim, Number > &input)
Tensor< 3, spacedim, Number > apply_covariant_hessian(const DerivativeForm< 1, dim, spacedim, Number > &covariant, const Tensor< 3, dim, Number > &input)
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices()
static double subface_ratio(const internal::SubfaceCase< dim > &subface_case, const unsigned int subface_no)
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 > &)