SecondOrderDivTestvecDivTrialvec.hpp 6.35 KB
Newer Older
1
2
3
4
#pragma once

#include <type_traits>

5
#include <amdis/GridFunctionOperator.hpp>
6
#include <amdis/common/StaticSize.hpp>
7
#include <amdis/typetree/FiniteElementType.hpp>
8
9
10

namespace AMDiS
{
11
12
13
14
15
  /**
   * \addtogroup operators
   * @{
   **/

16
17
18
19
20
21
  namespace tag
  {
    struct divtestvec_divtrialvec {};
  }


22
  /// second-order operator \f$ \langle\nabla\cdot\Psi, c\,\nabla\cdot\Phi\rangle \f$
23
  class SecondOrderDivTestvecDivTrialvec
24
25
  {
  public:
26
    SecondOrderDivTestvecDivTrialvec(tag::divtestvec_divtrialvec) {}
27

28
29
30
    template <class CG, class RN, class CN, class Quad, class LocalFct, class Mat>
    void assemble(CG const& contextGeo, RN const& rowNode, CN const& colNode,
                  Quad const& quad, LocalFct const& localFct, Mat& elementMatrix) const
31
    {
32
33
      static_assert(static_size_v<typename LocalFct::Range> == 1,
        "Expression must be of scalar type.");
34
      static_assert(RN::isPower && CN::isPower,
35
        "Operator can be applied to Power-Nodes only.");
36

37
      const bool sameFE = std::is_same_v<FiniteElementType_t<RN>, FiniteElementType_t<CN>>;
38
39
40
      const bool sameNode = rowNode.treeIndex() == colNode.treeIndex();

      if (sameFE && sameNode)
41
        getElementMatrixOptimized(contextGeo, quad, rowNode, colNode, localFct, elementMatrix);
42
      else
43
        getElementMatrixStandard(contextGeo, quad, rowNode, colNode, localFct, elementMatrix);
44
45
46
    }

  protected:
47
    template <class CG, class QR, class RN, class CN, class LocalFct, class Mat>
48
49
    void getElementMatrixStandard(CG const& contextGeo, QR const& quad,
                                  RN const& rowNode, CN const& colNode,
50
                                  LocalFct const& localFct, Mat& elementMatrix) const
51
    {
52
      assert( rowNode.degree() == colNode.degree() );
53

54
55
      std::size_t rowSize = rowNode.child(0).size();
      std::size_t colSize = colNode.child(0).size();
56

57
58
59
      using RowFieldType = typename RN::ChildType::LocalBasis::Traits::RangeFieldType;
      using RowWorldVector = FieldVector<RowFieldType,CG::dow>;
      std::vector<RowWorldVector> rowGradients;
60

61
62
63
      using ColFieldType = typename CN::ChildType::LocalBasis::Traits::RangeFieldType;
      using ColWorldVector = FieldVector<ColFieldType,CG::dow>;
      std::vector<ColWorldVector> colGradients;
64

65
      for (auto const& qp : quad) {
66
        // Position of the current quadrature point in the reference element
67
        decltype(auto) local = contextGeo.local(qp.position());
68
69

        // The transposed inverse Jacobian of the map from the reference element to the element
70
        const auto jacobian = contextGeo.geometry().jacobianInverseTransposed(local);
71
72

        // The multiplicative factor in the integral transformation formula
73
        const auto factor = localFct(local) * contextGeo.integrationElement(qp.position()) * qp.weight();
74
75

        // The gradients of the shape functions on the reference element
76
77
        auto const& rowShapeGradients = rowNode.child(0).localBasisJacobiansAt(local);
        auto const& colShapeGradients = colNode.child(0).localBasisJacobiansAt(local);
78

79
        // Compute the shape function gradients on the real element
80
        rowGradients.resize(rowShapeGradients.size());
81

82
        for (std::size_t i = 0; i < rowGradients.size(); ++i)
83
          jacobian.mv(rowShapeGradients[i][0], rowGradients[i]);
84

85
        colGradients.resize(colShapeGradients.size());
86

87
        for (std::size_t i = 0; i < colGradients.size(); ++i)
88
          jacobian.mv(colShapeGradients[i][0], colGradients[i]);
89

90
91
        for (std::size_t i = 0; i < rowSize; ++i) {
          for (std::size_t j = 0; j < colSize; ++j) {
92
93
94
95
96
97
98
              for (std::size_t k = 0; k < CG::dow; ++k) {
                  for (std::size_t l = 0; l < CG::dow; ++l) {
                      const auto local_ki = rowNode.child(k).localIndex(i);
                      const auto local_kj = colNode.child(l).localIndex(j);
                      elementMatrix[local_ki][local_kj] += factor * rowGradients[i][k] * colGradients[j][l];
                  }
              }
99
100
101
102
103
104
          }
        }
      }
    }


105
    template <class CG, class QR, class Node, class LocalFct, class Mat>
106
107
    void getElementMatrixOptimized(CG const& contextGeo, QR const& quad,
                                   Node const& node, Node const& /*colNode*/,
108
                                   LocalFct const& localFct, Mat& elementMatrix) const
109
    {
110
      std::size_t size = node.child(0).size();
111

112
113
114
      using RangeFieldType = typename Node::ChildType::LocalBasis::Traits::RangeFieldType;
      using WorldVector = FieldVector<RangeFieldType,CG::dow>;
      std::vector<WorldVector> gradients;
115

116
      for (auto const& qp : quad) {
117
        // Position of the current quadrature point in the reference element
118
        auto&& local = contextGeo.local(qp.position());
119
120

        // The transposed inverse Jacobian of the map from the reference element to the element
121
        const auto jacobian = contextGeo.geometry().jacobianInverseTransposed(local);
122
123

        // The multiplicative factor in the integral transformation formula
124
        const auto factor = localFct(local) * contextGeo.integrationElement(qp.position()) * qp.weight();
125
126

        // The gradients of the shape functions on the reference element
127
        auto const& shapeGradients = node.child(0).localBasisJacobiansAt(local);
128
129

        // Compute the shape function gradients on the real element
130
        gradients.resize(shapeGradients.size());
131

132
        for (std::size_t i = 0; i < gradients.size(); ++i)
133
          jacobian.mv(shapeGradients[i][0], gradients[i]);
134

135
136
137
138
139
140
141
142
143
144
145
146
        for (std::size_t k = 0; k < CG::dow; ++k) {
          for (std::size_t k = 0; k < CG::dow; ++k) {
            for (std::size_t i = 0; i < size; ++i) {
              const auto local_ki = node.child(k).localIndex(i);
              const auto value = factor * gradients[i][k];
              elementMatrix[local_ki][local_ki] += value * gradients[i][k];

              for (std::size_t j = i + 1; j < size; ++j) {
                const auto local_kj = node.child(l).localIndex(j);
                elementMatrix[local_ki][local_kj] += value * gradients[j][l];
                elementMatrix[local_kj][local_ki] += value * gradients[j][l];
              }
147
148
149
150
151
152
153
            }
          }
        }
      }
    }
  };

154
155
156
157
158
159
160
  template <class LC>
  struct GridFunctionOperatorRegistry<tag::divtestvec_divtrialvec, LC>
  {
    static constexpr int degree = 2;
    using type = SecondOrderDivTestvecDivTrialvec;
  };

161
162
  /** @} **/

163
} // end namespace AMDiS