Commit d2aafda1 authored by Praetorius, Simon's avatar Praetorius, Simon

expression and DirichletBC with lambda functions

parent 7bd09e85
......@@ -97,7 +97,7 @@ SET(AMDIS_SRC ${SOURCE_DIR}/AdaptBase.cc
${SOURCE_DIR}/DOFMatrix.cc
${SOURCE_DIR}/DOFVector.cc
${SOURCE_DIR}/Debug.cc
${SOURCE_DIR}/DirichletBC.cc
# ${SOURCE_DIR}/DirichletBC.cc
${SOURCE_DIR}/DualTraverse.cc
${SOURCE_DIR}/ElInfo.cc
${SOURCE_DIR}/ElInfo1d.cc
......
......@@ -28,6 +28,7 @@
#include <boost/numeric/mtl/mtl.hpp>
#include "OpenMP.h"
#include "Config.h"
namespace AMDiS {
......@@ -133,8 +134,12 @@ namespace AMDiS {
struct BoundaryObject;
struct AtomicBoundary;
#if HAS_VARIADIC_TEMPLATES
template<typename ReturnType, typename... Args > class AbstractFunction;
#else
template<typename ReturnType, typename ArgumentType> class AbstractFunction;
#endif
template<typename ReturnType,
typename ArgumentType1,
typename ArgumentType2> class BinaryAbstractFunction;
......@@ -153,6 +158,7 @@ namespace AMDiS {
template<typename T> class DOFVector;
template<typename T> class DimVec;
template<typename T> class DimMat;
template<typename T> class DirichletBC;
// template<typename ITLSolver> class ITL_LinearSolverInterface;
template<typename T, typename MatT, typename VecT > class ITL_Preconditioner;
template<typename T> class Matrix;
......
......@@ -32,43 +32,6 @@
#include <boost/preprocessor/repetition/repeat.hpp>
namespace AMDiS {
/**
* \ingroup Common
*
* \brief
* An AbstractFunction object represents a function
* f : ArgumentType -> ReturnType.
*
* AbstractFunction is a pure virtual class interface class.
* To create your own function you have to derive AbstractFunction and
* overload operator().
*/
// #ifndef HAS_VARIADIC_TEMPLATES
template<typename ReturnType, typename ArgumentType>
class AbstractFunction
{
public:
/// Constructor.
AbstractFunction(int degree = 0) :
degree_(degree)
{}
virtual ~AbstractFunction() {}
/// Returns \ref degree_.
inline int getDegree() const
{
return degree_;
}
/// Deligates the evaluation to overriden method f.
virtual ReturnType operator()(const ArgumentType& x) const = 0;
protected:
int degree_;
};
// #endif
/**
* \ingroup Common
......@@ -175,7 +138,68 @@ namespace AMDiS {
int degree_;
};
// #ifndef HAS_VARIADIC_TEMPLATES
#if HAS_VARIADIC_TEMPLATES
// C++11 implementation of AbstractFunction with arbitrary nr of arguments using variadic templates
/**
* \ingroup Common
*
* \brief
* An AbstractFunction object represents a function
* f : ArgumentTypes... -> ReturnType.
*
* AbstractFunction is a pure virtual class interface class.
* To create your own function you have to derive AbstractFunction and
* overload operator().
*/
template< typename ReturnType, typename... Args >
class AbstractFunction
{
public:
AbstractFunction(int degree = 0)
: degree_(degree)
{}
virtual ~AbstractFunction() {}
/// Returns \ref degree_.
inline int getDegree() const
{
return degree_;
}
/// function evaluation.
virtual ReturnType operator()(Args const&... args) const = 0;
protected:
int degree_;
};
#else
template<typename ReturnType, typename ArgumentType>
class AbstractFunction
{
public:
/// Constructor.
AbstractFunction(int degree = 0) :
degree_(degree)
{}
virtual ~AbstractFunction() {}
/// Returns \ref degree_.
inline int getDegree() const
{
return degree_;
}
/// Deligates the evaluation to overriden method f.
virtual ReturnType operator()(const ArgumentType& x) const = 0;
protected:
int degree_;
};
///////////////////////////////////////////////////////////////
// test of AbstractFunction with arbitrary number of arguments
......@@ -225,34 +249,8 @@ namespace AMDiS {
#endif
BOOST_PP_REPEAT_FROM_TO(1, 11, ABSTRACT_FUNCTION_MACRO, nil)
// #else
//
// /// C++11 implementation of abstract functions with arbitrary nr of arguments using variadic templates
// template< typename ReturnType, typename... Ts >
// class AbstractFunction
// {
// public:
// AbstractFunction(int degree = 0)
// : degree_(degree)
// {}
//
// virtual ~AbstractFunction() {}
//
// /// Returns \ref degree_.
// inline int getDegree() const
// {
// return degree_;
// }
//
// /// function evaluation.
// virtual ReturnType operator()(Ts const&... args) const = 0;
//
// protected:
// int degree_;
// };
//
// #endif
#endif
}
#endif // AMDIS_ABSTRACTFUNCTION_H
......@@ -72,21 +72,23 @@ namespace AMDiS {
const BasisFunction *basFcts = rowFeSpace->getBasisFcts();
for (int i = 0; i < nBasFcts; i++) {
if (localBound[i] == boundaryType) {
double value = 0.0;
if (f) {
if (f) {
for (int i = 0; i < nBasFcts; i++)
if (localBound[i] == boundaryType) {
elInfo->coordToWorld(*(basFcts->getCoords(i)), worldCoords);
value = (*f)(worldCoords);
} else {
if (dofVec)
value = (*dofVec)[dofIndices[i]];
else
ERROR_EXIT("There is something wrong!\n");
double value = (*f)(worldCoords);
vector->setDirichletDofValue(dofIndices[i], value);
(*vector)[dofIndices[i]] = value;
}
vector->setDirichletDofValue(dofIndices[i], value);
(*vector)[dofIndices[i]] = value;
}
} else if (dofVec) {
for (int i = 0; i < nBasFcts; i++)
if (localBound[i] == boundaryType) {
double value = value = (*dofVec)[dofIndices[i]];
vector->setDirichletDofValue(dofIndices[i], value);
(*vector)[dofIndices[i]] = value;
}
} else {
ERROR_EXIT("No data provided to assemble DirichletBC!\n");
}
}
......
......@@ -30,8 +30,49 @@
#include "AbstractFunction.h"
#include "FixVec.h"
namespace AMDiS {
namespace AMDiS
{
// some tags used for tag-dispatching
struct _value_by_abstractfunction {};
struct _value_by_dofvector {};
struct _value_by_function {};
namespace detail
{
template <class Tag>
struct ValueContainer {};
template <>
struct ValueContainer<_value_by_abstractfunction>
{
ValueContainer(AbstractFunction<double, WorldVector<double> > *fct) : value(*fct) {};
ValueContainer(AbstractFunction<double, WorldVector<double> > &fct) : value(fct) {};
AbstractFunction<double, WorldVector<double> > &value;
};
template <>
struct ValueContainer<_value_by_dofvector>
{
ValueContainer(DOFVectorBase<double> *vec) : value(vec) {};
ValueContainer(DOFVectorBase<double> &vec) : value(&vec) {};
DOFVectorBase<double> *value;
};
#if __cplusplus > 199711L
template <>
struct ValueContainer<_value_by_function>
{
ValueContainer(std::function<double(WorldVector<double>)> fct) : value(fct) {};
std::function<double(WorldVector<double>)> value;
};
#endif
} // end namespace detail
/**
* \ingroup Assembler
*
......@@ -41,6 +82,7 @@ namespace AMDiS {
* the row corresponding to a Dirichlet dof is replaced by a row containing
* only a 1.0 in the diagonal.
*/
template <class ValueTag>
class DirichletBC : public BoundaryCondition
{
public:
......@@ -50,6 +92,15 @@ namespace AMDiS {
const FiniteElemSpace *rowFeSpace,
const FiniteElemSpace *colFeSpace = NULL,
bool apply = true);
#if __cplusplus > 199711L
/// Constructor.
DirichletBC(BoundaryType type,
std::function<double(WorldVector<double>)> fct,
const FiniteElemSpace *rowFeSpace,
const FiniteElemSpace *colFeSpace = NULL,
bool apply = true);
#endif
/// Constructor.
DirichletBC(BoundaryType type,
......@@ -57,18 +108,18 @@ namespace AMDiS {
bool apply = true);
/// Implementation of BoundaryCondition::fillBoundaryCondition().
void fillBoundaryCondition(DOFMatrix* matrix,
virtual void fillBoundaryCondition(DOFMatrix* matrix,
ElInfo* elInfo,
const DegreeOfFreedom* dofIndices,
const BoundaryType* localBound,
int nBasFcts);
int nBasFcts) override;
/// Implementation of BoundaryCondition::fillBoundaryCondition().
void fillBoundaryCondition(DOFVectorBase<double>* vector,
virtual void fillBoundaryCondition(DOFVectorBase<double>* vector,
ElInfo* elInfo,
const DegreeOfFreedom* dofIndices,
const BoundaryType* localBound,
int nBasFcts);
int nBasFcts) override;
///
void initVector(DOFVectorBase<double>*);
......@@ -92,26 +143,31 @@ namespace AMDiS {
{
return applyBC;
}
inline AbstractFunction<double, WorldVector<double> > *getF()
{
return f;
}
inline DOFVectorBase<double> *getDOFVector()
{
return dofVec;
}
protected:
/// Function which is evaluated at world coords of Dirichlet dofs.
AbstractFunction<double, WorldVector<double> > *f;
///
WorldVector<double> worldCoords;
void fillBC(_value_by_abstractfunction,
DOFVectorBase<double>* vector,
ElInfo* elInfo,
const DegreeOfFreedom* dofIndices,
const BoundaryType* localBound,
int nBasFcts);
void fillBC(_value_by_function,
DOFVectorBase<double>* vector,
ElInfo* elInfo,
const DegreeOfFreedom* dofIndices,
const BoundaryType* localBound,
int nBasFcts);
void fillBC(_value_by_dofvector,
DOFVectorBase<double>* vector,
ElInfo* elInfo,
const DegreeOfFreedom* dofIndices,
const BoundaryType* localBound,
int nBasFcts);
/// DOFVector containing the boundary values
DOFVectorBase<double> *dofVec;
protected:
detail::ValueContainer<ValueTag> container;
/// Defines, if the boundary condition must be applied to the matrix. See
/// comment of \ref BoundaryCondition::applyBoundaryCondition.
......@@ -120,4 +176,6 @@ namespace AMDiS {
}
#include "DirichletBC.hh"
#endif
......@@ -36,8 +36,6 @@ namespace AMDiS {
#define MAX_DIM 3
#define MAX_DEGREE 4
template<typename ReturnType, typename ArgumentType> class AbstractFunction;
/** \ingroup FEMSpace
* \brief
* Lagrange basis functions. Sub class of BasisFunction
......
......@@ -1383,10 +1383,10 @@ namespace AMDiS {
boundaryConditionSet = true;
DirichletBC *dirichletApply =
new DirichletBC(type, b, componentSpaces[row], componentSpaces[col], true);
DirichletBC *dirichletNotApply =
new DirichletBC(type, b, componentSpaces[row], componentSpaces[col], false);
DirichletBC<_value_by_abstractfunction> *dirichletApply =
new DirichletBC<_value_by_abstractfunction>(type, b, componentSpaces[row], componentSpaces[col], true);
DirichletBC<_value_by_abstractfunction> *dirichletNotApply =
new DirichletBC<_value_by_abstractfunction>(type, b, componentSpaces[row], componentSpaces[col], false);
for (int i = 0; i < nComponents; i++)
if (systemMatrix && (*systemMatrix)[row][i]) {
......@@ -1402,6 +1402,38 @@ namespace AMDiS {
solution->getDOFVector(col)->getBoundaryManager()->addBoundaryCondition(dirichletApply);
}
#if __cplusplus > 199711L
void ProblemStatSeq::addDirichletBC(BoundaryType type, int row, int col,
std::function<double(WorldVector<double>)> b)
{
FUNCNAME("ProblemStat::addDirichletBC()");
TEST_EXIT(row >= 0 && row < nComponents)("Wrong row number: %d\n", row);
TEST_EXIT(col >= 0 && col < nComponents)("Wrong col number: %d\n", col);
boundaryConditionSet = true;
DirichletBC<_value_by_function> *dirichletApply =
new DirichletBC<_value_by_function>(type, b, componentSpaces[row], componentSpaces[col], true);
DirichletBC<_value_by_function> *dirichletNotApply =
new DirichletBC<_value_by_function>(type, b, componentSpaces[row], componentSpaces[col], false);
for (int i = 0; i < nComponents; i++)
if (systemMatrix && (*systemMatrix)[row][i]) {
if (i == col)
(*systemMatrix)[row][i]->getBoundaryManager()->addBoundaryCondition(dirichletApply);
else
(*systemMatrix)[row][i]->getBoundaryManager()->addBoundaryCondition(dirichletNotApply);
}
if (rhs)
rhs->getDOFVector(row)->getBoundaryManager()->addBoundaryCondition(dirichletApply);
if (solution)
solution->getDOFVector(col)->getBoundaryManager()->addBoundaryCondition(dirichletApply);
}
#endif
void ProblemStatSeq::addDirichletBC(BoundaryType type, int row, int col,
DOFVector<double> *vec)
......@@ -1413,8 +1445,8 @@ namespace AMDiS {
boundaryConditionSet = true;
DirichletBC *dirichletApply = new DirichletBC(type, vec, true);
DirichletBC *dirichletNotApply = new DirichletBC(type, vec, false);
DirichletBC<_value_by_dofvector> *dirichletApply = new DirichletBC<_value_by_dofvector>(type, vec, true);
DirichletBC<_value_by_dofvector> *dirichletNotApply = new DirichletBC<_value_by_dofvector>(type, vec, false);
for (int i = 0; i < nComponents; i++)
if (systemMatrix && (*systemMatrix)[row][i]) {
......
......@@ -27,6 +27,9 @@
#include <vector>
#include <list>
#if __cplusplus > 199711L
#include <functional>
#endif
#include "AMDiS_fwd.h"
#include "ProblemStatBase.h"
#include "Initfile.h"
......@@ -188,6 +191,14 @@ namespace AMDiS {
/// abstract function.
virtual void addDirichletBC(BoundaryType type, int row, int col,
AbstractFunction<double, WorldVector<double> > *b);
#if __cplusplus > 199711L
/// Adds a Dirichlet boundary condition, where the rhs is given by an
/// lambda function or a std::function object
virtual void addDirichletBC(BoundaryType type, int row, int col,
std::function<double(WorldVector<double>)> b);
#endif
/// Adds a Dirichlet boundary condition, where the rhs is given by a DOF
/// vector.
......
......@@ -34,11 +34,7 @@
#include "add_expr.hpp" // add two expressions
#include "mult_expr.hpp" // multiply two expressions
#if HAS_VARIADIC_TEMPLATES && HAS_ALIAS_TEMPLATES
#include "functorN_expr.hpp" // apply a functor with arbitrary nr. of arguments to expressions
#else
#include "functor_expr.hpp" // apply a functor with 1/2/3 arguments to expressions
#endif
#include "functor_expr.hpp" // apply a functor with 1/2/3 arguments to expressions
#include "cmath_expr.hpp" // apply a cmath function to expressions
#include "vec_functors.hpp" // apply a vector function to expressions
......
......@@ -28,13 +28,14 @@
#include "AMDiS_fwd.h"
#include "LazyOperatorTerm.h"
#include "Functors.h"
#include "expressions/functor_expr.hpp"
// #include "expressions/functor_expr.hpp"
#include "operations/functors.hpp"
#include <boost/static_assert.hpp>
#include <tuple>
#include <utility>
#include <functional>
namespace AMDiS
{
......@@ -71,7 +72,66 @@ namespace AMDiS
template<typename... Int>
static int eval(F f, Int... d) { return f.getDegree(d...); }
};
}
// specialization for abstract-functions
template<typename R, typename... Args>
struct functor_degree<AbstractFunction<R, Args...> >
{
template<typename... Int>
static int eval(AbstractFunction<R, Args...> const& fct, Int... d) { return fct.getDegree(); }
};
template<typename R, typename Arg0, typename Arg1>
struct functor_degree<BinaryAbstractFunction<R, Arg0, Arg1> >
{
template<typename... Int>
static int eval(BinaryAbstractFunction<R, Arg0, Arg1> const& fct, Int... d) { return fct.getDegree(); }
};
template<typename R, typename Arg0, typename Arg1, typename Arg2>
struct functor_degree<TertiaryAbstractFunction<R, Arg0, Arg1, Arg2> >
{
template<typename... Int>
static int eval(TertiaryAbstractFunction<R, Arg0, Arg1, Arg2> const& fct, Int... d) { return fct.getDegree(); }
};
} // end namespace traits
namespace result_of
{
/// extract result type from function pointers
template <class FPtr>
struct Function;
template <class R, class C, class... As>
struct Function<R (C::*)(As...)>
{
typedef R result_type;
};
template<class R, class C, class... As>
struct Function<R (C::*)(As...) const>
{
typedef R type;
};
template<class T>
typename Function<T>::type function_helper(T);
/// extract result type from functors
template <class F>
struct Functor
{
typedef decltype(function_helper(&F::operator())) type;
};
template <class R, class... As>
struct Functor<std::function<R(As...)> >
{
typedef R type;
};
} // end namespace result_of
namespace detail
......@@ -167,7 +227,7 @@ namespace AMDiS
typedef LazyOperatorTerms<Terms...> super;
static const int N = sizeof...(Terms);
typedef typename traits::functor_result_type<F>::type value_type;
typedef typename result_of::Functor<F>::type value_type;
BOOST_STATIC_ASSERT_MSG( (!boost::is_same<value_type, traits::no_valid_type>::value), "********** ERROR: You have to define a result_type for your Functor **********" );
F f; ///< the functor
......@@ -210,50 +270,93 @@ namespace AMDiS
inline value_type operator()(const int& iq) const { return eval(iq, int_<N>()); }
};
template<typename F, typename Term>
using Function1 = FunctionN<F, Term>;
template<typename F, typename Term1, typename Term2>
using Function2 = FunctionN<F, Term1, Term2>;
template<typename F, typename Term1, typename Term2, typename Term3>
using Function3 = FunctionN<F, Term1, Term2, Term3>;
template<typename F, typename Term1, typename Term2, typename Term3, typename Term4>
using Function4 = FunctionN<F, Term1, Term2, Term3, Term4>;
/// A wrapper functor for AMDiS::AbstractFunctions
template<typename TOut, typename TIn>
struct Wrapper : public FunctorBase
{
typedef TOut result_type;
Wrapper(AbstractFunction<TOut, TIn>* fct_) : fct(fct_) {}
int getDegree(int degree) const { return fct->getDegree(); }
TOut operator()(const TIn& x) const
{
return (*fct)(x);
}
protected:
AbstractFunction<TOut, TIn>* fct;
};
} // end namespace expressions
namespace result_of
{
// result of generator-functions (used for enable_if constructs)
template<typename F, typename... Terms>
struct FunctionN : enable_if
template <typename F, typename... Terms>
struct FunctionN : std::enable_if
<
typename and_< typename traits::is_valid_arg<Terms>::type... >::type,
and_< typename traits::is_valid_arg<Terms>::type... >::value,
expressions::FunctionN< F, typename traits::to_expr<Terms>::type...>
> {};
template <typename F, typename Term>
struct FunctionN<F, Term> : std::enable_if
<
traits::is_valid_arg<Term>::value,
expressions::FunctionN< F, typename traits::to_expr<Term>::type>
> {};