deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
portable_fe_evaluation.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2023 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_portable_fe_evaluation_h
14#define dealii_portable_fe_evaluation_h
15
16#include <deal.II/base/config.h>
17
19#include <deal.II/base/tensor.h>
21
26#include <deal.II/matrix_free/portable_matrix_free.templates.h>
28
29#include <Kokkos_Core.hpp>
30
32
36namespace Portable
37{
61 template <int dim,
62 int fe_degree,
63 int n_q_points_1d = fe_degree + 1,
64 int n_components_ = 1,
65 typename Number = double>
67 {
68 public:
73 using value_type = std::conditional_t<(n_components_ == 1),
74 Number,
76
80 using gradient_type = std::conditional_t<
81 n_components_ == 1,
83 std::conditional_t<n_components_ == dim,
86
91
95 static constexpr unsigned int dimension = dim;
96
100 static constexpr unsigned int n_components = n_components_;
101
105 static constexpr unsigned int n_q_points =
106 Utilities::pow(n_q_points_1d, dim);
107
112 static constexpr unsigned int tensor_dofs_per_component =
113 Utilities::pow(fe_degree + 1, dim);
114
120 static constexpr unsigned int tensor_dofs_per_cell =
122
132 explicit FEEvaluation(const data_type *data,
133 const unsigned int dof_handler_index = 0);
134
139 int
141
148 const data_type *
150
161
170
179 evaluate(const EvaluationFlags::EvaluationFlags evaluate_flag);
180
188 integrate(const EvaluationFlags::EvaluationFlags integration_flag);
189
196 get_value(const int q_point) const;
197
203 get_dof_value(const int dof_index) const;
204
211 submit_value(const value_type &val_in, const int q_point);
212
219 submit_dof_value(const value_type &value, const int dof_index);
220
227 get_gradient(const int q_point) const;
228
235 submit_gradient(const gradient_type &gradient, const int q_point);
236
245 get_symmetric_gradient(const int q_point) const;
246
254 get_divergence(const int q_point) const;
255
272 submit_divergence(const Number &div_in, const int q_point);
273
282 const int q_point);
283
284 private:
285 const unsigned int dof_handler_index;
290
291
298
304
311
316 DEAL_II_HOST_DEVICE unsigned int
317 inv_jacobian_index(const int q_point) const
318 {
319 return mapping_data_offset +
321 q_point :
322 0);
323 }
324
330 JxW_value(const int q_point) const
331 {
333 precomputed_data->JxW(mapping_data_offset + q_point) :
334 cell_determinant * precomputed_data->q_weights(q_point);
335 }
336 };
337
338
339
340 template <int dim,
341 int fe_degree,
342 int n_q_points_1d,
343 int n_components_,
344 typename Number>
347 FEEvaluation(const data_type *data, const unsigned int dof_handler_index)
348 : dof_handler_index(dof_handler_index)
349 , data(data)
350 , precomputed_data(&data->precomputed_data[dof_handler_index])
351 , shared_data(&data->shared_data[dof_handler_index])
352 , cell_id(data->team_member.league_rank())
353 , cell_type(precomputed_data->cell_type(cell_id))
354 , mapping_data_offset(precomputed_data->data_index_offsets(cell_id))
355 , cell_determinant(
356 (cell_type != ::internal::MatrixFreeFunctions::general &&
357 precomputed_data->JxW.size() > 0) ?
358 precomputed_data->JxW(mapping_data_offset) :
359 Number())
360 {
361 AssertIndexRange(dof_handler_index, data->n_dof_handler);
362
363 Assert(
364 n_components_ == precomputed_data->n_components,
366 "Portable::FEEvaluation initialized with wrong number of components. Should be " +
368 " but the template argument 4 is set to " +
369 Utilities::to_string(n_components_)));
370
371 // TODO: check fe_degree is correct by storing the used FE degree
372 // inside PrecomputedData.
373 }
374
375
376
377 template <int dim,
378 int fe_degree,
379 int n_q_points_1d,
380 int n_components_,
381 typename Number>
388
389
390
391 template <int dim,
392 int fe_degree,
393 int n_q_points_1d,
394 int n_components_,
395 typename Number>
396 DEAL_II_HOST_DEVICE const typename FEEvaluation<dim,
397 fe_degree,
398 n_q_points_1d,
399 n_components_,
400 Number>::data_type *
406
407
408
409 template <int dim,
410 int fe_degree,
411 int n_q_points_1d,
412 int n_components_,
413 typename Number>
417 {
418 // Populate the scratch memory
419 Kokkos::parallel_for(Kokkos::TeamThreadRange(data->team_member,
420 tensor_dofs_per_component),
421 [&](const int &i) {
422 for (unsigned int c = 0; c < n_components_; ++c)
423 shared_data->values(i, c) =
424 src[precomputed_data->local_to_global(
425 i + tensor_dofs_per_component * c, cell_id)];
426 });
427 data->team_member.team_barrier();
428
429 for (unsigned int c = 0; c < n_components_; ++c)
430 {
431 if (precomputed_data->constraint_mask(cell_id * n_components + c) !=
433 unconstrained)
434 internal::resolve_hanging_nodes<dim, fe_degree, false, Number>(
435 data->team_member,
436 precomputed_data->constraint_weights,
437 precomputed_data->constraint_mask(cell_id * n_components + c),
438 Kokkos::subview(shared_data->values, Kokkos::ALL, c));
439 }
440 }
441
442
443
444 template <int dim,
445 int fe_degree,
446 int n_q_points_1d,
447 int n_components_,
448 typename Number>
452 {
453 for (unsigned int c = 0; c < n_components_; ++c)
454 {
455 if (precomputed_data->constraint_mask(cell_id * n_components + c) !=
457 unconstrained)
458 internal::resolve_hanging_nodes<dim, fe_degree, true, Number>(
459 data->team_member,
460 precomputed_data->constraint_weights,
461 precomputed_data->constraint_mask(cell_id * n_components + c),
462 Kokkos::subview(shared_data->values, Kokkos::ALL, c));
463 }
464
465 if (precomputed_data->use_coloring)
466 {
467 Kokkos::parallel_for(
468 Kokkos::TeamThreadRange(data->team_member, tensor_dofs_per_component),
469 [&](const int &i) {
470 for (unsigned int c = 0; c < n_components_; ++c)
471 dst[precomputed_data->local_to_global(
472 i + tensor_dofs_per_component * c, cell_id)] +=
473 shared_data->values(i, c);
474 });
475 }
476 else
477 {
478 Kokkos::parallel_for(
479 Kokkos::TeamThreadRange(data->team_member, tensor_dofs_per_component),
480 [&](const int &i) {
481 for (unsigned int c = 0; c < n_components_; ++c)
482 Kokkos::atomic_add(&dst[precomputed_data->local_to_global(
483 i + (tensor_dofs_per_component)*c, cell_id)],
484 shared_data->values(i, c));
485 });
486 }
487 }
488
489
490
491 template <int dim,
492 int fe_degree,
493 int n_q_points_1d,
494 int n_components,
495 typename Number>
498 const EvaluationFlags::EvaluationFlags evaluation_flag)
499 {
501
502 if (fe_degree >= 0 && fe_degree + 1 == n_q_points_1d &&
503 precomputed_data->element_type ==
504 ElementType::tensor_symmetric_collocation)
505 {
507 dof_handler_index, n_components, evaluation_flag, data);
508 }
509 // '<=' on type means tensor_symmetric or tensor_symmetric_hermite, see
510 // shape_info.h for more details
511 else if (fe_degree >= 0 &&
512 internal::use_collocation_evaluation(fe_degree, n_q_points_1d) &&
513 precomputed_data->element_type <= ElementType::tensor_symmetric)
514 {
516 dim,
517 fe_degree,
518 n_q_points_1d,
519 Number>::evaluate(dof_handler_index,
520 n_components,
521 evaluation_flag,
522 data);
523 }
524 else if (fe_degree >= 0 && precomputed_data->element_type <=
525 ElementType::tensor_symmetric_no_collocation)
526 {
528 evaluate(dof_handler_index, n_components, evaluation_flag, data);
529 }
530 else
531 {
532 Kokkos::abort("The element type is not yet supported by the portable "
533 "matrix-free module.");
534 }
535 }
536
537
538
539 template <int dim,
540 int fe_degree,
541 int n_q_points_1d,
542 int n_components_,
543 typename Number>
546 const EvaluationFlags::EvaluationFlags integration_flag)
547 {
549
550 if (fe_degree >= 0 && fe_degree + 1 == n_q_points_1d &&
551 precomputed_data->element_type ==
552 ElementType::tensor_symmetric_collocation)
553 {
555 integrate(dof_handler_index, n_components, integration_flag, data);
556 }
557 // '<=' on type means tensor_symmetric or tensor_symmetric_hermite, see
558 // shape_info.h for more details
559 else if (fe_degree >= 0 &&
560 internal::use_collocation_evaluation(fe_degree, n_q_points_1d) &&
561 precomputed_data->element_type <= ElementType::tensor_symmetric)
562 {
564 dim,
565 fe_degree,
566 n_q_points_1d,
567 Number>::integrate(dof_handler_index,
568 n_components,
569 integration_flag,
570 data);
571 }
572 else if (fe_degree >= 0 && precomputed_data->element_type <=
573 ElementType::tensor_symmetric_no_collocation)
574 {
576 integrate(dof_handler_index, n_components, integration_flag, data);
577 }
578 else
579 {
580 Kokkos::abort("The element type is not yet supported by the portable "
581 "matrix-free module.");
582 }
583 }
584
585
586
587 template <int dim,
588 int fe_degree,
589 int n_q_points_1d,
590 int n_components_,
591 typename Number>
593 fe_degree,
594 n_q_points_1d,
595 n_components_,
596 Number>::value_type
598 const int q_point) const
599 {
600 AssertIndexRange(q_point, n_q_points);
601 if constexpr (n_components_ == 1)
602 {
603 return shared_data->values(q_point, 0);
604 }
605 else
606 {
607 value_type result;
608 for (unsigned int c = 0; c < n_components; ++c)
609 result[c] = shared_data->values(q_point, c);
610 return result;
611 }
612 }
613
614
615
616 template <int dim,
617 int fe_degree,
618 int n_q_points_1d,
619 int n_components_,
620 typename Number>
622 fe_degree,
623 n_q_points_1d,
624 n_components_,
625 Number>::value_type
627 get_dof_value(const int dof_index) const
628 {
629 AssertIndexRange(dof_index, tensor_dofs_per_component);
630 if constexpr (n_components_ == 1)
631 {
632 return shared_data->values(dof_index, 0);
633 }
634 else
635 {
636 value_type result;
637 for (unsigned int c = 0; c < n_components; ++c)
638 result[c] = shared_data->values(dof_index, c);
639 return result;
640 }
641 }
642
643
644
645 template <int dim,
646 int fe_degree,
647 int n_q_points_1d,
648 int n_components_,
649 typename Number>
652 submit_value(const value_type &value, const int q_point)
653 {
654 AssertIndexRange(q_point, n_q_points);
655 Assert(precomputed_data->JxW.size() > 0,
656 ExcMessage("submit_value() requires precomputed JxW"));
657 const Number JxW = JxW_value(q_point);
658 if constexpr (n_components_ == 1)
659 {
660 shared_data->values(q_point, 0) = value * JxW;
661 }
662 else
663 {
664 for (unsigned int c = 0; c < n_components; ++c)
665 shared_data->values(q_point, c) = value[c] * JxW;
666 }
667 }
668
669
670
671 template <int dim,
672 int fe_degree,
673 int n_q_points_1d,
674 int n_components_,
675 typename Number>
678 submit_dof_value(const value_type &value, const int dof_index)
679 {
680 AssertIndexRange(dof_index, tensor_dofs_per_component);
681 if constexpr (n_components_ == 1)
682 {
683 shared_data->values(dof_index, 0) = value;
684 }
685 else
686 {
687 for (unsigned int c = 0; c < n_components; ++c)
688 shared_data->values(dof_index, c) = value[c];
689 }
690 }
691
692
693
694 template <int dim,
695 int fe_degree,
696 int n_q_points_1d,
697 int n_components_,
698 typename Number>
700 fe_degree,
701 n_q_points_1d,
702 n_components_,
703 Number>::gradient_type
705 get_gradient(const int q_point) const
706 {
707 AssertIndexRange(q_point, n_q_points);
708 Assert(precomputed_data->inv_jacobian.size() > 0,
709 ExcMessage("get_gradient() requires precomputed inv_jacobian"));
710 gradient_type grad;
711
712 const unsigned int inv_jac_idx = inv_jacobian_index(q_point);
714 {
715 if constexpr (n_components_ == 1)
716 {
717 for (unsigned int d = 0; d < dim; ++d)
718 grad[d] = precomputed_data->inv_jacobian(inv_jac_idx, d, d) *
719 shared_data->gradients(q_point, d, 0);
720 }
721 else
722 {
723 for (unsigned int c = 0; c < n_components; ++c)
724 for (unsigned int d = 0; d < dim; ++d)
725 grad[c][d] = precomputed_data->inv_jacobian(inv_jac_idx, d, d) *
726 shared_data->gradients(q_point, d, c);
727 }
728 }
729 else if constexpr (n_components_ == 1)
730 {
731 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
732 {
733 Number tmp = 0.;
734 for (unsigned int d_2 = 0; d_2 < dim; ++d_2)
735 tmp += precomputed_data->inv_jacobian(inv_jac_idx, d_2, d_1) *
736 shared_data->gradients(q_point, d_2, 0);
737 grad[d_1] = tmp;
738 }
739 }
740 else
741 {
742 for (unsigned int c = 0; c < n_components; ++c)
743 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
744 {
745 Number tmp = 0.;
746 for (unsigned int d_2 = 0; d_2 < dim; ++d_2)
747 tmp += precomputed_data->inv_jacobian(inv_jac_idx, d_2, d_1) *
748 shared_data->gradients(q_point, d_2, c);
749 grad[c][d_1] = tmp;
750 }
751 }
752
753 return grad;
754 }
755
756
757
758 template <int dim,
759 int fe_degree,
760 int n_q_points_1d,
761 int n_components_,
762 typename Number>
765 submit_gradient(const gradient_type &gradient, const int q_point)
766 {
767 AssertIndexRange(q_point, n_q_points);
768 Assert(precomputed_data->inv_jacobian.size() > 0,
769 ExcMessage("submit_gradient() requires precomputed inv_jacobian"));
770 Assert(precomputed_data->JxW.size() > 0,
771 ExcMessage("submit_gradient() requires precomputed JxW"));
772
773 const unsigned int inv_jac_idx = inv_jacobian_index(q_point);
774 const Number JxW = JxW_value(q_point);
776 {
777 if constexpr (n_components_ == 1)
778 {
779 for (unsigned int d = 0; d < dim; ++d)
780 shared_data->gradients(q_point, d, 0) =
781 precomputed_data->inv_jacobian(inv_jac_idx, d, d) *
782 gradient[d] * JxW;
783 }
784 else
785 {
786 for (unsigned int c = 0; c < n_components; ++c)
787 for (unsigned int d = 0; d < dim; ++d)
788 shared_data->gradients(q_point, d, c) =
789 precomputed_data->inv_jacobian(inv_jac_idx, d, d) *
790 gradient[c][d] * JxW;
791 }
792 }
793 else if constexpr (n_components_ == 1)
794 {
795 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
796 {
797 Number tmp = 0.;
798 for (unsigned int d_2 = 0; d_2 < dim; ++d_2)
799 tmp += precomputed_data->inv_jacobian(inv_jac_idx, d_1, d_2) *
800 gradient[d_2];
801 shared_data->gradients(q_point, d_1, 0) = tmp * JxW;
802 }
803 }
804 else
805 {
806 for (unsigned int c = 0; c < n_components; ++c)
807 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
808 {
809 Number tmp = 0.;
810 for (unsigned int d_2 = 0; d_2 < dim; ++d_2)
811 tmp += precomputed_data->inv_jacobian(inv_jac_idx, d_1, d_2) *
812 gradient[c][d_2];
813 shared_data->gradients(q_point, d_1, c) = tmp * JxW;
814 }
815 }
816 }
817
818
819
820 template <int dim,
821 int fe_degree,
822 int n_q_points_1d,
823 int n_components_,
824 typename Number>
827 get_symmetric_gradient(const int q_point) const
828 {
829 AssertIndexRange(q_point, n_q_points);
830 Assert(n_components_ == dim,
831 ExcMessage("Function get_symmetric_gradient() only works when the "
832 "number of components and the number of dimensions are "
833 "equal."));
834
835 return symmetrize(get_gradient(q_point));
836 }
837
838
839
840 template <int dim,
841 int fe_degree,
842 int n_q_points_1d,
843 int n_components_,
844 typename Number>
847 get_divergence(const int q_point) const
848 {
849 AssertIndexRange(q_point, n_q_points);
850 Assert(n_components_ == dim,
851 ExcMessage("Function get_divergence() only works when the "
852 "number of components and the number of dimensions are "
853 "equal."));
854 Assert(precomputed_data->inv_jacobian.size() > 0,
855 ExcMessage("get_divergence() requires precomputed inv_jacobian"));
856
857 const unsigned int inv_jac_idx = inv_jacobian_index(q_point);
858 Number divergence = 0.;
859 for (unsigned int c = 0; c < dim; ++c)
860 for (unsigned int d = 0; d < dim; ++d)
861 divergence += precomputed_data->inv_jacobian(inv_jac_idx, d, c) *
862 shared_data->gradients(q_point, d, c);
863 return divergence;
864 }
865
866
867
868 template <int dim,
869 int fe_degree,
870 int n_q_points_1d,
871 int n_components_,
872 typename Number>
875 submit_divergence(const Number &div_in, const int q_point)
876 {
877 AssertIndexRange(q_point, n_q_points);
878 Assert(n_components_ == dim,
879 ExcMessage("Function submit_divergence() only works when the "
880 "number of components and the number of dimensions are "
881 "equal."));
882 Assert(precomputed_data->inv_jacobian.size() > 0,
883 ExcMessage("submit_divergence() requires precomputed inv_jacobian"));
884 Assert(precomputed_data->JxW.size() > 0,
885 ExcMessage("submit_divergence() requires precomputed JxW"));
886
887 const unsigned int inv_jac_idx = inv_jacobian_index(q_point);
888 const Number JxW = JxW_value(q_point);
889 for (unsigned int c = 0; c < dim; ++c)
890 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
891 shared_data->gradients(q_point, d_1, c) =
892 precomputed_data->inv_jacobian(inv_jac_idx, d_1, c) * div_in * JxW;
893 }
894
895
896
897 template <int dim,
898 int fe_degree,
899 int n_q_points_1d,
900 int n_components_,
901 typename Number>
905 const int q_point)
906 {
907 AssertIndexRange(q_point, n_q_points);
908 Assert(n_components_ == dim,
909 ExcMessage("Function submit_symmetric_gradient() only works when "
910 "the number of components and the number of dimensions "
911 "are equal."));
912 Assert(precomputed_data->inv_jacobian.size() > 0,
914 "submit_symmetric_gradient() requires precomputed inv_jacobian"));
915 Assert(precomputed_data->JxW.size() > 0,
916 ExcMessage("submit_symmetric_gradient() requires precomputed JxW"));
917
918 const unsigned int inv_jac_idx = inv_jacobian_index(q_point);
919 const Number JxW = JxW_value(q_point);
920 for (unsigned int c = 0; c < dim; ++c)
921 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
922 {
923 Number tmp = 0.;
924 for (unsigned int d_2 = 0; d_2 < dim; ++d_2)
925 tmp += precomputed_data->inv_jacobian(inv_jac_idx, d_1, d_2) *
926 sym_grad[c][d_2];
927 shared_data->gradients(q_point, d_1, c) = tmp * JxW;
928 }
929 }
930
931
932
933#ifndef DOXYGEN
934 template <int dim,
935 int fe_degree,
936 int n_q_points_1d,
937 int n_components_,
938 typename Number>
939 constexpr unsigned int
941 n_q_points;
942#endif
943} // namespace Portable
944
946
947#endif
unsigned int n_components() const
static constexpr unsigned int n_q_points
SharedData< dim, Number > * shared_data
void integrate(const EvaluationFlags::EvaluationFlags integration_flag)
static constexpr unsigned int dimension
const data_type * get_matrix_free_data()
const MatrixFree< dim, Number >::Data * data
static constexpr unsigned int n_components
void submit_gradient(const gradient_type &gradient, const int q_point)
void submit_divergence(const Number &div_in, const int q_point)
void evaluate(const EvaluationFlags::EvaluationFlags evaluate_flag)
void read_dof_values(const DeviceVector< Number > &src)
Number get_divergence(const int q_point) const
void distribute_local_to_global(DeviceVector< Number > &dst) const
static constexpr unsigned int tensor_dofs_per_cell
void submit_value(const value_type &val_in, const int q_point)
const MatrixFree< dim, Number >::PrecomputedData * precomputed_data
unsigned int inv_jacobian_index(const int q_point) const
const unsigned int dof_handler_index
std::conditional_t< n_components_==1, Tensor< 1, dim, Number >, std::conditional_t< n_components_==dim, Tensor< 2, dim, Number >, Tensor< 1, n_components_, Tensor< 1, dim, Number > > > > gradient_type
SymmetricTensor< 2, dim, Number > get_symmetric_gradient(const int q_point) const
::internal::MatrixFreeFunctions::GeometryType cell_type
std::conditional_t<(n_components_==1), Number, Tensor< 1, n_components_, Number > > value_type
void submit_dof_value(const value_type &value, const int dof_index)
value_type get_value(const int q_point) const
void submit_symmetric_gradient(const SymmetricTensor< 2, dim, Number > &sym_grad, const int q_point)
static constexpr unsigned int tensor_dofs_per_component
typename MatrixFree< dim, Number >::Data data_type
gradient_type get_gradient(const int q_point) const
Number JxW_value(const int q_point) const
value_type get_dof_value(const int dof_index) const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_HOST_DEVICE
Definition config.h:171
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcMessage(std::string arg1)
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
EvaluationFlags
The EvaluationFlags enum.
*  *  *  RotationFunction< dim, Number >::RotationFunction Number(dim)
constexpr bool use_collocation_evaluation(const unsigned int fe_degree, const unsigned int n_q_points_1d)
Kokkos::View< Number *, MemorySpace::Default::kokkos_space > DeviceVector
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:473
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
static void integrate(const unsigned int dof_handler_index, const unsigned int n_components, const EvaluationFlags::EvaluationFlags integration_flag, const typename MatrixFree< dim, Number >::Data *data)
static void evaluate(const unsigned int dof_handler_index, const unsigned int n_components, const EvaluationFlags::EvaluationFlags evaluation_flag, const typename MatrixFree< dim, Number >::Data *data)
static void evaluate(const unsigned int dof_handler_index, const unsigned int n_components, const EvaluationFlags::EvaluationFlags evaluation_flag, const typename MatrixFree< dim, Number >::Data *data)
static void integrate(const unsigned int dof_handler_index, const unsigned int n_components, const EvaluationFlags::EvaluationFlags integration_flag, const typename MatrixFree< dim, Number >::Data *data)
constexpr SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)