diff --git a/src/amdis/CMakeLists.txt b/src/amdis/CMakeLists.txt index c21899d28f5d04dc8c23f965a5070db433dc66f0..dd4aa6406d1bc2df7ad3cb379adb7c61da0f1290 100644 --- a/src/amdis/CMakeLists.txt +++ b/src/amdis/CMakeLists.txt @@ -67,6 +67,7 @@ install(FILES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis) add_subdirectory("common") +add_subdirectory("functions") add_subdirectory("gridfunctions") add_subdirectory("linearalgebra") add_subdirectory("localoperators") diff --git a/src/amdis/common/FieldMatVec.hpp b/src/amdis/common/FieldMatVec.hpp index dbc3f6c56db6970aeea80d219a82fe16b6cef91a..ceb547bf0ab9f54c7caed3b0aa9dc5eaaf4a133d 100644 --- a/src/amdis/common/FieldMatVec.hpp +++ b/src/amdis/common/FieldMatVec.hpp @@ -398,15 +398,32 @@ namespace Dune template <class T1, class T2, int M, int N, int L> FieldMatrix<std::common_type_t<T1,T2>,M,N> multiplies_ABt(FieldMatrix<T1, M, L> const& A, FieldMatrix<T2, N, L> const& B); + template <class T1, class T2, class T3, int M, int N, int L> FieldMatrix<T3,M,N>& multiplies_ABt(FieldMatrix<T1, M, L> const& A, FieldMatrix<T2, N, L> const& B, FieldMatrix<T3,M,N>& C); + template <class T1, class T2, class T3, int N, int L> + FieldVector<T3,N>& multiplies_ABt(FieldMatrix<T1, 1, L> const& A, FieldMatrix<T2, N, L> const& B, FieldVector<T3,N>& C); + + template <class T1, class T2, class T3, int N, int L> + FieldVector<T3,N>& multiplies_ABt(FieldVector<T1, L> const& A, FieldMatrix<T2, N, L> const& B, FieldVector<T3,N>& C); + + template <class T1, class T2, class T3, int N, int L> + FieldMatrix<T3,1,N>& multiplies_ABt(FieldVector<T1, L> const& A, FieldMatrix<T2, N, L> const& B, FieldMatrix<T3,1,N>& C); + + template <class T1, class T2, class T3, int M, int N> FieldMatrix<T3,M,N>& multiplies_ABt(FieldMatrix<T1, M, N> const& A, DiagonalMatrix<T2, N> const& B, FieldMatrix<T3,M,N>& C); template <class T1, class T2, class T3, int N> FieldVector<T3,N>& multiplies_ABt(FieldMatrix<T1, 1, N> const& A, DiagonalMatrix<T2, N> const& B, FieldVector<T3,N>& C); + template <class T1, class T2, class T3, int N> + FieldVector<T3,N>& multiplies_ABt(FieldVector<T1, N> const& A, DiagonalMatrix<T2, N> const& B, FieldVector<T3,N>& C); + + template <class T1, class T2, class T3, int N> + FieldMatrix<T3,1,N>& multiplies_ABt(FieldVector<T1, N> const& A, DiagonalMatrix<T2, N> const& B, FieldMatrix<T3,1,N>& C); + // ----------------------------------------------------------------------------- template <class T, int N> diff --git a/src/amdis/common/FieldMatVec.inc.hpp b/src/amdis/common/FieldMatVec.inc.hpp index 340b24e68fdc6c6e2aff7cafbb41beed8b92dd10..93f0c219159bc36224dce8e2ddd2957f0764a9b8 100644 --- a/src/amdis/common/FieldMatVec.inc.hpp +++ b/src/amdis/common/FieldMatVec.inc.hpp @@ -517,6 +517,41 @@ FieldMatrix<T3,M,N>& multiplies_ABt(FieldMatrix<T1, M, L> const& A, FieldMatrix return C; } +template <class T1, class T2, class T3, int N, int L> +FieldVector<T3,N>& multiplies_ABt(FieldMatrix<T1, 1, L> const& A, FieldMatrix<T2, N, L> const& B, FieldVector<T3,N>& C) +{ + for (int n = 0; n < N; ++n) { + C[n] = 0; + for (int l = 0; l < L; ++l) + C[n] += A[0][l] * B[n][l]; + } + return C; +} + +template <class T1, class T2, class T3, int N, int L> +FieldVector<T3,N>& multiplies_ABt(FieldVector<T1, L> const& A, FieldMatrix<T2, N, L> const& B, FieldVector<T3,N>& C) +{ + for (int n = 0; n < N; ++n) { + C[n] = 0; + for (int l = 0; l < L; ++l) + C[n] += A[l] * B[n][l]; + } + return C; +} + +template <class T1, class T2, class T3, int N, int L> +FieldMatrix<T3,1,N>& multiplies_ABt(FieldVector<T1, L> const& A, FieldMatrix<T2, N, L> const& B, FieldMatrix<T3,1,N>& C) +{ + for (int n = 0; n < N; ++n) { + C[0][n] = 0; + for (int l = 0; l < L; ++l) + C[0][n] += A[l] * B[n][l]; + } + return C; +} + + + template <class T1, class T2, class T3, int M, int N> FieldMatrix<T3,M,N>& multiplies_ABt(FieldMatrix<T1, M, N> const& A, DiagonalMatrix<T2, N> const& B, FieldMatrix<T3,M,N>& C) { @@ -537,6 +572,25 @@ FieldVector<T3,N>& multiplies_ABt(FieldMatrix<T1, 1, N> const& A, DiagonalMatri return C; } +template <class T1, class T2, class T3, int N> +FieldVector<T3,N>& multiplies_ABt(FieldVector<T1, N> const& A, DiagonalMatrix<T2, N> const& B, FieldVector<T3,N>& C) +{ + for (int n = 0; n < N; ++n) { + C[n] = A[n] * B.diagonal(n); + } + return C; +} + +template <class T1, class T2, class T3, int N> +FieldMatrix<T3,1,N>& multiplies_ABt(FieldVector<T1, N> const& A, DiagonalMatrix<T2, N> const& B, FieldMatrix<T3,1,N>& C) +{ + for (int n = 0; n < N; ++n) { + C[0][n] = A[n] * B.diagonal(n); + } + return C; +} + + template <class T, int N> T const& at(FieldMatrix<T,N,1> const& vec, std::size_t i) { diff --git a/src/amdis/functions/CMakeLists.txt b/src/amdis/functions/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..13244525b3280e8c2abc2f98606792edf8d03e57 --- /dev/null +++ b/src/amdis/functions/CMakeLists.txt @@ -0,0 +1,6 @@ +#install headers + +install(FILES + HierarchicNodeToRangeMap.hpp + Interpolate.hpp +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/functions) diff --git a/src/amdis/functions/HierarchicNodeToRangeMap.hpp b/src/amdis/functions/HierarchicNodeToRangeMap.hpp new file mode 100644 index 0000000000000000000000000000000000000000..259714400aafa064e6f958f92c249f3cac1c7b75 --- /dev/null +++ b/src/amdis/functions/HierarchicNodeToRangeMap.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include <utility> +#include <type_traits> + +#include <dune/common/concept.hh> + +#include <dune/functions/functionspacebases/concepts.hh> +#include <dune/functions/common/indexaccess.hh> + +#include <amdis/common/ConceptsBase.hpp> + +namespace AMDiS +{ + /** + * \brief A simple node to range map using the nested tree indices + * + * This map directly usses the tree path entries of the given + * node to access the nested container. + * + * If the container does not provide any operator[] access, + * it is simply forwarded for all nodes. + */ + struct HierarchicNodeToRangeMap + { + template <class Node, class TreePath, class Range, + REQUIRES(Dune::models<Dune::Functions::Concept::HasIndexAccess, Range, Dune::index_constant<0>>())> + decltype(auto) operator()(const Node& node, const TreePath& treePath, Range&& y) const + { + return Dune::Functions::resolveStaticMultiIndex(y, treePath); + } + + template <class Node, class TreePath, class Range, + REQUIRES(not Dune::models<Dune::Functions::Concept::HasIndexAccess, Range, Dune::index_constant<0>>())> + decltype(auto) operator()(const Node& node, const TreePath& treePath, Range&& y) const + { + return std::forward<Range>(y); + } + }; + +} // end namespace AMDiS diff --git a/src/amdis/functions/Interpolate.hpp b/src/amdis/functions/Interpolate.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5845b52fe8a3966ec40058cc3a06a8a004422d8d --- /dev/null +++ b/src/amdis/functions/Interpolate.hpp @@ -0,0 +1,436 @@ +#pragma once + +#include <memory> +#include <vector> + +#include <dune/common/tuplevector.hh> +#include <dune/common/version.hh> +#include <dune/common/std/optional.hh> +#include <dune/functions/functionspacebases/interpolate.hh> + +#include <amdis/common/Concepts.hpp> +#include <amdis/common/FieldMatVec.hpp> +#include <amdis/common/Logical.hpp> +#include <amdis/functions/HierarchicNodeToRangeMap.hpp> +#include <amdis/typetree/Traversal.hpp> + +namespace AMDiS { +namespace Impl { + + struct FakeCounter + { + struct Sink + { + template <class T> constexpr Sink& operator =(T const&) { return *this; } + template <class T> constexpr Sink& operator+=(T const&) { return *this; } + template <class T> constexpr Sink& operator-=(T const&) { return *this; } + + constexpr operator int() const { return 1; } + }; + + template <class SizeInfo> + constexpr void resize(SizeInfo const& sizeInfo) { /* do nothing */ } + constexpr std::size_t size() const { return 0; } + + template <class MI> constexpr Sink operator[](MI const&) { return Sink{}; } + template <class MI> constexpr int operator[](MI const&) const { return 1; } + }; + + + /// \brief Visitor evalued on the leaf nodes of basis-tree + /** + * \tparam B GlobalBasis + * \tparam Vec The Coefficient vector + * \tparam C A counter vector(-like) datastructure + * \tparam BV BitVector indicating which DOFs to visit + * \tparam LF LocalFunction to evaluate in the local interpolation + * \tparam NTRE A node-to-range-map, by default \ref HierarchicNodeToRangeMap + * \tparam average Indicates whether to do value averaging on shared DOFs (true), or simple assignment. + **/ + template <class B, class Vec, class C, class BV, class LF, class NTRE, bool average> + class LocalInterpolateVisitor + { + public: + using Basis = B; + using LocalView = typename Basis::LocalView; + using MultiIndex = typename LocalView::MultiIndex; + + using NodeToRangeEntry = NTRE; + using VectorBackend = Vec; + using CounterBackend = C; + using BitVectorBackend = BV; + using LocalFunction = LF; + + using GridView = typename Basis::GridView; + using Element = typename GridView::template Codim<0>::Entity; + using LocalDomain = typename Element::Geometry::LocalCoordinate; + + /// Functor called in the LocalInterpolation + template <class Node, class TreePath> + class LocalFunctionComponent + : public Dune::LocalFiniteElementFunctionBase<typename Node::FiniteElement>::type + { + using FiniteElement = typename Node::FiniteElement; + using Range = typename FiniteElement::Traits::LocalBasisType::Traits::RangeType; + + public: + LocalFunctionComponent(Node const& node, TreePath const& treePath, LF const& localF, NTRE const& nodeToRangeEntry) + : node_(node) + , treePath_(treePath) + , localF_(localF) + , nodeToRangeEntry_(nodeToRangeEntry) + {} + + void evaluate(const LocalDomain& x, Range& y) const + { + const auto& tmp = localF_(x); + const auto& tmp_vec = Dune::MatVec::as_vector(tmp); + y = Dune::Functions::flatVectorView(nodeToRangeEntry_(node_, transformTreePath(treePath_), tmp_vec))[comp_]; + } + + void setComponent(std::size_t comp) + { + comp_ = comp; + } + +#if DUNE_VERSION_GT(DUNE_FUNCTIONS,2,6) + static TreePath const& transformTreePath(TreePath const& treePath) + { + return treePath; + } +#else + // NOTE: due to a bug in dune-functions <= 2.6, a hybrid-treepath can not be passed to a HierarchicNodeToRangeMap, + // i.e. the HybridTreePath missed a size() function + static auto transformTreePath(TreePath const& treePath) + { + return Tools::apply([](auto... i) { return Dune::makeTupleVector(i...); }, treePath._data); + } +#endif + + private: + Node const& node_; + TreePath const& treePath_; + LocalFunction const& localF_; + NodeToRangeEntry const& nodeToRangeEntry_; + + std::size_t comp_ = 0; + }; + + public: + /// Constructor. Stores references to all passed objects. + LocalInterpolateVisitor(Vec& vector, C& counter, BV const& bitVector, + LF const& localF, LocalView const& localView, + NodeToRangeEntry const& nodeToRangeEntry) + : vector_(vector) + , counter_(counter) + , bitVector_(bitVector) + , localF_(localF) + , localView_(localView) + , nodeToRangeEntry_(nodeToRangeEntry) + { + static_assert(Concepts::Callable<LocalFunction, LocalDomain>, + "Function passed to LocalInterpolateVisitor does not model the Callable<LocalCoordinate> concept"); + } + + /// Apply the visitor to a node in the basis-tree (with corresponding treepath) + template <class Node, class TreePath> + void operator()(Node const& node, TreePath const& treePath) + { + using FiniteElement = typename Node::FiniteElement; + using RangeField = typename FiniteElement::Traits::LocalBasisType::Traits::RangeFieldType; + + auto&& fe = node.finiteElement(); + std::size_t feSize = fe.localBasis().size(); + + thread_local std::vector<bool> visit; + visit.resize(feSize, false); + + // Create a bitfield which DOFs to interpolate, using the global bitVector + // Here also the counter might be incremented + bool visit_any = false; + for (std::size_t i = 0; i < feSize; ++i) + { + auto multiIndex = localView_.index(node.localIndex(i)); + if (bitVector_[multiIndex]) { + visit[i] = true; + visit_any = true; + if (average) + counter_[multiIndex] += 1; + } else { + visit[i] = false; + } + } + + if (!visit_any) + return; + + LocalFunctionComponent<Node, TreePath> localFj(node, treePath, localF_, nodeToRangeEntry_); + thread_local std::vector<RangeField> interpolationCoefficients; + + // Traverse the range-components of the coefficient vector + std::size_t blockSize = Dune::Functions::flatVectorView(vector_[localView_.index(0)]).size(); + for (std::size_t j = 0; j < blockSize; ++j) + { + localFj.setComponent(j); + fe.localInterpolation().interpolate(localFj, interpolationCoefficients); + assert(interpolationCoefficients.size() == feSize); + + // Traverse all local DOFs (only if marked for visit with the bitVector) + for (std::size_t i = 0; i < feSize; ++i) + { + if (visit[i]) + { + auto multiIndex = localView_.index(node.localIndex(i)); + auto vectorBlock = Dune::Functions::flatVectorView(vector_[multiIndex]); + if (average && counter_[multiIndex] > 1) + vectorBlock[j] += interpolationCoefficients[i]; + else + vectorBlock[j] = interpolationCoefficients[i]; + } + } + } + } + + protected: + VectorBackend& vector_; + CounterBackend& counter_; + BitVectorBackend const& bitVector_; + + LocalFunction const& localF_; + LocalView const& localView_; + NodeToRangeEntry const& nodeToRangeEntry_; + }; + + // Small helper functions to wrap vectors using istlVectorBackend + // if they do not already satisfy the VectorBackend interface. + template <class B, class Vec> + decltype(auto) toVectorBackend(B const& basis, Vec& vec) + { + return Dune::Hybrid::ifElse(Dune::models<Dune::Functions::Concept::VectorBackend<B>, Vec>(), + [&](auto id) -> decltype(auto) { return vec; }, + [&](auto id) -> decltype(auto) { return Dune::Functions::istlVectorBackend(vec); }); + } + + template <class B, class Vec> + decltype(auto) toConstVectorBackend(B const& basis, Vec const& vec) + { + return Dune::Hybrid::ifElse(Dune::models<Dune::Functions::Concept::ConstVectorBackend<B>, Vec>(), + [&](auto id) -> decltype(auto) { return vec; }, + [&](auto id) -> decltype(auto) { return Dune::Functions::istlVectorBackend(vec); }); + } + +} // namespace Impl + + +/** + * \brief Interpolate given function in discrete function space + * + * Interpolation is done wrt the leaf node of the ansatz tree + * corresponding to the given tree path. + * + * Notice that this will only work if the range type of f and + * the block type of coeff are compatible and supported by + * flatVectorView. + * + * \param basis Global function space basis of discrete function space + * \param treePath Tree path specifying the part of the ansatz tree to use + * \param coeff Coefficient vector to represent the interpolation + * \param f Function to interpolate + * \param nodeToRangeEntry Polymorphic functor mapping local ansatz nodes to range-indices of given function + * \param bitVector A vector with flags marking all DOFs that should be interpolated + */ +template <class B, class TP, class Vec, class C, class BV, class GF, class NTRE, bool average> +void interpolateTreeSubset(B const& basis, TP const& treePath, Vec& vec, C& count, BV const& bitVec, + GF const& gf, NTRE const& nodeToRangeEntry, bool_t<average>) +{ + auto&& vector = Impl::toVectorBackend(basis,vec); + auto&& counter = Impl::toVectorBackend(basis,count); + auto&& bitVector = Impl::toConstVectorBackend(basis,bitVec); + vector.resize(sizeInfo(basis)); + counter.resize(sizeInfo(basis)); + + // Obtain a local view of f + auto lf = localFunction(gf); + auto localView = basis.localView(); + + for (const auto& e : elements(basis.gridView())) + { + localView.bind(e); + lf.bind(e); + + auto&& subTree = Dune::TypeTree::child(localView.tree(),treePath); + + using Visitor + = Impl::LocalInterpolateVisitor<B, TYPEOF(vector), TYPEOF(counter), TYPEOF(bitVector), TYPEOF(lf), NTRE, average>; + for_each_leaf_node(subTree, Visitor{vector, counter, bitVector, lf, localView, nodeToRangeEntry}); + } +} + + +template <class B, class... I, class Vec, class C, class BV, class GF, bool average, + REQUIRES(Dune::models<Dune::Functions::Concept::GlobalBasis<typename B::GridView>,B>()), + REQUIRES(Concepts::GridFunction<GF>)> +void interpolateTreeSubset(B const& basis, Dune::TypeTree::HybridTreePath<I...> const& treePath, + Vec& vec, C& count, BV const& bitVec, GF const& gf, bool_t<average>) +{ + auto ntrm = AMDiS::HierarchicNodeToRangeMap(); + AMDiS::interpolateTreeSubset(basis, treePath, vec, count, bitVec, gf, ntrm, bool_t<average>{}); +} + + +template <class B, class... I, class Vec, class C, class GF, class NTRE, bool average, + REQUIRES(Dune::models<Dune::Functions::Concept::GlobalBasis<typename B::GridView>,B>()), + REQUIRES(Concepts::GridFunction<GF>)> +void interpolateTree(B const& basis, Dune::TypeTree::HybridTreePath<I...> const& treePath, + Vec& vec, C& count, GF const& gf, NTRE const& nodeToRangeEntry, bool_t<average>) +{ + auto bitVec = Dune::Functions::Imp::AllTrueBitSetVector(); + AMDiS::interpolateTreeSubset(basis, treePath, vec, count, bitVec, gf, nodeToRangeEntry, bool_t<average>{}); +} + + +template <class B, class... I, class Vec, class C, class GF, bool average, + REQUIRES(Dune::models<Dune::Functions::Concept::GlobalBasis<typename B::GridView>,B>()), + REQUIRES(Concepts::GridFunction<GF>)> +void interpolateTree(B const& basis, Dune::TypeTree::HybridTreePath<I...> const& treePath, + Vec& vec, C& count, GF const& gf, bool_t<average>) +{ + auto bitVec = Dune::Functions::Imp::AllTrueBitSetVector(); + auto ntrm = AMDiS::HierarchicNodeToRangeMap(); + AMDiS::interpolateTreeSubset(basis, treePath, vec, count, bitVec, gf, ntrm, bool_t<average>{}); +} + + +/** + * \brief Interpolate given function in discrete function space + * + * Interpolation is done wrt the leaf node of the ansatz tree + * corresponding to the given tree path. + * + * Notice that this will only work if the range type of f and + * the block type of coeff are compatible and supported by + * flatVectorView. + * + * \param basis Global function space basis of discrete function space + * \param treePath Tree path specifying the part of the ansatz tree to use + * \param vec Coefficient vector to represent the interpolation + * \param count Vector that counts for the number of value assignments + * \param bitVec A vector with flags marking all DOFs that should be interpolated + * \param gf GridFunction to interpolate + */ +template <class B, class... I, class Vec, class C, class GF, class BV, bool average, + REQUIRES(Dune::models<Dune::Functions::Concept::GlobalBasis<typename B::GridView>,B>()), + REQUIRES(Concepts::GridFunction<GF>)> +void interpolateFiltered(B const& basis, Dune::TypeTree::HybridTreePath<I...> const& treePath, + Vec& vec, C& count, BV const& bitVec, GF const& gf, bool_t<average>) +{ + auto ntrm = AMDiS::HierarchicNodeToRangeMap(); + AMDiS::interpolateTreeSubset(basis, treePath, vec, count, bitVec, gf, ntrm, bool_t<average>{}); +} + + +/** + * \brief Interpolate given function in discrete function space + * + * Interpolation is done wrt the leaf node of the ansatz tree + * corresponding to the given tree path. Only vector coefficients marked as 'true' in the + * bitVector argument are interpolated. Use this, e.g., to interpolate Dirichlet boundary values. + * + * Notice that this will only work if the range type of f and + * the block type of coeff are compatible and supported by + * flatVectorView. + * + * \param basis Global function space basis of discrete function space + * \param vec Coefficient vector to represent the interpolation + * \param count Vector that counts for the number of value assignments + * \param bitVec A vector with flags marking all DOFs that should be interpolated + * \param gf GridFunction to interpolate + */ +template <class B, class Vec, class C, class BV, class GF, bool average, + REQUIRES(Dune::models<Dune::Functions::Concept::GlobalBasis<typename B::GridView>,B>()), + REQUIRES(not Dune::Functions::Imp::isHybridTreePath<Vec>()), + REQUIRES(Concepts::GridFunction<GF>)> +void interpolateFiltered(B const& basis, Vec& vec, C& count, BV const& bitVec, GF const& gf, bool_t<average>) +{ + auto root = Dune::TypeTree::hybridTreePath(); + auto ntrm = AMDiS::HierarchicNodeToRangeMap(); + AMDiS::interpolateTreeSubset(basis, root, vec, count, bitVec, gf, ntrm, bool_t<average>{}); +} + + +/** + * \brief Interpolate given function in discrete function space + * + * Notice that this will only work if the range type of f and + * the block type of coeff are compatible and supported by + * flatVectorView. + * + * This function will only work, if the local ansatz tree of + * the basis is trivial, i.e., a single leaf node. + * + * \param basis Global function space basis of discrete function space + * \param vec Coefficient vector to represent the interpolation + * \param count Vector that counts for the number of value assignments + * \param gf GridFunction to interpolate + */ +template <class B, class Vec, class C, class GF, bool average, + REQUIRES(Dune::models<Dune::Functions::Concept::GlobalBasis<typename B::GridView>,B>()), + REQUIRES(not Dune::Functions::Imp::isHybridTreePath<Vec>()), + REQUIRES(Concepts::GridFunction<GF>)> +void interpolate(B const& basis, Vec& vec, C& count, GF const& gf, bool_t<average>) +{ + auto root = Dune::TypeTree::hybridTreePath(); + auto bitVec = Dune::Functions::Imp::AllTrueBitSetVector(); + AMDiS::interpolateFiltered(basis, root, vec, count, bitVec, gf, bool_t<average>{}); +} + +template <class B, class... I, class Vec, class GF, + REQUIRES(Dune::models<Dune::Functions::Concept::GlobalBasis<typename B::GridView>,B>()), + REQUIRES(not Dune::Functions::Imp::isHybridTreePath<Vec>()), + REQUIRES(Concepts::GridFunction<GF>)> +void interpolate(B const& basis, Vec& vec, GF const& gf) +{ + auto root = Dune::TypeTree::hybridTreePath(); + auto bitVec = Dune::Functions::Imp::AllTrueBitSetVector(); + auto count = Impl::FakeCounter(); + AMDiS::interpolateFiltered(basis, root, vec, count, bitVec, gf, std::false_type{}); +} + + +/** + * \brief Interpolate given function in discrete function space + * + * Interpolation is done wrt the leaf node of the ansatz tree + * corresponding to the given tree path. + * + * Notice that this will only work if the range type of f and + * the block type of corresponding coeff entries are compatible + * and supported by flatVectorView. + * + * \param basis Global function space basis of discrete function space + * \param treePath Tree path specifying the part of the ansatz tree to use + * \param vec Coefficient vector to represent the interpolation + * \param count Vector that counts for the number of value assignments + * \param gf GridFunction to interpolate + */ +template <class B, class... I, class Vec, class C, class GF, bool average, + REQUIRES(Dune::models<Dune::Functions::Concept::GlobalBasis<typename B::GridView>,B>()), + REQUIRES(Concepts::GridFunction<GF>)> +void interpolate(B const& basis, Dune::TypeTree::HybridTreePath<I...> const& treePath, + Vec& vec, C& count, GF const& gf, bool_t<average>) +{ + auto bitVec = Dune::Functions::Imp::AllTrueBitSetVector(); + AMDiS::interpolateFiltered(basis, treePath, vec, count, bitVec, gf, bool_t<average>{}); +} + +template <class B, class... I, class Vec, class GF, + REQUIRES(Dune::models<Dune::Functions::Concept::GlobalBasis<typename B::GridView>,B>()), + REQUIRES(Concepts::GridFunction<GF>)> +void interpolate(B const& basis, Dune::TypeTree::HybridTreePath<I...> const& treePath, Vec& vec, GF const& gf) +{ + auto bitVec = Dune::Functions::Imp::AllTrueBitSetVector(); + auto count = Impl::FakeCounter(); + AMDiS::interpolateFiltered(basis, treePath, vec, count, bitVec, gf, std::false_type{}); +} + +} // end namespace AMDiS diff --git a/src/amdis/gridfunctions/DOFVectorView.hpp b/src/amdis/gridfunctions/DOFVectorView.hpp index f95677a960a72583a1807c9e38efae57feee6a27..edbd33f96db49a9c082837875955cbedb053e966 100644 --- a/src/amdis/gridfunctions/DOFVectorView.hpp +++ b/src/amdis/gridfunctions/DOFVectorView.hpp @@ -1,10 +1,18 @@ #pragma once #include <amdis/GridFunctions.hpp> +#include <amdis/functions/Interpolate.hpp> #include <amdis/gridfunctions/DiscreteFunction.hpp> namespace AMDiS { + namespace tag + { + struct average {}; + struct assign {}; + + } // end namespace tag + /// A mutable view on the subspace of a DOFVector, \relates DiscreteFunction template <class GB, class VT, class TP> class DOFVectorView @@ -23,8 +31,9 @@ namespace AMDiS {} /// Constructor. Stores a pointer to the mutable `dofvector`. - DOFVectorView(DOFVector<GB,VT>& dofVector, TP const& treePath) - : Super(dofVector, treePath) + template <class PreTreePath> + DOFVectorView(DOFVector<GB,VT>& dofVector, PreTreePath const& preTreePath) + : Super(dofVector, makeTreePath(preTreePath)) , mutableDofVector_(&dofVector) {} @@ -38,15 +47,27 @@ namespace AMDiS * v.interpolate_noalias([](auto const& x) { return x[0]; }); * ``` **/ - template <class Expr> - void interpolate_noalias(Expr&& expr) + template <class Expr, class Tag = tag::average> + void interpolate_noalias(Expr&& expr, Tag strategy = {}) { auto const& basis = this->basis(); auto const& treePath = this->treePath(); auto&& gridFct = makeGridFunction(FWD(expr), basis.gridView()); - Dune::Functions::interpolate(basis, treePath, coefficients(), FWD(gridFct)); + if (std::is_same<Tag, tag::average>::value) { + thread_local std::vector<std::uint8_t> counter; + counter.clear(); + AMDiS::interpolate(basis, treePath, coefficients(), counter, FWD(gridFct), std::true_type{}); + + auto& coeff = coefficients().vector(); + for (std::size_t i = 0; i < counter.size(); ++i) { + if (counter[i] > 0) + coeff[i] /= double(counter[i]); + } + } else { + AMDiS::interpolate(basis, treePath, coefficients(), FWD(gridFct)); + } } /// \brief Interpolation of GridFunction to DOFVector @@ -59,13 +80,13 @@ namespace AMDiS * Allows to have a reference to the DOFVector in the expression, e.g. as * \ref DiscreteFunction or \ref gradientAtQP() of a DiscreteFunction. **/ - template <class Expr> - void interpolate(Expr&& expr) + template <class Expr, class Tag = tag::average> + void interpolate(Expr&& expr, Tag strategy = {}) { // create temporary copy of data DOFVector<GB,VT> tmp(coefficients()); Self tmpView{tmp, this->treePath()}; - tmpView.interpolate_noalias(FWD(expr)); + tmpView.interpolate_noalias(FWD(expr), strategy); // move data from temporary vector into stored DOFVector coefficients().vector() = std::move(tmp.vector()); @@ -107,6 +128,11 @@ namespace AMDiS #if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION + // Deduction guide for DOFVectorView class + template <class GlobalBasis, class ValueType, class PreTreePath> + DOFVectorView(DOFVector<GlobalBasis, ValueType>& dofVector, PreTreePath const& preTreePath) + -> DOFVectorView<GlobalBasis, ValueType, TYPEOF(makeTreePath(preTreePath))>; + // Deduction guide for DOFVectorView class template <class GlobalBasis, class ValueType> DOFVectorView(DOFVector<GlobalBasis, ValueType>& dofVector)