Commit 7e44b707 authored by Praetorius, Simon's avatar Praetorius, Simon

new operator style implemented, using tags

parent 0057b587
......@@ -14,9 +14,6 @@
namespace AMDiS
{
const Flag EQUAL_BASES = 0x01L;
const Flag EQUAL_LOCALBASES = 0x02L;
template <class Traits>
class Assembler
{
......
......@@ -110,7 +110,7 @@ void Assembler<Traits>::assembleElementOperators(
auto assemble_operators = [&](auto const& context, auto& operator_list) {
for (auto scaled : operator_list) {
scaled.op->bind(element, geometry);
bool add_op = scaled.op->assemble(context, elementContainer, localViews.tree()..., scaled.factor);
bool add_op = scaled.op->assemble(context, elementContainer, localViews.tree()...);
scaled.op->unbind();
add = add || add_op;
}
......@@ -148,18 +148,16 @@ void Assembler<Traits>::initMatrixVector(
auto localView = globalBasis_.localView();
forEachNode(localView.tree(), [&,this](auto const& rowNode, auto rowTreePath)
{
#ifdef HAVE_EXTENDED_DUNE_FUNCTIONS
if (rowNode.isLeaf)
msg(globalBasis_.dimension(rowTreePath), " DOFs for Basis[", to_string(rowTreePath), "]");
#endif
auto rowBasis = Dune::Functions::subspaceBasis(globalBasis_, rowTreePath);
//if (rhsOperators_[rowNode].assemble(asmVector))
// rhsOperators_[rowNode].init(rowBasis);
forEachNode(localView.tree(), [&,this](auto const& colNode, auto colTreePath)
{
auto colBasis = Dune::Functions::subspaceBasis(globalBasis_, colTreePath);
//if (matrixOperators_[rowNode][colNode].assemble(asmMatrix))
// matrixOperators_[rowNode][colNode].init(rowBasis, colBasis);
for (auto bc : constraints_[rowNode][colNode].scalar)
bc->init(matrix, solution, rhs, rowBasis, colBasis);
......
#pragma once
namespace AMDiS
{
template <class LocalContext, class Geometry, class LocalGeometry>
struct ContextGeometry
{
enum {
dim = Geometry::mydimension, //< the dimension of the grid element
dow = Geometry::coorddimension //< the dimension of the world
};
LocalContext const& localContext;
Geometry const& geometry;
LocalGeometry const& localGeometry;
/// Coordinate `p` given in `localGeometry`, transformed to coordinate in `geometry`.
template <class Coordinate>
decltype(auto) position(Coordinate const& p) const
{
return position(p, std::is_same<Geometry, LocalGeometry>{});
}
/// The integration element from the `localGeometry`, the quadrature points are
/// defined in.
template <class Coordinate>
auto integrationElement(Coordinate const& p) const
{
return localGeometry.integrationElement(p);
}
/// Transformation of coordinate `p` given in `localGeometry` to world space coordinates.
template <class Coordinate>
decltype(auto) global(Coordinate const& p) const
{
return geometry.global(p);
}
private: // implementation detail
// position for elements
template <class Coordinate>
Coordinate const& position(Coordinate const& p, std::true_type) const
{
return p;
}
// position for intersection
template <class Coordinate>
auto position(Coordinate const& p, std::false_type) const
{
return localGeometry.global(p);
}
};
} // end namespace AMDiS
......@@ -91,7 +91,7 @@ namespace AMDiS
{
using WorldVector = typename GlobalBasis::GridView::template Codim<0>::Geometry::GlobalCoordinate;
template <class Node>
template <class RowNode, class ColNode>
struct type
{
std::list<std::shared_ptr<DirichletBC<WorldVector, double>>> scalar;
......
#pragma once
#include <vector>
#include <dune/typetree/nodetags.hh>
#include <dune/amdis/LocalAssembler.hpp>
#include <dune/amdis/common/Mpl.hpp>
#include <dune/amdis/common/TypeDefs.hpp>
#include <dune/amdis/utility/GetEntity.hpp>
namespace AMDiS
{
template <class GridView, class LocalContext, FirstOrderType type>
class FirstOrderAssembler
: public LocalAssembler<GridView, LocalContext>
{
using Super = LocalAssembler<GridView, LocalContext>;
static constexpr int dim = GridView::dimension;
static constexpr int dow = GridView::dimensionworld;
using ElementMatrix = Impl::ElementMatrix;
using ElementVector = Impl::ElementVector;
using OrderTag = std::conditional_t<(type==GRD_PHI), tag::fot_grd_phi, tag::fot_grd_psi>;
public:
FirstOrderAssembler()
: Super(1, type)
{}
template <class Operator, class... Args>
void bind(double factor, Operator& op, LocalContext const& localContext, Args&&... args)
{
Super::bind(op, localContext, std::forward<Args>(args)...);
factor_ = factor;
op.init(OrderTag{}, localContext, Super::getQuadrature());
}
// tag dispatching for FirstOrderType...
template <class Operator, class RowNode, class ColNode>
void calculateElementMatrix(Operator& op,
ElementMatrix& elementMatrix,
RowNode const& rowNode, ColNode const& colNode)
{
calculateElementMatrix(op, elementMatrix, rowNode, colNode,
typename RowNode::NodeTag{}, typename ColNode::NodeTag{}, FirstOrderType_<type>);
}
template <class Operator, class Node>
void calculateElementVector(Operator& op,
ElementVector& elementVector,
Node const& node)
{
calculateElementVector(op, elementVector, node,
typename Node::NodeTag{}, FirstOrderType_<type>);
}
template <class Operator, class RowNode, class ColNode>
void calculateElementMatrix(Operator& op,
ElementMatrix& elementMatrix,
RowNode const& rowNode, ColNode const& colNode,
Dune::TypeTree::LeafNodeTag, Dune::TypeTree::LeafNodeTag,
FirstOrderType_t<GRD_PHI>)
{
auto const& rowLocalFE = rowNode.finiteElement();
auto const& colLocalFE = colNode.finiteElement();
auto const& quad = Super::getQuadrature().getRule();
for (std::size_t iq = 0; iq < quad.size(); ++iq) {
// Position of the current quadrature point in the reference element
decltype(auto) local = Super::getLocal(quad[iq].position());
// The transposed inverse Jacobian of the map from the reference element to the element
const auto jacobian = Super::getGeometry().jacobianInverseTransposed(local);
// The multiplicative factor in the integral transformation formula
const double factor = Super::getLocalGeometry().integrationElement(quad[iq].position()) * quad[iq].weight() * factor_;
std::vector<Dune::FieldVector<double,1> > rowShapeValues;
rowLocalFE.localBasis().evaluateFunction(local, rowShapeValues);
// The gradients of the shape functions on the reference element
std::vector<Dune::FieldMatrix<double,1,dim> > colReferenceGradients;
colLocalFE.localBasis().evaluateJacobian(local, colReferenceGradients);
// Compute the shape function gradients on the real element
std::vector<Dune::FieldVector<double,dow> > colGradients(colReferenceGradients.size());
for (std::size_t i = 0; i < colGradients.size(); ++i)
jacobian.mv(colReferenceGradients[i][0], colGradients[i]);
for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
const int local_i = rowNode.localIndex(i);
const int local_j = colNode.localIndex(j);
op.eval(tag::fot_grd_phi{}, elementMatrix[local_i][local_j], iq, factor, rowShapeValues[i], colGradients[j]);
}
}
}
}
template <class Operator, class RowNode, class ColNode>
void calculateElementMatrix(Operator& op,
ElementMatrix& elementMatrix,
RowNode const& rowNode, ColNode const& colNode,
Dune::TypeTree::LeafNodeTag, Dune::TypeTree::LeafNodeTag,
FirstOrderType_t<GRD_PSI>)
{
auto const& rowLocalFE = rowNode.finiteElement();
auto const& colLocalFE = colNode.finiteElement();
auto const& quad = Super::getQuadrature().getRule();
for (std::size_t iq = 0; iq < quad.size(); ++iq) {
// Position of the current quadrature point in the reference element
decltype(auto) local = Super::getLocal(quad[iq].position());
// The transposed inverse Jacobian of the map from the reference element to the element
const auto jacobian = Super::getGeometry().jacobianInverseTransposed(local);
// The multiplicative factor in the integral transformation formula
const double factor = Super::getLocalGeometry().integrationElement(quad[iq].position()) * quad[iq].weight() * factor_;
// The gradients of the shape functions on the reference element
std::vector<Dune::FieldMatrix<double,1,dim> > rowReferenceGradients;
rowLocalFE.localBasis().evaluateJacobian(local, rowReferenceGradients);
// Compute the shape function gradients on the real element
std::vector<Dune::FieldVector<double,dow> > rowGradients(rowReferenceGradients.size());
for (std::size_t i = 0; i < rowGradients.size(); ++i)
jacobian.mv(rowReferenceGradients[i][0], rowGradients[i]);
std::vector<Dune::FieldVector<double,1> > colShapeValues;
colLocalFE.localBasis().evaluateFunction(local, colShapeValues);
for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
const int local_i = rowNode.localIndex(i);
const int local_j = colNode.localIndex(j);
op.eval(tag::fot_grd_psi{}, elementMatrix[local_i][local_j], iq, factor, rowGradients[i], colShapeValues[j]);
}
}
}
}
template <class Operator, class RowNode, class ColNode>
void calculateElementMatrix(Operator& op,
ElementMatrix& elementMatrix,
RowNode const& rowNode, ColNode const& colNode,
Dune::TypeTree::LeafNodeTag, Dune::TypeTree::PowerNodeTag,
FirstOrderType_t<GRD_PHI>)
{
auto const& rowLocalFE = rowNode.finiteElement();
auto const& colLocalFE = colNode.child(0).finiteElement();
auto const& quad = Super::getQuadrature().getRule();
test_exit( dow == degree(colNode), "Number of childs of Power-Node must be DOW");
for (std::size_t iq = 0; iq < quad.size(); ++iq) {
// Position of the current quadrature point in the reference element
decltype(auto) local = Super::getLocal(quad[iq].position());
// The transposed inverse Jacobian of the map from the reference element to the element
const auto jacobian = Super::getGeometry().jacobianInverseTransposed(local);
// The multiplicative factor in the integral transformation formula
const double factor = Super::getLocalGeometry().integrationElement(quad[iq].position()) * quad[iq].weight() * factor_;
std::vector<Dune::FieldVector<double,1> > rowShapeValues;
rowLocalFE.localBasis().evaluateFunction(local, rowShapeValues);
// The gradients of the shape functions on the reference element
std::vector<Dune::FieldMatrix<double,1,dim> > colReferenceGradients;
colLocalFE.localBasis().evaluateJacobian(local, colReferenceGradients);
// Compute the shape function gradients on the real element
std::vector<Dune::FieldVector<double,dow> > colGradients(colReferenceGradients.size());
for (std::size_t i = 0; i < colGradients.size(); ++i)
jacobian.mv(colReferenceGradients[i][0], colGradients[i]);
// <div(u), q>
for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
const int local_i = rowNode.localIndex(i);
for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
for (std::size_t k = 0; k < degree(colNode); ++k) {
const int local_j = colNode.child(k).localIndex(j);
op.eval(tag::fot_grd_phi{}, elementMatrix[local_i][local_j], iq, factor, rowShapeValues[i], colGradients[j][k]);
}
}
}
}
}
template <class Operator, class RowNode, class ColNode>
void calculateElementMatrix(Operator& op,
ElementMatrix& elementMatrix,
RowNode const& rowNode, ColNode const& colNode,
Dune::TypeTree::PowerNodeTag, Dune::TypeTree::LeafNodeTag,
FirstOrderType_t<GRD_PSI>)
{
auto const& rowLocalFE = rowNode.child(0).finiteElement();
auto const& colLocalFE = colNode.finiteElement();
auto const& quad = Super::getQuadrature().getRule();
test_exit( dow == degree(rowNode), "Number of childs of Power-Node must be DOW");
for (std::size_t iq = 0; iq < quad.size(); ++iq) {
// Position of the current quadrature point in the reference element
decltype(auto) local = Super::getLocal(quad[iq].position());
// The transposed inverse Jacobian of the map from the reference element to the element
const auto jacobian = Super::getGeometry().jacobianInverseTransposed(local);
// The multiplicative factor in the integral transformation formula
const double factor = Super::getLocalGeometry().integrationElement(quad[iq].position()) * quad[iq].weight() * factor_;
// The gradients of the shape functions on the reference element
std::vector<Dune::FieldMatrix<double,1,dim> > rowReferenceGradients;
rowLocalFE.localBasis().evaluateJacobian(local, rowReferenceGradients);
// Compute the shape function gradients on the real element
std::vector<Dune::FieldVector<double,dow> > rowGradients(rowReferenceGradients.size());
for (std::size_t i = 0; i < rowGradients.size(); ++i)
jacobian.mv(rowReferenceGradients[i][0], rowGradients[i]);
std::vector<Dune::FieldVector<double,1> > colShapeValues;
colLocalFE.localBasis().evaluateFunction(local, colShapeValues);
// <p, div(v)>
for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
const int local_j = colNode.localIndex(j);
for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
for (std::size_t k = 0; k < degree(rowNode); ++k) {
const int local_i = rowNode.child(k).localIndex(i);
op.eval(tag::fot_grd_psi{}, elementMatrix[local_i][local_j], iq, factor, rowGradients[i][k], colShapeValues[j]);
}
}
}
}
}
template <class Operator, class RowNode, class ColNode, class RowNodeTag, class ColNodeTag, class FOT>
void calculateElementMatrix(Operator&, ElementMatrix&,
RowNode const&, ColNode const&,
RowNodeTag, ColNodeTag, FOT)
{
warning("FirstOrderAssembler::calculateElementMatrix not implemented for RowNode x ColNode");
}
template <class Operator, class Node>
void calculateElementVector(Operator& op,
ElementVector& elementVector,
Node const& node,
Dune::TypeTree::LeafNodeTag,
FirstOrderType_t<GRD_PSI>)
{
auto const& localFE = node.finiteElement();
auto const& quad = Super::getQuadrature().getRule();
for (std::size_t iq = 0; iq < quad.size(); ++iq) {
// Position of the current quadrature point in the reference element
decltype(auto) local = Super::getLocal(quad[iq].position());
// The transposed inverse Jacobian of the map from the reference element to the element
const auto jacobian = Super::getGeometry().jacobianInverseTransposed(local);
// The multiplicative factor in the integral transformation formula
const double factor = Super::getLocalGeometry().integrationElement(quad[iq].position()) * quad[iq].weight() * factor_;
// The gradients of the shape functions on the reference element
std::vector<Dune::FieldMatrix<double,1,dim> > rowReferenceGradients;
localFE.localBasis().evaluateJacobian(local, rowReferenceGradients);
// Compute the shape function gradients on the real element
std::vector<Dune::FieldVector<double,dow> > rowGradients(rowReferenceGradients.size());
for (std::size_t i = 0; i < rowGradients.size(); ++i)
jacobian.mv(rowReferenceGradients[i][0], rowGradients[i]);
for (std::size_t i = 0; i < localFE.size(); ++i) {
const int local_i = node.localIndex(i);
op.eval(tag::fot_grd_psi{}, elementVector[local_i], iq, factor, rowGradients[i]);
}
}
}
template <class Operator, class Node, class NodeTag, class FOT>
void calculateElementVector(Operator&, ElementVector&,
Node const&, NodeTag, FOT)
{
warning("FirstOrderAssembler::calculateElementVector not implemented for Node");
}
private:
double factor_;
};
} // end namespace AMDiS
#pragma once
// std c++ headers
#include <functional>
#include <memory>
#include <type_traits>
// AMDiS includes
#include <dune/amdis/QuadratureRules.hpp>
#include <dune/amdis/common/TypeDefs.hpp>
#include <dune/geometry/quadraturerules.hh>
#include <dune/amdis/ContextGeometry.hpp>
#include <dune/amdis/LocalAssemblerBase.hpp>
#include <dune/amdis/common/Concepts.hpp>
#include <dune/amdis/utility/FiniteElementType.hpp>
namespace AMDiS
{
// the LocalContext is either an Codim=0-EntityType or an IntersectionType
template <class GridView, class LocalContext>
/// Implementation of interface \ref LocalAssemblerBase
template <class LocalContext, class Operator, class... Nodes>
class LocalAssembler
: public LocalAssemblerBase<LocalContext, Nodes...>
{
static constexpr int dim = GridView::dimension;
using ctype = typename GridView::ctype;
using Super = LocalAssemblerBase<LocalContext, Nodes...>;
private:
using Element = typename Super::Element;
using ElementMatrixVector = typename Super::ElementMatrixVector;
using LocalQuadratureRules = Dune::QuadratureRules<ctype, LocalContext::mydimension>;
using QuadratureRule = QuadratureRuleFactory_t<LocalContext, ctype, dim>;
using Geometry = typename Super::Geometry;
using LocalGeometry = typename Super::LocalGeometry;
using Geometry = typename GridView::template Codim<0>::Entity::Geometry;
using LocalGeometry = typename Impl::Get<LocalContext>::Geometry;
using Context = ContextGeometry<LocalContext, Geometry, LocalGeometry>;
public:
explicit LocalAssembler(int degree, FirstOrderType type = GRD_PHI)
: degree_(degree)
, type_(type)
/// Constructor. Stores a copy of operator `op`.
explicit LocalAssembler(Operator const& op)
: opStorage_(std::make_unique<Operator>(op))
, op_(*opStorage_)
{}
/// Constructor. Stores the reference to the operator.
explicit LocalAssembler(std::reference_wrapper<Operator> const& op)
: op_(op)
{}
/// Constructor, initializes the geometry of the element and a
/// quadrature-rule wrapper
template <class Operator>
void bind(Operator& op, LocalContext const& localContext, Geometry const& geometry, LocalGeometry const& localGeometry)
/// \brief Implementation of \ref LocalAssemblerBase::bind.
/**
* Binds the operator `op_` to the `element` and `geometry` and
* stores point to the `element` and `geometry`.
**/
virtual void bind(Element const& element, Geometry const& geometry) final
{
localContext_ = &localContext;
element_ = &element;
geometry_ = &geometry;
localGeometry_ = &localGeometry;
int order = op.getQuadratureDegree(localGeometry.type(), localGeometry, degree_, type_);
auto const& quad = LocalQuadratureRules::rule(localGeometry.type(), order);
quadrature_.reset(new QuadratureRule(localContext, quad));
op_.bind(element, geometry);
}
void unbind()
/// \brief Implementation of \ref LocalAssemblerBase::unbind
/**
* Unbinds the operator `op_` and sets \ref element_ and \ref geometry_
* to nullptr.
**/
virtual void unbind() final
{
localContext_ = nullptr;
op_.unbind();
geometry_ = nullptr;
localGeometry_ = nullptr;
element_ = nullptr;
}
/// \brief Returns reference to the transformed quadrature rule
/// Implementation of \ref LocalAssemblerBase::assemble
/**
* For intersections this corresponds to the points in the intersection
* geometry, but coordinates extended to the whole inside-entity. For
* elements this is a wrapper around the classical element quadrature rule.
* Access the underlying dune-quadrature rule, with `quadrature->getRule()`.
* Provides a quadrature formula with necessary degree to integrate the operator,
* stores geometry and localGeometry and a \ref ContextGeometry and calls
* \ref calculateElementVector or \ref calculateElementMatrix on the
* vector or matrix operator, respectively.
*
* The call to operator passes two optimization flags:
* 1. RowNode and ColNode implement the same local finiteelement
* 2. RowNode and ColNode are the same node in the globalBasis tree.
**/
QuadratureRule const& getQuadrature() const
virtual bool assemble(
LocalContext const& localContext,
ElementMatrixVector& elementMatrixVector,
Nodes const&... nodes) final
{
assert( quadrature_ );
return *quadrature_;
decltype(auto) localGeometry = getLocalGeometry(localContext);
using QuadratureRules = Dune::QuadratureRules<typename Geometry::ctype, LocalContext::mydimension>;
int degree = op_.getDegree(nodes...);
auto const& quad = QuadratureRules::rule(localGeometry.type(), degree);
Context data{localContext, getGeometry(), localGeometry};
assembleImpl(data, quad, elementMatrixVector, nodes...);
return true;
}
#ifndef DOXYGEN
protected: // implementation detail
// matrix assembling
template <class QuadratureRule, class ElementMatrix, class RowNode, class ColNode>
void assembleImpl(Context const& context,
QuadratureRule const& quad,
ElementMatrix& elementMatrix,
RowNode const& rowNode, ColNode const& colNode)
{
assembleImpl(context, quad, elementMatrix, rowNode, colNode,
std::is_same<FiniteElementType_t<RowNode>, FiniteElementType_t<ColNode>>{});
}
LocalContext const& getLocalContext() const
// local finite elements are the same for rowNode and colNode
template <class QuadratureRule, class ElementMatrix, class RowNode, class ColNode>
void assembleImpl(Context const& context,
QuadratureRule const& quad,
ElementMatrix& elementMatrix,
RowNode const& rowNode, ColNode const& colNode,
std::true_type /*sameFE*/)
{
assert( localContext_ );
return *localContext_;
if (rowNode.treeIndex() == colNode.treeIndex())
op_.calculateElementMatrix(
context, quad, elementMatrix, rowNode, colNode, std::true_type{}, std::true_type{});
else
op_.calculateElementMatrix(
context, quad, elementMatrix, rowNode, colNode, std::true_type{}, std::false_type{});
}
// local finite elements are different for rowNode and colNode
template <class QuadratureRule, class ElementMatrix, class RowNode, class ColNode>
void assembleImpl(Context const& context,
QuadratureRule const& quad,
ElementMatrix& elementMatrix,
RowNode const& rowNode, ColNode const& colNode,
std::false_type /*sameFE*/)
{
op_.calculateElementMatrix(
context, quad, elementMatrix, rowNode, colNode, std::false_type{}, std::false_type{});