Commit a0f8bdcf authored by Müller, Felix's avatar Müller, Felix

Feature/data transfer implementation

parent bb4f7a06
#pragma once
#include <memory>
#include <type_traits>
#include <utility>
#include <dune/functions/functionspacebases/subspacebasis.hh>
#include <amdis/Output.hpp>
#include <amdis/utility/TreeData.hpp>
#include <amdis/utility/Visitor.hpp>
namespace AMDiS
{
......@@ -17,17 +11,6 @@ namespace AMDiS
INTERPOLATE = 1
} DataTransferOperation;
template <class Node, class RangeType>
class NodeDataTransfer
{
public:
template <class Basis, class Container>
void preAdapt(Basis const& basis, Container const& coeff, bool mightCoarsen) {}
template <class Basis, class Container>
void postAdapt(Basis const& basis, Container& coeff, bool refined) const {}
};
template <class Container>
class DataTransferInterface
......@@ -40,7 +23,7 @@ namespace AMDiS
virtual void preAdapt(Container const& container, bool mightCoarsen) = 0;
/// Interpolate data to new grid after grid adaption
virtual void postAdapt(Container& container, bool refined) const = 0;
virtual void postAdapt(Container& container, bool refined) = 0;
};
......@@ -51,9 +34,9 @@ namespace AMDiS
: public DataTransferInterface<Container>
{
public:
virtual void preAdapt(Container const& container, bool) override {}
void preAdapt(Container const& container, bool) override {}
virtual void postAdapt(Container& container, bool) const override
void postAdapt(Container& container, bool) override
{
container.compress();
}
......@@ -61,45 +44,7 @@ namespace AMDiS
template <class Container, class Basis>
class DataTransfer
: public DataTransferInterface<Container>
{
template <class Node>
using NDT = NodeDataTransfer<std::decay_t<Node>, typename Container::value_type>;
public:
DataTransfer(Basis const& basis)
: basis_(&basis)
{}
/// Calls \ref NodeDataTransfer::preAdapt() on each basis node
virtual void preAdapt(Container const& container, bool mightCoarsen) override
{
nodeDataTransfer_.init(*basis_);
AMDiS::forEachLeafNode_(basis_->localView().tree(), [&](auto const& node, auto const& treePath)
{
auto subBasis = Dune::Functions::subspaceBasis(*basis_, treePath);
nodeDataTransfer_[node].preAdapt(subBasis, container.vector(), mightCoarsen);
});
}
/// Calls \ref NodeDataTransfer::postAdapt() on each basis node after compressing the
/// Container the dimension of the basis
virtual void postAdapt(Container& container, bool refined) const override
{
container.compress();
AMDiS::forEachLeafNode_(basis_->localView().tree(), [&](auto const& node, auto const& treePath)
{
auto subBasis = Dune::Functions::subspaceBasis(*basis_, treePath);
nodeDataTransfer_[node].postAdapt(subBasis, container.vector(), refined);
});
}
private:
Basis const* basis_;
TreeData<Basis, NDT, true> nodeDataTransfer_;
};
class DataTransfer;
/// Factory to create DataTransfer objects based on the \ref DataTransferOperation
template <class Container>
......@@ -116,7 +61,7 @@ namespace AMDiS
case NO_OPERATION:
return std::make_unique<NoDataTransfer<Container>>();
case INTERPOLATE:
return std::make_unique<DataTransfer<Container, Basis>>(basis);
return std::make_unique< DataTransfer<Container, Basis> >(basis);
default:
error_exit("Invalid data transfer\n");
return nullptr; // avoid warnings
......@@ -125,3 +70,5 @@ namespace AMDiS
};
} // end namespace AMDiS
#include "DataTransfer.inc.hpp"
This diff is collapsed.
#pragma once
#include <tuple>
#include <type_traits>
#include <utility>
#include <amdis/common/Mpl.hpp>
namespace AMDiS
{
namespace Tools
{
namespace Impl_
{
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>)
{
return f(std::get<I>(std::forward<Tuple>(t))...);
}
template <class F, std::size_t I0, std::size_t... I>
constexpr decltype(auto) apply_indices_impl(F&& f, index_t<I0>, std::index_sequence<I...>)
{
return f(index_t<I0+I>{}...);
}
} // namespace Impl_
template <class F, class Tuple>
constexpr decltype(auto) apply(F&& f, Tuple&& t)
{
return Impl_::apply_impl(
std::forward<F>(f), std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
}
template <class F, class... Args>
constexpr decltype(auto) apply_variadic(F&& f, Args&&... args)
{
return apply(std::forward<F>(f), std::forward_as_tuple(args...));
}
template <class F, std::size_t N>
constexpr decltype(auto) apply_indices(F&& f, index_t<N>)
{
return Impl_::apply_indices_impl(
std::forward<F>(f),
index_t<0>{},
std::make_index_sequence<N>{});
}
template <class F, std::size_t I0, std::size_t I1>
constexpr decltype(auto) apply_indices(F&& f, index_t<I0>, index_t<I1>)
{
return Impl_::apply_indices_impl(
std::forward<F>(f), index_t<I0>{},
std::make_index_sequence<I1-I0>{});
}
}
} // end namespace AMDiS
#pragma once
#include <array>
#include <functional>
#include <type_traits>
#include <utility>
#include <dune/common/indices.hh>
#include <dune/common/tuplevector.hh>
#include <dune/typetree/treepath.hh>
#include <amdis/common/Apply.hpp>
// NOTE: backport of dune/typetree/treecontainer.hh
namespace AMDiS
{
namespace Impl
{
/*
* \brief A factory class creating a hybrid container compatible with a type tree
*
* This class allows to create a nested hybrid container having the same structure
* as a given type tree. Power nodes are represented as std::array's while composite
* nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
* are creating using a given predicate. Once created, the factory provides an
* operator() creating the container for the tree given as argument.
*
* \tparam LeafToValue Type of a predicate that determines the stored values at the leafs
*/
template<class LeafToValue>
class ContainerFactory
{
public:
/**
* \brief Create ContainerFactory
*
* The given predicate will be stored by value.
*
* \param A predicate used to generate the stored values for the leaves
*/
ContainerFactory(LeafToValue leafToValue) :
leafToValue_(leafToValue)
{}
template<class Node,
std::enable_if_t<Node::isLeaf, int> = 0>
auto operator()(const Node& node)
{
return leafToValue_(node);
}
template<class Node,
std::enable_if_t<Node::isPower, int> = 0>
auto operator()(const Node& node)
{
using TransformedChild = decltype((*this)(node.child(0)));
return std::array<TransformedChild, Node::degree()>();
}
template<class Node,
std::enable_if_t<Node::isComposite, int> = 0>
auto operator()(const Node& node)
{
return Tools::apply_indices([&](auto... indices) { return Dune::makeTupleVector((*this)(node.child(indices))...); },
index_t<Node::degree()>{});
}
private:
LeafToValue leafToValue_;
};
/*
* \brief Wrap nested container to provide a VectorBackend
*/
template<class Container>
class TreeContainerVectorBackend
{
template<class C>
static constexpr decltype(auto) accessByTreePath(C&& container, const Dune::TypeTree::HybridTreePath<>& path)
{
return container;
}
template<class C, class... T>
static constexpr decltype(auto) accessByTreePath(C&& container, const Dune::TypeTree::HybridTreePath<T...>& path)
{
auto head = Dune::TypeTree::treePathEntry(path,Dune::Indices::_0);
auto tailPath = Tools::apply_indices([&](auto... i)
{
using namespace Dune::TypeTree;
return hybridTreePath(treePathEntry(path,index_t<i.value+1>{})...);
}, index_t<sizeof...(T)-1>{});
return accessByTreePath(container[head], tailPath);
}
public:
TreeContainerVectorBackend(Container&& container) :
container_(std::move(container))
{}
TreeContainerVectorBackend(TreeContainerVectorBackend&& other) :
container_(std::move(other.container_))
{}
template<class... T>
decltype(auto) operator[](const Dune::TypeTree::HybridTreePath<T...>& path) const
{
return accessByTreePath(container_, path);
}
template<class... T>
decltype(auto) operator[](const Dune::TypeTree::HybridTreePath<T...>& path)
{
return accessByTreePath(container_, path);
}
const Container& data() const
{
return container_;
}
Container& data()
{
return container_;
}
private:
Container container_;
};
template<class Container>
auto makeTreeContainerVectorBackend(Container&& container)
{
return TreeContainerVectorBackend<std::decay_t<Container>>(std::forward<Container>(container));
}
} // end namespace Impl
/** \addtogroup TypeTree
* \{
*/
/**
* \brief Create container havin the same structure as the given tree
*
* This class allows to create a nested hybrid container having the same structure
* as a given type tree. Power nodes are represented as std::array's while composite
* nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
* are creating using a given predicate. For convenience the created container is
* not returned directly. Instead, the returned object stores the container and
* provides operator[] access using a HybridTreePath.
*
* \param tree The tree which should be mapper to a container
* \param leafToValue A predicate used to generate the stored values for the leaves
*
* \returns A container matching the tree structure
*/
template<class Tree, class LeafToValue>
auto makeTreeContainer(const Tree& tree, LeafToValue&& leafToValue)
{
auto f = std::ref(leafToValue);
auto factory = Impl::ContainerFactory<decltype(f)>(f);
return Impl::makeTreeContainerVectorBackend(factory(tree));
}
/**
* \brief Create container havin the same structure as the given tree
*
* This class allows to create a nested hybrid container having the same structure
* as a given type tree. Power nodes are represented as std::array's while composite
* nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
* are of the given type Value. For convenience the created container is
* not returned directly. Instead, the returned object stores the container and
* provides operator[] access using a HybridTreePath.
*
* \tparam Value Type of the values to be stored for the leafs. Should be default constructible.
* \param leafToValue A predicate used to generate the stored values for the leaves
*
* \returns A container matching the tree structure
*/
template<class Value, class Tree>
auto makeTreeContainer(const Tree& tree)
{
return makeTreeContainer(tree, [](const auto&) {return Value{};});
}
/**
* \brief Alias to container type generated by makeTreeContainer for given value and tree type
*/
template<class Value, class Tree>
using TreeContainer = std::decay_t<decltype(makeTreeContainer<Value>(std::declval<const Tree&>()))>;
//! \} group TypeTree
} //namespace AMDiS
......@@ -8,6 +8,12 @@ dune_add_test(SOURCES ClonablePtrTest.cpp
dune_add_test(SOURCES ConceptsTest.cpp
LINK_LIBRARIES amdis)
dune_add_test(SOURCES DataTransferTest2d.cpp
LINK_LIBRARIES amdis)
dune_add_test(SOURCES DataTransferTest3d.cpp
LINK_LIBRARIES amdis)
dune_add_test(SOURCES DOFVectorTest.cpp
LINK_LIBRARIES amdis)
......
......@@ -53,13 +53,13 @@ int main(int argc, char** argv)
DOFVector<Basis> vec1(basis);
test_dofvector(basis, vec1);
DOFVector<Basis, float> vec2(basis);
DOFVector<Basis, double> vec2(basis);
test_dofvector(basis, vec2);
auto vec3 = makeDOFVector(basis);
test_dofvector(basis, vec3);
auto vec4 = makeDOFVector<float>(basis);
auto vec4 = makeDOFVector<double>(basis);
test_dofvector(basis, vec4);
#if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
......
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <array>
#include <cmath>
#include <functional>
#include <memory>
#include <vector>
#include <dune/common/fvector.hh>
#include <dune/common/parallel/mpihelper.hh>
#ifdef HAVE_DUNE_UGGRID
#include <dune/grid/uggrid.hh>
#else
#include <dune/grid/yaspgrid.hh>
#endif
#include <amdis/ProblemStat.hpp>
#include <amdis/ProblemStatTraits.hpp>
#include "Tests.hpp"
using namespace AMDiS;
template <class BasisCreator>
auto makeGrid(bool simplex, int globalRefines = 0)
{
using Grid = typename BasisCreator::GlobalBasis::GridView::Grid;
static constexpr int d = Grid::dimension; // problem dimension
using DomainType = typename Dune::FieldVector<double, d>;
// constants
DomainType lowerLeft; lowerLeft = 0.0; // lower left grid corner
DomainType upperRight; upperRight = 1.0; // upper right grid corner
std::array<unsigned int, d> s; s.fill(1); // number of elements on each axis
// make grid
std::unique_ptr<Grid> gridPtr;
if (simplex)
{
gridPtr = std::unique_ptr<Grid>{
Dune::StructuredGridFactory<Grid>::createSimplexGrid(lowerLeft, upperRight, s)};
}
else
{
gridPtr = std::unique_ptr<Grid>{
Dune::StructuredGridFactory<Grid>::createCubeGrid(lowerLeft, upperRight, s)};
}
gridPtr->globalRefine(globalRefines);
return gridPtr;
}
template <class BasisCreator, class Fcts>
auto makeProblem(typename BasisCreator::GlobalBasis::GridView::Grid& grid, Fcts const& funcs)
{
using Problem = ProblemStat<BasisCreator>;
// make problem
Problem prob("test", grid);
prob.initialize(INIT_ALL);
auto& globalBasis = prob.globalBasis();
auto localView = globalBasis.localView();
// interpolate given function to initial grid
int k = 0;
AMDiS::forEachLeafNode_(localView.tree(), [&](auto const& node, auto tp)
{
interpolate(globalBasis, tp, prob.solution(tp).coefficients(), funcs[k]);
k++;
});
return prob;
}
template <class Problem, class Fcts>
double calcError(Problem const& prob, Fcts const& funcs)
{
auto& globalBasis = prob.globalBasis();
auto localView = globalBasis.localView();
auto sol = prob.solution().coefficients();
std::vector<double> ref;
ref.resize(globalBasis.size());
double error = 0;
double maxError = 0;
int k = 0;
// interpolate given function onto reference vector
AMDiS::forEachLeafNode_(localView.tree(), [&](auto const& node, auto tp)
{
interpolate(globalBasis, tp, ref, funcs[k]);
k++;
});
// compare the solution with the reference
for (std::size_t i = 0; i < ref.size(); ++i)
{
error = std::abs(ref[i]-sol[i]);
maxError = std::max(maxError, error);
}
return maxError;
}
template <class BasisCreator>
using Fcts = std::vector<std::function<double(
Dune::FieldVector<double, BasisCreator::GlobalBasis::GridView::Grid::dimension>)> >;
/// Test data transfer for the case where no grid changes are made
template <class BasisCreator>
bool unchanged_test(Fcts<BasisCreator> const& funcs, bool simplex = true)
{
using Grid = typename BasisCreator::GlobalBasis::GridView::Grid;
static constexpr int d = Grid::dimension; // problem dimension
auto gridPtr = makeGrid<BasisCreator>(simplex, (d > 2 ? 3 : 5));
auto prob = makeProblem<BasisCreator, Fcts<BasisCreator>>(*gridPtr, funcs);
// mark a single element for coarsening -> no adaptation is done
auto e = *gridPtr->leafGridView().template begin<0>();
gridPtr->mark(-1, e);
AdaptInfo adaptInfo("adapt");
prob.adaptGrid(adaptInfo);
auto error = calcError(prob, funcs);
return error < AMDIS_TEST_TOL;
}
/// Test data transfer for the case of global coarsening
template <class BasisCreator>
bool coarsen_test(Fcts<BasisCreator> const& funcs, bool simplex = true)
{
using Grid = typename BasisCreator::GlobalBasis::GridView::Grid;
static constexpr int d = Grid::dimension; // problem dimension
auto gridPtr = makeGrid<BasisCreator>(simplex, (d > 2 ? 2 : 4));
auto prob = makeProblem<BasisCreator, Fcts<BasisCreator>>(*gridPtr, funcs);
prob.globalCoarsen(1);
auto error = calcError(prob, funcs);
return error < AMDIS_TEST_TOL;
}
/// Test data transfer for the case of global refinement
template <class BasisCreator>
bool refine_test(Fcts<BasisCreator> const& funcs, bool simplex = true)
{
using Grid = typename BasisCreator::GlobalBasis::GridView::Grid;
static constexpr int d = Grid::dimension; // problem dimension
auto gridPtr = makeGrid<BasisCreator>(simplex, (d > 2 ? 1 : 3));
auto prob = makeProblem<BasisCreator, Fcts<BasisCreator>>(*gridPtr, funcs);
prob.globalRefine(1);
auto error = calcError(prob, funcs);
return error < AMDIS_TEST_TOL;
}
template <class Grid>
using Lagrange3 = LagrangeBasis<typename Grid::LeafGridView, 3>;
template <class Grid>
using TaylorHood = TaylorHoodBasis<typename Grid::LeafGridView>;
constexpr double pi = 3.141592653589793238463;
#include "DataTransferTest.hpp"
int main(int argc, char** argv)
{
#ifdef HAVE_DUNE_UGGRID
using Grid = Dune::UGGrid<2>;
#else
using Grid = Dune::YaspGrid<2>;
#endif
Dune::MPIHelper::instance(argc, argv);
using Domain = typename Dune::FieldVector<double, 2>;
// polynomial of order 1
auto p1 = [](const Domain& x) -> double { return {0.5 + 0.25*(x[0]+x[1])}; };
// polynomial of order 2
auto p2 = [](const Domain& x) -> double { return {0.5 + 0.25*(2*std::pow(x[0],2) + x[0]*x[1] - std::pow(x[1],2))}; };
// polynomial of order 3
auto p3 = [](const Domain& x) -> double { return {0.5 + 0.25*(2*std::pow(x[0],3) + x[0]*x[1] - std::pow(x[1],3))}; };
// analytic function
auto f = [](const Domain& x) -> double { return {0.5 + 0.25*(std::sin(2*pi*x[0]) + 0.25*std::cos(6*pi*x[1]))}; };
AMDIS_TEST( (unchanged_test< Lagrange3<Grid> >({f})) );
AMDIS_TEST( (coarsen_test< Lagrange3<Grid> >({f})) );
AMDIS_TEST( (refine_test< Lagrange3<Grid> >({p3})) );
AMDIS_TEST( (unchanged_test< TaylorHood<Grid> >({f,f,f})) );
AMDIS_TEST( (coarsen_test< TaylorHood<Grid> >({f,f,f})) );
AMDIS_TEST( (refine_test< TaylorHood<Grid> >({p2,p2,p1})) );
return report_errors();
}
\ No newline at end of file
#include "DataTransferTest.hpp"
int main(int argc, char** argv)
{
#ifdef HAVE_DUNE_UGGRID
using Grid = Dune::UGGrid<3>;
#else
using Grid = Dune::YaspGrid<3>;
#endif
Dune::MPIHelper::instance(argc, argv);
using Domain = typename Dune::FieldVector<double, 3>;
// polynomial of order 1
auto p1 = [](const Domain& x) -> double { return {0.5 + 0.25*(x[0]+x[2])}; };
// polynomial of order 2
auto p2 = [](const Domain& x) -> double { return {0.5 + 0.25*(2*std::pow(x[0],2) + x[0]*x[1] - std::pow(x[2],2))}; };
// polynomial of order 3
auto p3 = [](const Domain& x) -> double { return {0.5 + 0.25*(2*std::pow(x[0],3) + x[0]*x[1] - std::pow(x[2],3))}; };
// analytic function
auto f = [](const Domain& x) -> double { return {0.5 + 0.25*(std::sin(2*pi*x[0]) + 0.25*std::cos(6*pi*x[2]))}; };
AMDIS_TEST( (unchanged_test< Lagrange3<Grid> >({f})) );
AMDIS_TEST( (coarsen_test< Lagrange3<Grid> >({f})) );
AMDIS_TEST( (refine_test< Lagrange3<Grid> >({p3})) );
AMDIS_TEST( (unchanged_test< TaylorHood<Grid> >({f,f,f,f})) );
AMDIS_TEST( (coarsen_test< TaylorHood<Grid> >({f,f,f,f})) );
AMDIS_TEST( (refine_test< TaylorHood<Grid> >({p2,p2,p2,p1})) );
return report_errors();
}
\ No newline at end of file
......@@ -97,7 +97,7 @@ int main(int argc, char** argv)
dlocalFct.unbind();
}
auto V0 = makeDOFVector<float>(prob.globalBasis());
auto V0 = makeDOFVector<double>(prob.globalBasis());
auto v0 = makeDOFVectorView(V0);
v0 << expr;
......
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