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

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) ...@@ -32,6 +32,8 @@ int main(int argc, char** argv)
auto opForce = makeOperator(tag::test{}, [](auto const& x) { return -1.0; }, 0); auto opForce = makeOperator(tag::test{}, [](auto const& x) { return -1.0; }, 0);
prob.addVectorOperator(opForce, _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 // set boundary condition
auto predicate = [](auto const& x){ return x[0] < 1.e-8 || x[1] < 1.e-8; }; // define boundary auto predicate = [](auto const& x){ return x[0] < 1.e-8 || x[1] < 1.e-8; }; // define boundary
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include <amdis/DirichletBC.hpp> #include <amdis/DirichletBC.hpp>
#include <amdis/LinearAlgebra.hpp> #include <amdis/LinearAlgebra.hpp>
#include <amdis/LocalAssemblerBase.hpp> #include <amdis/LocalAssemblerList.hpp>
#include <amdis/common/Mpl.hpp> #include <amdis/common/Mpl.hpp>
#include <amdis/common/TypeDefs.hpp> #include <amdis/common/TypeDefs.hpp>
...@@ -54,6 +54,8 @@ namespace AMDiS ...@@ -54,6 +54,8 @@ namespace AMDiS
SystemVectorType& rhs, SystemVectorType& rhs,
bool asmMatrix, bool asmVector) const; 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> template <class Element, class Operators, class ElementAssembler>
void assembleElementOperators( void assembleElementOperators(
Element const& element, Element const& element,
...@@ -70,14 +72,14 @@ namespace AMDiS ...@@ -70,14 +72,14 @@ namespace AMDiS
bool asmMatrix, bool asmVector) const; 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> template <class LocalView0, class... LovalViews>
auto const& getElement(LocalView0 const& localView, LovalViews const&...) const auto const& getElement(LocalView0 const& localView, LovalViews const&...) const
{ {
return localView.element(); 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> template <class LocalView0, class... LovalViews>
auto const& getGridView(LocalView0 const& localView, LovalViews const&...) const auto const& getGridView(LocalView0 const& localView, LovalViews const&...) const
{ {
......
...@@ -45,12 +45,12 @@ void Assembler<Traits>::assemble( ...@@ -45,12 +45,12 @@ void Assembler<Traits>::assemble(
rowLocalView.bind(element); rowLocalView.bind(element);
auto& rhsOp = rhsOperators_[rowNode]; auto& rhsOp = rhsOperators_[rowNode];
if (rhsOp.assemble(asmVector) && !rhsOp.empty()) { if (rhsOp.doAssemble(asmVector) && !rhsOp.empty()) {
rhsOp.bind(element, geometry); rhsOp.bind(element, geometry);
auto vecAssembler = [&](auto const& context, auto& operator_list) { auto vecAssembler = [&](auto const& context, auto& operator_list) {
for (auto scaled : 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); this->assembleElementOperators(element, rhsOp, vecAssembler);
...@@ -59,7 +59,7 @@ void Assembler<Traits>::assemble( ...@@ -59,7 +59,7 @@ void Assembler<Traits>::assemble(
AMDiS::forEachNode_(localView.tree(), [&,this](auto const& colNode, auto colTreePath) AMDiS::forEachNode_(localView.tree(), [&,this](auto const& colNode, auto colTreePath)
{ {
auto& matOp = matrixOperators_[rowNode][colNode]; 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 colBasis = Dune::Functions::subspaceBasis(globalBasis_, colTreePath);
auto colLocalView = colBasis.localView(); auto colLocalView = colBasis.localView();
colLocalView.bind(element); colLocalView.bind(element);
...@@ -68,7 +68,7 @@ void Assembler<Traits>::assemble( ...@@ -68,7 +68,7 @@ void Assembler<Traits>::assemble(
auto matAssembler = [&](auto const& context, auto& operator_list) { auto matAssembler = [&](auto const& context, auto& operator_list) {
for (auto scaled : 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); this->assembleElementOperators(element, matOp, matAssembler);
...@@ -121,10 +121,10 @@ template <class Traits> ...@@ -121,10 +121,10 @@ template <class Traits>
void Assembler<Traits>::assembleElementOperators( void Assembler<Traits>::assembleElementOperators(
Element const& element, Element const& element,
Operators& operators, Operators& operators,
ElementAssembler const& elementAssembler) const ElementAssembler const& localAssembler) const
{ {
// assemble element operators // assemble element operators
elementAssembler(element, operators.element); localAssembler(element, operators.element);
// assemble intersection operators // assemble intersection operators
if (!operators.intersection.empty() if (!operators.intersection.empty()
...@@ -132,9 +132,9 @@ void Assembler<Traits>::assembleElementOperators( ...@@ -132,9 +132,9 @@ void Assembler<Traits>::assembleElementOperators(
{ {
for (auto const& intersection : intersections(globalBasis_.gridView(), element)) { for (auto const& intersection : intersections(globalBasis_.gridView(), element)) {
if (intersection.boundary()) if (intersection.boundary())
elementAssembler(intersection, operators.boundary); localAssembler(intersection, operators.boundary);
else else
elementAssembler(intersection, operators.intersection); localAssembler(intersection, operators.intersection);
} }
} }
} }
...@@ -191,14 +191,14 @@ std::size_t Assembler<Traits>::finishMatrixVector( ...@@ -191,14 +191,14 @@ std::size_t Assembler<Traits>::finishMatrixVector(
{ {
auto rowBasis = Dune::Functions::subspaceBasis(globalBasis_, rowTreePath); auto rowBasis = Dune::Functions::subspaceBasis(globalBasis_, rowTreePath);
auto& rhsOp = rhsOperators_[rowNode]; auto& rhsOp = rhsOperators_[rowNode];
if (rhsOp.assemble(asmVector)) if (rhsOp.doAssemble(asmVector))
rhsOp.assembled = true; rhsOp.assembled = true;
AMDiS::forEachNode_(localView.tree(), [&,this](auto const& colNode, auto colTreePath) AMDiS::forEachNode_(localView.tree(), [&,this](auto const& colNode, auto colTreePath)
{ {
auto colBasis = Dune::Functions::subspaceBasis(globalBasis_, colTreePath); auto colBasis = Dune::Functions::subspaceBasis(globalBasis_, colTreePath);
auto& matOp = matrixOperators_[rowNode][colNode]; auto& matOp = matrixOperators_[rowNode][colNode];
if (matOp.assemble(asmMatrix)) if (matOp.doAssemble(asmMatrix))
matOp.assembled = true; matOp.assembled = true;
// finish boundary condition // finish boundary condition
......
#pragma once #pragma once
#include <type_traits>
#include <dune/common/typetraits.hh>
#include <dune/common/std/optional.hh>
#include <dune/geometry/type.hh>
namespace AMDiS 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 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 { enum {
dim = Geometry::mydimension, //< the dimension of the grid element dim = Geometry::mydimension, //< the dimension of the grid element
dow = Geometry::coorddimension //< the dimension of the world dow = Geometry::coorddimension //< the dimension of the world
}; };
LocalContext const& localContext; /// Constructor. Stores pointer to localContext, element, and geometry.
Geometry const& geometry; ContextGeometry(LocalContext const& localContext, Element const& element, Geometry const& geometry)
LocalGeometry const& localGeometry; : localContext_(&localContext)
, element_(&element)
ContextGeometry(LocalContext const& localContext, , geometry_(&geometry)
Geometry const& geometry,
LocalGeometry const& localGeometry)
: localContext(localContext)
, geometry(geometry)
, localGeometry(localGeometry)
{} {}
/// Coordinate `p` given in `localGeometry`, transformed to coordinate in `geometry`. public:
template <class Coordinate>
decltype(auto) position(Coordinate const& p) const Element const& element() const
{ {
return position(p, std::is_same<Geometry, LocalGeometry>{}); return *element_;
} }
/// The integration element from the `localGeometry`, the quadrature points are LocalContext const& localContext() const
/// defined in. {
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> 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. /// Transformation of coordinate `p` given in `localGeometry` to world space coordinates.
template <class Coordinate> template <class Coordinate>
decltype(auto) global(Coordinate const& p) const 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 private: // implementation detail
// position for elements // position for elements
template <class Coordinate> 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; return p;
} }
// position for intersection // position for intersection
template <class Coordinate> 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 } // 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 ...@@ -23,12 +23,8 @@ namespace AMDiS
private: private:
using Element = typename Super::Element; using Element = typename Super::Element;
using ElementMatrixVector = typename Super::ElementMatrixVector;
using Geometry = typename Super::Geometry; using Geometry = typename Super::Geometry;
using LocalGeometry = typename Super::LocalGeometry; using ElementMatrixVector = typename Super::ElementMatrixVector;
using Context = ContextGeometry<LocalContext, Geometry, LocalGeometry>;
public: public:
...@@ -69,26 +65,16 @@ namespace AMDiS ...@@ -69,26 +65,16 @@ namespace AMDiS
/// Implementation of \ref LocalAssemblerBase::assemble /// Implementation of \ref LocalAssemblerBase::assemble
/** /**
* Provides a quadrature formula with necessary degree to integrate the operator, * Stores geometry and localGeometry and calls
* stores geometry and localGeometry and a \ref ContextGeometry and calls
* \ref calculateElementVector or \ref calculateElementMatrix on the * \ref calculateElementVector or \ref calculateElementMatrix on the
* vector or matrix operator, respectively. * 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( virtual void assemble(LocalContext const& localContext,
LocalContext const& localContext, Nodes const&... nodes,
ElementMatrixVector& elementMatrixVector, ElementMatrixVector& elementMatrixVector) final
Nodes const&... nodes) final
{ {
auto&& localGeometry = getLocalGeometry(localContext); ContextGeometry<LocalContext> context{localContext, getElement(), getGeometry()};
auto&& quad = op_.getQuadratureRule(localGeometry.type(), nodes...); assembleImpl(context, nodes..., elementMatrixVector);
Context data{localContext, getGeometry(), localGeometry};
assembleImpl(data, std::forward<decltype(quad)>(quad), elementMatrixVector, nodes...);
return true;
} }
...@@ -97,96 +83,46 @@ namespace AMDiS ...@@ -97,96 +83,46 @@ namespace AMDiS
protected: // implementation detail protected: // implementation detail
// matrix assembling // matrix assembling
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)
{
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