Commit 36d6a365 authored by Praetorius, Simon's avatar Praetorius, Simon

Merge branch 'feature/local_operator' into 'develop'

Feature/local operator

See merge request !24
parents fd552d52 15764e96
Pipeline #1111 passed with stage
in 3 minutes and 24 seconds
......@@ -32,6 +32,8 @@ int main(int argc, char** argv)
auto opForce = makeOperator(tag::test{}, [](auto const& x) { return -1.0; }, 0);
prob.addVectorOperator(opForce, _0);
auto opForce2 = makeOperator(tag::test{}, [](auto const& x) { return -2.0; }, 0);
prob.addVectorOperator(BoundaryType{0}, opForce2, _0);
// set boundary condition
auto predicate = [](auto const& x){ return x[0] < 1.e-8 || x[1] < 1.e-8; }; // define boundary
......
......@@ -8,7 +8,7 @@
#include <amdis/DirichletBC.hpp>
#include <amdis/LinearAlgebra.hpp>
#include <amdis/LocalAssemblerBase.hpp>
#include <amdis/LocalAssemblerList.hpp>
#include <amdis/common/Mpl.hpp>
#include <amdis/common/TypeDefs.hpp>
......@@ -54,6 +54,8 @@ namespace AMDiS
SystemVectorType& rhs,
bool asmMatrix, bool asmVector) const;
/// Assemble operators on an element, by passing the element/intersection to
/// `elementAssembler` functor.
template <class Element, class Operators, class ElementAssembler>
void assembleElementOperators(
Element const& element,
......@@ -70,14 +72,14 @@ namespace AMDiS
bool asmMatrix, bool asmVector) const;
/// Return whether the matrix-block needs to be assembled
/// Return the element the LocalViews are bound to
template <class LocalView0, class... LovalViews>
auto const& getElement(LocalView0 const& localView, LovalViews const&...) const
{
return localView.element();
}
/// Return whether the matrix-block needs to be assembled
/// Return the gridView the localViews are bound to
template <class LocalView0, class... LovalViews>
auto const& getGridView(LocalView0 const& localView, LovalViews const&...) const
{
......
......@@ -45,12 +45,12 @@ void Assembler<Traits>::assemble(
rowLocalView.bind(element);
auto& rhsOp = rhsOperators_[rowNode];
if (rhsOp.assemble(asmVector) && !rhsOp.empty()) {
if (rhsOp.doAssemble(asmVector) && !rhsOp.empty()) {
rhsOp.bind(element, geometry);
auto vecAssembler = [&](auto const& context, auto& operator_list) {
for (auto scaled : operator_list)
scaled.op->assemble(context, elementVector, rowLocalView.tree());
scaled.op->assemble(context, rowLocalView.tree(), elementVector);
};
this->assembleElementOperators(element, rhsOp, vecAssembler);
......@@ -59,7 +59,7 @@ void Assembler<Traits>::assemble(
AMDiS::forEachNode_(localView.tree(), [&,this](auto const& colNode, auto colTreePath)
{
auto& matOp = matrixOperators_[rowNode][colNode];
if (matOp.assemble(asmMatrix) && !matOp.empty()) {
if (matOp.doAssemble(asmMatrix) && !matOp.empty()) {
auto colBasis = Dune::Functions::subspaceBasis(globalBasis_, colTreePath);
auto colLocalView = colBasis.localView();
colLocalView.bind(element);
......@@ -68,7 +68,7 @@ void Assembler<Traits>::assemble(
auto matAssembler = [&](auto const& context, auto& operator_list) {
for (auto scaled : operator_list)
scaled.op->assemble(context, elementMatrix, rowLocalView.tree(), colLocalView.tree());
scaled.op->assemble(context, rowLocalView.tree(), colLocalView.tree(), elementMatrix);
};
this->assembleElementOperators(element, matOp, matAssembler);
......@@ -121,10 +121,10 @@ template <class Traits>
void Assembler<Traits>::assembleElementOperators(
Element const& element,
Operators& operators,
ElementAssembler const& elementAssembler) const
ElementAssembler const& localAssembler) const
{
// assemble element operators
elementAssembler(element, operators.element);
localAssembler(element, operators.element);
// assemble intersection operators
if (!operators.intersection.empty()
......@@ -132,9 +132,9 @@ void Assembler<Traits>::assembleElementOperators(
{
for (auto const& intersection : intersections(globalBasis_.gridView(), element)) {
if (intersection.boundary())
elementAssembler(intersection, operators.boundary);
localAssembler(intersection, operators.boundary);
else
elementAssembler(intersection, operators.intersection);
localAssembler(intersection, operators.intersection);
}
}
}
......@@ -191,14 +191,14 @@ std::size_t Assembler<Traits>::finishMatrixVector(
{
auto rowBasis = Dune::Functions::subspaceBasis(globalBasis_, rowTreePath);
auto& rhsOp = rhsOperators_[rowNode];
if (rhsOp.assemble(asmVector))
if (rhsOp.doAssemble(asmVector))
rhsOp.assembled = true;
AMDiS::forEachNode_(localView.tree(), [&,this](auto const& colNode, auto colTreePath)
{
auto colBasis = Dune::Functions::subspaceBasis(globalBasis_, colTreePath);
auto& matOp = matrixOperators_[rowNode][colNode];
if (matOp.assemble(asmMatrix))
if (matOp.doAssemble(asmMatrix))
matOp.assembled = true;
// finish boundary condition
......
#pragma once
#include <type_traits>
#include <dune/common/typetraits.hh>
#include <dune/common/std/optional.hh>
#include <dune/geometry/type.hh>
namespace AMDiS
{
template <class LocalContext, class Geometry, class LocalGeometry>
namespace Impl
{
template <class E, class = Dune::void_t<>>
struct ContextTypes
{
using Entity = E;
using LocalGeometry = typename E::Geometry;
};
// specialization for intersections
template <class I>
struct ContextTypes<I, Dune::void_t<decltype(std::declval<I>().inside())>>
{
using Entity = typename I::Entity;
using LocalGeometry = typename I::LocalGeometry;
};
} // end namespace Impl
/// \brief Wrapper class for element and geometry
/**
* A LocalContext can be either a grid entity of codim 0 (called an element)
* or an intersection of elements. The element and its geometry may be stored
* externally and can be passed along with the localContext object.
* Since an intersection has a geometry (and localGeometry) different from the
* geometry (and localGeometry) of the entity it belongs to, these objects
* are provided as well.
**/
template <class LocalContextType>
struct ContextGeometry
{
public:
using LocalContext = LocalContextType;
using Element = typename Impl::ContextTypes<LocalContext>::Entity;
using Geometry = typename Element::Geometry;
using LocalGeometry = typename Impl::ContextTypes<LocalContext>::LocalGeometry;
using IsEntity = std::is_same<Element, LocalContext>;
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;
ContextGeometry(LocalContext const& localContext,
Geometry const& geometry,
LocalGeometry const& localGeometry)
: localContext(localContext)
, geometry(geometry)
, localGeometry(localGeometry)
/// Constructor. Stores pointer to localContext, element, and geometry.
ContextGeometry(LocalContext const& localContext, Element const& element, Geometry const& geometry)
: localContext_(&localContext)
, element_(&element)
, geometry_(&geometry)
{}
/// Coordinate `p` given in `localGeometry`, transformed to coordinate in `geometry`.
template <class Coordinate>
decltype(auto) position(Coordinate const& p) const
public:
Element const& element() const
{
return position(p, std::is_same<Geometry, LocalGeometry>{});
return *element_;
}
/// The integration element from the `localGeometry`, the quadrature points are
/// defined in.
LocalContext const& localContext() const
{
return *localContext_;
}
Geometry const& geometry() const
{
return *geometry_;
}
LocalGeometry const& localGeometry() const
{
return localGeometryImpl(IsEntity{});
}
public:
/// Coordinate `p` given in `localGeometry`, transformed to coordinate in `geometry`.
template <class Coordinate>
auto integrationElement(Coordinate const& p) const
decltype(auto) local(Coordinate const& p) const
{
return localGeometry.integrationElement(p);
return localImpl(p, IsEntity{});
}
/// 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);
return geometry_->global(p);
}
/// Return the geometry-type of the localContext
Dune::GeometryType type() const
{
return localContext_->type();
}
/// 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);
}
private: // implementation detail
// position for elements
template <class Coordinate>
Coordinate const& position(Coordinate const& p, std::true_type) const
Coordinate const& localImpl(Coordinate const& p, std::true_type) const
{
return p;
}
// position for intersection
template <class Coordinate>
auto position(Coordinate const& p, std::false_type) const
auto localImpl(Coordinate const& p, std::false_type) const
{
return localGeometry().global(p);
}
// local-geometry is the same as geometry
Geometry const& localGeometryImpl(std::true_type) const
{
return *geometry_;
}
// local-geometry of intersection in inside element
LocalGeometry const& localGeometryImpl(std::false_type) const
{
return localGeometry.global(p);
if (!localGeometry_)
localGeometry_.emplace(localContext_->geometryInInside());
return *localGeometry_;
}
private:
LocalContext const* localContext_;
Element const* element_;
Geometry const* geometry_;
// The localGeometry may be constructed only if needed
mutable Dune::Std::optional<LocalGeometry> localGeometry_;
};
} // end namespace AMDiS
#pragma once
#include <amdis/common/TupleUtility.hpp>
#include <amdis/common/IndexSeq.hpp>
#include <amdis/common/Loops.hpp>
namespace AMDiS
{
template <class FeSpace>
struct LocalView
{
using type = typename FeSpace::LocalView;
};
template <class FeSpace>
struct LocalIndexSet
{
using type = typename FeSpace::LocalIndexSet;
};
template <class FeSpaces>
class FiniteElementSpaces
{
template <std::size_t I>
using FeSpace = std::tuple_element_t<I, FeSpaces>;
static constexpr int nComponents = std::tuple_size<FeSpaces>::value;
static_assert( nComponents > 0, "" );
using LocalViews = MapTuple_t<LocalView, FeSpaces>;
using LocalIndexSets = MapTuple_t<LocalIndexSet, FeSpaces>;
/// The grid view the global FE basis lives on
using GridView = typename FeSpace<0>::GridView;
/// Type of the grid element we are bound to
using Element = typename GridView::template Codim<0>::Entity;
public:
explicit FiniteElementSpaces(std::shared_ptr<FeSpaces> const& feSpaces)
: feSpaces_(feSpaces)
, localViews_(mapTuple([](auto const& basis) { return basis.localView(); }, *feSpaces))
, localIndexSets_(mapTuple([](auto const& basis) { return basis.localIndexSet(); }, *feSpaces))
{}
/// Update all global bases. This will update the indexing information of the global basis.
/// NOTE: It must be called if the grid has changed.
void update(GridView const& gv)
{
forEach(range_<0, nComponents>, [&,this](auto const _i)
{
static const int I = decltype(_i)::value;
std::get<I>(*feSpaces_).update(gv);
});
}
/// Bind the \ref localViews and \ref localIndexSets to a grid element
void bind(Element const& element)
{
forEach(range_<0, nComponents>, [&,this](auto const _i)
{
static const int I = decltype(_i)::value;
auto& localView = std::get<I>(localViews_);
localView.bind(element);
auto& localIndexSet = std::get<I>(localIndexSets_);
localIndexSet.bind(localView);
});
// NOTE: maybe create element-geometry here
bound_ = true;
}
/// Unbind from the current element
void unbind()
{
forEach(range_<0, nComponents>, [&,this](auto const _i)
{
static const int I = decltype(_i)::value;
std::get<I>(localIndexSets_).unbind();
std::get<I>(localViews_).unbind();
});
bound_ = false;
}
template <std::size_t I>
auto const& feSpace(const index_t<I> _i = {}) const
{
return std::get<I>(*feSpaces_);
}
template <std::size_t I>
auto const& localView(const index_t<I> _i = {}) const
{
assert( bound_ && "localViews must be bound to an element." );
return std::get<I>(localViews_);
}
template <std::size_t I>
auto const& localIndexSet(const index_t<I> _i = {}) const
{
assert( bound_ && "localIndexSets must be bound to a localView." );
return std::get<I>(localIndexSets_);
}
auto const& element() const
{
assert( bound_ && "localViews must be bound to an element." );
return std::get<0>(localViews_).element();
}
auto const& gridView() const
{
return std::get<0>(*feSpaces_).gridView();
}
private:
/// Tuple of global functionspace bases
std::shared_ptr<FeSpaces> feSpaces_;
/// Tuple of localView objects, obtained from the tuple of global bases
LocalViews localViews_;
/// Tuple of localIndexSet objects, obtained from the tuple of global bases
LocalIndexSets localIndexSets_;
/// True, if localViews and localIndexSets are bound to an element
bool bound_ = false;
};
} // end namespace AMDiS
This diff is collapsed.
......@@ -23,12 +23,8 @@ namespace AMDiS
private:
using Element = typename Super::Element;
using ElementMatrixVector = typename Super::ElementMatrixVector;
using Geometry = typename Super::Geometry;
using LocalGeometry = typename Super::LocalGeometry;
using Context = ContextGeometry<LocalContext, Geometry, LocalGeometry>;
using ElementMatrixVector = typename Super::ElementMatrixVector;
public:
......@@ -69,26 +65,16 @@ namespace AMDiS
/// Implementation of \ref LocalAssemblerBase::assemble
/**
* Provides a quadrature formula with necessary degree to integrate the operator,
* stores geometry and localGeometry and a \ref ContextGeometry and calls
* Stores geometry and localGeometry 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.
**/
virtual bool assemble(
LocalContext const& localContext,
ElementMatrixVector& elementMatrixVector,
Nodes const&... nodes) final
virtual void assemble(LocalContext const& localContext,
Nodes const&... nodes,
ElementMatrixVector& elementMatrixVector) final
{
auto&& localGeometry = getLocalGeometry(localContext);
auto&& quad = op_.getQuadratureRule(localGeometry.type(), nodes...);
Context data{localContext, getGeometry(), localGeometry};
assembleImpl(data, std::forward<decltype(quad)>(quad), elementMatrixVector, nodes...);
return true;
ContextGeometry<LocalContext> context{localContext, getElement(), getGeometry()};
assembleImpl(context, nodes..., elementMatrixVector);
}
......@@ -97,96 +83,46 @@ namespace AMDiS
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>>{});
}
// 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*/)
{
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>
template <class Context, class RowNode, class ColNode, class ElementMatrix>
void assembleImpl(Context const& context,
QuadratureRule const& quad,
ElementMatrix& elementMatrix,
RowNode const& rowNode, ColNode const& colNode,
std::false_type /*sameFE*/)
ElementMatrix& elementMatrix)
{
op_.calculateElementMatrix(
context, quad, elementMatrix, rowNode, colNode, std::false_type{}, std::false_type{});
op_.calculateElementMatrix(context, rowNode, colNode, elementMatrix);
}
// vector assembling
template <class QuadratureRule, class ElementVector, class Node>
template <class Context, class Node, class ElementVector>
void assembleImpl(Context const& context,
QuadratureRule const& quad,
ElementVector& elementVector,
Node const& node)
Node const& node,
ElementVector& elementVector)
{
op_.calculateElementVector(context, quad, elementVector, node);
op_.calculateElementVector(context, node, elementVector);
}
#endif // DOXYGEN
public:
/// return the bound entity (of codim 0)
Element const& getElement() const
{
assert( element_ );
return *element_;
}
/// return the geometry of the bound element
Geometry const& getGeometry() const
{
assert( geometry_ );
return *geometry_;
}
decltype(auto) getLocalGeometry(LocalContext const& context) const
{
return getLocalGeometry(context, std::is_same<LocalContext, Element>{});
}
private: // implementation detail
// localGeometry for Entities
Geometry const& getLocalGeometry(Element const& element, std::true_type) const
{
return *geometry_;
}
// localGeometry for intersections
LocalGeometry getLocalGeometry(LocalContext const& intersection, std::false_type) const
{
return intersection.geometryInInside();
}
private:
std::unique_ptr<Operator> storage_; //< the stored operator, implementing \ref GridFunctionOperatorBase
/// the stored operator, implementing \ref GridFunctionOperatorBase
std::unique_ptr<Operator> storage_;
Operator& op_;
Element const* element_ = nullptr;
......
#pragma once
#include <list>
#include <memory>
#include <type_traits>
#include <amdis/common/ConceptsBase.hpp>
#include <amdis/ContextGeometry.hpp>
// #include <amdis/common/ConceptsBase.hpp>
#include <amdis/common/TypeDefs.hpp>
#include <amdis/utility/TreeData.hpp>
namespace AMDiS
{
namespace Impl
{
template <class E, class = Void_t<>>
struct ContextImpl
{
using Entity = E;
using Geometry = typename E::Geometry;
};
// specialization for intersections
template <class I>
struct ContextImpl<I, Void_t<decltype(std::declval<I>().inside())>>
{
using Entity = typename I::Entity;
using Geometry = typename I::LocalGeometry;
};