Reference documentation for deal.II version 9.1.0-pre
fe_evaluation.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2011 - 2018 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 
17 #ifndef dealii_matrix_free_fe_evaluation_h
18 #define dealii_matrix_free_fe_evaluation_h
19 
20 
21 #include <deal.II/base/config.h>
22 
23 #include <deal.II/base/array_view.h>
24 #include <deal.II/base/exceptions.h>
25 #include <deal.II/base/smartpointer.h>
27 #include <deal.II/base/template_constraints.h>
28 #include <deal.II/base/vectorization.h>
29 
30 #include <deal.II/lac/vector_operation.h>
31 
32 #include <deal.II/matrix_free/evaluation_kernels.h>
33 #include <deal.II/matrix_free/evaluation_selector.h>
34 #include <deal.II/matrix_free/mapping_data_on_the_fly.h>
35 #include <deal.II/matrix_free/matrix_free.h>
36 #include <deal.II/matrix_free/shape_info.h>
37 #include <deal.II/matrix_free/tensor_product_kernels.h>
38 
39 DEAL_II_NAMESPACE_OPEN
40 
41 
42 
43 // forward declarations
44 namespace LinearAlgebra
45 {
46  namespace distributed
47  {
48  template <typename>
49  class Vector;
50  }
51 } // namespace LinearAlgebra
52 namespace internal
53 {
55 }
56 
57 template <int dim,
58  int fe_degree,
59  int n_q_points_1d = fe_degree + 1,
60  int n_components_ = 1,
61  typename Number = double>
63 
64 
90 template <int dim, int n_components_, typename Number, bool is_face = false>
92 {
93 public:
94  using number_type = Number;
96  using gradient_type =
98  static constexpr unsigned int dimension = dim;
99  static constexpr unsigned int n_components = n_components_;
100 
108  ~FEEvaluationBase();
109 
113  DEAL_II_DEPRECATED
114  unsigned int
115  get_cell_data_number() const;
116 
125  unsigned int
126  get_mapping_data_index_offset() const;
127 
135  get_cell_type() const;
136 
141  get_shape_info() const;
142 
144 
181  template <typename VectorType>
182  void
183  read_dof_values(const VectorType &src, const unsigned int first_index = 0);
184 
213  template <typename VectorType>
214  void
215  read_dof_values_plain(const VectorType & src,
216  const unsigned int first_index = 0);
217 
241  template <typename VectorType>
242  void
243  distribute_local_to_global(VectorType & dst,
244  const unsigned int first_index = 0) const;
245 
272  template <typename VectorType>
273  void
274  set_dof_values(VectorType &dst, const unsigned int first_index = 0) const;
275 
277 
298  value_type
299  get_dof_value(const unsigned int dof) const;
300 
311  void
312  submit_dof_value(const value_type val_in, const unsigned int dof);
313 
325  value_type
326  get_value(const unsigned int q_point) const;
327 
339  void
340  submit_value(const value_type val_in, const unsigned int q_point);
341 
352  get_gradient(const unsigned int q_point) const;
353 
367  value_type
368  get_normal_derivative(const unsigned int q_point) const;
369 
382  void
383  submit_gradient(const gradient_type grad_in, const unsigned int q_point);
384 
402  void
403  submit_normal_derivative(const value_type grad_in,
404  const unsigned int q_point);
405 
417  get_hessian(const unsigned int q_point) const;
418 
428  get_hessian_diagonal(const unsigned int q_point) const;
429 
440  value_type
441  get_laplacian(const unsigned int q_point) const;
442 
443 #ifdef DOXYGEN
444  // doxygen does not anyhow mention functions coming from partial template
445  // specialization of the base class, in this case FEEvaluationAccess<dim,dim>.
446  // For now, hack-in those functions manually only to fix documentation:
447 
452  get_divergence(const unsigned int q_point) const;
453 
458  get_symmetric_gradient(const unsigned int q_point) const;
459 
464  get_curl(const unsigned int q_point) const;
465 
474  void
475  submit_divergence(const VectorizedArray<Number> div_in,
476  const unsigned int q_point);
477 
487  void
488  submit_symmetric_gradient(
489  const SymmetricTensor<2, dim, VectorizedArray<Number>> grad_in,
490  const unsigned int q_point);
491 
501  void
502  submit_curl(
503  const Tensor<1, dim == 2 ? 1 : dim, VectorizedArray<Number>> curl_in,
504  const unsigned int q_point);
505 
506 #endif
507 
524  value_type
525  integrate_value() const;
526 
532  JxW(const unsigned int q_index) const;
533 
537  void
538  fill_JxW_values(AlignedVector<VectorizedArray<Number>> &JxW_values) const;
539 
547  inverse_jacobian(const unsigned int q_index) const;
548 
562  get_normal_vector(const unsigned int q_point) const;
563 
571  read_cell_data(const AlignedVector<VectorizedArray<Number>> &array) const;
572 
574 
588  begin_dof_values() const;
589 
599  begin_dof_values();
600 
612  begin_values() const;
613 
625  begin_values();
626 
639  begin_gradients() const;
640 
653  begin_gradients();
654 
668  begin_hessians() const;
669 
683  begin_hessians();
684 
690  const std::vector<unsigned int> &
691  get_internal_dof_numbering() const;
692 
700  get_scratch_data() const;
701 
703 
704 protected:
713  FEEvaluationBase(const MatrixFree<dim, Number> &matrix_free,
714  const unsigned int dof_no,
715  const unsigned int first_selected_component,
716  const unsigned int quad_no,
717  const unsigned int fe_degree,
718  const unsigned int n_q_points,
719  const bool is_interior_face);
720 
755  template <int n_components_other>
757  const Mapping<dim> & mapping,
758  const FiniteElement<dim> &fe,
759  const Quadrature<1> & quadrature,
760  const UpdateFlags update_flags,
761  const unsigned int first_selected_component,
763 
770  FEEvaluationBase(const FEEvaluationBase &other);
771 
778  FEEvaluationBase &
779  operator=(const FEEvaluationBase &other);
780 
787  template <typename VectorType, typename VectorOperation>
788  void
789  read_write_operation(const VectorOperation &operation,
790  VectorType * vectors[],
791  const bool apply_constraints = true) const;
792 
800  template <typename VectorType, typename VectorOperation>
801  void
802  read_write_operation_contiguous(const VectorOperation &operation,
803  VectorType * vectors[]) const;
804 
812  template <typename VectorType, typename VectorOperation>
813  void
814  read_write_operation_global(const VectorOperation &operation,
815  VectorType * vectors[]) const;
816 
821 
828 
841  VectorizedArray<Number> *values_dofs[n_components];
842 
854  VectorizedArray<Number> *values_quad[n_components];
855 
869  VectorizedArray<Number> *gradients_quad[n_components][dim];
870 
882  VectorizedArray<Number> *hessians_quad[n_components][(dim * (dim + 1)) / 2];
883 
887  const unsigned int quad_no;
888 
893  const unsigned int n_fe_components;
894 
899  const unsigned int active_fe_index;
900 
905  const unsigned int active_quad_index;
906 
910  const unsigned int n_quadrature_points;
911 
916 
923 
931  MappingInfoStorage<(is_face ? dim - 1 : dim), dim, Number> *mapping_data;
932 
940 
946 
954 
959 
964 
968  const Number *quadrature_weights;
969 
974  unsigned int cell;
975 
981 
987 
992  unsigned int face_no;
993 
998  unsigned int face_orientation;
999 
1007  unsigned int subface_index;
1008 
1016 
1023 
1030 
1037 
1044 
1051 
1058 
1063  std::shared_ptr<
1066 
1071  const unsigned int first_selected_component;
1072 
1077  mutable std::vector<types::global_dof_index> local_dof_indices;
1078 
1079 private:
1084  void
1085  set_data_pointers();
1086 
1090  template <int, int, typename, bool>
1091  friend class FEEvaluationBase;
1092  template <int, int, int, int, typename>
1093  friend class FEEvaluation;
1094 };
1095 
1096 
1097 
1107 template <int dim, int n_components_, typename Number, bool is_face>
1109  : public FEEvaluationBase<dim, n_components_, Number, is_face>
1110 {
1111 public:
1112  using number_type = Number;
1114  using gradient_type =
1116  static constexpr unsigned int dimension = dim;
1117  static constexpr unsigned int n_components = n_components_;
1119 
1120 protected:
1128  FEEvaluationAccess(const MatrixFree<dim, Number> &matrix_free,
1129  const unsigned int dof_no,
1130  const unsigned int first_selected_component,
1131  const unsigned int quad_no,
1132  const unsigned int fe_degree,
1133  const unsigned int n_q_points,
1134  const bool is_interior_face = true);
1135 
1140  template <int n_components_other>
1142  const Mapping<dim> & mapping,
1143  const FiniteElement<dim> &fe,
1144  const Quadrature<1> & quadrature,
1145  const UpdateFlags update_flags,
1146  const unsigned int first_selected_component,
1148 
1152  FEEvaluationAccess(const FEEvaluationAccess &other);
1153 
1157  FEEvaluationAccess &
1158  operator=(const FEEvaluationAccess &other);
1159 };
1160 
1161 
1162 
1173 template <int dim, typename Number, bool is_face>
1174 class FEEvaluationAccess<dim, 1, Number, is_face>
1175  : public FEEvaluationBase<dim, 1, Number, is_face>
1176 {
1177 public:
1178  using number_type = Number;
1181  static constexpr unsigned int dimension = dim;
1183 
1186  value_type
1187  get_dof_value(const unsigned int dof) const;
1188 
1191  void
1192  submit_dof_value(const value_type val_in, const unsigned int dof);
1193 
1196  value_type
1197  get_value(const unsigned int q_point) const;
1198 
1201  void
1202  submit_value(const value_type val_in, const unsigned int q_point);
1203 
1206  void
1207  submit_value(const Tensor<1, 1, VectorizedArray<Number>> val_in,
1208  const unsigned int q_point);
1209 
1213  get_gradient(const unsigned int q_point) const;
1214 
1217  value_type
1218  get_normal_derivative(const unsigned int q_point) const;
1219 
1222  void
1223  submit_gradient(const gradient_type grad_in, const unsigned int q_point);
1224 
1227  void
1228  submit_normal_derivative(const value_type grad_in,
1229  const unsigned int q_point);
1230 
1234  get_hessian(unsigned int q_point) const;
1235 
1239  get_hessian_diagonal(const unsigned int q_point) const;
1240 
1243  value_type
1244  get_laplacian(const unsigned int q_point) const;
1245 
1248  value_type
1249  integrate_value() const;
1250 
1251 protected:
1259  FEEvaluationAccess(const MatrixFree<dim, Number> &matrix_free,
1260  const unsigned int dof_no,
1261  const unsigned int first_selected_component,
1262  const unsigned int quad_no,
1263  const unsigned int fe_degree,
1264  const unsigned int n_q_points,
1265  const bool is_interior_face = true);
1266 
1271  template <int n_components_other>
1273  const Mapping<dim> & mapping,
1274  const FiniteElement<dim> &fe,
1275  const Quadrature<1> & quadrature,
1276  const UpdateFlags update_flags,
1277  const unsigned int first_selected_component,
1279 
1283  FEEvaluationAccess(const FEEvaluationAccess &other);
1284 
1288  FEEvaluationAccess &
1289  operator=(const FEEvaluationAccess &other);
1290 };
1291 
1292 
1293 
1305 template <int dim, typename Number, bool is_face>
1306 class FEEvaluationAccess<dim, dim, Number, is_face>
1307  : public FEEvaluationBase<dim, dim, Number, is_face>
1308 {
1309 public:
1310  using number_type = Number;
1313  static constexpr unsigned int dimension = dim;
1314  static constexpr unsigned int n_components = dim;
1316 
1320  get_gradient(const unsigned int q_point) const;
1321 
1327  get_divergence(const unsigned int q_point) const;
1328 
1336  get_symmetric_gradient(const unsigned int q_point) const;
1337 
1343  get_curl(const unsigned int q_point) const;
1344 
1348  get_hessian(const unsigned int q_point) const;
1349 
1353  get_hessian_diagonal(const unsigned int q_point) const;
1354 
1357  void
1358  submit_gradient(const gradient_type grad_in, const unsigned int q_point);
1359 
1368  void
1369  submit_gradient(
1370  const Tensor<1, dim, Tensor<1, dim, VectorizedArray<Number>>> grad_in,
1371  const unsigned int q_point);
1372 
1381  void
1382  submit_divergence(const VectorizedArray<Number> div_in,
1383  const unsigned int q_point);
1384 
1393  void
1394  submit_symmetric_gradient(
1395  const SymmetricTensor<2, dim, VectorizedArray<Number>> grad_in,
1396  const unsigned int q_point);
1397 
1402  void
1403  submit_curl(
1404  const Tensor<1, dim == 2 ? 1 : dim, VectorizedArray<Number>> curl_in,
1405  const unsigned int q_point);
1406 
1407 protected:
1415  FEEvaluationAccess(const MatrixFree<dim, Number> &matrix_free,
1416  const unsigned int dof_no,
1417  const unsigned int first_selected_component,
1418  const unsigned int quad_no,
1419  const unsigned int dofs_per_cell,
1420  const unsigned int n_q_points,
1421  const bool is_interior_face = true);
1422 
1427  template <int n_components_other>
1429  const Mapping<dim> & mapping,
1430  const FiniteElement<dim> &fe,
1431  const Quadrature<1> & quadrature,
1432  const UpdateFlags update_flags,
1433  const unsigned int first_selected_component,
1435 
1439  FEEvaluationAccess(const FEEvaluationAccess &other);
1440 
1444  FEEvaluationAccess &
1445  operator=(const FEEvaluationAccess &other);
1446 };
1447 
1448 
1460 template <typename Number, bool is_face>
1461 class FEEvaluationAccess<1, 1, Number, is_face>
1462  : public FEEvaluationBase<1, 1, Number, is_face>
1463 {
1464 public:
1465  using number_type = Number;
1468  static constexpr unsigned int dimension = 1;
1470 
1473  value_type
1474  get_dof_value(const unsigned int dof) const;
1475 
1478  void
1479  submit_dof_value(const value_type val_in, const unsigned int dof);
1480 
1483  value_type
1484  get_value(const unsigned int q_point) const;
1485 
1488  void
1489  submit_value(const value_type val_in, const unsigned int q_point);
1490 
1493  void
1494  submit_value(const gradient_type val_in, const unsigned int q_point);
1495 
1499  get_gradient(const unsigned int q_point) const;
1500 
1503  value_type
1504  get_normal_derivative(const unsigned int q_point) const;
1505 
1508  void
1509  submit_gradient(const gradient_type grad_in, const unsigned int q_point);
1510 
1513  void
1514  submit_gradient(const value_type grad_in, const unsigned int q_point);
1515 
1518  void
1519  submit_normal_derivative(const value_type grad_in,
1520  const unsigned int q_point);
1521 
1524  void
1525  submit_normal_derivative(const gradient_type grad_in,
1526  const unsigned int q_point);
1527 
1531  get_hessian(unsigned int q_point) const;
1532 
1536  get_hessian_diagonal(const unsigned int q_point) const;
1537 
1540  value_type
1541  get_laplacian(const unsigned int q_point) const;
1542 
1545  value_type
1546  integrate_value() const;
1547 
1548 protected:
1556  FEEvaluationAccess(const MatrixFree<1, Number> &matrix_free,
1557  const unsigned int dof_no,
1558  const unsigned int first_selected_component,
1559  const unsigned int quad_no,
1560  const unsigned int fe_degree,
1561  const unsigned int n_q_points,
1562  const bool is_interior_face = true);
1563 
1568  template <int n_components_other>
1570  const Mapping<1> & mapping,
1571  const FiniteElement<1> &fe,
1572  const Quadrature<1> & quadrature,
1573  const UpdateFlags update_flags,
1574  const unsigned int first_selected_component,
1576 
1580  FEEvaluationAccess(const FEEvaluationAccess &other);
1581 
1585  FEEvaluationAccess &
1586  operator=(const FEEvaluationAccess &other);
1587 };
1588 
1589 
1590 
2140 template <int dim,
2141  int fe_degree,
2142  int n_q_points_1d,
2143  int n_components_,
2144  typename Number>
2145 class FEEvaluation
2146  : public FEEvaluationAccess<dim, n_components_, Number, false>
2147 {
2148 public:
2153 
2157  using number_type = Number;
2158 
2165 
2172 
2176  static constexpr unsigned int dimension = dim;
2177 
2182  static constexpr unsigned int n_components = n_components_;
2183 
2190  static constexpr unsigned int static_n_q_points =
2191  Utilities::pow(n_q_points_1d, dim);
2192 
2200  static constexpr unsigned int static_dofs_per_component =
2201  Utilities::pow(fe_degree + 1, dim);
2202 
2210  static constexpr unsigned int tensor_dofs_per_cell =
2211  static_dofs_per_component * n_components;
2212 
2220  static constexpr unsigned int static_dofs_per_cell =
2221  static_dofs_per_component * n_components;
2222 
2248  FEEvaluation(const MatrixFree<dim, Number> &matrix_free,
2249  const unsigned int dof_no = 0,
2250  const unsigned int quad_no = 0,
2251  const unsigned int first_selected_component = 0);
2252 
2279  FEEvaluation(const Mapping<dim> & mapping,
2280  const FiniteElement<dim> &fe,
2281  const Quadrature<1> & quadrature,
2282  const UpdateFlags update_flags,
2283  const unsigned int first_selected_component = 0);
2284 
2290  FEEvaluation(const FiniteElement<dim> &fe,
2291  const Quadrature<1> & quadrature,
2292  const UpdateFlags update_flags,
2293  const unsigned int first_selected_component = 0);
2294 
2305  template <int n_components_other>
2306  FEEvaluation(const FiniteElement<dim> & fe,
2308  const unsigned int first_selected_component = 0);
2309 
2316  FEEvaluation(const FEEvaluation &other);
2317 
2324  FEEvaluation &
2325  operator=(const FEEvaluation &other);
2326 
2335  void
2336  reinit(const unsigned int cell_batch_index);
2337 
2350  template <typename DoFHandlerType, bool level_dof_access>
2351  void
2353  &cell);
2354 
2365  void
2366  reinit(const typename Triangulation<dim>::cell_iterator &cell);
2367 
2377  void
2378  evaluate(const bool evaluate_values,
2379  const bool evaluate_gradients,
2380  const bool evaluate_hessians = false);
2381 
2394  void
2395  evaluate(const VectorizedArray<Number> *values_array,
2396  const bool evaluate_values,
2397  const bool evaluate_gradients,
2398  const bool evaluate_hessians = false);
2399 
2413  template <typename VectorType>
2414  void
2415  gather_evaluate(const VectorType &input_vector,
2416  const bool evaluate_values,
2417  const bool evaluate_gradients,
2418  const bool evaluate_hessians = false);
2419 
2430  void
2431  integrate(const bool integrate_values, const bool integrate_gradients);
2432 
2444  void
2445  integrate(const bool integrate_values,
2446  const bool integrate_gradients,
2447  VectorizedArray<Number> *values_array);
2448 
2462  template <typename VectorType>
2463  void
2464  integrate_scatter(const bool integrate_values,
2465  const bool integrate_gradients,
2466  VectorType &output_vector);
2467 
2473  quadrature_point(const unsigned int q_point) const;
2474 
2481  const unsigned int dofs_per_component;
2482 
2489  const unsigned int dofs_per_cell;
2490 
2498  const unsigned int n_q_points;
2499 
2500 private:
2505  void
2506  check_template_arguments(const unsigned int fe_no,
2507  const unsigned int first_selected_component);
2508 };
2509 
2510 
2511 
2543 template <int dim,
2544  int fe_degree,
2545  int n_q_points_1d = fe_degree + 1,
2546  int n_components_ = 1,
2547  typename Number = double>
2549  : public FEEvaluationAccess<dim, n_components_, Number, true>
2550 {
2551 public:
2556 
2560  using number_type = Number;
2561 
2568 
2575 
2579  static constexpr unsigned int dimension = dim;
2580 
2585  static constexpr unsigned int n_components = n_components_;
2586 
2594  static constexpr unsigned int static_n_q_points =
2595  Utilities::pow(n_q_points_1d, dim - 1);
2596 
2603  static constexpr unsigned int static_n_q_points_cell =
2604  Utilities::pow(n_q_points_1d, dim);
2605 
2612  static constexpr unsigned int static_dofs_per_component =
2613  Utilities::pow(fe_degree + 1, dim);
2614 
2621  static constexpr unsigned int tensor_dofs_per_cell =
2622  static_dofs_per_component * n_components;
2623 
2630  static constexpr unsigned int static_dofs_per_cell =
2631  static_dofs_per_component * n_components;
2632 
2662  FEFaceEvaluation(const MatrixFree<dim, Number> &matrix_free,
2663  const bool is_interior_face = true,
2664  const unsigned int dof_no = 0,
2665  const unsigned int quad_no = 0,
2666  const unsigned int first_selected_component = 0);
2667 
2671  ~FEFaceEvaluation();
2672 
2683  void
2684  reinit(const unsigned int face_batch_number);
2685 
2693  void
2694  reinit(const unsigned int cell_batch_number, const unsigned int face_number);
2695 
2706  void
2707  evaluate(const bool evaluate_values, const bool evaluate_gradients);
2708 
2721  void
2722  evaluate(const VectorizedArray<Number> *values_array,
2723  const bool evaluate_values,
2724  const bool evaluate_gradients);
2725 
2737  template <typename VectorType>
2738  void
2739  gather_evaluate(const VectorType &input_vector,
2740  const bool evaluate_values,
2741  const bool evaluate_gradients);
2742 
2752  void
2753  integrate(const bool integrate_values, const bool integrate_gradients);
2754 
2763  void
2764  integrate(const bool integrate_values,
2765  const bool integrate_gradients,
2766  VectorizedArray<Number> *values_array);
2767 
2779  template <typename VectorType>
2780  void
2781  integrate_scatter(const bool integrate_values,
2782  const bool integrate_gradients,
2783  VectorType &output_vector);
2784 
2790  quadrature_point(const unsigned int q_point) const;
2791 
2798  const unsigned int dofs_per_component;
2799 
2806  const unsigned int dofs_per_cell;
2807 
2815  const unsigned int n_q_points;
2816 
2817 protected:
2823  void
2824  adjust_for_face_orientation(const bool integrate,
2825  const bool values,
2826  const bool gradients);
2827 };
2828 
2829 
2830 
2831 namespace internal
2832 {
2833  namespace MatrixFreeFunctions
2834  {
2835  // a helper function to compute the number of DoFs of a DGP element at
2836  // compile time, depending on the degree
2837  template <int dim, int degree>
2838  struct DGP_dofs_per_component
2839  {
2840  // this division is always without remainder
2841  static constexpr unsigned int value =
2842  (DGP_dofs_per_component<dim - 1, degree>::value * (degree + dim)) / dim;
2843  };
2844 
2845  // base specialization: 1d elements have 'degree+1' degrees of freedom
2846  template <int degree>
2847  struct DGP_dofs_per_component<1, degree>
2848  {
2849  static constexpr unsigned int value = degree + 1;
2850  };
2851  } // namespace MatrixFreeFunctions
2852 } // namespace internal
2853 
2854 
2855 /*----------------------- Inline functions ----------------------------------*/
2856 
2857 #ifndef DOXYGEN
2858 
2859 
2860 
2861 /*----------------------- FEEvaluationBase ----------------------------------*/
2862 
2863 template <int dim, int n_components_, typename Number, bool is_face>
2865  const MatrixFree<dim, Number> &data_in,
2866  const unsigned int dof_no,
2867  const unsigned int first_selected_component,
2868  const unsigned int quad_no_in,
2869  const unsigned int fe_degree,
2870  const unsigned int n_q_points,
2871  const bool is_interior_face)
2872  : scratch_data_array(data_in.acquire_scratch_data())
2873  , quad_no(quad_no_in)
2874  , n_fe_components(data_in.get_dof_info(dof_no).start_components.back())
2875  , active_fe_index(fe_degree != numbers::invalid_unsigned_int ?
2876  data_in.get_dof_info(dof_no).fe_index_from_degree(
2877  first_selected_component,
2878  fe_degree) :
2879  0)
2880  , active_quad_index(fe_degree != numbers::invalid_unsigned_int ?
2881  (is_face ? data_in.get_mapping_info()
2882  .face_data[quad_no_in]
2883  .quad_index_from_n_q_points(n_q_points) :
2884  data_in.get_mapping_info()
2885  .cell_data[quad_no_in]
2886  .quad_index_from_n_q_points(n_q_points)) :
2887  0)
2888  , n_quadrature_points(fe_degree != numbers::invalid_unsigned_int ?
2889  n_q_points :
2890  (is_face ? data_in
2891  .get_shape_info(dof_no,
2892  quad_no_in,
2893  active_fe_index,
2894  active_quad_index)
2895  .n_q_points_face :
2896  data_in
2897  .get_shape_info(dof_no,
2898  quad_no_in,
2899  active_fe_index,
2900  active_quad_index)
2901  .n_q_points))
2902  , matrix_info(&data_in)
2903  , dof_info(&data_in.get_dof_info(dof_no))
2904  , mapping_data(internal::MatrixFreeFunctions::
2905  MappingInfoCellsOrFaces<dim, Number, is_face>::get(
2906  data_in.get_mapping_info(),
2907  quad_no))
2908  , data(&data_in.get_shape_info(
2909  dof_no,
2910  quad_no_in,
2911  dof_info->component_to_base_index[first_selected_component],
2912  active_fe_index,
2913  active_quad_index))
2914  , jacobian(nullptr)
2915  , J_value(nullptr)
2916  , normal_vectors(nullptr)
2917  , normal_x_jacobian(nullptr)
2918  , quadrature_weights(
2919  mapping_data->descriptor[active_quad_index].quadrature_weights.begin())
2920  , cell(numbers::invalid_unsigned_int)
2921  , is_interior_face(is_interior_face)
2922  , dof_access_index(
2923  is_face ?
2924  (is_interior_face ?
2925  internal::MatrixFreeFunctions::DoFInfo::dof_access_face_interior :
2926  internal::MatrixFreeFunctions::DoFInfo::dof_access_face_exterior) :
2927  internal::MatrixFreeFunctions::DoFInfo::dof_access_cell)
2928  , cell_type(internal::MatrixFreeFunctions::general)
2929  , dof_values_initialized(false)
2930  , values_quad_initialized(false)
2931  , gradients_quad_initialized(false)
2932  , hessians_quad_initialized(false)
2933  , values_quad_submitted(false)
2934  , gradients_quad_submitted(false)
2935  , first_selected_component(first_selected_component)
2936 {
2938  Assert(matrix_info->mapping_initialized() == true, ExcNotInitialized());
2941  AssertDimension((is_face ? data->n_q_points_face : data->n_q_points),
2945  Assert(
2946  dof_info->start_components.back() == 1 ||
2947  (int)n_components_ <=
2948  (int)dof_info->start_components
2951  ExcMessage(
2952  "You tried to construct a vector-valued evaluator with " +
2954  " components. However, "
2955  "the current base element has only " +
2957  dof_info->start_components
2958  [dof_info->component_to_base_index[first_selected_component] + 1] -
2959  first_selected_component) +
2960  " components left when starting from local element index " +
2962  first_selected_component -
2963  dof_info->start_components
2964  [dof_info->component_to_base_index[first_selected_component]]) +
2965  " (global index " + Utilities::to_string(first_selected_component) +
2966  ")"));
2967 
2968  // do not check for correct dimensions of data fields here, should be done
2969  // in derived classes
2970 }
2971 
2972 
2973 
2974 template <int dim, int n_components_, typename Number, bool is_face>
2975 template <int n_components_other>
2977  const Mapping<dim> & mapping,
2978  const FiniteElement<dim> &fe,
2979  const Quadrature<1> & quadrature,
2980  const UpdateFlags update_flags,
2981  const unsigned int first_selected_component,
2984  , quad_no(numbers::invalid_unsigned_int)
2985  , n_fe_components(n_components_)
2986  , active_fe_index(numbers::invalid_unsigned_int)
2987  , active_quad_index(numbers::invalid_unsigned_int)
2989  Utilities::fixed_power < is_face ? dim - 1 : dim > (quadrature.size()))
2990  , matrix_info(nullptr)
2991  , dof_info(nullptr)
2992  , mapping_data(nullptr)
2993  ,
2994  // select the correct base element from the given FE component
2995  data(new internal::MatrixFreeFunctions::ShapeInfo<VectorizedArray<Number>>(
2996  quadrature,
2997  fe,
2998  fe.component_to_base_index(first_selected_component).first))
2999  , jacobian(nullptr)
3000  , J_value(nullptr)
3001  , normal_vectors(nullptr)
3002  , normal_x_jacobian(nullptr)
3003  , quadrature_weights(nullptr)
3004  , cell(0)
3005  , cell_type(internal::MatrixFreeFunctions::general)
3006  , is_interior_face(true)
3007  , dof_access_index(internal::MatrixFreeFunctions::DoFInfo::dof_access_cell)
3008  , dof_values_initialized(false)
3009  , values_quad_initialized(false)
3011  , hessians_quad_initialized(false)
3012  , values_quad_submitted(false)
3013  , gradients_quad_submitted(false)
3014  ,
3015  // keep the number of the selected component within the current base element
3016  // for reading dof values
3017  first_selected_component(first_selected_component)
3018 {
3020 
3021  Assert(other == nullptr || other->mapped_geometry.get() != nullptr,
3022  ExcInternalError());
3023  if (other != nullptr &&
3024  other->mapped_geometry->get_quadrature() == quadrature)
3026  else
3027  mapped_geometry = std::make_shared<
3029  mapping, quadrature, update_flags);
3030  cell = 0;
3031 
3032  mapping_data = &mapped_geometry->get_data_storage();
3033  jacobian = mapped_geometry->get_data_storage().jacobians[0].begin();
3034  J_value = mapped_geometry->get_data_storage().JxW_values.begin();
3035 
3036  const unsigned int base_element_number =
3037  fe.component_to_base_index(first_selected_component).first;
3038  Assert(fe.element_multiplicity(base_element_number) == 1 ||
3039  fe.element_multiplicity(base_element_number) -
3040  first_selected_component >=
3041  n_components_,
3042  ExcMessage("The underlying element must at least contain as many "
3043  "components as requested by this class"));
3044  (void)base_element_number;
3045 }
3046 
3047 
3048 
3049 template <int dim, int n_components_, typename Number, bool is_face>
3052  : scratch_data_array(other.matrix_info == nullptr ?
3053  new AlignedVector<VectorizedArray<Number>>() :
3054  other.matrix_info->acquire_scratch_data())
3055  , quad_no(other.quad_no)
3060  , matrix_info(other.matrix_info)
3061  , dof_info(other.dof_info)
3062  , mapping_data(other.mapping_data)
3063  , data(
3064  other.matrix_info == nullptr ?
3065  new internal::MatrixFreeFunctions::ShapeInfo<VectorizedArray<Number>>(
3066  *other.data) :
3067  other.data)
3068  , jacobian(nullptr)
3069  , J_value(nullptr)
3070  , normal_vectors(nullptr)
3071  , normal_x_jacobian(nullptr)
3073  other.matrix_info == nullptr ?
3074  nullptr :
3075  mapping_data->descriptor[active_quad_index].quadrature_weights.begin())
3076  , cell(numbers::invalid_unsigned_int)
3077  , cell_type(internal::MatrixFreeFunctions::general)
3078  , is_interior_face(other.is_interior_face)
3080  , dof_values_initialized(false)
3081  , values_quad_initialized(false)
3083  , hessians_quad_initialized(false)
3084  , values_quad_submitted(false)
3085  , gradients_quad_submitted(false)
3086  , first_selected_component(other.first_selected_component)
3087 {
3089 
3090  // Create deep copy of mapped geometry for use in parallel...
3091  if (other.mapped_geometry.get() != nullptr)
3092  {
3093  mapped_geometry.reset(
3095  other.mapped_geometry->get_fe_values().get_mapping(),
3096  other.mapped_geometry->get_quadrature(),
3097  other.mapped_geometry->get_fe_values().get_update_flags()));
3098  mapping_data = &mapped_geometry->get_data_storage();
3099  cell = 0;
3100 
3101  jacobian = mapped_geometry->get_data_storage().jacobians[0].begin();
3102  J_value = mapped_geometry->get_data_storage().JxW_values.begin();
3103  }
3104 }
3105 
3106 
3107 
3108 template <int dim, int n_components_, typename Number, bool is_face>
3112 {
3117  AssertDimension(first_selected_component, other.first_selected_component);
3118 
3119  // release old memory
3120  if (matrix_info == nullptr)
3121  {
3122  delete data;
3123  delete scratch_data_array;
3124  }
3125  else
3126  {
3128  }
3129 
3130  matrix_info = other.matrix_info;
3131  dof_info = other.dof_info;
3132  mapping_data = other.mapping_data;
3133  if (other.matrix_info == nullptr)
3134  {
3135  data =
3137  *other.data);
3139  }
3140  else
3141  {
3142  data = other.data;
3143  scratch_data_array = matrix_info->acquire_scratch_data();
3144  }
3146 
3148  (mapping_data != nullptr ?
3149  mapping_data->descriptor[active_quad_index].quadrature_weights.begin() :
3150  nullptr);
3153  is_interior_face = other.is_interior_face;
3155 
3156  // Create deep copy of mapped geometry for use in parallel...
3157  if (other.mapped_geometry.get() != nullptr)
3158  {
3159  mapped_geometry.reset(
3161  other.mapped_geometry->get_fe_values().get_mapping(),
3162  other.mapped_geometry->get_quadrature(),
3163  other.mapped_geometry->get_fe_values().get_update_flags()));
3164  cell = 0;
3165  mapping_data = &mapped_geometry->get_data_storage();
3166  jacobian = mapped_geometry->get_data_storage().jacobians[0].begin();
3167  J_value = mapped_geometry->get_data_storage().JxW_values.begin();
3168  }
3169 
3170  return *this;
3171 }
3172 
3173 
3174 
3175 template <int dim, int n_components_, typename Number, bool is_face>
3178 {
3179  if (matrix_info != nullptr)
3180  {
3181  try
3182  {
3184  }
3185  catch (...)
3186  {}
3187  }
3188  else
3189  {
3190  delete scratch_data_array;
3191  delete data;
3192  data = nullptr;
3193  }
3194  scratch_data_array = nullptr;
3195 }
3196 
3197 
3198 
3199 template <int dim, int n_components_, typename Number, bool is_face>
3200 inline void
3202 {
3204 
3205  const unsigned int tensor_dofs_per_component =
3206  Utilities::fixed_power<dim>(this->data->fe_degree + 1);
3207  const unsigned int dofs_per_component =
3208  this->data->dofs_per_component_on_cell;
3209  const unsigned int n_quadrature_points =
3210  is_face ? this->data->n_q_points_face : this->data->n_q_points;
3211 
3212  const unsigned int shift =
3213  std::max(tensor_dofs_per_component + 1, dofs_per_component) *
3214  n_components_ * 3 +
3215  2 * n_quadrature_points;
3216  const unsigned int allocated_size =
3217  shift + n_components_ * dofs_per_component +
3218  (n_components_ * (dim * dim + 2 * dim + 1) * n_quadrature_points);
3219  scratch_data_array->resize_fast(allocated_size);
3220 
3221  // set the pointers to the correct position in the data array
3222  for (unsigned int c = 0; c < n_components_; ++c)
3223  {
3224  this->values_dofs[c] =
3226  this->values_quad[c] = scratch_data_array->begin() +
3227  n_components * dofs_per_component +
3228  c * n_quadrature_points;
3229  for (unsigned int d = 0; d < dim; ++d)
3230  this->gradients_quad[c][d] =
3232  n_components * (dofs_per_component + n_quadrature_points) +
3233  (c * dim + d) * n_quadrature_points;
3234  for (unsigned int d = 0; d < (dim * dim + dim) / 2; ++d)
3235  this->hessians_quad[c][d] =
3237  n_components *
3238  ((dim + 1) * n_quadrature_points + dofs_per_component) +
3239  (c * (dim * dim + dim) + d) * n_quadrature_points;
3240  }
3241  scratch_data =
3242  scratch_data_array->begin() + n_components_ * dofs_per_component +
3243  (n_components_ * (dim * dim + 2 * dim + 1) * n_quadrature_points);
3244 }
3245 
3246 
3247 
3248 template <int dim, int n_components_, typename Number, bool is_face>
3249 inline unsigned int
3251  const
3252 {
3254 }
3255 
3256 
3257 
3258 template <int dim, int n_components_, typename Number, bool is_face>
3259 inline unsigned int
3262 {
3263  if (matrix_info == 0)
3264  return 0;
3265  else
3266  {
3268  return this->mapping_data->data_index_offsets[cell];
3269  }
3270 }
3271 
3272 
3273 
3274 template <int dim, int n_components_, typename Number, bool is_face>
3277 {
3279  return cell_type;
3280 }
3281 
3282 
3283 
3284 template <int dim, int n_components_, typename Number, bool is_face>
3287 {
3288  Assert(data != nullptr, ExcInternalError());
3289  return *data;
3290 }
3291 
3292 
3293 
3294 template <int dim, int n_components_, typename Number, bool is_face>
3295 inline void
3297  AlignedVector<VectorizedArray<Number>> &JxW_values) const
3298 {
3299  AssertDimension(JxW_values.size(), n_quadrature_points);
3300  Assert(J_value != nullptr, ExcNotInitialized());
3302  {
3303  VectorizedArray<Number> J = J_value[0];
3304  for (unsigned int q = 0; q < this->n_quadrature_points; ++q)
3305  JxW_values[q] = J * this->quadrature_weights[q];
3306  }
3307  else
3308  for (unsigned int q = 0; q < n_quadrature_points; ++q)
3309  JxW_values[q] = J_value[q];
3310 }
3311 
3312 
3313 
3314 template <int dim, int n_components_, typename Number, bool is_face>
3315 inline DEAL_II_ALWAYS_INLINE Tensor<1, dim, VectorizedArray<Number>>
3317  const unsigned int q_index) const
3318 {
3320  Assert(normal_vectors != nullptr, ExcMessage("Did not call reinit()!"));
3322  return normal_vectors[0];
3323  else
3324  return normal_vectors[q_index];
3325 }
3326 
3327 
3328 
3329 template <int dim, int n_components_, typename Number, bool is_face>
3330 inline DEAL_II_ALWAYS_INLINE VectorizedArray<Number>
3332  const unsigned int q_index) const
3333 {
3335  Assert(J_value != nullptr, ExcNotInitialized());
3337  {
3338  Assert(this->quadrature_weights != nullptr, ExcInternalError());
3339  return J_value[0] * this->quadrature_weights[q_index];
3340  }
3341  else
3342  return J_value[q_index];
3343 }
3344 
3345 
3346 
3347 template <int dim, int n_components_, typename Number, bool is_face>
3350  const unsigned int q_index) const
3351 {
3353  Assert(this->jacobian != nullptr, ExcNotImplemented());
3355  return jacobian[0];
3356  else
3357  return jacobian[q_index];
3358 }
3359 
3360 
3361 
3362 template <int dim, int n_components_, typename Number, bool is_face>
3365  const AlignedVector<VectorizedArray<Number>> &array) const
3366 {
3367  Assert(matrix_info != nullptr, ExcNotImplemented());
3368  AssertDimension(array.size(),
3369  matrix_info->get_task_info().cell_partition_data.back());
3370  if (is_face)
3371  {
3372  VectorizedArray<Number> out = make_vectorized_array<Number>(Number(1.));
3373  const unsigned int * cells =
3374  is_interior_face ?
3375  &this->matrix_info->get_face_info(cell).cells_interior[0] :
3376  &this->matrix_info->get_face_info(cell).cells_exterior[0];
3377  for (unsigned int i = 0; i < VectorizedArray<Number>::n_array_elements;
3378  ++i)
3379  if (cells[i] != numbers::invalid_unsigned_int)
3380  out[i] = array[cells[i] / VectorizedArray<Number>::n_array_elements]
3382  return out;
3383  }
3384  else
3385  return array[cell];
3386 }
3387 
3388 
3389 
3390 namespace internal
3391 {
3392  // access to generic vectors that have operator ().
3393  template <typename VectorType>
3394  inline typename VectorType::value_type &
3395  vector_access(VectorType &vec, const unsigned int entry)
3396  {
3397  return vec(entry);
3398  }
3399 
3400 
3401 
3402  // access to distributed MPI vectors that have a local_element(uint)
3403  // method to access data in local index space, which is what we use in
3404  // DoFInfo and hence in read_dof_values etc.
3405  template <typename Number>
3406  inline Number &
3407  vector_access(LinearAlgebra::distributed::Vector<Number> &vec,
3408  const unsigned int entry)
3409  {
3410  return vec.local_element(entry);
3411  }
3412 
3413 
3414 
3415  // this is to make sure that the parallel partitioning in the
3416  // LinearAlgebra::distributed::Vector is really the same as stored in
3417  // MatrixFree
3418  template <typename VectorType>
3419  inline void
3420  check_vector_compatibility(
3421  const VectorType & vec,
3423  {
3424  (void)vec;
3425  (void)dof_info;
3426 
3427  AssertDimension(vec.size(), dof_info.vector_partitioner->size());
3428  }
3429 
3430  template <typename Number>
3431  inline void
3432  check_vector_compatibility(
3434  const internal::MatrixFreeFunctions::DoFInfo & dof_info)
3435  {
3436  (void)vec;
3437  (void)dof_info;
3439  ExcMessage(
3440  "The parallel layout of the given vector is not "
3441  "compatible with the parallel partitioning in MatrixFree. "
3442  "Use MatrixFree::initialize_dof_vector to get a "
3443  "compatible vector."));
3444  }
3445 
3446  // A class to use the same code to read from and write to vector
3447  template <typename Number>
3448  struct VectorReader
3449  {
3450  template <typename VectorType>
3451  void
3452  process_dof(const unsigned int index, VectorType &vec, Number &res) const
3453  {
3454  res = vector_access(vec, index);
3455  }
3456 
3457  template <typename VectorType>
3458  void
3459  process_dofs_vectorized_transpose(const unsigned int dofs_per_cell,
3460  const unsigned int * dof_indices,
3461  VectorType & vec,
3462  VectorizedArray<Number> *dof_values,
3463  std::integral_constant<bool, true>) const
3464  {
3465  ::vectorized_load_and_transpose(dofs_per_cell,
3466  vec.begin(),
3467  dof_indices,
3468  dof_values);
3469  }
3470 
3471 
3472  template <typename VectorType>
3473  void
3474  process_dofs_vectorized_transpose(const unsigned int dofs_per_cell,
3475  const unsigned int * dof_indices,
3476  VectorType & vec,
3477  VectorizedArray<Number> *dof_values,
3478  std::integral_constant<bool, false>) const
3479  {
3480  for (unsigned int d = 0; d < dofs_per_cell; ++d)
3481  for (unsigned int v = 0; v < VectorizedArray<Number>::n_array_elements;
3482  ++v)
3483  dof_values[d][v] = vector_access(vec, dof_indices[v] + d);
3484  }
3485 
3486  // variant where VectorType::value_type is the same as Number -> can call
3487  // gather
3488  template <typename VectorType>
3489  void
3490  process_dof_gather(const unsigned int * indices,
3491  VectorType & vec,
3492  const unsigned int constant_offset,
3494  std::integral_constant<bool, true>) const
3495  {
3496  res.gather(vec.begin() + constant_offset, indices);
3497  }
3498 
3499  // variant where VectorType::value_type is not the same as Number -> must
3500  // manually load the data
3501  template <typename VectorType>
3502  void
3503  process_dof_gather(const unsigned int * indices,
3504  VectorType & vec,
3505  const unsigned int constant_offset,
3507  std::integral_constant<bool, false>) const
3508  {
3509  for (unsigned int v = 0; v < VectorizedArray<Number>::n_array_elements;
3510  ++v)
3511  res[v] = vector_access(vec, indices[v] + constant_offset);
3512  }
3513 
3514  template <typename VectorType>
3515  void
3516  process_dof_global(const types::global_dof_index index,
3517  VectorType & vec,
3518  Number & res) const
3519  {
3520  res = const_cast<const VectorType &>(vec)(index);
3521  }
3522 
3523  void
3524  pre_constraints(const Number &, Number &res) const
3525  {
3526  res = Number();
3527  }
3528 
3529  template <typename VectorType>
3530  void
3531  process_constraint(const unsigned int index,
3532  const Number weight,
3533  VectorType & vec,
3534  Number & res) const
3535  {
3536  res += weight * vector_access(vec, index);
3537  }
3538 
3539  void
3540  post_constraints(const Number &sum, Number &write_pos) const
3541  {
3542  write_pos = sum;
3543  }
3544 
3545  void
3546  process_empty(VectorizedArray<Number> &res) const
3547  {
3548  res = VectorizedArray<Number>();
3549  }
3550  };
3551 
3552  // A class to use the same code to read from and write to vector
3553  template <typename Number>
3554  struct VectorDistributorLocalToGlobal
3555  {
3556  template <typename VectorType>
3557  void
3558  process_dof(const unsigned int index, VectorType &vec, Number &res) const
3559  {
3560  vector_access(vec, index) += res;
3561  }
3562 
3563  template <typename VectorType>
3564  void
3565  process_dofs_vectorized_transpose(const unsigned int dofs_per_cell,
3566  const unsigned int * dof_indices,
3567  VectorType & vec,
3568  VectorizedArray<Number> *dof_values,
3569  std::integral_constant<bool, true>) const
3570  {
3571  vectorized_transpose_and_store(
3572  true, dofs_per_cell, dof_values, dof_indices, vec.begin());
3573  }
3574 
3575  template <typename VectorType>
3576  void
3577  process_dofs_vectorized_transpose(const unsigned int dofs_per_cell,
3578  const unsigned int * dof_indices,
3579  VectorType & vec,
3580  VectorizedArray<Number> *dof_values,
3581  std::integral_constant<bool, false>) const
3582  {
3583  for (unsigned int d = 0; d < dofs_per_cell; ++d)
3584  for (unsigned int v = 0; v < VectorizedArray<Number>::n_array_elements;
3585  ++v)
3586  vector_access(vec, dof_indices[v] + d) += dof_values[d][v];
3587  }
3588 
3589  // variant where VectorType::value_type is the same as Number -> can call
3590  // scatter
3591  template <typename VectorType>
3592  void
3593  process_dof_gather(const unsigned int * indices,
3594  VectorType & vec,
3595  const unsigned int constant_offset,
3597  std::integral_constant<bool, true>) const
3598  {
3599 # if DEAL_II_COMPILER_VECTORIZATION_LEVEL < 3
3600  for (unsigned int v = 0; v < VectorizedArray<Number>::n_array_elements;
3601  ++v)
3602  vector_access(vec, indices[v] + constant_offset) += res[v];
3603 # else
3604  // only use gather in case there is also scatter.
3606  tmp.gather(vec.begin() + constant_offset, indices);
3607  tmp += res;
3608  tmp.scatter(indices, vec.begin() + constant_offset);
3609 # endif
3610  }
3611 
3612  // variant where VectorType::value_type is not the same as Number -> must
3613  // manually append all data
3614  template <typename VectorType>
3615  void
3616  process_dof_gather(const unsigned int * indices,
3617  VectorType & vec,
3618  const unsigned int constant_offset,
3620  std::integral_constant<bool, false>) const
3621  {
3622  for (unsigned int v = 0; v < VectorizedArray<Number>::n_array_elements;
3623  ++v)
3624  vector_access(vec, indices[v] + constant_offset) += res[v];
3625  }
3626 
3627  template <typename VectorType>
3628  void
3629  process_dof_global(const types::global_dof_index index,
3630  VectorType & vec,
3631  Number & res) const
3632  {
3633  vec(index) += res;
3634  }
3635 
3636  void
3637  pre_constraints(const Number &input, Number &res) const
3638  {
3639  res = input;
3640  }
3641 
3642  template <typename VectorType>
3643  void
3644  process_constraint(const unsigned int index,
3645  const Number weight,
3646  VectorType & vec,
3647  Number & res) const
3648  {
3649  vector_access(vec, index) += weight * res;
3650  }
3651 
3652  void
3653  post_constraints(const Number &, Number &) const
3654  {}
3655 
3656  void
3657  process_empty(VectorizedArray<Number> &) const
3658  {}
3659  };
3660 
3661 
3662  // A class to use the same code to read from and write to vector
3663  template <typename Number>
3664  struct VectorSetter
3665  {
3666  template <typename VectorType>
3667  void
3668  process_dof(const unsigned int index, VectorType &vec, Number &res) const
3669  {
3670  vector_access(vec, index) = res;
3671  }
3672 
3673  template <typename VectorType>
3674  void
3675  process_dofs_vectorized_transpose(const unsigned int dofs_per_cell,
3676  const unsigned int * dof_indices,
3677  VectorType & vec,
3678  VectorizedArray<Number> *dof_values,
3679  std::integral_constant<bool, true>) const
3680  {
3681  vectorized_transpose_and_store(
3682  false, dofs_per_cell, dof_values, dof_indices, vec.begin());
3683  }
3684 
3685  template <typename VectorType, bool booltype>
3686  void
3687  process_dofs_vectorized_transpose(const unsigned int dofs_per_cell,
3688  const unsigned int * dof_indices,
3689  VectorType & vec,
3690  VectorizedArray<Number> *dof_values,
3691  std::integral_constant<bool, false>) const
3692  {
3693  for (unsigned int i = 0; i < dofs_per_cell; ++i)
3694  for (unsigned int v = 0; v < VectorizedArray<Number>::n_array_elements;
3695  ++v)
3696  vector_access(vec, dof_indices[v] + i) = dof_values[i][v];
3697  }
3698 
3699  template <typename VectorType>
3700  void
3701  process_dof_gather(const unsigned int * indices,
3702  VectorType & vec,
3703  const unsigned int constant_offset,
3705  std::integral_constant<bool, true>) const
3706  {
3707  res.scatter(indices, vec.begin() + constant_offset);
3708  }
3709 
3710  template <typename VectorType>
3711  void
3712  process_dof_gather(const unsigned int * indices,
3713  VectorType & vec,
3714  const unsigned int constant_offset,
3716  std::integral_constant<bool, false>) const
3717  {
3718  for (unsigned int v = 0; v < VectorizedArray<Number>::n_array_elements;
3719  ++v)
3720  vector_access(vec, indices[v] + constant_offset) = res[v];
3721  }
3722 
3723  template <typename VectorType>
3724  void
3725  process_dof_global(const types::global_dof_index index,
3726  VectorType & vec,
3727  Number & res) const
3728  {
3729  vec(index) = res;
3730  }
3731 
3732  void
3733  pre_constraints(const Number &, Number &) const
3734  {}
3735 
3736  template <typename VectorType>
3737  void
3738  process_constraint(const unsigned int,
3739  const Number,
3740  VectorType &,
3741  Number &) const
3742  {}
3743 
3744  void
3745  post_constraints(const Number &, Number &) const
3746  {}
3747 
3748  void
3749  process_empty(VectorizedArray<Number> &) const
3750  {}
3751  };
3752 
3753  // allows to select between block vectors and non-block vectors, which
3754  // allows to use a unified interface for extracting blocks on block vectors
3755  // and doing nothing on usual vectors
3756  template <typename VectorType, bool>
3757  struct BlockVectorSelector
3758  {};
3759 
3760  template <typename VectorType>
3761  struct BlockVectorSelector<VectorType, true>
3762  {
3763  using BaseVectorType = typename VectorType::BlockType;
3764 
3765  static BaseVectorType *
3766  get_vector_component(VectorType &vec, const unsigned int component)
3767  {
3768  AssertIndexRange(component, vec.n_blocks());
3769  return &vec.block(component);
3770  }
3771  };
3772 
3773  template <typename VectorType>
3774  struct BlockVectorSelector<VectorType, false>
3775  {
3776  using BaseVectorType = VectorType;
3777 
3778  static BaseVectorType *
3779  get_vector_component(VectorType &vec, const unsigned int component)
3780  {
3781  // FEEvaluation allows to combine several vectors from a scalar
3782  // FiniteElement into a "vector-valued" FEEvaluation object with
3783  // multiple components. These components can be extracted with the other
3784  // get_vector_component functions. If we do not get a vector of vectors
3785  // (std::vector<VectorType>, std::vector<VectorType*>, BlockVector), we
3786  // must make sure that we do not duplicate the components in input
3787  // and/or duplicate the resulting integrals. In such a case, we should
3788  // only get the zeroth component in the vector contained set nullptr for
3789  // the others which allows us to catch unintended use in
3790  // read_write_operation.
3791  if (component == 0)
3792  return &vec;
3793  else
3794  return nullptr;
3795  }
3796  };
3797 
3798  template <typename VectorType>
3799  struct BlockVectorSelector<std::vector<VectorType>, false>
3800  {
3801  using BaseVectorType = VectorType;
3802 
3803  static BaseVectorType *
3804  get_vector_component(std::vector<VectorType> &vec,
3805  const unsigned int component)
3806  {
3807  AssertIndexRange(component, vec.size());
3808  return &vec[component];
3809  }
3810  };
3811 
3812  template <typename VectorType>
3813  struct BlockVectorSelector<std::vector<VectorType *>, false>
3814  {
3815  using BaseVectorType = VectorType;
3816 
3817  static BaseVectorType *
3818  get_vector_component(std::vector<VectorType *> &vec,
3819  const unsigned int component)
3820  {
3821  AssertIndexRange(component, vec.size());
3822  return vec[component];
3823  }
3824  };
3825 } // namespace internal
3826 
3827 
3828 
3829 template <int dim, int n_components_, typename Number, bool is_face>
3830 template <typename VectorType, typename VectorOperation>
3831 inline void
3833  const VectorOperation &operation,
3834  VectorType * src[],
3835  const bool apply_constraints) const
3836 {
3837  // Case 1: No MatrixFree object given, simple case because we do not need to
3838  // process constraints and need not care about vectorization -> go to
3839  // separate function
3840  if (matrix_info == nullptr)
3841  {
3842  read_write_operation_global(operation, src);
3843  return;
3844  }
3845 
3846  Assert(dof_info != nullptr, ExcNotInitialized());
3847  Assert(matrix_info->indices_initialized() == true, ExcNotInitialized());
3848  if (n_fe_components == 1)
3849  for (unsigned int comp = 0; comp < n_components; ++comp)
3850  internal::check_vector_compatibility(*src[comp], *dof_info);
3851  else
3852  {
3853  internal::check_vector_compatibility(*src[0], *dof_info);
3854  }
3855 
3856  // Case 2: contiguous indices which use reduced storage of indices and can
3857  // use vectorized load/store operations -> go to separate function
3859  dof_info->index_storage_variants[dof_access_index].size());
3860  if (dof_info->index_storage_variants
3861  [is_face ? dof_access_index :
3863  [cell] >=
3865  {
3866  read_write_operation_contiguous(operation, src);
3867  return;
3868  }
3869 
3870  // Case 3: standard operation with one index per degree of freedom -> go on
3871  // here
3872 
3873  constexpr unsigned int n_vectorization =
3875  const unsigned int dofs_per_component =
3876  this->data->dofs_per_component_on_cell;
3877  if (dof_info->index_storage_variants
3878  [is_face ? dof_access_index :
3880  [cell] ==
3882  {
3883  const unsigned int *dof_indices =
3884  dof_info->dof_indices_interleaved.data() +
3885  dof_info->row_starts[cell * n_fe_components * n_vectorization].first +
3888  n_vectorization;
3889  if (n_components == 1 || n_fe_components == 1)
3890  for (unsigned int i = 0; i < dofs_per_component;
3891  ++i, dof_indices += n_vectorization)
3892  for (unsigned int comp = 0; comp < n_components; ++comp)
3893  operation.process_dof_gather(
3894  dof_indices,
3895  *src[comp],
3896  0,
3897  values_dofs[comp][i],
3898  std::integral_constant<
3899  bool,
3900  std::is_same<typename VectorType::value_type,
3901  Number>::value>());
3902  else
3903  for (unsigned int comp = 0; comp < n_components; ++comp)
3904  for (unsigned int i = 0; i < dofs_per_component;
3905  ++i, dof_indices += n_vectorization)
3906  operation.process_dof_gather(
3907  dof_indices,
3908  *src[0],
3909  0,
3910  values_dofs[comp][i],
3911  std::integral_constant<
3912  bool,
3913  std::is_same<typename VectorType::value_type,
3914  Number>::value>());
3915  return;
3916  }
3917 
3918  const unsigned int * dof_indices[n_vectorization];
3920  const_cast<VectorizedArray<Number> **>(&this->values_dofs[0]);
3921 
3922  unsigned int cells_copied[n_vectorization];
3923  const unsigned int *cells;
3924  unsigned int n_vectorization_actual =
3926  bool has_constraints = false;
3927  if (is_face)
3928  {
3929  if (dof_access_index ==
3931  for (unsigned int v = 0; v < n_vectorization_actual; ++v)
3932  cells_copied[v] =
3934  cells = dof_access_index ==
3936  &cells_copied[0] :
3937  (is_interior_face ?
3938  &this->matrix_info->get_face_info(cell).cells_interior[0] :
3939  &this->matrix_info->get_face_info(cell).cells_exterior[0]);
3940  for (unsigned int v = 0; v < n_vectorization_actual; ++v)
3941  {
3942  Assert(cells[v] < dof_info->row_starts.size() - 1,
3943  ExcInternalError());
3944  has_constraints =
3945  has_constraints &&
3946  dof_info
3947  ->row_starts[cells[v] * n_fe_components +
3948  first_selected_component + n_components]
3949  .second != dof_info
3950  ->row_starts[cells[v] * n_fe_components +
3952  .second;
3953  dof_indices[v] = dof_info->dof_indices.data() +
3954  dof_info
3955  ->row_starts[cells[v] * n_fe_components +
3957  .first;
3958  }
3959  for (unsigned int v = n_vectorization_actual; v < n_vectorization; ++v)
3960  dof_indices[v] = nullptr;
3961  }
3962  else
3963  {
3964  AssertIndexRange((cell + 1) * n_vectorization * n_fe_components,
3965  dof_info->row_starts.size());
3966  const unsigned int n_components_read =
3967  n_fe_components > 1 ? n_components : 1;
3968  for (unsigned int v = 0; v < n_vectorization_actual; ++v)
3969  {
3970  if (dof_info
3971  ->row_starts[(cell * n_vectorization + v) * n_fe_components +
3972  first_selected_component + n_components_read]
3973  .second !=
3974  dof_info
3975  ->row_starts[(cell * n_vectorization + v) * n_fe_components +
3976  first_selected_component]
3977  .second)
3978  has_constraints = true;
3979  Assert(
3980  dof_info
3981  ->row_starts[(cell * n_vectorization + v) * n_fe_components +
3982  first_selected_component + n_components_read]
3983  .first ==
3984  dof_info
3985  ->row_starts[(cell * n_vectorization + v) * n_fe_components +
3986  first_selected_component]
3987  .first ||
3988  dof_info
3989  ->row_starts[(cell * n_vectorization + v) * n_fe_components +
3990  first_selected_component]
3991  .first < dof_info->dof_indices.size(),
3992  ExcIndexRange(
3993  0,
3994  dof_info
3995  ->row_starts[(cell * n_vectorization + v) * n_fe_components +
3996  first_selected_component]
3997  .first,
3998  dof_info->dof_indices.size()));
3999  dof_indices[v] =
4000  dof_info->dof_indices.data() +
4001  dof_info
4002  ->row_starts[(cell * n_vectorization + v) * n_fe_components +
4003  first_selected_component]
4004  .first;
4005  }
4006  for (unsigned int v = n_vectorization_actual; v < n_vectorization; ++v)
4007  dof_indices[v] = nullptr;
4008  }
4009 
4010  // Case where we have no constraints throughout the whole cell: Can go
4011  // through the list of DoFs directly
4012  if (!has_constraints)
4013  {
4014  if (n_vectorization_actual < n_vectorization)
4015  for (unsigned int comp = 0; comp < n_components; ++comp)
4016  for (unsigned int i = 0; i < dofs_per_component; ++i)
4017  operation.process_empty(values_dofs[comp][i]);
4018  if (n_components == 1 || n_fe_components == 1)
4019  {
4020  for (unsigned int v = 0; v < n_vectorization_actual; ++v)
4021  for (unsigned int i = 0; i < dofs_per_component; ++i)
4022  for (unsigned int comp = 0; comp < n_components; ++comp)
4023  operation.process_dof(dof_indices[v][i],
4024  *src[comp],
4025  values_dofs[comp][i][v]);
4026  }
4027  else
4028  {
4029  for (unsigned int comp = 0; comp < n_components; ++comp)
4030  for (unsigned int v = 0; v < n_vectorization_actual; ++v)
4031  for (unsigned int i = 0; i < dofs_per_component; ++i)
4032  operation.process_dof(
4033  dof_indices[v][comp * dofs_per_component + i],
4034  *src[0],
4035  values_dofs[comp][i][v]);
4036  }
4037  return;
4038  }
4039 
4040  // In the case where there are some constraints to be resolved, loop over
4041  // all vector components that are filled and then over local dofs. ind_local
4042  // holds local number on cell, index iterates over the elements of
4043  // index_local_to_global and dof_indices points to the global indices stored
4044  // in index_local_to_global
4045  if (n_vectorization_actual < n_vectorization)
4046  for (unsigned int comp = 0; comp < n_components; ++comp)
4047  for (unsigned int i = 0; i < dofs_per_component; ++i)
4048  operation.process_empty(values_dofs[comp][i]);
4049  for (unsigned int v = 0; v < n_vectorization_actual; ++v)
4050  {
4051  unsigned int index_indicators, next_index_indicators;
4052  const unsigned int n_components_read =
4053  n_fe_components > 1 ? n_components : 1;
4054  if (is_face)
4055  {
4056  index_indicators = dof_info
4057  ->row_starts[cells[v] * n_fe_components +
4059  .second;
4060  next_index_indicators = dof_info
4061  ->row_starts[cells[v] * n_fe_components +
4062  first_selected_component + 1]
4063  .second;
4064  }
4065  else
4066  {
4067  index_indicators =
4068  dof_info
4069  ->row_starts[(cell * n_vectorization + v) * n_fe_components +
4070  first_selected_component]
4071  .second;
4072  next_index_indicators =
4073  dof_info
4074  ->row_starts[(cell * n_vectorization + v) * n_fe_components +
4075  first_selected_component + 1]
4076  .second;
4077  }
4078 
4079  if (apply_constraints == false &&
4080  dof_info
4081  ->row_starts[(cell * n_vectorization + v) * n_fe_components +
4083  .second !=
4084  dof_info
4085  ->row_starts[(cell * n_vectorization + v) * n_fe_components +
4086  first_selected_component + n_components_read]
4087  .second)
4088  {
4089  Assert(
4090  dof_info->row_starts_plain_indices[cell * n_vectorization + v] !=
4092  ExcNotInitialized());
4093  dof_indices[v] =
4094  dof_info->plain_dof_indices.data() +
4097  (is_face ?
4098  dof_info->row_starts_plain_indices[cells[v]] :
4099  dof_info->row_starts_plain_indices[cell * n_vectorization + v]);
4100  next_index_indicators = index_indicators;
4101  }
4102 
4103  if (n_components == 1 || n_fe_components == 1)
4104  {
4105  for (unsigned int c = 0; c < n_components; ++c)
4106  Assert(src[c] != nullptr,
4107  ExcMessage(
4108  "The finite element underlying this FEEvaluation "
4109  "object is scalar, but you requested " +
4110  std::to_string(n_components) +
4111  " components via the template argument in "
4112  "FEEvaluation. In that case, you must pass an "
4113  "std::vector<VectorType> or a BlockVector to " +
4114  "read_dof_values and distribute_local_to_global."));
4115 
4116  unsigned int ind_local = 0;
4117  for (; index_indicators != next_index_indicators; ++index_indicators)
4118  {
4119  const std::pair<unsigned short, unsigned short> indicator =
4120  dof_info->constraint_indicator[index_indicators];
4121  // run through values up to next constraint
4122  for (unsigned int j = 0; j < indicator.first; ++j)
4123  for (unsigned int comp = 0; comp < n_components; ++comp)
4124  operation.process_dof(dof_indices[v][j],
4125  *src[comp],
4126  values_dofs[comp][ind_local + j][v]);
4127 
4128  ind_local += indicator.first;
4129  dof_indices[v] += indicator.first;
4130 
4131  // constrained case: build the local value as a linear
4132  // combination of the global value according to constraints
4133  Number value[n_components];
4134  for (unsigned int comp = 0; comp < n_components; ++comp)
4135  operation.pre_constraints(values_dofs[comp][ind_local][v],
4136  value[comp]);
4137 
4138  const Number *data_val =
4139  matrix_info->constraint_pool_begin(indicator.second);
4140  const Number *end_pool =
4141  matrix_info->constraint_pool_end(indicator.second);
4142  for (; data_val != end_pool; ++data_val, ++dof_indices[v])
4143  for (unsigned int comp = 0; comp < n_components; ++comp)
4144  operation.process_constraint(*dof_indices[v],
4145  *data_val,
4146  *src[comp],
4147  value[comp]);
4148 
4149  for (unsigned int comp = 0; comp < n_components; ++comp)
4150  operation.post_constraints(value[comp],
4151  values_dofs[comp][ind_local][v]);
4152  ind_local++;
4153  }
4154 
4155  AssertIndexRange(ind_local, dofs_per_component + 1);
4156 
4157  for (; ind_local < dofs_per_component; ++dof_indices[v], ++ind_local)
4158  for (unsigned int comp = 0; comp < n_components; ++comp)
4159  operation.process_dof(*dof_indices[v],
4160  *src[comp],
4161  values_dofs[comp][ind_local][v]);
4162  }
4163  else
4164  {
4165  // case with vector-valued finite elements where all components are
4166  // included in one single vector. Assumption: first come all entries
4167  // to the first component, then all entries to the second one, and
4168  // so on. This is ensured by the way MatrixFree reads out the
4169  // indices.
4170  for (unsigned int comp = 0; comp < n_components; ++comp)
4171  {
4172  unsigned int ind_local = 0;
4173 
4174  // check whether there is any constraint on the current cell
4175  for (; index_indicators != next_index_indicators;
4176  ++index_indicators)
4177  {
4178  const std::pair<unsigned short, unsigned short> indicator =
4179  dof_info->constraint_indicator[index_indicators];
4180 
4181  // run through values up to next constraint
4182  for (unsigned int j = 0; j < indicator.first; ++j)
4183  operation.process_dof(dof_indices[v][j],
4184  *src[0],
4185  values_dofs[comp][ind_local + j][v]);
4186  ind_local += indicator.first;
4187  dof_indices[v] += indicator.first;
4188 
4189  // constrained case: build the local value as a linear
4190  // combination of the global value according to constraints
4191  Number value;
4192  operation.pre_constraints(values_dofs[comp][ind_local][v],
4193  value);
4194 
4195  const Number *data_val =
4196  matrix_info->constraint_pool_begin(indicator.second);
4197  const Number *end_pool =
4198  matrix_info->constraint_pool_end(indicator.second);
4199 
4200  for (; data_val != end_pool; ++data_val, ++dof_indices[v])
4201  operation.process_constraint(*dof_indices[v],
4202  *data_val,
4203  *src[0],
4204  value);
4205 
4206  operation.post_constraints(value,
4207  values_dofs[comp][ind_local][v]);
4208  ind_local++;
4209  }
4210 
4211  AssertIndexRange(ind_local, dofs_per_component + 1);
4212 
4213  // get the dof values past the last constraint
4214  for (; ind_local < dofs_per_component;
4215  ++dof_indices[v], ++ind_local)
4216  {
4217  AssertIndexRange(*dof_indices[v], src[0]->size());
4218  operation.process_dof(*dof_indices[v],
4219  *src[0],
4220  values_dofs[comp][ind_local][v]);
4221  }
4222 
4223  if (apply_constraints == true && comp + 1 < n_components)
4224  {
4225  if (is_face)
4226  next_index_indicators =
4227  dof_info
4228  ->row_starts[cells[v] * n_fe_components +
4229  first_selected_component + comp + 2]
4230  .second;
4231  else
4232  next_index_indicators =
4233  dof_info
4234  ->row_starts[(cell * n_vectorization + v) *
4235  n_fe_components +
4236  first_selected_component + comp + 2]
4237  .second;
4238  }
4239  }
4240  }
4241  }
4242 }
4243 
4244 
4245 
4246 template <int dim, int n_components_, typename Number, bool is_face>
4247 template <typename VectorType, typename VectorOperation>
4248 inline void
4251  VectorType * src[]) const
4252 {
4253  Assert(!local_dof_indices.empty(), ExcNotInitialized());
4254 
4255  unsigned int index =
4256  first_selected_component * data->dofs_per_component_on_cell;
4257  for (unsigned int comp = 0; comp < n_components; ++comp)
4258  {
4259  for (unsigned int i = 0; i < data->dofs_per_component_on_cell;
4260  ++i, ++index)
4261  {
4262  operation.process_empty(values_dofs[comp][i]);
4263  operation.process_dof_global(
4264  local_dof_indices[data->lexicographic_numbering[index]],
4265  *src[0],
4266  values_dofs[comp][i][0]);
4267  }
4268  }
4269 }
4270 
4271 
4272 
4273 template <int dim, int n_components_, typename Number, bool is_face>
4274 template <typename VectorType, typename VectorOperation>
4275 inline void
4278  VectorType * src[]) const
4279 {
4280  // This functions processes the functions read_dof_values,
4281  // distribute_local_to_global, and set_dof_values with the same code for
4282  // contiguous cell indices (DG case). The distinction between these three
4283  // cases is made by the input VectorOperation that either reads values from
4284  // a vector and puts the data into the local data field or write local data
4285  // into the vector. Certain operations are no-ops for the given use case.
4286 
4287  std::integral_constant<
4288  bool,
4289  std::is_same<typename VectorType::value_type, Number>::value>
4290  vector_selector;
4292  is_face ? dof_access_index :
4294 
4295  const std::vector<unsigned int> &dof_indices_cont =
4296  dof_info->dof_indices_contiguous[ind];
4297  const unsigned int vectorization_populated =
4298  dof_info->n_vectorization_lanes_filled[ind][this->cell];
4299  unsigned int dof_indices[VectorizedArray<Number>::n_array_elements];
4300  for (unsigned int v = 0; v < vectorization_populated; ++v)
4301  dof_indices[v] =
4302  dof_indices_cont[cell * VectorizedArray<Number>::n_array_elements + v] +
4304  [first_selected_component];
4305  for (unsigned int v = vectorization_populated;
4306  v < VectorizedArray<Number>::n_array_elements;
4307  ++v)
4308  dof_indices[v] = numbers::invalid_unsigned_int;
4309 
4310  // In the case with contiguous cell indices, we know that there are no
4311  // constraints and that the indices within each element are contiguous
4312  if (vectorization_populated == VectorizedArray<Number>::n_array_elements)
4313  {
4314  if (n_components == 1 || n_fe_components == 1)
4315  for (unsigned int comp = 0; comp < n_components; ++comp)
4316  operation.process_dofs_vectorized_transpose(
4318  dof_indices,
4319  *src[comp],
4320  values_dofs[comp],
4321  vector_selector);
4322  else
4323  operation.process_dofs_vectorized_transpose(
4324  data->dofs_per_component_on_cell * n_components,
4325  dof_indices,
4326  *src[0],
4327  &values_dofs[0][0],
4328  vector_selector);
4329  }
4330  else
4331  for (unsigned int comp = 0; comp < n_components; ++comp)
4332  {
4333  for (unsigned int i = 0; i < data->dofs_per_component_on_cell; ++i)
4334  operation.process_empty(values_dofs[comp][i]);
4335  if (n_components == 1 || n_fe_components == 1)
4336  for (unsigned int v = 0; v < vectorization_populated; ++v)
4337  for (unsigned int i = 0; i < data->dofs_per_component_on_cell; ++i)
4338  operation.process_dof(dof_indices[v] + i,
4339  *src[comp],
4340  values_dofs[comp][i][v]);
4341  else
4342  for (unsigned int v = 0; v < vectorization_populated; ++v)
4343  for (unsigned int i = 0; i < data->dofs_per_component_on_cell; ++i)
4344  operation.process_dof(dof_indices[v] + i +
4345  comp * data->dofs_per_component_on_cell,
4346  *src[0],
4347  values_dofs[comp][i][v]);
4348  }
4349 }
4350 
4351 
4352 
4353 template <int dim, int n_components_, typename Number, bool is_face>
4354 template <typename VectorType>
4355 inline void
4357  const VectorType & src,
4358  const unsigned int first_index)
4359 {
4360  // select between block vectors and non-block vectors. Note that the number
4361  // of components is checked in the internal data
4362  typename internal::BlockVectorSelector<
4363  VectorType,
4364  IsBlockVector<VectorType>::value>::BaseVectorType *src_data[n_components];
4365  for (unsigned int d = 0; d < n_components; ++d)
4366  src_data[d] =
4367  internal::BlockVectorSelector<VectorType,
4369  get_vector_component(const_cast<VectorType &>(src), d + first_index);
4370 
4371  internal::VectorReader<Number> reader;
4372  read_write_operation(reader, src_data, true);
4373 
4374 # ifdef DEBUG
4375  dof_values_initialized = true;
4376 # endif
4377 }
4378 
4379 
4380 
4381 template <int dim, int n_components_, typename Number, bool is_face>
4382 template <typename VectorType>
4383 inline void
4385  const VectorType & src,
4386  const unsigned int first_index)
4387 {
4388  // select between block vectors and non-block vectors. Note that the number
4389  // of components is checked in the internal data
4390  typename internal::BlockVectorSelector<
4391  VectorType,
4392  IsBlockVector<VectorType>::value>::BaseVectorType *src_data[n_components];
4393  for (unsigned int d = 0; d < n_components; ++d)
4394  src_data[d] =
4395  internal::BlockVectorSelector<VectorType,
4397  get_vector_component(const_cast<VectorType &>(src), d + first_index);
4398 
4399  internal::VectorReader<Number> reader;
4400  read_write_operation(reader, src_data, false);
4401 
4402 # ifdef DEBUG
4403  dof_values_initialized = true;
4404 # endif
4405 }
4406 
4407 
4408 
4409 template <int dim, int n_components_, typename Number, bool is_face>
4410 template <typename VectorType>
4411 inline void
4413  distribute_local_to_global(VectorType & dst,
4414  const unsigned int first_index) const
4415 {
4418 
4419  // select between block vectors and non-block vectors. Note that the number
4420  // of components is checked in the internal data
4421  typename internal::BlockVectorSelector<
4422  VectorType,
4423  IsBlockVector<VectorType>::value>::BaseVectorType *dst_data[n_components];
4424  for (unsigned int d = 0; d < n_components; ++d)
4425  dst_data[d] = internal::BlockVectorSelector<
4426  VectorType,
4427  IsBlockVector<VectorType>::value>::get_vector_component(dst,
4428  d + first_index);
4429 
4430  internal::VectorDistributorLocalToGlobal<Number> distributor;
4431  read_write_operation(distributor, dst_data);
4432 }
4433 
4434 
4435 
4436 template <int dim, int n_components_, typename Number, bool is_face>
4437 template <typename VectorType>
4438 inline void
4440  VectorType & dst,
4441  const unsigned int first_index) const
4442 {
4445 
4446  // select between block vectors and non-block vectors. Note that the number
4447  // of components is checked in the internal data
4448  typename internal::BlockVectorSelector<
4449  VectorType,
4450  IsBlockVector<VectorType>::value>::BaseVectorType *dst_data[n_components];
4451  for (unsigned int d = 0; d < n_components; ++d)
4452  dst_data[d] = internal::BlockVectorSelector<
4453  VectorType,
4454  IsBlockVector<VectorType>::value>::get_vector_component(dst,
4455  d + first_index);
4456 
4457  internal::VectorSetter<Number> setter;
4458  read_write_operation(setter, dst_data);
4459 }
4460 
4461 
4462 
4463 /*------------------------------ access to data fields ----------------------*/
4464 
4465 template <int dim, int n_components, typename Number, bool is_face>
4466 inline const std::vector<unsigned int> &
4469 {
4470  return data->lexicographic_numbering;
4471 }
4472 
4473 
4474 
4475 template <int dim, int n_components, typename Number, bool is_face>
4478 {
4480  const_cast<VectorizedArray<Number> *>(scratch_data),
4482 }
4483 
4484 
4485 
4486 template <int dim, int n_components, typename Number, bool is_face>
4487 inline const VectorizedArray<Number> *
4489 {
4490  return &values_dofs[0][0];
4491 }
4492 
4493 
4494 
4495 template <int dim, int n_components, typename Number, bool is_face>
4496 inline VectorizedArray<Number> *
4498 {
4499 # ifdef DEBUG
4500  dof_values_initialized = true;
4501 # endif
4502  return &values_dofs[0][0];
4503 }
4504 
4505 
4506 
4507 template <int dim, int n_components, typename Number, bool is_face>
4508 inline const VectorizedArray<Number> *
4510 {
4512  return &values_quad[0][0];
4513 }
4514 
4515 
4516 
4517 template <int dim, int n_components, typename Number, bool is_face>
4518 inline VectorizedArray<Number> *
4520 {
4521 # ifdef DEBUG
4522  values_quad_initialized = true;
4523  values_quad_submitted = true;
4524 # endif
4525  return &values_quad[0][0];
4526 }
4527 
4528 
4529 
4530 template <int dim, int n_components, typename Number, bool is_face>
4531 inline const VectorizedArray<Number> *
4533 {
4535  ExcNotInitialized());
4536  return &gradients_quad[0][0][0];
4537 }
4538 
4539 
4540 
4541 template <int dim, int n_components, typename Number, bool is_face>
4542 inline VectorizedArray<Number> *
4544 {
4545 # ifdef DEBUG
4546  gradients_quad_submitted = true;
4548 # endif
4549  return &gradients_quad[0][0][0];
4550 }
4551 
4552 
4553 
4554 template <int dim, int n_components, typename Number, bool is_face>
4555 inline const VectorizedArray<Number> *
4557 {
4559  return &hessians_quad[0][0][0];
4560 }
4561 
4562 
4563 
4564 template <int dim, int n_components, typename Number, bool is_face>
4565 inline VectorizedArray<Number> *
4567 {
4568 # ifdef DEBUG
4570 # endif
4571  return &hessians_quad[0][0][0];
4572 }
4573 
4574 
4575 
4576 template <int dim, int n_components_, typename Number, bool is_face>
4577 inline DEAL_II_ALWAYS_INLINE Tensor<1, n_components_, VectorizedArray<Number>>
4579  const unsigned int dof) const
4580 {
4581  AssertIndexRange(dof, this->data->dofs_per_component_on_cell);
4583  for (unsigned int comp = 0; comp < n_components; comp++)
4584  return_value[comp] = this->values_dofs[comp][dof];
4585  return return_value;
4586 }
4587 
4588 
4589 
4590 template <int dim, int n_components_, typename Number, bool is_face>
4591 inline DEAL_II_ALWAYS_INLINE Tensor<1, n_components_, VectorizedArray<Number>>
4593  const unsigned int q_point) const
4594 {
4595  Assert(this->values_quad_initialized == true,
4597  AssertIndexRange(q_point, this->n_quadrature_points);
4599  for (unsigned int comp = 0; comp < n_components; comp++)
4600  return_value[comp] = this->values_quad[comp][q_point];
4601  return return_value;
4602 }
4603 
4604 
4605 
4606 template <int dim, int n_components_, typename Number, bool is_face>
4607 inline DEAL_II_ALWAYS_INLINE
4610  const unsigned int q_point) const
4611 {
4612  Assert(this->gradients_quad_initialized == true,
4614  AssertIndexRange(q_point, this->n_quadrature_points);
4615 
4616  Assert(jacobian != nullptr, ExcNotInitialized());
4617 
4619 
4620  // Cartesian cell
4621  if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
4622  {
4623  for (unsigned int comp = 0; comp < n_components; comp++)
4624  for (unsigned int d = 0; d < dim; ++d)
4625  grad_out[comp][d] =
4626  (this->gradients_quad[comp][d][q_point] * jacobian[0][d][d]);
4627  }
4628  // cell with general/affine Jacobian
4629  else
4630  {
4633  q_point :
4634  0];
4635  for (unsigned int comp = 0; comp < n_components; comp++)
4636  for (unsigned int d = 0; d < dim; ++d)
4637  {
4638  grad_out[comp][d] =
4639  jac[d][0] * this->gradients_quad[comp][0][q_point];
4640  for (unsigned int e = 1; e < dim; ++e)
4641  grad_out[comp][d] +=
4642  jac[d][e] * this->gradients_quad[comp][e][q_point];
4643  }
4644  }
4645  return grad_out;
4646 }
4647 
4648 
4649 
4650 template <int dim, int n_components_, typename Number, bool is_face>
4651 inline DEAL_II_ALWAYS_INLINE Tensor<1, n_components_, VectorizedArray<Number>>
4653  const unsigned int q_point) const
4654 {
4655  AssertIndexRange(q_point, this->n_quadrature_points);
4656  Assert(this->gradients_quad_initialized == true,
4658 
4659  Assert(normal_x_jacobian != nullptr, ExcNotInitialized());
4660 
4663  for (unsigned int comp = 0; comp < n_components; comp++)
4664  grad_out[comp] = this->gradients_quad[comp][dim - 1][q_point] *
4665  (this->normal_x_jacobian[0][dim - 1]);
4666  else
4667  {
4668  const unsigned int index =
4669  this->cell_type <= internal::MatrixFreeFunctions::affine ? 0 : q_point;
4670  for (unsigned int comp = 0; comp < n_components; comp++)
4671  {
4672  grad_out[comp] = this->gradients_quad[comp][0][q_point] *
4673  this->normal_x_jacobian[index][0];
4674  for (unsigned int d = 1; d < dim; ++d)
4675  grad_out[comp] += this->gradients_quad[comp][d][q_point] *
4676  this->normal_x_jacobian[index][d];
4677  }
4678  }
4679  return grad_out;
4680 }
4681 
4682 
4683 
4684 namespace internal
4685 {
4686  // compute tmp = hess_unit(u) * J^T. do this manually because we do not
4687  // store the lower diagonal because of symmetry
4688  template <typename Number>
4689  inline void
4690  hessian_unit_times_jac(const Tensor<2, 1, VectorizedArray<Number>> &jac,
4691  const VectorizedArray<Number> *const hessians_quad[1],
4692  const unsigned int q_point,
4693  VectorizedArray<Number> (&tmp)[1][1])
4694  {
4695  tmp[0][0] = jac[0][0] * hessians_quad[0][q_point];
4696  }
4697 
4698  template <typename Number>
4699  inline void
4700  hessian_unit_times_jac(const Tensor<2, 2, VectorizedArray<Number>> &jac,
4701  const VectorizedArray<Number> *const hessians_quad[3],
4702  const unsigned int q_point,
4703  VectorizedArray<Number> (&tmp)[2][2])
4704  {
4705  for (unsigned int d = 0; d < 2; ++d)
4706  {
4707  tmp[0][d] = (jac[d][0] * hessians_quad[0][q_point] +
4708  jac[d][1] * hessians_quad[2][q_point]);
4709  tmp[1][d] = (jac[d][0] * hessians_quad[2][q_point] +
4710  jac[d][1] * hessians_quad[1][q_point]);
4711  }
4712  }
4713 
4714  template <typename Number>
4715  inline void
4716  hessian_unit_times_jac(const Tensor<2, 3, VectorizedArray<Number>> &jac,
4717  const VectorizedArray<Number> *const hessians_quad[6],
4718  const unsigned int q_point,
4719  VectorizedArray<Number> (&tmp)[3][3])
4720  {
4721  for (unsigned int d = 0; d < 3; ++d)
4722  {
4723  tmp[0][d] = (jac[d][0] * hessians_quad[0][q_point] +
4724  jac[d][1] * hessians_quad[3][q_point] +
4725  jac[d][2] * hessians_quad[4][q_point]);
4726  tmp[1][d] = (jac[d][0] * hessians_quad[3][q_point] +
4727  jac[d][1] * hessians_quad[1][q_point] +
4728  jac[d][2] * hessians_quad[5][q_point]);
4729  tmp[2][d] = (jac[d][0] * hessians_quad[4][q_point] +
4730  jac[d][1] * hessians_quad[5][q_point] +
4731  jac[d][2] * hessians_quad[2][q_point]);
4732  }
4733  }
4734 } // namespace internal
4735 
4736 
4737 
4738 template <int dim, int n_components_, typename Number, bool is_face>
4741  const unsigned int q_point) const
4742 {
4743  Assert(!is_face, ExcNotImplemented());
4744  Assert(this->hessians_quad_initialized == true,
4746  AssertIndexRange(q_point, this->n_quadrature_points);
4747 
4748  Assert(jacobian != nullptr, ExcNotImplemented());
4751  0 :
4752  q_point];
4753 
4755 
4756  // Cartesian cell
4757  if (this->cell_type == internal::MatrixFreeFunctions::cartesian)
4758  {
4759  for (unsigned int comp = 0; comp < n_components; comp++)
4760  for (unsigned int d = 0; d < dim; ++d)
4761  {
4762  hessian_out[comp][d][d] =
4763  (this->hessians_quad[comp][d][q_point] * jac[d][d] * jac[d][d]);
4764  switch (dim)
4765  {
4766  case 1:
4767  break;
4768  case 2:
4769  hessian_out[comp][0][1] =
4770  (this->hessians_quad[comp][2][q_point] * jac[0][0] *
4771  jac[1][1]);
4772  break;
4773  case 3:
4774  hessian_out[comp][0][1] =
4775  (this->hessians_quad[comp][3][q_point] * jac[0][0] *
4776  jac[1][1]);
4777  hessian_out[comp][0][2] =
4778  (this->hessians_quad[comp][4][q_point] * jac[0][0] *
4779  jac[2][2]);
4780  hessian_out[comp][1][2] =
4781  (this->hessians_quad[comp][5][q_point] * jac[1][1] *
4782  jac[2][2]);
4783  break;
4784  default:
4785  Assert(false, ExcNotImplemented());
4786  }
4787  for (unsigned int e = d + 1; e < dim; ++e)
4788  hessian_out[comp][e][d] = hessian_out[comp][d][e];
4789  }
4790  }
4791  // cell with general Jacobian, but constant within the cell
4792  else if (this->cell_type == internal::MatrixFreeFunctions::affine)
4793  {
4794  for (unsigned int comp = 0; comp < n_components; comp++)
4795  {
4796  // compute laplacian before the gradient because it needs to access
4797  // unscaled gradient data
4798  VectorizedArray<Number> tmp[dim][dim];
4799  internal::hessian_unit_times_jac(jac,
4800  this->hessians_quad[comp],
4801  q_point,
4802  tmp);
4803 
4804  // compute first part of hessian, J * tmp = J * hess_unit(u) * J^T
4805  for (unsigned int d = 0; d < dim; ++d)
4806  for (unsigned int e = d; e < dim; ++e)
4807  {
4808  hessian_out[comp][d][e] = jac[d][0] * tmp[0][e];
4809  for (unsigned int f = 1; f < dim; ++f)
4810  hessian_out[comp][d][e] += jac[d][f] * tmp[f][e];
4811  }
4812 
4813  // no J' * grad(u) part here because the Jacobian is constant
4814  // throughout the cell and hence, its derivative is zero
4815 
4816  // take symmetric part
4817  for (unsigned int d = 0; d < dim; ++d)
4818  for (unsigned int e = d + 1; e < dim; ++e)
4819  hessian_out[comp][e][d] = hessian_out[comp][d][e];
4820  }
4821  }
4822  // cell with general Jacobian
4823  else
4824  {
4825  const Tensor<1,
4826  dim *(dim + 1) / 2,
4827  Tensor<1, dim, VectorizedArray<Number>>> &jac_grad =
4829  [1 - this->is_interior_face]
4830  [this->mapping_data->data_index_offsets[this->cell] + q_point];
4831  for (unsigned int comp = 0; comp < n_components; comp++)
4832  {
4833  // compute laplacian before the gradient because it needs to access
4834  // unscaled gradient data
4835  VectorizedArray<Number> tmp[dim][dim];
4836  internal::hessian_unit_times_jac(jac,
4837  this->hessians_quad[comp],
4838  q_point,
4839  tmp);
4840 
4841  // compute first part of hessian, J * tmp = J * hess_unit(u) * J^T
4842  for (unsigned int d = 0; d < dim; ++d)
4843  for (unsigned int e = d; e < dim; ++e)
4844  {
4845  hessian_out[comp][d][e] = jac[d][0] * tmp[0][e];
4846  for (unsigned int f = 1; f < dim; ++f)
4847  hessian_out[comp][d][e] += jac[d][f] * tmp[f][e];
4848  }
4849 
4850  // add diagonal part of J' * grad(u)
4851  for (unsigned int d = 0; d < dim; ++d)
4852  for (unsigned int e = 0; e < dim; ++e)
4853  hessian_out[comp][d][d] +=
4854  (jac_grad[d][e] * this->gradients_quad[comp][e][q_point]);
4855 
4856  // add off-diagonal part of J' * grad(u)
4857  for (unsigned int d = 0, count = dim; d < dim; ++d)
4858  for (unsigned int e = d + 1; e < dim; ++e, ++count)
4859  for (unsigned int f = 0; f < dim; ++f)
4860  hessian_out[comp][d][e] +=
4861  (jac_grad[count][f] * this->gradients_quad[comp][f][q_point]);
4862 
4863  // take symmetric part
4864  for (unsigned int d = 0; d < dim; ++d)
4865  for (unsigned int e = d + 1; e < dim; ++e)
4866  hessian_out[comp][e][d] = hessian_out[comp][d][e];
4867  }
4868  }
4870  hessian_out);
4871 }
4872 
4873 
4874 
4875 template <int dim, int n_components_, typename Number, bool is_face>
4878  const unsigned int q_point) const
4879 {
4880  Assert(!is_face, ExcNotImplemented());
4881  Assert(this->hessians_quad_initialized == true,
4883  AssertIndexRange(q_point, this->n_quadrature_points);
4884 
4885  Assert(jacobian != nullptr, ExcNotImplemented());
4887  jacobian[this->cell_type <= internal::MatrixFreeFunctions::affine ?
4888  0 :
4889  q_point];
4890 
4892 
4893  // Cartesian cell
4894  if (this->cell_type == internal::MatrixFreeFunctions::cartesian)
4895  {
4896  for (unsigned int comp = 0; comp < n_components; comp++)
4897  for (unsigned int d = 0; d < dim; ++d)
4898  hessian_out[comp][d] =
4899  (this->hessians_quad[comp][d][q_point] * jac[d][d] * jac[d][d]);
4900  }
4901  // cell with general Jacobian, but constant within the cell
4902  else if (this->cell_type == internal::MatrixFreeFunctions::affine)
4903  {
4904  for (unsigned int comp = 0; comp < n_components; comp++)
4905  {
4906  // compute laplacian before the gradient because it needs to access
4907  // unscaled gradient data
4908  VectorizedArray<Number> tmp[dim][dim];
4909  internal::hessian_unit_times_jac(jac,
4910  this->hessians_quad[comp],
4911  q_point,
4912  tmp);
4913 
4914  // compute only the trace part of hessian, J * tmp = J *
4915  // hess_unit(u) * J^T
4916  for (unsigned int d = 0; d < dim; ++d)
4917  {
4918  hessian_out[comp][d] = jac[d][0] * tmp[0][d];
4919  for (unsigned int f = 1; f < dim; ++f)
4920  hessian_out[comp][d] += jac[d][f] * tmp[f][d];
4921  }
4922  }
4923  }
4924  // cell with general Jacobian
4925  else
4926  {
4927  const Tensor<1,
4928  dim *(dim + 1) / 2,
4929  Tensor<1, dim, VectorizedArray<Number>>> &jac_grad =
4931  [0][this->mapping_data->data_index_offsets[this->cell] + q_point];
4932  for (unsigned int comp = 0; comp < n_components; comp++)
4933  {
4934  // compute laplacian before the gradient because it needs to access
4935  // unscaled gradient data
4936  VectorizedArray<Number> tmp[dim][dim];
4937  internal::hessian_unit_times_jac(jac,
4938  this->hessians_quad[comp],
4939  q_point,
4940  tmp);
4941 
4942  // compute only the trace part of hessian, J * tmp = J *
4943  // hess_unit(u) * J^T
4944  for (unsigned int d = 0; d < dim; ++d)
4945  {
4946  hessian_out[comp][d] = jac[d][0] * tmp[0][d];
4947  for (unsigned int f = 1; f < dim; ++f)
4948  hessian_out[comp][d] += jac[d][f] * tmp[f][d];
4949  }
4950 
4951  for (unsigned int d = 0; d < dim; ++d)
4952  for (unsigned int e = 0; e < dim; ++e)
4953  hessian_out[comp][d] +=
4954  (jac_grad[d][e] * this->gradients_quad[comp][e][q_point]);
4955  }
4956  }
4957  return hessian_out;
4958 }
4959 
4960 
4961 
4962 template <int dim, int n_components_, typename Number, bool is_face>
4965  const unsigned int q_point) const
4966 {
4967  Assert(is_face == false, ExcNotImplemented());
4968  Assert(this->hessians_quad_initialized == true,
4970  AssertIndexRange(q_point, this->n_quadrature_points);
4971 
4974  hess_diag = get_hessian_diagonal(q_point);
4975  for (unsigned int comp = 0; comp < n_components; ++comp)
4976  {
4977  laplacian_out[comp] = hess_diag[comp][0];
4978  for (unsigned int d = 1; d < dim; ++d)
4979  laplacian_out[comp] += hess_diag[comp][d];
4980  }
4981  return laplacian_out;
4982 }
4983 
4984 
4985 
4986 template <int dim, int n_components_, typename Number, bool is_face>
4987 inline DEAL_II_ALWAYS_INLINE void
4989  const Tensor<1, n_components_, VectorizedArray<Number>> val_in,
4990  const unsigned int dof)
4991 {
4992 # ifdef DEBUG
4993  this->dof_values_initialized = true;
4994 # endif
4995  AssertIndexRange(dof, this->data->dofs_per_component_on_cell);
4996  for (unsigned int comp = 0; comp < n_components; comp++)
4997  this->values_dofs[comp][dof] = val_in[comp];
4998 }
4999 
5000 
5001 
5002 template <int dim, int n_components_, typename Number, bool is_face>
5003 inline DEAL_II_ALWAYS_INLINE void
5005  const Tensor<1, n_components_, VectorizedArray<Number>> val_in,
5006  const unsigned int q_point)
5007 {
5008 # ifdef DEBUG
5010  AssertIndexRange(q_point, this->n_quadrature_points);
5011  Assert(this->J_value != nullptr, ExcNotInitialized());
5012  this->values_quad_submitted = true;
5013 # endif
5014 
5015  if (this->cell_type <= internal::MatrixFreeFunctions::affine)
5016  {
5018  J_value[0] * quadrature_weights[q_point];
5019  for (unsigned int comp = 0; comp < n_components; ++comp)
5020  this->values_quad[comp][q_point] = val_in[comp] * JxW;
5021  }
5022  else
5023  {
5024  const VectorizedArray<Number> JxW = J_value[q_point];
5025  for (unsigned int comp = 0; comp < n_components; ++comp)
5026  this->values_quad[comp][q_point] = val_in[comp] * JxW;
5027  }
5028 }
5029 
5030 
5031 
5032 template <int dim, int n_components_, typename Number, bool is_face>
5033 inline DEAL_II_ALWAYS_INLINE void
5035  const Tensor<1, n_components_, Tensor<1, dim, VectorizedArray<Number>>>
5036  grad_in,
5037  const unsigned int q_point)
5038 {
5039 # ifdef DEBUG
5041  AssertIndexRange(q_point, this->n_quadrature_points);
5042  this->gradients_quad_submitted = true;
5043  Assert(this->J_value != nullptr, ExcNotInitialized());
5044  Assert(this->jacobian != nullptr, ExcNotInitialized());
5045 # endif
5046 
5047  if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
5048  {
5049  const VectorizedArray<Number> JxW =
5050  J_value[0] * quadrature_weights[q_point];
5051  for (unsigned int comp = 0; comp < n_components; comp++)
5052  for (unsigned int d = 0; d < dim; ++d)
5053  this->gradients_quad[comp][d][q_point] =
5054  (grad_in[comp][d] * jacobian[0][d][d] * JxW);
5055  }
5056  else
5057  {
5059  this->cell_type > internal::MatrixFreeFunctions::affine ?
5060  jacobian[q_point] :
5061  jacobian[0];
5062  const VectorizedArray<Number> JxW =
5063  this->cell_type > internal::MatrixFreeFunctions::affine ?
5064  J_value[q_point] :
5065  J_value[0] * quadrature_weights[q_point];
5066  for (unsigned int comp = 0; comp < n_components; ++comp)
5067  for (unsigned int d = 0; d < dim; ++d)
5068  {
5069  VectorizedArray<Number> new_val = jac[0][d] * grad_in[comp][0];
5070  for (unsigned int e = 1; e < dim; ++e)
5071  new_val += (jac[e][d] * grad_in[comp][e]);
5072  this->gradients_quad[comp][d][q_point] = new_val * JxW;
5073  }
5074  }
5075 }
5076 
5077 
5078 
5079 template <int dim, int n_components_, typename Number, bool is_face>
5080 inline DEAL_II_ALWAYS_INLINE void
5082  const Tensor<1, n_components_, VectorizedArray<Number>> grad_in,
5083  const unsigned int q_point)
5084 {
5085 # ifdef DEBUG
5086  AssertIndexRange(q_point, this->n_quadrature_points);
5087  this->gradients_quad_submitted = true;
5088  Assert(this->normal_x_jacobian != nullptr, ExcNotInitialized());
5089 # endif
5090 
5091  if (this->cell_type == internal::MatrixFreeFunctions::cartesian)
5092  for (unsigned int comp = 0; comp < n_components; comp++)
5093  {
5094  for (unsigned int d = 0; d < dim - 1; ++d)
5095  this->gradients_quad[comp][d][q_point] = VectorizedArray<Number>();
5096  this->gradients_quad[comp][dim - 1][q_point] =
5097  grad_in[comp] *
5098  (this->normal_x_jacobian[0][dim - 1] * this->J_value[0] *
5099  this->quadrature_weights[q_point]);
5100  }
5101  else
5102  {
5103  const unsigned int index =
5104  this->cell_type <= internal::MatrixFreeFunctions::affine ? 0 : q_point;
5105  for (unsigned int comp = 0; comp < n_components; comp++)
5106  {
5107  VectorizedArray<Number> factor = grad_in[comp] * this->J_value[index];
5108  if (this->cell_type <= internal::MatrixFreeFunctions::affine)
5109  factor = factor * this->quadrature_weights[q_point];
5110  for (unsigned int d = 0; d < dim; ++d)
5111  this->gradients_quad[comp][d][q_point] =
5112  factor * this->normal_x_jacobian[index][d];
5113  }
5114  }
5115 }
5116 
5117 
5118 
5119 template <int dim, int n_components_, typename Number, bool is_face>
5122 {
5123 # ifdef DEBUG
5125  Assert(this->values_quad_submitted == true,
5127 # endif
5129  for (unsigned int comp = 0; comp < n_components; ++comp)
5130  return_value[comp] = this->values_quad[comp][0];
5131  const unsigned int n_q_points = this->n_quadrature_points;
5132  for (unsigned int q = 1; q < n_q_points; ++q)
5133  for (unsigned int comp = 0; comp < n_components; ++comp)
5134  return_value[comp] += this->values_quad[comp][q];
5135  return (return_value);
5136 }
5137 
5138 
5139 
5140 /*----------------------- FEEvaluationAccess --------------------------------*/
5141 
5142 
5143 template <int dim, int n_components_, typename Number, bool is_face>
5146  const unsigned int dof_no,
5147  const unsigned int first_selected_component,
5148  const unsigned int quad_no_in,
5149  const unsigned int fe_degree,
5150  const unsigned int n_q_points,
5151  const bool is_interior_face)
5152  : FEEvaluationBase<dim, n_components_, Number, is_face>(
5153  data_in,
5154  dof_no,
5155  first_selected_component,
5156  quad_no_in,
5157  fe_degree,
5158  n_q_points,
5159  is_interior_face)
5160 {}
5161 
5162 
5163 
5164 template <int dim, int n_components_, typename Number, bool is_face>
5165 template <int n_components_other>
5168  const Mapping<dim> & mapping,
5169  const FiniteElement<dim> &fe,
5170  const Quadrature<1> & quadrature,
5171  const UpdateFlags update_flags,
5172  const unsigned int first_selected_component,
5174  : FEEvaluationBase<dim, n_components_, Number, is_face>(
5175  mapping,
5176  fe,
5177  quadrature,
5178  update_flags,
5179  first_selected_component,
5180  other)
5181 {}
5182 
5183 
5184 
5185 template <int dim, int n_components_, typename Number, bool is_face>
5189  : FEEvaluationBase<dim, n_components_, Number, is_face>(other)
5190 {}
5191 
5192 
5193 
5194 template <int dim, int n_components_, typename Number, bool is_face>
5198 {
5200  return *this;
5201 }
5202 
5203 
5204 
5205 /*-------------------- FEEvaluationAccess scalar ----------------------------*/
5206 
5207 
5208 template <int dim, typename Number, bool is_face>
5210  const MatrixFree<dim, Number> &data_in,
5211  const unsigned int dof_no,
5212  const unsigned int first_selected_component,
5213  const unsigned int quad_no_in,
5214  const unsigned int fe_degree,
5215  const unsigned int n_q_points,
5216  const bool is_interior_face)
5217  : FEEvaluationBase<dim, 1, Number, is_face>(data_in,
5218  dof_no,
5219  first_selected_component,
5220  quad_no_in,
5221  fe_degree,
5222  n_q_points,
5223  is_interior_face)
5224 {}
5225 
5226 
5227 
5228 template <int dim, typename Number, bool is_face>
5229 template <int n_components_other>
5231  const Mapping<dim> & mapping,
5232  const FiniteElement<dim> &fe,
5233  const Quadrature<1> & quadrature,
5234  const UpdateFlags update_flags,
5235  const unsigned int first_selected_component,
5237  : FEEvaluationBase<dim, 1, Number, is_face>(mapping,
5238  fe,
5239  quadrature,
5240  update_flags,
5241  first_selected_component,
5242  other)
5243 {}
5244 
5245 
5246 
5247 template <int dim, typename Number, bool is_face>
5250  : FEEvaluationBase<dim, 1, Number, is_face>(other)
5251 {}
5252 
5253 
5254 
5255 template <int dim, typename Number, bool is_face>
5259 {
5261  return *this;
5262 }
5263 
5264 
5265 
5266 template <int dim, typename Number, bool is_face>
5267 inline DEAL_II_ALWAYS_INLINE VectorizedArray<Number>
5269  const unsigned int dof) const
5270 {
5271  AssertIndexRange(dof, this->data->dofs_per_component_on_cell);
5272  return this->values_dofs[0][dof];
5273 }
5274 
5275 
5276 
5277 template <int dim, typename Number, bool is_face>
5278 inline DEAL_II_ALWAYS_INLINE VectorizedArray<Number>
5280  const unsigned int q_point) const
5281 {
5282  Assert(this->values_quad_initialized == true,
5284  AssertIndexRange(q_point, this->n_quadrature_points);
5285  return this->values_quad[0][q_point];
5286 }
5287 
5288 
5289 
5290 template <int dim, typename Number, bool is_face>
5291 inline DEAL_II_ALWAYS_INLINE VectorizedArray<Number>
5293  const unsigned int q_point) const
5294 {
5295  return BaseClass::get_normal_derivative(q_point)[0];
5296 }
5297 
5298 
5299 
5300 template <int dim, typename Number, bool is_face>
5301 inline DEAL_II_ALWAYS_INLINE Tensor<1, dim, VectorizedArray<Number>>
5303  const unsigned int q_point) const
5304 {
5305  // could use the base class gradient, but that involves too many expensive
5306  // initialization operations on tensors
5307 
5308  Assert(this->gradients_quad_initialized == true,
5310  AssertIndexRange(q_point, this->n_quadrature_points);
5311 
5312  Assert(this->jacobian != nullptr, ExcNotInitialized());
5313 
5315 
5316  if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
5317  {
5318  for (unsigned int d = 0; d < dim; ++d)
5319  grad_out[d] =
5320  (this->gradients_quad[0][d][q_point] * this->jacobian[0][d][d]);
5321  }
5322  // cell with general/affine Jacobian
5323  else
5324  {
5326  this->jacobian[this->cell_type > internal::MatrixFreeFunctions::affine ?
5327  q_point :
5328  0];
5329  for (unsigned int d = 0; d < dim; ++d)
5330  {
5331  grad_out[d] = jac[d][0] * this->gradients_quad[0][0][q_point];
5332  for (unsigned int e = 1; e < dim; ++e)
5333  grad_out[d] += jac[d][e] * this->gradients_quad[0][e][q_point];
5334  }
5335  }
5336  return grad_out;
5337 }
5338 
5339 
5340 
5341 template <int dim, typename Number, bool is_face>
5344  const unsigned int q_point) const
5345 {
5346  return BaseClass::get_hessian(q_point)[0];
5347 }
5348 
5349 
5350 
5351 template <int dim, typename Number, bool is_face>
5354  const unsigned int q_point) const
5355 {
5356  return BaseClass::get_hessian_diagonal(q_point)[0];
5357 }
5358 
5359 
5360 
5361 template <int dim, typename Number, bool is_face>
5364  const unsigned int q_point) const
5365 {
5366  return BaseClass::get_laplacian(q_point)[0];
5367 }
5368 
5369 
5370 
5371 template <int dim, typename Number, bool is_face>
5372 inline void DEAL_II_ALWAYS_INLINE
5374  const VectorizedArray<Number> val_in,
5375  const unsigned int dof)
5376 {
5377 # ifdef DEBUG
5378  this->dof_values_initialized = true;
5379  AssertIndexRange(dof, this->data->dofs_per_component_on_cell);
5380 # endif
5381  this->values_dofs[0][dof] = val_in;
5382 }
5383 
5384 
5385 
5386 template <int dim, typename Number, bool is_face>
5387 inline void DEAL_II_ALWAYS_INLINE
5389  const VectorizedArray<Number> val_in,
5390  const unsigned int q_index)
5391 {
5392 # ifdef DEBUG
5394  AssertIndexRange(q_index, this->n_quadrature_points);
5395  Assert(this->J_value != nullptr, ExcNotInitialized());
5396  this->values_quad_submitted = true;
5397 # endif
5398  if (this->cell_type <= internal::MatrixFreeFunctions::affine)
5399  {
5400  const VectorizedArray<Number> JxW =
5401  this->J_value[0] * this->quadrature_weights[q_index];
5402  this->values_quad[0][q_index] = val_in * JxW;
5403  }
5404  else // if (this->cell_type < internal::MatrixFreeFunctions::general)
5405  {
5406  this->values_quad[0][q_index] = val_in * this->J_value[q_index];
5407  }
5408 }
5409 
5410 
5411 
5412 template <int dim, typename Number, bool is_face>
5413 inline DEAL_II_ALWAYS_INLINE void
5415  const Tensor<1, 1, VectorizedArray<Number>> val_in,
5416  const unsigned int q_point)
5417 {
5418  submit_value(val_in[0], q_point);
5419 }
5420 
5421 
5422 
5423 template <int dim, typename Number, bool is_face>
5424 inline DEAL_II_ALWAYS_INLINE void
5426  const VectorizedArray<Number> grad_in,
5427  const unsigned int q_point)
5428 {
5430  grad[0] = grad_in;
5431  BaseClass::submit_normal_derivative(grad, q_point);
5432 }
5433 
5434 
5435 
5436 template <int dim, typename Number, bool is_face>
5437 inline DEAL_II_ALWAYS_INLINE void
5439  const Tensor<1, dim, VectorizedArray<Number>> grad_in,
5440  const unsigned int q_index)
5441 {
5442 # ifdef DEBUG
5444  AssertIndexRange(q_index, this->n_quadrature_points);
5445  this->gradients_quad_submitted = true;
5446  Assert(this->J_value != nullptr, ExcNotInitialized());
5447  Assert(this->jacobian != nullptr, ExcNotInitialized());
5448 # endif
5449 
5450  if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
5451  {
5452  const VectorizedArray<Number> JxW =
5453  this->J_value[0] * this->quadrature_weights[q_index];
5454  for (unsigned int d = 0; d < dim; ++d)
5455  this->gradients_quad[0][d][q_index] =
5456  (grad_in[d] * this->jacobian[0][d][d] * JxW);
5457  }
5458  // general/affine cell type
5459  else
5460  {
5462  this->cell_type > internal::MatrixFreeFunctions::affine ?
5463  this->jacobian[q_index] :
5464  this->jacobian[0];
5465  const VectorizedArray<Number> JxW =
5466  this->cell_type > internal::MatrixFreeFunctions::affine ?
5467  this->J_value[q_index] :
5468  this->J_value[0] * this->quadrature_weights[q_index];
5469  for (unsigned int d = 0; d < dim; ++d)
5470  {
5471  VectorizedArray<Number> new_val = jac[0][d] * grad_in[0];
5472  for (unsigned int e = 1; e < dim; ++e)
5473  new_val += jac[e][d] * grad_in[e];
5474  this->gradients_quad[0][d][q_index] = new_val * JxW;
5475  }
5476  }
5477 }
5478 
5479 
5480 
5481 template <int dim, typename Number, bool is_face>
5484 {
5485  return BaseClass::integrate_value()[0];
5486 }
5487 
5488 
5489 
5490 /*----------------- FEEvaluationAccess vector-valued ------------------------*/
5491 
5492 
5493 template <int dim, typename Number, bool is_face>
5495  const MatrixFree<dim, Number> &data_in,
5496  const unsigned int dof_no,
5497  const unsigned int first_selected_component,
5498  const unsigned int quad_no_in,
5499  const unsigned int fe_degree,
5500  const unsigned int n_q_points,
5501  const bool is_interior_face)
5502  : FEEvaluationBase<dim, dim, Number, is_face>(data_in,
5503  dof_no,
5504  first_selected_component,
5505  quad_no_in,
5506  fe_degree,
5507  n_q_points,
5508  is_interior_face)
5509 {}
5510 
5511 
5512 
5513 template <int dim, typename Number, bool is_face>
5514 template <int n_components_other>
5516  const Mapping<dim> & mapping,
5517  const FiniteElement<dim> &fe,
5518  const Quadrature<1> & quadrature,
5519  const UpdateFlags update_flags,
5520  const unsigned int first_selected_component,
5522  : FEEvaluationBase<dim, dim, Number, is_face>(mapping,
5523  fe,
5524  quadrature,
5525  update_flags,
5526  first_selected_component,
5527  other)
5528 {}
5529 
5530 
5531 
5532 template <int dim, typename Number, bool is_face>
5535  : FEEvaluationBase<dim, dim, Number, is_face>(other)
5536 {}
5537 
5538 
5539 
5540 template <int dim, typename Number, bool is_face>
5544 {
5546  return *this;
5547 }
5548 
5549 
5550 
5551 template <int dim, typename Number, bool is_face>
5552 inline DEAL_II_ALWAYS_INLINE Tensor<2, dim, VectorizedArray<Number>>
5554  const unsigned int q_point) const
5555 {
5556  return BaseClass::get_gradient(q_point);
5557 }
5558 
5559 
5560 
5561 template <int dim, typename Number, bool is_face>
5562 inline DEAL_II_ALWAYS_INLINE VectorizedArray<Number>
5564  const unsigned int q_point) const
5565 {
5566  Assert(this->gradients_quad_initialized == true,
5568  AssertIndexRange(q_point, this->n_quadrature_points);
5569  Assert(this->jacobian != nullptr, ExcNotInitialized());
5570 
5571  VectorizedArray<Number> divergence;
5572 
5573  // Cartesian cell
5574  if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
5575  {
5576  divergence =
5577  (this->gradients_quad[0][0][q_point] * this->jacobian[0][0][0]);
5578  for (unsigned int d = 1; d < dim; ++d)
5579  divergence +=
5580  (this->gradients_quad[d][d][q_point] * this->jacobian[0][d][d]);
5581  }
5582  // cell with general/constant Jacobian
5583  else
5584  {
5586  this->cell_type == internal::MatrixFreeFunctions::general ?
5587  this->jacobian[q_point] :
5588  this->jacobian[0];
5589  divergence = (jac[0][0] * this->gradients_quad[0][0][q_point]);
5590  for (unsigned int e = 1; e < dim; ++e)
5591  divergence += (jac[0][e] * this->gradients_quad[0][e][q_point]);
5592  for (unsigned int d = 1; d < dim; ++d)
5593  for (unsigned int e = 0; e < dim; ++e)
5594  divergence += (jac[d][e] * this->gradients_quad[d][e][q_point]);
5595  }
5596  return divergence;
5597 }
5598 
5599 
5600 
5601 template <int dim, typename Number, bool is_face>
5602 inline DEAL_II_ALWAYS_INLINE SymmetricTensor<2, dim, VectorizedArray<Number>>
5604  const unsigned int q_point) const
5605 {
5606  // copy from generic function into dim-specialization function
5608  VectorizedArray<Number> symmetrized[(dim * dim + dim) / 2];
5609  VectorizedArray<Number> half = make_vectorized_array<Number>(0.5);
5610  for (unsigned int d = 0; d < dim; ++d)
5611  symmetrized[d] = grad[d][d];
5612  switch (dim)
5613  {
5614  case 1:
5615  break;
5616  case 2:
5617  symmetrized[2] = grad[0][1] + grad[1][0];
5618  symmetrized[2] *= half;
5619  break;
5620  case 3:
5621  symmetrized[3] = grad[0][1] + grad[1][0];
5622  symmetrized[3] *= half;
5623  symmetrized[4] = grad[0][2] + grad[2][0];
5624  symmetrized[4] *= half;
5625  symmetrized[5] = grad[1][2] + grad[2][1];
5626  symmetrized[5] *= half;
5627  break;
5628  default:
5629  Assert(false, ExcNotImplemented());
5630  }
5632 }
5633 
5634 
5635 
5636 template <int dim, typename Number, bool is_face>
5637 inline DEAL_II_ALWAYS_INLINE
5640  const unsigned int q_point) const
5641 {
5642  // copy from generic function into dim-specialization function
5645  switch (dim)
5646  {
5647  case 1:
5648  Assert(false,
5649  ExcMessage(
5650  "Computing the curl in 1d is not a useful operation"));
5651  break;
5652  case 2:
5653  curl[0] = grad[1][0] - grad[0][1];
5654  break;
5655  case 3:
5656  curl[0] = grad[2][1] - grad[1][2];
5657  curl[1] = grad[0][2] - grad[2][0];
5658  curl[2] = grad[1][0] - grad[0][1];
5659  break;
5660  default:
5661  Assert(false, ExcNotImplemented());
5662  }
5663  return curl;
5664 }
5665 
5666 
5667 
5668 template <int dim, typename Number, bool is_face>
5669 inline DEAL_II_ALWAYS_INLINE Tensor<2, dim, VectorizedArray<Number>>
5671  const unsigned int q_point) const
5672 {
5673  return BaseClass::get_hessian_diagonal(q_point);
5674 }
5675 
5676 
5677 
5678 template <int dim, typename Number, bool is_face>
5679 inline DEAL_II_ALWAYS_INLINE Tensor<3, dim, VectorizedArray<Number>>
5681  const unsigned int q_point) const
5682 {
5683  Assert(this->hessians_quad_initialized == true,
5685  AssertIndexRange(q_point, this->n_quadrature_points);
5686  return BaseClass::get_hessian(q_point);
5687 }
5688 
5689 
5690 
5691 template <int dim, typename Number, bool is_face>
5692 inline DEAL_II_ALWAYS_INLINE void
5694  const Tensor<2, dim, VectorizedArray<Number>> grad_in,
5695  const unsigned int q_point)
5696 {
5697  BaseClass::submit_gradient(grad_in, q_point);
5698 }
5699 
5700 
5701 
5702 template <int dim, typename Number, bool is_face>
5703 inline DEAL_II_ALWAYS_INLINE void
5705  const Tensor<1, dim, Tensor<1, dim, VectorizedArray<Number>>> grad_in,
5706  const unsigned int q_point)
5707 {
5708  BaseClass::submit_gradient(grad_in, q_point);
5709 }
5710 
5711 
5712 
5713 template <int dim, typename Number, bool is_face>
5714 inline DEAL_II_ALWAYS_INLINE void
5716  const VectorizedArray<Number> div_in,
5717  const unsigned int q_point)
5718 {
5719 # ifdef DEBUG
5721  AssertIndexRange(q_point, this->n_quadrature_points);
5722  this->gradients_quad_submitted = true;
5723  Assert(this->J_value != nullptr, ExcNotInitialized());
5724  Assert(this->jacobian != nullptr, ExcNotInitialized());
5725 # endif
5726 
5727  if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
5728  {
5729  const VectorizedArray<Number> fac =
5730  this->J_value[0] * this->quadrature_weights[q_point] * div_in;
5731  for (unsigned int d = 0; d < dim; ++d)
5732  {
5733  this->gradients_quad[d][d][q_point] = (fac * this->jacobian[0][d][d]);
5734  for (unsigned int e = d + 1; e < dim; ++e)
5735  {
5736  this->gradients_quad[d][e][q_point] = VectorizedArray<Number>();
5737  this->gradients_quad[e][d][q_point] = VectorizedArray<Number>();
5738  }
5739  }
5740  }
5741  else
5742  {
5744  this->cell_type == internal::MatrixFreeFunctions::general ?
5745  this->jacobian[q_point] :
5746  this->jacobian[0];
5747  const VectorizedArray<Number> fac =
5748  (this->cell_type == internal::MatrixFreeFunctions::general ?
5749  this->J_value[q_point] :
5750  this->J_value[0] * this->quadrature_weights[q_point]) *
5751  div_in;
5752  for (unsigned int d = 0; d < dim; ++d)
5753  {
5754  for (unsigned int e = 0; e < dim; ++e)
5755  this->gradients_quad[d][e][q_point] = jac[d][e] * fac;
5756  }
5757  }
5758 }
5759 
5760 
5761 
5762 template <int dim, typename Number, bool is_face>
5763 inline DEAL_II_ALWAYS_INLINE void
5765  const SymmetricTensor<2, dim, VectorizedArray<Number>> sym_grad,
5766  const unsigned int q_point)
5767 {
5768  // could have used base class operator, but that involves some overhead
5769  // which is inefficient. it is nice to have the symmetric tensor because
5770  // that saves some operations
5771 # ifdef DEBUG
5773  AssertIndexRange(q_point, this->n_quadrature_points);
5774  this->gradients_quad_submitted = true;
5775  Assert(this->J_value != nullptr, ExcNotInitialized());
5776  Assert(this->jacobian != nullptr, ExcNotInitialized());
5777 # endif
5778 
5779  if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
5780  {
5781  const VectorizedArray<Number> JxW =
5782  this->J_value[0] * this->quadrature_weights[q_point];
5783  for (unsigned int d = 0; d < dim; ++d)
5784  this->gradients_quad[d][d][q_point] =
5785  (sym_grad.access_raw_entry(d) * JxW * this->jacobian[0][d][d]);
5786  for (unsigned int e = 0, counter = dim; e < dim; ++e)
5787  for (unsigned int d = e + 1; d < dim; ++d, ++counter)
5788  {
5789  const VectorizedArray<Number> value =
5790  sym_grad.access_raw_entry(counter) * JxW;
5791  this->gradients_quad[e][d][q_point] =
5792  (value * this->jacobian[0][d][d]);
5793  this->gradients_quad[d][e][q_point] =
5794  (value * this->jacobian[0][e][e]);
5795  }
5796  }
5797  // general/affine cell type
5798  else
5799  {
5800  const VectorizedArray<Number> JxW =
5801  this->cell_type == internal::MatrixFreeFunctions::general ?
5802  this->J_value[q_point] :
5803  this->J_value[0] * this->quadrature_weights[q_point];
5805  this->cell_type == internal::MatrixFreeFunctions::general ?
5806  this->jacobian[q_point] :
5807  this->jacobian[0];
5808  VectorizedArray<Number> weighted[dim][dim];
5809  for (unsigned int i = 0; i < dim; ++i)
5810  weighted[i][i] = sym_grad.access_raw_entry(i) * JxW;
5811  for (unsigned int i = 0, counter = dim; i < dim; ++i)
5812  for (unsigned int j = i + 1; j < dim; ++j, ++counter)
5813  {
5814  const VectorizedArray<Number> value =
5815  sym_grad.access_raw_entry(counter) * JxW;
5816  weighted[i][j] = value;
5817  weighted[j][i] = value;
5818  }
5819  for (unsigned int comp = 0; comp < dim; ++comp)
5820  for (unsigned int d = 0; d < dim; ++d)
5821  {
5822  VectorizedArray<Number> new_val = jac[0][d] * weighted[comp][0];
5823  for (unsigned int e = 1; e < dim; ++e)
5824  new_val += jac[e][d] * weighted[comp][e];
5825  this->gradients_quad[comp][d][q_point] = new_val;
5826  }
5827  }
5828 }
5829 
5830 
5831 
5832 template <int dim, typename Number, bool is_face>
5833 inline DEAL_II_ALWAYS_INLINE void
5835  const Tensor<1, dim == 2 ? 1 : dim, VectorizedArray<Number>> curl,
5836  const unsigned int q_point)
5837 {
5839  switch (dim)
5840  {
5841  case 1:
5842  Assert(false,
5843  ExcMessage(
5844  "Testing by the curl in 1d is not a useful operation"));
5845  break;
5846  case 2:
5847  grad[1][0] = curl[0];
5848  grad[0][1] = -curl[0];
5849  break;
5850  case 3:
5851  grad[2][1] = curl[0];
5852  grad[1][2] = -curl[0];
5853  grad[0][2] = curl[1];
5854  grad[2][0] = -curl[1];
5855  grad[1][0] = curl[2];
5856  grad[0][1] = -curl[2];
5857  break;
5858  default:
5859  Assert(false, ExcNotImplemented());
5860  }
5861  submit_gradient(grad, q_point);
5862 }
5863 
5864 
5865 /*-------------------- FEEvaluationAccess scalar for 1d ---------------------*/
5866 
5867 
5868 template <typename Number, bool is_face>
5870  const MatrixFree<1, Number> &data_in,
5871  const unsigned int dof_no,
5872  const unsigned int first_selected_component,
5873  const unsigned int quad_no_in,
5874  const unsigned int fe_degree,
5875  const unsigned int n_q_points,
5876  const bool is_interior_face)
5877  : FEEvaluationBase<1, 1, Number, is_face>(data_in,
5878  dof_no,
5879  first_selected_component,
5880  quad_no_in,
5881  fe_degree,
5882  n_q_points,
5883  is_interior_face)
5884 {}
5885 
5886 
5887 
5888 template <typename Number, bool is_face>
5889 template <int n_components_other>
5891  const Mapping<1> & mapping,
5892  const FiniteElement<1> &fe,
5893  const Quadrature<1> & quadrature,
5894  const UpdateFlags update_flags,
5895  const unsigned int first_selected_component,
5897  : FEEvaluationBase<1, 1, Number, is_face>(mapping,
5898  fe,
5899  quadrature,
5900  update_flags,
5901  first_selected_component,
5902  other)
5903 {}
5904 
5905 
5906 
5907 template <typename Number, bool is_face>
5910  : FEEvaluationBase<1, 1, Number, is_face>(other)
5911 {}
5912 
5913 
5914 
5915 template <typename Number, bool is_face>
5919 {
5921  return *this;
5922 }
5923 
5924 
5925 
5926 template <typename Number, bool is_face>
5927 inline DEAL_II_ALWAYS_INLINE VectorizedArray<Number>
5929  const unsigned int dof) const
5930 {
5931  AssertIndexRange(dof, this->data->dofs_per_component_on_cell);
5932  return this->values_dofs[0][dof];
5933 }
5934 
5935 
5936 
5937 template <typename Number, bool is_face>
5938 inline DEAL_II_ALWAYS_INLINE VectorizedArray<Number>
5940  const unsigned int q_point) const
5941 {
5942  Assert(this->values_quad_initialized == true,
5944  AssertIndexRange(q_point, this->n_quadrature_points);
5945  return this->values_quad[0][q_point];
5946 }
5947 
5948 
5949 
5950 template <typename Number, bool is_face>
5951 inline DEAL_II_ALWAYS_INLINE Tensor<1, 1, VectorizedArray<Number>>
5953  const unsigned int q_point) const
5954 {
5955  // could use the base class gradient, but that involves too many inefficient
5956  // initialization operations on tensors
5957 
5958  Assert(this->gradients_quad_initialized == true,
5960  AssertIndexRange(q_point, this->n_quadrature_points);
5961 
5963  this->cell_type == internal::MatrixFreeFunctions::general ?
5964  this->jacobian[q_point] :
5965  this->jacobian[0];
5966 
5968  grad_out[0] = jac[0][0] * this->gradients_quad[0][0][q_point];
5969 
5970  return grad_out;
5971 }
5972 
5973 
5974 
5975 template <typename Number, bool is_face>
5976 inline DEAL_II_ALWAYS_INLINE VectorizedArray<Number>
5978  const unsigned int q_point) const
5979 {
5980  return BaseClass::get_normal_derivative(q_point)[0];
5981 }
5982 
5983 
5984 
5985 template <typename Number, bool is_face>
5986 inline DEAL_II_ALWAYS_INLINE Tensor<2, 1, VectorizedArray<Number>>
5988  const unsigned int q_point) const
5989 {
5990  return BaseClass::get_hessian(q_point)[0];
5991 }
5992 
5993 
5994 
5995 template <typename Number, bool is_face>
5996 inline DEAL_II_ALWAYS_INLINE Tensor<1, 1, VectorizedArray<Number>>
5998  const unsigned int q_point) const
5999 {
6000  return BaseClass::get_hessian_diagonal(q_point)[0];
6001 }
6002 
6003 
6004 
6005 template <typename Number, bool is_face>
6006 inline DEAL_II_ALWAYS_INLINE VectorizedArray<Number>
6008  const unsigned int q_point) const
6009 {
6010  return BaseClass::get_laplacian(q_point)[0];
6011 }
6012 
6013 
6014 
6015 template <typename Number, bool is_face>
6016 inline DEAL_II_ALWAYS_INLINE void DEAL_II_ALWAYS_INLINE
6018  const VectorizedArray<Number> val_in,
6019  const unsigned int dof)
6020 {
6021 # ifdef DEBUG
6022  this->dof_values_initialized = true;
6023  AssertIndexRange(dof, this->data->dofs_per_component_on_cell);
6024 # endif
6025  this->values_dofs[0][dof] = val_in;
6026 }
6027 
6028 
6029 
6030 template <typename Number, bool is_face>
6031 inline DEAL_II_ALWAYS_INLINE void
6033  const VectorizedArray<Number> val_in,
6034  const unsigned int q_point)
6035 {
6036 # ifdef DEBUG
6038  AssertIndexRange(q_point, this->n_quadrature_points);
6039  this->values_quad_submitted = true;
6040 # endif
6041  if (this->cell_type == internal::MatrixFreeFunctions::general)
6042  {
6043  const VectorizedArray<Number> JxW = this->J_value[q_point];
6044  this->values_quad[0][q_point] = val_in * JxW;
6045  }
6046  else // if (this->cell_type == internal::MatrixFreeFunctions::general)
6047  {
6048  const VectorizedArray<Number> JxW =
6049  this->J_value[0] * this->quadrature_weights[q_point];
6050  this->values_quad[0][q_point] = val_in * JxW;
6051  }
6052 }
6053 
6054 
6055 
6056 template <typename Number, bool is_face>
6057 inline DEAL_II_ALWAYS_INLINE void
6059  const Tensor<1, 1, VectorizedArray<Number>> val_in,
6060  const unsigned int q_point)
6061 {
6062  submit_value(val_in[0], q_point);
6063 }
6064 
6065 
6066 
6067 template <typename Number, bool is_face>
6068 inline DEAL_II_ALWAYS_INLINE void
6070  const Tensor<1, 1, VectorizedArray<Number>> grad_in,
6071  const unsigned int q_point)
6072 {
6073  submit_gradient(grad_in[0], q_point);
6074 }
6075 
6076 
6077 
6078 template <typename Number, bool is_face>
6079 inline DEAL_II_ALWAYS_INLINE void
6081  const VectorizedArray<Number> grad_in,
6082  const unsigned int q_point)
6083 {
6084 # ifdef DEBUG
6086  AssertIndexRange(q_point, this->n_quadrature_points);
6087  this->gradients_quad_submitted = true;
6088 # endif
6089 
6091  this->cell_type == internal::MatrixFreeFunctions::general ?
6092  this->jacobian[q_point] :
6093  this->jacobian[0];
6094  const VectorizedArray<Number> JxW =
6095  this->cell_type == internal::MatrixFreeFunctions::general ?
6096  this->J_value[q_point] :
6097  this->J_value[0] * this->quadrature_weights[q_point];
6098 
6099  this->gradients_quad[0][0][q_point] = jac[0][0] * grad_in * JxW;
6100 }
6101 
6102 
6103 
6104 template <typename Number, bool is_face>
6105 inline DEAL_II_ALWAYS_INLINE void
6107  const VectorizedArray<Number> grad_in,
6108  const unsigned int q_point)
6109 {
6111  grad[0] = grad_in;
6112  BaseClass::submit_normal_derivative(grad, q_point);
6113 }
6114 
6115 
6116 
6117 template <typename Number, bool is_face>
6118 inline DEAL_II_ALWAYS_INLINE void
6120  const Tensor<1, 1, VectorizedArray<Number>> grad_in,
6121  const unsigned int q_point)
6122 {
6123  BaseClass::submit_normal_derivative(grad_in, q_point);
6124 }
6125 
6126 
6127 
6128 template <typename Number, bool is_face>
6131 {
6132  return BaseClass::integrate_value()[0];
6133 }
6134 
6135 
6136 
6137 /*-------------------------- FEEvaluation -----------------------------------*/
6138 
6139 
6140 template <int dim,
6141  int fe_degree,
6142  int n_q_points_1d,
6143  int n_components_,
6144  typename Number>
6146  FEEvaluation(const MatrixFree<dim, Number> &data_in,
6147  const unsigned int fe_no,
6148  const unsigned int quad_no,
6149  const unsigned int first_selected_component)
6150  : BaseClass(data_in,
6151  fe_no,
6152  first_selected_component,
6153  quad_no,
6154  fe_degree,
6156  , dofs_per_component(this->data->dofs_per_component_on_cell)
6157  , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6158  , n_q_points(this->data->n_q_points)
6159 {
6160  check_template_arguments(fe_no, 0);
6161 }
6162 
6163 
6164 
6165 template <int dim,
6166  int fe_degree,
6167  int n_q_points_1d,
6168  int n_components_,
6169  typename Number>
6171  FEEvaluation(const Mapping<dim> & mapping,
6172  const FiniteElement<dim> &fe,
6173  const Quadrature<1> & quadrature,
6174  const UpdateFlags update_flags,
6175  const unsigned int first_selected_component)
6176  : BaseClass(mapping,
6177  fe,
6178  quadrature,
6179  update_flags,
6180  first_selected_component,
6181  static_cast<FEEvaluationBase<dim, 1, Number, false> *>(nullptr))
6182  , dofs_per_component(this->data->dofs_per_component_on_cell)
6183  , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6184  , n_q_points(this->data->n_q_points)
6185 {
6186  check_template_arguments(numbers::invalid_unsigned_int, 0);
6187 }
6188 
6189 
6190 
6191 template <int dim,
6192  int fe_degree,
6193  int n_q_points_1d,
6194  int n_components_,
6195  typename Number>
6198  const Quadrature<1> & quadrature,
6199  const UpdateFlags update_flags,
6200  const unsigned int first_selected_component)
6201  : BaseClass(StaticMappingQ1<dim>::mapping,
6202  fe,
6203  quadrature,
6204  update_flags,
6205  first_selected_component,
6206  static_cast<FEEvaluationBase<dim, 1, Number, false> *>(nullptr))
6207  , dofs_per_component(this->data->dofs_per_component_on_cell)
6208  , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6209  , n_q_points(this->data->n_q_points)
6210 {
6211  check_template_arguments(numbers::invalid_unsigned_int, 0);
6212 }
6213 
6214 
6215 
6216 template <int dim,
6217  int fe_degree,
6218  int n_q_points_1d,
6219  int n_components_,
6220  typename Number>
6221 template <int n_components_other>
6225  const unsigned int first_selected_component)
6226  : BaseClass(other.mapped_geometry->get_fe_values().get_mapping(),
6227  fe,
6228  other.mapped_geometry->get_quadrature(),
6229  other.mapped_geometry->get_fe_values().get_update_flags(),
6230  first_selected_component,
6231  &other)
6232  , dofs_per_component(this->data->dofs_per_component_on_cell)
6233  , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6234  , n_q_points(this->data->n_q_points)
6235 {
6236  check_template_arguments(numbers::invalid_unsigned_int, 0);
6237 }
6238 
6239 
6240 
6241 template <int dim,
6242  int fe_degree,
6243  int n_q_points_1d,
6244  int n_components_,
6245  typename Number>
6247  FEEvaluation(const FEEvaluation &other)
6248  : BaseClass(other)
6249  , dofs_per_component(this->data->dofs_per_component_on_cell)
6250  , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6251  , n_q_points(this->data->n_q_points)
6252 {
6253  check_template_arguments(numbers::invalid_unsigned_int, 0);
6254 }
6255 
6256 
6257 
6258 template <int dim,
6259  int fe_degree,
6260  int n_q_points_1d,
6261  int n_components_,
6262  typename Number>
6265 operator=(const FEEvaluation &other)
6266 {
6267  BaseClass::operator=(other);
6268  check_template_arguments(numbers::invalid_unsigned_int, 0);
6269  return *this;
6270 }
6271 
6272 
6273 
6274 template <int dim,
6275  int fe_degree,
6276  int n_q_points_1d,
6277  int n_components_,
6278  typename Number>
6279 inline void
6281  check_template_arguments(const unsigned int dof_no,
6282  const unsigned int first_selected_component)
6283 {
6284  (void)dof_no;
6285  (void)first_selected_component;
6286 
6287 # ifdef DEBUG
6288  // print error message when the dimensions do not match. Propose a possible
6289  // fix
6290  if ((static_cast<unsigned int>(fe_degree) != numbers::invalid_unsigned_int &&
6291  static_cast<unsigned int>(fe_degree) != this->data->fe_degree) ||
6292  n_q_points != this->n_quadrature_points)
6293  {
6294  std::string message =
6295  "-------------------------------------------------------\n";
6296  message += "Illegal arguments in constructor/wrong template arguments!\n";
6297  message += " Called --> FEEvaluation<dim,";
6298  message += Utilities::int_to_string(fe_degree) + ",";
6299  message += Utilities::int_to_string(n_q_points_1d);
6300  message += "," + Utilities::int_to_string(n_components);
6301  message += ",Number>(data";
6302  if (first_selected_component != numbers::invalid_unsigned_int)
6303  {
6304  message += ", " + Utilities::int_to_string(dof_no) + ", ";
6305  message += Utilities::int_to_string(this->quad_no) + ", ";
6306  message += Utilities::int_to_string(first_selected_component);
6307  }
6308  message += ")\n";
6309 
6310  // check whether some other vector component has the correct number of
6311  // points
6312  unsigned int proposed_dof_comp = numbers::invalid_unsigned_int,
6313  proposed_fe_comp = numbers::invalid_unsigned_int,
6314  proposed_quad_comp = numbers::invalid_unsigned_int;
6315  if (dof_no != numbers::invalid_unsigned_int)
6316  {
6317  if (static_cast<unsigned int>(fe_degree) == this->data->fe_degree)
6318  {
6319  proposed_dof_comp = dof_no;
6320  proposed_fe_comp = first_selected_component;
6321  }
6322  else
6323  for (unsigned int no = 0; no < this->matrix_info->n_components();
6324  ++no)
6325  for (unsigned int nf = 0;
6326  nf < this->matrix_info->n_base_elements(no);
6327  ++nf)
6328  if (this->matrix_info
6329  ->get_shape_info(no, 0, nf, this->active_fe_index, 0)
6330  .fe_degree == static_cast<unsigned int>(fe_degree))
6331  {
6332  proposed_dof_comp = no;
6333  proposed_fe_comp = nf;
6334  break;
6335  }
6336  if (n_q_points ==
6337  this->mapping_data->descriptor[this->active_quad_index]
6338  .n_q_points)
6339  proposed_quad_comp = this->quad_no;
6340  else
6341  for (unsigned int no = 0;
6342  no < this->matrix_info->get_mapping_info().cell_data.size();
6343  ++no)
6344  if (this->matrix_info->get_mapping_info()
6345  .cell_data[no]
6346  .descriptor[this->active_quad_index]
6347  .n_q_points == n_q_points)
6348  {
6349  proposed_quad_comp = no;
6350  break;
6351  }
6352  }
6353  if (proposed_dof_comp != numbers::invalid_unsigned_int &&
6354  proposed_quad_comp != numbers::invalid_unsigned_int)
6355  {
6356  if (proposed_dof_comp != first_selected_component)
6357  message += "Wrong vector component selection:\n";
6358  else
6359  message += "Wrong quadrature formula selection:\n";
6360  message += " Did you mean FEEvaluation<dim,";
6361  message += Utilities::int_to_string(fe_degree) + ",";
6362  message += Utilities::int_to_string(n_q_points_1d);
6363  message += "," + Utilities::int_to_string(n_components);
6364  message += ",Number>(data";
6365  if (dof_no != numbers::invalid_unsigned_int)
6366  {
6367  message +=
6368  ", " + Utilities::int_to_string(proposed_dof_comp) + ", ";
6369  message += Utilities::int_to_string(proposed_quad_comp) + ", ";
6370  message += Utilities::int_to_string(proposed_fe_comp);
6371  }
6372  message += ")?\n";
6373  std::string correct_pos;
6374  if (proposed_dof_comp != dof_no)
6375  correct_pos = " ^ ";
6376  else
6377  correct_pos = " ";
6378  if (proposed_quad_comp != this->quad_no)
6379  correct_pos += " ^ ";
6380  else
6381  correct_pos += " ";
6382  if (proposed_fe_comp != first_selected_component)
6383  correct_pos += " ^\n";
6384  else
6385  correct_pos += " \n";
6386  message += " " +
6387  correct_pos;
6388  }
6389  // ok, did not find the numbers specified by the template arguments in
6390  // the given list. Suggest correct template arguments
6391  const unsigned int proposed_n_q_points_1d = static_cast<unsigned int>(
6392  std::pow(1.001 * this->n_quadrature_points, 1. / dim));
6393  message += "Wrong template arguments:\n";
6394  message += " Did you mean FEEvaluation<dim,";
6395  message += Utilities::int_to_string(this->data->fe_degree) + ",";
6396  message += Utilities::int_to_string(proposed_n_q_points_1d);
6397  message += "," + Utilities::int_to_string(n_components);
6398  message += ",Number>(data";
6399  if (dof_no != numbers::invalid_unsigned_int)
6400  {
6401  message += ", " + Utilities::int_to_string(dof_no) + ", ";
6402  message += Utilities::int_to_string(this->quad_no);
6403  message += ", " + Utilities::int_to_string(first_selected_component);
6404  }
6405  message += ")?\n";
6406  std::string correct_pos;
6407  if (this->data->fe_degree != static_cast<unsigned int>(fe_degree))
6408  correct_pos = " ^";
6409  else
6410  correct_pos = " ";
6411  if (proposed_n_q_points_1d != n_q_points_1d)
6412  correct_pos += " ^\n";
6413  else
6414  correct_pos += " \n";
6415  message += " " + correct_pos;
6416 
6417  Assert(static_cast<unsigned int>(fe_degree) == this->data->fe_degree &&
6418  n_q_points == this->n_quadrature_points,
6419  ExcMessage(message));
6420  }
6421  if (dof_no != numbers::invalid_unsigned_int)
6423  n_q_points,
6424  this->mapping_data->descriptor[this->active_quad_index].n_q_points);
6425 # endif
6426 }
6427 
6428 
6429 
6430 template <int dim,
6431  int fe_degree,
6432  int n_q_points_1d,
6433  int n_components_,
6434  typename Number>
6435 inline void
6437  const unsigned int cell_index)
6438 {
6439  Assert(this->mapped_geometry == nullptr,
6440  ExcMessage("FEEvaluation was initialized without a matrix-free object."
6441  " Integer indexing is not possible"));
6442  if (this->mapped_geometry != nullptr)
6443  return;
6444 
6445  Assert(this->dof_info != nullptr, ExcNotInitialized());
6446  Assert(this->mapping_data != nullptr, ExcNotInitialized());
6447  this->cell = cell_index;
6448  this->cell_type =
6449  this->matrix_info->get_mapping_info().get_cell_type(cell_index);
6450 
6451  const unsigned int offsets =
6452  this->mapping_data->data_index_offsets[cell_index];
6453  this->jacobian = &this->mapping_data->jacobians[0][offsets];
6454  this->J_value = &this->mapping_data->JxW_values[offsets];
6455 
6456 # ifdef DEBUG
6457  this->dof_values_initialized = false;
6458  this->values_quad_initialized = false;
6459  this->gradients_quad_initialized = false;
6460  this->hessians_quad_initialized = false;
6461 # endif
6462 }
6463 
6464 
6465 
6466 template <int dim,
6467  int fe_degree,
6468  int n_q_points_1d,
6469  int n_components_,
6470  typename Number>
6471 template <typename DoFHandlerType, bool level_dof_access>
6472 inline void
6475 {
6476  Assert(this->matrix_info == nullptr,
6477  ExcMessage("Cannot use initialization from cell iterator if "
6478  "initialized from MatrixFree object. Use variant for "
6479  "on the fly computation with arguments as for FEValues "
6480  "instead"));
6481  Assert(this->mapped_geometry.get() != nullptr, ExcNotInitialized());
6482  this->mapped_geometry->reinit(
6483  static_cast<typename Triangulation<dim>::cell_iterator>(cell));
6484  this->local_dof_indices.resize(cell->get_fe().dofs_per_cell);
6485  if (level_dof_access)
6486  cell->get_mg_dof_indices(this->local_dof_indices);
6487  else
6488  cell->get_dof_indices(this->local_dof_indices);
6489 }
6490 
6491 
6492 
6493 template <int dim,
6494  int fe_degree,
6495  int n_q_points_1d,
6496  int n_components_,
6497  typename Number>
6498 inline void
6500  const typename Triangulation<dim>::cell_iterator &cell)
6501 {
6502  Assert(this->matrix_info == 0,
6503  ExcMessage("Cannot use initialization from cell iterator if "
6504  "initialized from MatrixFree object. Use variant for "
6505  "on the fly computation with arguments as for FEValues "
6506  "instead"));
6507  Assert(this->mapped_geometry.get() != 0, ExcNotInitialized());
6508  this->mapped_geometry->reinit(cell);
6509 }
6510 
6511 
6512 
6513 template <int dim,
6514  int fe_degree,
6515  int n_q_points_1d,
6516  int n_components_,
6517  typename Number>
6520  quadrature_point(const unsigned int q) const
6521 {
6522  if (this->matrix_info == nullptr)
6523  {
6524  Assert((this->mapped_geometry->get_fe_values().get_update_flags() |
6526  ExcNotInitialized());
6527  }
6528  else
6529  {
6531  ExcNotInitialized());
6532  }
6533 
6534  AssertIndexRange(q, n_q_points);
6535 
6536  const unsigned int n_q_points_1d_actual =
6537  fe_degree == -1 ? this->data->n_q_points_1d : n_q_points_1d;
6538 
6539  // Cartesian mesh: not all quadrature points are stored, only the
6540  // diagonal. Hence, need to find the tensor product index and retrieve the
6541  // value from that
6542  const Point<dim, VectorizedArray<Number>> *quadrature_points =
6544  [this->mapping_data->quadrature_point_offsets[this->cell]];
6545  if (this->cell_type == internal::MatrixFreeFunctions::cartesian)
6546  {
6548  switch (dim)
6549  {
6550  case 1:
6551  return quadrature_points[q];
6552  case 2:
6553  point[0] = quadrature_points[q % n_q_points_1d_actual][0];
6554  point[1] = quadrature_points[q / n_q_points_1d_actual][1];
6555  return point;
6556  case 3:
6557  point[0] = quadrature_points[q % n_q_points_1d_actual][0];
6558  point[1] = quadrature_points[(q / n_q_points_1d_actual) %
6559  n_q_points_1d_actual][1];
6560  point[2] = quadrature_points[q / (n_q_points_1d_actual *
6561  n_q_points_1d_actual)][2];
6562  return point;
6563  default:
6564  Assert(false, ExcNotImplemented());
6565  return point;
6566  }
6567  }
6568  // all other cases: just return the respective data as it is fully stored
6569  else
6570  return quadrature_points[q];
6571 }
6572 
6573 
6574 
6575 template <int dim,
6576  int fe_degree,
6577  int n_q_points_1d,
6578  int n_components_,
6579  typename Number>
6580 inline void
6582  const bool evaluate_values,
6583  const bool evaluate_gradients,
6584  const bool evaluate_hessians)
6585 {
6586  Assert(this->dof_values_initialized == true,
6588  evaluate(this->values_dofs[0],
6589  evaluate_values,
6590  evaluate_gradients,
6591  evaluate_hessians);
6592 }
6593 
6594 
6595 
6596 template <int dim,
6597  int fe_degree,
6598  int n_q_points_1d,
6599  int n_components_,
6600  typename Number>
6601 inline void
6603  const VectorizedArray<Number> *values_array,
6604  const bool evaluate_values,
6605  const bool evaluate_gradients,
6606  const bool evaluate_hessians)
6607 {
6609  dim,
6610  fe_degree,
6611  n_q_points_1d,
6612  n_components,
6613  VectorizedArray<Number>>::evaluate(*this->data,
6614  const_cast<VectorizedArray<Number> *>(
6615  values_array),
6616  this->values_quad[0],
6617  this->gradients_quad[0][0],
6618  this->hessians_quad[0][0],
6619  this->scratch_data,
6620  evaluate_values,
6621  evaluate_gradients,
6622  evaluate_hessians);
6623 
6624 # ifdef DEBUG
6625  if (evaluate_values == true)
6626  this->values_quad_initialized = true;
6627  if (evaluate_gradients == true)
6628  this->gradients_quad_initialized = true;
6629  if (evaluate_hessians == true)
6630  this->hessians_quad_initialized = true;
6631 # endif
6632 }
6633 
6634 
6635 
6636 template <int dim,
6637  int fe_degree,
6638  int n_q_points_1d,
6639  int n_components_,
6640  typename Number>
6641 template <typename VectorType>
6642 inline void
6644  gather_evaluate(const VectorType &input_vector,
6645  const bool evaluate_values,
6646  const bool evaluate_gradients,
6647  const bool evaluate_hessians)
6648 {
6649  this->read_dof_values(input_vector);
6650  evaluate(this->begin_dof_values(),
6651  evaluate_values,
6652  evaluate_gradients,
6653  evaluate_hessians);
6654 }
6655 
6656 
6657 
6658 template <int dim,
6659  int fe_degree,
6660  int n_q_points_1d,
6661  int n_components_,
6662  typename Number>
6663 inline void
6665  const bool integrate_values,
6666  const bool integrate_gradients)
6667 {
6668  integrate(integrate_values, integrate_gradients, this->values_dofs[0]);
6669 
6670 # ifdef DEBUG
6671  this->dof_values_initialized = true;
6672 # endif
6673 }
6674 
6675 
6676 
6677 template <int dim,
6678  int fe_degree,
6679  int n_q_points_1d,
6680  int n_components_,
6681  typename Number>
6682 inline void
6684  const bool integrate_values,
6685  const bool integrate_gradients,
6686  VectorizedArray<Number> *values_array)
6687 {
6688  if (integrate_values == true)
6689  Assert(this->values_quad_submitted == true,
6691  if (integrate_gradients == true)
6692  Assert(this->gradients_quad_submitted == true,
6694  Assert(this->matrix_info != nullptr ||
6695  this->mapped_geometry->is_initialized(),
6696  ExcNotInitialized());
6697 
6698  SelectEvaluator<dim,
6699  fe_degree,
6700  n_q_points_1d,
6701  n_components,
6703  values_array,
6704  this->values_quad[0],
6705  this
6706  ->gradients_quad[0][0],
6707  this->scratch_data,
6708  integrate_values,
6709  integrate_gradients);
6710 
6711 # ifdef DEBUG
6712  this->dof_values_initialized = true;
6713 # endif
6714 }
6715 
6716 
6717 
6718 template <int dim,
6719  int fe_degree,
6720  int n_q_points_1d,
6721  int n_components_,
6722  typename Number>
6723 template <typename VectorType>
6724 inline void
6726  integrate_scatter(const bool integrate_values,
6727  const bool integrate_gradients,
6728  VectorType &destination)
6729 {
6730  integrate(integrate_values, integrate_gradients, this->begin_dof_values());
6731  this->distribute_local_to_global(destination);
6732 }
6733 
6734 
6735 
6736 /*-------------------------- FEFaceEvaluation ---------------------------*/
6737 
6738 
6739 
6740 template <int dim,
6741  int fe_degree,
6742  int n_q_points_1d,
6743  int n_components_,
6744  typename Number>
6746  FEFaceEvaluation(const MatrixFree<dim, Number> &matrix_free,
6747  const bool is_interior_face,
6748  const unsigned int dof_no,
6749  const unsigned int quad_no,
6750  const unsigned int first_selected_component)
6751  : BaseClass(matrix_free,
6752  dof_no,
6753  first_selected_component,
6754  quad_no,
6755  fe_degree,
6757  is_interior_face)
6758  , dofs_per_component(this->data->dofs_per_component_on_cell)
6759  , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6760  , n_q_points(this->data->n_q_points_face)
6761 {}
6762 
6763 
6764 
6765 template <int dim,
6766  int fe_degree,
6767  int n_q_points_1d,
6768  int n_components_,
6769  typename Number>
6772 {}
6773 
6774 
6775 
6776 template <int dim,
6777  int fe_degree,
6778  int n_q_points_1d,
6779  int n_components_,
6780  typename Number>
6781 inline void
6783  const unsigned int face_index)
6784 {
6785  Assert(this->mapped_geometry == nullptr,
6786  ExcMessage("FEEvaluation was initialized without a matrix-free object."
6787  " Integer indexing is not possible"));
6788  if (this->mapped_geometry != nullptr)
6789  return;
6790 
6791  this->cell = face_index;
6792  this->dof_access_index =
6793  this->is_interior_face ?
6796  Assert(this->mapping_data != nullptr, ExcNotInitialized());
6797  const unsigned int n_vectors = VectorizedArray<Number>::n_array_elements;
6799  this->matrix_info->get_face_info(face_index);
6800  if (face_index >=
6801  this->matrix_info->get_task_info().face_partition_data.back() &&
6802  face_index <
6803  this->matrix_info->get_task_info().boundary_partition_data.back())
6804  Assert(this->is_interior_face,
6805  ExcMessage("Boundary faces do not have a neighbor"));
6806 
6807  this->face_no =
6808  (this->is_interior_face ? faces.interior_face_no : faces.exterior_face_no);
6809  this->subface_index = faces.subface_index;
6810  if (this->is_interior_face == true)
6811  {
6813  if (faces.face_orientation > 8)
6814  this->face_orientation = faces.face_orientation - 8;
6815  else
6816  this->face_orientation = 0;
6817  }
6818  else
6819  {
6820  if (faces.face_orientation < 8)
6821  this->face_orientation = faces.face_orientation;
6822  else
6823  this->face_orientation = 0;
6824  }
6825 
6826  this->values_quad_submitted = false;
6827 
6828  this->cell_type = this->matrix_info->get_mapping_info().face_type[face_index];
6829  const unsigned int offsets =
6830  this->mapping_data->data_index_offsets[face_index];
6831  this->J_value = &this->mapping_data->JxW_values[offsets];
6832  this->normal_vectors = &this->mapping_data->normal_vectors[offsets];
6833  this->jacobian =
6834  &this->mapping_data->jacobians[!this->is_interior_face][offsets];
6835  this->normal_x_jacobian =
6836  &this->mapping_data
6837  ->normals_times_jacobians[!this->is_interior_face][offsets];
6838 
6839 # ifdef DEBUG
6840  this->dof_values_initialized = false;
6841  this->values_quad_initialized = false;
6842  this->gradients_quad_initialized = false;
6843  this->hessians_quad_initialized = false;
6844 # endif
6845 }
6846 
6847 
6848 
6849 template <int dim,
6850  int fe_degree,
6851  int n_q_points_1d,
6852  int n_components_,
6853  typename Number>
6854 inline void
6856  const unsigned int cell_index,
6857  const unsigned int face_number)
6858 {
6859  Assert(
6860  this->quad_no <
6861  this->matrix_info->get_mapping_info().face_data_by_cells.size(),
6862  ExcMessage(
6863  "You must set MatrixFree::AdditionalData::mapping_update_flags_faces_by_cells to use the present reinit method."));
6865  AssertIndexRange(cell_index,
6866  this->matrix_info->get_mapping_info().cell_type.size());
6867  Assert(this->mapped_geometry == nullptr,
6868  ExcMessage("FEEvaluation was initialized without a matrix-free object."
6869  " Integer indexing is not possible"));
6870  Assert(this->is_interior_face == true,
6871  ExcMessage(
6872  "Cell-based FEFaceEvaluation::reinit only possible for the "
6873  "interior face with second argument to constructor as true"));
6874  if (this->mapped_geometry != nullptr)
6875  return;
6876  Assert(this->matrix_info != nullptr, ExcNotInitialized());
6877 
6878  this->cell_type = this->matrix_info->get_mapping_info().cell_type[cell_index];
6879  this->cell = cell_index;
6880  this->face_orientation = 0;
6882  this->face_no = face_number;
6883  this->dof_access_index =
6885 
6886  const unsigned int offsets =
6887  this->matrix_info->get_mapping_info()
6888  .face_data_by_cells[this->quad_no]
6889  .data_index_offsets[cell_index * GeometryInfo<dim>::faces_per_cell +
6890  face_number];
6891  AssertIndexRange(offsets,
6892  this->matrix_info->get_mapping_info()
6893  .face_data_by_cells[this->quad_no]
6894  .JxW_values.size());
6895  this->J_value = &this->matrix_info->get_mapping_info()
6896  .face_data_by_cells[this->quad_no]
6897  .JxW_values[offsets];
6898  this->normal_vectors = &this->matrix_info->get_mapping_info()
6899  .face_data_by_cells[this->quad_no]
6900  .normal_vectors[offsets];
6901  this->jacobian = &this->matrix_info->get_mapping_info()
6902  .face_data_by_cells[this->quad_no]
6903  .jacobians[0][offsets];
6904  this->normal_x_jacobian = &this->matrix_info->get_mapping_info()
6905  .face_data_by_cells[this->quad_no]
6906  .normals_times_jacobians[0][offsets];
6907 
6908 # ifdef DEBUG
6909  this->dof_values_initialized = false;
6910  this->values_quad_initialized = false;
6911  this->gradients_quad_initialized = false;
6912  this->hessians_quad_initialized = false;
6913 # endif
6914 }
6915 
6916 
6917 
6918 template <int dim,
6919  int fe_degree,
6920  int n_q_points_1d,
6921  int n_components,
6922  typename Number>
6923 inline void
6925  const bool evaluate_values,
6926  const bool evaluate_gradients)
6927 {
6929 
6930  evaluate(this->values_dofs[0], evaluate_values, evaluate_gradients);
6931 }
6932 
6933 
6934 
6935 template <int dim,
6936  int fe_degree,
6937  int n_q_points_1d,
6938  int n_components,
6939  typename Number>
6940 inline void
6942  const VectorizedArray<Number> *values_array,
6943  const bool evaluate_values,
6944  const bool evaluate_gradients)
6945 {
6946  if (!(evaluate_values + evaluate_gradients))
6947  return;
6948 
6949  constexpr unsigned int static_dofs_per_face =
6950  fe_degree > -1 ? Utilities::pow(fe_degree + 1, dim - 1) :
6951  numbers::invalid_unsigned_int;
6952  const unsigned int dofs_per_face =
6953  fe_degree > -1 ? static_dofs_per_face :
6954  Utilities::pow(this->data->fe_degree + 1, dim - 1);
6955 
6956  // we allocate small amounts of data on the stack to signal the compiler
6957  // that this temporary data is only needed for the calculations but the
6958  // final results can be discarded and need not be written back to
6959  // memory. For large sizes or when the dofs per face is not a compile-time
6960  // constant, however, we want to go to the heap in the `scratch_data`
6961  // variable to not risk a stack overflow.
6962  constexpr unsigned int stack_array_size_threshold = 100;
6963 
6965  temp_data[static_dofs_per_face < stack_array_size_threshold ?
6966  n_components * 2 * static_dofs_per_face :
6967  1];
6968  VectorizedArray<Number> *temp1;
6969  if (static_dofs_per_face < stack_array_size_threshold)
6970  temp1 = &temp_data[0];
6971  else
6972  temp1 = this->scratch_data;
6973 
6974  internal::FEFaceNormalEvaluationImpl<dim,
6975  fe_degree,
6976  n_components,
6978  template interpolate<true, false>(
6979  *this->data, values_array, temp1, evaluate_gradients, this->face_no);
6980 
6981  const unsigned int n_q_points_1d_actual = fe_degree > -1 ? n_q_points_1d : 0;
6982  if (fe_degree > -1 &&
6984  this->data->element_type <=
6985  internal::MatrixFreeFunctions::tensor_symmetric)
6986  internal::FEFaceEvaluationImpl<
6987  true,
6988  dim,
6989  fe_degree,
6990  n_q_points_1d_actual,
6991  n_components,
6992  VectorizedArray<Number>>::evaluate_in_face(*this->data,
6993  temp1,
6994  this->begin_values(),
6995  this->begin_gradients(),
6996  this->scratch_data +
6997  2 * n_components *
6998  dofs_per_face,
6999  evaluate_values,
7000  evaluate_gradients,
7001  this->subface_index);
7002  else
7003  internal::FEFaceEvaluationImpl<
7004  false,
7005  dim,
7006  fe_degree,
7007  n_q_points_1d_actual,
7008  n_components,
7009  VectorizedArray<Number>>::evaluate_in_face(*this->data,
7010  temp1,
7011  this->begin_values(),
7012  this->begin_gradients(),
7013  this->scratch_data +
7014  2 * n_components *
7015  dofs_per_face,
7016  evaluate_values,
7017  evaluate_gradients,
7018  this->subface_index);
7019 
7020  if (this->face_orientation)
7021  adjust_for_face_orientation(false, evaluate_values, evaluate_gradients);
7022 
7023 # ifdef DEBUG
7024  if (evaluate_values == true)
7025  this->values_quad_initialized = true;
7026  if (evaluate_gradients == true)
7027  this->gradients_quad_initialized = true;
7028 # endif
7029 }
7030 
7031 
7032 
7033 template <int dim,
7034  int fe_degree,
7035  int n_q_points_1d,
7036  int n_components,
7037  typename Number>
7038 inline void
7040  integrate(const bool integrate_values, const bool integrate_gradients)
7041 {
7042  integrate(integrate_values, integrate_gradients, this->values_dofs[0]);
7043 
7044 # ifdef DEBUG
7045  this->dof_values_initialized = true;
7046 # endif
7047 }
7048 
7049 
7050 
7051 template <int dim,
7052  int fe_degree,
7053  int n_q_points_1d,
7054  int n_components,
7055  typename Number>
7056 inline void
7058  integrate(const bool integrate_values,
7059  const bool integrate_gradients,
7060  VectorizedArray<Number> *values_array)
7061 {
7062  if (!(integrate_values + integrate_gradients))
7063  return;
7064 
7065  if (this->face_orientation)
7066  adjust_for_face_orientation(true, integrate_values, integrate_gradients);
7067 
7068  constexpr unsigned int static_dofs_per_face =
7069  fe_degree > -1 ? Utilities::pow(fe_degree + 1, dim - 1) :
7070  numbers::invalid_unsigned_int;
7071  const unsigned int dofs_per_face =
7072  fe_degree > -1 ? static_dofs_per_face :
7073  Utilities::pow(this->data->fe_degree + 1, dim - 1);
7074 
7075  constexpr unsigned int stack_array_size_threshold = 100;
7076 
7078  temp_data[static_dofs_per_face < stack_array_size_threshold ?
7079  n_components * 2 * static_dofs_per_face :
7080  1];
7081  VectorizedArray<Number> *temp1;
7082  if (static_dofs_per_face < stack_array_size_threshold)
7083  temp1 = &temp_data[0];
7084  else
7085  temp1 = this->scratch_data;
7086 
7087  const unsigned int n_q_points_1d_actual = fe_degree > -1 ? n_q_points_1d : 0;
7088  if (fe_degree > -1 &&
7090  this->data->element_type <=
7091  internal::MatrixFreeFunctions::tensor_symmetric)
7092  internal::FEFaceEvaluationImpl<
7093  true,
7094  dim,
7095  fe_degree,
7096  n_q_points_1d_actual,
7097  n_components,
7098  VectorizedArray<Number>>::integrate_in_face(*this->data,
7099  temp1,
7100  this->begin_values(),
7101  this->begin_gradients(),
7102  this->scratch_data +
7103  2 * n_components *
7104  dofs_per_face,
7105  integrate_values,
7106  integrate_gradients,
7107  this->subface_index);
7108  else
7109  internal::FEFaceEvaluationImpl<
7110  false,
7111  dim,
7112  fe_degree,
7113  n_q_points_1d_actual,
7114  n_components,
7115  VectorizedArray<Number>>::integrate_in_face(*this->data,
7116  temp1,
7117  this->begin_values(),
7118  this->begin_gradients(),
7119  this->scratch_data +
7120  2 * n_components *
7121  dofs_per_face,
7122  integrate_values,
7123  integrate_gradients,
7124  this->subface_index);
7125 
7126  internal::FEFaceNormalEvaluationImpl<dim,
7127  fe_degree,
7128  n_components,
7130  template interpolate<false, false>(
7131  *this->data, temp1, values_array, integrate_gradients, this->face_no);
7132 }
7133 
7134 
7135 
7136 template <int dim,
7137  int fe_degree,
7138  int n_q_points_1d,
7139  int n_components_,
7140  typename Number>
7141 template <typename VectorType>
7142 inline void
7144  gather_evaluate(const VectorType &input_vector,
7145  const bool evaluate_values,
7146  const bool evaluate_gradients)
7147 {
7148  const unsigned int side = this->face_no % 2;
7149 
7150  constexpr unsigned int static_dofs_per_face =
7151  fe_degree > -1 ? Utilities::pow(fe_degree + 1, dim - 1) :
7152  numbers::invalid_unsigned_int;
7153  const unsigned int dofs_per_face =
7154  fe_degree > -1 ? static_dofs_per_face :
7155  Utilities::pow(this->data->fe_degree + 1, dim - 1);
7156 
7157  constexpr unsigned int stack_array_size_threshold = 100;
7158 
7160  temp_data[static_dofs_per_face < stack_array_size_threshold ?
7161  n_components_ * 2 * dofs_per_face :
7162  1];
7163  VectorizedArray<Number> *__restrict temp1;
7164  if (static_dofs_per_face < stack_array_size_threshold)
7165  temp1 = &temp_data[0];
7166  else
7167  temp1 = this->scratch_data;
7168 
7169  internal::VectorReader<Number> reader;
7170 
7171  if (this->dof_info
7172  ->index_storage_variants[this->dof_access_index][this->cell] ==
7174  contiguous &&
7175  this->dof_info
7176  ->n_vectorization_lanes_filled[this->dof_access_index][this->cell] ==
7178  ((evaluate_gradients == false &&
7179  this->data->nodal_at_cell_boundaries == true) ||
7180  (this->data->element_type ==
7181  internal::MatrixFreeFunctions::tensor_symmetric_hermite &&
7182  fe_degree > 1)))
7183  {
7184  const unsigned int *indices =
7185  &this->dof_info
7187  [this->cell *
7189  if (evaluate_gradients == true &&
7190  this->data->element_type ==
7191  internal::MatrixFreeFunctions::tensor_symmetric_hermite)
7192  {
7193  // we know that the gradient weights for the Hermite case on the
7194  // right (side==1) are the negative from the value at the left
7195  // (side==0), so we only read out one of them.
7196  const VectorizedArray<Number> grad_weight0 =
7197  (side ? -1. : 1.) *
7198  this->data->shape_data_on_face[0][fe_degree + 1];
7199  const VectorizedArray<Number> grad_weight1 =
7200  (side ? -1. : 1.) *
7201  this->data->shape_data_on_face[0][fe_degree + 2];
7202  AssertDimension(this->data->face_to_cell_index_hermite.size(1),
7203  2 * dofs_per_face);
7204 
7205  const unsigned int *index_array =
7206  &this->data->face_to_cell_index_hermite(this->face_no, 0);
7207  for (unsigned int i = 0; i < dofs_per_face; ++i)
7208  {
7209  const unsigned int ind1 = index_array[2 * i];
7210  const unsigned int ind2 = index_array[2 * i + 1];
7211  for (unsigned int comp = 0; comp < n_components_; ++comp)
7212  {
7213  reader.process_dof_gather(
7214  indices,
7215  input_vector,
7216  ind1 + comp * static_dofs_per_component +
7217  this->dof_info->component_dof_indices_offset
7218  [this->active_fe_index][this->first_selected_component],
7219  temp1[i + 2 * comp * dofs_per_face],
7220  std::integral_constant<
7221  bool,
7222  std::is_same<typename VectorType::value_type,
7223  Number>::value>());
7225  reader.process_dof_gather(
7226  indices,
7227  input_vector,
7228  ind2 + comp * static_dofs_per_component +
7229  this->dof_info->component_dof_indices_offset
7230  [this->active_fe_index][this->first_selected_component],
7231  grad,
7232  std::integral_constant<
7233  bool,
7234  std::is_same<typename VectorType::value_type,
7235  Number>::value>());
7236  temp1[i + dofs_per_face + 2 * comp * dofs_per_face] =
7237  grad_weight0 * temp1[i + 2 * comp * dofs_per_face] +
7238  grad_weight1 * grad;
7239  }
7240  }
7241  }
7242  else
7243  {
7244  AssertDimension(this->data->face_to_cell_index_nodal.size(1),
7245  dofs_per_face);
7246  const unsigned int *index_array =
7247  &this->data->face_to_cell_index_nodal(this->face_no, 0);
7248  for (unsigned int i = 0; i < dofs_per_face; ++i)
7249  for (unsigned int comp = 0; comp < n_components_; ++comp)
7250  {
7251  const unsigned int ind = index_array[i];
7252  reader.process_dof_gather(
7253  indices,
7254  input_vector,
7255  ind + comp * static_dofs_per_component +
7256  this->dof_info->component_dof_indices_offset
7257  [this->active_fe_index][this->first_selected_component],
7258  temp1[i + comp * 2 * dofs_per_face],
7259  std::integral_constant<
7260  bool,
7261  std::is_same<typename VectorType::value_type,
7262  Number>::value>());
7263  }
7264  }
7265  }
7266  else
7267  {
7268  this->read_dof_values(input_vector);
7269  internal::FEFaceNormalEvaluationImpl<dim,
7270  fe_degree,
7271  n_components_,
7273  template interpolate<true, false>(*this->data,
7274  this->values_dofs[0],
7275  temp1,
7276  evaluate_gradients,
7277  this->face_no);
7278  }
7279 
7280  if (fe_degree > -1 &&
7282  this->data->element_type <=
7283  internal::MatrixFreeFunctions::tensor_symmetric)
7284  internal::FEFaceEvaluationImpl<
7285  true,
7286  dim,
7287  fe_degree,
7288  n_q_points_1d,
7289  n_components_,
7290  VectorizedArray<Number>>::evaluate_in_face(*this->data,
7291  temp1,
7292  this->values_quad[0],
7293  this->gradients_quad[0][0],
7294  this->scratch_data +
7295  2 * n_components_ *
7296  dofs_per_face,
7297  evaluate_values,
7298  evaluate_gradients,
7299  this->subface_index);
7300  else
7301  internal::FEFaceEvaluationImpl<
7302  false,
7303  dim,
7304  fe_degree,
7305  n_q_points_1d,
7306  n_components_,
7307  VectorizedArray<Number>>::evaluate_in_face(*this->data,
7308  temp1,
7309  this->values_quad[0],
7310  this->gradients_quad[0][0],
7311  this->scratch_data +
7312  2 * n_components_ *
7313  dofs_per_face,
7314  evaluate_values,
7315  evaluate_gradients,
7316  this->subface_index);
7317 
7318  if (this->face_orientation)
7319  adjust_for_face_orientation(false, evaluate_values, evaluate_gradients);
7320 
7321 # ifdef DEBUG
7322  if (evaluate_values == true)
7323  this->values_quad_initialized = true;
7324  if (evaluate_gradients == true)
7325  this->gradients_quad_initialized = true;
7326 # endif
7327 }
7328 
7329 
7330 
7331 template <int dim,
7332  int fe_degree,
7333  int n_q_points_1d,
7334  int n_components_,
7335  typename Number>
7336 template <typename VectorType>
7337 inline void
7339  integrate_scatter(const bool integrate_values,
7340  const bool integrate_gradients,
7341  VectorType &destination)
7342 {
7343  const unsigned int side = this->face_no % 2;
7344  const unsigned int dofs_per_face =
7345  fe_degree > -1 ? Utilities::pow(fe_degree + 1, dim - 1) :
7346  Utilities::pow(this->data->fe_degree + 1, dim - 1);
7347 
7348  constexpr unsigned int stack_array_size_threshold = 100;
7349 
7350  VectorizedArray<Number> temp_data[dofs_per_face < stack_array_size_threshold ?
7351  n_components_ * 2 * dofs_per_face :
7352  1];
7353  VectorizedArray<Number> *__restrict temp1;
7354  if (dofs_per_face < stack_array_size_threshold)
7355  temp1 = &temp_data[0];
7356  else
7357  temp1 = this->scratch_data;
7358 
7359  if (this->face_orientation)
7360  adjust_for_face_orientation(true, integrate_values, integrate_gradients);
7361  if (fe_degree > -1 &&
7363  this->data->element_type <=
7364  internal::MatrixFreeFunctions::tensor_symmetric)
7365  internal::FEFaceEvaluationImpl<
7366  true,
7367  dim,
7368  fe_degree,
7369  n_q_points_1d,
7370  n_components_,
7371  VectorizedArray<Number>>::integrate_in_face(*this->data,
7372  temp1,
7373  this->values_quad[0],
7374  this->gradients_quad[0][0],
7375  this->scratch_data +
7376  2 * n_components_ *
7377  dofs_per_face,
7378  integrate_values,
7379  integrate_gradients,
7380  this->subface_index);
7381  else
7382  internal::FEFaceEvaluationImpl<
7383  false,
7384  dim,
7385  fe_degree,
7386  n_q_points_1d,
7387  n_components_,
7388  VectorizedArray<Number>>::integrate_in_face(*this->data,
7389  temp1,
7390  this->values_quad[0],
7391  this->gradients_quad[0][0],
7392  this->scratch_data +
7393  2 * n_components_ *
7394  dofs_per_face,
7395  integrate_values,
7396  integrate_gradients,
7397  this->subface_index);
7398 
7399 # ifdef DEBUG
7400  this->dof_values_initialized = true;
7401 # endif
7402 
7403  internal::VectorDistributorLocalToGlobal<Number> writer;
7404 
7405  if (this->dof_info
7406  ->index_storage_variants[this->dof_access_index][this->cell] ==
7408  contiguous &&
7409  this->dof_info
7410  ->n_vectorization_lanes_filled[this->dof_access_index][this->cell] ==
7412  ((integrate_gradients == false &&
7413  this->data->nodal_at_cell_boundaries == true) ||
7414  (this->data->element_type ==
7415  internal::MatrixFreeFunctions::tensor_symmetric_hermite &&
7416  fe_degree > 1)))
7417  {
7418  const unsigned int *indices =
7419  &this->dof_info
7421  [this->cell *
7423 
7424  if (integrate_gradients == true &&
7425  this->data->element_type ==
7426  internal::MatrixFreeFunctions::tensor_symmetric_hermite)
7427  {
7428  // we know that the gradient weights for the Hermite case on the
7429  // right (side==1) are the negative from the value at the left
7430  // (side==0), so we only read out one of them.
7431  const VectorizedArray<Number> grad_weight0 =
7432  (side ? -1. : 1.) *
7433  this->data->shape_data_on_face[0][fe_degree + 1];
7434  const VectorizedArray<Number> grad_weight1 =
7435  (side ? -1. : 1.) *
7436  this->data->shape_data_on_face[0][fe_degree + 2];
7437  AssertDimension(this->data->face_to_cell_index_hermite.size(1),
7438  2 * dofs_per_face);
7439  const unsigned int *index_array =
7440  &this->data->face_to_cell_index_hermite(this->face_no, 0);
7441  for (unsigned int i = 0; i < dofs_per_face; ++i)
7442  {
7443  const unsigned int ind1 = index_array[2 * i];
7444  const unsigned int ind2 = index_array[2 * i + 1];
7445  for (unsigned int comp = 0; comp < n_components_; ++comp)
7446  {
7448  temp1[i + 2 * comp * dofs_per_face] +
7449  grad_weight0 *
7450  temp1[i + dofs_per_face + 2 * comp * dofs_per_face];
7452  grad_weight1 *
7453  temp1[i + dofs_per_face + 2 * comp * dofs_per_face];
7454  writer.process_dof_gather(
7455  indices,
7456  destination,
7457  comp * static_dofs_per_component + ind1 +
7458  this->dof_info->component_dof_indices_offset
7459  [this->active_fe_index][this->first_selected_component],
7460  val,
7461  std::integral_constant<
7462  bool,
7463  std::is_same<typename VectorType::value_type,
7464  Number>::value>());
7465  writer.process_dof_gather(
7466  indices,
7467  destination,
7468  comp * static_dofs_per_component + ind2 +
7469  this->dof_info->component_dof_indices_offset
7470  [this->active_fe_index][this->first_selected_component],
7471  grad,
7472  std::integral_constant<
7473  bool,
7474  std::is_same<typename VectorType::value_type,
7475  Number>::value>());
7476  }
7477  }
7478  }
7479  else
7480  {
7481  AssertDimension(this->data->face_to_cell_index_nodal.size(1),
7482  dofs_per_face);
7483  const unsigned int *index_array =
7484  &this->data->face_to_cell_index_nodal(this->face_no, 0);
7485  for (unsigned int i = 0; i < dofs_per_face; ++i)
7486  {
7487  const unsigned int ind = index_array[i];
7488  for (unsigned int comp = 0; comp < n_components_; ++comp)
7489  writer.process_dof_gather(
7490  indices,
7491  destination,
7492  comp * static_dofs_per_component + ind +
7493  this->dof_info->component_dof_indices_offset
7494  [this->active_fe_index][this->first_selected_component],
7495  temp1[i + 2 * comp * dofs_per_face],
7496  std::integral_constant<
7497  bool,
7498  std::is_same<typename VectorType::value_type,
7499  Number>::value>());
7500  }
7501  }
7502  }
7503  else
7504  {
7505  internal::FEFaceNormalEvaluationImpl<dim,
7506  fe_degree,
7507  n_components_,
7509  template interpolate<false, false>(*this->data,
7510  temp1,
7511  this->values_dofs[0],
7512  integrate_gradients,
7513  this->face_no);
7514  this->distribute_local_to_global(destination);
7515  }
7516 }
7517 
7518 
7519 
7520 template <int dim,
7521  int fe_degree,
7522  int n_q_points_1d,
7523  int n_components,
7524  typename Number>
7525 inline void
7528  const bool values,
7529  const bool gradients)
7530 {
7531  VectorizedArray<Number> *tmp_values = this->scratch_data;
7532  const unsigned int * orientations =
7533  &this->mapping_data->descriptor[this->active_fe_index]
7534  .face_orientations[this->face_orientation][0];
7535  for (unsigned int c = 0; c < n_components; ++c)
7536  {
7537  if (values == true)
7538  {
7539  if (integrate)
7540  for (unsigned int q = 0; q < n_q_points; ++q)
7541  tmp_values[orientations[q]] = this->values_quad[c][q];
7542  else
7543  for (unsigned int q = 0; q < n_q_points; ++q)
7544  tmp_values[q] = this->values_quad[c][orientations[q]];
7545  for (unsigned int q = 0; q < n_q_points; ++q)
7546  this->values_quad[c][q] = tmp_values[q];
7547  }
7548  if (gradients == true)
7549  for (unsigned int d = 0; d < dim; ++d)
7550  {
7551  if (integrate)
7552  for (unsigned int q = 0; q < n_q_points; ++q)
7553  tmp_values[orientations[q]] = this->gradients_quad[c][d][q];
7554  else
7555  for (unsigned int q = 0; q < n_q_points; ++q)
7556  tmp_values[q] = this->gradients_quad[c][d][orientations[q]];
7557  for (unsigned int q = 0; q < n_q_points; ++q)
7558  this->gradients_quad[c][d][q] = tmp_values[q];
7559  }
7560  }
7561 }
7562 
7563 
7564 
7565 template <int dim,
7566  int fe_degree,
7567  int n_q_points_1d,
7568  int n_components_,
7569  typename Number>
7572  quadrature_point(const unsigned int q) const
7573 {
7574  AssertIndexRange(q, n_q_points);
7575  if (this->dof_access_index < 2)
7576  {
7578  ExcNotImplemented());
7579  AssertIndexRange(this->cell,
7581  return this->mapping_data->quadrature_points
7582  [this->mapping_data->quadrature_point_offsets[this->cell] + q];
7583  }
7584  else
7585  {
7586  Assert(this->matrix_info->get_mapping_info()
7587  .face_data_by_cells[this->quad_no]
7588  .quadrature_point_offsets.empty() == false,
7589  ExcNotImplemented());
7590  const unsigned int index =
7591  this->cell * GeometryInfo<dim>::faces_per_cell + this->face_no;
7592  AssertIndexRange(index,
7593  this->matrix_info->get_mapping_info()
7594  .face_data_by_cells[this->quad_no]
7595  .quadrature_point_offsets.size());
7596  return this->matrix_info->get_mapping_info()
7597  .face_data_by_cells[this->quad_no]
7598  .quadrature_points[this->matrix_info->get_mapping_info()
7599  .face_data_by_cells[this->quad_no]
7600  .quadrature_point_offsets[index] +
7601  q];
7602  }
7603 }
7604 
7605 
7606 
7607 /*------------------------- end FEFaceEvaluation ------------------------- */
7608 
7609 
7610 #endif // ifndef DOXYGEN
7611 
7612 
7613 DEAL_II_NAMESPACE_CLOSE
7614 
7615 #endif
const unsigned int active_quad_index
const internal::MatrixFreeFunctions::TaskInfo & get_size_info() const
std::vector< unsigned int > plain_dof_indices
Definition: dof_info.h:422
AlignedVector< Tensor< 1, spacedim, VectorizedArray< Number > > > normals_times_jacobians[2]
Definition: mapping_info.h:238
static const unsigned int invalid_unsigned_int
Definition: types.h:173
AlignedVector< unsigned int > data_index_offsets
Definition: mapping_info.h:178
value_type integrate_value() const
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1366
Number local_element(const size_type local_index) const
void submit_divergence(const VectorizedArray< Number > div_in, const unsigned int q_point)
void read_write_operation(const VectorOperation &operation, VectorType *vectors[], const bool apply_constraints=true) const
VectorizedArray< Number > JxW(const unsigned int q_index) const
void check_template_arguments(const unsigned int fe_no, const unsigned int first_selected_component)
FEEvaluation & operator=(const FEEvaluation &other)
AlignedVector< Tensor< 1, spacedim *(spacedim+1)/2, Tensor< 1, spacedim, VectorizedArray< Number > > > > jacobian_gradients[2]
Definition: mapping_info.h:228
void read_write_operation_contiguous(const VectorOperation &operation, VectorType *vectors[]) const
internal::MatrixFreeFunctions::GeometryType cell_type
static::ExceptionBase & ExcAccessToUninitializedField()
std::vector< unsigned int > component_to_base_index
Definition: dof_info.h:452
bool mapping_initialized() const
internal::MatrixFreeFunctions::GeometryType get_cell_type() const
constexpr unsigned int pow(const unsigned int base, const unsigned int iexp)
Definition: utilities.h:353
std::vector< IndexStorageVariants > index_storage_variants[3]
Definition: dof_info.h:315
const unsigned int dofs_per_cell
void evaluate(const bool evaluate_values, const bool evaluate_gradients, const bool evaluate_hessians=false)
AlignedVector< unsigned int > quadrature_point_offsets
Definition: mapping_info.h:246
void integrate(const bool integrate_values, const bool integrate_gradients)
const internal::MatrixFreeFunctions::ShapeInfo< VectorizedArray< Number > > & get_shape_info() const
void submit_normal_derivative(const value_type grad_in, const unsigned int q_point)
#define AssertIndexRange(index, range)
Definition: exceptions.h:1407
std::shared_ptr< const Utilities::MPI::Partitioner > vector_partitioner
Definition: dof_info.h:386
FEEvaluationBase & operator=(const FEEvaluationBase &other)
const internal::MatrixFreeFunctions::MappingInfoStorage<(is_face?dim-1:dim), dim, Number > * mapping_data
const unsigned int active_fe_index
unsigned int get_mapping_data_index_offset() const
void integrate_scatter(const bool integrate_values, const bool integrate_gradients, VectorType &output_vector)
const internal::MatrixFreeFunctions::ShapeInfo< VectorizedArray< Number > > * data
Point< dim, VectorizedArray< Number > > quadrature_point(const unsigned int q_point) const
STL namespace.
Tensor< 1, dim, VectorizedArray< Number > > get_normal_vector(const unsigned int q_point) const
Transformed quadrature points.
static::ExceptionBase & ExcNotInitialized()
std::vector< unsigned int > cell_partition_data
Definition: task_info.h:471
unsigned int get_cell_data_number() const
void read_dof_values(const VectorType &src, const unsigned int first_index=0)
value_type get_value(const unsigned int q_point) const
FEEvaluationAccess & operator=(const FEEvaluationAccess &other)
AlignedVector< VectorizedArray< Number > > * scratch_data_array
static::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
gradient_type get_gradient(const unsigned int q_point) const
std::vector< unsigned int > dof_indices
Definition: dof_info.h:340
Definition: point.h:106
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:105
const unsigned int dofs_per_component
unsigned long long int global_dof_index
Definition: types.h:72
const VectorizedArray< Number > * begin_gradients() const
const internal::MatrixFreeFunctions::TaskInfo & get_task_info() const
ArrayView< VectorizedArray< Number > > get_scratch_data() const
const internal::MatrixFreeFunctions::FaceToCellTopology< VectorizedArray< Number >::n_array_elements > & get_face_info(const unsigned int face_batch_number) const
void submit_value(const value_type val_in, const unsigned int q_point)
std::vector< QuadratureDescriptor > descriptor
Definition: mapping_info.h:170
void scatter(const unsigned int *offsets, Number *base_ptr) const
const std::vector< unsigned int > & get_internal_dof_numbering() const
std::vector< unsigned char > n_vectorization_lanes_filled[3]
Definition: dof_info.h:378
void set_data_pointers()
const Tensor< 1, dim, VectorizedArray< Number > > * normal_vectors
size_type size() const
void submit_curl(const Tensor< 1, dim==2?1:dim, VectorizedArray< Number >> curl_in, const unsigned int q_point)
const Number * quadrature_weights
unsigned int element_multiplicity(const unsigned int index) const
Definition: fe.h:3111
void read_dof_values_plain(const VectorType &src, const unsigned int first_index=0)
const unsigned int dofs_per_cell
internal::MatrixFreeFunctions::DoFInfo::DoFAccessIndex dof_access_index
static::ExceptionBase & ExcMessage(std::string arg1)
const unsigned int n_q_points
void submit_symmetric_gradient(const SymmetricTensor< 2, dim, VectorizedArray< Number >> grad_in, const unsigned int q_point)
const Tensor< 2, dim, VectorizedArray< Number > > * jacobian
std::vector< unsigned int > dof_indices_interleaved
Definition: dof_info.h:357
const unsigned int quad_no
VectorizedArray< Number > * scratch_data
#define Assert(cond, exc)
Definition: exceptions.h:1227
Point< dim, VectorizedArray< Number > > quadrature_point(const unsigned int q_point) const
UpdateFlags
const internal::MatrixFreeFunctions::DoFInfo * dof_info
unsigned int n_components() const
unsigned int subface_index
bool indices_initialized() const
std::vector< unsigned int > row_starts_plain_indices
Definition: dof_info.h:412
std::pair< unsigned int, unsigned int > component_to_base_index(const unsigned int component) const
Definition: fe.h:3212
const MatrixFree< dim, Number > * matrix_info
const VectorizedArray< Number > * begin_values() const
#define DeclException0(Exception0)
Definition: exceptions.h:385
std::vector< unsigned int > boundary_partition_data
Definition: task_info.h:489
SymmetricTensor< 2, dim, VectorizedArray< Number > > get_symmetric_gradient(const unsigned int q_point) const
void release_scratch_data(const AlignedVector< VectorizedArray< Number >> *memory) const
std::vector< std::pair< unsigned int, unsigned int > > row_starts
Definition: dof_info.h:323
void reinit(const unsigned int face_batch_number)
unsigned int face_no
Tensor< 2, dim, VectorizedArray< Number > > inverse_jacobian(const unsigned int q_index) const
void fill_JxW_values(AlignedVector< VectorizedArray< Number >> &JxW_values) const
VectorizedArray< Number > * gradients_quad[n_components][dim]
std::shared_ptr< internal::MatrixFreeFunctions::MappingDataOnTheFly< dim, Number > > mapped_geometry
friend class FEEvaluationBase
void gather_evaluate(const VectorType &input_vector, const bool evaluate_values, const bool evaluate_gradients)
std::vector< std::pair< unsigned short, unsigned short > > constraint_indicator
Definition: dof_info.h:352
VectorizedArray< Number > read_cell_data(const AlignedVector< VectorizedArray< Number >> &array) const
const VectorizedArray< Number > * J_value
bool hessians_quad_initialized
AlignedVector< Point< spacedim, VectorizedArray< Number > > > quadrature_points
Definition: mapping_info.h:255
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:96
bool partitioners_are_compatible(const Utilities::MPI::Partitioner &part) const
void reinit(const unsigned int cell_batch_index)
void distribute_local_to_global(VectorType &dst, const unsigned int first_index=0) const
void adjust_for_face_orientation(const bool integrate, const bool values, const bool gradients)
unsigned int cell
void integrate(const bool integrate_values, const bool integrate_gradients)
static constexpr unsigned int n_components
const Number * constraint_pool_end(const unsigned int pool_index) const
std::vector< unsigned int > face_partition_data
Definition: task_info.h:480
unsigned int n_base_elements(const unsigned int dof_handler_index) const
void read_write_operation_global(const VectorOperation &operation, VectorType *vectors[]) const
FEFaceEvaluation(const MatrixFree< dim, Number > &matrix_free, const bool is_interior_face=true, const unsigned int dof_no=0, const unsigned int quad_no=0, const unsigned int first_selected_component=0)
Definition: cuda.h:32
void resize_fast(const size_type size)
void evaluate(const bool evaluate_values, const bool evaluate_gradients)
Definition: mpi.h:55
std::vector< unsigned int > dof_indices_contiguous[3]
Definition: dof_info.h:367
iterator end()
AlignedVector< Tensor< 1, spacedim, VectorizedArray< Number > > > normal_vectors
Definition: mapping_info.h:195
const unsigned int n_q_points
std::vector< std::vector< unsigned int > > component_dof_indices_offset
Definition: dof_info.h:465
const VectorizedArray< Number > * begin_dof_values() const
VectorizedArray< Number > * values_dofs[n_components]
VectorizedArray< Number > get_divergence(const unsigned int q_point) const
iterator begin()
static constexpr unsigned int static_dofs_per_component
const unsigned int n_quadrature_points
void gather(const Number *base_ptr, const unsigned int *offsets)
const unsigned int dofs_per_component
static::ExceptionBase & ExcNotImplemented()
const Tensor< 1, dim, VectorizedArray< Number > > * normal_x_jacobian
value_type get_normal_derivative(const unsigned int q_point) const
std::vector< types::global_dof_index > local_dof_indices
gradient_type get_hessian_diagonal(const unsigned int q_point) const
void gather_evaluate(const VectorType &input_vector, const bool evaluate_values, const bool evaluate_gradients, const bool evaluate_hessians=false)
VectorizedArray< Number > * values_quad[n_components]
void submit_dof_value(const value_type val_in, const unsigned int dof)
bool gradients_quad_initialized
std::vector< unsigned int > start_components
Definition: dof_info.h:446
const Number * constraint_pool_begin(const unsigned int pool_index) const
void integrate_scatter(const bool integrate_values, const bool integrate_gradients, VectorType &output_vector)
std::vector< unsigned int > lexicographic_numbering
Definition: shape_info.h:226
FEEvaluation(const MatrixFree< dim, Number > &matrix_free, const unsigned int dof_no=0, const unsigned int quad_no=0, const unsigned int first_selected_component=0)
bool empty() const
const VectorizedArray< Number > * begin_hessians() const
AlignedVector< VectorizedArray< Number > > * acquire_scratch_data() const
FEEvaluationAccess(const MatrixFree< dim, Number > &matrix_free, const unsigned int dof_no, const unsigned int first_selected_component, const unsigned int quad_no, const unsigned int fe_degree, const unsigned int n_q_points, const bool is_interior_face=true)
unsigned int face_orientation
void set_dof_values(VectorType &dst, const unsigned int first_index=0) const
static constexpr unsigned int static_n_q_points
value_type get_laplacian(const unsigned int q_point) const
AlignedVector< Tensor< 2, spacedim, VectorizedArray< Number > > > jacobians[2]
Definition: mapping_info.h:208
AlignedVector< VectorizedArray< Number > > JxW_values
Definition: mapping_info.h:187
value_type get_dof_value(const unsigned int dof) const
const unsigned int n_fe_components
void submit_gradient(const gradient_type grad_in, const unsigned int q_point)
const unsigned int first_selected_component
static::ExceptionBase & ExcInternalError()
Tensor< 1, n_components_, Tensor< 2, dim, VectorizedArray< Number > > > get_hessian(const unsigned int q_point) const
Tensor< 1,(dim==2?1:dim), VectorizedArray< Number > > get_curl(const unsigned int q_point) const