Reference documentation for deal.II version 9.1.0-pre
derivative_approximation.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/quadrature_lib.h>
17 #include <deal.II/base/work_stream.h>
18 
19 #include <deal.II/dofs/dof_accessor.h>
20 #include <deal.II/dofs/dof_handler.h>
21 
22 #include <deal.II/fe/fe.h>
23 #include <deal.II/fe/fe_values.h>
24 #include <deal.II/fe/mapping_q1.h>
25 
26 #include <deal.II/grid/filtered_iterator.h>
27 #include <deal.II/grid/grid_tools.h>
28 #include <deal.II/grid/tria_iterator.h>
29 
30 #include <deal.II/hp/fe_collection.h>
31 #include <deal.II/hp/fe_values.h>
32 #include <deal.II/hp/mapping_collection.h>
33 #include <deal.II/hp/q_collection.h>
34 
35 #include <deal.II/lac/block_vector.h>
36 #include <deal.II/lac/la_parallel_block_vector.h>
37 #include <deal.II/lac/la_parallel_vector.h>
38 #include <deal.II/lac/la_vector.h>
39 #include <deal.II/lac/petsc_block_vector.h>
40 #include <deal.II/lac/petsc_vector.h>
41 #include <deal.II/lac/trilinos_parallel_block_vector.h>
42 #include <deal.II/lac/trilinos_vector.h>
43 #include <deal.II/lac/vector.h>
44 
45 #include <deal.II/numerics/derivative_approximation.h>
46 
47 #include <cmath>
48 
49 DEAL_II_NAMESPACE_OPEN
50 
51 
52 
53 namespace
54 {
55  template <typename T>
56  inline T
57  sqr(const T t)
58  {
59  return t * t;
60  }
61 } // namespace
62 
63 // --- First the classes and functions that describe individual derivatives ---
64 
66 {
67  namespace internal
68  {
77  template <int dim>
78  class Gradient
79  {
80  public:
85  static const UpdateFlags update_flags;
86 
92 
98 
105  template <class InputVector, int spacedim>
106  static ProjectedDerivative
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>
136  inline typename Gradient<dim>::ProjectedDerivative
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,
152  Vector<typename InputVector::value_type>(
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  inline 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  inline void
176  {
177  // nothing to do here
178  }
179 
180 
181 
190  template <int dim>
192  {
193  public:
198  static const UpdateFlags update_flags;
199 
205 
211 
218  template <class InputVector, int spacedim>
219  static ProjectedDerivative
221  const InputVector & solution,
222  const unsigned int component);
223 
231  static double
232  derivative_norm(const Derivative &d);
233 
243  static void
244  symmetrize(Derivative &derivative_tensor);
245  };
246 
247  template <int dim>
249 
250 
251  template <int dim>
252  template <class InputVector, int spacedim>
255  const FEValues<dim, spacedim> &fe_values,
256  const InputVector & solution,
257  const unsigned int component)
258  {
259  if (fe_values.get_fe().n_components() == 1)
260  {
261  std::vector<Tensor<1, dim, typename InputVector::value_type>> values(
262  1);
263  fe_values.get_function_gradients(solution, values);
264  return ProjectedDerivative(values[0]);
265  }
266  else
267  {
268  std::vector<
269  std::vector<Tensor<1, dim, typename InputVector::value_type>>>
270  values(
271  1,
273  fe_values.get_fe().n_components()));
274  fe_values.get_function_gradients(solution, values);
275  return ProjectedDerivative(values[0][component]);
276  };
277  }
278 
279 
280 
281  template <>
282  inline double
284  {
285  return std::fabs(d[0][0]);
286  }
287 
288 
289 
290  template <>
291  inline double
293  {
294  // note that d should be a
295  // symmetric 2x2 tensor, so the
296  // eigenvalues are:
297  //
298  // 1/2(a+b\pm\sqrt((a-b)^2+4c^2))
299  //
300  // if the d_11=a, d_22=b,
301  // d_12=d_21=c
302  const double radicand =
303  ::sqr(d[0][0] - d[1][1]) + 4 * ::sqr(d[0][1]);
304  const double eigenvalues[2] = {
305  0.5 * (d[0][0] + d[1][1] + std::sqrt(radicand)),
306  0.5 * (d[0][0] + d[1][1] - std::sqrt(radicand))};
307 
308  return std::max(std::fabs(eigenvalues[0]), std::fabs(eigenvalues[1]));
309  }
310 
311 
312 
313  template <>
314  inline double
316  {
317  /*
318  compute the three eigenvalues of the tensor @p{d} and take the
319  largest. one could use the following maple script to generate C
320  code:
321 
322  with(linalg);
323  readlib(C);
324  A:=matrix(3,3,[[a00,a01,a02],[a01,a11,a12],[a02,a12,a22]]);
325  E:=eigenvals(A);
326  EE:=vector(3,[E[1],E[2],E[3]]);
327  C(EE);
328 
329  Unfortunately, with both optimized and non-optimized output, at some
330  places the code `sqrt(-1.0)' is emitted, and I don't know what
331  Maple intends to do with it. This happens both with Maple4 and
332  Maple5.
333 
334  Fortunately, Roger Young provided the following Fortran code, which
335  is transcribed below to C. The code uses an algorithm that uses the
336  invariants of a symmetric matrix. (The translated algorithm is
337  augmented by a test for R>0, since R==0 indicates that all three
338  eigenvalues are equal.)
339 
340 
341  PROGRAM MAIN
342 
343  C FIND EIGENVALUES OF REAL SYMMETRIC MATRIX
344  C (ROGER YOUNG, 2001)
345 
346  IMPLICIT NONE
347 
348  REAL*8 A11, A12, A13, A22, A23, A33
349  REAL*8 I1, J2, J3, AM
350  REAL*8 S11, S12, S13, S22, S23, S33
351  REAL*8 SS12, SS23, SS13
352  REAL*8 R,R3, XX,YY, THETA
353  REAL*8 A1,A2,A3
354  REAL*8 PI
355  PARAMETER (PI=3.141592653587932384D0)
356  REAL*8 A,B,C, TOL
357  PARAMETER (TOL=1.D-14)
358 
359  C DEFINE A TEST MATRIX
360 
361  A11 = -1.D0
362  A12 = 5.D0
363  A13 = 3.D0
364  A22 = -2.D0
365  A23 = 0.5D0
366  A33 = 4.D0
367 
368 
369  I1 = A11 + A22 + A33
370  AM = I1/3.D0
371 
372  S11 = A11 - AM
373  S22 = A22 - AM
374  S33 = A33 - AM
375  S12 = A12
376  S13 = A13
377  S23 = A23
378 
379  SS12 = S12*S12
380  SS23 = S23*S23
381  SS13 = S13*S13
382 
383  J2 = S11*S11 + S22*S22 + S33*S33
384  J2 = J2 + 2.D0*(SS12 + SS23 + SS13)
385  J2 = J2/2.D0
386 
387  J3 = S11**3 + S22**3 + S33**3
388  J3 = J3 + 3.D0*S11*(SS12 + SS13)
389  J3 = J3 + 3.D0*S22*(SS12 + SS23)
390  J3 = J3 + 3.D0*S33*(SS13 + SS23)
391  J3 = J3 + 6.D0*S12*S23*S13
392  J3 = J3/3.D0
393 
394  R = SQRT(4.D0*J2/3.D0)
395  R3 = R*R*R
396  XX = 4.D0*J3/R3
397 
398  YY = 1.D0 - DABS(XX)
399  IF(YY.LE.0.D0)THEN
400  IF(YY.GT.(-TOL))THEN
401  WRITE(6,*)'Equal roots: XX= ',XX
402  A = -(XX/DABS(XX))*SQRT(J2/3.D0)
403  B = AM + A
404  C = AM - 2.D0*A
405  WRITE(6,*)B,' (twice) ',C
406  STOP
407  ELSE
408  WRITE(6,*)'Error: XX= ',XX
409  STOP
410  ENDIF
411  ENDIF
412 
413  THETA = (ACOS(XX))/3.D0
414 
415  A1 = AM + R*COS(THETA)
416  A2 = AM + R*COS(THETA + 2.D0*PI/3.D0)
417  A3 = AM + R*COS(THETA + 4.D0*PI/3.D0)
418 
419  WRITE(6,*)A1,A2,A3
420 
421  STOP
422  END
423 
424  */
425 
426  const double am = trace(d) / 3.;
427 
428  // s := d - trace(d) I
429  Tensor<2, 3> s = d;
430  for (unsigned int i = 0; i < 3; ++i)
431  s[i][i] -= am;
432 
433  const double ss01 = s[0][1] * s[0][1], ss12 = s[1][2] * s[1][2],
434  ss02 = s[0][2] * s[0][2];
435 
436  const double J2 = (s[0][0] * s[0][0] + s[1][1] * s[1][1] +
437  s[2][2] * s[2][2] + 2 * (ss01 + ss02 + ss12)) /
438  2.;
439  const double J3 =
440  (std::pow(s[0][0], 3) + std::pow(s[1][1], 3) + std::pow(s[2][2], 3) +
441  3. * s[0][0] * (ss01 + ss02) + 3. * s[1][1] * (ss01 + ss12) +
442  3. * s[2][2] * (ss02 + ss12) + 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]),
483  std::max(std::fabs(EE[1]), std::fabs(EE[2])));
484  }
485 
486 
487 
488  template <int dim>
489  inline double
491  {
492  // computing the spectral norm is
493  // not so simple in general. it is
494  // feasible for dim==3 as shown
495  // above, since then there are
496  // still closed form expressions of
497  // the roots of the characteristic
498  // polynomial, and they can easily
499  // be computed using
500  // maple. however, for higher
501  // dimensions, some other method
502  // needs to be employed. maybe some
503  // steps of the power method would
504  // suffice?
505  Assert(false, ExcNotImplemented());
506  return 0;
507  }
508 
509 
510 
511  template <int dim>
512  inline void
514  {
515  // symmetrize non-diagonal entries
516  for (unsigned int i = 0; i < dim; ++i)
517  for (unsigned int j = i + 1; j < dim; ++j)
518  {
519  const double s = (d[i][j] + d[j][i]) / 2;
520  d[i][j] = d[j][i] = s;
521  };
522  }
523 
524 
525 
526  template <int dim>
527  class ThirdDerivative
528  {
529  public:
534  static const UpdateFlags update_flags;
535 
541  using Derivative = Tensor<3, dim>;
542 
548 
555  template <class InputVector, int spacedim>
556  static ProjectedDerivative
558  const InputVector & solution,
559  const unsigned int component);
560 
568  static double
569  derivative_norm(const Derivative &d);
570 
580  static void
581  symmetrize(Derivative &derivative_tensor);
582  };
583 
584  template <int dim>
585  const UpdateFlags ThirdDerivative<dim>::update_flags = update_hessians;
586 
587 
588  template <int dim>
589  template <class InputVector, int spacedim>
591  ThirdDerivative<dim>::get_projected_derivative(
592  const FEValues<dim, spacedim> &fe_values,
593  const InputVector & solution,
594  const unsigned int component)
595  {
596  if (fe_values.get_fe().n_components() == 1)
597  {
598  std::vector<Tensor<2, dim, typename InputVector::value_type>> values(
599  1);
600  fe_values.get_function_hessians(solution, values);
601  return ProjectedDerivative(values[0]);
602  }
603  else
604  {
605  std::vector<
606  std::vector<Tensor<2, dim, typename InputVector::value_type>>>
607  values(
608  1,
610  fe_values.get_fe().n_components()));
611  fe_values.get_function_hessians(solution, values);
612  return ProjectedDerivative(values[0][component]);
613  };
614  }
615 
616 
617 
618  template <>
619  inline double
620  ThirdDerivative<1>::derivative_norm(const Derivative &d)
621  {
622  return std::fabs(d[0][0][0]);
623  }
624 
625 
626 
627  template <int dim>
628  inline double
629  ThirdDerivative<dim>::derivative_norm(const Derivative &d)
630  {
631  // return the Frobenius-norm. this is a
632  // member function of Tensor<rank_,dim>
633  return d.norm();
634  }
635 
636 
637  template <int dim>
638  inline void
640  {
641  // symmetrize non-diagonal entries
642 
643  // first do it in the case, that i,j,k are
644  // pairwise different (which can onlky happen
645  // in dim >= 3)
646  for (unsigned int i = 0; i < dim; ++i)
647  for (unsigned int j = i + 1; j < dim; ++j)
648  for (unsigned int k = j + 1; k < dim; ++k)
649  {
650  const double s = (d[i][j][k] + d[i][k][j] + d[j][i][k] +
651  d[j][k][i] + d[k][i][j] + d[k][j][i]) /
652  6;
653  d[i][j][k] = d[i][k][j] = d[j][i][k] = d[j][k][i] = d[k][i][j] =
654  d[k][j][i] = s;
655  }
656  // now do the case, where two indices are
657  // equal
658  for (unsigned int i = 0; i < dim; ++i)
659  for (unsigned int j = i + 1; j < dim; ++j)
660  {
661  // case 1: index i (lower one) is
662  // double
663  const double s = (d[i][i][j] + d[i][j][i] + d[j][i][i]) / 3;
664  d[i][i][j] = d[i][j][i] = d[j][i][i] = s;
665 
666  // case 2: index j (higher one) is
667  // double
668  const double t = (d[i][j][j] + d[j][i][j] + d[j][j][i]) / 3;
669  d[i][j][j] = d[j][i][j] = d[j][j][i] = t;
670  }
671  }
672 
673 
674  template <int order, int dim>
675  class DerivativeSelector
676  {
677  public:
683  using DerivDescr = void;
684  };
685 
686  template <int dim>
687  class DerivativeSelector<1, dim>
688  {
689  public:
690  using DerivDescr = Gradient<dim>;
691  };
692 
693  template <int dim>
694  class DerivativeSelector<2, dim>
695  {
696  public:
697  using DerivDescr = SecondDerivative<dim>;
698  };
699 
700  template <int dim>
701  class DerivativeSelector<3, dim>
702  {
703  public:
704  using DerivDescr = ThirdDerivative<dim>;
705  };
706  } // namespace internal
707 } // namespace DerivativeApproximation
708 
709 // Dummy structures and dummy function used for WorkStream
710 namespace DerivativeApproximation
711 {
712  namespace internal
713  {
714  namespace Assembler
715  {
716  struct Scratch
717  {
718  Scratch() = default;
719  };
720 
721  struct CopyData
722  {
723  CopyData() = default;
724  };
725  } // namespace Assembler
726  } // namespace internal
727 } // namespace DerivativeApproximation
728 
729 // --------------- now for the functions that do the actual work --------------
730 
731 namespace DerivativeApproximation
732 {
733  namespace internal
734  {
739  template <class DerivativeDescription,
740  int dim,
741  template <int, int> class DoFHandlerType,
742  class InputVector,
743  int spacedim>
744  void
745  approximate_cell(
746  const Mapping<dim, spacedim> & mapping,
747  const DoFHandlerType<dim, spacedim> &dof_handler,
748  const InputVector & solution,
749  const unsigned int component,
750  const TriaActiveIterator<
751  ::DoFCellAccessor<DoFHandlerType<dim, spacedim>, false>> &cell,
752  typename DerivativeDescription::Derivative &derivative)
753  {
754  QMidpoint<dim> midpoint_rule;
755 
756  // create collection objects from
757  // single quadratures, mappings,
758  // and finite elements. if we have
759  // an hp DoFHandler,
760  // dof_handler.get_fe() returns a
761  // collection of which we do a
762  // shallow copy instead
763  const hp::QCollection<dim> q_collection(midpoint_rule);
764  const hp::FECollection<dim> &fe_collection =
765  dof_handler.get_fe_collection();
766  const hp::MappingCollection<dim> mapping_collection(mapping);
767 
768  hp::FEValues<dim> x_fe_midpoint_value(
769  mapping_collection,
770  fe_collection,
771  q_collection,
772  DerivativeDescription::update_flags | update_quadrature_points);
773 
774  // matrix Y=sum_i y_i y_i^T
775  Tensor<2, dim> Y;
776 
777 
778  // vector to hold iterators to all
779  // active neighbors of a cell
780  // reserve the maximal number of
781  // active neighbors
782  std::vector<TriaActiveIterator<
784  active_neighbors;
785 
786  active_neighbors.reserve(GeometryInfo<dim>::faces_per_cell *
788 
789  // vector
790  // g=sum_i y_i (f(x+y_i)-f(x))/|y_i|
791  // or related type for higher
792  // derivatives
793  typename DerivativeDescription::Derivative projected_derivative;
794 
795  // reinit fe values object...
796  x_fe_midpoint_value.reinit(cell);
797  const FEValues<dim> &fe_midpoint_value =
798  x_fe_midpoint_value.get_present_fe_values();
799 
800  // ...and get the value of the
801  // projected derivative...
802  const typename DerivativeDescription::ProjectedDerivative
803  this_midpoint_value =
804  DerivativeDescription::get_projected_derivative(fe_midpoint_value,
805  solution,
806  component);
807  // ...and the place where it lives
808  const Point<dim> this_center = fe_midpoint_value.quadrature_point(0);
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<DoFHandlerType<dim, spacedim>>(
823  cell, active_neighbors);
824 
825  // now loop over all active
826  // neighbors and collect the
827  // data we need
828  typename std::vector<TriaActiveIterator<
829  ::DoFCellAccessor<DoFHandlerType<dim, spacedim>, false>>>::
830  const_iterator neighbor_ptr = active_neighbors.begin();
831  for (; neighbor_ptr != active_neighbors.end(); ++neighbor_ptr)
832  {
833  const TriaActiveIterator<
834  ::DoFCellAccessor<DoFHandlerType<dim, spacedim>, false>>
835  neighbor = *neighbor_ptr;
836 
837  // reinit fe values object...
838  x_fe_midpoint_value.reinit(neighbor);
839  const FEValues<dim> &neighbor_fe_midpoint_value =
840  x_fe_midpoint_value.get_present_fe_values();
841 
842  // ...and get the value of the
843  // solution...
844  const typename DerivativeDescription::ProjectedDerivative
845  neighbor_midpoint_value =
846  DerivativeDescription::get_projected_derivative(
847  neighbor_fe_midpoint_value, solution, component);
848 
849  // ...and the place where it lives
850  const Point<dim> neighbor_center =
851  neighbor_fe_midpoint_value.quadrature_point(0);
852 
853 
854  // vector for the
855  // normalized
856  // direction between
857  // the centers of two
858  // cells
859  Tensor<1, dim> y = neighbor_center - this_center;
860  const double distance = y.norm();
861  // normalize y
862  y /= distance;
863  // *** note that unlike in
864  // the docs, y denotes the
865  // normalized vector
866  // connecting the centers
867  // of the two cells, rather
868  // than the normal
869  // difference! ***
870 
871  // add up the
872  // contribution of
873  // this cell to Y
874  for (unsigned int i = 0; i < dim; ++i)
875  for (unsigned int j = 0; j < dim; ++j)
876  Y[i][j] += y[i] * y[j];
877 
878  // then update the sum
879  // of difference
880  // quotients
881  typename DerivativeDescription::ProjectedDerivative
882  projected_finite_difference =
883  (neighbor_midpoint_value - this_midpoint_value);
884  projected_finite_difference /= distance;
885 
886  projected_derivative += outer_product(y, projected_finite_difference);
887  };
888 
889  // can we determine an
890  // approximation of the
891  // gradient for the present
892  // cell? if so, then we need to
893  // have passed over vectors y_i
894  // which span the whole space,
895  // otherwise we would not have
896  // all components of the
897  // gradient
899 
900  // compute Y^-1 g
901  const Tensor<2, dim> Y_inverse = invert(Y);
902 
903  derivative = Y_inverse * projected_derivative;
904 
905  // finally symmetrize the derivative
907  }
908 
909 
910 
916  template <class DerivativeDescription,
917  int dim,
918  template <int, int> class DoFHandlerType,
919  class InputVector,
920  int spacedim>
921  void
922  approximate(
923  SynchronousIterators<std::tuple<
925  ::DoFCellAccessor<DoFHandlerType<dim, spacedim>, false>>,
926  Vector<float>::iterator>> const & cell,
927  const Mapping<dim, spacedim> & mapping,
928  const DoFHandlerType<dim, spacedim> &dof_handler,
929  const InputVector & solution,
930  const unsigned int component)
931  {
932  // if the cell is not locally owned, then there is nothing to do
933  if (std::get<0>(*cell)->is_locally_owned() == false)
934  *std::get<1>(*cell) = 0;
935  else
936  {
937  typename DerivativeDescription::Derivative derivative;
938  // call the function doing the actual
939  // work on this cell
940  approximate_cell<DerivativeDescription,
941  dim,
942  DoFHandlerType,
943  InputVector,
944  spacedim>(mapping,
945  dof_handler,
946  solution,
947  component,
948  std::get<0>(*cell),
949  derivative);
950 
951  // evaluate the norm and fill the vector
952  //*derivative_norm_on_this_cell
953  *std::get<1>(*cell) =
954  DerivativeDescription::derivative_norm(derivative);
955  }
956  }
957 
958 
969  template <class DerivativeDescription,
970  int dim,
971  template <int, int> class DoFHandlerType,
972  class InputVector,
973  int spacedim>
974  void
975  approximate_derivative(const Mapping<dim, spacedim> & mapping,
976  const DoFHandlerType<dim, spacedim> &dof_handler,
977  const InputVector & solution,
978  const unsigned int component,
979  Vector<float> & derivative_norm)
980  {
981  Assert(derivative_norm.size() ==
982  dof_handler.get_triangulation().n_active_cells(),
984  derivative_norm.size(),
985  dof_handler.get_triangulation().n_active_cells()));
986  Assert(component < dof_handler.get_fe(0).n_components(),
987  ExcIndexRange(component, 0, dof_handler.get_fe(0).n_components()));
988 
989  using Iterators = std::tuple<
992  Vector<float>::iterator>;
994  Iterators(dof_handler.begin_active(), derivative_norm.begin())),
995  end(Iterators(dof_handler.end(), derivative_norm.end()));
996 
997  // There is no need for a copier because there is no conflict between
998  // threads to write in derivative_norm. Scratch and CopyData are also
999  // useless.
1001  begin,
1002  end,
1003  static_cast<std::function<void(SynchronousIterators<Iterators> const &,
1004  Assembler::Scratch const &,
1005  Assembler::CopyData &)>>(
1006  std::bind(&approximate<DerivativeDescription,
1007  dim,
1008  DoFHandlerType,
1009  InputVector,
1010  spacedim>,
1011  std::placeholders::_1,
1012  std::cref(mapping),
1013  std::cref(dof_handler),
1014  std::cref(solution),
1015  component)),
1016  std::function<void(internal::Assembler::CopyData const &)>(),
1017  internal::Assembler::Scratch(),
1018  internal::Assembler::CopyData());
1019  }
1020 
1021  } // namespace internal
1022 
1023 } // namespace DerivativeApproximation
1024 
1025 
1026 // ------------------------ finally for the public interface of this namespace
1027 
1028 namespace DerivativeApproximation
1029 {
1030  template <int dim,
1031  template <int, int> class DoFHandlerType,
1032  class InputVector,
1033  int spacedim>
1034  void
1036  const DoFHandlerType<dim, spacedim> &dof_handler,
1037  const InputVector & solution,
1038  Vector<float> & derivative_norm,
1039  const unsigned int component)
1040  {
1041  internal::approximate_derivative<internal::Gradient<dim>, dim>(
1042  mapping, dof_handler, solution, component, derivative_norm);
1043  }
1044 
1045 
1046  template <int dim,
1047  template <int, int> class DoFHandlerType,
1048  class InputVector,
1049  int spacedim>
1050  void
1051  approximate_gradient(const DoFHandlerType<dim, spacedim> &dof_handler,
1052  const InputVector & solution,
1053  Vector<float> & derivative_norm,
1054  const unsigned int component)
1055  {
1056  internal::approximate_derivative<internal::Gradient<dim>, dim>(
1058  dof_handler,
1059  solution,
1060  component,
1061  derivative_norm);
1062  }
1063 
1064 
1065  template <int dim,
1066  template <int, int> class DoFHandlerType,
1067  class InputVector,
1068  int spacedim>
1069  void
1071  const Mapping<dim, spacedim> & mapping,
1072  const DoFHandlerType<dim, spacedim> &dof_handler,
1073  const InputVector & solution,
1074  Vector<float> & derivative_norm,
1075  const unsigned int component)
1076  {
1077  internal::approximate_derivative<internal::SecondDerivative<dim>, dim>(
1078  mapping, dof_handler, solution, component, derivative_norm);
1079  }
1080 
1081 
1082  template <int dim,
1083  template <int, int> class DoFHandlerType,
1084  class InputVector,
1085  int spacedim>
1086  void
1088  const DoFHandlerType<dim, spacedim> &dof_handler,
1089  const InputVector & solution,
1090  Vector<float> & derivative_norm,
1091  const unsigned int component)
1092  {
1093  internal::approximate_derivative<internal::SecondDerivative<dim>, dim>(
1095  dof_handler,
1096  solution,
1097  component,
1098  derivative_norm);
1099  }
1100 
1101 
1102  template <typename DoFHandlerType, class InputVector, int order>
1103  void
1106  & mapping,
1107  const DoFHandlerType &dof,
1108  const InputVector & solution,
1109 #ifndef _MSC_VER
1110  const typename DoFHandlerType::active_cell_iterator &cell,
1111 #else
1113  &cell,
1114 #endif
1116  const unsigned int component)
1117  {
1118  internal::approximate_cell<
1119  typename internal::DerivativeSelector<order, DoFHandlerType::dimension>::
1120  DerivDescr>(mapping, dof, solution, component, cell, derivative);
1121  }
1122 
1123 
1124 
1125  template <typename DoFHandlerType, class InputVector, int order>
1126  void
1128  const DoFHandlerType &dof,
1129  const InputVector & solution,
1130 #ifndef _MSC_VER
1131  const typename DoFHandlerType::active_cell_iterator &cell,
1132 #else
1134  &cell,
1135 #endif
1137  const unsigned int component)
1138  {
1139  // just call the respective function with Q1 mapping
1141  StaticMappingQ1<DoFHandlerType::dimension,
1142  DoFHandlerType::space_dimension>::mapping,
1143  dof,
1144  solution,
1145  cell,
1146  derivative,
1147  component);
1148  }
1149 
1150 
1151 
1152  template <int dim, int order>
1153  double
1155  {
1156  return internal::DerivativeSelector<order, dim>::DerivDescr::
1157  derivative_norm(derivative);
1158  }
1159 
1160 } // namespace DerivativeApproximation
1161 
1162 
1163 // --------------------------- explicit instantiations ---------------------
1164 #include "derivative_approximation.inst"
1165 
1166 
1167 DEAL_II_NAMESPACE_CLOSE
void get_function_values(const InputVector &fe_function, std::vector< typename InputVector::value_type > &values) const
Definition: fe_values.cc:3657
Shape function values.
static::ExceptionBase & ExcInsufficientDirections()
Number determinant(const SymmetricTensor< 2, dim, Number > &)
static void symmetrize(Derivative &derivative_tensor)
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)
Number trace(const SymmetricTensor< 2, dim, Number > &d)
void get_function_gradients(const InputVector &fe_function, std::vector< Tensor< 1, spacedim, typename InputVector::value_type >> &gradients) const
Definition: fe_values.cc:3799
SymmetricTensor< 4, dim, Number > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
Transformed quadrature points.
numbers::NumberTraits< Number >::real_type norm() const
Definition: tensor.h:1301
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
static::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
static ProjectedDerivative get_projected_derivative(const FEValues< dim, spacedim > &fe_values, const InputVector &solution, const unsigned int component)
SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)
static const double PI
Definition: numbers.h:143
#define Assert(cond, exc)
Definition: exceptions.h:1227
UpdateFlags
Abstract base class for mapping classes.
Definition: dof_tools.h:57
const FiniteElement< dim, spacedim > & get_fe() const
static void symmetrize(Derivative &derivative_tensor)
SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)
static ProjectedDerivative get_projected_derivative(const FEValues< dim, spacedim > &fe_values, const InputVector &solution, const unsigned int component)
void reinit(const TriaIterator< DoFCellAccessor< DoFHandlerType, 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:142
Second derivatives of shape functions.
void approximate_derivative_tensor(const Mapping< DoFHandlerType::dimension, DoFHandlerType::space_dimension > &mapping, const DoFHandlerType &dof, const InputVector &solution, const typename DoFHandlerType::active_cell_iterator &cell, Tensor< order, DoFHandlerType::dimension > &derivative, const unsigned int component=0)
Shape function gradients.
Definition: fe.h:36
static::ExceptionBase & ExcNotImplemented()
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)
Definition: work_stream.h:1099
const ::FEValues< dim, spacedim > & get_present_fe_values() const
static double derivative_norm(const Derivative &d)
void approximate_second_derivative(const Mapping< dim, spacedim > &mapping, const DoFHandlerType< dim, spacedim > &dof, const InputVector &solution, Vector< float > &derivative_norm, const unsigned int component=0)
void approximate_gradient(const Mapping< dim, spacedim > &mapping, const DoFHandlerType< dim, spacedim > &dof, const InputVector &solution, Vector< float > &derivative_norm, const unsigned int component=0)
const Point< spacedim > & quadrature_point(const unsigned int q) const
static::ExceptionBase & ExcInternalError()
static::ExceptionBase & ExcVectorLengthVsNActiveCells(int arg1, int arg2)
void get_function_hessians(const InputVector &fe_function, std::vector< Tensor< 2, spacedim, typename InputVector::value_type >> &hessians) const
Definition: fe_values.cc:3913