Commit 0fa90a2b authored by Praetorius, Simon's avatar Praetorius, Simon

derivative of gridFunction and functor applied to gridFunctions added

parent 5b02e94d
This diff is collapsed.
#pragma once
namespace AMDiS
namespace AMDiS {
template <class GlobalBasis, class TreePath>
typename DOFVectorView<GlobalBasis, TreePath, true>::Range DOFVectorView<GlobalBasis, TreePath, true>::
LocalFunction::operator()(LocalDomain const& x) const
{
assert( bound_ );
auto y = Range(0);
auto&& coefficients = *globalFunction_->dofVector_;
auto&& nodeToRangeEntry = globalFunction_->nodeToRangeEntry_;
forEachLeafNode(*subTree_, [&,this](auto const& node, auto)
{
using Node = std::decay_t<decltype(node)>;
using LocalBasisRange = typename LocalFunction::template LocalBasisRange<Node>;
using MultiIndex = typename LocalIndexSet::MultiIndex;
using CoefficientBlock = typename std::decay<decltype(std::declval<Vector>()[std::declval<MultiIndex>()])>::type;
using RangeBlock = std::decay_t<decltype(std::declval<NodeToRangeEntry>()(node, y))>;
auto&& fe = node.finiteElement();
auto&& localBasis = fe.localBasis();
auto&& shapeFunctionValues = shapeFunctionValueContainer_[node];
localBasis.evaluateFunction(x, shapeFunctionValues);
// Get range entry associated to this node
auto&& re = nodeToRangeEntry(node, y);
for (std::size_t i = 0; i < localBasis.size(); ++i) {
auto&& multiIndex = localIndexSet_.index(node.localIndex(i));
// Get coefficient associated to i-th shape function
auto&& c = coefficients[multiIndex];
// Get value of i-th shape function
auto&& v = shapeFunctionValues[i];
// Notice that the range entry re, the coefficient c, and the shape functions
// value v may all be scalar, vector, matrix, or general container valued.
std::size_t dimC = Flat<CoefficientBlock>::size(c);
std::size_t dimV = Flat<LocalBasisRange>::size(v);
assert(dimC*dimV == Flat<RangeBlock>::size(re));
for(std::size_t j = 0; j < dimC; ++j) {
auto&& c_j = Flat<CoefficientBlock>::getEntry(c, j);
for(std::size_t k = 0; k < dimV; ++k) {
auto&& v_k = Flat<LocalBasisRange>::getEntry(v, k);
Flat<RangeBlock>::getEntry(re, j*dimV + k) += c_j*v_k;
}
}
}
});
return y;
}
template <class GlobalBasis, class TreePath>
typename DOFVectorView<GlobalBasis, TreePath, true>::DerivativeRange DOFVectorView<GlobalBasis, TreePath, true>::
GradientLocalFunction::operator()(LocalDomain const& x) const
{
assert( bound_ );
Range dy;
for (std::size_t j = 0; j < dy.size(); ++j)
dy[j] = 0;
auto&& coefficients = *globalFunction_->dofVector_;
auto&& nodeToRangeEntry = globalFunction_->nodeToRangeEntry_;
forEachLeafNode(*subTree_, [&,this](auto const& node, auto)
{
// TODO: may DOFVectorView::Range to FieldVector type if necessary
using LocalDerivativeTraits = Dune::Functions::DefaultDerivativeTraits<Dune::FieldVector<double,1>(Domain)>;
using GradientBlock = typename LocalDerivativeTraits::Range;
using MultiIndex = typename LocalIndexSet::MultiIndex;
using CoefficientBlock = typename std::decay<decltype(std::declval<Vector>()[std::declval<MultiIndex>()])>::type;
using RangeBlock = std::decay_t<decltype(std::declval<NodeToRangeEntry>()(node, dy))>;
auto&& fe = node.finiteElement();
auto&& localBasis = fe.localBasis();
// The transposed inverse Jacobian of the map from the reference element to the element
auto&& jacobian = geometry_.value().jacobianInverseTransposed(x);
auto&& referenceGradients = referenceGradientContainer_[node];
localBasis.evaluateJacobian(x, referenceGradients);
// Compute the shape function gradients on the real element
std::vector<GradientBlock> gradients(referenceGradients.size());
for (std::size_t i = 0; i < gradients.size(); ++i)
multiplies_ABt(referenceGradients[i], jacobian, gradients[i]); // D[phi] * J^(-1) -> grad
// Get range entry associated to this node
auto&& re = nodeToRangeEntry(node, dy);
for (std::size_t i = 0; i < localBasis.size(); ++i) {
auto&& multiIndex = localIndexSet_.index(node.localIndex(i));
// Get coefficient associated to i-th shape function
auto&& c = coefficients[multiIndex];
// Get value of i-th transformed reference gradient
auto&& grad = gradients[i];
{
auto y = Range(0);
auto const& coefficients = globalFunction_.coefficients();
auto const& nodeToRangeEntry = globalFunction_.nodeToRangeEntry();
forEachLeafNode(subTree_, [&,this](auto const& node, auto)
{
using Node = std::decay_t<decltype(node)>;
using LocalBasisRange = typename LocalFunction::template LocalBasisRange<Node>;
using MultiIndex = typename LocalIndexSet::MultiIndex;
using CoefficientBlock = Range;
using RangeBlock = std::decay_t<decltype(nodeToRangeEntry(node, y))>;
auto&& fe = node.finiteElement();
auto&& localBasis = fe.localBasis();
auto&& shapeFunctionValues = shapeFunctionValueContainer_[node];
localBasis.evaluateFunction(x, shapeFunctionValues);
// Get range entry associated to this node
auto&& re = nodeToRangeEntry(node, y);
for (std::size_t i = 0; i < localBasis.size(); ++i) {
auto&& multiIndex = localIndexSet_.index(node.localIndex(i));
// Get coefficient associated to i-th shape function
auto&& c = coefficients[multiIndex];
// Get value of i-th shape function
auto&& v = shapeFunctionValues[i];
// Notice that the range entry re, the coefficient c, and the shape functions
// value v may all be scalar, vector, matrix, or general container valued.
auto dimC = Flat<CoefficientBlock>::size(c);
auto dimV = Flat<LocalBasisRange>::size(v);
assert(dimC*dimV == Flat<RangeBlock>::size(re));
for(std::size_t j = 0; j < dimC; ++j) {
auto&& c_j = Flat<CoefficientBlock>::getEntry(c, j);
for(std::size_t k = 0; k < dimV; ++k) {
auto&& v_k = Flat<LocalBasisRange>::getEntry(v, k);
Flat<RangeBlock>::getEntry(re, j*dimV + k) += c_j*v_k;
}
}
}
});
return y;
// Notice that the range entry re, the coefficient c, and the transformed
// reference gradient grad may all be scalar, vector, matrix, or general container valued.
std::size_t dimC = Flat<CoefficientBlock>::size(c);
std::size_t dimV = Flat<GradientBlock>::size(grad);
assert(dimC*dimV == Flat<RangeBlock>::size(re));
for(std::size_t j = 0; j < dimC; ++j) {
auto&& c_j = Flat<CoefficientBlock>::getEntry(c, j);
for(std::size_t k = 0; k < dimV; ++k) {
auto&& v_k = Flat<GradientBlock>::getEntry(grad, k);
Flat<RangeBlock>::getEntry(re, j*dimV + k) += c_j*v_k;
}
}
}
});
return dy;
}
} // end namespace AMDiS
......@@ -107,7 +107,7 @@ namespace AMDiS
template <class T, int N>
auto unary_dot(Dune::FieldVector<T, N> const& x)
{
auto op = [](auto const& a, auto const& b) { return a + sqr(std::abs(b)); };
auto op = [](auto const& a, auto const& b) { return a + Math::sqr(std::abs(b)); };
return Impl::accumulate(x, op);
}
......@@ -187,7 +187,7 @@ namespace AMDiS
{
T result = 0;
for (int i = 0; i < N; ++i)
result += sqr(lhs[i] - rhs[i]);
result += Math::sqr(lhs[i] - rhs[i]);
return std::sqrt(result);
}
......@@ -274,4 +274,67 @@ namespace AMDiS
return sqrt(dot(DF[0], DF[0]));
}
template <class T, int M, int N>
Dune::FieldMatrix<T,N,M> trans(Dune::FieldMatrix<T, M, N> const& A)
{
Dune::FieldMatrix<T,N,M> At;
for (int i = 0; i < M; ++i)
for (int j = 0; j < N; ++j)
At[j][i] = A[i][j];
return At;
}
template <class T, int M, int N, int L>
Dune::FieldMatrix<T,M,N> multiplies(Dune::FieldMatrix<T, M, L> const& A, Dune::FieldMatrix<T, L, N> const& B)
{
return A.rightmultiplyany(B);
}
template <class T, int M, int N, int L>
Dune::FieldMatrix<T,M,N> multiplies_AtB(Dune::FieldMatrix<T, L, M> const& A, Dune::FieldMatrix<T, N, L> const& B)
{
Dune::FieldMatrix<T,M,N> C;
for (int m = 0; m < M; ++m) {
for (int n = 0; n < N; ++n) {
C[m][n] = 0;
for (int l = 0; l < L; ++l)
C[m][n] += A[l][m] * B[n][l];
}
}
return C;
}
template <class T, int M, int N, int L>
Dune::FieldMatrix<T,M,N> multiplies_ABt(Dune::FieldMatrix<T, M, L> const& A, Dune::FieldMatrix<T, N, L> const& B)
{
Dune::FieldMatrix<T,M,N> C;
for (int m = 0; m < M; ++m) {
for (int n = 0; n < N; ++n) {
C[m][n] = 0;
for (int l = 0; l < L; ++l)
C[m][n] += A[m][l] * B[n][l];
}
}
return C;
}
template <class T, int M, int N, int L>
Dune::FieldMatrix<T,M,N>& multiplies_ABt(Dune::FieldMatrix<T, M, L> const& A, Dune::FieldMatrix<T, N, L> const& B, Dune::FieldMatrix<T,M,N>& C)
{
for (int m = 0; m < M; ++m) {
for (int n = 0; n < N; ++n) {
C[m][n] = 0;
for (int l = 0; l < L; ++l)
C[m][n] += A[m][l] * B[n][l];
}
}
return C;
}
} // end namespace AMDiS
#pragma once
#include <type_traits>
#include <dune/functions/common/defaultderivativetraits.hh>
namespace AMDiS
{
/**
* \addtogroup OperatorTerms
* @{
**/
/// \brief A Gridfunction that returns the derivative when calling localFunction
template <class GridFct>
class DerivativeGridFunction
{
using GridFctRange = typename GridFct::Range;
using GridFctDomain = typename GridFct::Domain;
public:
using Range = typename Dune::Functions::DefaultDerivativeTraits<GridFctRange(GridFctDomain)>::Range;
using Domain = GridFctDomain;
using LocalFunction = std::decay_t<decltype(derivative(std::declval<GridFct>()))>;
using EntitySet = typename GridFct::EntitySet;
public:
explicit DerivativeGridFunction(GridFct const& gridFct)
: gridFct_(gridFct)
{}
Range operator()(Domain const& x) const
{
error_exit("Not implemented");
return Range(0);
}
friend LocalFunction localFunction(DerivativeGridFunction const& gf)
{
msg("DerivativeGridFunction::localFunction()\n");
return derivative(gf.gridFct_);
}
EntitySet const& entitySet() const
{
return gridFct_.entitySet();
}
private:
GridFct gridFct_;
};
/// Generator function for \ref DerivativeGridFunction expressions
template <class GridFct>
auto makeDerivativeGridFunction(GridFct&& gridFct)
{
return DerivativeGridFunction<std::decay_t<GridFct>>{std::forward<GridFct>(gridFct)};
}
/** @} **/
} // end namespace AMDiS
#pragma once
#include <tuple>
#include <type_traits>
#include <dune/amdis/common/IndexSeq.hpp>
#include <dune/amdis/common/Loops.hpp>
namespace AMDiS
{
/**
* \addtogroup OperatorTerms
* @{
**/
namespace Impl
{
template <class T0, class... Ts>
struct DomainType
{
using type = typename T0::Domain;
static_assert( and_< std::is_same<type, typename DomainType<Ts>::type>::value... >, "All GridFunctions must have the same Domain." );
};
template <class T0, class... Ts>
struct EntitySetType
{
using type = typename T0::EntitySet;
static_assert( and_< std::is_same<type, typename EntitySetType<Ts>::type>::value... >, "All GridFunctions must have the same EntitySet." );
};
} // end namespace Impl
/// \brief A Gridfunction that applies a functor to the evaluated Gridfunctions
template <class Functor, class... GridFunctions>
class FunctorGridFunction
{
public:
using Range = typename std::result_of<Functor(typename GridFunctions::Range...)>::type;
using Domain = typename Impl::DomainType<GridFunctions...>::type;
using EntitySet = typename Impl::EntitySetType<GridFunctions...>::type;
public:
class LocalFunction
{
template <class GridFct>
using LocalFct = std::decay_t<decltype(localFunction(std::declval<GridFct>()))>;
using Element = typename EntitySet::Element;
public:
using Range = typename FunctorGridFunction::Range;
using Domain = typename Impl::DomainType<LocalFct<GridFunctions>...>::type;
public:
template <class... GridFcts>
LocalFunction(Functor const& fct, GridFcts&&... gridFcts)
: fct_(fct)
, localFcts_(localFunction(std::forward<GridFcts>(gridFcts))...)
{}
void bind(Element const& element)
{
forEach(localFcts_, [&](auto& localFct) {
localFct.bind(element);
});
}
void unbind()
{
forEach(localFcts_, [&](auto& localFct) {
localFct.unbind();
});
}
Range operator()(Domain const& x) const
{
return eval([&x](auto const& localFct) { return localFct(x); },
MakeSeq_t<sizeof...(GridFunctions)>{});
}
private:
template <class Op, std::size_t... I>
auto eval(Op op, Indices<I...>) const
{
return fct_(op(std::get<I>(localFcts_))...);
}
private:
Functor fct_;
std::tuple<LocalFct<GridFunctions>...> localFcts_;
};
public:
template <class... GridFcts>
explicit FunctorGridFunction(Functor const& fct, GridFcts&&... gridFcts)
: fct_(fct)
, gridFcts_(std::forward<GridFcts>(gridFcts)...)
{}
Range operator()(Domain const& x) const
{
return eval([&x](auto const& gridFct) { return gridFct(x); },
MakeSeq_t<sizeof...(GridFunctions)>{});
}
friend LocalFunction localFunction(FunctorGridFunction const& gf)
{
msg("FunctorGridFunction::localFunction()\n");
return gf.expand([&fct=gf.fct_](auto const&... gridFcts) { return LocalFunction{fct,gridFcts...}; },
MakeSeq_t<sizeof...(GridFunctions)>{});
}
EntitySet const& entitySet() const
{
return std::get<0>(gridFcts_).entitySet();
}
private:
template <class Op, std::size_t... I>
auto eval(Op op, Indices<I...>) const
{
return fct_(op(std::get<I>(gridFcts_))...);
}
template <class Op, std::size_t... I>
auto expand(Op op, Indices<I...>) const
{
return op(std::get<I>(gridFcts_)...);
}
private:
Functor fct_;
std::tuple<GridFunctions...> gridFcts_;
};
/// Generator function for \ref FunctorGridFunction expressions
template <class Functor, class... GridFunctions>
auto makeFunctorGridFunction(Functor const& f, GridFunctions&&... gridFcts)
{
return FunctorGridFunction<Functor, std::decay_t<GridFunctions>...>{f, std::forward<GridFunctions>(gridFcts)...};
}
/** @} **/
} // end namespace AMDiS
......@@ -8,7 +8,12 @@
#include <dune/amdis/Operators.hpp>
#include <dune/amdis/Terms.hpp>
#include <dune/amdis/common/Literals.hpp>
#include <dune/amdis/terms/Interpolation.hpp>
#include <dune/amdis/common/FieldMatVec.hpp>
//#include <dune/amdis/terms/Interpolation.hpp>
#include <dune/amdis/DOFVectorView.hpp>
#include <dune/amdis/terms/DerivativeGridFunction.hpp>
#include <dune/amdis/terms/FunctorGridFunction.hpp>
using namespace AMDiS;
......@@ -26,8 +31,14 @@ int main(int argc, char** argv)
AdaptInfo adaptInfo("adapt");
prob.getSolution(_0) << [](auto const& x) { return x[0] + x[1]; };
prob.getSolution(_0) << func([](double u) { return 2.0 * u; }, valueOf(prob.getSolution(_0)));
// prob.getSolution(_0) << [](auto const& x) { return x[0] + x[1]; };
// prob.getSolution(_0) << func([](double u) { return 2.0 * u; }, valueOf(prob.getSolution(_0)));
auto u0 = makeDOFVectorView(*prob.getSolution(), treepath(_0));
u0 << [](auto const& x) { return x[0] + x[1]; };
auto grad_u0 = makeDerivativeGridFunction(u0);
u0.interpol(makeFunctorGridFunction([](auto const& grd) { return grd[0]; }, grad_u0));
prob.writeFiles(adaptInfo, true);
AMDiS::finalize();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment