FirstOrderDivTestvec.hpp 3.19 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
88
89
90
91
92
93
#pragma once

#include <type_traits>

#include <amdis/GridFunctionOperator.hpp>
#include <amdis/LocalBasisCache.hpp>
#include <amdis/Output.hpp>
#include <amdis/common/Size.hpp>

namespace AMDiS
{
  /**
   * \addtogroup operators
   * @{
   **/

  namespace tag
  {
    struct divtestvec {};
  }


  /// first-order operator \f$ \langle\nabla\cdot\Psi, c\rangle \f$
  template <class LocalContext, class GridFct>
  class GridFunctionOperator<tag::divtestvec, LocalContext, GridFct>
      : public GridFunctionOperatorBase<GridFunctionOperator<tag::divtestvec, LocalContext, GridFct>,
                                        LocalContext, GridFct>
  {
    using Self = GridFunctionOperator;
    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;

    static_assert( Size_v<typename GridFct::Range> == 1, "Expression must be of scalar type." );

  public:
    GridFunctionOperator(tag::divtestvec, GridFct const& expr)
      : Super(expr, 1)
    {}

    template <class Context, class Node, class ElementVector>
    void getElementVector(Context const& context,
                          Node const& node,
                          ElementVector& elementVector)
    {
      static_assert(Node::isPower, "Node must be a Power-Node.");

      static const std::size_t CHILDREN = Node::CHILDREN;
      static_assert( CHILDREN == Context::dow, "" );

      auto const& quad = this->getQuadratureRule(context.type(), node);
      auto const& localFE = node.child(0).finiteElement();
      std::size_t feSize = localFE.size();

      using LocalBasisType = typename std::decay_t<decltype(localFE)>::Traits::LocalBasisType;
      using RangeFieldType = typename LocalBasisType::Traits::RangeFieldType;

      LocalBasisCache<LocalBasisType> cache(localFE.localBasis());

      auto const& shapeGradientsCache = cache.evaluateJacobianAtQp(context, quad);
      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
        // Position of the current quadrature point in the reference element
        decltype(auto) local = context.local(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
        const auto factor = Super::coefficient(local) * context.integrationElement(quad[iq].position()) * quad[iq].weight();

        // The gradients of the shape functions on the reference element
        auto const& shapeGradients = shapeGradientsCache[iq];

        // Compute the shape function gradients on the real element
        using WorldVector = FieldVector<RangeFieldType,Context::dow>;
        thread_local std::vector<WorldVector> gradients;
        gradients.resize(shapeGradients.size());

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

        for (std::size_t j = 0; j < feSize; ++j) {
          for (std::size_t k = 0; k < CHILDREN; ++k) {
            const auto local_kj = node.child(k).localIndex(j);
            elementVector[local_kj] += factor * gradients[j][k];
          }
        }
      }

    }
  };

  /** @} **/

} // end namespace AMDiS