FirstOrderTestGradTrial.hpp 3.16 KB
Newer Older
1
2
3
4
#pragma once

#include <type_traits>

5
#include <dune/amdis/GridFunctionOperator.hpp>
6
7
8
9
10
11
12
13
14
15
16
17
#include <dune/amdis/Output.hpp>
#include <dune/amdis/common/ValueCategory.hpp>

namespace AMDiS
{
  namespace tag
  {
    struct test_gradtrial {};
  }


  // first-order operator <psi, b*grad(phi)>
18
19
20
  template <class GridFct>
  class GridFunctionOperator<tag::test_gradtrial, GridFct>
      : public GridFunctionOperatorBase<GridFct>
21
  {
22
    using Super = GridFunctionOperatorBase<GridFct>;
23

24
    static_assert( Category::Vector<typename GridFct::Range>, "Expression must be of vector type." );
25
26

  public:
27
28
    GridFunctionOperator(tag::test_gradtrial, GridFct const& expr, int degree)
      : Super(expr, 1, degree)
29
30
31
32
33
34
35
36
37
38
39
40
    {}

    template <class Context, class QuadratureRule,
              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
    void calculateElementMatrix(Context const& context,
                                QuadratureRule const& quad,
                                ElementMatrix& elementMatrix,
                                RowNode const& rowNode,
                                ColNode const& colNode,
                                std::integral_constant<bool, sameFE>,
                                std::integral_constant<bool, sameNode>)
    {
41
42
      static_assert(RowNode::isLeaf && ColNode::isLeaf,
        "Operator can be applied to Leaf-Nodes only.");
43
44
45
46
47
48
49
50
51
52
53
54
55
56

      auto const& rowLocalFE = rowNode.finiteElement();
      auto const& colLocalFE = colNode.finiteElement();

      std::vector<Dune::FieldMatrix<double,1,Context::dim> > referenceGradients;

      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
        // Position of the current quadrature point in the reference element
        decltype(auto) local = context.position(quad[iq].position());

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

        // The multiplicative factor in the integral transformation formula
57
58
        double factor = context.integrationElement(quad[iq].position()) * quad[iq].weight();
        const auto b = Super::coefficient(local);
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValues_);

        // The gradients of the shape functions on the reference element
        colLocalFE.localBasis().evaluateJacobian(local, referenceGradients);

        // Compute the shape function gradients on the real element
        std::vector<Dune::FieldVector<double,Context::dow> > colGradients(referenceGradients.size());

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

        for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
          const int local_j = colNode.localIndex(j);
          double value = factor * (b * colGradients[j]);
          for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
            const int local_i = rowNode.localIndex(i);
            elementMatrix[local_i][local_j] += value * rowShapeValues_[i];
          }
        }
      }

    }

  private:
    std::vector<Dune::FieldVector<double,1>> rowShapeValues_;
  };

} // end namespace AMDiS