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
derivative_approximation.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) 2000 - 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
16
19
20#include <deal.II/fe/fe.h>
22#include <deal.II/fe/mapping.h>
23
28
33
44#include <deal.II/lac/vector.h>
45
47
48#include <algorithm>
49#include <cmath>
50
52
53
54
55namespace
56{
57 template <typename T>
58 T
59 sqr(const T t)
60 {
61 return t * t;
62 }
63} // namespace
64
65// --- First the classes and functions that describe individual derivatives ---
66
68{
69 namespace internal
70 {
77 template <int dim>
79 {
80 public:
86
92
98
105 template <class InputVector, int spacedim>
108 const InputVector &solution,
109 const unsigned int component);
110
115 static double
116 derivative_norm(const Derivative &d);
117
125 static void
126 symmetrize(Derivative &derivative_tensor);
127 };
128
129 // static variables
130 template <int dim>
132
133
134 template <int dim>
135 template <class InputVector, int spacedim>
138 const FEValues<dim, spacedim> &fe_values,
139 const InputVector &solution,
140 const unsigned int component)
141 {
142 if (fe_values.get_fe().n_components() == 1)
143 {
144 std::vector<typename InputVector::value_type> values(1);
145 fe_values.get_function_values(solution, values);
146 return values[0];
147 }
148 else
149 {
150 std::vector<Vector<typename InputVector::value_type>> values(
151 1,
153 fe_values.get_fe().n_components()));
154 fe_values.get_function_values(solution, values);
155 return values[0](component);
156 }
157 }
158
159
160
161 template <int dim>
162 double
164 {
165 double s = 0;
166 for (unsigned int i = 0; i < dim; ++i)
167 s += d[i] * d[i];
168 return std::sqrt(s);
169 }
170
171
172
173 template <int dim>
174 void
176 {
177 // nothing to do here
178 }
179
180
181
188 template <int dim>
190 {
191 public:
197
203
209
216 template <class InputVector, int spacedim>
219 const InputVector &solution,
220 const unsigned int component);
221
229 static double
230 derivative_norm(const Derivative &d);
231
241 static void
242 symmetrize(Derivative &derivative_tensor);
243 };
244
245 template <int dim>
247
248
249 template <int dim>
250 template <class InputVector, int spacedim>
253 const FEValues<dim, spacedim> &fe_values,
254 const InputVector &solution,
255 const unsigned int component)
256 {
257 if (fe_values.get_fe().n_components() == 1)
258 {
259 std::vector<Tensor<1, dim, typename InputVector::value_type>> values(
260 1);
261 fe_values.get_function_gradients(solution, values);
262 return ProjectedDerivative(values[0]);
263 }
264 else
265 {
266 std::vector<
267 std::vector<Tensor<1, dim, typename InputVector::value_type>>>
268 values(
269 1,
271 fe_values.get_fe().n_components()));
272 fe_values.get_function_gradients(solution, values);
273 return ProjectedDerivative(values[0][component]);
274 }
275 }
276
277
278
279 template <>
280 double
282 {
283 return std::fabs(d[0][0]);
284 }
285
286
287
288 template <>
289 double
291 {
292 // note that d should be a
293 // symmetric 2x2 tensor, so the
294 // eigenvalues are:
295 //
296 // 1/2(a+b\pm\sqrt((a-b)^2+4c^2))
297 //
298 // if the d_11=a, d_22=b,
299 // d_12=d_21=c
300 const double radicand =
301 ::sqr(d[0][0] - d[1][1]) + 4 * ::sqr(d[0][1]);
302 const double eigenvalues[2] = {
303 0.5 * (d[0][0] + d[1][1] + std::sqrt(radicand)),
304 0.5 * (d[0][0] + d[1][1] - std::sqrt(radicand))};
305
306 return std::max(std::fabs(eigenvalues[0]), std::fabs(eigenvalues[1]));
307 }
308
309
310
311 template <>
312 double
314 {
315 /*
316 compute the three eigenvalues of the tensor @p{d} and take the
317 largest. one could use the following maple script to generate C
318 code:
319
320 with(linalg);
321 readlib(C);
322 A:=matrix(3,3,[[a00,a01,a02],[a01,a11,a12],[a02,a12,a22]]);
323 E:=eigenvals(A);
324 EE:=vector(3,[E[1],E[2],E[3]]);
325 C(EE);
326
327 Unfortunately, with both optimized and non-optimized output, at some
328 places the code `sqrt(-1.0)' is emitted, and I don't know what
329 Maple intends to do with it. This happens both with Maple4 and
330 Maple5.
331
332 Fortunately, Roger Young provided the following Fortran code, which
333 is transcribed below to C. The code uses an algorithm that uses the
334 invariants of a symmetric matrix. (The translated algorithm is
335 augmented by a test for R>0, since R==0 indicates that all three
336 eigenvalues are equal.)
337
338
339 PROGRAM MAIN
340
341 C FIND EIGENVALUES OF REAL SYMMETRIC MATRIX
342 C (ROGER YOUNG, 2001)
343
344 IMPLICIT NONE
345
346 REAL*8 A11, A12, A13, A22, A23, A33
347 REAL*8 I1, J2, J3, AM
348 REAL*8 S11, S12, S13, S22, S23, S33
349 REAL*8 SS12, SS23, SS13
350 REAL*8 R,R3, XX,YY, THETA
351 REAL*8 A1,A2,A3
352 REAL*8 PI
353 PARAMETER (PI=3.141592653587932384D0)
354 REAL*8 A,B,C, TOL
355 PARAMETER (TOL=1.D-14)
356
357 C DEFINE A TEST MATRIX
358
359 A11 = -1.D0
360 A12 = 5.D0
361 A13 = 3.D0
362 A22 = -2.D0
363 A23 = 0.5D0
364 A33 = 4.D0
365
366
367 I1 = A11 + A22 + A33
368 AM = I1/3.D0
369
370 S11 = A11 - AM
371 S22 = A22 - AM
372 S33 = A33 - AM
373 S12 = A12
374 S13 = A13
375 S23 = A23
376
377 SS12 = S12*S12
378 SS23 = S23*S23
379 SS13 = S13*S13
380
381 J2 = S11*S11 + S22*S22 + S33*S33
382 J2 = J2 + 2.D0*(SS12 + SS23 + SS13)
383 J2 = J2/2.D0
384
385 J3 = S11**3 + S22**3 + S33**3
386 J3 = J3 + 3.D0*S11*(SS12 + SS13)
387 J3 = J3 + 3.D0*S22*(SS12 + SS23)
388 J3 = J3 + 3.D0*S33*(SS13 + SS23)
389 J3 = J3 + 6.D0*S12*S23*S13
390 J3 = J3/3.D0
391
392 R = SQRT(4.D0*J2/3.D0)
393 R3 = R*R*R
394 XX = 4.D0*J3/R3
395
396 YY = 1.D0 - DABS(XX)
397 IF(YY.LE.0.D0)THEN
398 IF(YY.GT.(-TOL))THEN
399 WRITE(6,*)'Equal roots: XX= ',XX
400 A = -(XX/DABS(XX))*SQRT(J2/3.D0)
401 B = AM + A
402 C = AM - 2.D0*A
403 WRITE(6,*)B,' (twice) ',C
404 STOP
405 ELSE
406 WRITE(6,*)'Error: XX= ',XX
407 STOP
408 ENDIF
409 ENDIF
410
411 THETA = (ACOS(XX))/3.D0
412
413 A1 = AM + R*COS(THETA)
414 A2 = AM + R*COS(THETA + 2.D0*PI/3.D0)
415 A3 = AM + R*COS(THETA + 4.D0*PI/3.D0)
416
417 WRITE(6,*)A1,A2,A3
418
419 STOP
420 END
421
422 */
423
424 const double am = trace(d) / 3.;
425
426 // s := d - trace(d) I
427 Tensor<2, 3> s = d;
428 for (unsigned int i = 0; i < 3; ++i)
429 s[i][i] -= am;
430
431 const double ss01 = s[0][1] * s[0][1], ss12 = s[1][2] * s[1][2],
432 ss02 = s[0][2] * s[0][2];
433
434 const double J2 = (s[0][0] * s[0][0] + s[1][1] * s[1][1] +
435 s[2][2] * s[2][2] + 2 * (ss01 + ss02 + ss12)) /
436 2.;
437 const double J3 =
438 (Utilities::fixed_power<3>(s[0][0]) +
439 Utilities::fixed_power<3>(s[1][1]) +
440 Utilities::fixed_power<3>(s[2][2]) + 3. * s[0][0] * (ss01 + ss02) +
441 3. * s[1][1] * (ss01 + ss12) + 3. * s[2][2] * (ss02 + ss12) +
442 6. * s[0][1] * s[0][2] * s[1][2]) /
443 3.;
444
445 const double R = std::sqrt(4. * J2 / 3.);
446
447 double EE[3] = {0, 0, 0};
448 // the eigenvalues are away from
449 // @p{am} in the order of R. thus,
450 // if R<<AM, then we have the
451 // degenerate case with three
452 // identical eigenvalues. check
453 // this first
454 if (R <= 1e-14 * std::fabs(am))
455 EE[0] = EE[1] = EE[2] = am;
456 else
457 {
458 // at least two eigenvalues are
459 // distinct
460 const double R3 = R * R * R;
461 const double XX = 4. * J3 / R3;
462 const double YY = 1. - std::fabs(XX);
463
464 Assert(YY > -1e-14, ExcInternalError());
465
466 if (YY < 0)
467 {
468 // two roots are equal
469 const double a = (XX > 0 ? -1. : 1.) * R / 2;
470 EE[0] = EE[1] = am + a;
471 EE[2] = am - 2. * a;
472 }
473 else
474 {
475 const double theta = std::acos(XX) / 3.;
476 EE[0] = am + R * std::cos(theta);
477 EE[1] = am + R * std::cos(theta + 2. / 3. * numbers::PI);
478 EE[2] = am + R * std::cos(theta + 4. / 3. * numbers::PI);
479 }
480 }
481
482 return std::max({std::fabs(EE[0]), std::fabs(EE[1]), std::fabs(EE[2])});
483 }
484
485
486
487 template <int dim>
488 double
490 {
491 // computing the spectral norm is
492 // not so simple in general. it is
493 // feasible for dim==3 as shown
494 // above, since then there are
495 // still closed form expressions of
496 // the roots of the characteristic
497 // polynomial, and they can easily
498 // be computed using
499 // maple. however, for higher
500 // dimensions, some other method
501 // needs to be employed. maybe some
502 // steps of the power method would
503 // suffice?
505 return 0;
506 }
507
508
509
510 template <int dim>
511 void
513 {
514 // symmetrize non-diagonal entries
515 for (unsigned int i = 0; i < dim; ++i)
516 for (unsigned int j = i + 1; j < dim; ++j)
517 {
518 const double s = (d[i][j] + d[j][i]) / 2;
519 d[i][j] = d[j][i] = s;
520 }
521 }
522
523
524
525 template <int dim>
527 {
528 public:
534
541
547
554 template <class InputVector, int spacedim>
557 const InputVector &solution,
558 const unsigned int component);
559
567 static double
568 derivative_norm(const Derivative &d);
569
579 static void
580 symmetrize(Derivative &derivative_tensor);
581 };
582
583 template <int dim>
585
586
587 template <int dim>
588 template <class InputVector, int spacedim>
591 const FEValues<dim, spacedim> &fe_values,
592 const InputVector &solution,
593 const unsigned int component)
594 {
595 if (fe_values.get_fe().n_components() == 1)
596 {
597 std::vector<Tensor<2, dim, typename InputVector::value_type>> values(
598 1);
599 fe_values.get_function_hessians(solution, values);
600 return ProjectedDerivative(values[0]);
601 }
602 else
603 {
604 std::vector<
605 std::vector<Tensor<2, dim, typename InputVector::value_type>>>
606 values(
607 1,
609 fe_values.get_fe().n_components()));
610 fe_values.get_function_hessians(solution, values);
611 return ProjectedDerivative(values[0][component]);
612 }
613 }
614
615
616
617 template <>
618 double
620 {
621 return std::fabs(d[0][0][0]);
622 }
623
624
625
626 template <int dim>
627 double
629 {
630 // return the Frobenius-norm. this is a
631 // member function of Tensor<rank_,dim>
632 return d.norm();
633 }
634
635
636 template <int dim>
637 void
639 {
640 // symmetrize non-diagonal entries
641
642 // first do it in the case, that i,j,k are
643 // pairwise different (which can onlky happen
644 // in dim >= 3)
645 for (unsigned int i = 0; i < dim; ++i)
646 for (unsigned int j = i + 1; j < dim; ++j)
647 for (unsigned int k = j + 1; k < dim; ++k)
648 {
649 const double s = (d[i][j][k] + d[i][k][j] + d[j][i][k] +
650 d[j][k][i] + d[k][i][j] + d[k][j][i]) /
651 6;
652 d[i][j][k] = d[i][k][j] = d[j][i][k] = d[j][k][i] = d[k][i][j] =
653 d[k][j][i] = s;
654 }
655 // now do the case, where two indices are
656 // equal
657 for (unsigned int i = 0; i < dim; ++i)
658 for (unsigned int j = i + 1; j < dim; ++j)
659 {
660 // case 1: index i (lower one) is
661 // double
662 const double s = (d[i][i][j] + d[i][j][i] + d[j][i][i]) / 3;
663 d[i][i][j] = d[i][j][i] = d[j][i][i] = s;
664
665 // case 2: index j (higher one) is
666 // double
667 const double t = (d[i][j][j] + d[j][i][j] + d[j][j][i]) / 3;
668 d[i][j][j] = d[j][i][j] = d[j][j][i] = t;
669 }
670 }
671
672
673 template <int order, int dim>
675 {
676 public:
682 using DerivDescr = void;
683 };
684
685 template <int dim>
686 class DerivativeSelector<1, dim>
687 {
688 public:
690 };
691
692 template <int dim>
693 class DerivativeSelector<2, dim>
694 {
695 public:
697 };
698
699 template <int dim>
700 class DerivativeSelector<3, dim>
701 {
702 public:
704 };
705 } // namespace internal
706} // namespace DerivativeApproximation
707
708// Dummy structures and dummy function used for WorkStream
710{
711 namespace internal
712 {
713 namespace Assembler
714 {
715 struct Scratch
716 {
717 Scratch() = default;
718 };
719
720 struct CopyData
721 {
722 CopyData() = default;
723 };
724 } // namespace Assembler
725 } // namespace internal
726} // namespace DerivativeApproximation
727
728// --------------- now for the functions that do the actual work --------------
729
731{
732 namespace internal
733 {
738 template <class DerivativeDescription,
739 int dim,
740 class InputVector,
741 int spacedim>
742 void
744 const Mapping<dim, spacedim> &mapping,
745 const DoFHandler<dim, spacedim> &dof_handler,
746 const InputVector &solution,
747 const unsigned int component,
749 typename DerivativeDescription::Derivative &derivative)
750 {
751 const QMidpoint<dim> midpoint_rule;
752
753 // create collection objects from
754 // single quadratures, mappings,
755 // and finite elements. if we have
756 // an hp-DoFHandler,
757 // dof_handler.get_fe() returns a
758 // collection of which we do a
759 // shallow copy instead
760 const hp::QCollection<dim> q_collection(midpoint_rule);
761 const hp::FECollection<dim> &fe_collection =
762 dof_handler.get_fe_collection();
763 const hp::MappingCollection<dim> mapping_collection(mapping);
764
765 hp::FEValues<dim> x_fe_midpoint_value(
766 mapping_collection,
767 fe_collection,
768 q_collection,
769 DerivativeDescription::update_flags | update_quadrature_points);
770
771 // matrix Y=sum_i y_i y_i^T
773
774
775 // vector to hold iterators to all
776 // active neighbors of a cell
777 // reserve the maximal number of
778 // active neighbors
779 std::vector<typename DoFHandler<dim, spacedim>::active_cell_iterator>
780 active_neighbors;
781
782 active_neighbors.reserve(GeometryInfo<dim>::faces_per_cell *
784
785 // vector
786 // g=sum_i y_i (f(x+y_i)-f(x))/|y_i|
787 // or related type for higher
788 // derivatives
789 typename DerivativeDescription::Derivative projected_derivative;
790
791 // reinit FE values object...
792 x_fe_midpoint_value.reinit(cell);
793 const FEValues<dim> &fe_midpoint_value =
794 x_fe_midpoint_value.get_present_fe_values();
795
796 // ...and get the value of the
797 // projected derivative...
798 const typename DerivativeDescription::ProjectedDerivative
799 this_midpoint_value =
800 DerivativeDescription::get_projected_derivative(fe_midpoint_value,
801 solution,
802 component);
803 // ...and the place where it lives
804 // This needs to be a copy. If it was a reference, it would be changed
805 // after the next `reinit` call of the FEValues object. clang-tidy
806 // complains about this not being a reference, so we suppress the warning.
807 const Point<dim> this_center =
808 fe_midpoint_value.quadrature_point(0); // NOLINT
809
810 // loop over all neighbors and
811 // accumulate the difference
812 // quotients from them. note
813 // that things get a bit more
814 // complicated if the neighbor
815 // is more refined than the
816 // present one
817 //
818 // to make processing simpler,
819 // first collect all neighbor
820 // cells in a vector, and then
821 // collect the data from them
822 GridTools::get_active_neighbors<DoFHandler<dim, spacedim>>(
823 cell, active_neighbors);
824
825 // now loop over all active
826 // neighbors and collect the
827 // data we need
828 auto neighbor_ptr = active_neighbors.begin();
829 for (; neighbor_ptr != active_neighbors.end(); ++neighbor_ptr)
830 {
831 const auto &neighbor = *neighbor_ptr;
832
833 // reinit FE values object...
834 x_fe_midpoint_value.reinit(neighbor);
835 const FEValues<dim> &neighbor_fe_midpoint_value =
836 x_fe_midpoint_value.get_present_fe_values();
837
838 // ...and get the value of the
839 // solution...
840 const typename DerivativeDescription::ProjectedDerivative
841 neighbor_midpoint_value =
842 DerivativeDescription::get_projected_derivative(
843 neighbor_fe_midpoint_value, solution, component);
844
845 // ...and the place where it lives
846 const Point<dim> &neighbor_center =
847 neighbor_fe_midpoint_value.quadrature_point(0);
848
849
850 // vector for the
851 // normalized
852 // direction between
853 // the centers of two
854 // cells
855
856 Tensor<1, dim> y = neighbor_center - this_center;
857 const double distance = y.norm();
858 // normalize y
859 y /= distance;
860 // *** note that unlike in
861 // the docs, y denotes the
862 // normalized vector
863 // connecting the centers
864 // of the two cells, rather
865 // than the normal
866 // difference! ***
867
868 // add up the
869 // contribution of
870 // this cell to Y
871 for (unsigned int i = 0; i < dim; ++i)
872 for (unsigned int j = 0; j < dim; ++j)
873 Y[i][j] += y[i] * y[j];
874
875 // then update the sum
876 // of difference
877 // quotients
878 typename DerivativeDescription::ProjectedDerivative
879 projected_finite_difference =
880 (neighbor_midpoint_value - this_midpoint_value);
881 projected_finite_difference /= distance;
882
883 projected_derivative += outer_product(y, projected_finite_difference);
884 }
885
886 // can we determine an
887 // approximation of the
888 // gradient for the present
889 // cell? if so, then we need to
890 // have passed over vectors y_i
891 // which span the whole space,
892 // otherwise we would not have
893 // all components of the
894 // gradient
896
897 // compute Y^-1 g
898 const Tensor<2, dim> Y_inverse = invert(Y);
899
900 derivative = Y_inverse * projected_derivative;
901
902 // finally symmetrize the derivative
903 DerivativeDescription::symmetrize(derivative);
904 }
905
906
907
913 template <class DerivativeDescription,
914 int dim,
915 class InputVector,
916 int spacedim>
917 void
922 const Mapping<dim, spacedim> &mapping,
923 const DoFHandler<dim, spacedim> &dof_handler,
924 const InputVector &solution,
925 const unsigned int component)
926 {
927 // if the cell is not locally owned, then there is nothing to do
928 if (std::get<0>(*cell)->is_locally_owned() == false)
929 *std::get<1>(*cell) = 0;
930 else
931 {
932 typename DerivativeDescription::Derivative derivative;
933 // call the function doing the actual
934 // work on this cell
935 approximate_cell<DerivativeDescription, dim, InputVector, spacedim>(
936 mapping,
937 dof_handler,
938 solution,
939 component,
940 std::get<0>(*cell),
941 derivative);
942
943 // evaluate the norm and fill the vector
944 //*derivative_norm_on_this_cell
945 *std::get<1>(*cell) =
946 DerivativeDescription::derivative_norm(derivative);
947 }
948 }
949
950
961 template <class DerivativeDescription,
962 int dim,
963 class InputVector,
964 int spacedim>
965 void
967 const DoFHandler<dim, spacedim> &dof_handler,
968 const InputVector &solution,
969 const unsigned int component,
971 {
972 Assert(derivative_norm.size() ==
973 dof_handler.get_triangulation().n_active_cells(),
975 derivative_norm.size(),
976 dof_handler.get_triangulation().n_active_cells()));
977 AssertIndexRange(component, dof_handler.get_fe(0).n_components());
978
979 using Iterators =
980 std::tuple<typename DoFHandler<dim, spacedim>::active_cell_iterator,
983 Iterators(dof_handler.begin_active(), derivative_norm.begin())),
984 end(Iterators(dof_handler.end(), derivative_norm.end()));
985
986 // Use type erasure to prevent workstream from seeing this function's type
987 // (which in turn prevents it from instantiating for every possible
988 // InputVector type)
989 std::function<void(const SynchronousIterators<Iterators> &cell,
990 const Assembler::Scratch &,
992 worker = [&mapping,
993 &dof_handler,
994 &solution,
995 component](const SynchronousIterators<Iterators> &cell,
996 const Assembler::Scratch &,
998 approximate<DerivativeDescription, dim, InputVector, spacedim>(
999 cell, mapping, dof_handler, solution, component);
1000 };
1001
1002 // There is no need for a copier because there is no conflict between
1003 // threads to write in derivative_norm. Scratch and CopyData are also
1004 // useless.
1006 begin,
1007 end,
1008 worker,
1009 std::function<void(const internal::Assembler::CopyData &)>(),
1012 }
1013
1014 } // namespace internal
1015
1016} // namespace DerivativeApproximation
1017
1018
1019// ------------------------ finally for the public interface of this namespace
1020
1022{
1023 template <int dim, class InputVector, int spacedim>
1024 void
1026 const DoFHandler<dim, spacedim> &dof_handler,
1027 const InputVector &solution,
1029 const unsigned int component)
1030 {
1031 internal::approximate_derivative<internal::Gradient<dim>, dim>(
1032 mapping, dof_handler, solution, component, derivative_norm);
1033 }
1034
1035
1036 template <int dim, class InputVector, int spacedim>
1037 void
1039 const InputVector &solution,
1041 const unsigned int component)
1042 {
1043 Assert(!dof_handler.get_triangulation().is_mixed_mesh(),
1045 const auto reference_cell =
1046 dof_handler.get_triangulation().get_reference_cells()[0];
1047 internal::approximate_derivative<internal::Gradient<dim>, dim>(
1048 reference_cell.template get_default_linear_mapping<spacedim>(),
1049 dof_handler,
1050 solution,
1051 component,
1053 }
1054
1055
1056 template <int dim, class InputVector, int spacedim>
1057 void
1059 const DoFHandler<dim, spacedim> &dof_handler,
1060 const InputVector &solution,
1062 const unsigned int component)
1063 {
1064 internal::approximate_derivative<internal::SecondDerivative<dim>, dim>(
1065 mapping, dof_handler, solution, component, derivative_norm);
1066 }
1067
1068
1069 template <int dim, class InputVector, int spacedim>
1070 void
1072 const InputVector &solution,
1074 const unsigned int component)
1075 {
1076 Assert(!dof_handler.get_triangulation().is_mixed_mesh(),
1078 const auto reference_cell =
1079 dof_handler.get_triangulation().get_reference_cells()[0];
1080 internal::approximate_derivative<internal::SecondDerivative<dim>, dim>(
1081 reference_cell.template get_default_linear_mapping<spacedim>(),
1082 dof_handler,
1083 solution,
1084 component,
1086 }
1087
1088
1089 template <int dim, int spacedim, class InputVector, int order>
1090 void
1092 const Mapping<dim, spacedim> &mapping,
1093 const DoFHandler<dim, spacedim> &dof,
1094 const InputVector &solution,
1095#ifndef _MSC_VER
1097#else
1099 &cell,
1100#endif
1101 Tensor<order, dim> &derivative,
1102 const unsigned int component)
1103 {
1106 mapping, dof, solution, component, cell, derivative);
1107 }
1108
1109
1110
1111 template <int dim, int spacedim, class InputVector, int order>
1112 void
1114 const DoFHandler<dim, spacedim> &dof,
1115 const InputVector &solution,
1116#ifndef _MSC_VER
1118#else
1120 &cell,
1121#endif
1122 Tensor<order, dim> &derivative,
1123 const unsigned int component)
1124 {
1125 // just call the respective function with Q1 mapping
1127 cell->reference_cell().template get_default_linear_mapping<spacedim>(),
1128 dof,
1129 solution,
1130 cell,
1131 derivative,
1132 component);
1133 }
1134
1135
1136
1137 template <int dim, int order>
1138 double
1144
1145} // namespace DerivativeApproximation
1146
1147
1148// --------------------------- explicit instantiations ---------------------
1149#include "numerics/derivative_approximation.inst"
1150
1151
*  iterator end()
*  *  iterator begin()
static ProjectedDerivative get_projected_derivative(const FEValues< dim, spacedim > &fe_values, const InputVector &solution, const unsigned int component)
static void symmetrize(Derivative &derivative_tensor)
static double derivative_norm(const Derivative &d)
static ProjectedDerivative get_projected_derivative(const FEValues< dim, spacedim > &fe_values, const InputVector &solution, const unsigned int component)
static void symmetrize(Derivative &derivative_tensor)
static ProjectedDerivative get_projected_derivative(const FEValues< dim, spacedim > &fe_values, const InputVector &solution, const unsigned int component)
static void symmetrize(Derivative &derivative_tensor)
cell_iterator end() const
const hp::FECollection< dim, spacedim > & get_fe_collection() const
const FiniteElement< dim, spacedim > & get_fe(const types::fe_index index=0) const
const Triangulation< dim, spacedim > & get_triangulation() const
active_cell_iterator begin_active(const unsigned int level=0) const
void get_function_values(const ReadVector< Number > &fe_function, std::vector< Number > &values) const
void get_function_hessians(const ReadVector< Number > &fe_function, std::vector< Tensor< 2, spacedim, Number > > &hessians) const
const Point< spacedim > & quadrature_point(const unsigned int q_point) const
void get_function_gradients(const ReadVector< Number > &fe_function, std::vector< Tensor< 1, spacedim, Number > > &gradients) const
const FiniteElement< dim, spacedim > & get_fe() const
unsigned int n_components() const
Abstract base class for mapping classes.
Definition mapping.h:318
Definition point.h:111
numbers::NumberTraits< Number >::real_type norm() const
unsigned int n_active_cells() const
bool is_mixed_mesh() const
const std::vector< ReferenceCell< dim > > & get_reference_cells() const
value_type * iterator
Definition vector.h:118
const FEValuesType & get_present_fe_values() const
Definition fe_values.h:693
void reinit(const TriaIterator< DoFCellAccessor< dim, spacedim, lda > > &cell, const unsigned int q_index=numbers::invalid_unsigned_int, const unsigned int mapping_index=numbers::invalid_unsigned_int, const unsigned int fe_index=numbers::invalid_unsigned_int)
Definition fe_values.cc:294
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcInsufficientDirections()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcVectorLengthVsNActiveCells(int arg1, int arg2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
#define AssertThrow(cond, exc)
typename ActiveSelector::active_cell_iterator active_cell_iterator
UpdateFlags
@ update_hessians
Second derivatives of shape functions.
@ update_values
Shape function values.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
void approximate_derivative(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof_handler, const InputVector &solution, const unsigned int component, Vector< float > &derivative_norm)
void approximate(const SynchronousIterators< std::tuple< typename DoFHandler< dim, spacedim >::active_cell_iterator, Vector< float >::iterator > > &cell, const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof_handler, const InputVector &solution, const unsigned int component)
void approximate_cell(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof_handler, const InputVector &solution, const unsigned int component, const typename DoFHandler< dim, spacedim >::active_cell_iterator &cell, typename DerivativeDescription::Derivative &derivative)
void approximate_gradient(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const InputVector &solution, Vector< float > &derivative_norm, const unsigned int component=0)
double derivative_norm(const Tensor< order, dim > &derivative)
void approximate_derivative_tensor(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const InputVector &solution, const typename DoFHandler< dim, spacedim >::active_cell_iterator &cell, Tensor< order, dim > &derivative, const unsigned int component=0)
void approximate_second_derivative(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const InputVector &solution, Vector< float > &derivative_norm, const unsigned int component=0)
constexpr char T
void run(const std::vector< std::vector< Iterator > > &colored_iterators, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
constexpr double PI
Definition numbers.h:240
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
inline ::VectorizedArray< Number, width > acos(const ::VectorizedArray< Number, width > &x)
constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &)
constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)
constexpr Number trace(const SymmetricTensor< 2, dim2, Number > &)
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)
constexpr SymmetricTensor< 4, dim, Number > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)