diff --git a/.ci/make_env_file.py b/.ci/make_env_file.py deleted file mode 100755 index 450d3b7a7fa0fcd7cc2325ecc2882b71651d6e77..0000000000000000000000000000000000000000 --- a/.ci/make_env_file.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python3 -# -# ~~~ -# This file is part of the dune-gdt project: -# https://github.com/dune-community/dune-gdt -# Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -# License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -# or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -# with "runtime exception" (http://www.dune-project.org/license.html) -# Authors: -# René Fritze (2018) -# ~~~ - -import os -from os.path import expanduser -from shlex import quote -home = expanduser("~") - -prefixes = os.environ.get('ENV_PREFIXES', 'TRAVIS DRONE GITLAB CODECOV CI encrypt TOKEN TESTS').split(' ') -blacklist = ['TRAVIS_COMMIT_MESSAGE'] -env_file = os.environ.get('ENV_FILE', os.path.join(home, 'env')) -with open(env_file, 'wt') as env: - for k, v in os.environ.items(): - for pref in prefixes: - if k.startswith(pref) and k not in blacklist: - env.write('{}={}\n'.format(k, quote(v))) diff --git a/.ci/shared b/.ci/shared index f108b7fd0ac9fefcab197eb331be48da6da3ff57..cc324c2a418c2e10cca465da7aeb81bd9201a462 160000 --- a/.ci/shared +++ b/.ci/shared @@ -1 +1 @@ -Subproject commit f108b7fd0ac9fefcab197eb331be48da6da3ff57 +Subproject commit cc324c2a418c2e10cca465da7aeb81bd9201a462 diff --git a/.ci/travis/add_swap.bash b/.ci/travis/add_swap.bash deleted file mode 100755 index cd8ccf409302adb8508f32be200aa272b7c157d4..0000000000000000000000000000000000000000 --- a/.ci/travis/add_swap.bash +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# -# ~~~ -# This file is part of the dune-gdt project: -# https://github.com/dune-community/dune-gdt -# Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -# License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -# or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -# with "runtime exception" (http://www.dune-project.org/license.html) -# Authors: -# Felix Schindler (2013, 2016 - 2018) -# René Fritze (2016 - 2018) -# Tobias Leibner (2016 - 2018) -# ~~~ - -# ~~~ -# This file is part of the dune-gdt project: -# https://github.com/dune-community/dune-gdt -# Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -# License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -# or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -# with "runtime exception" (http://www.dune-project.org/license.html) -# Authors: -# Rene Milk (2017 - 2018) -# ~~~ - -set -e -SWAP=$HOME/swap.img -MB_SIZE=${1:-4000} -sudo -E dd if=/dev/zero of=${SWAP} bs=1M count=${MB_SIZE} -sudo -E chown root:root ${SWAP} -sudo -E chmod 0600 ${SWAP} -sudo -E mkswap ${SWAP} -sudo -E swapon ${SWAP} -echo "echo 3 > /proc/sys/vm/drop_caches" | sudo -E sh - diff --git a/.ci/travis/after_script.bash b/.ci/travis/after_script.bash deleted file mode 100755 index 066fb95fd459d4c80c1724ab69b7f2717d653015..0000000000000000000000000000000000000000 --- a/.ci/travis/after_script.bash +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -# -# ~~~ -# This file is part of the dune-gdt project: -# https://github.com/dune-community/dune-gdt -# Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -# License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -# or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -# with "runtime exception" (http://www.dune-project.org/license.html) -# Authors: -# Felix Schindler (2017) -# René Fritze (2016, 2018) -# Tobias Leibner (2018) -# ~~~ - -git config --global hooks.clangformat ${CLANG_FORMAT} -CHECK_DIR=${SUPERDIR}/${MY_MODULE} -PYTHONPATH=${SUPERDIR}/scripts/python/ python3 -c "import travis_report as tp; tp.clang_format_status(\"${CHECK_DIR}\")" -${SRC_DCTRL} ${BLD} --only=${MY_MODULE} configure -${SRC_DCTRL} ${BLD} --only=${MY_MODULE} make doc -if [ "X${TRAVIS_PULL_REQUEST}" != "Xfalse" ] ; then - ${SUPERDIR}/.ci/init_sshkey.sh ${encrypted_95fb78800815_key} ${encrypted_95fb78800815_iv} keys/dune-community/dune-community.github.io - ${SUPERDIR}/.ci/deploy_docs.sh ${MY_MODULE} "${DUNE_BUILD_DIR}" -fi diff --git a/.ci/travis/script.bash b/.ci/travis/script.bash deleted file mode 100755 index d0d43f0f52726deb1d3ad9a7af9f66f9ddda189b..0000000000000000000000000000000000000000 --- a/.ci/travis/script.bash +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -# -# ~~~ -# This file is part of the dune-gdt project: -# https://github.com/dune-community/dune-gdt -# Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -# License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -# or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -# with "runtime exception" (http://www.dune-project.org/license.html) -# Authors: -# René Fritze (2018) -# Tobias Leibner (2018) -# ~~~ - -set -ex - -WAIT="${SUPERDIR}/scripts/bash/travis_wait_new.bash 45" -source ${SUPERDIR}/scripts/bash/retry_command.bash - -${SRC_DCTRL} ${BLD} --only=${MY_MODULE} configure -${SRC_DCTRL} ${BLD} --only=${MY_MODULE} make - -free -h - -if [ x"${TESTS}" == x ] ; then - ${WAIT} ${SRC_DCTRL} ${BLD} --only=${MY_MODULE} bexec ninja -v test_binaries - ${WAIT} ${SRC_DCTRL} ${BLD} --only=${MY_MODULE} bexec ctest -V -j 2 -else - ${WAIT} ${SRC_DCTRL} ${BLD} --only=${MY_MODULE} bexec ninja -v -j 1 test_binaries_builder_${TESTS} - ${WAIT} ${SRC_DCTRL} ${BLD} --only=${MY_MODULE} bexec ctest -V -j 2 -L "^builder_${TESTS}$" -fi -if [ "X${TRAVIS_PULL_REQUEST}" != "Xfalse" ] ; then - ${SUPERDIR}/.ci/init_sshkey.sh ${encrypted_95fb78800815_key} ${encrypted_95fb78800815_iv} keys/dune-community/dune-gdt-testlogs - retry_command ${SUPERDIR}/scripts/bash/travis_upload_test_logs.bash ${DUNE_BUILD_DIR}/${MY_MODULE}/dune/gdt/test/ -fi - -# clang coverage currently disabled for being to mem hungry -if [[ ${CC} == *"clang"* ]] ; then - exit 0 -fi - -pushd ${DUNE_BUILD_DIR}/${MY_MODULE} -COVERAGE_INFO=${PWD}/coverage.info -lcov --directory . --output-file ${COVERAGE_INFO} -c -for d in "dune-common" "dune-pybindxi" "dune-geometry" "dune-istl" "dune-grid" "dune-alugrid" "dune-uggrid" "dune-localfunctions" \ - "dune-xt-common" "dune-xt-functions" "dune-xt-la" "dune-xt-grid" ; do - lcov --directory . --output-file ${COVERAGE_INFO} -r ${COVERAGE_INFO} "${SUPERDIR}/${d}/*" -done -lcov --directory . --output-file ${COVERAGE_INFO} -r ${COVERAGE_INFO} "${SUPERDIR}/${MY_MODULE}/dune/xt/*/test/*" -cd ${SUPERDIR}/${MY_MODULE} -${OLDPWD}/run-in-dune-env pip install codecov -${OLDPWD}/run-in-dune-env codecov -v -X gcov -X coveragepy -F ctest -f ${COVERAGE_INFO} -t ${CODECOV_TOKEN} -popd diff --git a/.gitignore b/.gitignore index 197a93be4ec62814daac4395fd2872dfb58bd8b3..1701849adf8b3da45bffd6322cf43ef748e47749 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,5 @@ demos-* build-* *.pyc .idea +tags +.vscode diff --git a/.gitsuper b/.gitsuper deleted file mode 100644 index f6402be6a07f302cb78213a1cb5fe66f910c04d2..0000000000000000000000000000000000000000 --- a/.gitsuper +++ /dev/null @@ -1,118 +0,0 @@ -[supermodule] -remote = git@github.com:dune-community/dune-gdt-super.git -status = 1a3bcab04b011a5d6e44f9983cae6ff89fa695e8 bin (heads/master) - 28c9ce81c14c878a71e907ab05b9bb72df77883e config.opts (heads/master) - f308c6637edd65dcb83c4c1a46feaf05b958130e dune-alugrid (v2.6.0-7-gf308c663) - 76d7f0c9886a061571cb8dc66dd45a4ef86e7a58 dune-common (v2.2.1-2269-g76d7f0c9) - +36634986b34d08cd8f3805e2e607a7bba86ff25d dune-gdt (heads/saddlepoint) - 5235397bc16d24c759a1672fed7b8cfde4852e52 dune-geometry (v2.2.0-834-g5235397) - af5766f0df47e3d0b62ea486efb9cdbf8e1cfc52 dune-grid (v2.2.0-2671-gaf5766f0d) - 1369ae9329d0928480d6b18ed772fc77e1abf752 dune-grid-glue (v2.4.0-161-g1369ae9) - ef68ae0ec40f9d369e4ea9b31e560af6af545bf6 dune-istl (v2.6.0-4-gef68ae0e) - 5a1f77d7a0a41c2d065b29f00dda0871ec70337b dune-localfunctions (v2.6.0-2-g5a1f77d) - 6d2a4680493a2483d53f9dd05a19dd6b5f436572 dune-pybindxi (v2.2.1-30-g6d2a468) - 58bd932e2311a288e0163d041f836b50f19111cb dune-testtools (remotes/origin/testname_listing_hack2.6) - 07f9700459c616186737a9a34277f2edee76f475 dune-uggrid (v2.6.0-1-g07f97004) - 27a8010443c03eebddc3a910bdbef63ccf1f3e5d dune-xt-common (heads/master) - 376e88d14fd23ea12c3e23befc3fc967d4833751 dune-xt-data (heads/master) - 2da2612032ce64337f5af5cfec68d3c6d639e178 dune-xt-functions (heads/master) - 654c823f698418b67a696618342b54324f2cc151 dune-xt-grid (heads/master) - d1ffc46178cb9d93308294c5144afb4d7d0f0d82 dune-xt-la (heads/master) - 09d0378f616b94d68bcdd9fc6114813181849ec0 scripts (heads/master) -commit = ee1fda4fe42ee5f7c744cf529f84adf689251563 - -[submodule.bin] -remote = git@github.com:dune-community/local-bin.git -status = -commit = 1a3bcab04b011a5d6e44f9983cae6ff89fa695e8 - -[submodule.config.opts] -remote = git@github.com:dune-community/config.opts.git -status = -commit = 28c9ce81c14c878a71e907ab05b9bb72df77883e - -[submodule.dune-alugrid] -remote = https://github.com/dune-mirrors/dune-alugrid.git -status = -commit = f308c6637edd65dcb83c4c1a46feaf05b958130e - -[submodule.dune-common] -remote = git@github.com:dune-community/dune-common.git -status = -commit = 76d7f0c9886a061571cb8dc66dd45a4ef86e7a58 - -[submodule.dune-gdt] -remote = git@github.com:dune-community/dune-gdt.git -status = c0b1735fab0ecbd4bb4f1eaa27cb65fe813e98f0 .vcsetup (heads/master) -commit = 36634986b34d08cd8f3805e2e607a7bba86ff25d - -[submodule.dune-geometry] -remote = git@github.com:dune-community/dune-geometry.git -status = -commit = 5235397bc16d24c759a1672fed7b8cfde4852e52 - -[submodule.dune-grid] -remote = git@github.com:dune-community/dune-grid.git -status = -commit = af5766f0df47e3d0b62ea486efb9cdbf8e1cfc52 - -[submodule.dune-grid-glue] -remote = https://github.com/dune-mirrors/dune-grid-glue.git -status = -commit = 1369ae9329d0928480d6b18ed772fc77e1abf752 - -[submodule.dune-istl] -remote = https://github.com/dune-mirrors/dune-istl.git -status = -commit = ef68ae0ec40f9d369e4ea9b31e560af6af545bf6 - -[submodule.dune-localfunctions] -remote = https://github.com/dune-mirrors/dune-localfunctions.git -status = -commit = 5a1f77d7a0a41c2d065b29f00dda0871ec70337b - -[submodule.dune-pybindxi] -remote = git@github.com:dune-community/dune-pybindxi.git -status = c0b1735fab0ecbd4bb4f1eaa27cb65fe813e98f0 .vcsetup (heads/master) -commit = 6d2a4680493a2483d53f9dd05a19dd6b5f436572 - -[submodule.dune-testtools] -remote = git@github.com:dune-community/dune-testtools.git -status = -commit = 58bd932e2311a288e0163d041f836b50f19111cb - -[submodule.dune-uggrid] -remote = https://github.com/dune-mirrors/dune-uggrid.git -status = -commit = 07f9700459c616186737a9a34277f2edee76f475 - -[submodule.dune-xt-common] -remote = git@github.com:dune-community/dune-xt-common.git -status = cc1bbdac283f4b9323c64345030f1b8f634b88d5 .vcsetup (heads/master) -commit = 27a8010443c03eebddc3a910bdbef63ccf1f3e5d - -[submodule.dune-xt-data] -remote = git@github.com:dune-community/dune-xt-data -status = cc1bbdac283f4b9323c64345030f1b8f634b88d5 .vcsetup (heads/master) -commit = 376e88d14fd23ea12c3e23befc3fc967d4833751 - -[submodule.dune-xt-functions] -remote = git@github.com:dune-community/dune-xt-functions.git -status = cc1bbdac283f4b9323c64345030f1b8f634b88d5 .vcsetup (heads/master) -commit = 2da2612032ce64337f5af5cfec68d3c6d639e178 - -[submodule.dune-xt-grid] -remote = git@github.com:dune-community/dune-xt-grid.git -status = cc1bbdac283f4b9323c64345030f1b8f634b88d5 .vcsetup (heads/master) -commit = 654c823f698418b67a696618342b54324f2cc151 - -[submodule.dune-xt-la] -remote = git@github.com:dune-community/dune-xt-la.git -status = cc1bbdac283f4b9323c64345030f1b8f634b88d5 .vcsetup (heads/master) -commit = d1ffc46178cb9d93308294c5144afb4d7d0f0d82 - -[submodule.scripts] -remote = https://github.com/wwu-numerik/scripts.git -status = fb5ebc10e647d637c69497af2ec2560847eb2112 python/pylicense (v0.2.0~10) -commit = 09d0378f616b94d68bcdd9fc6114813181849ec0 - diff --git a/.pylicense-other.py b/.pylicense-other.py index 9466c53ec881f5c7b485e504e0e27ce8b4893b61..57d6fabcd0e3fa210f9e5636a58eee4c02eb4799 100644 --- a/.pylicense-other.py +++ b/.pylicense-other.py @@ -24,4 +24,4 @@ include_patterns = ('*.txt', '*.cmake', '*.py', '*.sh', '*.bash', '*.dgf', '*.ms '*.gitignore', '*.mailmap', '*.gitattributes', '*gitignore-*', '*stamp-vc', '*dune.module', '*Doxylocal', '*.clang-format', '*COPYING-CMAKE-SCRIPTS', '*README', '*LICENSE', '*mainpage', '*switch-build_dir', '*dune-xt-common.pc.in', '*CMakeLists.txt') -exclude_patterns = ('*config.h.cmake', '*.vcsetup*', '*builder_definitions.cmake', '*.ci/shared/*) +exclude_patterns = ('*config.h.cmake', '*.vcsetup*', '*builder_definitions.cmake', '*.ci/shared/*') diff --git a/.vcsetup b/.vcsetup index 0fe2d7bb19a198ee8d099ff308b9208af0914eb4..1f967c99ec990e557ad7b39a25c0148886019b79 160000 --- a/.vcsetup +++ b/.vcsetup @@ -1 +1 @@ -Subproject commit 0fe2d7bb19a198ee8d099ff308b9208af0914eb4 +Subproject commit 1f967c99ec990e557ad7b39a25c0148886019b79 diff --git a/dune/gdt/discretefunction/default-datahandle.hh b/dune/gdt/discretefunction/default-datahandle.hh new file mode 100644 index 0000000000000000000000000000000000000000..187c13ddb76fd61f93418a92e34358ba7de0ae4d --- /dev/null +++ b/dune/gdt/discretefunction/default-datahandle.hh @@ -0,0 +1,111 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_DISCRETEFUNCTION_DATAHANDLE_HH +#define DUNE_GDT_DISCRETEFUNCTION_DATAHANDLE_HH + +#include <dune/grid/common/datahandleif.hh> + +#include <dune/xt/common/unused.hh> + +namespace Dune { +namespace GDT { + + +template <class DiscreteFunctionType> +class DiscreteFunctionDataHandle + : public Dune::CommDataHandleIF<DiscreteFunctionDataHandle<DiscreteFunctionType>, + typename DiscreteFunctionType::SpaceType::R> +{ +public: + DiscreteFunctionDataHandle(DiscreteFunctionType& discrete_function, bool fixed_size = true) + : discrete_function_(discrete_function) + , mapper_(discrete_function_.space().mapper()) + , vector_(discrete_function_.dofs().vector()) + , fixed_size_(fixed_size) + {} + + //! export type of data for message buffer + typedef typename DiscreteFunctionType::SpaceType::D DataType; + + //! returns true if data for this codim should be communicated + bool contains(int /*dim*/, int codim) const + { + return (codim == 0); + } + + //! returns true if size per entity of given dim and codim is a constant + bool fixedsize(int /*dim*/, int /*codim*/) const + { + return fixed_size_; + } + + /*! how many objects of type DataType have to be sent for a given entity + + Note: Only the sender side needs to know this size. + */ + template <class EntityType> + std::enable_if_t<EntityType::codimension != 0, size_t> size(const EntityType& /*entity*/) const + { + return 0; + } + + /*! how many objects of type DataType have to be sent for a given entity + Note: Only the sender side needs to know this size. + */ + template <class EntityType> + std::enable_if_t<EntityType::codimension == 0, size_t> size(const EntityType& entity) const + { + return discrete_function_.space().mapper().local_size(entity); + } + + //! pack data from user to message buffer + template <class MessageBuffer, class EntityType> + std::enable_if_t<EntityType::codimension != 0> gather(MessageBuffer& /*buff*/, const EntityType& /*entity*/) const + {} + + template <class MessageBuffer, class EntityType> + std::enable_if_t<EntityType::codimension == 0> gather(MessageBuffer& buff, const EntityType& entity) const + { + const auto global_indices = mapper_.global_indices(entity); + for (const auto& index : global_indices) + buff.write(vector_.get_entry(index)); + } + + /*! unpack data from message buffer to user + n is the number of objects sent by the sender + */ + template <class MessageBuffer, class EntityType> + std::enable_if_t<EntityType::codimension != 0> + scatter(MessageBuffer& /*buff*/, const EntityType& /*entity*/, size_t /*n*/) + {} + + template <class MessageBuffer, class EntityType> + std::enable_if_t<EntityType::codimension == 0> + scatter(MessageBuffer& buff, const EntityType& entity, size_t DXTC_DEBUG_ONLY(n)) + { + assert(mapper_.local_size(entity) == n); + const auto global_indices = mapper_.global_indices(entity); + for (const auto& index : global_indices) + buff.read(vector_[index]); + } + +private: + DiscreteFunctionType& discrete_function_; + const typename DiscreteFunctionType::SpaceType::MapperType& mapper_; + typename DiscreteFunctionType::VectorType& vector_; + const bool fixed_size_; +}; + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_DISCRETEFUNCTION_DATAHANDLE_HH diff --git a/dune/gdt/discretefunction/default.hh b/dune/gdt/discretefunction/default.hh index 1901ae741d374cc7858b134a1abf2215bd41ea53..0a6e7954529c174b456c993e714b02f32a2c0f21 100644 --- a/dune/gdt/discretefunction/default.hh +++ b/dune/gdt/discretefunction/default.hh @@ -56,7 +56,7 @@ class ConstDiscreteFunction range_dim, range_dim_cols, RangeField>; - using ThisType = ConstDiscreteFunction<Vector, GridView, range_dim, range_dim_cols, RangeField>; + using ThisType = ConstDiscreteFunction; public: using ConstDofVectorType = ConstDofVector<Vector, GridView>; @@ -124,6 +124,7 @@ public: */ using BaseType::visualize; + using BaseType::visualize_gradient; /** * \brief Visualizes the function using Dune::XT::Functions::GridFunctionInterface::visualize on the grid view @@ -135,9 +136,27 @@ public: const VTK::OutputType vtk_output_type = VTK::appendedraw, const XT::Common::Parameter& param = {}) const { - this->visualize(space_.grid_view(), filename, space_.max_polorder() > 1, vtk_output_type, param); + const bool subsampling = + param.has_key("subsampling") ? static_cast<bool>(param.get("subsampling")[0]) : (space_.max_polorder() > 1); + this->visualize(space_.grid_view(), filename, subsampling, vtk_output_type, param); } + /** + * \brief Visualizes the function using Dune::XT::Functions::GridFunctionInterface::visualize on the grid view + * associated with the space. + * \sa Dune::XT::Functions::GridFunctionInterface::visualize + * \note Subsampling is enabled by default for functions of order greater than one. + */ + void visualize_gradient(const std::string filename, + const VTK::OutputType vtk_output_type = VTK::appendedraw, + const XT::Common::Parameter& param = {}) const + { + const bool subsampling = + param.has_key("subsampling") ? static_cast<bool>(param.get("subsampling")[0]) : (space_.max_polorder() > 1); + this->visualize_gradient(space_.grid_view(), filename, subsampling, vtk_output_type, param); + } + + protected: const SpaceType& space_; @@ -163,7 +182,7 @@ class DiscreteFunction : XT::Common::StorageProvider<Vector> , public ConstDiscreteFunction<Vector, GridView, range_dim, range_dim_cols, RangeField> { - using ThisType = DiscreteFunction<Vector, GridView, range_dim, range_dim_cols, RangeField>; + using ThisType = DiscreteFunction; using VectorStorage = XT::Common::StorageProvider<Vector>; using BaseType = ConstDiscreteFunction<Vector, GridView, range_dim, range_dim_cols, RangeField>; @@ -188,12 +207,17 @@ public: {} DiscreteFunction(const SpaceType& spc, const std::string nm = "dune.gdt.discretefunction") - : VectorStorage(new VectorType(spc.mapper().size(), 0)) + : VectorStorage(new VectorType(spc.mapper().size(), 0.)) , BaseType(spc, VectorStorage::access(), nm) , dofs_(space_.mapper(), VectorStorage::access()) {} - DiscreteFunction(const ThisType&) = default; + DiscreteFunction(const ThisType& other) + : VectorStorage(new VectorType(other.access())) + , BaseType(other.space(), VectorStorage::access(), other.name()) + , dofs_(other.space().mapper(), VectorStorage::access()) + {} + DiscreteFunction(ThisType&&) = default; ThisType& operator=(const ThisType&) = delete; @@ -281,4 +305,6 @@ make_discrete_function(const SpaceInterface<GV, r, rC, R>& space, const std::str } // namespace GDT } // namespace Dune +#include "default-datahandle.hh" + #endif // DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH diff --git a/dune/gdt/discretefunction/dof-vector.hh b/dune/gdt/discretefunction/dof-vector.hh index 5bf37949b3c3da427dca892622651824963b4d58..5cb1739ad79121773a51e5e47aa090ef26cf8549 100644 --- a/dune/gdt/discretefunction/dof-vector.hh +++ b/dune/gdt/discretefunction/dof-vector.hh @@ -26,7 +26,7 @@ class ConstDofVector { static_assert(XT::LA::is_vector<Vector>::value, ""); - using ThisType = ConstDofVector<Vector, GridView>; + using ThisType = ConstDofVector; public: using VectorType = Vector; @@ -67,7 +67,7 @@ class DofVector : public ConstDofVector<Vector, GridView> { static_assert(XT::LA::is_vector<Vector>::value, ""); - using ThisType = DofVector<Vector, GridView>; + using ThisType = DofVector; using BaseType = ConstDofVector<Vector, GridView>; public: diff --git a/dune/gdt/functionals/l2.hh b/dune/gdt/functionals/l2.hh index 72d8f5c8a481a2208eafceb09bd4f850873c32c2..2f3faafea297032bc11fab19e5b0b4e2e4e27fc3 100644 --- a/dune/gdt/functionals/l2.hh +++ b/dune/gdt/functionals/l2.hh @@ -40,7 +40,7 @@ namespace GDT { template <class V, class GV, size_t r = 1, size_t rC = 1, class F = double, class AssemblyGridView = GV> class L2VolumeVectorFunctional : public VectorBasedFunctional<V, GV, r, rC, F, AssemblyGridView> { - using ThisType = L2VolumeVectorFunctional<V, GV, r, rC, F, AssemblyGridView>; + using ThisType = L2VolumeVectorFunctional; using BaseType = VectorBasedFunctional<V, GV, r, rC, F, AssemblyGridView>; public: diff --git a/dune/gdt/functionals/localizable-functional.hh b/dune/gdt/functionals/localizable-functional.hh index a4105dfc8623ad8e12983160353bcc66faf56c2d..90c2224642df3580cd9432ad0d83403c23ecfbe7 100644 --- a/dune/gdt/functionals/localizable-functional.hh +++ b/dune/gdt/functionals/localizable-functional.hh @@ -31,7 +31,7 @@ class LocalizableFunctionalBase : public XT::Grid::Walker<GridView> { static_assert(XT::Grid::is_view<GridView>::value, ""); - using ThisType = LocalizableFunctionalBase<GridView, range_dim, range_dim_cols, RangeField>; + using ThisType = LocalizableFunctionalBase; using BaseType = XT::Grid::Walker<GridView>; public: diff --git a/dune/gdt/functionals/vector-based.hh b/dune/gdt/functionals/vector-based.hh index e82925e9fbe3ee8671d0753255790f179289152e..0841e094fbbd5199754265a3ffc1414eb94f46c7 100644 --- a/dune/gdt/functionals/vector-based.hh +++ b/dune/gdt/functionals/vector-based.hh @@ -25,8 +25,6 @@ #include "interfaces.hh" -// clang-format off -// see https://github.com/dune-community/dune-gdt/issues/142 namespace Dune { namespace GDT { @@ -45,7 +43,7 @@ class ConstVectorBasedFunctional : public FunctionalInterface<V, GV, r, rC, F> // All other types are checked elsewhere. static_assert(XT::LA::is_vector<V>::value, ""); - using ThisType = ConstVectorBasedFunctional<V, GV, r, rC, F>; + using ThisType = ConstVectorBasedFunctional; using FunctionalBaseType = FunctionalInterface<V, GV, r, rC, F>; public: @@ -145,7 +143,7 @@ class VectorBasedFunctional static_assert(std::is_same<XT::Grid::extract_entity_t<GV>, XT::Grid::extract_entity_t<AssemblyGridView>>::value, "We cannot handle different element types!"); - using ThisType = VectorBasedFunctional<V, GV, r, rC, F, AssemblyGridView>; + using ThisType = VectorBasedFunctional; using VectorStorage = XT::Common::StorageProvider<V>; using FunctionalBaseType = ConstVectorBasedFunctional<V, GV, r, rC, F>; using WalkerBaseType = XT::Grid::Walker<AssemblyGridView>; @@ -277,6 +275,4 @@ make_vector_functional(const SpaceInterface<GV, r, rC, F>& space) } // namespace GDT } // namespace Dune -// clang-format on - #endif // DUNE_GDT_FUNCTIONALS_VECTOR_BASED_HH diff --git a/dune/gdt/interpolations/default.hh b/dune/gdt/interpolations/default.hh index b9715b16a34e8aad15d3290e48b067daed34f938..1ce16f3f4d133fc660801ce9e62820ba03339cb3 100644 --- a/dune/gdt/interpolations/default.hh +++ b/dune/gdt/interpolations/default.hh @@ -17,19 +17,75 @@ #include <dune/grid/common/rangegenerators.hh> #include <dune/xt/grid/type_traits.hh> +#include <dune/xt/grid/functors/interfaces.hh> +#include <dune/xt/grid/walker.hh> + #include <dune/xt/functions/interfaces/grid-function.hh> #include <dune/xt/functions/interfaces/function.hh> #include <dune/xt/functions/generic/function.hh> #include <dune/gdt/discretefunction/default.hh> - namespace Dune { namespace GDT { // ### Variants for GridFunctionInterface +template <class GV, size_t r, size_t rC, class R, class V, class IGV> +class DefaultInterpolationElementFunctor : public XT::Grid::ElementFunctor<IGV> +{ + using BaseType = typename XT::Grid::ElementFunctor<IGV>; + +public: + using typename BaseType::E; + using SourceType = XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GV>, r, rC, R>; + using LocalSourceType = typename SourceType::LocalFunctionType; + using TargetType = DiscreteFunction<V, GV, r, rC, R>; + using LocalDofVectorType = typename TargetType::DofVectorType::LocalDofVectorType; + using TargetBasisType = typename TargetType::SpaceType::GlobalBasisType::LocalizedType; + + DefaultInterpolationElementFunctor(const SourceType& source, TargetType& target) + : source_(source) + , target_(target) + , local_dof_vector_(target.dofs().localize()) + , local_source_(source_.local_function()) + , target_basis_(target.space().basis().localize()) + { + DUNE_THROW_IF(target_.space().type() == SpaceType::raviart_thomas, + Exceptions::interpolation_error, + "Use the correct one from interpolations/raviart-thomas.hh instead!"); + } + DefaultInterpolationElementFunctor(const DefaultInterpolationElementFunctor& other) + : BaseType(other) + , source_(other.source_) + , target_(other.target_) + , local_dof_vector_(target_.dofs().localize()) + , local_source_(source_.local_function()) + , target_basis_(target_.space().basis().localize()) + {} + + XT::Grid::ElementFunctor<IGV>* copy() override final + { + return new DefaultInterpolationElementFunctor(*this); + } + + void apply_local(const E& element) override final + { + local_source_->bind(element); + local_dof_vector_.bind(element); + target_basis_->bind(element); + target_basis_->interpolate( + [&](const auto& xx) { return local_source_->evaluate(xx); }, local_source_->order(), local_dof_vector_); + } + +private: + const SourceType& source_; + TargetType& target_; + LocalDofVectorType local_dof_vector_; + std::unique_ptr<LocalSourceType> local_source_; + std::unique_ptr<TargetBasisType> target_basis_; +}; /** * \brief Interpolates a localizable function within a given space [most general variant]. @@ -46,26 +102,18 @@ namespace GDT { * * \note This might not be correct for all spaces, in particular if source is not continuous. */ -template <class GV, size_t r, size_t rC, class R, class V, class IGV> -std::enable_if_t<std::is_same<XT::Grid::extract_entity_t<GV>, typename IGV::Grid::template Codim<0>::Entity>::value, +template <class GV, size_t r, size_t rC, class R, class V, class IGVT> +std::enable_if_t<std::is_same<XT::Grid::extract_entity_t<GV>, typename IGVT::Grid::template Codim<0>::Entity>::value, void> default_interpolation(const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GV>, r, rC, R>& source, DiscreteFunction<V, GV, r, rC, R>& target, - const GridView<IGV>& interpolation_grid_view) + const GridView<IGVT>& interpolation_grid_view) { - DUNE_THROW_IF(target.space().type() == SpaceType::raviart_thomas, - Exceptions::interpolation_error, - "Use the correct one from interpolations/raviart-thomas.hh instead!"); - auto local_dof_vector = target.dofs().localize(); - auto local_source = source.local_function(); - auto target_basis = target.space().basis().localize(); - for (auto&& element : elements(interpolation_grid_view)) { - local_source->bind(element); - local_dof_vector.bind(element); - target_basis->bind(element); - target_basis->interpolate( - [&](const auto& xx) { return local_source->evaluate(xx); }, local_source->order(), local_dof_vector); - } + DefaultInterpolationElementFunctor<GV, r, rC, R, V, GridView<IGVT>> functor(source, target); + auto walker = XT::Grid::Walker<GridView<IGVT>>(interpolation_grid_view); + walker.append(functor); + // Basis functions other than FV do not seem to be thread safe. TODO: fix + walker.walk(target.space().type() == SpaceType::finite_volume); } // ... default_interpolation(...) @@ -84,14 +132,14 @@ void default_interpolation(const XT::Functions::GridFunctionInterface<XT::Grid:: /** * \brief Interpolates a localizable function within a given space [creates a suitable target function]. **/ -template <class VectorType, class GV, size_t r, size_t rC, class R, class IGV> +template <class VectorType, class GV, size_t r, size_t rC, class R, class IGVT> std::enable_if_t< XT::LA::is_vector<VectorType>::value - && std::is_same<XT::Grid::extract_entity_t<GV>, typename IGV::Grid::template Codim<0>::Entity>::value, + && std::is_same<XT::Grid::extract_entity_t<GV>, typename IGVT::Grid::template Codim<0>::Entity>::value, DiscreteFunction<VectorType, GV, r, rC, R>> default_interpolation(const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GV>, r, rC, R>& source, const SpaceInterface<GV, r, rC, R>& target_space, - const GridView<IGV>& interpolation_grid_view) + const GridView<IGVT>& interpolation_grid_view) { auto target_function = make_discrete_function<VectorType>(target_space); default_interpolation(source, target_function, interpolation_grid_view); @@ -122,12 +170,12 @@ default_interpolation(const XT::Functions::GridFunctionInterface<XT::Grid::extra * * Simply calls as_grid_function<>() and redirects to the appropriate default_interpolation() function. */ -template <class GV, size_t r, size_t rC, class R, class V, class IGV> -std::enable_if_t<std::is_same<XT::Grid::extract_entity_t<GV>, typename IGV::Grid::template Codim<0>::Entity>::value, +template <class GV, size_t r, size_t rC, class R, class V, class IGVT> +std::enable_if_t<std::is_same<XT::Grid::extract_entity_t<GV>, typename IGVT::Grid::template Codim<0>::Entity>::value, void> -default_interpolation(const XT::Functions::FunctionInterface<GridView<IGV>::dimension, r, rC, R>& source, +default_interpolation(const XT::Functions::FunctionInterface<GridView<IGVT>::dimension, r, rC, R>& source, DiscreteFunction<V, GV, r, rC, R>& target, - const GridView<IGV>& interpolation_grid_view) + const GridView<IGVT>& interpolation_grid_view) { default_interpolation(source.as_grid_function(interpolation_grid_view), target, interpolation_grid_view); } @@ -148,14 +196,14 @@ void default_interpolation(const XT::Functions::FunctionInterface<GV::dimension, /** * \brief Interpolates a function within a given space [creates a suitable target function]. **/ -template <class VectorType, class GV, size_t r, size_t rC, class R, class IGV> +template <class VectorType, class GV, size_t r, size_t rC, class R, class IGVT> std::enable_if_t< XT::LA::is_vector<VectorType>::value - && std::is_same<XT::Grid::extract_entity_t<GV>, typename IGV::Grid::template Codim<0>::Entity>::value, + && std::is_same<XT::Grid::extract_entity_t<GV>, typename IGVT::Grid::template Codim<0>::Entity>::value, DiscreteFunction<VectorType, GV, r, rC, R>> -default_interpolation(const XT::Functions::FunctionInterface<GridView<IGV>::dimension, r, rC, R>& source, +default_interpolation(const XT::Functions::FunctionInterface<GridView<IGVT>::dimension, r, rC, R>& source, const SpaceInterface<GV, r, rC, R>& target_space, - const GridView<IGV>& interpolation_grid_view) + const GridView<IGVT>& interpolation_grid_view) { return default_interpolation<VectorType>( source.as_grid_function(interpolation_grid_view), target_space, interpolation_grid_view); @@ -183,19 +231,19 @@ default_interpolation(const XT::Functions::FunctionInterface<GV::dimension, r, r * * Simply creates a XT::Functions::GenericFunction and redirects to the appropriate default_interpolation() function. */ -template <class GV, size_t r, size_t rC, class R, class V, class IGV> -std::enable_if_t<std::is_same<XT::Grid::extract_entity_t<GV>, typename IGV::Grid::template Codim<0>::Entity>::value, +template <class GV, size_t r, size_t rC, class R, class V, class IGVT> +std::enable_if_t<std::is_same<XT::Grid::extract_entity_t<GV>, typename IGVT::Grid::template Codim<0>::Entity>::value, void> default_interpolation( const int source_order, - const std::function<typename XT::Functions::GenericFunction<GridView<IGV>::dimension, r, rC, R>::RangeReturnType( - const typename XT::Functions::GenericFunction<GridView<IGV>::dimension, r, rC, R>::DomainType&, + const std::function<typename XT::Functions::GenericFunction<GridView<IGVT>::dimension, r, rC, R>::RangeReturnType( + const typename XT::Functions::GenericFunction<GridView<IGVT>::dimension, r, rC, R>::DomainType&, const XT::Common::Parameter&)> source_evaluate_lambda, DiscreteFunction<V, GV, r, rC, R>& target, - const GridView<IGV>& interpolation_grid_view) + const GridView<IGVT>& interpolation_grid_view) { default_interpolation( - XT::Functions::GenericFunction<GridView<IGV>::dimension, r, rC, R>(source_order, source_evaluate_lambda), + XT::Functions::GenericFunction<GridView<IGVT>::dimension, r, rC, R>(source_order, source_evaluate_lambda), target, interpolation_grid_view); } @@ -222,21 +270,21 @@ void default_interpolation( * \brief Interpolates a function given as a lambda expression within a given space [creates a suitable target * function]. **/ -template <class VectorType, class GV, size_t r, size_t rC, class R, class IGV> +template <class VectorType, class GV, size_t r, size_t rC, class R, class IGVT> std::enable_if_t< XT::LA::is_vector<VectorType>::value - && std::is_same<XT::Grid::extract_entity_t<GV>, typename IGV::Grid::template Codim<0>::Entity>::value, + && std::is_same<XT::Grid::extract_entity_t<GV>, typename IGVT::Grid::template Codim<0>::Entity>::value, DiscreteFunction<VectorType, GV, r, rC, R>> default_interpolation( const int source_order, - const std::function<typename XT::Functions::GenericFunction<GridView<IGV>::dimension, r, rC, R>::RangeReturnType( - const typename XT::Functions::GenericFunction<GridView<IGV>::dimension, r, rC, R>::DomainType&, + const std::function<typename XT::Functions::GenericFunction<GridView<IGVT>::dimension, r, rC, R>::RangeReturnType( + const typename XT::Functions::GenericFunction<GridView<IGVT>::dimension, r, rC, R>::DomainType&, const XT::Common::Parameter&)> source_evaluate_lambda, const SpaceInterface<GV, r, rC, R>& target_space, - const GridView<IGV>& interpolation_grid_view) + const GridView<IGVT>& interpolation_grid_view) { return default_interpolation<VectorType>( - XT::Functions::GenericFunction<GridView<IGV>::dimension, r, rC, R>(source_order, source_evaluate_lambda), + XT::Functions::GenericFunction<GridView<IGVT>::dimension, r, rC, R>(source_order, source_evaluate_lambda), target_space, interpolation_grid_view); } diff --git a/dune/gdt/local/assembler/bilinear-form-accumulators.hh b/dune/gdt/local/assembler/bilinear-form-accumulators.hh index 14c0b36d7a0b4d34ae972be5a11638c5e824210c..e300e65690cf0093edf1594298e4547756360be0 100644 --- a/dune/gdt/local/assembler/bilinear-form-accumulators.hh +++ b/dune/gdt/local/assembler/bilinear-form-accumulators.hh @@ -48,7 +48,7 @@ class LocalElementBilinearFormAccumulator { static_assert(XT::Grid::is_view<GV>::value, ""); - using ThisType = LocalElementBilinearFormAccumulator<GV, s_r, s_rC, SF, R, r_r, r_rC, RF>; + using ThisType = LocalElementBilinearFormAccumulator; using BaseType = XT::Grid::ElementFunctor<GV>; using Propagator = XT::Common::ThreadResultPropagator<LocalElementBilinearFormAccumulator<GV, s_r, s_rC, SF, R, r_r, r_rC, RF>, R>; diff --git a/dune/gdt/local/assembler/bilinear-form-assemblers.hh b/dune/gdt/local/assembler/bilinear-form-assemblers.hh index 526bb127a5d9416f6cabe63470602f14cd43da90..089ce82d541a26c837330c7be23deba1bf2b7ab5 100644 --- a/dune/gdt/local/assembler/bilinear-form-assemblers.hh +++ b/dune/gdt/local/assembler/bilinear-form-assemblers.hh @@ -36,7 +36,7 @@ class LocalElementBilinearFormAssembler : public XT::Grid::ElementFunctor<GridVi static_assert(XT::LA::is_matrix<Matrix>::value, ""); static_assert(XT::Grid::is_view<GridView>::value, ""); - using ThisType = LocalElementBilinearFormAssembler<Matrix, GridView, t_r, t_rC, TR, TGV, AGV, a_r, a_rC, AR>; + using ThisType = LocalElementBilinearFormAssembler; using BaseType = XT::Grid::ElementFunctor<GridView>; public: @@ -53,41 +53,41 @@ public: MatrixType& global_matrix, const XT::Common::Parameter& param = {}) : BaseType() - , test_space_(test_space) - , ansatz_space_(ansatz_space) + , test_space_(test_space.copy()) + , ansatz_space_(ansatz_space.copy()) , local_bilinear_form_(local_two_form.copy()) , global_matrix_(global_matrix) , param_(param) , scaling_(param_.has_key("matrixoperator.scaling") ? param_.get("matrixoperator.scaling").at(0) : 1.) - , local_matrix_(test_space_.mapper().max_local_size(), ansatz_space_.mapper().max_local_size()) - , global_test_indices_(test_space_.mapper().max_local_size()) - , global_ansatz_indices_(ansatz_space_.mapper().max_local_size()) - , test_basis_(test_space_.basis().localize()) - , ansatz_basis_(ansatz_space_.basis().localize()) + , local_matrix_(test_space_->mapper().max_local_size(), ansatz_space_->mapper().max_local_size()) + , global_test_indices_(test_space_->mapper().max_local_size()) + , global_ansatz_indices_(ansatz_space_->mapper().max_local_size()) + , test_basis_(test_space_->basis().localize()) + , ansatz_basis_(ansatz_space_->basis().localize()) { - DUNE_THROW_IF(global_matrix_.rows() != test_space_.mapper().size(), + DUNE_THROW_IF(global_matrix_.rows() != test_space_->mapper().size(), XT::Common::Exceptions::shapes_do_not_match, "global_matrix_.rows() = " << global_matrix_.rows() << "\n " - << "test_space_.mapper().size()" << test_space_.mapper().size()); - DUNE_THROW_IF(global_matrix_.cols() != ansatz_space_.mapper().size(), + << "test_space_->mapper().size()" << test_space_->mapper().size()); + DUNE_THROW_IF(global_matrix_.cols() != ansatz_space_->mapper().size(), XT::Common::Exceptions::shapes_do_not_match, "global_matrix_.cols() = " << global_matrix_.cols() << "\n " - << "ansatz_space_.mapper().size()" << ansatz_space_.mapper().size()); + << "ansatz_space_->mapper().size()" << ansatz_space_->mapper().size()); } LocalElementBilinearFormAssembler(const ThisType& other) : BaseType() - , test_space_(other.test_space_) - , ansatz_space_(other.ansatz_space_) + , test_space_(other.test_space_->copy()) + , ansatz_space_(other.ansatz_space_->copy()) , local_bilinear_form_(other.local_bilinear_form_->copy()) , global_matrix_(other.global_matrix_) , param_(other.param_) , scaling_(other.scaling_) - , local_matrix_(test_space_.mapper().max_local_size(), ansatz_space_.mapper().max_local_size()) - , global_test_indices_(test_space_.mapper().max_local_size()) - , global_ansatz_indices_(ansatz_space_.mapper().max_local_size()) - , test_basis_(test_space_.basis().localize()) - , ansatz_basis_(ansatz_space_.basis().localize()) + , local_matrix_(test_space_->mapper().max_local_size(), ansatz_space_->mapper().max_local_size()) + , global_test_indices_(test_space_->mapper().max_local_size()) + , global_ansatz_indices_(ansatz_space_->mapper().max_local_size()) + , test_basis_(test_space_->basis().localize()) + , ansatz_basis_(ansatz_space_->basis().localize()) {} LocalElementBilinearFormAssembler(ThisType&& source) = default; @@ -104,8 +104,8 @@ public: ansatz_basis_->bind(element); local_bilinear_form_->apply2(*test_basis_, *ansatz_basis_, local_matrix_, param_); // copy local matrix to global matrix - test_space_.mapper().global_indices(element, global_test_indices_); - ansatz_space_.mapper().global_indices(element, global_ansatz_indices_); + test_space_->mapper().global_indices(element, global_test_indices_); + ansatz_space_->mapper().global_indices(element, global_ansatz_indices_); for (size_t ii = 0; ii < test_basis_->size(param_); ++ii) for (size_t jj = 0; jj < ansatz_basis_->size(param_); ++jj) global_matrix_.add_to_entry( @@ -113,8 +113,8 @@ public: } // ... apply_local(...) private: - const TestSpaceType& test_space_; - const AnsatzSpaceType& ansatz_space_; + const std::unique_ptr<TestSpaceType> test_space_; + const std::unique_ptr<AnsatzSpaceType> ansatz_space_; const std::unique_ptr<LocalBilinearFormType> local_bilinear_form_; MatrixType& global_matrix_; XT::Common::Parameter param_; @@ -142,7 +142,7 @@ class LocalIntersectionBilinearFormAssembler : public XT::Grid::IntersectionFunc static_assert(XT::LA::is_matrix<Matrix>::value, ""); static_assert(XT::Grid::is_view<GridView>::value, ""); - using ThisType = LocalIntersectionBilinearFormAssembler<Matrix, GridView, t_r, t_rC, TR, TGV, AGV, a_r, a_rC, AR>; + using ThisType = LocalIntersectionBilinearFormAssembler; using BaseType = XT::Grid::IntersectionFunctor<GridView>; public: @@ -161,55 +161,55 @@ public: MatrixType& global_matrix, const XT::Common::Parameter& param = {}) : BaseType() - , test_space_(test_space) - , ansatz_space_(ansatz_space) + , test_space_(test_space.copy()) + , ansatz_space_(ansatz_space.copy()) , local_bilinear_form_(local_two_form.copy()) , global_matrix_(global_matrix) , param_(param) , scaling_(param_.has_key("matrixoperator.scaling") ? param_.get("matrixoperator.scaling").at(0) : 1.) - , local_matrix_in_in_(test_space_.mapper().max_local_size(), ansatz_space_.mapper().max_local_size()) - , local_matrix_in_out_(test_space_.mapper().max_local_size(), ansatz_space_.mapper().max_local_size()) - , local_matrix_out_in_(test_space_.mapper().max_local_size(), ansatz_space_.mapper().max_local_size()) - , local_matrix_out_out_(test_space_.mapper().max_local_size(), ansatz_space_.mapper().max_local_size()) - , global_test_indices_in_(test_space_.mapper().max_local_size()) - , global_test_indices_out_(test_space_.mapper().max_local_size()) - , global_ansatz_indices_in_(ansatz_space_.mapper().max_local_size()) - , global_ansatz_indices_out_(ansatz_space_.mapper().max_local_size()) - , test_basis_inside_(test_space_.basis().localize()) - , test_basis_outside_(test_space_.basis().localize()) - , ansatz_basis_inside_(ansatz_space_.basis().localize()) - , ansatz_basis_outside_(ansatz_space_.basis().localize()) + , local_matrix_in_in_(test_space_->mapper().max_local_size(), ansatz_space_->mapper().max_local_size()) + , local_matrix_in_out_(test_space_->mapper().max_local_size(), ansatz_space_->mapper().max_local_size()) + , local_matrix_out_in_(test_space_->mapper().max_local_size(), ansatz_space_->mapper().max_local_size()) + , local_matrix_out_out_(test_space_->mapper().max_local_size(), ansatz_space_->mapper().max_local_size()) + , global_test_indices_in_(test_space_->mapper().max_local_size()) + , global_test_indices_out_(test_space_->mapper().max_local_size()) + , global_ansatz_indices_in_(ansatz_space_->mapper().max_local_size()) + , global_ansatz_indices_out_(ansatz_space_->mapper().max_local_size()) + , test_basis_inside_(test_space_->basis().localize()) + , test_basis_outside_(test_space_->basis().localize()) + , ansatz_basis_inside_(ansatz_space_->basis().localize()) + , ansatz_basis_outside_(ansatz_space_->basis().localize()) { - DUNE_THROW_IF(global_matrix_.rows() != test_space_.mapper().size(), + DUNE_THROW_IF(global_matrix_.rows() != test_space_->mapper().size(), XT::Common::Exceptions::shapes_do_not_match, "global_matrix_.rows() = " << global_matrix_.rows() << "\n " - << "test_space_.mapper().size()" << test_space_.mapper().size()); - DUNE_THROW_IF(global_matrix_.cols() != ansatz_space_.mapper().size(), + << "test_space_->mapper().size()" << test_space_->mapper().size()); + DUNE_THROW_IF(global_matrix_.cols() != ansatz_space_->mapper().size(), XT::Common::Exceptions::shapes_do_not_match, "global_matrix_.cols() = " << global_matrix_.cols() << "\n " - << "ansatz_space_.mapper().size()" << ansatz_space_.mapper().size()); + << "ansatz_space_->mapper().size()" << ansatz_space_->mapper().size()); } LocalIntersectionBilinearFormAssembler(const ThisType& other) : BaseType() - , test_space_(other.test_space_) - , ansatz_space_(other.ansatz_space_) + , test_space_(other.test_space_->copy()) + , ansatz_space_(other.ansatz_space_->copy()) , local_bilinear_form_(other.local_bilinear_form_->copy()) , global_matrix_(other.global_matrix_) , param_(other.param_) , scaling_(other.scaling_) - , local_matrix_in_in_(test_space_.mapper().max_local_size(), ansatz_space_.mapper().max_local_size()) - , local_matrix_in_out_(test_space_.mapper().max_local_size(), ansatz_space_.mapper().max_local_size()) - , local_matrix_out_in_(test_space_.mapper().max_local_size(), ansatz_space_.mapper().max_local_size()) - , local_matrix_out_out_(test_space_.mapper().max_local_size(), ansatz_space_.mapper().max_local_size()) - , global_test_indices_in_(test_space_.mapper().max_local_size()) - , global_test_indices_out_(test_space_.mapper().max_local_size()) - , global_ansatz_indices_in_(ansatz_space_.mapper().max_local_size()) - , global_ansatz_indices_out_(ansatz_space_.mapper().max_local_size()) - , test_basis_inside_(test_space_.basis().localize()) - , test_basis_outside_(test_space_.basis().localize()) - , ansatz_basis_inside_(ansatz_space_.basis().localize()) - , ansatz_basis_outside_(ansatz_space_.basis().localize()) + , local_matrix_in_in_(test_space_->mapper().max_local_size(), ansatz_space_->mapper().max_local_size()) + , local_matrix_in_out_(test_space_->mapper().max_local_size(), ansatz_space_->mapper().max_local_size()) + , local_matrix_out_in_(test_space_->mapper().max_local_size(), ansatz_space_->mapper().max_local_size()) + , local_matrix_out_out_(test_space_->mapper().max_local_size(), ansatz_space_->mapper().max_local_size()) + , global_test_indices_in_(test_space_->mapper().max_local_size()) + , global_test_indices_out_(test_space_->mapper().max_local_size()) + , global_ansatz_indices_in_(ansatz_space_->mapper().max_local_size()) + , global_ansatz_indices_out_(ansatz_space_->mapper().max_local_size()) + , test_basis_inside_(test_space_->basis().localize()) + , test_basis_outside_(test_space_->basis().localize()) + , ansatz_basis_inside_(ansatz_space_->basis().localize()) + , ansatz_basis_outside_(ansatz_space_->basis().localize()) {} LocalIntersectionBilinearFormAssembler(ThisType&& source) = default; @@ -239,10 +239,10 @@ public: local_matrix_out_out_, param_); // copy local matrices to global matrix - test_space_.mapper().global_indices(inside_element, global_test_indices_in_); - test_space_.mapper().global_indices(outside_element, global_test_indices_out_); - ansatz_space_.mapper().global_indices(inside_element, global_ansatz_indices_in_); - ansatz_space_.mapper().global_indices(outside_element, global_ansatz_indices_out_); + test_space_->mapper().global_indices(inside_element, global_test_indices_in_); + test_space_->mapper().global_indices(outside_element, global_test_indices_out_); + ansatz_space_->mapper().global_indices(inside_element, global_ansatz_indices_in_); + ansatz_space_->mapper().global_indices(outside_element, global_ansatz_indices_out_); for (size_t ii = 0; ii < test_basis_inside_->size(param_); ++ii) { for (size_t jj = 0; jj < ansatz_basis_inside_->size(param_); ++jj) global_matrix_.add_to_entry( @@ -262,8 +262,8 @@ public: } // ... apply_local(...) private: - const TestSpaceType& test_space_; - const AnsatzSpaceType& ansatz_space_; + const std::unique_ptr<TestSpaceType> test_space_; + const std::unique_ptr<AnsatzSpaceType> ansatz_space_; const std::unique_ptr<LocalBilinearFormType> local_bilinear_form_; MatrixType& global_matrix_; XT::Common::Parameter param_; diff --git a/dune/gdt/local/assembler/functional-accumulators.hh b/dune/gdt/local/assembler/functional-accumulators.hh index 0d6d7809289b339d858fa71ca11363a256026c31..c152f0103ae4405deadeccaa9bc30631298d0807 100644 --- a/dune/gdt/local/assembler/functional-accumulators.hh +++ b/dune/gdt/local/assembler/functional-accumulators.hh @@ -40,7 +40,7 @@ class LocalElementFunctionalAccumulator { static_assert(XT::Grid::is_view<GridView>::value, ""); - using ThisType = LocalElementFunctionalAccumulator<GridView, r, rC, R, F>; + using ThisType = LocalElementFunctionalAccumulator; using BaseType = XT::Grid::ElementFunctor<GridView>; using Propagator = XT::Common::ThreadResultPropagator<LocalElementFunctionalAccumulator<GridView, r, rC, R, F>, F>; friend Propagator; diff --git a/dune/gdt/local/assembler/functional-assemblers.hh b/dune/gdt/local/assembler/functional-assemblers.hh index 56eadff3b33ea9ae1d65d19b6e741352ce93884d..841fb6adece82dd916ec50d0492f5398f48997b5 100644 --- a/dune/gdt/local/assembler/functional-assemblers.hh +++ b/dune/gdt/local/assembler/functional-assemblers.hh @@ -28,7 +28,7 @@ class LocalElementFunctionalAssembler : public XT::Grid::ElementFunctor<GridView static_assert(XT::Grid::is_view<GridView>::value, ""); static_assert(XT::Grid::is_view<SpaceGridView>::value, ""); - using ThisType = LocalElementFunctionalAssembler<Vector, GridView, r, rC, R, SpaceGridView>; + using ThisType = LocalElementFunctionalAssembler; using BaseType = XT::Grid::ElementFunctor<GridView>; public: @@ -42,29 +42,29 @@ public: const LocalFunctionalType& local_functional, VectorType& global_vector, const XT::Common::Parameter& param = {}) - : space_(space) + : space_(space.copy()) , local_functional_(local_functional.copy()) , global_vector_(global_vector) , param_(param) - , local_vector_(space_.mapper().max_local_size()) - , global_indices_(space_.mapper().max_local_size()) - , basis_(space_.basis().localize()) + , local_vector_(space_->mapper().max_local_size()) + , global_indices_(space_->mapper().max_local_size()) + , basis_(space_->basis().localize()) { - DUNE_THROW_IF(global_vector_.size() != space_.mapper().size(), + DUNE_THROW_IF(global_vector_.size() != space_->mapper().size(), XT::Common::Exceptions::shapes_do_not_match, "global_vector.size() = " << global_vector_.size() << "\n " - << "space.mapper().size()" << space_.mapper().size()); + << "space.mapper().size()" << space_->mapper().size()); } LocalElementFunctionalAssembler(const ThisType& other) : BaseType() - , space_(other.space_) + , space_(other.space_->copy()) , local_functional_(other.local_functional_->copy()) , global_vector_(other.global_vector_) , param_(other.param_) , local_vector_(other.local_vector_) , global_indices_(other.global_indices_) - , basis_(space_.basis().localize()) + , basis_(space_->basis().localize()) {} LocalElementFunctionalAssembler(ThisType&& source) = default; @@ -80,13 +80,13 @@ public: basis_->bind(element); local_functional_->apply(*basis_, local_vector_, param_); // copy local vector to global - space_.mapper().global_indices(element, global_indices_); + space_->mapper().global_indices(element, global_indices_); for (size_t jj = 0; jj < basis_->size(param_); ++jj) global_vector_.add_to_entry(global_indices_[jj], local_vector_[jj]); } private: - const SpaceType& space_; + std::unique_ptr<const SpaceType> space_; std::unique_ptr<LocalFunctionalType> local_functional_; VectorType& global_vector_; XT::Common::Parameter param_; diff --git a/dune/gdt/local/assembler/operator-applicators.hh b/dune/gdt/local/assembler/operator-applicators.hh index afadc887836ec544c1b4994255e93cc1d0c24cf0..fdfd45a27b22a1315e8b9e44d31ae5ea3ab74db9 100644 --- a/dune/gdt/local/assembler/operator-applicators.hh +++ b/dune/gdt/local/assembler/operator-applicators.hh @@ -51,7 +51,7 @@ class LocalElementOperatorApplicator : public XT::Grid::ElementFunctor<AssemblyG static_assert(std::is_same<XT::Grid::extract_entity_t<AssemblyGridView>, XT::Grid::extract_entity_t<SGV>>::value, ""); static_assert(std::is_same<XT::Grid::extract_entity_t<AssemblyGridView>, XT::Grid::extract_entity_t<RGV>>::value, ""); - using ThisType = LocalElementOperatorApplicator<AssemblyGridView, SV, s_r, s_rC, SF, SGV, r_r, r_rC, RF, RGV, RV>; + using ThisType = LocalElementOperatorApplicator; using BaseType = XT::Grid::ElementFunctor<AssemblyGridView>; public: @@ -62,18 +62,16 @@ public: using LocalOperatorType = LocalElementOperatorInterface<SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, RGV, RV>; LocalElementOperatorApplicator(const LocalOperatorType& local_operator, - const SourceType& source, RangeType& range, const XT::Common::Parameter& param = {}) : local_operator_(local_operator.copy()) - , source_(source) , range_(range) , param_(param) , local_range_(range_.local_discrete_function()) {} LocalElementOperatorApplicator(const ThisType& other) - : LocalElementOperatorApplicator(*other.local_operator_, other.source_, other.range_, other.param_) + : LocalElementOperatorApplicator(*other.local_operator_, other.range_, other.param_) {} BaseType* copy() override final @@ -84,12 +82,11 @@ public: void apply_local(const ElementType& element) override final { local_range_->bind(element); - local_operator_->apply(source_, *local_range_, param_); + local_operator_->apply(*local_range_, param_); } private: const std::unique_ptr<LocalOperatorType> local_operator_; - const SourceType& source_; RangeType& range_; const XT::Common::Parameter param_; std::unique_ptr<typename RangeType::LocalDiscreteFunctionType> local_range_; @@ -103,12 +100,11 @@ template <class SV, class GV, size_t s_r, size_t s_rC, class SF, size_t r_r, siz std::unique_ptr<LocalElementOperatorApplicator<GV, SV, s_r, s_rC, SF, GV, r_r, r_rC, RF, GV, RV>> make_local_element_operator_applicator( const LocalElementOperatorInterface<SV, GV, s_r, s_rC, SF, r_r, r_rC, RF, GV, RV>& local_operator, - const ConstDiscreteFunction<SV, GV, s_r, s_rC, SF>& source, DiscreteFunction<RV, GV, r_r, r_rC, RF>& range, const XT::Common::Parameter& param = {}) { return std::make_unique<LocalElementOperatorApplicator<GV, SV, s_r, s_rC, SF, GV, r_r, r_rC, RF, GV, RV>>( - local_operator, source, range, param); + local_operator, range, param); } /** @@ -128,13 +124,12 @@ template <class AssemblyGridView, std::unique_ptr<LocalElementOperatorApplicator<AssemblyGridView, SV, s_r, s_rC, SF, SGV, r_r, r_rC, RF, RGV, RV>> make_local_element_operator_applicator( const LocalElementOperatorInterface<SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, RGV, RV>& local_operator, - const ConstDiscreteFunction<SV, SGV, s_r, s_rC, SF>& source, DiscreteFunction<RV, RGV, r_r, r_rC, RF>& range, const XT::Common::Parameter& param = {}) { return std::make_unique< LocalElementOperatorApplicator<AssemblyGridView, SV, s_r, s_rC, SF, SGV, r_r, r_rC, RF, RGV, RV>>( - local_operator, source, range, param); + local_operator, range, param); } @@ -199,12 +194,10 @@ public: LocalIntersectionOperatorInterface<IntersectionType, SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, IRGV, IRV, ORGV, ORV>; LocalIntersectionOperatorApplicator(const LocalOperatorType& local_operator, - const SourceType& source, InsideRangeType& range_inside, OutsideRangeType& range_outside, const XT::Common::Parameter& param = {}) : local_operator_(local_operator.copy()) - , source_(source) , range_inside_(range_inside) , range_outside_(range_outside) , param_(param) @@ -214,7 +207,7 @@ public: LocalIntersectionOperatorApplicator(const ThisType& other) : LocalIntersectionOperatorApplicator( - *other.local_operator_, other.source_, other.range_inside_, other.range_outside_, other.param_) + *other.local_operator_, other.range_inside_, other.range_outside_, other.param_) {} BaseType* copy() override final @@ -228,12 +221,12 @@ public: { local_range_inside_->bind(inside_element); local_range_outside_->bind(outside_element); - local_operator_->apply(source_, intersection, *local_range_inside_, *local_range_outside_, param_); + local_operator_->bind(intersection); + local_operator_->apply(intersection, *local_range_inside_, *local_range_outside_, param_); } private: const std::unique_ptr<LocalOperatorType> local_operator_; - const SourceType& source_; InsideRangeType& range_inside_; OutsideRangeType& range_outside_; const XT::Common::Parameter param_; @@ -263,14 +256,13 @@ std::enable_if_t< std::unique_ptr<LocalIntersectionOperatorApplicator<GV, SV, s_r, s_rC, SF, GV, r_r, r_rC, RF, GV, IRV, GV, ORV>>> make_local_intersection_operator_applicator( const LocalIntersectionOperatorInterface<I, SV, GV, s_r, s_rC, SF, r_r, r_rC, RF, GV, IRV, GV, ORV>& local_operator, - const ConstDiscreteFunction<SV, GV, s_r, s_rC, SF>& source, DiscreteFunction<IRV, GV, r_r, r_rC, RF>& range_inside, DiscreteFunction<ORV, GV, r_r, r_rC, RF>& range_outside, const XT::Common::Parameter& param = {}) { return std::make_unique< LocalIntersectionOperatorApplicator<GV, SV, s_r, s_rC, SF, GV, r_r, r_rC, RF, GV, IRV, GV, ORV>>( - local_operator, source, range_inside, range_outside, param); + local_operator, range_inside, range_outside, param); } // ... make_local_intersection_operator_applicator(...) template <class I, class SV, class GV, size_t s_r, size_t s_rC, class SF, size_t r_r, size_t r_rC, class RF, class RV> @@ -278,12 +270,11 @@ std::enable_if_t<std::is_same<XT::Grid::extract_intersection_t<GV>, I>::value, std::unique_ptr<LocalIntersectionOperatorApplicator<GV, SV, s_r, s_rC, SF, GV, r_r, r_rC, RF, GV, RV>>> make_local_intersection_operator_applicator( const LocalIntersectionOperatorInterface<I, SV, GV, s_r, s_rC, SF, r_r, r_rC, RF, GV, RV>& local_operator, - const ConstDiscreteFunction<SV, GV, s_r, s_rC, SF>& source, DiscreteFunction<RV, GV, r_r, r_rC, RF>& range, const XT::Common::Parameter& param = {}) { return std::make_unique<LocalIntersectionOperatorApplicator<GV, SV, s_r, s_rC, SF, GV, r_r, r_rC, RF, GV, RV>>( - local_operator, source, range, range, param); + local_operator, range, range, param); } /** @@ -322,7 +313,6 @@ std::enable_if_t<std::is_same<XT::Grid::extract_intersection_t<AssemblyGridView> make_local_intersection_operator_applicator( const LocalIntersectionOperatorInterface<I, SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, IRGV, IRV, ORGV, ORV>& local_operator, - const ConstDiscreteFunction<SV, SGV, s_r, s_rC, SF>& source, DiscreteFunction<IRV, IRGV, r_r, r_rC, RF>& range_inside, DiscreteFunction<ORV, ORGV, r_r, r_rC, RF>& range_outside, const XT::Common::Parameter& param = {}) @@ -339,8 +329,7 @@ make_local_intersection_operator_applicator( IRGV, IRV, ORGV, - ORV>>( - local_operator, source, range_inside, range_outside, param); + ORV>>(local_operator, range_inside, range_outside, param); } // ... make_local_intersection_operator_applicator(...) template <class AssemblyGridView, @@ -361,13 +350,12 @@ std::enable_if_t< LocalIntersectionOperatorApplicator<AssemblyGridView, SV, s_r, s_rC, SF, SGV, r_r, r_rC, RF, RGV, RV>>> make_local_intersection_operator_applicator( const LocalIntersectionOperatorInterface<I, SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, RGV, RV>& local_operator, - const ConstDiscreteFunction<SV, SGV, s_r, s_rC, SF>& source, DiscreteFunction<RV, RGV, r_r, r_rC, RF>& range, const XT::Common::Parameter& param = {}) { return std::make_unique< LocalIntersectionOperatorApplicator<AssemblyGridView, SV, s_r, s_rC, SF, SGV, r_r, r_rC, RF, RGV, RV>>( - local_operator, source, range, range, param); + local_operator, range, range, param); } /// \} diff --git a/dune/gdt/local/assembler/operator-fd-jacobian-assemblers.hh b/dune/gdt/local/assembler/operator-fd-jacobian-assemblers.hh index bc0c6ba940a221dcf593581192b4b77aad59f84c..3c5714b4ddfd65b802c76347f4ee460c1df46ff5 100644 --- a/dune/gdt/local/assembler/operator-fd-jacobian-assemblers.hh +++ b/dune/gdt/local/assembler/operator-fd-jacobian-assemblers.hh @@ -59,7 +59,7 @@ class LocalElementOperatorFiniteDifferenceJacobianAssembler : public XT::Grid::E static_assert(std::is_same<XT::Grid::extract_entity_t<SGV>, XT::Grid::extract_entity_t<RGV>>::value, ""); using BaseType = XT::Grid::ElementFunctor<SGV>; - using ThisType = LocalElementOperatorFiniteDifferenceJacobianAssembler<M, SGV, s_r, s_rC, F, r_r, r_rC, RGV>; + using ThisType = LocalElementOperatorFiniteDifferenceJacobianAssembler; public: using typename BaseType::ElementType; @@ -69,7 +69,7 @@ public: using V = VectorType; using LocalElementOperatorType = LocalElementOperatorInterface<V, SGV, s_r, s_rC, F, r_r, r_rC, F, RGV>; - using SourceSpaceType = typename LocalElementOperatorType::SourceType::SpaceType; + using SourceSpaceType = typename LocalElementOperatorType::DiscreteSourceType::SpaceType; using RangeSpaceType = typename LocalElementOperatorType::LocalRangeType::SpaceType; LocalElementOperatorFiniteDifferenceJacobianAssembler(const SourceSpaceType& source_space, @@ -79,37 +79,37 @@ public: const LocalElementOperatorType& local_operator, const XT::Common::Parameter& param = {}) : BaseType() - , source_space_(source_space) - , range_space_(range_space) + , source_space_(source_space.copy()) + , range_space_(range_space.copy()) , matrix_(matrix) , source_vector_(source_vector) - , local_op_(local_operator.copy()) , param_(param) , scaling_(param_.has_key("matrixoperator.scaling") ? param_.get("matrixoperator.scaling").at(0) : 1.) , eps_(param_.has_key("finite-difference-jacobians.eps") ? param_.get("finite-difference-jacobians.eps").at(0) : 1e-7) - , source_(source_space_) // This is a full vector, and intended! - , range_(range_space_) // This is a full vector, and intended! + , source_(*source_space_) // This is a full vector, and intended! + , range_(*range_space_) // This is a full vector, and intended! , local_source_(source_.local_discrete_function()) , local_range_(range_.local_discrete_function()) + , local_op_(local_operator.with_source(source_)) { source_.dofs().vector() = source_vector_; } LocalElementOperatorFiniteDifferenceJacobianAssembler(const ThisType& other) : BaseType(other) - , source_space_(other.source_space_) - , range_space_(other.range_space_) + , source_space_(other.source_space_->copy()) + , range_space_(other.range_space_->copy()) , matrix_(other.matrix_) , source_vector_(other.source_vector_) - , local_op_(other.local_op_->copy()) , param_(other.param_) , scaling_(other.scaling_) , eps_(other.eps_) - , source_(source_space_) // This is a full vector, and intended! - , range_(range_space_) // This is a full vector, and intended! + , source_(*source_space_) // This is a full vector, and intended! + , range_(*range_space_) // This is a full vector, and intended! , local_source_(source_.local_discrete_function()) , local_range_(range_.local_discrete_function()) + , local_op_(other.local_op_->with_source(source_)) { source_.dofs().vector() = source_vector_; } @@ -124,15 +124,15 @@ public: // some preparations local_source_->bind(element); local_range_->bind(element); - source_space_.mapper().global_indices(element, global_source_indices_); - range_space_.mapper().global_indices(element, global_range_indices_); - const size_t local_source_size = source_space_.mapper().local_size(element); - const size_t local_range_size = range_space_.mapper().local_size(element); + source_space_->mapper().global_indices(element, global_source_indices_); + range_space_->mapper().global_indices(element, global_range_indices_); + const size_t local_source_size = source_space_->mapper().local_size(element); + const size_t local_range_size = range_space_->mapper().local_size(element); if (range_DoFs_.size() < local_range_size) range_DoFs_.resize(local_range_size, 0); local_range_->dofs().set_all(0); // apply op as is, keep the result, clear local range - local_op_->apply(source_, *local_range_, param_); + local_op_->apply(*local_range_, param_); for (size_t ii = 0; ii < local_range_size; ++ii) range_DoFs_[ii] = local_range_->dofs()[ii]; local_range_->dofs().set_all(0); @@ -143,7 +143,7 @@ public: const auto eps = eps_ * (1. + std::abs(jjth_source_DoF)); local_source_->dofs()[jj] += eps; // apply op with perturbed source DoF - local_op_->apply(source_, *local_range_, param_); + local_op_->apply(*local_range_, param_); // observe perturbation in range DoFs for (size_t ii = 0; ii < local_range_size; ++ii) { auto derivative = (local_range_->dofs()[ii] - range_DoFs_[ii]) / eps; @@ -157,11 +157,10 @@ public: } // ... apply_local(...) private: - const SourceSpaceType& source_space_; - const RangeSpaceType& range_space_; + std::unique_ptr<const SourceSpaceType> source_space_; + std::unique_ptr<const RangeSpaceType> range_space_; MatrixType& matrix_; const VectorType& source_vector_; - const std::unique_ptr<LocalElementOperatorType> local_op_; const XT::Common::Parameter param_; const double scaling_; const real_t<F> eps_; @@ -172,6 +171,7 @@ private: DynamicVector<size_t> global_source_indices_; DynamicVector<size_t> global_range_indices_; DynamicVector<F> range_DoFs_; + const std::unique_ptr<LocalElementOperatorType> local_op_; }; // class LocalElementOperatorFiniteDifferenceJacobianAssembler @@ -205,7 +205,7 @@ class LocalIntersectionOperatorFiniteDifferenceJacobianAssembler : public XT::Gr static_assert(std::is_same<XT::Grid::extract_entity_t<SGV>, XT::Grid::extract_entity_t<RGV>>::value, ""); using BaseType = XT::Grid::IntersectionFunctor<SGV>; - using ThisType = LocalIntersectionOperatorFiniteDifferenceJacobianAssembler<M, SGV, s_r, s_rC, F, r_r, r_rC, RGV>; + using ThisType = LocalIntersectionOperatorFiniteDifferenceJacobianAssembler; public: using typename BaseType::ElementType; @@ -217,7 +217,7 @@ public: using V = VectorType; using LocalIntersectionOperatorType = LocalIntersectionOperatorInterface<I, V, SGV, s_r, s_rC, F, r_r, r_rC, F, RGV>; - using SourceSpaceType = typename LocalIntersectionOperatorType::SourceType::SpaceType; + using SourceSpaceType = typename LocalIntersectionOperatorType::DiscreteSourceType::SpaceType; using RangeSpaceType = typename LocalIntersectionOperatorType::LocalInsideRangeType::SpaceType; LocalIntersectionOperatorFiniteDifferenceJacobianAssembler(const SourceSpaceType& source_space, @@ -227,40 +227,40 @@ public: const LocalIntersectionOperatorType& local_operator, const XT::Common::Parameter& param = {}, const real_t<F> eps = 1e-7) - : source_space_(source_space) - , range_space_(range_space) + : source_space_(source_space.copy()) + , range_space_(range_space.copy()) , matrix_(matrix) , source_vector_(source_vector) - , local_op_(local_operator.copy()) , param_(param) , scaling_(param_.has_key("matrixoperator.scaling") ? param_.get("matrixoperator.scaling").at(0) : 1.) , eps_(eps) - , source_(source_space_) // This is a full vector, and intended! - , range_(range_space_) // This is a full vector, and intended! + , source_(*source_space_) // This is a full vector, and intended! + , range_(*range_space_) // This is a full vector, and intended! , local_source_inside_(source_.local_discrete_function()) , local_source_outside_(source_.local_discrete_function()) , local_range_inside_(range_.local_discrete_function()) , local_range_outside_(range_.local_discrete_function()) + , local_op_(local_operator.with_source(source_)) { source_.dofs().vector() = source_vector_; } LocalIntersectionOperatorFiniteDifferenceJacobianAssembler(const ThisType& other) : BaseType(other) - , source_space_(other.source_space_) - , range_space_(other.range_space_) + , source_space_(other.source_space_->copy()) + , range_space_(other.range_space_->copy()) , matrix_(other.matrix_) , source_vector_(other.source_vector_) - , local_op_(other.local_op_->copy()) , param_(other.param_) , scaling_(other.scaling_) , eps_(other.eps_) - , source_(source_space_) // This is a full vector, and intended! - , range_(range_space_) // This is a full vector, and intended! + , source_(*source_space_) // This is a full vector, and intended! + , range_(*range_space_) // This is a full vector, and intended! , local_source_inside_(source_.local_discrete_function()) , local_source_outside_(source_.local_discrete_function()) , local_range_inside_(range_.local_discrete_function()) , local_range_outside_(range_.local_discrete_function()) + , local_op_(other.local_op_->with_source(source_)) { source_.dofs().vector() = source_vector_; } @@ -276,28 +276,29 @@ public: { const bool treat_outside = intersection.neighbor(); // some preparations + local_op_->bind(intersection); local_source_inside_->bind(inside_element); local_range_inside_->bind(inside_element); - source_space_.mapper().global_indices(inside_element, global_source_indices_inside_); - range_space_.mapper().global_indices(inside_element, global_range_indices_inside_); - const size_t local_source_inside_size = source_space_.mapper().local_size(inside_element); - const size_t local_source_outside_size = treat_outside ? source_space_.mapper().local_size(outside_element) : 0; - const size_t local_range_inside_size = range_space_.mapper().local_size(inside_element); - const size_t local_range_outside_size = treat_outside ? range_space_.mapper().local_size(outside_element) : 0; + source_space_->mapper().global_indices(inside_element, global_source_indices_inside_); + range_space_->mapper().global_indices(inside_element, global_range_indices_inside_); + const size_t local_source_inside_size = source_space_->mapper().local_size(inside_element); + const size_t local_source_outside_size = treat_outside ? source_space_->mapper().local_size(outside_element) : 0; + const size_t local_range_inside_size = range_space_->mapper().local_size(inside_element); + const size_t local_range_outside_size = treat_outside ? range_space_->mapper().local_size(outside_element) : 0; if (range_DoFs_inside_.size() < local_range_inside_size) range_DoFs_inside_.resize(local_range_inside_size, 0); local_range_inside_->dofs().set_all(0); if (treat_outside) { local_source_outside_->bind(outside_element); local_range_outside_->bind(outside_element); - source_space_.mapper().global_indices(outside_element, global_source_indices_outside_); - range_space_.mapper().global_indices(outside_element, global_range_indices_outside_); + source_space_->mapper().global_indices(outside_element, global_source_indices_outside_); + range_space_->mapper().global_indices(outside_element, global_range_indices_outside_); if (range_DoFs_outside_.size() < local_range_outside_size) range_DoFs_outside_.resize(local_range_outside_size, 0); local_range_outside_->dofs().set_all(0); } // apply op as is, keep the result, clear local range - local_op_->apply(source_, intersection, *local_range_inside_, *local_range_outside_, param_); + local_op_->apply(*local_range_inside_, *local_range_outside_, param_); for (size_t ii = 0; ii < local_range_inside_size; ++ii) range_DoFs_inside_[ii] = local_range_inside_->dofs()[ii]; local_range_inside_->dofs().set_all(0); @@ -313,7 +314,7 @@ public: const auto eps = eps_ * (1. + std::abs(jjth_source_DoF)); local_source_inside_->dofs()[jj] += eps; // apply op with perturbed source DoF - local_op_->apply(source_, intersection, *local_range_inside_, *local_range_outside_, param_); + local_op_->apply(*local_range_inside_, *local_range_outside_, param_); // observe perturbation in inside range DoFs for (size_t ii = 0; ii < local_range_inside_size; ++ii) { auto derivative = (local_range_inside_->dofs()[ii] - range_DoFs_inside_[ii]) / eps; @@ -346,7 +347,7 @@ public: const auto eps = eps_ * (1. + std::abs(jjth_source_DoF)); local_source_outside_->dofs()[jj] += eps; // apply op with perturbed source DoF - local_op_->apply(source_, intersection, *local_range_inside_, *local_range_outside_, param_); + local_op_->apply(*local_range_inside_, *local_range_outside_, param_); // observe perturbation in inside range DoFs for (size_t ii = 0; ii < local_range_inside_size; ++ii) { auto derivative = (local_range_inside_->dofs()[ii] - range_DoFs_inside_[ii]) / eps; @@ -370,11 +371,10 @@ public: } // ... apply_local(...) private: - const SourceSpaceType& source_space_; - const RangeSpaceType& range_space_; + std::unique_ptr<const SourceSpaceType> source_space_; + std::unique_ptr<const RangeSpaceType> range_space_; MatrixType& matrix_; const VectorType& source_vector_; - const std::unique_ptr<LocalIntersectionOperatorType> local_op_; const XT::Common::Parameter param_; const double scaling_; const real_t<F> eps_; @@ -390,6 +390,7 @@ private: DynamicVector<size_t> global_range_indices_outside_; DynamicVector<F> range_DoFs_inside_; DynamicVector<F> range_DoFs_outside_; + const std::unique_ptr<LocalIntersectionOperatorType> local_op_; }; // class LocalIntersectionOperatorFiniteDifferenceJacobianAssembler diff --git a/dune/gdt/local/bilinear-forms/generic.hh b/dune/gdt/local/bilinear-forms/generic.hh index d75d9cf3179e2e8c9c45b7452c438b7739e643c7..79723b95686950b4871172f26d5bb8d289b78b4b 100644 --- a/dune/gdt/local/bilinear-forms/generic.hh +++ b/dune/gdt/local/bilinear-forms/generic.hh @@ -34,7 +34,7 @@ template <class E, class AR = TR> class GenericLocalElementBilinearForm : public LocalElementBilinearFormInterface<E, t_r, t_rC, TR, F, a_r, a_rC, AR> { - using ThisType = GenericLocalElementBilinearForm<E, t_r, t_rC, TR, F, a_r, a_rC, AR>; + using ThisType = GenericLocalElementBilinearForm; using BaseType = LocalElementBilinearFormInterface<E, t_r, t_rC, TR, F, a_r, a_rC, AR>; public: @@ -94,7 +94,7 @@ template <class I, class GenericLocalIntersectionBilinearForm : public LocalIntersectionBilinearFormInterface<I, t_r, t_rC, TR, F, a_r, a_rC, AR> { - using ThisType = GenericLocalIntersectionBilinearForm<I, t_r, t_rC, TR, F, a_r, a_rC, AR>; + using ThisType = GenericLocalIntersectionBilinearForm; using BaseType = LocalIntersectionBilinearFormInterface<I, t_r, t_rC, TR, F, a_r, a_rC, AR>; public: diff --git a/dune/gdt/local/bilinear-forms/integrals.hh b/dune/gdt/local/bilinear-forms/integrals.hh index 2bf67f25342bf21d85fb8a529971d78f40d3662a..72ad281eaa7d91c9bb638da5e0cca3f7cecc5954 100644 --- a/dune/gdt/local/bilinear-forms/integrals.hh +++ b/dune/gdt/local/bilinear-forms/integrals.hh @@ -36,7 +36,7 @@ template <class E, class AR = TR> class LocalElementIntegralBilinearForm : public LocalElementBilinearFormInterface<E, t_r, t_rC, TR, F, a_r, a_rC, AR> { - using ThisType = LocalElementIntegralBilinearForm<E, t_r, t_rC, TR, F, a_r, a_rC, AR>; + using ThisType = LocalElementIntegralBilinearForm; using BaseType = LocalElementBilinearFormInterface<E, t_r, t_rC, TR, F, a_r, a_rC, AR>; public: @@ -55,7 +55,7 @@ public: {} LocalElementIntegralBilinearForm(typename GenericIntegrand::GenericOrderFunctionType order_function, - typename GenericIntegrand::GenericEvalauteFunctionType evaluate_function, + typename GenericIntegrand::GenericEvaluateFunctionType evaluate_function, const XT::Common::ParameterType& param_type = {}, const int over_integrate = 0) : BaseType(param_type) @@ -132,7 +132,7 @@ template <class I, class LocalIntersectionIntegralBilinearForm : public LocalIntersectionBilinearFormInterface<I, t_r, t_rC, TR, F, a_r, a_rC, AR> { - using ThisType = LocalIntersectionIntegralBilinearForm<I, t_r, t_rC, TR, F, a_r, a_rC, AR>; + using ThisType = LocalIntersectionIntegralBilinearForm; using BaseType = LocalIntersectionBilinearFormInterface<I, t_r, t_rC, TR, F, a_r, a_rC, AR>; public: diff --git a/dune/gdt/local/bilinear-forms/interfaces.hh b/dune/gdt/local/bilinear-forms/interfaces.hh index 18f0b90a6939ac2a194d98d4b9be52f9f2146241..b65572225f3593a8734d147ed13f0c36507f9bda 100644 --- a/dune/gdt/local/bilinear-forms/interfaces.hh +++ b/dune/gdt/local/bilinear-forms/interfaces.hh @@ -172,6 +172,27 @@ public: DynamicMatrix<F>& result_out_out, const XT::Common::Parameter& param = {}) const = 0; + /** + * Variant which consideres the intersection only from the inside. + */ + virtual void apply2(const IntersectionType& intersection, + const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + DynamicMatrix<F>& result, + const XT::Common::Parameter& param = {}) const + { + this->apply2(intersection, + test_basis, + ansatz_basis, + test_basis, + ansatz_basis, + result, + unused_result_, + unused_result_, + unused_result_, + param); + } + /** * This method is provided for convenience and should not be used within library code. */ @@ -197,7 +218,23 @@ public: result_out_out, param); return {result_in_in, result_in_out, result_out_in, result_out_out}; - } // ... apply(...) + } // ... apply2(...) + + /** + * This method is provided for convenience and should not be used within library code. + */ + DynamicMatrix<F> apply2(const IntersectionType& intersection, + const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + const XT::Common::Parameter& param = {}) const + { + DynamicMatrix<F> result(test_basis.size(param), ansatz_basis.size(param), 0); + this->apply2(intersection.test_basis, ansatz_basis, param); + return result; + } + +protected: + mutable DynamicMatrix<F> unused_result_; }; // class LocalIntersectionBilinearFormInterface diff --git a/dune/gdt/local/discretefunction.hh b/dune/gdt/local/discretefunction.hh index efdf28230764bfe8d08fc981e7be8b733882f204..08653f544ac01a3114072d48234f1b94648bdbe8 100644 --- a/dune/gdt/local/discretefunction.hh +++ b/dune/gdt/local/discretefunction.hh @@ -34,7 +34,7 @@ class ConstLocalDiscreteFunction static_assert(XT::LA::is_vector<Vector>::value, ""); static_assert(range_dim_cols == 1, "The matrix-valued case requires updates to evaluate/jacobian/derivative!"); - using ThisType = ConstLocalDiscreteFunction<Vector, GridView, range_dim, range_dim_cols, RangeField>; + using ThisType = ConstLocalDiscreteFunction; using BaseType = XT::Functions:: ElementFunctionInterface<XT::Grid::extract_entity_t<GridView>, range_dim, range_dim_cols, RangeField>; @@ -63,19 +63,19 @@ public: ConstLocalDiscreteFunction(const SpaceType& spc, const ConstDofVectorType& dof_vector) : BaseType() - , space_(spc) + , space_(spc.copy()) , dof_vector_(dof_vector.localize()) - , basis_(space_.basis().localize()) - , basis_values_(space_.mapper().max_local_size()) - , dynamic_basis_values_(space_.mapper().max_local_size()) - , basis_derivatives_(space_.mapper().max_local_size()) - , dynamic_basis_derivatives_(space_.mapper().max_local_size()) + , basis_(space_->basis().localize()) + , basis_values_(space_->mapper().max_local_size()) + , dynamic_basis_values_(space_->mapper().max_local_size()) + , basis_derivatives_(space_->mapper().max_local_size()) + , dynamic_basis_derivatives_(space_->mapper().max_local_size()) {} virtual ~ConstLocalDiscreteFunction() = default; protected: - virtual void post_bind(const ElementType& ent) override + void post_bind(const ElementType& ent) override { basis_->bind(ent); dof_vector_.bind(ent); @@ -90,7 +90,7 @@ public: const SpaceType& space() const { - return space_; + return *space_; } const LocalBasisType& basis() const @@ -119,7 +119,7 @@ public: { DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, ""); RangeReturnType result(0); - if (space_.type() == GDT::SpaceType::finite_volume) { + if (space_->type() == GDT::SpaceType::finite_volume) { for (size_t ii = 0; ii < r; ++ii) result[ii] = dof_vector_[ii]; } else { @@ -135,7 +135,7 @@ public: { DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, ""); DerivativeRangeReturnType result(0); - if (space_.type() == GDT::SpaceType::finite_volume) { + if (space_->type() == GDT::SpaceType::finite_volume) { return result; } else { basis_->jacobians(point_in_reference_element, basis_derivatives_, param); @@ -150,7 +150,7 @@ public: const XT::Common::Parameter& /*param*/ = {}) const override final { DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, ""); - DUNE_THROW_IF(space_.type() != GDT::SpaceType::finite_volume, + DUNE_THROW_IF(space_->type() != GDT::SpaceType::finite_volume, Exceptions::discrete_function_error, "arbitrary derivatives are not supported by the local finite elements!\n\n" << "alpha = " << alpha << "\n" @@ -183,7 +183,7 @@ public: DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, ""); RangeSelector::ensure_size(result); result *= 0; - if (space_.type() == GDT::SpaceType::finite_volume) { + if (space_->type() == GDT::SpaceType::finite_volume) { for (size_t ii = 0; ii < r; ++ii) result[ii] = dof_vector_[ii]; } else { @@ -200,7 +200,7 @@ public: DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, ""); DerivativeRangeSelector::ensure_size(result); result *= 0; - if (space_.type() == GDT::SpaceType::finite_volume) { + if (space_->type() == GDT::SpaceType::finite_volume) { return; } else { basis_->jacobians(point_in_reference_element, dynamic_basis_derivatives_, param); @@ -215,7 +215,7 @@ public: const XT::Common::Parameter& /*param*/ = {}) const override final { DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, ""); - DUNE_THROW_IF(space_.type() != GDT::SpaceType::finite_volume, + DUNE_THROW_IF(space_->type() != GDT::SpaceType::finite_volume, Exceptions::discrete_function_error, "arbitrary derivatives are not supported by the local finite elements!\n\n" << "alpha = " << alpha << "\n" @@ -248,7 +248,7 @@ public: { DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, ""); this->assert_correct_dims(row, col, "evaluate"); - if (space_.type() == GDT::SpaceType::finite_volume) { + if (space_->type() == GDT::SpaceType::finite_volume) { return dof_vector_[row]; } else { R result(0); @@ -266,7 +266,7 @@ public: { DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, ""); this->assert_correct_dims(row, col, "jacobian"); - if (space_.type() == GDT::SpaceType::finite_volume) { + if (space_->type() == GDT::SpaceType::finite_volume) { return 0; } else { SingleDerivativeRangeReturnType result(0); @@ -280,7 +280,7 @@ public: /// \} private: - const SpaceType& space_; + std::unique_ptr<const SpaceType> space_; ConstLocalDofVectorType dof_vector_; std::unique_ptr<LocalBasisType> basis_; mutable std::vector<RangeType> basis_values_; @@ -293,7 +293,7 @@ private: template <class V, class GV, size_t r = 1, size_t rC = 1, class R = double> class LocalDiscreteFunction : public ConstLocalDiscreteFunction<V, GV, r, rC, R> { - using ThisType = LocalDiscreteFunction<V, GV, r, rC, R>; + using ThisType = LocalDiscreteFunction; using BaseType = ConstLocalDiscreteFunction<V, GV, r, rC, R>; public: diff --git a/dune/gdt/local/dof-vector.hh b/dune/gdt/local/dof-vector.hh index e442cd65043da1c5a90d35c18393a8515fda0f3e..7b396b89b4eaa63a955df933a138a391120a4127 100644 --- a/dune/gdt/local/dof-vector.hh +++ b/dune/gdt/local/dof-vector.hh @@ -88,7 +88,7 @@ class ConstLocalDofVector , public XT::Grid::ElementBoundObject<XT::Grid::extract_entity_t<GridView>> { - using ThisType = ConstLocalDofVector<Vector, GridView, Traits>; + using ThisType = ConstLocalDofVector; using BaseType = XT::LA::VectorInterface<Traits>; public: @@ -196,7 +196,7 @@ template <class Vector, class GridView> class LocalDofVector : public ConstLocalDofVector<Vector, GridView, internal::LocalDofVectorTraits<Vector, GridView>> { - using ThisType = LocalDofVector<Vector, GridView>; + using ThisType = LocalDofVector; using BaseType = ConstLocalDofVector<Vector, GridView, internal::LocalDofVectorTraits<Vector, GridView>>; public: diff --git a/dune/gdt/local/finite-elements/0d.hh b/dune/gdt/local/finite-elements/0d.hh index 1ed5e95c97721ee76fd34178b0e1776c56437813..4cb52a01451a50ce3c53e4580098d203d5fad1d4 100644 --- a/dune/gdt/local/finite-elements/0d.hh +++ b/dune/gdt/local/finite-elements/0d.hh @@ -26,17 +26,19 @@ namespace GDT { * \sa LocalFiniteElementBasisInterface * \sa Local0dFiniteElement */ -template <class D, class R> -class Local0dFiniteElementBasis : public LocalFiniteElementBasisInterface<D, 0, R, 1> +template <class D, class R, size_t r = 1> +class Local0dFiniteElementBasis : public LocalFiniteElementBasisInterface<D, 0, R, r> { - using ThisType = Local0dFiniteElementBasis<D, R>; - using BaseType = LocalFiniteElementBasisInterface<D, 0, R, 1>; + using ThisType = Local0dFiniteElementBasis; + using BaseType = LocalFiniteElementBasisInterface<D, 0, R, r>; public: using typename BaseType::DerivativeRangeType; using typename BaseType::DomainType; using typename BaseType::RangeType; + static_assert(r == 1, "Not yet implemented for r > 1"); + Local0dFiniteElementBasis() : geometry_type_(GeometryTypes::simplex(0)) {} @@ -93,16 +95,18 @@ private: * \sa LocalFiniteElementInterpolationInterface * \sa Local0dFiniteElement */ -template <class D, class R> -class Local0dFiniteElementInterpolation : public LocalFiniteElementInterpolationInterface<D, 0, R, 1> +template <class D, class R, size_t r = 1> +class Local0dFiniteElementInterpolation : public LocalFiniteElementInterpolationInterface<D, 0, R, r> { - using ThisType = Local0dFiniteElementInterpolation<D, R>; - using BaseType = LocalFiniteElementInterpolationInterface<D, 0, R, 1>; + using ThisType = Local0dFiniteElementInterpolation; + using BaseType = LocalFiniteElementInterpolationInterface<D, 0, R, r>; public: using typename BaseType::DomainType; using typename BaseType::RangeType; + static_assert(r == 1, "Not yet implemented for r > 1"); + Local0dFiniteElementInterpolation() : geometry_type_(GeometryTypes::simplex(0)) {} @@ -149,14 +153,17 @@ private: template <class D> class Local0dFiniteElementCoefficients : public LocalFiniteElementCoefficientsInterface<D, 0> { - using ThisType = Local0dFiniteElementCoefficients<D>; + using ThisType = Local0dFiniteElementCoefficients; using BaseType = LocalFiniteElementCoefficientsInterface<D, 0>; public: - Local0dFiniteElementCoefficients() + Local0dFiniteElementCoefficients(const size_t r = 1) : geometry_type_(GeometryTypes::simplex(0)) - , local_key_(0, 0, 0) - {} + , local_keys_(r) + { + for (unsigned int ii = 0; ii < r; ++ii) + local_keys_[ii] = LocalKey(0, 0, ii); + } Local0dFiniteElementCoefficients(const ThisType& other) = default; @@ -172,18 +179,20 @@ public: size_t size() const override final { - return 1; + return local_keys_.size(); } const LocalKey& local_key(const size_t ii) const override final { - DUNE_THROW_IF(ii > 0, Exceptions::finite_element_error, "ii = " << ii << "\n size() = 1"); - return local_key_; + DUNE_THROW_IF(ii > local_keys_.size(), + Exceptions::finite_element_error, + "ii = " << ii << "\n size() = " << local_keys_.size()); + return local_keys_[ii]; } private: const GeometryType geometry_type_; - const LocalKey local_key_; + std::vector<LocalKey> local_keys_; }; // class Local0dFiniteElementCoefficients @@ -197,17 +206,17 @@ private: * \sa Local0dFiniteElementInterpolation * \sa Local0dFiniteElementCoefficients */ -template <class D, class R> -class Local0dFiniteElement : public LocalFiniteElementDefault<D, 0, R, 1> +template <class D, class R, size_t r = 1> +class Local0dFiniteElement : public LocalFiniteElementDefault<D, 0, R, r> { - using BaseType = LocalFiniteElementDefault<D, 0, R, 1>; + using BaseType = LocalFiniteElementDefault<D, 0, R, r>; public: Local0dFiniteElement() : BaseType(0, - new Local0dFiniteElementBasis<D, R>(), - new Local0dFiniteElementCoefficients<D>(), - new Local0dFiniteElementInterpolation<D, R>(), + new Local0dFiniteElementBasis<D, R, r>(), + new Local0dFiniteElementCoefficients<D>(r), + new Local0dFiniteElementInterpolation<D, R, r>(), {ReferenceElements<D, 0>::simplex().position(0, 0)}) {} }; // class Local0dFiniteElement diff --git a/dune/gdt/local/finite-elements/default.hh b/dune/gdt/local/finite-elements/default.hh index ed2b1ae5f6402341b7d807114436876223256746..afcc6eabddb5926f50eb887cc97e92fd189adc58 100644 --- a/dune/gdt/local/finite-elements/default.hh +++ b/dune/gdt/local/finite-elements/default.hh @@ -11,7 +11,10 @@ #ifndef DUNE_GDT_LOCAL_FINITE_ELEMENTS_DEFAULT_HH #define DUNE_GDT_LOCAL_FINITE_ELEMENTS_DEFAULT_HH +#include <dune/geometry/quadraturerules.hh> + #include <dune/xt/common/memory.hh> +#include <dune/xt/grid/integrals.hh> #include "interfaces.hh" @@ -25,7 +28,7 @@ namespace GDT { template <class D, size_t d, class R, size_t r, size_t rC = 1> class LocalFiniteElementDefault : public LocalFiniteElementInterface<D, d, R, r, rC> { - using ThisType = LocalFiniteElementDefault<D, d, R, r, rC>; + using ThisType = LocalFiniteElementDefault; using BaseType = LocalFiniteElementInterface<D, d, R, r, rC>; public: @@ -145,26 +148,26 @@ private: template <class D, size_t d, class R = double, size_t r = 1, size_t rC = 1> -class ThreadSafeDefaultLocalLagrangeFiniteElementFamily : public LocalFiniteElementFamilyInterface<D, d, R, r, rC> +class ThreadSafeDefaultLocalFiniteElementFamily : public LocalFiniteElementFamilyInterface<D, d, R, r, rC> { - using ThisType = ThreadSafeDefaultLocalLagrangeFiniteElementFamily<D, d, R, r, rC>; + using ThisType = ThreadSafeDefaultLocalFiniteElementFamily; using BaseType = LocalFiniteElementFamilyInterface<D, d, R, r, rC>; public: using typename BaseType::LocalFiniteElementType; - ThreadSafeDefaultLocalLagrangeFiniteElementFamily( + ThreadSafeDefaultLocalFiniteElementFamily( std::function<std::unique_ptr<LocalFiniteElementType>(const GeometryType&, const int&)> factory) : factory_(factory) {} - ThreadSafeDefaultLocalLagrangeFiniteElementFamily(const ThisType& other) + ThreadSafeDefaultLocalFiniteElementFamily(const ThisType& other) : factory_(other.factory_) { // we do not even try to create the FEs in a thread safe way, they will just be recreated when required } - ThreadSafeDefaultLocalLagrangeFiniteElementFamily(ThisType&& source) + ThreadSafeDefaultLocalFiniteElementFamily(ThisType&& source) : factory_(std::move(source.factory_)) , fes_(std::move(source.fes_)) {} @@ -179,19 +182,80 @@ public: // the FE needs to be created, we need to lock std::lock_guard<std::mutex> DXTC_UNUSED(guard)(mutex_); // and to check again if someone else created the FE while we were waiting to acquire the lock - if (fes_.count(key) == 0) { - auto dings = factory_(geometry_type, order); - fes_.insert(std::make_pair(key, std::shared_ptr<LocalFiniteElementType>(dings.release()))); - } + if (fes_.count(key) == 0) + fes_[key] = factory_(geometry_type, order); } return *fes_.at(key); } // ... get(...) private: const std::function<std::unique_ptr<LocalFiniteElementType>(const GeometryType&, const int&)> factory_; - mutable std::map<std::pair<GeometryType, int>, std::shared_ptr<LocalFiniteElementType>> fes_; + mutable std::map<std::pair<GeometryType, int>, std::unique_ptr<LocalFiniteElementType>> fes_; mutable std::mutex mutex_; -}; // class ThreadSafeDefaultLocalLagrangeFiniteElementFamily +}; // class ThreadSafeDefaultLocalFiniteElementFamily + + +template <class D, size_t d, class R, size_t r = 1> +class LocalL2FiniteElementInterpolation : public LocalFiniteElementInterpolationInterface<D, d, R, r, 1> +{ + using ThisType = LocalL2FiniteElementInterpolation; + using BaseType = LocalFiniteElementInterpolationInterface<D, d, R, r, 1>; + +public: + using typename BaseType::DomainType; + using typename BaseType::RangeType; + + using LocalBasisType = LocalFiniteElementBasisInterface<D, d, R, r, 1>; + + LocalL2FiniteElementInterpolation(const LocalBasisType& local_basis) + : local_basis_(local_basis.copy()) + {} + + LocalL2FiniteElementInterpolation(const ThisType& other) + : local_basis_(other.local_basis_->copy()) + {} + + LocalL2FiniteElementInterpolation(ThisType& source) = default; + + ThisType* copy() const override final + { + return new ThisType(*this); + } + + const GeometryType& geometry_type() const override final + { + return local_basis_->geometry_type(); + } + + size_t size() const override final + { + return local_basis_->size(); + } + + using BaseType::interpolate; + + void interpolate(const std::function<RangeType(DomainType)>& local_function, + const int order, + DynamicVector<R>& dofs) const override final + { + if (dofs.size() < this->size()) + dofs.resize(this->size()); + dofs *= 0.; + std::vector<RangeType> basis_values(local_basis_->size()); + RangeType function_value; + for (auto&& quadrature_point : QuadratureRules<D, d>::rule(this->geometry_type(), order + local_basis_->order())) { + const auto point_in_reference_element = quadrature_point.position(); + const auto quadrature_weight = quadrature_point.weight(); + local_basis_->evaluate(point_in_reference_element, basis_values); + function_value = local_function(point_in_reference_element); + for (size_t ii = 0; ii < local_basis_->size(); ++ii) + dofs[ii] = (basis_values[ii] * function_value) * quadrature_weight; + } + } // ... interpolate(...) + +private: + std::unique_ptr<LocalBasisType> local_basis_; +}; // class LocalL2FiniteElementInterpolation } // namespace GDT diff --git a/dune/gdt/local/finite-elements/flattop.hh b/dune/gdt/local/finite-elements/flattop.hh new file mode 100644 index 0000000000000000000000000000000000000000..8d7723d54a12c54235a3fae01acaca722a3c188c --- /dev/null +++ b/dune/gdt/local/finite-elements/flattop.hh @@ -0,0 +1,297 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#ifndef DUNE_GDT_LOCAL_FINITE_ELEMENTS_FLATTOP_HH +#define DUNE_GDT_LOCAL_FINITE_ELEMENTS_FLATTOP_HH + +#include <functional> + +#include <dune/gdt/exceptions.hh> + +#include "default.hh" +#include "interfaces.hh" +#include "lagrange.hh" +#include "power.hh" + +namespace Dune { +namespace GDT { + + +/** + * \sa LocalFlatTop2dCubeFiniteElement + * \sa LocalFlatTopFiniteElementFactory + */ +template <class D = double, class R = double> +class LocalFlatTop2dCubeFiniteElementBasis : public LocalFiniteElementBasisInterface<D, 2, R, 1, 1> +{ + using ThisType = LocalFlatTop2dCubeFiniteElementBasis; + using BaseType = LocalFiniteElementBasisInterface<D, 2, R, 1, 1>; + +public: + using typename BaseType::DerivativeRangeType; + using typename BaseType::DomainType; + using typename BaseType::RangeType; + + LocalFlatTop2dCubeFiniteElementBasis(const double& overlap = 0.5) + : geometry_type_(Dune::GeometryTypes::cube(2)) + { + // we cannot let L_ and R_ be members and define phi_L_ and phi_R_ in the ctor initializer list, as they will + // copy/reference broken/empty/default L_ and R_ + const auto L_ = (1. - overlap) / 2.; + const auto R_ = (1. + overlap) / 2.; + phi_L_ = [=](const D& x) { + if (x < L_) + return 1.; + else if (x > R_) + return 0.; + else + return -1. * (x / overlap) + R_ / overlap; + }; + grad_phi_L_ = [=](const D& x) { + if (x < L_) + return 0.; + else if (x > R_) + return 0.; + else + return -1. / overlap; + }; + phi_R_ = [=](const D& x) { + if (x < L_) + return 0.; + else if (x > R_) + return 1.; + else + return (x / overlap) - L_ / overlap; + }; + grad_phi_R_ = [=](const D& x) { + if (x < L_) + return 0.; + else if (x > R_) + return 0.; + else + return (1. / overlap); + }; + } // LocalFlatTop2dCubeFiniteElementBasis(...) + + LocalFlatTop2dCubeFiniteElementBasis(const ThisType& other) = default; + LocalFlatTop2dCubeFiniteElementBasis(ThisType&& source) = default; + + ThisType* copy() const override final + { + return new ThisType(*this); + } + + const GeometryType& geometry_type() const override final + { + return geometry_type_; + } + + int order() const override final + { + return 2; + } + + size_t size() const override final + { + return 4; + } + + using BaseType::evaluate; + + void evaluate(const DomainType& point_in_reference_element, std::vector<RangeType>& result) const override final + { + if (result.size() < 4) + result.resize(4); + const auto& x = point_in_reference_element[0]; + const auto& y = point_in_reference_element[1]; + // each shape function is associated with one corner, the positions of which are known on the reference element + // * shape function 0: bottom left corner + result[0] = phi_L_(x) * phi_L_(y); + // * shape function 1: bottom right corner + result[1] = phi_R_(x) * phi_L_(y); + // * shape function 2: top left corner + result[2] = phi_L_(x) * phi_R_(y); + // * shape function 3: top right corner + result[3] = phi_R_(x) * phi_R_(y); + } // ... evaluate(...) + + using BaseType::jacobian; + + void jacobian(const DomainType& point_in_reference_element, + std::vector<DerivativeRangeType>& result) const override final + { + if (result.size() < 4) + result.resize(4); + const auto& x = point_in_reference_element[0]; + const auto& y = point_in_reference_element[1]; + // * shape function 0 + result[0][0][0] = grad_phi_L_(x) * phi_L_(y); + result[0][0][1] = phi_L_(x) * grad_phi_L_(y); + // * shape function 1 + result[1][0][0] = grad_phi_R_(x) * phi_L_(y); + result[1][0][1] = phi_R_(x) * grad_phi_L_(y); + // * shape function 2 + result[2][0][0] = grad_phi_L_(x) * phi_R_(y); + result[2][0][1] = phi_L_(x) * grad_phi_R_(y); + // * shape function 3 + result[3][0][0] = grad_phi_R_(x) * phi_R_(y); + result[3][0][1] = phi_R_(x) * grad_phi_R_(y); + } // ... jacobian(...) + +private: + const GeometryType geometry_type_; + std::function<R(const D&)> phi_L_; + std::function<R(const D&)> phi_R_; + std::function<R(const D&)> grad_phi_L_; + std::function<R(const D&)> grad_phi_R_; +}; // class LocalFlatTop2dCubeFiniteElementBasis + + +template <class D = double, class R = double> +class LocalFlatTop2dCubeFiniteElement : public LocalFiniteElementDefault<D, 2, R, 1> +{ + using ThisType = LocalFlatTop2dCubeFiniteElement; + using BaseType = LocalFiniteElementDefault<D, 2, R, 1>; + +public: + LocalFlatTop2dCubeFiniteElement(const double& overlap = 0.5) + : BaseType( + 1, + LocalFlatTop2dCubeFiniteElementBasis<D, R>(overlap).copy(), + LocalLagrangeFiniteElementFactory<D, 2, R, 1>::create(Dune::GeometryTypes::cube(2), 1)->coefficients().copy(), + LocalL2FiniteElementInterpolation<D, 2, R, 1>(LocalFlatTop2dCubeFiniteElementBasis<D, R>(overlap)).copy(), + {}) + {} +}; // class LocalFlatTop2dCubeFiniteElement + + +template <class D, size_t d, class R, size_t r = 1> +class LocalFlatTopFiniteElementFactory +{ + using ScalarLocalFiniteElementType = LocalFiniteElementInterface<D, d, R, 1>; + +public: + using LocalFiniteElementType = LocalFiniteElementInterface<D, d, R, r>; + +private: + static std::string order_error(const GeometryType& geometry_type, const int order) + { + std::stringstream ss; + ss << "when creating a local FlatTop finite element: the FlatTopLocalFiniteElement is known to fail in " << d + << "d on a " << geometry_type << " reference element for order " << order + << " (if you think it is working, update this check)!"; + return ss.str(); + } + + static std::string geometry_error(const GeometryType& geometry_type, const int order) + { + std::stringstream ss; + ss << "when creating a local FlatTop finite element: this is untested!\n" + << "Please update this check if you believe that FlatTopLocalFiniteElement is available for\n- dimension: " << d + << "\n- geometry_type: " << geometry_type << "\n- order: " << order; + return ss.str(); + } + + // Fist we create the scalar FE ... + + template <size_t d_ = d, bool anything = true> + struct scalar_helper + { + static std::unique_ptr<ScalarLocalFiniteElementType> + create(const GeometryType& geometry_type, const int& order, const D& overlap = 0.5) + { + DUNE_THROW_IF(geometry_type.dim() != d, + Exceptions::finite_element_error, + "geometry_type = " << geometry_type << "\nd = " << d); + // checks + if (d == 2) { + if (geometry_type == GeometryTypes::cube(2)) + DUNE_THROW_IF(order != 1, Exceptions::finite_element_error, order_error(geometry_type, order)); + else + DUNE_THROW(Exceptions::finite_element_error, geometry_error(geometry_type, order)); + } else + DUNE_THROW(Exceptions::finite_element_error, geometry_error(geometry_type, order)); + // the actual finite element + return std::unique_ptr<LocalFiniteElementInterface<D, d, R, 1>>( + new LocalFlatTop2dCubeFiniteElement<D, R>(overlap)); + } + }; // helper<...> + + template <bool anything> + struct scalar_helper<0, anything> + { + static std::unique_ptr<ScalarLocalFiniteElementType> + create(const GeometryType& geometry_type, const int& /*order*/, const D& /*overlap*/ = 0.5) + { + // If we need this, and geometry_type.dim() == 0, we must simply implement the corresponding ctors of the 0d FE! + DUNE_THROW_IF( + geometry_type.dim() != 0 || !geometry_type.isSimplex(), + Exceptions::finite_element_error, + "when creating a local 0d orthonomal finite element: not available for geometry_type = " << geometry_type); + return std::make_unique<Local0dFiniteElement<D, R>>(); + } + }; // helper<...> + + // ... then we wrap this in a power FE, if required. + + template <size_t d_ = d, size_t r_ = r> + struct helper // r != 1 + { + static std::unique_ptr<LocalFiniteElementType> + create(const GeometryType& geometry_type, const int& order, const D& overlap = 0.5) + { + return make_local_powered_finite_element<r>(*scalar_helper<>::create(geometry_type, order, overlap)); + } + }; + + template <size_t d_> + struct helper<d_, 1> + { + static std::unique_ptr<LocalFiniteElementType> + create(const GeometryType& geometry_type, const int& order, const D& overlap = 0.5) + { + return scalar_helper<>::create(geometry_type, order, overlap); + } + }; + +public: + static std::unique_ptr<LocalFiniteElementInterface<D, d, R, r>> + create(const GeometryType& geometry_type, const int& order, const D& overlap = 0.5) + { + return helper<>::create(geometry_type, order, overlap); + } +}; // class LocalFlatTopFiniteElementFactory + + +template <class D, size_t d, class R, size_t r = 1> +std::unique_ptr<LocalFiniteElementInterface<D, d, R, r>> +make_local_flattop_finite_element(const GeometryType& geometry_type, const int order, const D& overlap = 0.5) +{ + return LocalFlatTopFiniteElementFactory<D, d, R, r>::create(geometry_type, order, overlap); +} + + +template <class D, size_t d, class R, size_t r = 1> +class LocalFlatTopFiniteElementFamily : public ThreadSafeDefaultLocalFiniteElementFamily<D, d, R, r> +{ + using BaseType = ThreadSafeDefaultLocalFiniteElementFamily<D, d, R, r>; + +public: + LocalFlatTopFiniteElementFamily(const D& overlap = 0.5) + : BaseType([=](const auto& geometry_type, const auto& order) { + return LocalFlatTopFiniteElementFactory<D, d, R, r>::create(geometry_type, order, overlap); + }) + {} +}; // ... LocalFlatTopFiniteElementFamily(...) + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_LOCAL_FINITE_ELEMENTS_FLATTOP_HH diff --git a/dune/gdt/local/finite-elements/interfaces.hh b/dune/gdt/local/finite-elements/interfaces.hh index fff008196bf0751bc3f19954775599282dc467ba..09a890c5d1e1135f2a32265e7e167a9c53983ed5 100644 --- a/dune/gdt/local/finite-elements/interfaces.hh +++ b/dune/gdt/local/finite-elements/interfaces.hh @@ -42,7 +42,7 @@ class LocalDofVector; template <class DomainField, size_t domain_dim, class RangeField, size_t range_dim, size_t range_dim_columns = 1> class LocalFiniteElementBasisInterface { - using ThisType = LocalFiniteElementBasisInterface<DomainField, domain_dim, RangeField, range_dim, range_dim_columns>; + using ThisType = LocalFiniteElementBasisInterface; public: using D = DomainField; @@ -154,7 +154,7 @@ private: template <class DomainField, size_t domain_dim> class LocalFiniteElementCoefficientsInterface { - using ThisType = LocalFiniteElementCoefficientsInterface<DomainField, domain_dim>; + using ThisType = LocalFiniteElementCoefficientsInterface; public: using D = DomainField; diff --git a/dune/gdt/local/finite-elements/lagrange.hh b/dune/gdt/local/finite-elements/lagrange.hh index e575ddda9d24d78afbb4a31dd61d0d2f7f5c3ffe..3381f710564ebb3105c545f4b8d25f4c2886a775 100644 --- a/dune/gdt/local/finite-elements/lagrange.hh +++ b/dune/gdt/local/finite-elements/lagrange.hh @@ -36,16 +36,16 @@ namespace GDT { /** * Wraps the P0LocalFiniteElement from dune-localfunctions and adds Lagrange points. */ -template <class D, size_t d, class R> +template <class D, size_t d, class R, size_t r = 1> class LocalZeroOrderLagrangeFiniteElement - : XT::Common::ConstStorageProvider<LocalFiniteElementWrapper<P0LocalFiniteElement<D, R, d>, D, d, R, 1>> - , public LocalFiniteElementDefault<D, d, R, 1> + : XT::Common::ConstStorageProvider<LocalFiniteElementWrapper<P0LocalFiniteElement<D, R, d>, D, d, R, r>> + , public LocalFiniteElementDefault<D, d, R, r> { - using ThisType = LocalZeroOrderLagrangeFiniteElement<D, d, R>; + using ThisType = LocalZeroOrderLagrangeFiniteElement; using Implementation = P0LocalFiniteElement<D, R, d>; - using Wrapper = LocalFiniteElementWrapper<Implementation, D, d, R, 1>; + using Wrapper = LocalFiniteElementWrapper<Implementation, D, d, R, r>; using Storage = XT::Common::ConstStorageProvider<Wrapper>; - using BaseType = LocalFiniteElementDefault<D, d, R, 1>; + using BaseType = LocalFiniteElementDefault<D, d, R, r>; public: LocalZeroOrderLagrangeFiniteElement(const GeometryType& geometry_type) @@ -195,9 +195,9 @@ make_local_lagrange_finite_element(const GeometryType& geometry_type, const int template <class D, size_t d, class R, size_t r = 1> -class LocalLagrangeFiniteElementFamily : public ThreadSafeDefaultLocalLagrangeFiniteElementFamily<D, d, R, r> +class LocalLagrangeFiniteElementFamily : public ThreadSafeDefaultLocalFiniteElementFamily<D, d, R, r> { - using BaseType = ThreadSafeDefaultLocalLagrangeFiniteElementFamily<D, d, R, r>; + using BaseType = ThreadSafeDefaultLocalFiniteElementFamily<D, d, R, r>; public: LocalLagrangeFiniteElementFamily() diff --git a/dune/gdt/local/finite-elements/power.hh b/dune/gdt/local/finite-elements/power.hh index ed6d1bfa80f0eeef159d9624c7d1379e61c1db85..506415ad740a7b35ed57440caaad1698ecb6efb2 100644 --- a/dune/gdt/local/finite-elements/power.hh +++ b/dune/gdt/local/finite-elements/power.hh @@ -48,7 +48,7 @@ class LocalPowerFiniteElementBasis template <size_t power, class D, size_t d, class R, size_t r> class LocalPowerFiniteElementBasis<power, D, d, R, r, 1> : public LocalFiniteElementBasisInterface<D, d, R, power * r> { - using ThisType = LocalPowerFiniteElementBasis<power, D, d, R, r, 1>; + using ThisType = LocalPowerFiniteElementBasis; using BaseType = LocalFiniteElementBasisInterface<D, d, R, power * r>; public: @@ -149,7 +149,7 @@ template <size_t power, class D, size_t d, class R, size_t r> class LocalPowerFiniteElementInterpolation<power, D, d, R, r, 1> : public LocalFiniteElementInterpolationInterface<D, d, R, power * r, 1> { - using ThisType = LocalPowerFiniteElementInterpolation<power, D, d, R, r, 1>; + using ThisType = LocalPowerFiniteElementInterpolation; using BaseType = LocalFiniteElementInterpolationInterface<D, d, R, power * r, 1>; public: @@ -193,10 +193,17 @@ public: const size_t sz = this->size(); if (dofs.size() < sz) dofs.resize(sz); + eval_cache_.clear(); for (size_t pp = 0; pp < power; ++pp) { unpowered_->interpolate( [&](const auto& point_in_reference_element) { - const auto tmp = local_function(point_in_reference_element); + auto cache_it = eval_cache_.find(point_in_reference_element); + if (cache_it == eval_cache_.end()) + cache_it = + eval_cache_ + .insert(std::make_pair(point_in_reference_element, local_function(point_in_reference_element))) + .first; + const RangeType& tmp = cache_it->second; FieldVector<R, r> ret; for (size_t rr = 0; rr < r; ++rr) ret[rr] = tmp[pp * r + rr]; @@ -213,6 +220,7 @@ public: private: const std::unique_ptr<const UnpoweredType> unpowered_; mutable DynamicVector<R> unpowered_dofs_; + mutable std::map<DomainType, RangeType, XT::Common::FieldVectorLess> eval_cache_; }; // class LocalPowerFiniteElementInterpolation @@ -227,7 +235,7 @@ private: template <class D, size_t d> class LocalPowerFiniteElementCoefficients : public LocalFiniteElementCoefficientsInterface<D, d> { - using ThisType = LocalPowerFiniteElementCoefficients<D, d>; + using ThisType = LocalPowerFiniteElementCoefficients; using BaseType = LocalFiniteElementCoefficientsInterface<D, d>; public: @@ -309,7 +317,7 @@ class LocalPowerFiniteElement template <class D, size_t d, class R, size_t r, size_t rC> class LocalPowerFiniteElement<1, D, d, R, r, rC> : public LocalFiniteElementDefault<D, d, R, r, rC> { - using ThisType = LocalPowerFiniteElement<1, D, d, R, r, rC>; + using ThisType = LocalPowerFiniteElement; using BaseType = LocalFiniteElementDefault<D, d, R, r, rC>; public: @@ -331,7 +339,7 @@ public: template <size_t power, class D, size_t d, class R, size_t r> class LocalPowerFiniteElement<power, D, d, R, r, 1> : public LocalFiniteElementDefault<D, d, R, power * r> { - using ThisType = LocalPowerFiniteElement<power, D, d, R, r, 1>; + using ThisType = LocalPowerFiniteElement; using BaseType = LocalFiniteElementDefault<D, d, R, power * r>; public: diff --git a/dune/gdt/local/finite-elements/raviart-thomas.hh b/dune/gdt/local/finite-elements/raviart-thomas.hh index 244a502b616e77e41a8e87caabba91445a28d389..fbd8179c0ef00e5ec5c1f2e784a81e47b6f53f42 100644 --- a/dune/gdt/local/finite-elements/raviart-thomas.hh +++ b/dune/gdt/local/finite-elements/raviart-thomas.hh @@ -41,7 +41,7 @@ namespace GDT { template <class D, size_t d, class R> class LocalRaviartThomasInterpolation : public LocalFiniteElementInterpolationInterface<D, d, R, d, 1> { - using ThisType = LocalRaviartThomasInterpolation<D, d, R>; + using ThisType = LocalRaviartThomasInterpolation; using BaseType = LocalFiniteElementInterpolationInterface<D, d, R, d, 1>; public: @@ -353,13 +353,16 @@ make_local_raviart_thomas_finite_element(const GeometryType& geometry_type, cons template <class D, size_t d, class R> -class LocalRaviartThomasFiniteElementFamily : public ThreadSafeDefaultLocalLagrangeFiniteElementFamily<D, d, R, d, 1> +class LocalRaviartThomasFiniteElementFamily : public ThreadSafeDefaultLocalFiniteElementFamily<D, d, R, d, 1> { - using BaseType = ThreadSafeDefaultLocalLagrangeFiniteElementFamily<D, d, R, d, 1>; + using BaseType = ThreadSafeDefaultLocalFiniteElementFamily<D, d, R, d, 1>; public: LocalRaviartThomasFiniteElementFamily() : BaseType([](const auto& geometry_type, const auto& order) { + // Can't figure out why this lock is needed, but for some reasons without it we are not thread-safe + static std::mutex mutex; + std::lock_guard<std::mutex> DXTC_UNUSED(guard)(mutex); return LocalRaviartThomasFiniteElementFactory<D, d, R>::create(geometry_type, order); }) {} diff --git a/dune/gdt/local/finite-elements/wrapper.hh b/dune/gdt/local/finite-elements/wrapper.hh index 5f0abfee1dcaa157de6a1fc9bdfe47af0b5f8986..72415f1a7a885ab37cf7796ba4bfcc79bacc1d62 100644 --- a/dune/gdt/local/finite-elements/wrapper.hh +++ b/dune/gdt/local/finite-elements/wrapper.hh @@ -81,7 +81,7 @@ public: template <class Implementation, class D, size_t d, class R, size_t r, size_t rC = 1> class LocalFiniteElementBasisWrapper : public LocalFiniteElementBasisInterface<D, d, R, r, rC> { - using ThisType = LocalFiniteElementBasisWrapper<Implementation, D, d, R, r, rC>; + using ThisType = LocalFiniteElementBasisWrapper; using BaseType = LocalFiniteElementBasisInterface<D, d, R, r, rC>; public: @@ -164,7 +164,7 @@ private: template <class Implementation, class D, size_t d, class R, size_t r, size_t rC = 1> class LocalFiniteElementInterpolationWrapper : public LocalFiniteElementInterpolationInterface<D, d, R, r, rC> { - using ThisType = LocalFiniteElementInterpolationWrapper<Implementation, D, d, R, r, rC>; + using ThisType = LocalFiniteElementInterpolationWrapper; using BaseType = LocalFiniteElementInterpolationInterface<D, d, R, r, rC>; template <class R_ = R, size_t r_ = r, size_t rC_ = rC> @@ -244,7 +244,8 @@ public: size_t size() const override final { - return XT::Common::numeric_cast<size_t>(imp_->size()); + assert(imp_->size() >= 0 && imp_->size() < std::numeric_limits<size_t>::max()); + return static_cast<size_t>(imp_->size()); } using BaseType::interpolate; @@ -279,7 +280,7 @@ private: template <class Implementation, class D, size_t d> class LocalFiniteElementCoefficientsWrapper : public LocalFiniteElementCoefficientsInterface<D, d> { - using ThisType = LocalFiniteElementCoefficientsWrapper<Implementation, D, d>; + using ThisType = LocalFiniteElementCoefficientsWrapper; using BaseType = LocalFiniteElementCoefficientsInterface<D, d>; public: @@ -352,7 +353,7 @@ class LocalFiniteElementWrapper : XT::Common::ConstSharedStorageProvider<Implementation> , public LocalFiniteElementDefault<D, d, R, r, rC> { - using ThisType = LocalFiniteElementWrapper<Implementation, D, d, R, r, rC>; + using ThisType = LocalFiniteElementWrapper; using ImplementationProvider = XT::Common::ConstSharedStorageProvider<Implementation>; using BaseType = LocalFiniteElementDefault<D, d, R, r, rC>; diff --git a/dune/gdt/local/functionals/integrals.hh b/dune/gdt/local/functionals/integrals.hh index 2d528c62c032b44695f425db880db73caaad1160..95b1e4cc3ee24a50a52f5bff74be04d28495f68c 100644 --- a/dune/gdt/local/functionals/integrals.hh +++ b/dune/gdt/local/functionals/integrals.hh @@ -26,7 +26,7 @@ namespace GDT { template <class E, size_t r = 1, size_t rC = 1, class R = double, class F = R> class LocalElementIntegralFunctional : public LocalElementFunctionalInterface<E, r, rC, R, F> { - using ThisType = LocalElementIntegralFunctional<E, r, rC, R, F>; + using ThisType = LocalElementIntegralFunctional; using BaseType = LocalElementFunctionalInterface<E, r, rC, R, F>; public: @@ -43,11 +43,13 @@ public: {} LocalElementIntegralFunctional(typename GenericIntegrand::GenericOrderFunctionType order_function, - typename GenericIntegrand::GenericEvalauteFunctionType evaluate_function, + typename GenericIntegrand::GenericEvaluateFunctionType evaluate_function, + typename GenericIntegrand::GenericPostBindFunctionType post_bind_function = + [](const E&) {}, const XT::Common::ParameterType& param_type = {}, const int over_integrate = 0) : BaseType(param_type) - , integrand_(GenericIntegrand(order_function, evaluate_function).copy()) + , integrand_(GenericIntegrand(order_function, evaluate_function, post_bind_function).copy()) , over_integrate_(over_integrate) {} @@ -104,7 +106,7 @@ private: template <class I, size_t r = 1, size_t rC = 1, class R = double, class F = R> class LocalIntersectionIntegralFunctional : public LocalIntersectionFunctionalInterface<I, r, rC, R, F> { - using ThisType = LocalIntersectionIntegralFunctional<I, r, rC, R, F>; + using ThisType = LocalIntersectionIntegralFunctional; using BaseType = LocalIntersectionFunctionalInterface<I, r, rC, R, F>; public: @@ -122,11 +124,13 @@ public: {} LocalIntersectionIntegralFunctional(typename GenericIntegrand::GenericOrderFunctionType order_function, - typename GenericIntegrand::GenericEvalauteFunctionType evaluate_function, + typename GenericIntegrand::GenericEvaluateFunctionType evaluate_function, + typename GenericIntegrand::GenericPostBindFunctionType post_bind_function = + [](const I&) {}, const XT::Common::ParameterType& param_type = {}, const int over_integrate = 0) : BaseType(param_type) - , integrand_(GenericIntegrand(order_function, evaluate_function).copy()) + , integrand_(GenericIntegrand(order_function, evaluate_function, post_bind_function).copy()) , over_integrate_(over_integrate) {} diff --git a/dune/gdt/local/functionals/interfaces.hh b/dune/gdt/local/functionals/interfaces.hh index e01512b1a0050ebb29acb44cf679d3498acb6686..a9cb21a8202f916a25cc3fdebeb048d8a7902fc7 100644 --- a/dune/gdt/local/functionals/interfaces.hh +++ b/dune/gdt/local/functionals/interfaces.hh @@ -41,7 +41,7 @@ class LocalElementFunctionalInterface : public XT::Common::ParametricInterface { static_assert(XT::Grid::is_entity<Element>::value, ""); - using ThisType = LocalElementFunctionalInterface<Element, range_dim, range_dim_cols, RangeField>; + using ThisType = LocalElementFunctionalInterface; public: using E = Element; @@ -100,7 +100,7 @@ class LocalIntersectionFunctionalInterface : public XT::Common::ParametricInterf { static_assert(XT::Grid::is_intersection<Intersection>::value, ""); - using ThisType = LocalIntersectionFunctionalInterface<Intersection, range_dim, range_dim_cols, RangeField>; + using ThisType = LocalIntersectionFunctionalInterface; public: using IntersectionType = Intersection; diff --git a/dune/gdt/local/integrands/abs.hh b/dune/gdt/local/integrands/abs.hh index 970c2c3ae41bbb4b944b0741df4658c53fe6bfac..e09794fb5cf37557f9879e35356c8ee54645b233 100644 --- a/dune/gdt/local/integrands/abs.hh +++ b/dune/gdt/local/integrands/abs.hh @@ -23,7 +23,7 @@ template <class E, size_t r = 1, size_t rC = 1, class R = double, class F = doub class LocalElementAbsIntegrand : public LocalUnaryElementIntegrandInterface<E, r, rC, R, F> { static_assert(rC == 1, ""); - using ThisType = LocalElementAbsIntegrand<E, r, rC, R, F>; + using ThisType = LocalElementAbsIntegrand; using BaseType = LocalUnaryElementIntegrandInterface<E, r, rC, R, F>; public: diff --git a/dune/gdt/local/integrands/combined.hh b/dune/gdt/local/integrands/combined.hh new file mode 100644 index 0000000000000000000000000000000000000000..4d0ae1f71b44e5c9878f377a2bc95861ca88774b --- /dev/null +++ b/dune/gdt/local/integrands/combined.hh @@ -0,0 +1,379 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#ifndef DUNE_GDT_LOCAL_INTEGRANDS_COMBINED_HH +#define DUNE_GDT_LOCAL_INTEGRANDS_COMBINED_HH + +#include <dune/xt/common/memory.hh> + +#include "interfaces.hh" + +namespace Dune { +namespace GDT { + + +/// \todo add LocalUnaryElementIntegrandSum +/// \todo add operator+ to LocalUnaryElementIntegrandInterface +/// \sa LocalQuaternaryIntersectionIntegrandSum +// template <class E, size_t r, size_t rC, class R, class F> +// class LocalUnaryElementIntegrandSum +// : public XT::Common::ParametricInterface +// , public XT::Grid::ElementBoundObject<Element> +//{ +// static_assert(XT::Grid::is_entity<Element>::value, ""); + +// using ThisType = LocalUnaryElementIntegrandInterface; + +// public: +// using E = Element; +// using D = typename Element::Geometry::ctype; +// static const constexpr size_t d = E::dimension; +// using F = Field; + +// using R = RangeField; +// static const constexpr size_t r = range_dim; +// static const constexpr size_t rC = range_dim_cols; + +// using typename XT::Grid::ElementBoundObject<Element>::ElementType; +// using DomainType = FieldVector<D, d>; +// using LocalBasisType = XT::Functions::ElementFunctionSetInterface<E, r, rC, R>; + +// LocalUnaryElementIntegrandInterface(const XT::Common::ParameterType& param_type = {}) +// : XT::Common::ParametricInterface(param_type) +// {} + +// virtual ~LocalUnaryElementIntegrandInterface() = default; + +// virtual std::unique_ptr<ThisType> copy() const = 0; + +// protected: +// virtual void post_bind(const IntersectionType& intrsctn) = 0; + +// public: + +// /** +// * Returns the polynomial order of the integrand, given the basis. +// * +// * \note Will throw Exceptions::not_bound_to_an_element_yet error if not bound yet! +// **/ +// virtual int order(const LocalBasisType& basis, const XT::Common::Parameter& param = {}) const = 0; + +// /** +// * Computes the evaluation of this integrand at the given point for each function in the basis. +// * +// * \note Will throw Exceptions::not_bound_to_an_element_yet error if not bound yet! +// **/ +// virtual void evaluate(const LocalBasisType& basis, +// const DomainType& point_in_reference_element, +// DynamicVector<F>& result, +// const XT::Common::Parameter& param = {}) const = 0; + +// /** +// * This method is provided for convenience and should not be used within library code. +// * +// * \note Will throw Exceptions::not_bound_to_an_element_yet error if not bound yet! +// **/ +// virtual DynamicVector<F> evaluate(const LocalBasisType& basis, +// const DomainType& point_in_reference_element, +// const XT::Common::Parameter& param = {}) const +// { +// DynamicVector<F> result(basis.size(param)); +// evaluate(basis, point_in_reference_element, result, param); +// return result; +// } +//}; // class LocalUnaryElementIntegrandSum + + +/// \todo add LocalBinaryElementIntegrandSum +/// \todo add operator+ to LocalBinaryElementIntegrandInterface +/// \sa LocalQuaternaryIntersectionIntegrandSum +// template <class E, size_t t_r, size_t t_RC, class TF, class F, size_t a_r, size_t a_rC, class AF> +// class LocalBinaryElementIntegrandSum +// : public XT::Common::ParametricInterface +// , public XT::Grid::ElementBoundObject<Element> +//{ +// static_assert(XT::Grid::is_entity<Element>::value, ""); + +// using ThisType = LocalBinaryElementIntegrandInterface<Element, +// test_range_dim, +// test_range_dim_cols, +// TestRangeField, +// Field, +// ansatz_range_dim, +// ansatz_range_dim_cols, +// AnsatzRangeField>; + +// public: +// using E = Element; +// using D = typename Element::Geometry::ctype; +// static const constexpr size_t d = E::dimension; +// using F = Field; + +// using TR = TestRangeField; +// static const constexpr size_t t_r = test_range_dim; +// static const constexpr size_t t_rC = test_range_dim_cols; + +// using AR = AnsatzRangeField; +// static const constexpr size_t a_r = ansatz_range_dim; +// static const constexpr size_t a_rC = ansatz_range_dim_cols; + +// using typename XT::Grid::ElementBoundObject<Element>::ElementType; +// using DomainType = FieldVector<D, d>; +// using LocalTestBasisType = XT::Functions::ElementFunctionSetInterface<E, t_r, t_rC, TR>; +// using LocalAnsatzBasisType = XT::Functions::ElementFunctionSetInterface<E, a_r, a_rC, AR>; + +// LocalBinaryElementIntegrandInterface(const XT::Common::ParameterType& param_type = {}) +// : XT::Common::ParametricInterface(param_type) +// {} + +// virtual ~LocalBinaryElementIntegrandInterface() = default; + +// virtual std::unique_ptr<ThisType> copy() const = 0; + +// protected: +// virtual void post_bind(const IntersectionType& intrsctn) = 0; + +// public: +// /** +// * Returns the polynomial order of the integrand, given the bases. +// * +// * \note Will throw Exceptions::not_bound_to_an_element_yet error if not bound yet! +// **/ +// virtual int order(const LocalTestBasisType& test_basis, +// const LocalAnsatzBasisType& ansatz_basis, +// const XT::Common::Parameter& param = {}) const = 0; + +// /** +// * Computes the evaluation of this integrand at the given point for each combination of functions from the two +// bases. +// * +// * \note Will throw Exceptions::not_bound_to_an_element_yet error if not bound yet! +// **/ +// virtual void evaluate(const LocalTestBasisType& test_basis, +// const LocalAnsatzBasisType& ansatz_basis, +// const DomainType& point_in_reference_element, +// DynamicMatrix<F>& result, +// const XT::Common::Parameter& param = {}) const = 0; + +// /** +// * This method is provided for convenience and should not be used within library code. +// * +// * \note Will throw Exceptions::not_bound_to_an_element_yet error if not bound yet! +// **/ +// virtual DynamicMatrix<F> evaluate(const LocalTestBasisType& test_basis, +// const LocalAnsatzBasisType& ansatz_basis, +// const DomainType& point_in_reference_element, +// const XT::Common::Parameter& param = {}) const +// { +// DynamicMatrix<F> result(test_basis.size(param), ansatz_basis.size(param), 0); +// evaluate(test_basis, ansatz_basis, point_in_reference_element, result, param); +// return result; +// } +//}; // class LocalBinaryElementIntegrandInterface + + +/// \todo add LocalBinaryIntersectionIntegrandSum +/// \todo add operator+ to LocalBinaryIntersectionIntegrandInterface +/// \sa LocalQuaternaryIntersectionIntegrandSum +// template <class I, size_t r, size_t rC, class R, class F> +// class LocalBinaryIntersectionIntegrandSum +// : public XT::Common::ParametricInterface +// , public XT::Grid::IntersectionBoundObject<Intersection> +//{ +// static_assert(XT::Grid::is_intersection<Intersection>::value, ""); + +// using ThisType = +// LocalBinaryIntersectionIntegrandInterface<Intersection, range_dim, range_dim_cols, RangeField, Field>; + +// public: +// using typename XT::Grid::IntersectionBoundObject<Intersection>::IntersectionType; +// using ElementType = XT::Grid::extract_inside_element_t<Intersection>; + +// using I = Intersection; +// using E = ElementType; +// using D = typename ElementType::Geometry::ctype; +// static const constexpr size_t d = E::dimension; +// using F = Field; + +// using RF = RangeField; +// static const constexpr size_t r = range_dim; +// static const constexpr size_t rC = range_dim_cols; + +// using DomainType = FieldVector<D, d - 1>; +// using LocalBasisType = XT::Functions::ElementFunctionSetInterface<E, r, rC, RF>; + +// LocalBinaryIntersectionIntegrandInterface(const XT::Common::ParameterType& param_type = {}) +// : XT::Common::ParametricInterface(param_type) +// {} + +// virtual ~LocalBinaryIntersectionIntegrandInterface() = default; + +// virtual std::unique_ptr<ThisType> copy() const = 0; + +// protected: +// virtual void post_bind(const IntersectionType& intrsctn) = 0; + +// public: +// /** +// * Returns the polynomial order of the integrand, given the bases. +// * +// * \note Will throw Exceptions::not_bound_to_an_element_yet error if not bound yet! +// **/ +// virtual int order(const LocalBasisType& inside_basis, +// const LocalBasisType& outside_basis, +// const XT::Common::Parameter& param = {}) const = 0; + +// /** +// * Computes the evaluation of this integrand at the given point for each combination of functions from the two +// bases. +// * +// * \note Will throw Exceptions::not_bound_to_an_element_yet error if not bound yet! +// **/ +// virtual void evaluate(const LocalBasisType& inside_basis, +// const LocalBasisType& outside_basis, +// const DomainType& point_in_reference_element, +// DynamicMatrix<F>& result, +// const XT::Common::Parameter& param = {}) const = 0; + +// /** +// * This method is provided for convenience and should not be used within library code. +// * +// * \note Will throw Exceptions::not_bound_to_an_element_yet error if not bound yet! +// **/ +// virtual DynamicMatrix<F> evaluate(const LocalBasisType& inside_basis, +// const LocalBasisType& outside_basis, +// const DomainType& point_in_reference_element, +// const XT::Common::Parameter& param = {}) const +// { +// DynamicMatrix<F> result(inside_basis.size(param), outside_basis.size(param), 0); +// evaluate(inside_basis, inside_basis, point_in_reference_element, result, param); +// return result; +// } +//}; // class LocalBinaryIntersectionIntegrandSum + + +template <class I, size_t t_r, size_t t_rC, class TF, class F, size_t a_r, size_t a_rC, class AF> +class LocalQuaternaryIntersectionIntegrandSum + : public LocalQuaternaryIntersectionIntegrandInterface<I, t_r, t_rC, TF, F, a_r, a_rC, AF> +{ + using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I, t_r, t_rC, TF, F, a_r, a_rC, AF>; + using ThisType = LocalQuaternaryIntersectionIntegrandSum; + +public: + using typename BaseType::DomainType; + using typename BaseType::IntersectionType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::LocalTestBasisType; + + LocalQuaternaryIntersectionIntegrandSum(const BaseType& left, const BaseType& right) + : BaseType(left.parameter_type() + right.parameter_type()) + , left_(left.copy().release()) + , right_(right.copy().release()) + {} + + LocalQuaternaryIntersectionIntegrandSum(const ThisType& other) + : BaseType(other) + , left_(other.left_.access().copy().release()) + , right_(other.right_.access().copy().release()) + {} + + LocalQuaternaryIntersectionIntegrandSum(ThisType&& source) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + +protected: + void post_bind(const IntersectionType& intrsctn) override final + { + left_.access().bind(intrsctn); + right_.access().bind(intrsctn); + } + +public: + int order(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const XT::Common::Parameter& param = {}) const override final + { + return std::max( + left_.access().order(test_basis_inside, ansatz_basis_inside, test_basis_outside, ansatz_basis_outside, param), + right_.access().order(test_basis_inside, ansatz_basis_inside, test_basis_outside, ansatz_basis_outside, param)); + } + + using BaseType::evaluate; + + void evaluate(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const DomainType& point_in_reference_intersection, + DynamicMatrix<F>& result_in_in, + DynamicMatrix<F>& result_in_out, + DynamicMatrix<F>& result_out_in, + DynamicMatrix<F>& result_out_out, + const XT::Common::Parameter& param = {}) const override final + { + // Each integrand clears its storage, so we let the left one write into ... + left_.access().evaluate(test_basis_inside, + ansatz_basis_inside, + test_basis_outside, + ansatz_basis_outside, + point_in_reference_intersection, + result_in_in, + result_in_out, + result_out_in, + result_out_out, + param); + // ..., the right one into ... + right_.access().evaluate(test_basis_inside, + ansatz_basis_inside, + test_basis_outside, + ansatz_basis_outside, + point_in_reference_intersection, + result_in_in_, + result_in_out_, + result_out_in_, + result_out_out_, + param); + // ... and simply add them up (cannot use += here, matrices might be larger). + const size_t rows_in = test_basis_inside.size(param); + const size_t rows_out = test_basis_outside.size(param); + const size_t cols_in = ansatz_basis_inside.size(param); + const size_t cols_out = ansatz_basis_outside.size(param); + for (size_t ii = 0; ii < rows_in; ++ii) + for (size_t jj = 0; jj < cols_in; ++jj) + result_in_in[ii][jj] += result_in_in_[ii][jj]; + for (size_t ii = 0; ii < rows_in; ++ii) + for (size_t jj = 0; jj < cols_out; ++jj) + result_in_out[ii][jj] += result_in_out_[ii][jj]; + for (size_t ii = 0; ii < rows_out; ++ii) + for (size_t jj = 0; jj < cols_in; ++jj) + result_out_in[ii][jj] += result_out_in_[ii][jj]; + for (size_t ii = 0; ii < rows_out; ++ii) + for (size_t jj = 0; jj < cols_out; ++jj) + result_out_out[ii][jj] += result_out_out_[ii][jj]; + } // ... evaluate(...) + +private: + XT::Common::StorageProvider<BaseType> left_; + XT::Common::StorageProvider<BaseType> right_; + mutable DynamicMatrix<F> result_in_in_; + mutable DynamicMatrix<F> result_in_out_; + mutable DynamicMatrix<F> result_out_in_; + mutable DynamicMatrix<F> result_out_out_; +}; // class LocalQuaternaryIntersectionIntegrandSum + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_LOCAL_INTEGRANDS_COMBINED_HH diff --git a/dune/gdt/local/integrands/conversion.hh b/dune/gdt/local/integrands/conversion.hh index 2f1ec208c52b3c86cc1ed0d44e1624a660a97020..65dc14cfeb6dddc6c7497d20eb766182fd4cd0d4 100644 --- a/dune/gdt/local/integrands/conversion.hh +++ b/dune/gdt/local/integrands/conversion.hh @@ -39,7 +39,7 @@ template <class E, class AF = TF> class LocalBinaryToUnaryElementIntegrand : public LocalUnaryElementIntegrandInterface<E, a_r, a_rC, AF, F> { - using ThisType = LocalBinaryToUnaryElementIntegrand<E, t_r, t_rC, TF, F, a_r, a_rC, AF>; + using ThisType = LocalBinaryToUnaryElementIntegrand; using BaseType = LocalUnaryElementIntegrandInterface<E, a_r, a_rC, AF, F>; public: diff --git a/dune/gdt/local/integrands/div.hh b/dune/gdt/local/integrands/div.hh index 8c1629f6cb65b7e578f88bfe5e4b1a7801a017e3..4732224ba2298ae30d346b2fbae87d776b9bcea9 100644 --- a/dune/gdt/local/integrands/div.hh +++ b/dune/gdt/local/integrands/div.hh @@ -68,8 +68,8 @@ protected: /** - * Given an inducing function f, computes `f(x) * phi(x) * div(psi(x))` for all combinations of phi and psi in the - * bases. + * Given an inducing function f, computes `f(x) * phi(x) * div(psi(x))` for all combinations of phi in the ansatz basis + * and psi in the test basis. * * \note Note that f can also be given as a scalar value or omitted. * @@ -139,7 +139,7 @@ public: const LocalAnsatzBasisType& ansatz_basis, const XT::Common::Parameter& param = {}) const override final { - return std::max(local_function_->order(param) + test_basis.order(param) + ansatz_basis.order(param) - 1, 0); + return local_function_->order(param) + test_basis.order(param) + ansatz_basis.order(param); } using BaseType::evaluate; @@ -169,7 +169,8 @@ private: /** - * Given an inducing function f, computes `f(x) * div phi(x) * psi(x)` for all combinations of phi and psi in the bases. + * Given an inducing function f, computes `f(x) * div(phi(x)) * psi(x)` for all combinations of phi in the ansatz basis + * and psi in the test basis. * * \sa LocalElementAnsatzValueTestDivProductIntegrand */ @@ -234,7 +235,7 @@ public: const LocalAnsatzBasisType& ansatz_basis, const XT::Common::Parameter& param = {}) const override final { - return std::max(local_function_->order(param) + test_basis.order(param) + ansatz_basis.order(param) - 1 + 10, 0); + return local_function_->order(param) + test_basis.order(param) + ansatz_basis.order(param); } using BaseType::evaluate; @@ -245,14 +246,15 @@ public: DynamicMatrix<F>& result, const XT::Common::Parameter& param = {}) const override final { - DivBaseType::evaluate(test_basis, - ansatz_basis, + DivBaseType::evaluate(ansatz_basis, + test_basis, point_in_reference_element, result, param, *local_function_, ansatz_basis_jacobians_, test_basis_values_); + result = XT::Common::transposed(result); } // ... evaluate(...) private: diff --git a/dune/gdt/local/integrands/elliptic-ipdg.hh b/dune/gdt/local/integrands/elliptic-ipdg.hh index b79d79fd9266a945dda5b558192eeeb5acfb4459..edb8d2948518d9d6017dfdc12ab4116b26a5781f 100644 --- a/dune/gdt/local/integrands/elliptic-ipdg.hh +++ b/dune/gdt/local/integrands/elliptic-ipdg.hh @@ -10,16 +10,328 @@ // René Milk (2017) // Tobias Leibner (2014) +#warning This header is deprecated, use and include <dune/gdt/local/integrands/laplace-ipdg.hh> instead! + #ifndef DUNE_GDT_LOCAL_INTEGRANDS_ELLIPTIC_IPDG_HH -#define DUNE_GDT_LOCAL_INTEGRANDS_ELLIPTIC_IPDG_HH +# define DUNE_GDT_LOCAL_INTEGRANDS_ELLIPTIC_IPDG_HH -#include <dune/xt/functions/interfaces/grid-function.hh> +# include <dune/xt/common/deprecated.hh> +# include <dune/xt/functions/grid-function.hh> +# include <dune/xt/functions/interfaces/grid-function.hh> -#include "interfaces.hh" +# include "interfaces.hh" +# include "ipdg.hh" namespace Dune { namespace GDT { +/** + * \brief To replace the ones in LocalEllipticIpdgIntegrands at some point. + */ +namespace LocalEllipticIPDGIntegrands { + + +/** + * \note The role of symmetry_prefactor: + * * -1 => NIPDG + * * 0 => IIPDG + * * 1 => SIPDG + * \note The role of the weight: + * * symmetry_prefactor = 1 && weight_function = 1 => SIPDG + * * symmetry_prefactor = 1 && weight_function = diffusion => SWIPDG + */ +template <class I> +class InnerCoupling : public LocalQuaternaryIntersectionIntegrandInterface<I> +{ + using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I>; + using ThisType = InnerCoupling; + +public: + using BaseType::d; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::F; + using typename BaseType::IntersectionType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::LocalTestBasisType; + + InnerCoupling(const double& symmetry_prefactor, + XT::Functions::GridFunction<E, d, d> diffusion, + XT::Functions::GridFunction<E, d, d> weight_function = {1.}) + : BaseType(diffusion.parameter_type() + weight_function.parameter_type()) + , symmetry_prefactor_(symmetry_prefactor) + , diffusion_(diffusion) + , weight_(weight_function) + , local_diffusion_in_(diffusion_.local_function()) + , local_diffusion_out_(diffusion_.local_function()) + , local_weight_in_(weight_.local_function()) + , local_weight_out_(weight_.local_function()) + {} + + InnerCoupling(const ThisType& other) + : BaseType(other.parameter_type()) + , symmetry_prefactor_(other.symmetry_prefactor_) + , diffusion_(other.diffusion_) + , weight_(other.weight_) + , local_diffusion_in_(diffusion_.local_function()) + , local_diffusion_out_(diffusion_.local_function()) + , local_weight_in_(weight_.local_function()) + , local_weight_out_(weight_.local_function()) + {} + + InnerCoupling(ThisType&& source) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + +protected: + void post_bind(const IntersectionType& intersection) override final + { + DUNE_THROW_IF(!intersection.neighbor(), + Exceptions::integrand_error, + "This integrand cannot be used on a boundary intersection!"); + const auto inside_element = intersection.inside(); + const auto outside_element = intersection.outside(); + local_diffusion_in_->bind(inside_element); + local_weight_in_->bind(inside_element); + local_diffusion_out_->bind(outside_element); + local_weight_out_->bind(outside_element); + } // ... post_bind(...) + +public: + int order(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const XT::Common::Parameter& param = {}) const override final + { + return std::max(local_diffusion_in_->order(param), local_diffusion_out_->order(param)) + + std::max(local_weight_in_->order(), local_weight_out_->order(param)) + + std::max(test_basis_inside.order(param), test_basis_outside.order(param)) + + std::max(ansatz_basis_inside.order(param), ansatz_basis_outside.order(param)); + } + + void evaluate(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const DomainType& point_in_reference_intersection, + DynamicMatrix<F>& result_in_in, + DynamicMatrix<F>& result_in_out, + DynamicMatrix<F>& result_out_in, + DynamicMatrix<F>& result_out_out, + const XT::Common::Parameter& param = {}) const override final + { + // Prepare sotrage, ... + this->ensure_size_and_clear_results(test_basis_inside, + ansatz_basis_inside, + test_basis_outside, + ansatz_basis_outside, + result_in_in, + result_in_out, + result_out_in, + result_out_out, + param); + // evaluate ... + const auto point_in_inside_reference_element = + this->intersection().geometryInInside().global(point_in_reference_intersection); + const auto point_in_outside_reference_element = + this->intersection().geometryInOutside().global(point_in_reference_intersection); + const auto normal = this->intersection().unitOuterNormal(point_in_reference_intersection); + // ... basis functions and ... + test_basis_inside.evaluate(point_in_inside_reference_element, test_basis_in_values_, param); + test_basis_inside.jacobians(point_in_inside_reference_element, test_basis_in_grads_, param); + test_basis_outside.evaluate(point_in_outside_reference_element, test_basis_out_values_, param); + test_basis_outside.jacobians(point_in_outside_reference_element, test_basis_out_grads_, param); + ansatz_basis_inside.evaluate(point_in_inside_reference_element, ansatz_basis_in_values_, param); + ansatz_basis_inside.jacobians(point_in_inside_reference_element, ansatz_basis_in_grads_, param); + ansatz_basis_outside.evaluate(point_in_outside_reference_element, ansatz_basis_out_values_, param); + ansatz_basis_outside.jacobians(point_in_outside_reference_element, ansatz_basis_out_grads_, param); + // ... data functions, ... + const auto diffusion_in = local_diffusion_in_->evaluate(point_in_inside_reference_element, param); + const auto diffusion_out = local_diffusion_out_->evaluate(point_in_outside_reference_element, param); + const auto weight_in = local_weight_in_->evaluate(point_in_inside_reference_element, param); + const auto weight_out = local_weight_out_->evaluate(point_in_outside_reference_element, param); + // compute the weighted mean ... + const auto delta_plus = normal * (weight_out * normal); + const auto delta_minus = normal * (weight_in * normal); + const auto weight_minus = delta_plus / (delta_plus + delta_minus); + const auto weight_plus = delta_minus / (delta_plus + delta_minus); + // ... and finally compute the integrand. + const size_t rows_in = test_basis_inside.size(param); + const size_t rows_out = test_basis_outside.size(param); + const size_t cols_in = ansatz_basis_inside.size(param); + const size_t cols_out = ansatz_basis_outside.size(param); + for (size_t ii = 0; ii < rows_in; ++ii) { + for (size_t jj = 0; jj < cols_in; ++jj) { + result_in_in[ii][jj] += + -1.0 * weight_minus * ((diffusion_in * ansatz_basis_in_grads_[jj][0]) * normal) * test_basis_in_values_[ii]; + result_in_in[ii][jj] += -1.0 * symmetry_prefactor_ * weight_minus * ansatz_basis_in_values_[jj] + * ((diffusion_in * test_basis_in_grads_[ii][0]) * normal); + } + for (size_t jj = 0; jj < cols_out; ++jj) { + result_in_out[ii][jj] += -1.0 * weight_plus * ((diffusion_out * ansatz_basis_out_grads_[jj][0]) * normal) + * test_basis_in_values_[ii]; + result_in_out[ii][jj] += symmetry_prefactor_ * weight_minus * ansatz_basis_out_values_[jj] + * ((diffusion_in * test_basis_in_grads_[ii][0]) * normal); + } + } + for (size_t ii = 0; ii < rows_out; ++ii) { + for (size_t jj = 0; jj < cols_in; ++jj) { + result_out_in[ii][jj] += + weight_minus * ((diffusion_in * ansatz_basis_in_grads_[jj][0]) * normal) * test_basis_out_values_[ii]; + result_out_in[ii][jj] += -1.0 * symmetry_prefactor_ * weight_plus * ansatz_basis_in_values_[jj] + * ((diffusion_out * test_basis_out_grads_[ii][0]) * normal); + } + for (size_t jj = 0; jj < cols_out; ++jj) { + result_out_out[ii][jj] += + weight_plus * ((diffusion_out * ansatz_basis_out_grads_[jj][0]) * normal) * test_basis_out_values_[ii]; + result_out_out[ii][jj] += symmetry_prefactor_ * weight_plus * ansatz_basis_out_values_[jj] + * ((diffusion_out * test_basis_out_grads_[ii][0]) * normal); + } + } + } // ... evaluate(...) + +private: + const double symmetry_prefactor_; + XT::Functions::GridFunction<E, d, d> diffusion_; + XT::Functions::GridFunction<E, d, d> weight_; + std::unique_ptr<typename XT::Functions::GridFunctionInterface<E, d, d>::LocalFunctionType> local_diffusion_in_; + std::unique_ptr<typename XT::Functions::GridFunctionInterface<E, d, d>::LocalFunctionType> local_diffusion_out_; + std::unique_ptr<typename XT::Functions::GridFunctionInterface<E, d, d>::LocalFunctionType> local_weight_in_; + std::unique_ptr<typename XT::Functions::GridFunctionInterface<E, d, d>::LocalFunctionType> local_weight_out_; + mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_in_values_; + mutable std::vector<typename LocalTestBasisType::DerivativeRangeType> test_basis_in_grads_; + mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_out_values_; + mutable std::vector<typename LocalTestBasisType::DerivativeRangeType> test_basis_out_grads_; + mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_in_values_; + mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> ansatz_basis_in_grads_; + mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_out_values_; + mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> ansatz_basis_out_grads_; +}; // InnerCoupling + + +/** + * \note The role of symmetry_prefactor: + * * -1 => NIPDG + * * 0 => IIPDG + * * 1 => SIPDG + * \note The role of the weight: + * * symmetry_prefactor = 1 && weight_function = 1 => SIPDG + * * symmetry_prefactor = 1 && weight_function = diffusion => SWIPDG + */ +template <class I> +class DirichletCoupling : public LocalQuaternaryIntersectionIntegrandInterface<I> +{ + using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I>; + using ThisType = DirichletCoupling; + +public: + using BaseType::d; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::F; + using typename BaseType::IntersectionType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::LocalTestBasisType; + + DirichletCoupling(const double& symmetry_prefactor, XT::Functions::GridFunction<E, d, d> diffusion) + : BaseType(diffusion.parameter_type()) + , symmetry_prefactor_(symmetry_prefactor) + , diffusion_(diffusion) + , local_diffusion_(diffusion_.local_function()) + {} + + DirichletCoupling(const ThisType& other) + : BaseType(other.parameter_type()) + , symmetry_prefactor_(other.symmetry_prefactor_) + , diffusion_(other.diffusion_) + , local_diffusion_(diffusion_.local_function()) + {} + + DirichletCoupling(ThisType&& source) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + +protected: + void post_bind(const IntersectionType& intersection) override final + { + const auto inside_element = intersection.inside(); + local_diffusion_->bind(inside_element); + } + +public: + int order(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& /*test_basis_outside*/, + const LocalAnsatzBasisType& /*ansatz_basis_outside*/, + const XT::Common::Parameter& param = {}) const override final + { + return local_diffusion_->order(param) + test_basis_inside.order(param) + ansatz_basis_inside.order(param); + } + + void evaluate(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const DomainType& point_in_reference_intersection, + DynamicMatrix<F>& result_in_in, + DynamicMatrix<F>& result_in_out, + DynamicMatrix<F>& result_out_in, + DynamicMatrix<F>& result_out_out, + const XT::Common::Parameter& param = {}) const override final + { + // Prepare sotrage, ... + this->ensure_size_and_clear_results(test_basis_inside, + ansatz_basis_inside, + test_basis_outside, + ansatz_basis_outside, + result_in_in, + result_in_out, + result_out_in, + result_out_out, + param); + // evaluate ... + const auto point_in_inside_reference_element = + this->intersection().geometryInInside().global(point_in_reference_intersection); + const auto normal = this->intersection().unitOuterNormal(point_in_reference_intersection); + // ... basis functions and ... + test_basis_inside.evaluate(point_in_inside_reference_element, test_basis_values_, param); + test_basis_inside.jacobians(point_in_inside_reference_element, test_basis_grads_, param); + ansatz_basis_inside.evaluate(point_in_inside_reference_element, ansatz_basis_values_, param); + ansatz_basis_inside.jacobians(point_in_inside_reference_element, ansatz_basis_grads_, param); + // ... data functions, ... + const auto diffusion = local_diffusion_->evaluate(point_in_inside_reference_element, param); + // ... and finally compute the integrand. + const size_t rows = test_basis_inside.size(param); + const size_t cols = ansatz_basis_inside.size(param); + for (size_t ii = 0; ii < rows; ++ii) + for (size_t jj = 0; jj < cols; ++jj) { + result_in_in[ii][jj] += -1.0 * ((diffusion * ansatz_basis_grads_[jj][0]) * normal) * test_basis_values_[ii]; + result_in_in[ii][jj] += + -1.0 * symmetry_prefactor_ * ansatz_basis_values_[jj] * ((diffusion * test_basis_grads_[ii][0]) * normal); + } + } // ... evaluate(...) + +private: + const double symmetry_prefactor_; + XT::Functions::GridFunction<E, d, d> diffusion_; + std::unique_ptr<typename XT::Functions::GridFunctionInterface<E, d, d>::LocalFunctionType> local_diffusion_; + mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_values_; + mutable std::vector<typename LocalTestBasisType::DerivativeRangeType> test_basis_grads_; + mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_values_; + mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> ansatz_basis_grads_; +}; // DirichletCoupling + + +} // namespace LocalEllipticIPDGIntegrands + + /** * \brief Contains local integrands for the family of interior penalty discontinuous Galerkin (IPDG) * discretization schemes. @@ -32,7 +344,7 @@ namespace GDT { namespace LocalEllipticIpdgIntegrands { -enum class Method +enum class DXT_DEPRECATED_MSG("Use the LocalLaplaceIPDGIntegrands instead (10.08.2019)!") Method { ipdg, nipdg, @@ -132,6 +444,7 @@ namespace internal { /** * \note see Epshteyn, Riviere, 2007 */ +DXT_DEPRECATED_MSG("Use the LocalLaplaceIPDGIntegrands instead (10.08.2019)!") static inline double default_beta(const size_t d) { return 1.0 / (d - 1.0); @@ -141,6 +454,7 @@ static inline double default_beta(const size_t d) /** * \note see Epshteyn, Riviere, 2007 */ +DXT_DEPRECATED_MSG("Use the LocalLaplaceIPDGIntegrands instead (10.08.2019)!") static inline double inner_sigma(const size_t pol_order) { double sigma = 1.0; @@ -151,14 +465,14 @@ static inline double inner_sigma(const size_t pol_order) else if (pol_order <= 3) sigma *= 38.0; else { -#ifndef NDEBUG -# ifndef DUNE_GDT_DISABLE_WARNINGS +# ifndef NDEBUG +# ifndef DUNE_GDT_DISABLE_WARNINGS Dune::XT::Common::TimedLogger().get("gdt.local.integrands.elliptic-ipdg.inner").warn() << "a polynomial order of " << pol_order << " is untested!\n" << " #define DUNE_GDT_DISABLE_WARNINGS to statically disable this warning\n" << " or dynamically disable warnings of the TimedLogger() instance!" << std::endl; +# endif # endif -#endif sigma *= 50.0; } return sigma; @@ -168,6 +482,7 @@ static inline double inner_sigma(const size_t pol_order) /** * \note see Epshteyn, Riviere, 2007 */ +DXT_DEPRECATED_MSG("Use the LocalLaplaceIPDGIntegrands instead (10.08.2019)!") static inline double boundary_sigma(const size_t pol_order) { double sigma = 1.0; @@ -178,14 +493,14 @@ static inline double boundary_sigma(const size_t pol_order) else if (pol_order <= 3) sigma *= 74.0; else { -#ifndef NDEBUG -# ifndef DUNE_GDT_DISABLE_WARNINGS +# ifndef NDEBUG +# ifndef DUNE_GDT_DISABLE_WARNINGS Dune::XT::Common::TimedLogger().get("gdt.local.integrands.elliptic-ipdg.boundary").warn() << "a polynomial order of " << pol_order << " is untested!\n" << " #define DUNE_GDT_DISABLE_WARNINGS to statically disable this warning\n" << " or dynamically disable warnings of the TimedLogger() instance!" << std::endl; +# endif # endif -#endif sigma *= 100.0; } return sigma; @@ -199,10 +514,12 @@ static inline double boundary_sigma(const size_t pol_order) * \sa [Epshteyn, Riviere, 2007] for the meaning of beta */ template <class I, class F = double, Method method = default_method> -class Inner : public LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F> +class DXT_DEPRECATED_MSG( + "Use LocalLaplaceIPDGIntegrands::InnerCoupling + LocalIPDGIntegrands::InnerPenalty} instead (10.08.2019)!") Inner + : public LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F> { using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F>; - using ThisType = Inner<I, F, method>; + using ThisType = Inner; public: using BaseType::d; @@ -690,10 +1007,12 @@ private: * \sa [Epshteyn, Riviere, 2007] for the meaning of beta */ template <class I, class F = double, Method method = default_method> -class DirichletBoundaryLhs : public LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F> +class DXT_DEPRECATED_MSG( + "Use LocalLaplaceIPDGIntegrands::DirichletCoupling + LocalIPDGIntegrands::boundaryPenalty instead (10.08.2019)!") + DirichletBoundaryLhs : public LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F> { using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F>; - using ThisType = DirichletBoundaryLhs<I, F, method>; + using ThisType = DirichletBoundaryLhs; public: using BaseType::d; @@ -882,7 +1201,7 @@ private: }; // DirichletBoundaryLhs -#if 0 +# if 0 template <class DirichletImp, class DiffusionFactorImp, class DiffusionTensorImp, Method method> class BoundaryRHS : public LocalFaceIntegrandInterface<internal::BoundaryRHSTraits<DirichletImp, DiffusionFactorImp, @@ -1124,16 +1443,17 @@ public: const EllipticType elliptic_; const double beta_; }; // class BoundaryRHS -#endif // 0 +# endif // 0 /** * \sa [Epshteyn, Riviere, 2007] for the meaning of beta */ template <class I, class F = double, Method method = default_method> -class InnerOnlyPenalty : public LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F> +class DXT_DEPRECATED_MSG("Use LocalIPDGIntegrands::InnerPenalty instead (05.08.2019)!") InnerOnlyPenalty + : public LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F> { using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F>; - using ThisType = InnerOnlyPenalty<I, F, method>; + using ThisType = InnerOnlyPenalty; public: using BaseType::d; @@ -1576,14 +1896,16 @@ private: mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_out_values_; }; // InnerOnlyPenalty + /** * \sa [Epshteyn, Riviere, 2007] for the meaning of beta */ template <class I, class F = double, Method method = default_method> -class DirichletBoundaryLhsOnlyPenalty : public LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F> +class DXT_DEPRECATED_MSG("Use LocalIPDGIntegrands::BoundaryPenalty instead (05.08.2019)!") + DirichletBoundaryLhsOnlyPenalty : public LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F> { using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F>; - using ThisType = DirichletBoundaryLhsOnlyPenalty<I, F, method>; + using ThisType = DirichletBoundaryLhsOnlyPenalty; public: using BaseType::d; @@ -1764,6 +2086,7 @@ private: mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> ansatz_basis_grads_; }; // DirichletBoundaryLhsOnlyPenalty + } // namespace LocalEllipticIpdgIntegrands } // namespace GDT } // namespace Dune diff --git a/dune/gdt/local/integrands/elliptic.hh b/dune/gdt/local/integrands/elliptic.hh index 7f383af70ad5fb4bd5f357c3f19c3a9dff4fc5e2..e793ca67cefeeb9b71afc563b699d7531fd8c52b 100644 --- a/dune/gdt/local/integrands/elliptic.hh +++ b/dune/gdt/local/integrands/elliptic.hh @@ -11,27 +11,35 @@ // René Milk (2017) // Tobias Leibner (2014, 2016 - 2018) +#warning This header is deprecated, use and include <dune/gdt/local/integrands/laplace.hh> instead! + #ifndef DUNE_GDT_LOCAL_INTEGRANDS_ELLIPTIC_HH -#define DUNE_GDT_LOCAL_INTEGRANDS_ELLIPTIC_HH +# define DUNE_GDT_LOCAL_INTEGRANDS_ELLIPTIC_HH -#include <dune/xt/common/memory.hh> -#include <dune/xt/la/container/eye-matrix.hh> -#include <dune/xt/functions/base/function-as-grid-function.hh> -#include <dune/xt/functions/constant.hh> -#include <dune/xt/functions/interfaces/grid-function.hh> +# include <dune/xt/common/deprecated.hh> +# include <dune/xt/common/memory.hh> +# include <dune/xt/la/container/eye-matrix.hh> +# include <dune/xt/functions/base/function-as-grid-function.hh> +# include <dune/xt/functions/constant.hh> +# include <dune/xt/functions/interfaces/grid-function.hh> -#include "interfaces.hh" +# include "interfaces.hh" namespace Dune { namespace GDT { /** + * This class is deprecated, use LocalLaplaceIntegrand instead (10.08.2019)! * Given an inducing scalar function lambda and an inducing matrix-valued function kappa, computes - * `lambda(x) * {[kappa(x) \nabla phi(x)] * \nabla psi(x)}` for all combinations of phi and psi in the bases. + * `lambda(x) * {[kappa(x) \nabla phi(x)] * \nabla psi(x)}` for all combinations of phi in the ansatz basis and psi in + * the test basis. + * If phi and psi are vector-valued, \nabla phi is the jacobian matrix and we are actually computing + * `lambda(x) * {[kappa(x) (\nabla phi(x))^T] : (\nabla psi(x))^T}`, where ':' denotes the matrix scalar product. */ template <class E, size_t r = 1, class F = double> -class LocalEllipticIntegrand : public LocalBinaryElementIntegrandInterface<E, r, 1, F, F, r, 1, F> +class DXT_DEPRECATED_MSG("Use LocalLaplaceIntegrand instead (10.08.2019)!") LocalEllipticIntegrand + : public LocalBinaryElementIntegrandInterface<E, r, 1, F, F, r, 1, F> { using BaseType = LocalBinaryElementIntegrandInterface<E, r, 1, F, F, r, 1, F>; using ThisType = LocalEllipticIntegrand; @@ -93,6 +101,10 @@ public: protected: void post_bind(const ElementType& ele) override { +# ifndef NDEBUG + if (!ele.geometry().affine()) + std::cerr << "Warning: integration order has to be increased for non-affine geometries!" << std::endl; +# endif local_diffusion_factor_->bind(ele); local_diffusion_tensor_->bind(ele); } @@ -102,8 +114,8 @@ public: const LocalAnsatzBasisType& ansatz_basis, const XT::Common::Parameter& param = {}) const override final { - return local_diffusion_factor_->order(param) + local_diffusion_tensor_->order(param) - + std::max(test_basis.order(param) - 1, 0) + std::max(ansatz_basis.order(param) - 1, 0); + return local_diffusion_factor_->order(param) + local_diffusion_tensor_->order(param) + test_basis.order(param) + + ansatz_basis.order(param); } void evaluate(const LocalTestBasisType& test_basis, diff --git a/dune/gdt/local/integrands/generic.hh b/dune/gdt/local/integrands/generic.hh index d6597958aab7eeee26b6c7a86b10c85499c96963..06d901dbd9758451763fe9b6054a4489658dca7c 100644 --- a/dune/gdt/local/integrands/generic.hh +++ b/dune/gdt/local/integrands/generic.hh @@ -24,7 +24,7 @@ namespace GDT { template <class E, size_t r = 1, size_t rC = 1, class R = double, class F = double> class GenericLocalUnaryElementIntegrand : public LocalUnaryElementIntegrandInterface<E, r, rC, R, F> { - using ThisType = GenericLocalUnaryElementIntegrand<E, r, rC, R, F>; + using ThisType = GenericLocalUnaryElementIntegrand; using BaseType = LocalUnaryElementIntegrandInterface<E, r, rC, R, F>; public: @@ -33,41 +33,50 @@ public: using GenericOrderFunctionType = std::function<int(const LocalBasisType& /*basis*/, const XT::Common::Parameter& /*param*/)>; - using GenericEvalauteFunctionType = std::function<void(const LocalBasisType& /*basis*/, + using GenericEvaluateFunctionType = std::function<void(const LocalBasisType& /*basis*/, const DomainType& /*point_in_reference_element*/, DynamicVector<F>& /*result*/, const XT::Common::Parameter& /*param*/)>; + using GenericPostBindFunctionType = std::function<void(const E& /*ele*/)>; GenericLocalUnaryElementIntegrand(GenericOrderFunctionType order_function, - GenericEvalauteFunctionType evaluate_function, + GenericEvaluateFunctionType evaluate_function, + GenericPostBindFunctionType post_bind_function = [](const E&) {}, const XT::Common::ParameterType& param_type = {}) : BaseType(param_type) , order_(order_function) , evaluate_(evaluate_function) + , post_bind_(post_bind_function) {} GenericLocalUnaryElementIntegrand(const ThisType& other) : BaseType(other.parameter_type()) , order_(other.order_) , evaluate_(other.evaluate_) + , post_bind_(other.post_bind_) {} - std::unique_ptr<BaseType> copy() const + std::unique_ptr<BaseType> copy() const override final { return std::make_unique<ThisType>(*this); } - int order(const LocalBasisType& basis, const XT::Common::Parameter& param = {}) const + void post_bind(const E& ele) override final + { + post_bind_(ele); + } + + int order(const LocalBasisType& basis, const XT::Common::Parameter& param = {}) const override final { return order_(basis, this->parse_parameter(param)); } using BaseType::evaluate; - void evaluate(const LocalBasisType& basis, - const DomainType& point_in_reference_element, - DynamicVector<F>& result, - const XT::Common::Parameter& param = {}) const + virtual void evaluate(const LocalBasisType& basis, + const DomainType& point_in_reference_element, + DynamicVector<F>& result, + const XT::Common::Parameter& param = {}) const override final { // prepare storage const size_t size = basis.size(param); @@ -83,7 +92,8 @@ public: private: const GenericOrderFunctionType order_; - const GenericEvalauteFunctionType evaluate_; + const GenericEvaluateFunctionType evaluate_; + const GenericPostBindFunctionType post_bind_; }; // class GenericLocalUnaryElementIntegrand @@ -98,7 +108,7 @@ template <class E, class GenericLocalBinaryElementIntegrand : public LocalBinaryElementIntegrandInterface<E, t_r, t_rC, TF, F, a_r, a_rC, AF> { - using ThisType = GenericLocalBinaryElementIntegrand<E, t_r, t_rC, TF, F, a_r, a_rC, AF>; + using ThisType = GenericLocalBinaryElementIntegrand; using BaseType = LocalBinaryElementIntegrandInterface<E, t_r, t_rC, TF, F, a_r, a_rC, AF>; public: @@ -109,45 +119,54 @@ public: using GenericOrderFunctionType = std::function<int(const LocalTestBasisType& /*test_basis*/, const LocalAnsatzBasisType& /*ansatz_basis*/, const XT::Common::Parameter& /*param*/)>; - using GenericEvalauteFunctionType = std::function<void(const LocalTestBasisType& /*test_basis*/, + using GenericEvaluateFunctionType = std::function<void(const LocalTestBasisType& /*test_basis*/, const LocalAnsatzBasisType& /*ansatz_basis*/, const DomainType& /*point_in_reference_element*/, DynamicMatrix<F>& /*result*/, const XT::Common::Parameter& /*param*/)>; + using GenericPostBindFunctionType = std::function<void(const E& /*ele*/)>; GenericLocalBinaryElementIntegrand(GenericOrderFunctionType order_function, - GenericEvalauteFunctionType evaluate_function, + GenericEvaluateFunctionType evaluate_function, + GenericPostBindFunctionType post_bind_function = [](const E&) {}, const XT::Common::ParameterType& param_type = {}) : BaseType(param_type) , order_(order_function) , evaluate_(evaluate_function) + , post_bind_(post_bind_function) {} GenericLocalBinaryElementIntegrand(const ThisType& other) : BaseType(other.parameter_type()) , order_(other.order_) , evaluate_(other.evaluate_) + , post_bind_(other.post_bind_) {} - std::unique_ptr<BaseType> copy() const + std::unique_ptr<BaseType> copy() const override final { return std::make_unique<ThisType>(*this); } - int order(const LocalTestBasisType& test_basis, - const LocalAnsatzBasisType& ansatz_basis, - const XT::Common::Parameter& param = {}) const + void post_bind(const E& ele) override final + { + post_bind_(ele); + } + + virtual int order(const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + const XT::Common::Parameter& param = {}) const override final { return order_(test_basis, ansatz_basis, this->parse_parameter(param)); } using BaseType::evaluate; - void evaluate(const LocalTestBasisType& test_basis, - const LocalAnsatzBasisType& ansatz_basis, - const DomainType& point_in_reference_element, - DynamicMatrix<F>& result, - const XT::Common::Parameter& param = {}) const + virtual void evaluate(const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + const DomainType& point_in_reference_element, + DynamicMatrix<F>& result, + const XT::Common::Parameter& param = {}) const override final { // prepare storage const size_t rows = test_basis.size(param); @@ -166,15 +185,16 @@ public: private: const GenericOrderFunctionType order_; - const GenericEvalauteFunctionType evaluate_; + const GenericEvaluateFunctionType evaluate_; + const GenericPostBindFunctionType post_bind_; }; // class GenericLocalBinaryElementIntegrand template <class I, size_t r = 1, size_t rC = 1, class RF = double, class F = double> class GenericLocalBinaryIntersectionIntegrand : public LocalBinaryIntersectionIntegrandInterface<I, r, rC, RF, F> { + using ThisType = GenericLocalBinaryIntersectionIntegrand; using BaseType = LocalBinaryIntersectionIntegrandInterface<I, r, rC, RF, F>; - using ThisType = GenericLocalBinaryIntersectionIntegrand<I, r, rC, RF, F>; public: using typename BaseType::DomainType; @@ -183,24 +203,28 @@ public: using GenericOrderFunctionType = std::function<int(const LocalBasisType& /*inside_basis*/, const LocalBasisType& /*outside_basis*/, const XT::Common::Parameter& /*param*/)>; - using GenericEvalauteFunctionType = std::function<void(const LocalBasisType& /*inside_basis*/, + using GenericEvaluateFunctionType = std::function<void(const LocalBasisType& /*inside_basis*/, const LocalBasisType& /*outside_basis*/, const DomainType& /*point_in_reference_intersection*/, DynamicMatrix<F>& /*result*/, const XT::Common::Parameter& /*param*/)>; + using GenericPostBindFunctionType = std::function<void(const I& /*ele*/)>; GenericLocalBinaryIntersectionIntegrand(GenericOrderFunctionType order_function, - GenericEvalauteFunctionType evaluate_function, + GenericEvaluateFunctionType evaluate_function, + GenericPostBindFunctionType post_bind_function = [](const I&) {}, const XT::Common::ParameterType& param_type = {}) : BaseType(param_type) , order_(order_function) , evaluate_(evaluate_function) + , post_bind_(post_bind_function) {} GenericLocalBinaryIntersectionIntegrand(const ThisType& other) : BaseType(other.parameter_type()) , order_(other.order_) , evaluate_(other.evaluate_) + , post_bind_(other.post_bind_) {} std::unique_ptr<BaseType> copy() const override final @@ -208,20 +232,25 @@ public: return std::make_unique<ThisType>(*this); } - int order(const LocalBasisType& inside_basis, - const LocalBasisType& outside_basis, - const XT::Common::Parameter& param = {}) const override final + void post_bind(const I& intersect) override final + { + post_bind_(intersect); + } + + virtual int order(const LocalBasisType& inside_basis, + const LocalBasisType& outside_basis, + const XT::Common::Parameter& param = {}) const override final { return order_(inside_basis, outside_basis, this->parse_parameter(param)); } using BaseType::evaluate; - void evaluate(const LocalBasisType& inside_basis, - const LocalBasisType& outside_basis, - const DomainType& point_in_reference_intersection, - DynamicMatrix<F>& result, - const XT::Common::Parameter& param = {}) const override final + virtual void evaluate(const LocalBasisType& inside_basis, + const LocalBasisType& outside_basis, + const DomainType& point_in_reference_intersection, + DynamicMatrix<F>& result, + const XT::Common::Parameter& param = {}) const override final { // prepare storage const size_t rows = inside_basis.size(param); const size_t cols = outside_basis.size(param); @@ -239,7 +268,8 @@ public: private: const GenericOrderFunctionType order_; - const GenericEvalauteFunctionType evaluate_; + const GenericEvaluateFunctionType evaluate_; + const GenericPostBindFunctionType post_bind_; }; // class GenericLocalBinaryIntersectionIntegrand diff --git a/dune/gdt/local/integrands/gradient-value.hh b/dune/gdt/local/integrands/gradient-value.hh new file mode 100644 index 0000000000000000000000000000000000000000..2d93e0ad8acc91fc64d753a8bf33175505fb7e0b --- /dev/null +++ b/dune/gdt/local/integrands/gradient-value.hh @@ -0,0 +1,169 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2019) + +#ifndef DUNE_GDT_LOCAL_INTEGRANDS_GRADIENT_VALUE_HH +#define DUNE_GDT_LOCAL_INTEGRANDS_GRADIENT_VALUE_HH + +#include <dune/xt/common/memory.hh> +#include <dune/xt/functions/constant.hh> +#include <dune/xt/functions/grid-function.hh> + +#include "interfaces.hh" + +namespace Dune { +namespace GDT { + + +/** + * Given an inducing (vector-valued) function u, computes `(\nabla phi(x) * u(x)) * psi(x)` for all combinations of phi + * in the ansatz basis and psi in the test basis. If use_test_gradient is set to true, ansatz and test basis are + * swapped. + * + * \sa local_binary_to_unary_element_integrand + */ +template <class E, + size_t r = 1, + size_t rC = 1, + class TR = double, + class F = double, + class AR = TR, + bool use_test_gradient = false> +class LocalElementGradientValueIntegrand : public LocalBinaryElementIntegrandInterface<E, r, rC, TR, F, r, rC, AR> +{ + using BaseType = LocalBinaryElementIntegrandInterface<E, r, rC, TR, F, r, rC, AR>; + using ThisType = LocalElementGradientValueIntegrand; + static_assert(rC == 1, "Not tested for rC > 1!"); + +public: + using BaseType::d; + using typename BaseType::DomainType; + using typename BaseType::ElementType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::LocalTestBasisType; + using BasisValues = + std::vector<typename std::conditional_t<use_test_gradient, LocalAnsatzBasisType, LocalTestBasisType>::RangeType>; + using BasisJacobians = std::vector< + typename std::conditional_t<use_test_gradient, LocalTestBasisType, LocalAnsatzBasisType>::DerivativeRangeType>; + static const size_t vector_size = d; + + using VectorGridFunctionType = XT::Functions::GridFunction<E, vector_size, 1, F>; + using VectorValues = typename VectorGridFunctionType::LocalFunctionType::RangeReturnType; + + LocalElementGradientValueIntegrand(const VectorGridFunctionType vector_in) + : BaseType() + , vector_(vector_in) + , local_function_(vector_.local_function()) + {} + + LocalElementGradientValueIntegrand(const ThisType& other) + : BaseType(other.parameter_type()) + , vector_(other.vector_) + , local_function_(vector_.local_function()) + {} + + LocalElementGradientValueIntegrand(ThisType&& source) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + +protected: + void post_bind(const ElementType& ele) override final + { + local_function_->bind(ele); + } + +public: + int order(const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + const XT::Common::Parameter& param = {}) const override final + { + return local_function_->order(param) + test_basis.order(param) + ansatz_basis.order(param); + } + + using BaseType::evaluate; + + void evaluate(const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + const DomainType& point_in_reference_element, + DynamicMatrix<F>& result, + const XT::Common::Parameter& param = {}) const override final + { + // prepare storage + const size_t rows = test_basis.size(param); + const size_t cols = ansatz_basis.size(param); + if (result.rows() < rows || result.cols() < cols) + result.resize(rows, cols); + vector_values_ = local_function_->evaluate(point_in_reference_element, param); + helper<>::evaluate( + test_basis, ansatz_basis, point_in_reference_element, vector_values_, values_, jacobians_, result, param); + } // ... evaluate(...) + +private: + template <bool use_test = use_test_gradient, bool anything = true> + struct helper + { + static void evaluate(const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + const DomainType& point_in_reference_element, + const VectorValues& vector_values, + BasisValues& values, + BasisJacobians& jacobians, + DynamicMatrix<F>& result, + const XT::Common::Parameter& param) + { + test_basis.evaluate(point_in_reference_element, values, param); + ansatz_basis.jacobians(point_in_reference_element, jacobians, param); + + auto nabla_phi_times_u = values[0]; + for (size_t jj = 0; jj < ansatz_basis.size(); ++jj) { + jacobians[jj].mv(vector_values, nabla_phi_times_u); + for (size_t ii = 0; ii < test_basis.size(); ++ii) + result[ii][jj] = nabla_phi_times_u * values[ii]; + } + } + }; + + template <bool anything> + struct helper<true, anything> + { + static void evaluate(const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + const DomainType& point_in_reference_element, + const VectorValues& vector_values, + BasisValues& values, + BasisJacobians& jacobians, + DynamicMatrix<F>& result, + const XT::Common::Parameter& param) + { + ansatz_basis.evaluate(point_in_reference_element, values, param); + test_basis.jacobians(point_in_reference_element, jacobians, param); + + auto nabla_psi_times_u = values[0]; + for (size_t ii = 0; ii < test_basis.size(); ++ii) { + jacobians[ii].mv(vector_values, nabla_psi_times_u); + for (size_t jj = 0; jj < ansatz_basis.size(); ++jj) + result[ii][jj] = nabla_psi_times_u * values[jj]; + } + } + }; + + const VectorGridFunctionType vector_; + std::unique_ptr<typename VectorGridFunctionType::LocalFunctionType> local_function_; + mutable VectorValues vector_values_; + mutable BasisValues values_; + mutable BasisJacobians jacobians_; +}; // class LocalElementGradientValueIntegrand + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_LOCAL_INTEGRANDS_GRADIENT_VALUE_HH diff --git a/dune/gdt/local/integrands/identity.hh b/dune/gdt/local/integrands/identity.hh index 663822eba1e798fe79bab78508725e4c89d37d59..f93db08c6868957de490f652b2ece3d9b735d8ac 100644 --- a/dune/gdt/local/integrands/identity.hh +++ b/dune/gdt/local/integrands/identity.hh @@ -24,7 +24,7 @@ class LocalElementIdentityIntegrand : public LocalUnaryElementIntegrandInterface { static_assert(r == 1, ""); static_assert(rC == 1, ""); - using ThisType = LocalElementIdentityIntegrand<E, r, rC, R, F>; + using ThisType = LocalElementIdentityIntegrand; using BaseType = LocalUnaryElementIntegrandInterface<E, r, rC, R, F>; public: diff --git a/dune/gdt/local/integrands/interfaces.hh b/dune/gdt/local/integrands/interfaces.hh index cb6b15f872390708db877ec0a1b72514fd57ca11..25e377eabaa6f547213fe9b2fb9693d9bcbe1bc2 100644 --- a/dune/gdt/local/integrands/interfaces.hh +++ b/dune/gdt/local/integrands/interfaces.hh @@ -26,6 +26,20 @@ namespace Dune { namespace GDT { +// forwards (required for operator+, include are below) +template <class E, size_t r, size_t rC, class R, class F> +class LocalUnaryElementIntegrandSum; + +template <class E, size_t t_r, size_t t_RC, class TF, class F, size_t a_r, size_t a_rC, class AF> +class LocalBinaryElementIntegrandSum; + +template <class I, size_t r, size_t rC, class R, class F> +class LocalBinaryIntersectionIntegrandSum; + +template <class I, size_t t_r, size_t t_rC, class TF, class F, size_t a_r, size_t a_rC, class AF> +class LocalQuaternaryIntersectionIntegrandSum; + + /** * Interface for integrands in integrals over grid elements, which depend on one argument only (usually the test basis * in an integral-based functional). @@ -45,7 +59,7 @@ class LocalUnaryElementIntegrandInterface { static_assert(XT::Grid::is_entity<Element>::value, ""); - using ThisType = LocalUnaryElementIntegrandInterface<Element, range_dim, range_dim_cols, RangeField, Field>; + using ThisType = LocalUnaryElementIntegrandInterface; public: using E = Element; @@ -124,14 +138,7 @@ class LocalBinaryElementIntegrandInterface { static_assert(XT::Grid::is_entity<Element>::value, ""); - using ThisType = LocalBinaryElementIntegrandInterface<Element, - test_range_dim, - test_range_dim_cols, - TestRangeField, - Field, - ansatz_range_dim, - ansatz_range_dim_cols, - AnsatzRangeField>; + using ThisType = LocalBinaryElementIntegrandInterface; public: using E = Element; @@ -216,8 +223,7 @@ class LocalBinaryIntersectionIntegrandInterface { static_assert(XT::Grid::is_intersection<Intersection>::value, ""); - using ThisType = - LocalBinaryIntersectionIntegrandInterface<Intersection, range_dim, range_dim_cols, RangeField, Field>; + using ThisType = LocalBinaryIntersectionIntegrandInterface; public: using typename XT::Grid::IntersectionBoundObject<Intersection>::IntersectionType; @@ -295,14 +301,7 @@ class LocalQuaternaryIntersectionIntegrandInterface { static_assert(XT::Grid::is_intersection<Intersection>::value, ""); - using ThisType = LocalQuaternaryIntersectionIntegrandInterface<Intersection, - test_range_dim, - test_range_dim_cols, - TestRangeField, - Field, - ansatz_range_dim, - ansatz_range_dim_cols, - AnsatzRangeField>; + using ThisType = LocalQuaternaryIntersectionIntegrandInterface; public: using typename XT::Grid::IntersectionBoundObject<Intersection>::IntersectionType; @@ -334,6 +333,11 @@ public: virtual std::unique_ptr<ThisType> copy() const = 0; + LocalQuaternaryIntersectionIntegrandSum<I, t_r, t_rC, TR, F, a_r, a_rC, AR> operator+(const ThisType& other) const + { + return LocalQuaternaryIntersectionIntegrandSum<I, t_r, t_rC, TR, F, a_r, a_rC, AR>(*this, other); + } + /** * Returns the polynomial order of the integrand, given the bases. * @@ -390,12 +394,37 @@ public: return {result_in_in, result_in_out, result_out_in, result_out_out}; } // ... apply(...) -private: - std::unique_ptr<IntersectionType> intersection_; +protected: + void ensure_size_and_clear_results(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + DynamicMatrix<F>& result_in_in, + DynamicMatrix<F>& result_in_out, + DynamicMatrix<F>& result_out_in, + DynamicMatrix<F>& result_out_out, + const XT::Common::Parameter& param) const + { + const size_t rows_in = test_basis_inside.size(param); + const size_t rows_out = test_basis_outside.size(param); + const size_t cols_in = ansatz_basis_inside.size(param); + const size_t cols_out = ansatz_basis_outside.size(param); + const auto ensure_size_and_clear = [](auto& m, const auto& r, const auto& c) { + if (m.rows() < r || m.cols() < c) + m.resize(r, c); + m *= 0; + }; + ensure_size_and_clear(result_in_in, rows_in, cols_in); + ensure_size_and_clear(result_in_out, rows_in, cols_out); + ensure_size_and_clear(result_out_in, rows_out, cols_in); + ensure_size_and_clear(result_out_out, rows_out, cols_out); + } // ... ensure_size_and_clear_results(...) }; // class LocalQuaternaryIntersectionIntegrandInterface } // namespace GDT } // namespace Dune +#include "combined.hh" + #endif // DUNE_GDT_LOCAL_INTEGRANDS_INTERFACES_HH diff --git a/dune/gdt/local/integrands/ipdg.hh b/dune/gdt/local/integrands/ipdg.hh new file mode 100644 index 0000000000000000000000000000000000000000..8e6cba4a21ca8d4909ecdd6243d4402b1a536d4c --- /dev/null +++ b/dune/gdt/local/integrands/ipdg.hh @@ -0,0 +1,307 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#ifndef DUNE_GDT_LOCAL_INTEGRANDS_IPDG_HH +#define DUNE_GDT_LOCAL_INTEGRANDS_IPDG_HH + +#include <functional> + +#include <dune/xt/common/memory.hh> +#include <dune/xt/functions/grid-function.hh> +#include <dune/xt/grid/entity.hh> +#include <dune/xt/grid/intersection.hh> + +#include "interfaces.hh" + +namespace Dune { +namespace GDT { +namespace LocalIPDGIntegrands { +namespace internal { + + +template <class Intersection> +static std::function<double(const Intersection&)> default_inner_intersection_diameter() +{ + return [](const Intersection& intersection) { + if (Intersection::dimension == 1) { + if (intersection.neighbor()) + return 0.5 * (XT::Grid::diameter(intersection.inside()) + XT::Grid::diameter(intersection.outside())); + else + return XT::Grid::diameter(intersection.inside()); + } else + return XT::Grid::diameter(intersection); + }; +} // ... default_inner_intersection_diameter(...) + + +template <class Intersection> +static std::function<double(const Intersection&)> default_boundary_intersection_diameter() +{ + return [](const Intersection& intersection) { + if (Intersection::dimension == 1) + return XT::Grid::diameter(intersection.inside()); + else + return XT::Grid::diameter(intersection); + }; +} // ... default_boundary_intersection_diameter(...) + + +} // namespace internal + + +template <class I> +class InnerPenalty : public LocalQuaternaryIntersectionIntegrandInterface<I> +{ + using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I>; + using ThisType = InnerPenalty; + +public: + using BaseType::d; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::F; + using typename BaseType::IntersectionType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::LocalTestBasisType; + + InnerPenalty( + const double& penalty, + XT::Functions::GridFunction<E, d, d> weight_function = 1., + const std::function<double(const I&)>& intersection_diameter = internal::default_inner_intersection_diameter<I>()) + : BaseType(weight_function.parameter_type()) + , penalty_(penalty) + , weight_(weight_function) + , intersection_diameter_(intersection_diameter) + , local_weight_in_(weight_.local_function()) + , local_weight_out_(weight_.local_function()) + {} + + InnerPenalty(const ThisType& other) + : BaseType(other.parameter_type()) + , penalty_(other.penalty_) + , weight_(other.weight_) + , intersection_diameter_(other.intersection_diameter_) + , local_weight_in_(weight_.local_function()) + , local_weight_out_(weight_.local_function()) + {} + + InnerPenalty(ThisType&& source) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + +protected: + void post_bind(const IntersectionType& intrsctn) override final + { + DUNE_THROW_IF( + !intrsctn.neighbor(), Exceptions::integrand_error, "This integrand cannot be used on a boundary intersection!"); + local_weight_in_->bind(intrsctn.inside()); + local_weight_out_->bind(intrsctn.outside()); + } + +public: + int order(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const XT::Common::Parameter& param = {}) const override final + { + return std::max(local_weight_in_->order(param), local_weight_out_->order(param)) + + std::max(test_basis_inside.order(param), test_basis_outside.order(param)) + + std::max(ansatz_basis_inside.order(param), ansatz_basis_outside.order(param)); + } + + void evaluate(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const DomainType& point_in_reference_intersection, + DynamicMatrix<F>& result_in_in, + DynamicMatrix<F>& result_in_out, + DynamicMatrix<F>& result_out_in, + DynamicMatrix<F>& result_out_out, + const XT::Common::Parameter& param = {}) const override final + { + // Prepare sotrage, ... + this->ensure_size_and_clear_results(test_basis_inside, + ansatz_basis_inside, + test_basis_outside, + ansatz_basis_outside, + result_in_in, + result_in_out, + result_out_in, + result_out_out, + param); + // evaluate ... + const auto point_in_inside_reference_element = + this->intersection().geometryInInside().global(point_in_reference_intersection); + const auto point_in_outside_reference_element = + this->intersection().geometryInOutside().global(point_in_reference_intersection); + const auto normal = this->intersection().unitOuterNormal(point_in_reference_intersection); + // ... basis functions + test_basis_inside.evaluate(point_in_inside_reference_element, test_basis_in_values_, param); + test_basis_outside.evaluate(point_in_outside_reference_element, test_basis_out_values_, param); + ansatz_basis_inside.evaluate(point_in_inside_reference_element, ansatz_basis_in_values_, param); + ansatz_basis_outside.evaluate(point_in_outside_reference_element, ansatz_basis_out_values_, param); + // ... and data functions, ... + const auto weight_in = local_weight_in_->evaluate(point_in_inside_reference_element, param); + const auto weight_out = local_weight_out_->evaluate(point_in_outside_reference_element, param); + // compute the weighted penalty ... + const double delta_plus = normal * (weight_out * normal); + const double delta_minus = normal * (weight_in * normal); + const auto weight = (delta_plus * delta_minus) / (delta_plus + delta_minus); // half harmonic average + const auto h = intersection_diameter_(this->intersection()); + const auto penalty = (penalty_ * weight) / h; + // and finally compute the integrand. + const size_t rows_in = test_basis_inside.size(param); + const size_t rows_out = test_basis_outside.size(param); + const size_t cols_in = ansatz_basis_inside.size(param); + const size_t cols_out = ansatz_basis_outside.size(param); + for (size_t ii = 0; ii < rows_in; ++ii) { + for (size_t jj = 0; jj < cols_in; ++jj) + result_in_in[ii][jj] += penalty * ansatz_basis_in_values_[jj] * test_basis_in_values_[ii]; + for (size_t jj = 0; jj < cols_out; ++jj) + result_in_out[ii][jj] += -1.0 * penalty * ansatz_basis_out_values_[jj] * test_basis_in_values_[ii]; + } + for (size_t ii = 0; ii < rows_out; ++ii) { + for (size_t jj = 0; jj < cols_in; ++jj) + result_out_in[ii][jj] += -1.0 * penalty * ansatz_basis_in_values_[jj] * test_basis_out_values_[ii]; + for (size_t jj = 0; jj < cols_out; ++jj) + result_out_out[ii][jj] += penalty * ansatz_basis_out_values_[jj] * test_basis_out_values_[ii]; + } + } // ... evaluate(...) + +private: + const double penalty_; + XT::Functions::GridFunction<E, d, d> weight_; + const std::function<double(const I&)> intersection_diameter_; + std::unique_ptr<typename XT::Functions::GridFunction<E, d, d>::LocalFunctionType> local_weight_in_; + std::unique_ptr<typename XT::Functions::GridFunction<E, d, d>::LocalFunctionType> local_weight_out_; + mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_in_values_; + mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_out_values_; + mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_in_values_; + mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_out_values_; +}; // InnerPenalty + + +template <class I> +class BoundaryPenalty : public LocalQuaternaryIntersectionIntegrandInterface<I> +{ + using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I>; + using ThisType = BoundaryPenalty; + +public: + using BaseType::d; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::F; + using typename BaseType::IntersectionType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::LocalTestBasisType; + + BoundaryPenalty(const double& penalty, + XT::Functions::GridFunction<E, d, d> weight_function = 1., + const std::function<double(const I&)>& intersection_diameter = + internal::default_boundary_intersection_diameter<I>()) + : BaseType() + , penalty_(penalty) + , weight_(weight_function) + , intersection_diameter_(intersection_diameter) + , local_weight_(weight_.local_function()) + {} + + BoundaryPenalty(const ThisType& other) + : BaseType(other.parameter_type()) + , penalty_(other.penalty_) + , weight_(other.weight_) + , intersection_diameter_(other.intersection_diameter_) + , local_weight_(weight_.local_function()) + {} + + BoundaryPenalty(ThisType&& source) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + +protected: + void post_bind(const IntersectionType& intersection) override final + { + local_weight_->bind(intersection.inside()); + } + +public: + int order(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& /*test_basis_outside*/, + const LocalAnsatzBasisType& /*ansatz_basis_outside*/, + const XT::Common::Parameter& param = {}) const override final + { + return local_weight_->order(param) + test_basis_inside.order(param) + ansatz_basis_inside.order(param); + } + + void evaluate(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const DomainType& point_in_reference_intersection, + DynamicMatrix<F>& result_in_in, + DynamicMatrix<F>& result_in_out, + DynamicMatrix<F>& result_out_in, + DynamicMatrix<F>& result_out_out, + const XT::Common::Parameter& param = {}) const override final + { + // Prepare sotrage, ... + this->ensure_size_and_clear_results(test_basis_inside, + ansatz_basis_inside, + test_basis_outside, + ansatz_basis_outside, + result_in_in, + result_in_out, + result_out_in, + result_out_out, + param); + // evaluate ... + const auto point_in_inside_reference_element = + this->intersection().geometryInInside().global(point_in_reference_intersection); + const auto normal = this->intersection().unitOuterNormal(point_in_reference_intersection); + // ... basis functions ... + test_basis_inside.evaluate(point_in_inside_reference_element, test_basis_values_, param); + ansatz_basis_inside.evaluate(point_in_inside_reference_element, ansatz_basis_values_, param); + // ... and data functions, .... + const auto weight = local_weight_->evaluate(point_in_inside_reference_element, param); + // compute the weighted penalty ... + const auto h = intersection_diameter_(this->intersection()); + const auto penalty = (penalty_ * (normal * (weight * normal))) / h; + // and finally compute integrand. + const size_t rows = test_basis_inside.size(param); + const size_t cols = ansatz_basis_inside.size(param); + for (size_t ii = 0; ii < rows; ++ii) + for (size_t jj = 0; jj < cols; ++jj) + result_in_in[ii][jj] += penalty * ansatz_basis_values_[jj] * test_basis_values_[ii]; + } // ... evaluate(...) + +private: + const double penalty_; + XT::Functions::GridFunction<E, d, d> weight_; + const std::function<double(const I&)> intersection_diameter_; + std::unique_ptr<typename XT::Functions::GridFunction<E, d, d>::LocalFunctionType> local_weight_; + mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_values_; + mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_values_; +}; // BoundaryPenalty + + +} // namespace LocalIPDGIntegrands +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_LOCAL_INTEGRANDS_IPDG_HH diff --git a/dune/gdt/local/integrands/laplace-ipdg.hh b/dune/gdt/local/integrands/laplace-ipdg.hh new file mode 100644 index 0000000000000000000000000000000000000000..319451421ebeeb84dabd5631d93c89c83dd05290 --- /dev/null +++ b/dune/gdt/local/integrands/laplace-ipdg.hh @@ -0,0 +1,324 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#ifndef DUNE_GDT_LOCAL_INTEGRANDS_LAPLACE_IPDG_HH +#define DUNE_GDT_LOCAL_INTEGRANDS_LAPLACE_IPDG_HH + +#include <dune/xt/functions/grid-function.hh> + +#include "interfaces.hh" +#include "ipdg.hh" + +namespace Dune { +namespace GDT { +namespace LocalLaplaceIPDGIntegrands { + + +/** + * \note The role of symmetry_prefactor: + * * -1 => NIPDG + * * 0 => IIPDG + * * 1 => SIPDG + * \note The role of the weight: + * * symmetry_prefactor = 1 && weight_function = 1 => SIPDG + * * symmetry_prefactor = 1 && weight_function = diffusion => SWIPDG + */ +template <class I> +class InnerCoupling : public LocalQuaternaryIntersectionIntegrandInterface<I> +{ + using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I>; + using ThisType = InnerCoupling; + +public: + using BaseType::d; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::F; + using typename BaseType::IntersectionType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::LocalTestBasisType; + + InnerCoupling(const double& symmetry_prefactor, + XT::Functions::GridFunction<E, d, d> diffusion, + XT::Functions::GridFunction<E, d, d> weight_function = {1.}) + : BaseType(diffusion.parameter_type() + weight_function.parameter_type()) + , symmetry_prefactor_(symmetry_prefactor) + , diffusion_(diffusion) + , weight_(weight_function) + , local_diffusion_in_(diffusion_.local_function()) + , local_diffusion_out_(diffusion_.local_function()) + , local_weight_in_(weight_.local_function()) + , local_weight_out_(weight_.local_function()) + {} + + InnerCoupling(const ThisType& other) + : BaseType(other.parameter_type()) + , symmetry_prefactor_(other.symmetry_prefactor_) + , diffusion_(other.diffusion_) + , weight_(other.weight_) + , local_diffusion_in_(diffusion_.local_function()) + , local_diffusion_out_(diffusion_.local_function()) + , local_weight_in_(weight_.local_function()) + , local_weight_out_(weight_.local_function()) + {} + + InnerCoupling(ThisType&& source) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + +protected: + void post_bind(const IntersectionType& intrsctn) override final + { + DUNE_THROW_IF( + !intrsctn.neighbor(), Exceptions::integrand_error, "This integrand cannot be used on a boundary intersection!"); + const auto inside_element = intrsctn.inside(); + const auto outside_element = intrsctn.outside(); + local_diffusion_in_->bind(inside_element); + local_weight_in_->bind(inside_element); + local_diffusion_out_->bind(outside_element); + local_weight_out_->bind(outside_element); + } // ... post_bind(...) + +public: + int order(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const XT::Common::Parameter& param = {}) const override final + { + return std::max(local_diffusion_in_->order(param), local_diffusion_out_->order(param)) + + std::max(local_weight_in_->order(), local_weight_out_->order(param)) + + std::max(test_basis_inside.order(param), test_basis_outside.order(param)) + + std::max(ansatz_basis_inside.order(param), ansatz_basis_outside.order(param)); + } + + void evaluate(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const DomainType& point_in_reference_intersection, + DynamicMatrix<F>& result_in_in, + DynamicMatrix<F>& result_in_out, + DynamicMatrix<F>& result_out_in, + DynamicMatrix<F>& result_out_out, + const XT::Common::Parameter& param = {}) const override final + { + // Prepare sotrage, ... + this->ensure_size_and_clear_results(test_basis_inside, + ansatz_basis_inside, + test_basis_outside, + ansatz_basis_outside, + result_in_in, + result_in_out, + result_out_in, + result_out_out, + param); + // evaluate ... + const auto point_in_inside_reference_element = + this->intersection().geometryInInside().global(point_in_reference_intersection); + const auto point_in_outside_reference_element = + this->intersection().geometryInOutside().global(point_in_reference_intersection); + const auto normal = this->intersection().unitOuterNormal(point_in_reference_intersection); + // ... basis functions and ... + test_basis_inside.evaluate(point_in_inside_reference_element, test_basis_in_values_, param); + test_basis_inside.jacobians(point_in_inside_reference_element, test_basis_in_grads_, param); + test_basis_outside.evaluate(point_in_outside_reference_element, test_basis_out_values_, param); + test_basis_outside.jacobians(point_in_outside_reference_element, test_basis_out_grads_, param); + ansatz_basis_inside.evaluate(point_in_inside_reference_element, ansatz_basis_in_values_, param); + ansatz_basis_inside.jacobians(point_in_inside_reference_element, ansatz_basis_in_grads_, param); + ansatz_basis_outside.evaluate(point_in_outside_reference_element, ansatz_basis_out_values_, param); + ansatz_basis_outside.jacobians(point_in_outside_reference_element, ansatz_basis_out_grads_, param); + // ... data functions, ... + const auto diffusion_in = local_diffusion_in_->evaluate(point_in_inside_reference_element, param); + const auto diffusion_out = local_diffusion_out_->evaluate(point_in_outside_reference_element, param); + const auto weight_in = local_weight_in_->evaluate(point_in_inside_reference_element, param); + const auto weight_out = local_weight_out_->evaluate(point_in_outside_reference_element, param); + // compute the weighted mean ... + const auto delta_plus = normal * (weight_out * normal); + const auto delta_minus = normal * (weight_in * normal); + const auto weight_minus = delta_plus / (delta_plus + delta_minus); + const auto weight_plus = delta_minus / (delta_plus + delta_minus); + // ... and finally compute the integrand. + const size_t rows_in = test_basis_inside.size(param); + const size_t rows_out = test_basis_outside.size(param); + const size_t cols_in = ansatz_basis_inside.size(param); + const size_t cols_out = ansatz_basis_outside.size(param); + for (size_t ii = 0; ii < rows_in; ++ii) { + for (size_t jj = 0; jj < cols_in; ++jj) { + result_in_in[ii][jj] += + -1.0 * weight_minus * ((diffusion_in * ansatz_basis_in_grads_[jj][0]) * normal) * test_basis_in_values_[ii]; + result_in_in[ii][jj] += -1.0 * symmetry_prefactor_ * weight_minus * ansatz_basis_in_values_[jj] + * ((diffusion_in * test_basis_in_grads_[ii][0]) * normal); + } + for (size_t jj = 0; jj < cols_out; ++jj) { + result_in_out[ii][jj] += -1.0 * weight_plus * ((diffusion_out * ansatz_basis_out_grads_[jj][0]) * normal) + * test_basis_in_values_[ii]; + result_in_out[ii][jj] += symmetry_prefactor_ * weight_minus * ansatz_basis_out_values_[jj] + * ((diffusion_in * test_basis_in_grads_[ii][0]) * normal); + } + } + for (size_t ii = 0; ii < rows_out; ++ii) { + for (size_t jj = 0; jj < cols_in; ++jj) { + result_out_in[ii][jj] += + weight_minus * ((diffusion_in * ansatz_basis_in_grads_[jj][0]) * normal) * test_basis_out_values_[ii]; + result_out_in[ii][jj] += -1.0 * symmetry_prefactor_ * weight_plus * ansatz_basis_in_values_[jj] + * ((diffusion_out * test_basis_out_grads_[ii][0]) * normal); + } + for (size_t jj = 0; jj < cols_out; ++jj) { + result_out_out[ii][jj] += + weight_plus * ((diffusion_out * ansatz_basis_out_grads_[jj][0]) * normal) * test_basis_out_values_[ii]; + result_out_out[ii][jj] += symmetry_prefactor_ * weight_plus * ansatz_basis_out_values_[jj] + * ((diffusion_out * test_basis_out_grads_[ii][0]) * normal); + } + } + } // ... evaluate(...) + +private: + const double symmetry_prefactor_; + XT::Functions::GridFunction<E, d, d> diffusion_; + XT::Functions::GridFunction<E, d, d> weight_; + std::unique_ptr<typename XT::Functions::GridFunctionInterface<E, d, d>::LocalFunctionType> local_diffusion_in_; + std::unique_ptr<typename XT::Functions::GridFunctionInterface<E, d, d>::LocalFunctionType> local_diffusion_out_; + std::unique_ptr<typename XT::Functions::GridFunctionInterface<E, d, d>::LocalFunctionType> local_weight_in_; + std::unique_ptr<typename XT::Functions::GridFunctionInterface<E, d, d>::LocalFunctionType> local_weight_out_; + mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_in_values_; + mutable std::vector<typename LocalTestBasisType::DerivativeRangeType> test_basis_in_grads_; + mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_out_values_; + mutable std::vector<typename LocalTestBasisType::DerivativeRangeType> test_basis_out_grads_; + mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_in_values_; + mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> ansatz_basis_in_grads_; + mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_out_values_; + mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> ansatz_basis_out_grads_; +}; // InnerCoupling + + +/** + * \note The role of symmetry_prefactor: + * * -1 => NIPDG + * * 0 => IIPDG + * * 1 => SIPDG + * \note The role of the weight: + * * symmetry_prefactor = 1 && weight_function = 1 => SIPDG + * * symmetry_prefactor = 1 && weight_function = diffusion => SWIPDG + */ +template <class I> +class DirichletCoupling : public LocalQuaternaryIntersectionIntegrandInterface<I> +{ + using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I>; + using ThisType = DirichletCoupling; + +public: + using BaseType::d; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::F; + using typename BaseType::IntersectionType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::LocalTestBasisType; + + DirichletCoupling(const double& symmetry_prefactor, XT::Functions::GridFunction<E, d, d> diffusion) + : BaseType(diffusion.parameter_type()) + , symmetry_prefactor_(symmetry_prefactor) + , diffusion_(diffusion) + , local_diffusion_(diffusion_.local_function()) + {} + + DirichletCoupling(const ThisType& other) + : BaseType(other.parameter_type()) + , symmetry_prefactor_(other.symmetry_prefactor_) + , diffusion_(other.diffusion_) + , local_diffusion_(diffusion_.local_function()) + {} + + DirichletCoupling(ThisType&& source) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + +protected: + void post_bind(const IntersectionType& intersection) override final + { + const auto inside_element = intersection.inside(); + local_diffusion_->bind(inside_element); + } + +public: + int order(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& /*test_basis_outside*/, + const LocalAnsatzBasisType& /*ansatz_basis_outside*/, + const XT::Common::Parameter& param = {}) const override final + { + return local_diffusion_->order(param) + test_basis_inside.order(param) + ansatz_basis_inside.order(param); + } + + void evaluate(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const DomainType& point_in_reference_intersection, + DynamicMatrix<F>& result_in_in, + DynamicMatrix<F>& result_in_out, + DynamicMatrix<F>& result_out_in, + DynamicMatrix<F>& result_out_out, + const XT::Common::Parameter& param = {}) const override final + { + // Prepare sotrage, ... + this->ensure_size_and_clear_results(test_basis_inside, + ansatz_basis_inside, + test_basis_outside, + ansatz_basis_outside, + result_in_in, + result_in_out, + result_out_in, + result_out_out, + param); + // evaluate ... + const auto point_in_inside_reference_element = + this->intersection().geometryInInside().global(point_in_reference_intersection); + const auto normal = this->intersection().unitOuterNormal(point_in_reference_intersection); + // ... basis functions and ... + test_basis_inside.evaluate(point_in_inside_reference_element, test_basis_values_, param); + test_basis_inside.jacobians(point_in_inside_reference_element, test_basis_grads_, param); + ansatz_basis_inside.evaluate(point_in_inside_reference_element, ansatz_basis_values_, param); + ansatz_basis_inside.jacobians(point_in_inside_reference_element, ansatz_basis_grads_, param); + // ... data functions, ... + const auto diffusion = local_diffusion_->evaluate(point_in_inside_reference_element, param); + // ... and finally compute the integrand. + const size_t rows = test_basis_inside.size(param); + const size_t cols = ansatz_basis_inside.size(param); + for (size_t ii = 0; ii < rows; ++ii) + for (size_t jj = 0; jj < cols; ++jj) { + result_in_in[ii][jj] += -1.0 * ((diffusion * ansatz_basis_grads_[jj][0]) * normal) * test_basis_values_[ii]; + result_in_in[ii][jj] += + -1.0 * symmetry_prefactor_ * ansatz_basis_values_[jj] * ((diffusion * test_basis_grads_[ii][0]) * normal); + } + } // ... evaluate(...) + +private: + const double symmetry_prefactor_; + XT::Functions::GridFunction<E, d, d> diffusion_; + std::unique_ptr<typename XT::Functions::GridFunctionInterface<E, d, d>::LocalFunctionType> local_diffusion_; + mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_values_; + mutable std::vector<typename LocalTestBasisType::DerivativeRangeType> test_basis_grads_; + mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_values_; + mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> ansatz_basis_grads_; +}; // DirichletCoupling + + +} // namespace LocalLaplaceIPDGIntegrands +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_LOCAL_INTEGRANDS_LAPLACE_IPDG_HH diff --git a/dune/gdt/local/integrands/laplace.hh b/dune/gdt/local/integrands/laplace.hh new file mode 100644 index 0000000000000000000000000000000000000000..d7b6556af2bcbae3d9cd7464290a2ff171174962 --- /dev/null +++ b/dune/gdt/local/integrands/laplace.hh @@ -0,0 +1,112 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#ifndef DUNE_GDT_LOCAL_INTEGRANDS_LAPLACE_HH +#define DUNE_GDT_LOCAL_INTEGRANDS_LAPLACE_HH + +#include <dune/xt/common/memory.hh> +#include <dune/xt/la/container/eye-matrix.hh> +#include <dune/xt/functions/grid-function.hh> + +#include "interfaces.hh" + +namespace Dune { +namespace GDT { + + +/** + * Given a weight function kappa, computes `{[kappa(x) \nabla phi(x)] * \nabla psi(x)}` for all combinations of phi and + * psi in the bases. + */ +template <class E, size_t r = 1, class F = double> +class LocalLaplaceIntegrand : public LocalBinaryElementIntegrandInterface<E, r, 1, F, F, r, 1, F> +{ + using BaseType = LocalBinaryElementIntegrandInterface<E, r, 1, F, F, r, 1, F>; + using ThisType = LocalLaplaceIntegrand; + +public: + using BaseType::d; + using typename BaseType::DomainType; + using typename BaseType::ElementType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::LocalTestBasisType; + + explicit LocalLaplaceIntegrand( + XT::Functions::GridFunction<E, d, d, F> diffusion = XT::LA::eye_matrix<FieldMatrix<F, d, d>>(d, d)) + : BaseType() + , weight_(diffusion) + , local_weight_(weight_.local_function()) + {} + + LocalLaplaceIntegrand(const ThisType& other) + : BaseType(other.parameter_type()) + , weight_(other.weight_) + , local_weight_(weight_.local_function()) + {} + + LocalLaplaceIntegrand(ThisType&& source) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + +protected: + void post_bind(const ElementType& ele) override + { +#ifndef NDEBUG + if (!ele.geometry().affine()) + std::cerr << "Warning: integration order has to be increased for non-affine geometries!" << std::endl; +#endif + local_weight_->bind(ele); + } + +public: + int order(const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + const XT::Common::Parameter& param = {}) const override final + { + return local_weight_->order(param) + test_basis.order(param) + ansatz_basis.order(param); + } + + void evaluate(const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + const DomainType& point_in_reference_element, + DynamicMatrix<F>& result, + const XT::Common::Parameter& param = {}) const override final + { + // prepare storage + const size_t rows = test_basis.size(param); + const size_t cols = ansatz_basis.size(param); + if (result.rows() < rows || result.cols() < cols) + result.resize(rows, cols); + result *= 0; + // evaluate + test_basis.jacobians(point_in_reference_element, test_basis_grads_, param); + ansatz_basis.jacobians(point_in_reference_element, ansatz_basis_grads_, param); + const auto weight = local_weight_->evaluate(point_in_reference_element, param); + // compute elliptic evaluation + for (size_t ii = 0; ii < rows; ++ii) + for (size_t jj = 0; jj < cols; ++jj) + for (size_t rr = 0; rr < r; ++rr) + result[ii][jj] += (weight * ansatz_basis_grads_[jj][rr]) * test_basis_grads_[ii][rr]; + } // ... evaluate(...) + +private: + XT::Functions::GridFunction<E, d, d, F> weight_; + std::unique_ptr<typename XT::Functions::GridFunction<E, d, d, F>::LocalFunctionType> local_weight_; + mutable std::vector<typename LocalTestBasisType::DerivativeRangeType> test_basis_grads_; + mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> ansatz_basis_grads_; +}; // class LocalLaplaceIntegrand + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_LOCAL_INTEGRANDS_LAPLACE_HH diff --git a/dune/gdt/local/integrands/product.hh b/dune/gdt/local/integrands/product.hh index 8cb7c10970432005fcd9b45dc903b78996efd1d6..9507c4143c34cddb19be038e90e05a21193a8ebc 100644 --- a/dune/gdt/local/integrands/product.hh +++ b/dune/gdt/local/integrands/product.hh @@ -18,7 +18,7 @@ #include <dune/xt/functions/constant.hh> #include <dune/xt/functions/base/combined-functions.hh> #include <dune/xt/functions/base/combined-grid-functions.hh> -#include <dune/xt/functions/base/function-as-grid-function.hh> +#include <dune/xt/functions/grid-function.hh> #include <dune/xt/functions/interfaces/grid-function.hh> #include "interfaces.hh" @@ -28,16 +28,18 @@ namespace GDT { /** - * Given an inducing function f, computes `f(x) * phi(x) * psi(x)` for all combinations of phi and psi in the bases. + * Given an inducing function f (may be matrix-valued), computes `(f(x) * psi(x)) * phi(x)` for all combinations of phi + * in the ansatz basis and psi in the test basis. * * \note Note that f can also be given as a scalar value or omitted. + * \note Applying f to the ansatz basis can be done by passing f^T (the transposed of f) * * \sa local_binary_to_unary_element_integrand */ template <class E, size_t r = 1, class TR = double, class F = double, class AR = TR> class LocalElementProductIntegrand : public LocalBinaryElementIntegrandInterface<E, r, 1, TR, F, r, 1, AR> { - using ThisType = LocalElementProductIntegrand<E, r, TR, F, AR>; + using ThisType = LocalElementProductIntegrand; using BaseType = LocalBinaryElementIntegrandInterface<E, r, 1, TR, F, r, 1, AR>; public: @@ -47,60 +49,16 @@ public: using typename BaseType::LocalAnsatzBasisType; using typename BaseType::LocalTestBasisType; - using GridFunctionType = XT::Functions::GridFunctionInterface<E, r, r, F>; - - LocalElementProductIntegrand(const F& inducing_value = F(1)) - : BaseType() - , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, r, r, F>( - new XT::Functions::ProductFunction<XT::Functions::ConstantFunction<d, 1, 1, F>, - XT::Functions::ConstantFunction<d, r, r, F>>( - new XT::Functions::ConstantFunction<d, 1, 1, F>(inducing_value), - new XT::Functions::ConstantFunction<d, r, r, F>(XT::LA::eye_matrix<FieldMatrix<F, r, r>>(r))))) - , local_function_(inducing_function_.access().local_function()) - , test_basis_values_() - , ansatz_basis_values_() - {} - - LocalElementProductIntegrand(const XT::Functions::FunctionInterface<d, 1, 1, F>& inducing_function) - : BaseType() - , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, r, r, F>( - new XT::Functions::ProductFunction<XT::Functions::FunctionInterface<d, 1, 1, F>, - XT::Functions::ConstantFunction<d, r, r, F>>( - inducing_function, - new XT::Functions::ConstantFunction<d, r, r, F>(XT::LA::eye_matrix<FieldMatrix<F, r, r>>(r))))) - , local_function_(inducing_function_.access().local_function()) - , test_basis_values_() - , ansatz_basis_values_() - {} - - LocalElementProductIntegrand(const XT::Functions::GridFunctionInterface<E, 1, 1, F>& inducing_function) - : BaseType() - , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, r, r, F>( - new XT::Functions::ProductGridFunction<XT::Functions::GridFunctionInterface<E, 1, 1, F>, - XT::Functions::GridFunctionInterface<E, r, r, F>>( - inducing_function, - new XT::Functions::FunctionAsGridFunctionWrapper<E, r, r, F>( - new XT::Functions::ConstantFunction<d, r, r, F>(XT::LA::eye_matrix<FieldMatrix<F, r, r>>(r)))))) - , local_function_(inducing_function_.access().local_function()) - , test_basis_values_() - , ansatz_basis_values_() - {} - - template <class E_, typename = std::enable_if_t<std::is_same<E_, E>::value && r != 1, void>> - LocalElementProductIntegrand(const XT::Functions::GridFunctionInterface<E_, r, r, F>& inducing_function) + LocalElementProductIntegrand(XT::Functions::GridFunction<E, r, r, F> weight = {1.}) : BaseType() - , inducing_function_(inducing_function) - , local_function_(inducing_function_.access().local_function()) - , test_basis_values_() - , ansatz_basis_values_() + , weight_(weight) + , local_weight_(weight_.local_function()) {} LocalElementProductIntegrand(const ThisType& other) : BaseType(other.parameter_type()) - , inducing_function_(other.inducing_function_) - , local_function_(inducing_function_.access().local_function()) - , test_basis_values_() - , ansatz_basis_values_() + , weight_(other.weight_) + , local_weight_(weight_.local_function()) {} LocalElementProductIntegrand(ThisType&& source) = default; @@ -113,7 +71,7 @@ public: protected: void post_bind(const ElementType& ele) override final { - local_function_->bind(ele); + local_weight_->bind(ele); } public: @@ -121,7 +79,7 @@ public: const LocalAnsatzBasisType& ansatz_basis, const XT::Common::Parameter& param = {}) const override final { - return local_function_->order(param) + test_basis.order(param) + ansatz_basis.order(param); + return local_weight_->order(param) + test_basis.order(param) + ansatz_basis.order(param); } using BaseType::evaluate; @@ -140,23 +98,150 @@ public: // evaluate test_basis.evaluate(point_in_reference_element, test_basis_values_, param); ansatz_basis.evaluate(point_in_reference_element, ansatz_basis_values_, param); - const auto function_value = local_function_->evaluate(point_in_reference_element, param); + const auto weight = local_weight_->evaluate(point_in_reference_element, param); // compute product for (size_t ii = 0; ii < rows; ++ii) for (size_t jj = 0; jj < cols; ++jj) - result[ii][jj] = (function_value * test_basis_values_[ii]) * ansatz_basis_values_[jj]; + result[ii][jj] = (weight * test_basis_values_[ii]) * ansatz_basis_values_[jj]; } // ... evaluate(...) private: - const XT::Common::ConstStorageProvider<GridFunctionType> inducing_function_; - std::unique_ptr<typename GridFunctionType::LocalFunctionType> local_function_; + XT::Functions::GridFunction<E, r, r, F> weight_; + std::unique_ptr<typename XT::Functions::GridFunction<E, r, r, F>::LocalFunctionType> local_weight_; mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_values_; mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_values_; }; // class LocalElementProductIntegrand -/// \todo add LocalIntersectionProductIntegrand -/// +/** + * Given an inducing function f, computes `<f> * phi * psi` for all combinations of phi and psi in the bases, where + * `<f>` denotes the average of f evaluated on the inside and evaluated on the outside. + * + * \note Note that f can also be given as a scalar value or omitted. + */ +template <class I, size_t r = 1, class TR = double, class F = double, class AR = TR> +class LocalIntersectionProductIntegrand : public LocalQuaternaryIntersectionIntegrandInterface<I, r, 1, TR, F, r, 1, AR> +{ + using ThisType = LocalIntersectionProductIntegrand; + using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I, r, 1, TR, F, r, 1, AR>; + +public: + using BaseType::d; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::IntersectionType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::LocalTestBasisType; + + using GridFunctionType = XT::Functions::GridFunctionInterface<E, r, r, F>; + + LocalIntersectionProductIntegrand(XT::Functions::GridFunction<E, r, r, F> weight = {1.}) + : BaseType() + , weight_(weight) + , local_weight_in_(weight_.local_function()) + , local_weight_out_(weight_.local_function()) + {} + + LocalIntersectionProductIntegrand(const ThisType& other) + : BaseType(other.parameter_type()) + , weight_(other.weight_) + , local_weight_in_(weight_.local_function()) + , local_weight_out_(weight_.local_function()) + {} + + LocalIntersectionProductIntegrand(ThisType&& source) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + +protected: + void post_bind(const IntersectionType& intersct) override final + { + auto inside_element = intersct.inside(); + local_weight_in_->bind(inside_element); + if (intersct.neighbor()) { + local_weight_out_->bind(intersct.outside()); + } else + local_weight_out_->bind(intersct.inside()); + } // ... post_bind(...) + +public: + int order(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const XT::Common::Parameter& param = {}) const override final + { + return std::max(local_weight_in_->order(param), local_weight_out_->order(param)) + + std::max(test_basis_inside.order(param), test_basis_outside.order(param)) + + std::max(ansatz_basis_inside.order(param), ansatz_basis_outside.order(param)); + } + + using BaseType::evaluate; + + void evaluate(const LocalTestBasisType& test_basis_inside, + const LocalAnsatzBasisType& ansatz_basis_inside, + const LocalTestBasisType& test_basis_outside, + const LocalAnsatzBasisType& ansatz_basis_outside, + const DomainType& point_in_reference_intersection, + DynamicMatrix<F>& result_in_in, + DynamicMatrix<F>& result_in_out, + DynamicMatrix<F>& result_out_in, + DynamicMatrix<F>& result_out_out, + const XT::Common::Parameter& param = {}) const override final + { + // prepare sotrage + const size_t rows_in = test_basis_inside.size(param); + const size_t rows_out = test_basis_outside.size(param); + const size_t cols_in = ansatz_basis_inside.size(param); + const size_t cols_out = ansatz_basis_outside.size(param); + const auto ensure_size = [](auto& m, const auto& rws, const auto& cls) { + if (m.rows() < rws || m.cols() < cls) + m.resize(rws, cls); + }; + ensure_size(result_in_in, rows_in, cols_in); + ensure_size(result_in_out, rows_in, cols_out); + ensure_size(result_out_in, rows_out, cols_in); + ensure_size(result_out_out, rows_out, cols_out); + // evaluate + const auto point_in_inside_reference_element = + this->intersection().geometryInInside().global(point_in_reference_intersection); + test_basis_inside.evaluate(point_in_inside_reference_element, test_basis_in_values_, param); + ansatz_basis_inside.evaluate(point_in_inside_reference_element, ansatz_basis_in_values_, param); + const auto weight_in = local_weight_in_->evaluate(point_in_inside_reference_element, param); + const auto point_in_outside_reference_element = + this->intersection().geometryInOutside().global(point_in_reference_intersection); + test_basis_outside.evaluate(point_in_outside_reference_element, test_basis_out_values_, param); + ansatz_basis_outside.evaluate(point_in_outside_reference_element, ansatz_basis_out_values_, param); + const auto weight_out = local_weight_out_->evaluate(point_in_outside_reference_element, param); + // compute integrand + const auto average_function_value = (weight_in + weight_out) * 0.5; + for (size_t ii = 0; ii < rows_in; ++ii) { + for (size_t jj = 0; jj < cols_in; ++jj) + result_in_in[ii][jj] = (average_function_value * ansatz_basis_in_values_[jj]) * test_basis_in_values_[ii]; + for (size_t jj = 0; jj < cols_out; ++jj) + result_in_out[ii][jj] = (average_function_value * ansatz_basis_out_values_[jj]) * test_basis_in_values_[ii]; + } + for (size_t ii = 0; ii < rows_out; ++ii) { + for (size_t jj = 0; jj < cols_in; ++jj) + result_out_in[ii][jj] = (average_function_value * ansatz_basis_in_values_[jj]) * test_basis_out_values_[ii]; + for (size_t jj = 0; jj < cols_out; ++jj) + result_out_out[ii][jj] = (average_function_value * ansatz_basis_out_values_[jj]) * test_basis_out_values_[ii]; + } + } // ... evaluate(...) + +private: + XT::Functions::GridFunction<E, r, r, F> weight_; + std::unique_ptr<typename XT::Functions::GridFunction<E, r, r, F>::LocalFunctionType> local_weight_in_; + std::unique_ptr<typename XT::Functions::GridFunction<E, r, r, F>::LocalFunctionType> local_weight_out_; + mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_in_values_; + mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_out_values_; + mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_in_values_; + mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_out_values_; +}; // class LocalIntersectionProductIntegrand + } // namespace GDT } // namespace Dune diff --git a/dune/gdt/local/integrands/symmetrized-laplace.hh b/dune/gdt/local/integrands/symmetrized-laplace.hh new file mode 100644 index 0000000000000000000000000000000000000000..97792ac1f7762b09dbbebbc889481cd0374520f2 --- /dev/null +++ b/dune/gdt/local/integrands/symmetrized-laplace.hh @@ -0,0 +1,136 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2014, 2016 - 2018) + +#ifndef DUNE_GDT_LOCAL_INTEGRANDS_SYMMETRIZED_LAPLACE_HH +#define DUNE_GDT_LOCAL_INTEGRANDS_SYMMETRIZED_LAPLACE_HH + +#include <dune/xt/common/memory.hh> +#include <dune/xt/la/container/eye-matrix.hh> +#include <dune/xt/functions/base/function-as-grid-function.hh> +#include <dune/xt/functions/constant.hh> +#include <dune/xt/functions/interfaces/grid-function.hh> + +#include "interfaces.hh" + +namespace Dune { +namespace GDT { + + +/** + * Given an inducing scalar function lambda computes + * `lambda(x) * 1/2*(\nabla phi(x) + (\nabla phi(x))^T) : \nabla psi(x)` for all combinations of phi in the ansatz and + * psi in the test basis. Here, ':' denotes the (matrix) scalar product. + */ +template <class E, class F = double> +class LocalSymmetrizedLaplaceIntegrand + : public LocalBinaryElementIntegrandInterface<E, E::dimension, 1, F, F, E::dimension, 1, F> +{ + + using BaseType = LocalBinaryElementIntegrandInterface<E, E::dimension, 1, F, F, E::dimension, 1, F>; + using ThisType = LocalSymmetrizedLaplaceIntegrand; + +public: + using BaseType::d; + static constexpr size_t r = d; + using typename BaseType::DomainType; + using typename BaseType::ElementType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::LocalTestBasisType; + + using DiffusionFactorType = XT::Functions::GridFunctionInterface<E, 1, 1, F>; + + LocalSymmetrizedLaplaceIntegrand(const F& diffusion_factor = F(1)) + : BaseType() + , diffusion_factor_(new XT::Functions::FunctionAsGridFunctionWrapper<E, 1, 1, F>( + new XT::Functions::ConstantFunction<d, 1, 1, F>(diffusion_factor))) + , local_diffusion_factor_(diffusion_factor_.access().local_function()) + {} + + LocalSymmetrizedLaplaceIntegrand(const XT::Functions::FunctionInterface<d, 1, 1, F>& diffusion_factor) + : BaseType(diffusion_factor.parameter_type()) + , diffusion_factor_(new XT::Functions::FunctionAsGridFunctionWrapper<E, 1, 1, F>(diffusion_factor)) + , local_diffusion_factor_(diffusion_factor_.access().local_function()) + {} + + LocalSymmetrizedLaplaceIntegrand(const DiffusionFactorType& diffusion_factor) + : BaseType(diffusion_factor.parameter_type()) + , diffusion_factor_(diffusion_factor) + , local_diffusion_factor_(diffusion_factor_.access().local_function()) + {} + + LocalSymmetrizedLaplaceIntegrand(const ThisType& other) + : BaseType(other.parameter_type()) + , diffusion_factor_(other.diffusion_factor_) + , local_diffusion_factor_(diffusion_factor_.access().local_function()) + {} + + LocalSymmetrizedLaplaceIntegrand(ThisType&& source) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + +protected: + void post_bind(const ElementType& ele) override + { + local_diffusion_factor_->bind(ele); + } + +public: + int order(const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + const XT::Common::Parameter& param = {}) const override final + { + return local_diffusion_factor_->order(param) + test_basis.order(param) + ansatz_basis.order(param); + } + + void evaluate(const LocalTestBasisType& test_basis, + const LocalAnsatzBasisType& ansatz_basis, + const DomainType& point_in_reference_element, + DynamicMatrix<F>& result, + const XT::Common::Parameter& param = {}) const override final + { + // prepare storage + const size_t rows = test_basis.size(param); + const size_t cols = ansatz_basis.size(param); + if (result.rows() < rows || result.cols() < cols) + result.resize(rows, cols); + result *= 0; + // evaluate + test_basis.jacobians(point_in_reference_element, test_basis_grads_, param); + ansatz_basis.jacobians(point_in_reference_element, ansatz_basis_grads_, param); + const auto diffusion = local_diffusion_factor_->evaluate(point_in_reference_element, param); + symmetric_ansatz_basis_grads_.resize(cols); + for (size_t jj = 0; jj < cols; ++jj) + for (size_t rr = 0; rr < r; ++rr) + for (size_t cc = 0; cc < d; ++cc) + symmetric_ansatz_basis_grads_[jj][rr][cc] = + 0.5 * (ansatz_basis_grads_[jj][rr][cc] + ansatz_basis_grads_[jj][cc][rr]); + // compute elliptic evaluation + for (size_t ii = 0; ii < rows; ++ii) + for (size_t jj = 0; jj < cols; ++jj) + for (size_t rr = 0; rr < r; ++rr) + for (size_t cc = 0; cc < d; ++cc) + result[ii][jj] += symmetric_ansatz_basis_grads_[jj][rr][cc] * test_basis_grads_[ii][rr][cc] * diffusion; + } // ... evaluate(...) + +private: + const XT::Common::ConstStorageProvider<DiffusionFactorType> diffusion_factor_; + std::unique_ptr<typename DiffusionFactorType::LocalFunctionType> local_diffusion_factor_; + mutable std::vector<typename LocalTestBasisType::DerivativeRangeType> test_basis_grads_; + mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> ansatz_basis_grads_; + mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> symmetric_ansatz_basis_grads_; +}; // class LocalSymmetrizedLaplaceIntegrand + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_LOCAL_INTEGRANDS_SYMMETRIZED_LAPLACE_HH diff --git a/dune/gdt/local/numerical-fluxes/engquist-osher.hh b/dune/gdt/local/numerical-fluxes/engquist-osher.hh index 29f5f18b0d11bb09fcf37e14fe78811d8be85df4..c308728f9db67f1a91b97daf29a50094b8226eba 100644 --- a/dune/gdt/local/numerical-fluxes/engquist-osher.hh +++ b/dune/gdt/local/numerical-fluxes/engquist-osher.hh @@ -23,32 +23,39 @@ namespace Dune { namespace GDT { -template <size_t d, size_t m = 1, class R = double> -class NumericalEngquistOsherFlux : public internal::ThisNumericalFluxIsNotAvailableForTheseDimensions<d, m, R> +template <class I, size_t d, size_t m = 1, class R = double> +class NumericalEngquistOsherFlux : public internal::ThisNumericalFluxIsNotAvailableForTheseDimensions<I, d, m, R> { public: template <class... Args> explicit NumericalEngquistOsherFlux(Args&&... /*args*/) - : internal::ThisNumericalFluxIsNotAvailableForTheseDimensions<d, m, R>() + : internal::ThisNumericalFluxIsNotAvailableForTheseDimensions<I, d, m, R>() {} }; -template <size_t d, class R> -class NumericalEngquistOsherFlux<d, 1, R> : public NumericalFluxInterface<d, 1, R> +template <class I, size_t d, class R> +class NumericalEngquistOsherFlux<I, d, 1, R> : public NumericalFluxInterface<I, d, 1, R> { static const constexpr size_t m = 1; - using ThisType = NumericalEngquistOsherFlux<d, m, R>; - using BaseType = NumericalFluxInterface<d, m, R>; + using ThisType = NumericalEngquistOsherFlux; + using BaseType = NumericalFluxInterface<I, d, m, R>; public: using typename BaseType::FluxType; + using typename BaseType::LocalFluxType; + using typename BaseType::LocalIntersectionCoords; using typename BaseType::PhysicalDomainType; - using typename BaseType::StateRangeType; + using typename BaseType::StateType; + using typename BaseType::XIndependentFluxType; NumericalEngquistOsherFlux(const FluxType& flx) : BaseType(flx) {} + NumericalEngquistOsherFlux(const XIndependentFluxType& flx) + : BaseType(flx) + {} + NumericalEngquistOsherFlux(const ThisType& other) = default; std::unique_ptr<BaseType> copy() const override final @@ -58,38 +65,61 @@ public: using BaseType::apply; - StateRangeType apply(const StateRangeType& u, - const StateRangeType& v, - const PhysicalDomainType& n, - const XT::Common::Parameter& param = {}) const override final + StateType apply(const LocalIntersectionCoords& x_in_intersection_coords, + const StateType& u, + const StateType& v, + const PhysicalDomainType& n, + const XT::Common::Parameter& param = {}) const override final { - auto integrate_f = [&](const auto& s, const std::function<double(const R&, const R&)>& min_max) { + this->compute_entity_coords(x_in_intersection_coords); + auto integrate_f = [&](const LocalFluxType& local_flux, + const auto& x, + const auto& s, + const std::function<double(const R&, const R&)>& min_max) { if (!(s[0] > 0.)) return 0.; double ret = 0.; const OneDGrid state_grid(1, 0., s[0]); const auto state_interval = *state_grid.leafGridView().template begin<0>(); - for (const auto& quadrature_point : - QuadratureRules<R, 1>::rule(state_interval.type(), this->flux().order(param))) { + for (const auto& quadrature_point : QuadratureRules<R, 1>::rule(state_interval.type(), local_flux.order(param))) { const auto local_uu = quadrature_point.position(); const auto uu = state_interval.geometry().global(local_uu); - const auto df = this->flux().jacobian(uu, param); + const auto df = local_flux.jacobian(x, uu, param); ret += state_interval.geometry().integrationElement(local_uu) * quadrature_point.weight() * min_max(n * df, 0.); } return ret; }; - return (this->flux().evaluate(0., param) * n) - + integrate_f(u, [](const double& a, const double& b) { return std::max(a, b); }) - + integrate_f(v, [](const double& a, const double& b) { return std::min(a, b); }); + return (local_flux_inside_->evaluate(x_in_inside_coords_, 0., param) * n) + + integrate_f(*local_flux_inside_, + x_in_inside_coords_, + u, + [](const double& a, const double& b) { return std::max(a, b); }) + + integrate_f(this->intersection().neighbor() ? *local_flux_outside_ : *local_flux_inside_, + x_in_outside_coords_, + v, + [](const double& a, const double& b) { return std::min(a, b); }); } + +private: + using BaseType::local_flux_inside_; + using BaseType::local_flux_outside_; + using BaseType::x_in_inside_coords_; + using BaseType::x_in_outside_coords_; }; // class NumericalEngquistOsherFlux -template <size_t d, size_t m, class R> -NumericalEngquistOsherFlux<d, m, R> +template <class I, size_t d, size_t m, class R> +NumericalEngquistOsherFlux<I, d, m, R> +make_numerical_engquist_osher_flux(const XT::Functions::FluxFunctionInterface<I, m, d, m, R>& flux) +{ + return NumericalEngquistOsherFlux<I, d, m, R>(flux); +} + +template <class I, size_t d, size_t m, class R> +NumericalEngquistOsherFlux<I, d, m, R> make_numerical_engquist_osher_flux(const XT::Functions::FunctionInterface<m, d, m, R>& flux) { - return NumericalEngquistOsherFlux<d, m, R>(flux); + return NumericalEngquistOsherFlux<I, d, m, R>(flux); } diff --git a/dune/gdt/local/numerical-fluxes/generic.hh b/dune/gdt/local/numerical-fluxes/generic.hh index faf584fa59d42f57cbf3885979074722095fa0a6..519e46f4d6bef0a0dfccf57d053e4e9000980795 100644 --- a/dune/gdt/local/numerical-fluxes/generic.hh +++ b/dune/gdt/local/numerical-fluxes/generic.hh @@ -22,25 +22,38 @@ namespace GDT { /** * \brief Implementation of NumericalFluxInterface for a given lambda expression. */ -template <size_t d, size_t m = 1, class R = double> -class GenericNumericalFlux : public NumericalFluxInterface<d, m, R> +template <class I, size_t d, size_t m = 1, class R = double> +class GenericNumericalFlux : public NumericalFluxInterface<I, d, m, R> { - using ThisType = GenericNumericalFlux<d, m, R>; - using BaseType = NumericalFluxInterface<d, m, R>; + using ThisType = GenericNumericalFlux; + using BaseType = NumericalFluxInterface<I, d, m, R>; public: using typename BaseType::FluxType; + using typename BaseType::LocalIntersectionCoords; using typename BaseType::PhysicalDomainType; - using typename BaseType::StateRangeType; + using typename BaseType::StateType; + using typename BaseType::XIndependentFluxType; - using GenericFunctionType = std::function<StateRangeType( - const StateRangeType&, const StateRangeType&, const PhysicalDomainType&, const XT::Common::Parameter&)>; + using GenericFunctionType = std::function<StateType(const I&, + const LocalIntersectionCoords&, + const StateType&, + const StateType&, + const PhysicalDomainType&, + const XT::Common::Parameter&)>; GenericNumericalFlux(const FluxType& flx, GenericFunctionType func, const XT::Common::ParameterType& param_type = {}) : BaseType(flx, param_type) , numerical_flux_(func) {} + GenericNumericalFlux(const XIndependentFluxType& flx, + GenericFunctionType func, + const XT::Common::ParameterType& param_type = {}) + : BaseType(flx, param_type) + , numerical_flux_(func) + {} + std::unique_ptr<BaseType> copy() const override final { return std::make_unique<ThisType>(*this); @@ -48,12 +61,13 @@ public: using BaseType::apply; - StateRangeType apply(const StateRangeType& u, - const StateRangeType& v, - const PhysicalDomainType& n, - const XT::Common::Parameter& param = {}) const override final + StateType apply(const LocalIntersectionCoords& x, + const StateType& u, + const StateType& v, + const PhysicalDomainType& n, + const XT::Common::Parameter& param = {}) const override final { - return numerical_flux_(u, v, n, this->parse_parameter(param)); + return numerical_flux_(this->intersection(), x, u, v, n, this->parse_parameter(param)); } private: @@ -61,13 +75,22 @@ private: }; // class GenericNumericalFlux -template <size_t d, size_t m, class R> -GenericNumericalFlux<d, m, R> +template <class I, size_t d, size_t m, class R> +GenericNumericalFlux<I, d, m, R> +make_generic_numerical_flux(const XT::Functions::FluxFunctionInterface<I, m, d, m, R>& flux, + typename GenericNumericalFlux<I, d, m, R>::GenericFunctionType func, + const XT::Common::ParameterType& param_type = {}) +{ + return GenericNumericalFlux<I, d, m, R>(flux, func, param_type); +} + +template <class I, size_t d, size_t m, class R> +GenericNumericalFlux<I, d, m, R> make_generic_numerical_flux(const XT::Functions::FunctionInterface<m, d, m, R>& flux, - typename GenericNumericalFlux<d, m, R>::GenericFunctionType func, + typename GenericNumericalFlux<I, d, m, R>::GenericFunctionType func, const XT::Common::ParameterType& param_type = {}) { - return GenericNumericalFlux<d, m, R>(flux, func, param_type); + return GenericNumericalFlux<I, d, m, R>(flux, func, param_type); } diff --git a/dune/gdt/local/numerical-fluxes/interface.hh b/dune/gdt/local/numerical-fluxes/interface.hh index 136dc3e2e11aab61cd573eff132b8a1cec7c2612..542163b7459ab1bded531eb462cc6501b36e0d90 100644 --- a/dune/gdt/local/numerical-fluxes/interface.hh +++ b/dune/gdt/local/numerical-fluxes/interface.hh @@ -15,6 +15,7 @@ #include <dune/xt/common/memory.hh> #include <dune/xt/la/container/vector-interface.hh> #include <dune/xt/functions/constant.hh> +#include <dune/xt/functions/interfaces/flux-function.hh> #include <dune/xt/functions/interfaces/function.hh> #include <dune/gdt/exceptions.hh> @@ -24,28 +25,63 @@ namespace GDT { /** - * Given the sought solution of a system of m conservation laws, u: R^d -> R^m, and d flux functions f_s: R^m -> R^m, - * for 1 <= s <= d (modelled by the flux f: R^m -> R^{d x m}), the purpose of a numerical flux - * g: R^m x R^m x R^d -> R^m is to approximate f(.) * n, e.g., g(u, u, n) = f(u) * n. + * Given the sought solution of a system of m conservation laws, u: R^d -> R^m, and d flux + * functions f_s: R^d x R^m -> R^m, for 1 <= s <= d (modelled by the + * flux f: R^d x R^m -> R^{d x m}), the purpose of a numerical flux + * g: R^m x R^m x R^d -> R^m is to approximate f(.) * n, e.g., g(x, u, u, n) = f(x, u) * n. */ -template <size_t d, size_t m = 1, class R = double> -class NumericalFluxInterface : public XT::Common::ParametricInterface +template <class Intersection, size_t d, size_t m = 1, class R = double> +class NumericalFluxInterface + : public XT::Grid::IntersectionBoundObject<Intersection> + , public XT::Common::ParametricInterface { - using ThisType = NumericalFluxInterface<d, m, R>; + using ThisType = NumericalFluxInterface; public: - using FluxType = XT::Functions::FunctionInterface<m, d, m, R>; - using PhysicalDomainType = FieldVector<double, d>; - using StateRangeType = typename FluxType::DomainType; + using I = Intersection; + using E = typename I::Entity; + using FluxType = XT::Functions::FluxFunctionInterface<E, m, d, m, R>; + using LocalFluxType = typename FluxType::LocalFunctionType; + using XIndependentFluxType = XT::Functions::FunctionInterface<m, d, m, R>; + using FluxWrapperType = XT::Functions::StateFunctionAsFluxFunctionWrapper<E, m, d, m, R>; + using PhysicalDomainType = typename FluxType::DomainType; + using LocalIntersectionCoords = FieldVector<typename I::ctype, d - 1>; + using StateType = typename FluxType::StateType; NumericalFluxInterface(const FluxType& flx, const XT::Common::ParameterType& param_type = {}) : XT::Common::ParametricInterface(param_type + flx.parameter_type()) , flux_(flx) + , local_flux_inside_(flux_.access().local_function()) + , local_flux_outside_(flux_.access().local_function()) {} NumericalFluxInterface(FluxType*&& flx_ptr, const XT::Common::ParameterType& param_type = {}) : XT::Common::ParametricInterface(param_type + flx_ptr->parameter_type()) , flux_(flx_ptr) + , local_flux_inside_(flux_.access().local_function()) + , local_flux_outside_(flux_.access().local_function()) + {} + + NumericalFluxInterface(const XIndependentFluxType& func, const XT::Common::ParameterType& param_type = {}) + : XT::Common::ParametricInterface(param_type + func.parameter_type()) + , flux_(new FluxWrapperType(func)) + , local_flux_inside_(flux_.access().local_function()) + , local_flux_outside_(flux_.access().local_function()) + {} + + NumericalFluxInterface(XIndependentFluxType*&& func_ptr, const XT::Common::ParameterType& param_type = {}) + : XT::Common::ParametricInterface(param_type + func_ptr->parameter_type()) + , flux_(new FluxWrapperType(func_ptr)) + , local_flux_inside_(flux_.access().local_function()) + , local_flux_outside_(flux_.access().local_function()) + {} + + NumericalFluxInterface(const ThisType& other) + : XT::Grid::IntersectionBoundObject<Intersection>(other) + , XT::Common::ParametricInterface(other) + , flux_(other.flux_) + , local_flux_inside_(flux_.access().local_function()) + , local_flux_outside_(flux_.access().local_function()) {} virtual std::unique_ptr<ThisType> copy() const = 0; @@ -55,45 +91,54 @@ public: return false; } + virtual bool x_dependent() const + { + return flux_.access().x_dependent(); + } + const FluxType& flux() const { return flux_.access(); } - virtual StateRangeType apply(const StateRangeType& u, - const StateRangeType& v, - const PhysicalDomainType& n, - const XT::Common::Parameter& param = {}) const = 0; + virtual StateType apply(const LocalIntersectionCoords& x_in_local_intersection_coords, + const StateType& u, + const StateType& v, + const PhysicalDomainType& n, + const XT::Common::Parameter& param = {}) const = 0; template <class V> - StateRangeType apply(const StateRangeType& u, - const XT::LA::VectorInterface<V>& v, - const PhysicalDomainType& n, - const XT::Common::Parameter& param = {}) const + StateType apply(const LocalIntersectionCoords x_in_local_intersection_coords, + const StateType& u, + const XT::LA::VectorInterface<V>& v, + const PhysicalDomainType& n, + const XT::Common::Parameter& param = {}) const { DUNE_THROW_IF(v.size() != m, Exceptions::numerical_flux_error, "v.size() = " << v.size() << "\n m = " << m); for (size_t ii = 0; ii < m; ++ii) v_[ii] = v[ii]; - return this->apply(u, v_, n, param); + return this->apply(x_in_local_intersection_coords, u, v_, n, param); } template <class U> - StateRangeType apply(const XT::LA::VectorInterface<U>& u, - const StateRangeType& v, - const PhysicalDomainType& n, - const XT::Common::Parameter& param = {}) const + StateType apply(const LocalIntersectionCoords x_in_local_intersection_coords, + const XT::LA::VectorInterface<U>& u, + const StateType& v, + const PhysicalDomainType& n, + const XT::Common::Parameter& param = {}) const { DUNE_THROW_IF(u.size() != m, Exceptions::numerical_flux_error, "u.size() = " << u.size() << "\n m = " << m); for (size_t ii = 0; ii < m; ++ii) u_[ii] = u[ii]; - return this->apply(u_, v, n, param); + return this->apply(x_in_local_intersection_coords, u_, v, n, param); } template <class U, class V> - StateRangeType apply(const XT::LA::VectorInterface<U>& u, - const XT::LA::VectorInterface<V>& v, - const PhysicalDomainType& n, - const XT::Common::Parameter& param = {}) const + StateType apply(const LocalIntersectionCoords x_in_local_intersection_coords, + const XT::LA::VectorInterface<U>& u, + const XT::LA::VectorInterface<V>& v, + const PhysicalDomainType& n, + const XT::Common::Parameter& param = {}) const { DUNE_THROW_IF(u.size() != m, Exceptions::numerical_flux_error, "u.size() = " << u.size() << "\n m = " << m); DUNE_THROW_IF(v.size() != m, Exceptions::numerical_flux_error, "v.size() = " << v.size() << "\n m = " << m); @@ -101,28 +146,59 @@ public: u_[ii] = u[ii]; v_[ii] = v[ii]; } - return this->apply(u_, v_, n, param); + return this->apply(x_in_local_intersection_coords, u_, v_, n, param); } // ... apply(...) + using XT::Grid::IntersectionBoundObject<I>::intersection; + private: const XT::Common::ConstStorageProvider<FluxType> flux_; - mutable StateRangeType u_; - mutable StateRangeType v_; + mutable StateType u_; + mutable StateType v_; + +protected: + void post_bind(const I& inter) override + { + local_flux_inside_->bind(inter.inside()); + if (inter.neighbor()) + local_flux_outside_->bind(inter.outside()); + } + + void compute_entity_coords(const LocalIntersectionCoords& x_in_local_intersection_coords) const + { + if (this->x_dependent()) { + if (!this->is_bound_) + DUNE_THROW(Dune::InvalidStateException, "You have to call bind(intersection) before calling this function!"); + x_in_inside_coords_ = + intersection().inside().geometry().local(intersection().geometry().global(x_in_local_intersection_coords)); + if (intersection().neighbor()) + x_in_outside_coords_ = + intersection().outside().geometry().local(intersection().geometry().global(x_in_local_intersection_coords)); + else + x_in_outside_coords_ = x_in_inside_coords_; + } + } + + mutable std::unique_ptr<LocalFluxType> local_flux_inside_; + mutable std::unique_ptr<LocalFluxType> local_flux_outside_; + mutable PhysicalDomainType x_in_inside_coords_; + mutable PhysicalDomainType x_in_outside_coords_; }; // class NumericalFluxInterface namespace internal { -template <size_t d, size_t m = 1, class R = double> -class ThisNumericalFluxIsNotAvailableForTheseDimensions : public NumericalFluxInterface<d, m, R> +template <class Intersection, size_t d, size_t m = 1, class R = double> +class ThisNumericalFluxIsNotAvailableForTheseDimensions : public NumericalFluxInterface<Intersection, d, m, R> { - using ThisType = ThisNumericalFluxIsNotAvailableForTheseDimensions<d, m, R>; - using BaseType = NumericalFluxInterface<d, m, R>; + using BaseType = NumericalFluxInterface<Intersection, d, m, R>; public: + using typename BaseType::I; + using typename BaseType::LocalIntersectionCoords; using typename BaseType::PhysicalDomainType; - using typename BaseType::StateRangeType; + using typename BaseType::StateType; template <class... Args> explicit ThisNumericalFluxIsNotAvailableForTheseDimensions(Args&&... /*args*/) @@ -145,13 +221,14 @@ public: using BaseType::apply; - StateRangeType apply(const StateRangeType& /*u*/, - const StateRangeType& /*v*/, - const PhysicalDomainType& /*n*/, - const XT::Common::Parameter& /*param*/ = {}) const override final + StateType apply(const LocalIntersectionCoords& /*x_in_local_intersection_coords*/, + const StateType& /*u*/, + const StateType& /*v*/, + const PhysicalDomainType& /*n*/, + const XT::Common::Parameter& /*param*/ = {}) const override final { DUNE_THROW(Exceptions::numerical_flux_error, "d = " << d << "\n m = " << m); - return StateRangeType(); + return StateType(); } }; // class ThisNumericalFluxIsNotAvailableForTheseDimensions diff --git a/dune/gdt/local/numerical-fluxes/kinetic.hh b/dune/gdt/local/numerical-fluxes/kinetic.hh new file mode 100644 index 0000000000000000000000000000000000000000..6be4120470c38502e5301f94410b845596039df6 --- /dev/null +++ b/dune/gdt/local/numerical-fluxes/kinetic.hh @@ -0,0 +1,151 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2018) +// René Fritze (2018) + +#ifndef DUNE_GDT_LOCAL_NUMERICAL_FLUXES_KINETIC_HH +#define DUNE_GDT_LOCAL_NUMERICAL_FLUXES_KINETIC_HH + +#include <dune/xt/la/container.hh> + +#include <dune/gdt/test/momentmodels/basisfunctions.hh> +#include <dune/gdt/test/momentmodels/entropyflux.hh> + +#include "interface.hh" + +namespace Dune { +namespace GDT { + + +template <class GV, class MomentBasis, class EntropyFluxImp = EntropyBasedFluxFunction<GV, MomentBasis>> +class NumericalKineticFlux + : public NumericalFluxInterface<XT::Grid::extract_intersection_t<GV>, + MomentBasis::dimFlux, + MomentBasis::dimRange, + typename MomentBasis::RangeFieldType> +{ + static_assert(std::is_base_of<MomentBasisInterface<typename MomentBasis::D, + MomentBasis::d, + typename MomentBasis::R, + MomentBasis::r, + MomentBasis::rC, + MomentBasis::d_flux, + MomentBasis::entropy>, + MomentBasis>::value, + "Basisfunctions have to be derived from MomentBasisInterface"); + static const size_t d = MomentBasis::dimFlux; + static const size_t m = MomentBasis::r; + using R = typename MomentBasis::R; + using I = XT::Grid::extract_intersection_t<GV>; + using ThisType = NumericalKineticFlux; + using BaseType = NumericalFluxInterface<I, d, m, R>; + using EntropyFluxType = EntropyFluxImp; + using SparseMatrixType = typename XT::LA::CommonSparseMatrix<R>; + +public: + using typename BaseType::FluxType; + using typename BaseType::LocalIntersectionCoords; + using typename BaseType::PhysicalDomainType; + using typename BaseType::StateType; + using typename BaseType::XIndependentFluxType; + + NumericalKineticFlux(const FluxType& flx, const MomentBasis& basis) + : BaseType(flx) + , basis_(basis) + {} + + NumericalKineticFlux(const XIndependentFluxType& flx, const MomentBasis& basis) + : BaseType(flx) + , basis_(basis) + {} + + NumericalKineticFlux(const ThisType& other) = default; + + std::unique_ptr<BaseType> copy() const override final + { + return std::make_unique<ThisType>(*this); + } + + using BaseType::apply; + using BaseType::flux; + using BaseType::intersection; + + StateType apply(const LocalIntersectionCoords& /*x*/, + const StateType& u, + const StateType& v, + const PhysicalDomainType& n, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + // find direction of unit outer normal (we assume an axis-aligned cube grid) + size_t direction = intersection().indexInInside() / 2; + if (dynamic_cast<const EntropyFluxType*>(&flux()) != nullptr) { + auto ret = dynamic_cast<const EntropyFluxType*>(&flux())->evaluate_kinetic_flux( + intersection().inside(), + intersection().neighbor() ? intersection().outside() : intersection().inside(), + u, + v, + n, + direction); + for (auto&& entry : ret) + if (std::isnan(entry) || std::isinf(entry)) + DUNE_THROW(Dune::MathError, "NaN or inf in kinetic flux"); + return ret; + } else { + static const auto flux_matrices = initialize_flux_matrices(basis_); + StateType ret(0); + auto tmp_vec = ret; + const auto& inner_flux_matrix = flux_matrices[direction][n[direction] > 0 ? 1 : 0]; + const auto& outer_flux_matrix = flux_matrices[direction][n[direction] > 0 ? 0 : 1]; + inner_flux_matrix.mv(u, tmp_vec); + outer_flux_matrix.mv(v, ret); + ret += tmp_vec; + ret *= n[direction]; + return ret; + } + } + +private: + static FieldVector<FieldVector<SparseMatrixType, 2>, d> initialize_flux_matrices(const MomentBasis& basis) + { + // calculate < v_i b b^T >_- M^{-1} and < v_i b b^T >_+ M^{-1} + const auto flux_matrices_dense = basis.kinetic_flux_matrices(); + FieldVector<FieldVector<SparseMatrixType, 2>, d> flux_matrices( + FieldVector<SparseMatrixType, 2>(SparseMatrixType(m, m, size_t(0)))); + for (size_t dd = 0; dd < d; ++dd) + for (size_t kk = 0; kk < 2; ++kk) + flux_matrices[dd][kk] = flux_matrices_dense[dd][kk]; + return flux_matrices; + } + + const MomentBasis& basis_; +}; // class NumericalKineticFlux + + +template <class I, class MomentBasis> +NumericalKineticFlux<I, MomentBasis> make_numerical_kinetic_flux( + const XT::Functions:: + FluxFunctionInterface<I, MomentBasis::r, MomentBasis::dimFlux, MomentBasis::r, typename MomentBasis::R>& flux, + const MomentBasis& basis) +{ + return NumericalKineticFlux<I, MomentBasis>(flux, basis); +} + +template <class I, class MomentBasis> +NumericalKineticFlux<I, MomentBasis> make_numerical_kinetic_flux( + const XT::Functions:: + FunctionInterface<MomentBasis::r, MomentBasis::dimFlux, MomentBasis::r, typename MomentBasis::R>& flux, + const MomentBasis& basis) +{ + return NumericalKineticFlux<I, MomentBasis>(flux, basis); +} + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_LOCAL_NUMERICAL_FLUXES_KINETIC_HH diff --git a/dune/gdt/local/numerical-fluxes/lax-friedrichs.hh b/dune/gdt/local/numerical-fluxes/lax-friedrichs.hh index 3961767319a97ed80ed6ec258a2c035ada5752e8..36febbe080e0901bf41fa8d21d6ec7f366f146fa 100644 --- a/dune/gdt/local/numerical-fluxes/lax-friedrichs.hh +++ b/dune/gdt/local/numerical-fluxes/lax-friedrichs.hh @@ -19,31 +19,35 @@ namespace Dune { namespace GDT { -template <size_t d, size_t m = 1, class R = double> -class NumericalLaxFriedrichsFlux : public internal::ThisNumericalFluxIsNotAvailableForTheseDimensions<d, m, R> +template <class I, size_t d, size_t m, class R = double> +class NumericalLaxFriedrichsFlux : public NumericalFluxInterface<I, d, m, R> { -public: - template <class... Args> - explicit NumericalLaxFriedrichsFlux(Args&&... /*args*/) - : internal::ThisNumericalFluxIsNotAvailableForTheseDimensions<d, m, R>() - {} -}; - -template <size_t d, class R> -class NumericalLaxFriedrichsFlux<d, 1, R> : public NumericalFluxInterface<d, 1, R> -{ - static const constexpr size_t m = 1; - using ThisType = NumericalLaxFriedrichsFlux<d, m, R>; - using BaseType = NumericalFluxInterface<d, m, R>; + using ThisType = NumericalLaxFriedrichsFlux; + using BaseType = NumericalFluxInterface<I, d, m, R>; public: using typename BaseType::FluxType; + using typename BaseType::LocalIntersectionCoords; using typename BaseType::PhysicalDomainType; - using typename BaseType::StateRangeType; + using typename BaseType::StateType; + using typename BaseType::XIndependentFluxType; + using FluxJacobianType = XT::Common::FieldVector<XT::Common::FieldMatrix<R, m, m>, d>; - NumericalLaxFriedrichsFlux(const FluxType& flx) + NumericalLaxFriedrichsFlux(const FluxType& flx, const double lambda = 0.) : BaseType(flx) - {} + , lambda_(lambda) + { + if (XT::Common::is_zero(lambda_) && m != 1) + DUNE_THROW(Dune::NotImplemented, "Not yet implemented for m > 1 if lambda is not provided!"); + } + + NumericalLaxFriedrichsFlux(const XIndependentFluxType& func, const double lambda = 0.) + : BaseType(func) + , lambda_(lambda) + { + if (XT::Common::is_zero(lambda_) && m != 1) + DUNE_THROW(Dune::NotImplemented, "Not yet implemented for m > 1 if lambda is not provided!"); + } NumericalLaxFriedrichsFlux(const ThisType& other) = default; @@ -54,23 +58,55 @@ public: using BaseType::apply; - StateRangeType apply(const StateRangeType& u, - const StateRangeType& v, - const PhysicalDomainType& n, - const XT::Common::Parameter& param = {}) const override final + StateType apply(const LocalIntersectionCoords& x, + const StateType& u, + const StateType& v, + const PhysicalDomainType& n, + const XT::Common::Parameter& param = {}) const override final { - const auto lambda = - 1. / std::max(this->flux().jacobian(u, param).infinity_norm(), this->flux().jacobian(v, param).infinity_norm()); - return 0.5 * ((this->flux().evaluate(u, param) + this->flux().evaluate(v, param)) * n) + 0.5 * ((u - v) / lambda); + // prepare + this->compute_entity_coords(x); + // evaluate + R lambda = lambda_; + if (XT::Common::is_zero(lambda)) { + const auto df_u = local_flux_inside_->jacobian(x_in_inside_coords_, u, param); + const auto df_v = local_flux_outside_->jacobian(x_in_outside_coords_, v, param); + for (size_t dd = 0; dd < d; ++dd) { + lambda = std::max(lambda, df_u[dd].infinity_norm()); + lambda = std::max(lambda, df_v[dd].infinity_norm()); + } + lambda = 1. / lambda; + } + const auto f_u = local_flux_inside_->evaluate(x_in_inside_coords_, u, param); + const auto f_v = local_flux_outside_->evaluate(x_in_outside_coords_, v, param); + StateType ret(0.); + for (size_t dd = 0; dd < d; ++dd) + ret += (f_u[dd] + f_v[dd]) * (n[dd] * 0.5); + ret += (u - v) * (0.5 / lambda); + return ret; } + +private: + using BaseType::local_flux_inside_; + using BaseType::local_flux_outside_; + using BaseType::x_in_inside_coords_; + using BaseType::x_in_outside_coords_; + const double lambda_; }; // class NumericalLaxFriedrichsFlux -template <size_t d, size_t m, class R> -NumericalLaxFriedrichsFlux<d, m, R> +template <class I, size_t d, size_t m, class R> +NumericalLaxFriedrichsFlux<I, d, m, R> +make_numerical_lax_friedrichs_flux(const XT::Functions::FluxFunctionInterface<I, m, d, m, R>& flux) +{ + return NumericalLaxFriedrichsFlux<I, d, m, R>(flux); +} + +template <class I, size_t d, size_t m, class R> +NumericalLaxFriedrichsFlux<I, d, m, R> make_numerical_lax_friedrichs_flux(const XT::Functions::FunctionInterface<m, d, m, R>& flux) { - return NumericalLaxFriedrichsFlux<d, m, R>(flux); + return NumericalLaxFriedrichsFlux<I, d, m, R>(flux); } diff --git a/dune/gdt/local/numerical-fluxes/upwind.hh b/dune/gdt/local/numerical-fluxes/upwind.hh index d8d0961a0449b131aef36804587728a307825979..b7519530b00775185649fbcfc4e77dbb526bbe1e 100644 --- a/dune/gdt/local/numerical-fluxes/upwind.hh +++ b/dune/gdt/local/numerical-fluxes/upwind.hh @@ -17,32 +17,38 @@ namespace Dune { namespace GDT { -template <size_t d, size_t m = 1, class R = double> -class NumericalUpwindFlux : public internal::ThisNumericalFluxIsNotAvailableForTheseDimensions<d, m, R> +template <class I, size_t d, size_t m = 1, class R = double> +class NumericalUpwindFlux : public internal::ThisNumericalFluxIsNotAvailableForTheseDimensions<I, d, m, R> { public: template <class... Args> explicit NumericalUpwindFlux(Args&&... /*args*/) - : internal::ThisNumericalFluxIsNotAvailableForTheseDimensions<d, m, R>() + : internal::ThisNumericalFluxIsNotAvailableForTheseDimensions<I, d, m, R>() {} }; -template <size_t d, class R> -class NumericalUpwindFlux<d, 1, R> : public NumericalFluxInterface<d, 1, R> +template <class I, size_t d, class R> +class NumericalUpwindFlux<I, d, 1, R> : public NumericalFluxInterface<I, d, 1, R> { static const constexpr size_t m = 1; - using ThisType = NumericalUpwindFlux<d, m, R>; - using BaseType = NumericalFluxInterface<d, m, R>; + using ThisType = NumericalUpwindFlux; + using BaseType = NumericalFluxInterface<I, d, m, R>; public: using typename BaseType::FluxType; + using typename BaseType::LocalIntersectionCoords; using typename BaseType::PhysicalDomainType; - using typename BaseType::StateRangeType; + using typename BaseType::StateType; + using typename BaseType::XIndependentFluxType; NumericalUpwindFlux(const FluxType& flx) : BaseType(flx) {} + NumericalUpwindFlux(const XIndependentFluxType& func) + : BaseType(func) + {} + NumericalUpwindFlux(const ThisType& other) = default; std::unique_ptr<BaseType> copy() const override final @@ -52,24 +58,39 @@ public: using BaseType::apply; - StateRangeType apply(const StateRangeType& u, - const StateRangeType& v, - const PhysicalDomainType& n, - const XT::Common::Parameter& param = {}) const override final + StateType apply(const LocalIntersectionCoords& x, + const StateType& u, + const StateType& v, + const PhysicalDomainType& n, + const XT::Common::Parameter& param = {}) const override final { - const auto df = this->flux().jacobian((u + v) / 2., param); - if ((n * df) > 0) - return this->flux().evaluate(u, param) * n; + this->compute_entity_coords(x); + const auto df = local_flux_inside_->jacobian(x_in_inside_coords_, (u + v) / 2., param); + if (n * df > 0) + return local_flux_inside_->evaluate(x_in_inside_coords_, u, param) * n; else - return this->flux().evaluate(v, param) * n; + return local_flux_outside_->evaluate(x_in_outside_coords_, v, param) * n; } + +private: + using BaseType::local_flux_inside_; + using BaseType::local_flux_outside_; + using BaseType::x_in_inside_coords_; + using BaseType::x_in_outside_coords_; }; // class NumericalUpwindFlux -template <size_t d, size_t m, class R> -NumericalUpwindFlux<d, m, R> make_numerical_upwind_flux(const XT::Functions::FunctionInterface<m, d, m, R>& flux) +template <class I, size_t d, size_t m, class R> +NumericalUpwindFlux<I, d, m, R> +make_numerical_upwind_flux(const XT::Functions::FluxFunctionInterface<I, m, d, m, R>& flux) +{ + return NumericalUpwindFlux<I, d, m, R>(flux); +} + +template <class I, size_t d, size_t m, class R> +NumericalUpwindFlux<I, d, m, R> make_numerical_upwind_flux(const XT::Functions::FunctionInterface<m, d, m, R>& flux) { - return NumericalUpwindFlux<d, m, R>(flux); + return NumericalUpwindFlux<I, d, m, R>(flux); } diff --git a/dune/gdt/local/numerical-fluxes/vijayasundaram.hh b/dune/gdt/local/numerical-fluxes/vijayasundaram.hh index 770fa292f3a3c2690a44a4327eac9d97613b7984..ffe41e0a4db95bd85b5734afdcab8156e48f5031 100644 --- a/dune/gdt/local/numerical-fluxes/vijayasundaram.hh +++ b/dune/gdt/local/numerical-fluxes/vijayasundaram.hh @@ -24,39 +24,72 @@ namespace Dune { namespace GDT { -template <size_t d, size_t m = 1, class R = double> -class NumericalVijayasundaramFlux : public NumericalFluxInterface<d, m, R> +template <class I, size_t d, size_t m = 1, class R = double> +class NumericalVijayasundaramFlux : public NumericalFluxInterface<I, d, m, R> { - using ThisType = NumericalVijayasundaramFlux<d, m, R>; - using BaseType = NumericalFluxInterface<d, m, R>; + using ThisType = NumericalVijayasundaramFlux; + using BaseType = NumericalFluxInterface<I, d, m, R>; public: + using typename BaseType::E; using typename BaseType::FluxType; + using typename BaseType::LocalFluxType; + using typename BaseType::LocalIntersectionCoords; using typename BaseType::PhysicalDomainType; - using typename BaseType::StateRangeType; - - using FluxEigenDecompositionLambdaType = std::function<std::tuple< - std::vector<XT::Common::real_t<R>>, - XT::Common::FieldMatrix<XT::Common::real_t<R>, m, m>, - XT::Common::FieldMatrix<XT::Common::real_t<R>, m, m>>( - const FluxType&, const FieldVector<R, m>&, const FieldVector<double, d>&, const XT::Common::Parameter& param)>; - - NumericalVijayasundaramFlux(const FluxType& flx) - : BaseType(flx) - , flux_eigen_decomposition_([](const auto& f, const auto& w, const auto& n, const auto& param) { + using typename BaseType::StateType; + using typename BaseType::XIndependentFluxType; + + using FluxEigenDecompositionLambdaType = + std::function<std::tuple<std::vector<XT::Common::real_t<R>>, + XT::Common::FieldMatrix<XT::Common::real_t<R>, m, m>, + XT::Common::FieldMatrix<XT::Common::real_t<R>, m, m>>( + const LocalFluxType&, + const FieldVector<R, m>&, + const FieldVector<double, d>&, + const XT::Common::Parameter& param)>; + + static FluxEigenDecompositionLambdaType default_flux_eigen_decomposition() + { + return [](const LocalFluxType& local_flux, + const StateType& w, + const PhysicalDomainType& n, + const XT::Common::Parameter& param) { // evaluate flux jacobian, compute P matrix [DF2016, p. 404, (8.17)] - const auto df = f.jacobian(w, param); + static PhysicalDomainType dummy_x; + const auto df = local_flux.jacobian(dummy_x, w, param); const auto P = df * n; auto eigensolver = XT::LA::make_eigen_solver( P, {{"type", XT::LA::eigen_solver_types(P)[0]}, {"assert_real_eigendecomposition", "1e-10"}}); return std::make_tuple( eigensolver.real_eigenvalues(), eigensolver.real_eigenvectors(), eigensolver.real_eigenvectors_inverse()); - }) + }; + } + + NumericalVijayasundaramFlux(const FluxType& flx) + : BaseType(flx) + , flux_eigen_decomposition_(default_flux_eigen_decomposition()) + { + if (flx->x_dependent()) + DUNE_THROW(Dune::NotImplemented, "This flux is not yet implemented for x-dependent fluxes!"); + } + + NumericalVijayasundaramFlux(const XIndependentFluxType& flx) + : BaseType(flx) + , flux_eigen_decomposition_(default_flux_eigen_decomposition()) {} NumericalVijayasundaramFlux(const FluxType& flx, FluxEigenDecompositionLambdaType flux_eigen_decomposition) : BaseType(flx) , flux_eigen_decomposition_(flux_eigen_decomposition) + { + if (flx->x_dependent()) + DUNE_THROW(Dune::NotImplemented, "This flux is not yet implemented for x-dependent fluxes!"); + } + + NumericalVijayasundaramFlux(const XIndependentFluxType& flx, + FluxEigenDecompositionLambdaType flux_eigen_decomposition) + : BaseType(flx) + , flux_eigen_decomposition_(flux_eigen_decomposition) {} std::unique_ptr<BaseType> copy() const override final @@ -64,15 +97,19 @@ public: return std::make_unique<ThisType>(*this); } + NumericalVijayasundaramFlux(const ThisType& other) = default; + using BaseType::apply; - StateRangeType apply(const StateRangeType& u, - const StateRangeType& v, - const PhysicalDomainType& n, - const XT::Common::Parameter& param = {}) const override final + StateType apply(const LocalIntersectionCoords& x, + const StateType& u, + const StateType& v, + const PhysicalDomainType& n, + const XT::Common::Parameter& param = {}) const override final { // compute decomposition - const auto eigendecomposition = flux_eigen_decomposition_(this->flux(), 0.5 * (u + v), n, param); + this->compute_entity_coords(x); + const auto eigendecomposition = flux_eigen_decomposition_(*local_flux_inside_, 0.5 * (u + v), n, param); const auto& evs = std::get<0>(eigendecomposition); const auto& T = std::get<1>(eigendecomposition); const auto& T_inv = std::get<2>(eigendecomposition); @@ -90,15 +127,23 @@ public: } // ... apply(...) private: + using BaseType::local_flux_inside_; const FluxEigenDecompositionLambdaType flux_eigen_decomposition_; }; // class NumericalVijayasundaramFlux -template <size_t d, size_t m, class R, class... Args> -NumericalVijayasundaramFlux<d, m, R> +template <class I, size_t d, size_t m, class R, class... Args> +NumericalVijayasundaramFlux<I, d, m, R> +make_numerical_vijayasundaram_flux(const XT::Functions::FluxFunctionInterface<I, m, d, m, R>& flux, Args&&... args) +{ + return NumericalVijayasundaramFlux<I, d, m, R>(flux, std::forward<Args>(args)...); +} + +template <class I, size_t d, size_t m, class R, class... Args> +NumericalVijayasundaramFlux<I, d, m, R> make_numerical_vijayasundaram_flux(const XT::Functions::FunctionInterface<m, d, m, R>& flux, Args&&... args) { - return NumericalVijayasundaramFlux<d, m, R>(flux, std::forward<Args>(args)...); + return NumericalVijayasundaramFlux<I, d, m, R>(flux, std::forward<Args>(args)...); } diff --git a/dune/gdt/local/operators/advection-dg.hh b/dune/gdt/local/operators/advection-dg.hh index 5628844288993cde9eae8e2ae46d6f128eb68653..0183c8ab750ea46dc006714961a183ef78d1b1b6 100644 --- a/dune/gdt/local/operators/advection-dg.hh +++ b/dune/gdt/local/operators/advection-dg.hh @@ -41,33 +41,68 @@ namespace GDT { template <class SV, class SGV, size_t m = 1, class SF = double, class RF = SF, class RGV = SGV, class RV = SV> class LocalAdvectionDgVolumeOperator : public LocalElementOperatorInterface<SV, SGV, m, 1, SF, m, 1, RF, RGV, RV> { - using ThisType = LocalAdvectionDgVolumeOperator<SV, SGV, m, SF, RF, RGV, RV>; + using ThisType = LocalAdvectionDgVolumeOperator; using BaseType = LocalElementOperatorInterface<SV, SGV, m, 1, SF, m, 1, RF, RGV, RV>; public: using BaseType::d; using typename BaseType::D; + using typename BaseType::E; using typename BaseType::LocalRangeType; + using typename BaseType::LocalSourceType; + using typename BaseType::SourceSpaceType; using typename BaseType::SourceType; - using FluxType = XT::Functions::FunctionInterface<m, d, m, RF>; + using FluxType = XT::Functions::FluxFunctionInterface<E, m, d, m, RF>; using LocalMassMatrixProviderType = LocalMassMatrixProvider<RGV, m, 1, RF>; + // When using this constructor, source has to be set by a call to with_source before calling apply LocalAdvectionDgVolumeOperator(const FluxType& flux) - : BaseType(flux.parameter_type()) + : BaseType(1, flux.parameter_type()) + , flux_(flux) + , local_flux_(flux_.local_function()) + {} + + LocalAdvectionDgVolumeOperator(const SourceType& source, const FluxType& flux) + : BaseType(source, 1, flux.parameter_type()) , flux_(flux) + , local_flux_(flux_.local_function()) {} + // When using this constructor, source has to be set by a call to with_source before calling apply /// Applies the inverse of the local mass matrix. LocalAdvectionDgVolumeOperator(const LocalMassMatrixProviderType& local_mass_matrices, const FluxType& flux) - : BaseType(flux.parameter_type()) + : BaseType(1, flux.parameter_type()) + , flux_(flux) + , local_flux_(flux_.local_function()) + , local_mass_matrices_(local_mass_matrices) + {} + + /// Applies the inverse of the local mass matrix. + LocalAdvectionDgVolumeOperator(const SourceType& source, + const LocalMassMatrixProviderType& local_mass_matrices, + const FluxType& flux) + : BaseType(source, 1, flux.parameter_type()) + , flux_(flux) + , local_flux_(flux_.local_function()) + , local_mass_matrices_(local_mass_matrices) + {} + + /// Applies the inverse of the local mass matrix. + LocalAdvectionDgVolumeOperator(const SourceSpaceType& source_space, + const SV& source_vector, + const LocalMassMatrixProviderType& local_mass_matrices, + const FluxType& flux) + : BaseType(source_space, source_vector, 1, flux.parameter_type()) , flux_(flux) + , local_flux_(flux_.local_function()) , local_mass_matrices_(local_mass_matrices) {} LocalAdvectionDgVolumeOperator(const ThisType& other) - : BaseType(other.parameter_type()) + : BaseType(other) , flux_(other.flux_) + , local_flux_(flux_.local_function()) , local_mass_matrices_(other.local_mass_matrices_) {} @@ -76,18 +111,24 @@ public: return std::make_unique<ThisType>(*this); } - void apply(const SourceType& source, - LocalRangeType& local_range, - const XT::Common::Parameter& param = {}) const override final + /// \todo add linear() to XT::Functions::FluxFunctionInterface and return flux_.linear()! + bool linear() const override final { + return false; + } + + void apply(LocalRangeType& local_range, const XT::Common::Parameter& param = {}) const override final + { + const auto& u_ = local_sources_[0]; const auto& element = local_range.element(); const auto& basis = local_range.basis(); local_dofs_.resize(basis.size(param)); local_dofs_ *= 0.; - const auto local_source = source.local_discrete_function(element); - const auto local_source_order = local_source->order(param); + u_->bind(element); + const auto u_order = u_->order(param); const auto local_basis_order = basis.order(param); - const auto integrand_order = flux_.order(param) * local_source_order + std::max(local_basis_order - 1, 0); + local_flux_->bind(element); + const auto integrand_order = local_flux_->order(param) * u_order + std::max(local_basis_order - 1, 0); for (const auto& quadrature_point : QuadratureRules<D, d>::rule(element.geometry().type(), integrand_order)) { // prepare const auto point_in_reference_element = quadrature_point.position(); @@ -95,8 +136,8 @@ public: const auto quadrature_weight = quadrature_point.weight(); // evaluate basis.jacobians(point_in_reference_element, basis_jacobians_, param); - const auto source_value = local_source->evaluate(point_in_reference_element, param); - const auto flux_value = flux_.evaluate(source_value, param); + const auto source_value = u_->evaluate(point_in_reference_element, param); + const auto flux_value = local_flux_->evaluate(point_in_reference_element, source_value, param); // compute for (size_t ii = 0; ii < basis.size(param); ++ii) local_dofs_[ii] += integration_factor * quadrature_weight * -1. * (flux_value * basis_jacobians_[ii]); @@ -110,7 +151,9 @@ public: } // ... apply(...) private: + using BaseType::local_sources_; const FluxType& flux_; + std::unique_ptr<typename FluxType::LocalFunctionType> local_flux_; const XT::Common::ConstStorageProvider<LocalMassMatrixProviderType> local_mass_matrices_; mutable std::vector<typename LocalRangeType::LocalBasisType::DerivativeRangeType> basis_jacobians_; mutable XT::LA::CommonDenseVector<RF> local_dofs_; @@ -136,7 +179,7 @@ template <class I, class LocalAdvectionDgCouplingOperator : public LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SR, m, 1, IRR, IRGV, IRV, ORGV, ORV> { - using ThisType = LocalAdvectionDgCouplingOperator<I, SV, SGV, m, SR, IRR, IRGV, IRV, ORR, ORGV, ORV>; + using ThisType = LocalAdvectionDgCouplingOperator; using BaseType = LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SR, m, 1, IRR, IRGV, IRV, ORGV, ORV>; public: @@ -145,30 +188,71 @@ public: using typename BaseType::IntersectionType; using typename BaseType::LocalInsideRangeType; using typename BaseType::LocalOutsideRangeType; + using typename BaseType::LocalSourceType; + using typename BaseType::SourceSpaceType; using typename BaseType::SourceType; - using NumericalFluxType = NumericalFluxInterface<d, m, IRR>; + using NumericalFluxType = NumericalFluxInterface<I, d, m, IRR>; using LocalMassMatrixProviderType = LocalMassMatrixProvider<IRGV, m, 1, IRR>; + // When using this constructor, source has to be set by a call to with_source before calling apply LocalAdvectionDgCouplingOperator(const NumericalFluxType& numerical_flux, bool compute_outside = true) - : BaseType(numerical_flux.parameter_type()) + : BaseType(2, numerical_flux.parameter_type()) + , numerical_flux_(numerical_flux.copy()) + , local_flux_(numerical_flux_->flux().local_function()) + , compute_outside_(compute_outside) + {} + + LocalAdvectionDgCouplingOperator(const SourceType& source, + const NumericalFluxType& numerical_flux, + bool compute_outside = true) + : BaseType(source, 2, numerical_flux.parameter_type()) , numerical_flux_(numerical_flux.copy()) + , local_flux_(numerical_flux_->flux().local_function()) , compute_outside_(compute_outside) {} + // When using this constructor, source has to be set by a call to with_source before calling apply /// Applies the inverse of the local mass matrix. LocalAdvectionDgCouplingOperator(const LocalMassMatrixProviderType& local_mass_matrices, const NumericalFluxType& numerical_flux, bool compute_outside = true) - : BaseType(numerical_flux.parameter_type()) + : BaseType(2, numerical_flux.parameter_type()) + , numerical_flux_(numerical_flux.copy()) + , local_flux_(numerical_flux_->flux().local_function()) + , compute_outside_(compute_outside) + , local_mass_matrices_(local_mass_matrices) + {} + + /// Applies the inverse of the local mass matrix. + LocalAdvectionDgCouplingOperator(const SourceType& source, + const LocalMassMatrixProviderType& local_mass_matrices, + const NumericalFluxType& numerical_flux, + bool compute_outside = true) + : BaseType(source, 2, numerical_flux.parameter_type()) + , numerical_flux_(numerical_flux.copy()) + , local_flux_(numerical_flux_->flux().local_function()) + , compute_outside_(compute_outside) + , local_mass_matrices_(local_mass_matrices) + {} + + /// Applies the inverse of the local mass matrix. + LocalAdvectionDgCouplingOperator(const SourceSpaceType& source_space, + const SV& source_vector, + const LocalMassMatrixProviderType& local_mass_matrices, + const NumericalFluxType& numerical_flux, + bool compute_outside = true) + : BaseType(source_space, source_vector, 2, numerical_flux.parameter_type()) , numerical_flux_(numerical_flux.copy()) + , local_flux_(numerical_flux_->flux().local_function()) , compute_outside_(compute_outside) , local_mass_matrices_(local_mass_matrices) {} LocalAdvectionDgCouplingOperator(const ThisType& other) - : BaseType(other.parameter_type()) + : BaseType(other) , numerical_flux_(other.numerical_flux_->copy()) + , local_flux_(numerical_flux_->flux().local_function()) , compute_outside_(other.compute_outside_) , local_mass_matrices_(other.local_mass_matrices_) {} @@ -178,12 +262,17 @@ public: return std::make_unique<ThisType>(*this); } - void apply(const SourceType& source, - const IntersectionType& intersection, - LocalInsideRangeType& local_range_inside, + bool linear() const override final + { + return numerical_flux_->linear(); + } + + void apply(LocalInsideRangeType& local_range_inside, LocalOutsideRangeType& local_range_outside, const XT::Common::Parameter& param = {}) const override final { + const auto& u_ = local_sources_[0]; + const auto& v_ = local_sources_[1]; const auto& inside_element = local_range_inside.element(); const auto& outside_element = local_range_outside.element(); const auto& inside_basis = local_range_inside.basis(); @@ -192,10 +281,17 @@ public: outside_local_dofs_.resize(outside_basis.size(param)); inside_local_dofs_ *= 0.; outside_local_dofs_ *= 0.; - const auto u = source.local_discrete_function(inside_element); - const auto v = source.local_discrete_function(outside_element); + numerical_flux_->bind(intersection); + local_flux_->bind(intersection.inside()); + const auto inside_flux_order = local_flux_->order(param); + local_flux_->bind(intersection.outside()); + const auto outside_flux_order = local_flux_->order(param); + u_->bind(inside_element); + v_->bind(outside_element); + const auto u_order = u_->order(param); + const auto v_order = v_->order(param); const auto integrand_order = std::max(inside_basis.order(param), outside_basis.order(param)) - + numerical_flux_->flux().order(param) * std::max(u->order(param), v->order(param)); + + std::max(inside_flux_order * u_order, outside_flux_order * v_order); for (const auto& quadrature_point : QuadratureRules<D, d - 1>::rule(intersection.geometry().type(), integrand_order)) { // prepare @@ -211,10 +307,9 @@ public: inside_basis.evaluate(point_in_inside_reference_element, inside_basis_values_); if (compute_outside_) outside_basis.evaluate(point_in_outside_reference_element, outside_basis_values_); - const auto g = numerical_flux_->apply(u->evaluate(point_in_inside_reference_element), - v->evaluate(point_in_outside_reference_element), - normal, - param); + const auto u_val = u_->evaluate(point_in_inside_reference_element); + const auto v_val = v_->evaluate(point_in_outside_reference_element); + const auto g = numerical_flux_->apply(point_in_reference_intersection, u_val, v_val, normal, param); // compute for (size_t ii = 0; ii < inside_basis.size(param); ++ii) inside_local_dofs_[ii] += integration_factor * quadrature_weight * (g * inside_basis_values_[ii]); @@ -237,7 +332,9 @@ public: } // ... apply(...) private: - const std::unique_ptr<const NumericalFluxType> numerical_flux_; + using BaseType::local_sources_; + const std::unique_ptr<NumericalFluxType> numerical_flux_; + std::unique_ptr<typename NumericalFluxType::FluxType::LocalFunctionType> local_flux_; const bool compute_outside_; const XT::Common::ConstStorageProvider<LocalMassMatrixProviderType> local_mass_matrices_; mutable std::vector<typename LocalInsideRangeType::LocalBasisType::RangeType> inside_basis_values_; @@ -256,7 +353,7 @@ template <class I, class SV, class SGV, size_t m = 1, class SF = double, class R class LocalAdvectionDgBoundaryTreatmentByCustomNumericalFluxOperator : public LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SF, m, 1, RF, RGV, RV> { - using ThisType = LocalAdvectionDgBoundaryTreatmentByCustomNumericalFluxOperator<I, SV, SGV, m, SF, RF, RGV, RV>; + using ThisType = LocalAdvectionDgBoundaryTreatmentByCustomNumericalFluxOperator; using BaseType = LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SF, m, 1, RF, RGV, RV>; public: @@ -265,6 +362,7 @@ public: using typename BaseType::IntersectionType; using typename BaseType::LocalInsideRangeType; using typename BaseType::LocalOutsideRangeType; + using typename BaseType::SourceSpaceType; using typename BaseType::SourceType; using StateDomainType = FieldVector<typename SGV::ctype, SGV::dimension>; @@ -274,28 +372,45 @@ public: using LocalMassMatrixProviderType = LocalMassMatrixProvider<RGV, m, 1, RF>; LocalAdvectionDgBoundaryTreatmentByCustomNumericalFluxOperator( + const SourceType& source, + LambdaType numerical_boundary_flux, + const int numerical_flux_order, + const XT::Common::ParameterType& numerical_flux_param_type = {}) + : BaseType(source, 1, numerical_flux_param_type) + , numerical_boundary_flux_(numerical_boundary_flux) + , numerical_flux_order_(numerical_flux_order) + {} + + /// Applies the inverse of the local mass matrix. + LocalAdvectionDgBoundaryTreatmentByCustomNumericalFluxOperator( + const SourceType& source, + const LocalMassMatrixProviderType& local_mass_matrices, LambdaType numerical_boundary_flux, const int numerical_flux_order, const XT::Common::ParameterType& numerical_flux_param_type = {}) - : BaseType(numerical_flux_param_type) + : BaseType(source, 1, numerical_flux_param_type) , numerical_boundary_flux_(numerical_boundary_flux) , numerical_flux_order_(numerical_flux_order) + , local_mass_matrices_(local_mass_matrices) {} /// Applies the inverse of the local mass matrix. LocalAdvectionDgBoundaryTreatmentByCustomNumericalFluxOperator( + const SourceSpaceType& source_space, + const SV& source_vector, const LocalMassMatrixProviderType& local_mass_matrices, LambdaType numerical_boundary_flux, const int numerical_flux_order, const XT::Common::ParameterType& numerical_flux_param_type = {}) - : BaseType(numerical_flux_param_type) + : BaseType(source_space, source_vector, 1, numerical_flux_param_type) , numerical_boundary_flux_(numerical_boundary_flux) , numerical_flux_order_(numerical_flux_order) , local_mass_matrices_(local_mass_matrices) {} + LocalAdvectionDgBoundaryTreatmentByCustomNumericalFluxOperator(const ThisType& other) - : BaseType(other.parameter_type()) + : BaseType(other) , numerical_boundary_flux_(other.numerical_boundary_flux_) , numerical_flux_order_(other.numerical_flux_order_) , local_mass_matrices_(other.local_mass_matrices_) @@ -306,18 +421,23 @@ public: return std::make_unique<ThisType>(*this); } - void apply(const SourceType& source, - const IntersectionType& intersection, - LocalInsideRangeType& local_range_inside, + /// \todo store some numerical_flux_linear in ctor and return that + bool linear() const override final + { + return false; + } + + void apply(LocalInsideRangeType& local_range_inside, LocalOutsideRangeType& /*local_range_outside*/, const XT::Common::Parameter& param = {}) const override final { + const auto& u_ = local_sources_[0]; const auto& element = local_range_inside.element(); const auto& inside_basis = local_range_inside.basis(); inside_local_dofs_.resize(inside_basis.size(param)); inside_local_dofs_ *= 0.; - const auto u = source.local_discrete_function(element); - const auto integrand_order = inside_basis.order(param) + numerical_flux_order_ * u->order(param); + u_->bind(element); + const auto integrand_order = inside_basis.order(param) + numerical_flux_order_ * u_->order(param); for (const auto& quadrature_point : QuadratureRules<D, d - 1>::rule(intersection.geometry().type(), integrand_order)) { // prepare @@ -329,7 +449,7 @@ public: intersection.geometryInInside().global(point_in_reference_intersection); // evaluate inside_basis.evaluate(point_in_inside_reference_element, inside_basis_values_); - const auto g = numerical_boundary_flux_(u->evaluate(point_in_inside_reference_element), normal, param); + const auto g = numerical_boundary_flux_(u_->evaluate(point_in_inside_reference_element), normal, param); // compute for (size_t ii = 0; ii < inside_basis.size(param); ++ii) inside_local_dofs_[ii] += integration_factor * quadrature_weight * (g * inside_basis_values_[ii]); @@ -343,6 +463,7 @@ public: } // ... apply(...) private: + using BaseType::local_sources_; const LambdaType numerical_boundary_flux_; const int numerical_flux_order_; const XT::Common::ConstStorageProvider<LocalMassMatrixProviderType> local_mass_matrices_; @@ -360,7 +481,7 @@ template <class I, class SV, class SGV, size_t m = 1, class SF = double, class R class LocalAdvectionDgBoundaryTreatmentByCustomExtrapolationOperator : public LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SF, m, 1, RF, RGV, RV> { - using ThisType = LocalAdvectionDgBoundaryTreatmentByCustomExtrapolationOperator<I, SV, SGV, m, SF, RF, RGV, RV>; + using ThisType = LocalAdvectionDgBoundaryTreatmentByCustomExtrapolationOperator; using BaseType = LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SF, m, 1, RF, RGV, RV>; public: @@ -368,10 +489,11 @@ public: using typename BaseType::IntersectionType; using typename BaseType::LocalInsideRangeType; using typename BaseType::LocalOutsideRangeType; + using typename BaseType::SourceSpaceType; using typename BaseType::SourceType; using D = typename IntersectionType::ctype; - using NumericalFluxType = NumericalFluxInterface<d, m, RF>; + using NumericalFluxType = NumericalFluxInterface<I, d, m, RF>; using FluxType = typename NumericalFluxType::FluxType; using StateRangeType = typename XT::Functions::RangeTypeSelector<RF, m, 1>::type; using LambdaType = @@ -383,29 +505,49 @@ public: using LocalMassMatrixProviderType = LocalMassMatrixProvider<RGV, m, 1, RF>; LocalAdvectionDgBoundaryTreatmentByCustomExtrapolationOperator( + const SourceType& source, + const NumericalFluxType& numerical_flux, + LambdaType boundary_extrapolation_lambda, + const XT::Common::ParameterType& boundary_treatment_param_type = {}) + : BaseType(source, 1, numerical_flux.parameter_type() + boundary_treatment_param_type) + , numerical_flux_(numerical_flux.copy()) + , local_flux_(numerical_flux_->flux().local_function()) + , extrapolate_(boundary_extrapolation_lambda) + {} + + /// Applies the inverse of the local mass matrix. + LocalAdvectionDgBoundaryTreatmentByCustomExtrapolationOperator( + const SourceType& source, + const LocalMassMatrixProviderType& local_mass_matrices, const NumericalFluxType& numerical_flux, LambdaType boundary_extrapolation_lambda, const XT::Common::ParameterType& boundary_treatment_param_type = {}) - : BaseType(numerical_flux.parameter_type() + boundary_treatment_param_type) + : BaseType(source, 1, numerical_flux.parameter_type() + boundary_treatment_param_type) , numerical_flux_(numerical_flux.copy()) + , local_flux_(numerical_flux_->flux().local_function()) , extrapolate_(boundary_extrapolation_lambda) + , local_mass_matrices_(local_mass_matrices) {} /// Applies the inverse of the local mass matrix. LocalAdvectionDgBoundaryTreatmentByCustomExtrapolationOperator( + const SourceSpaceType& source_space, + const SV& source_vector, const LocalMassMatrixProviderType& local_mass_matrices, const NumericalFluxType& numerical_flux, LambdaType boundary_extrapolation_lambda, const XT::Common::ParameterType& boundary_treatment_param_type = {}) - : BaseType(numerical_flux.parameter_type() + boundary_treatment_param_type) + : BaseType(source_space, source_vector, 1, numerical_flux.parameter_type() + boundary_treatment_param_type) , numerical_flux_(numerical_flux.copy()) + , local_flux_(numerical_flux_->flux().local_function()) , extrapolate_(boundary_extrapolation_lambda) , local_mass_matrices_(local_mass_matrices) {} LocalAdvectionDgBoundaryTreatmentByCustomExtrapolationOperator(const ThisType& other) - : BaseType(other.parameter_type()) + : BaseType(other) , numerical_flux_(other.numerical_flux_->copy()) + , local_flux_(numerical_flux_->flux().local_function()) , extrapolate_(other.extrapolate_) , local_mass_matrices_(other.local_mass_matrices_) {} @@ -415,19 +557,24 @@ public: return std::make_unique<ThisType>(*this); } - void apply(const SourceType& source, - const IntersectionType& intersection, - LocalInsideRangeType& local_range_inside, + bool linear() const override final + { + return numerical_flux_->linear(); + } + + void apply(LocalInsideRangeType& local_range_inside, LocalOutsideRangeType& /*local_range_outside*/, const XT::Common::Parameter& param = {}) const override final { + const auto& u_ = local_sources_[0]; const auto& element = local_range_inside.element(); const auto& inside_basis = local_range_inside.basis(); inside_local_dofs_.resize(inside_basis.size(param)); inside_local_dofs_ *= 0.; - const auto local_source = source.local_discrete_function(element); - const auto integrand_order = - inside_basis.order(param) + numerical_flux_->flux().order(param) * local_source->order(param); + numerical_flux_->bind(intersection); + local_flux_->bind(intersection.inside()); + u_->bind(element); + const auto integrand_order = inside_basis.order(param) + local_flux_->order(param) * u_->order(param); for (const auto& quadrature_point : QuadratureRules<D, d - 1>::rule(intersection.geometry().type(), integrand_order)) { // prepare @@ -439,9 +586,9 @@ public: intersection.geometryInInside().global(point_in_reference_intersection); // evaluate inside_basis.evaluate(point_in_inside_reference_element, inside_basis_values_); - const auto u = local_source->evaluate(point_in_inside_reference_element); + const auto u = u_->evaluate(point_in_inside_reference_element); const auto v = extrapolate_(intersection, point_in_reference_intersection, numerical_flux_->flux(), u, param); - const auto g = numerical_flux_->apply(u, v, normal, param); + const auto g = numerical_flux_->apply(point_in_reference_intersection, u, v, normal, param); // compute for (size_t ii = 0; ii < inside_basis.size(param); ++ii) inside_local_dofs_[ii] += integration_factor * quadrature_weight * (g * inside_basis_values_[ii]); @@ -455,7 +602,9 @@ public: } // ... apply(...) private: - const std::unique_ptr<const NumericalFluxType> numerical_flux_; + using BaseType::local_sources_; + const std::unique_ptr<NumericalFluxType> numerical_flux_; + std::unique_ptr<typename NumericalFluxType::FluxType::LocalFunctionType> local_flux_; const LambdaType extrapolate_; const XT::Common::ConstStorageProvider<LocalMassMatrixProviderType> local_mass_matrices_; mutable std::vector<typename LocalInsideRangeType::LocalBasisType::RangeType> inside_basis_values_; @@ -467,36 +616,83 @@ template <class SV, class SGV, size_t m = 1, class SF = double, class RF = SF, c class LocalAdvectionDgArtificialViscosityShockCapturingOperator : public LocalElementOperatorInterface<SV, SGV, m, 1, SF, m, 1, RF, RGV, RV> { - using ThisType = LocalAdvectionDgArtificialViscosityShockCapturingOperator<SV, SGV, m, SF, RF, RGV, RV>; + using ThisType = LocalAdvectionDgArtificialViscosityShockCapturingOperator; using BaseType = LocalElementOperatorInterface<SV, SGV, m, 1, SF, m, 1, RF, RGV, RV>; public: using BaseType::d; using typename BaseType::D; using typename BaseType::LocalRangeType; + using typename BaseType::LocalSourceType; + using typename BaseType::SourceSpaceType; using typename BaseType::SourceType; using FluxType = XT::Functions::FunctionInterface<m, d, m, RF>; using LocalMassMatrixProviderType = LocalMassMatrixProvider<RGV, m, 1, RF>; + // When using this constructor, source has to be set by a call to with_source before calling apply LocalAdvectionDgArtificialViscosityShockCapturingOperator(const SGV& assembly_grid_view, const double& nu_1 = 0.2, const double& alpha_1 = 1.0, const size_t index = 0) - : BaseType() + : BaseType(2) , assembly_grid_view_(assembly_grid_view) , nu_1_(nu_1) , alpha_1_(alpha_1) , index_(index) {} + LocalAdvectionDgArtificialViscosityShockCapturingOperator(const SourceType& source, + const SGV& assembly_grid_view, + const double& nu_1 = 0.2, + const double& alpha_1 = 1.0, + const size_t index = 0) + : BaseType(source, 2) + , assembly_grid_view_(assembly_grid_view) + , nu_1_(nu_1) + , alpha_1_(alpha_1) + , index_(index) + {} + + // When using this constructor, source has to be set by a call to with_source before calling apply /// Applies the inverse of the local mass matrix. LocalAdvectionDgArtificialViscosityShockCapturingOperator(const LocalMassMatrixProviderType& local_mass_matrices, const SGV& assembly_grid_view, const double& nu_1 = 0.2, const double& alpha_1 = 1.0, const size_t index = 0) - : BaseType() + : BaseType(2) + , assembly_grid_view_(assembly_grid_view) + , nu_1_(nu_1) + , alpha_1_(alpha_1) + , index_(index) + , local_mass_matrices_(local_mass_matrices) + {} + + /// Applies the inverse of the local mass matrix. + LocalAdvectionDgArtificialViscosityShockCapturingOperator(const SourceType& source, + const LocalMassMatrixProviderType& local_mass_matrices, + const SGV& assembly_grid_view, + const double& nu_1 = 0.2, + const double& alpha_1 = 1.0, + const size_t index = 0) + : BaseType(source, 2) + , assembly_grid_view_(assembly_grid_view) + , nu_1_(nu_1) + , alpha_1_(alpha_1) + , index_(index) + , local_mass_matrices_(local_mass_matrices) + {} + + /// Applies the inverse of the local mass matrix. + LocalAdvectionDgArtificialViscosityShockCapturingOperator(const SourceSpaceType& source_space, + const SV& source_vector, + const LocalMassMatrixProviderType& local_mass_matrices, + const SGV& assembly_grid_view, + const double& nu_1 = 0.2, + const double& alpha_1 = 1.0, + const size_t index = 0) + : BaseType(source_space, source_vector, 2) , assembly_grid_view_(assembly_grid_view) , nu_1_(nu_1) , alpha_1_(alpha_1) @@ -518,16 +714,16 @@ public: return std::make_unique<ThisType>(*this); } - void apply(const SourceType& source, - LocalRangeType& local_range, - const XT::Common::Parameter& param = {}) const override final + void apply(LocalRangeType& local_range, const XT::Common::Parameter& param = {}) const override final { + const auto& u_ = local_sources_[0]; + const auto& v_ = local_sources_[1]; const auto& element = local_range.element(); const auto& basis = local_range.basis(); local_dofs_.resize(basis.size(param)); local_dofs_ *= 0.; - const auto local_source_element = source.local_discrete_function(element); - if (local_source_element->order(param) <= 0 || basis.order(param) <= 0) + u_->bind(element); + if (u_->order(param) <= 0 || basis.order(param) <= 0) return; // compute jump indicator (8.176) double element_jump_indicator = 0; @@ -537,9 +733,8 @@ public: if (d > 1) element_boundary_without_domain_boundary += XT::Grid::diameter(intersection); const auto neighbor = intersection.outside(); - const auto local_source_neighbor = source.local_discrete_function(neighbor); - const auto integration_order = - std::pow(std::max(local_source_element->order(param), local_source_neighbor->order(param)), 2); + v_->bind(neighbor); + const auto integration_order = std::pow(std::max(u_->order(param), v_->order(param)), 2); for (auto&& quadrature_point : QuadratureRules<D, d - 1>::rule(intersection.geometry().type(), integration_order)) { const auto point_in_reference_intersection = quadrature_point.position(); @@ -549,8 +744,8 @@ public: intersection.geometryInOutside().global(point_in_reference_intersection); const auto integration_factor = intersection.geometry().integrationElement(point_in_reference_intersection); const auto quadrature_weight = quadrature_point.weight(); - const auto value_on_element = local_source_element->evaluate(point_in_reference_element, param)[index_]; - const auto value_on_neighbor = local_source_neighbor->evaluate(point_in_reference_neighbor, param)[index_]; + const auto value_on_element = u_->evaluate(point_in_reference_element, param)[index_]; + const auto value_on_neighbor = v_->evaluate(point_in_reference_neighbor, param)[index_]; element_jump_indicator += integration_factor * quadrature_weight * std::pow(value_on_element - value_on_neighbor, 2); } @@ -572,12 +767,11 @@ public: if (smoothed_discrete_jump_indicator > 0) { const auto h = element.geometry().volume(); for (const auto& quadrature_point : QuadratureRules<D, d>::rule( - element.type(), - std::max(0, local_source_element->order(param) - 1) + std::max(0, basis.order(param) - 1))) { + element.type(), std::max(0, u_->order(param) - 1) + std::max(0, basis.order(param) - 1))) { const auto point_in_reference_element = quadrature_point.position(); const auto integration_factor = element.geometry().integrationElement(point_in_reference_element); const auto quadrature_weight = quadrature_point.weight(); - const auto source_jacobian = local_source_element->jacobian(point_in_reference_element, param); + const auto source_jacobian = u_->jacobian(point_in_reference_element, param); basis.jacobians(point_in_reference_element, basis_jacobians_, param); // compute beta_h for (size_t ii = 0; ii < basis.size(param); ++ii) @@ -594,6 +788,7 @@ public: } // ... apply(...) private: + using BaseType::local_sources_; const SGV& assembly_grid_view_; const double nu_1_; const double alpha_1_; diff --git a/dune/gdt/local/operators/advection-fv.hh b/dune/gdt/local/operators/advection-fv.hh index 93086c9cabfdd2514a73b0302f7875dced8b06ee..6c1ee194842a7f47aafbf4ec88f22b1edf033b41 100644 --- a/dune/gdt/local/operators/advection-fv.hh +++ b/dune/gdt/local/operators/advection-fv.hh @@ -48,26 +48,56 @@ template <class I, class LocalAdvectionFvCouplingOperator : public LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SR, m, 1, RR, IRGV, IRV, ORGV, ORV> { - using ThisType = LocalAdvectionFvCouplingOperator<I, SV, SGV, m, SR, RR, IRGV, IRV, ORR, ORGV, ORV>; + using ThisType = LocalAdvectionFvCouplingOperator; using BaseType = LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SR, m, 1, RR, IRGV, IRV, ORGV, ORV>; public: using BaseType::d; + using typename BaseType::DiscreteSourceType; using typename BaseType::IntersectionType; using typename BaseType::LocalInsideRangeType; using typename BaseType::LocalOutsideRangeType; + using typename BaseType::LocalSourceType; + using typename BaseType::SourceSpaceType; using typename BaseType::SourceType; + using StateType = typename XT::Functions::RangeTypeSelector<SR, m, 1>::type; + using NumericalFluxType = NumericalFluxInterface<I, d, m, RR>; + using LocalIntersectionCoords = typename NumericalFluxType::LocalIntersectionCoords; + static const typename LocalSourceType::DomainType static_x; + + // When using this constructor, source has to be set by a call to with_source before calling apply + LocalAdvectionFvCouplingOperator(const NumericalFluxType& numerical_flux, + const bool source_is_elementwise_constant = false) + : BaseType(2, numerical_flux.parameter_type()) + , numerical_flux_(numerical_flux.copy()) + , source_is_elementwise_constant_(source_is_elementwise_constant) + {} - using NumericalFluxType = NumericalFluxInterface<d, m, RR>; + LocalAdvectionFvCouplingOperator(const SourceType& source, + const NumericalFluxType& numerical_flux, + const bool source_is_elementwise_constant = false) + : BaseType(source, 2, numerical_flux.parameter_type()) + , numerical_flux_(numerical_flux.copy()) + , source_is_elementwise_constant_(source_is_elementwise_constant) + {} - LocalAdvectionFvCouplingOperator(const NumericalFluxType& numerical_flux) - : BaseType(numerical_flux.parameter_type()) + LocalAdvectionFvCouplingOperator(const SourceSpaceType& source_space, + const SV& source_vector, + const NumericalFluxType& numerical_flux, + const bool source_is_elementwise_constant = false) + : BaseType(source_space, source_vector, 2, numerical_flux.parameter_type()) , numerical_flux_(numerical_flux.copy()) + , source_is_elementwise_constant_(source_is_elementwise_constant) + {} + + LocalAdvectionFvCouplingOperator(const DiscreteSourceType& source, const NumericalFluxType& numerical_flux) + : ThisType(source, numerical_flux, source.space().type() == SpaceType::finite_volume) {} LocalAdvectionFvCouplingOperator(const ThisType& other) - : BaseType(other.parameter_type()) + : BaseType(other) , numerical_flux_(other.numerical_flux_->copy()) + , source_is_elementwise_constant_(other.source_is_elementwise_constant_) {} std::unique_ptr<BaseType> copy() const override final @@ -75,66 +105,134 @@ public: return std::make_unique<ThisType>(*this); } - void apply(const SourceType& source, - const IntersectionType& intersection, - LocalInsideRangeType& local_range_inside, + bool linear() const override final + { + return numerical_flux_->linear(); + } + + void apply(LocalInsideRangeType& local_range_inside, LocalOutsideRangeType& local_range_outside, const XT::Common::Parameter& param = {}) const override final { - DUNE_THROW_IF((source.space().type() != SpaceType::finite_volume) - || (local_range_inside.space().type() != SpaceType::finite_volume) + DUNE_THROW_IF((local_range_inside.space().type() != SpaceType::finite_volume) || (local_range_outside.space().type() != SpaceType::finite_volume), Exceptions::operator_error, "Use LocalAdvectionDgCouplingOperator instead!"); - const auto& inside_element = local_range_inside.element(); - const auto& outside_element = local_range_outside.element(); - const auto u = source.local_discrete_function(inside_element); - const auto v = source.local_discrete_function(outside_element); + u_ = local_sources_[0]->evaluate(source_is_elementwise_constant_ ? static_x + : intersection.geometryInInside().center()); + v_ = local_sources_[1]->evaluate(source_is_elementwise_constant_ ? static_x + : intersection.geometryInOutside().center()); const auto normal = intersection.centerUnitOuterNormal(); - const auto g = numerical_flux_->apply(u->dofs(), v->dofs(), normal, param); + if (numerical_flux_->x_dependent()) + x_in_intersection_coords_ = intersection.geometry().local(intersection.geometry().center()); + const auto g = numerical_flux_->apply(x_in_intersection_coords_, u_, v_, normal, param); const auto h_intersection = intersection.geometry().volume(); - const auto h_inside_element = inside_element.geometry().volume(); - const auto h_outside_element = outside_element.geometry().volume(); + const auto h_inside_element = intersection.inside().geometry().volume(); + const auto h_outside_element = intersection.outside().geometry().volume(); for (size_t ii = 0; ii < m; ++ii) { local_range_inside.dofs()[ii] += (g[ii] * h_intersection) / h_inside_element; local_range_outside.dofs()[ii] -= (g[ii] * h_intersection) / h_outside_element; } } // ... apply(...) +protected: + void post_bind(const I& inter) override + { + BaseType::post_bind(inter); + numerical_flux_->bind(inter); + } + private: + using BaseType::local_sources_; std::unique_ptr<NumericalFluxType> numerical_flux_; + const bool source_is_elementwise_constant_; + mutable LocalIntersectionCoords x_in_intersection_coords_; + mutable StateType u_; + mutable StateType v_; }; // class LocalAdvectionFvCouplingOperator +template <class I, + class SV, + class SGV, + size_t m, + class SR, + class RR, + class IRGV, + class IRV, + class ORR, + class ORGV, + class ORV> +const typename LocalAdvectionFvCouplingOperator<I, SV, SGV, m, SR, RR, IRGV, IRV, ORR, ORGV, ORV>::LocalSourceType:: + DomainType LocalAdvectionFvCouplingOperator<I, SV, SGV, m, SR, RR, IRGV, IRV, ORR, ORGV, ORV>::static_x; + template <class I, class SV, class SGV, size_t m = 1, class SF = double, class RF = SF, class RGV = SGV, class RV = SV> class LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator : public LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SF, m, 1, RF, RGV, RV> { - using ThisType = LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator<I, SV, SGV, m, SF, RF, RGV, RV>; + using ThisType = LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator; using BaseType = LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SF, m, 1, RF, RGV, RV>; + using CouplingOperatorType = LocalAdvectionFvCouplingOperator<I, SV, SGV, m, SF, RF, RGV, RV>; public: using BaseType::d; + using typename BaseType::DiscreteSourceType; using typename BaseType::IntersectionType; using typename BaseType::LocalInsideRangeType; using typename BaseType::LocalOutsideRangeType; + using typename BaseType::SourceSpaceType; using typename BaseType::SourceType; using StateDomainType = FieldVector<typename SGV::ctype, SGV::dimension>; - using StateDofsType = ConstLocalDofVector<SV, SGV>; - using StateRangeType = typename XT::Functions::RangeTypeSelector<SF, m, 1>::type; - using LambdaType = std::function<StateRangeType( - const StateDofsType& /*u*/, const StateDomainType& /*n*/, const XT::Common::Parameter& /*param*/)>; + using StateType = typename CouplingOperatorType::StateType; + using LambdaType = std::function<StateType( + const StateType& /*u*/, const StateDomainType& /*n*/, const XT::Common::Parameter& /*param*/)>; + + // When using this constructor, source has to be set by a call to with_source before calling apply + LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator( + LambdaType numerical_boundary_flux_lambda, + const XT::Common::ParameterType& boundary_treatment_param_type = {}, + const bool source_is_elementwise_constant = false) + : BaseType(1, boundary_treatment_param_type) + , numerical_boundary_flux_(numerical_boundary_flux_lambda) + , source_is_elementwise_constant_(source_is_elementwise_constant) + {} LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator( - LambdaType numerical_boundary_flux_lambda, const XT::Common::ParameterType& boundary_treatment_param_type = {}) - : BaseType(boundary_treatment_param_type) + const SourceType& source, + LambdaType numerical_boundary_flux_lambda, + const XT::Common::ParameterType& boundary_treatment_param_type = {}, + const bool source_is_elementwise_constant = false) + : BaseType(source, 1, boundary_treatment_param_type) , numerical_boundary_flux_(numerical_boundary_flux_lambda) + , source_is_elementwise_constant_(source_is_elementwise_constant) + {} + + LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator( + const SourceSpaceType& source_space, + const SV& source_vector, + LambdaType numerical_boundary_flux_lambda, + const XT::Common::ParameterType& boundary_treatment_param_type = {}, + const bool source_is_elementwise_constant = false) + : BaseType(source_space, source_vector, 1, boundary_treatment_param_type) + , numerical_boundary_flux_(numerical_boundary_flux_lambda) + , source_is_elementwise_constant_(source_is_elementwise_constant) + {} + + LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator( + const DiscreteSourceType& source, + LambdaType numerical_boundary_flux_lambda, + const XT::Common::ParameterType& boundary_treatment_param_type = {}) + : ThisType(source, + numerical_boundary_flux_lambda, + boundary_treatment_param_type, + source.space().type() == SpaceType::finite_volume) {} LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator(const ThisType& other) - : BaseType(other.parameter_type()) + : BaseType(other) , numerical_boundary_flux_(other.numerical_boundary_flux_) + , source_is_elementwise_constant_(other.source_is_elementwise_constant_) {} std::unique_ptr<BaseType> copy() const override final @@ -142,20 +240,24 @@ public: return std::make_unique<ThisType>(*this); } - void apply(const SourceType& source, - const IntersectionType& intersection, - LocalInsideRangeType& local_range_inside, + /// \todo store some numerical_flux_linear in ctor and return that + bool linear() const override final + { + return false; + } + + void apply(LocalInsideRangeType& local_range_inside, LocalOutsideRangeType& /*local_range_outside*/, const XT::Common::Parameter& param = {}) const override final { - DUNE_THROW_IF((source.space().type() != SpaceType::finite_volume) - || (local_range_inside.space().type() != SpaceType::finite_volume), + DUNE_THROW_IF(local_range_inside.space().type() != SpaceType::finite_volume, Exceptions::operator_error, "Use LocalAdvectionDgBoundaryTreatmentByCustomNumericalFluxOperator instead!"); const auto& element = local_range_inside.element(); - const auto u = source.local_discrete_function(element); + u_ = local_sources_[0]->evaluate(source_is_elementwise_constant_ ? CouplingOperatorType::static_x + : intersection.geometryInInside().center()); const auto normal = intersection.centerUnitOuterNormal(); - const auto g = numerical_boundary_flux_(u->dofs(), normal, param); + const auto g = numerical_boundary_flux_(u_, normal, param); const auto h_intersection = intersection.geometry().volume(); const auto h_element = element.geometry().volume(); for (size_t ii = 0; ii < m; ++ii) @@ -163,7 +265,10 @@ public: } // ... apply(...) private: + using BaseType::local_sources_; const LambdaType numerical_boundary_flux_; + const bool source_is_elementwise_constant_; + mutable StateType u_; }; // class LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator @@ -171,41 +276,84 @@ template <class I, class SV, class SGV, size_t m = 1, class SF = double, class R class LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator : public LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SF, m, 1, RF, RGV, RV> { - using ThisType = LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator<I, SV, SGV, m, SF, RF, RGV, RV>; + using ThisType = LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator; using BaseType = LocalIntersectionOperatorInterface<I, SV, SGV, m, 1, SF, m, 1, RF, RGV, RV>; + using CouplingOperatorType = LocalAdvectionFvCouplingOperator<I, SV, SGV, m, SF, RF, RGV, RV>; public: using BaseType::d; + using typename BaseType::DiscreteSourceType; using typename BaseType::IntersectionType; using typename BaseType::LocalInsideRangeType; using typename BaseType::LocalOutsideRangeType; + using typename BaseType::SourceSpaceType; using typename BaseType::SourceType; using D = typename IntersectionType::ctype; - using NumericalFluxType = NumericalFluxInterface<d, m, RF>; + using NumericalFluxType = NumericalFluxInterface<I, d, m, RF>; + using LocalIntersectionCoords = typename NumericalFluxType::LocalIntersectionCoords; using FluxType = typename NumericalFluxType::FluxType; - using StateDofsType = ConstLocalDofVector<SV, SGV>; - using StateRangeType = typename XT::Functions::RangeTypeSelector<RF, m, 1>::type; - using LambdaType = - std::function<StateRangeType(const IntersectionType& /*intersection*/, - const FieldVector<D, d - 1>& /*xx_in_reference_intersection_coordinates*/, - const FluxType& /*flux*/, - const StateDofsType& /*u*/, - const XT::Common::Parameter& /*param*/)>; + using StateType = typename CouplingOperatorType::StateType; + using LambdaType = std::function<StateType(const IntersectionType& /*intersection*/, + const FieldVector<D, d - 1>& /*xx_in_reference_intersection_coordinates*/, + const FluxType& /*flux*/, + const StateType& /*u*/, + const XT::Common::Parameter& /*param*/)>; + + // When using this constructor, source has to be set by a call to with_source before calling apply + LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator( + const NumericalFluxType& numerical_flux, + LambdaType boundary_extrapolation_lambda, + const XT::Common::ParameterType& boundary_treatment_param_type = {}, + const bool source_is_elementwise_constant = false) + : BaseType(1, numerical_flux.parameter_type() + boundary_treatment_param_type) + , numerical_flux_(numerical_flux.copy()) + , extrapolate_(boundary_extrapolation_lambda) + , source_is_elementwise_constant_(source_is_elementwise_constant) + {} LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator( + const SourceType& source, const NumericalFluxType& numerical_flux, LambdaType boundary_extrapolation_lambda, - const XT::Common::ParameterType& boundary_treatment_param_type = {}) - : BaseType(numerical_flux.parameter_type() + boundary_treatment_param_type) + const XT::Common::ParameterType& boundary_treatment_param_type = {}, + const bool source_is_elementwise_constant = false) + : BaseType(source, 1, numerical_flux.parameter_type() + boundary_treatment_param_type) + , numerical_flux_(numerical_flux.copy()) + , extrapolate_(boundary_extrapolation_lambda) + , source_is_elementwise_constant_(source_is_elementwise_constant) + {} + + LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator( + const SourceSpaceType& source_space, + const SV& source_vector, + const NumericalFluxType& numerical_flux, + LambdaType boundary_extrapolation_lambda, + const XT::Common::ParameterType& boundary_treatment_param_type = {}, + const bool source_is_elementwise_constant = false) + : BaseType(source_space, source_vector, 1, numerical_flux.parameter_type() + boundary_treatment_param_type) , numerical_flux_(numerical_flux.copy()) , extrapolate_(boundary_extrapolation_lambda) + , source_is_elementwise_constant_(source_is_elementwise_constant) + {} + + LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator( + const DiscreteSourceType& source, + const NumericalFluxType& numerical_flux, + LambdaType boundary_extrapolation_lambda, + const XT::Common::ParameterType& boundary_treatment_param_type = {}) + : ThisType(source, + numerical_flux, + boundary_extrapolation_lambda, + boundary_treatment_param_type, + source.space().type() == SpaceType::finite_volume) {} LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator(const ThisType& other) - : BaseType(other.parameter_type()) + : BaseType(other) , numerical_flux_(other.numerical_flux_->copy()) , extrapolate_(other.extrapolate_) + , source_is_elementwise_constant_(other.source_is_elementwise_constant_) {} std::unique_ptr<BaseType> copy() const override final @@ -213,34 +361,50 @@ public: return std::make_unique<ThisType>(*this); } - void apply(const SourceType& source, - const IntersectionType& intersection, - LocalInsideRangeType& local_range_inside, + bool linear() const override final + { + return numerical_flux_->linear(); + } + + void apply(LocalInsideRangeType& local_range_inside, LocalOutsideRangeType& /*local_range_outside*/, const XT::Common::Parameter& param = {}) const override final { - DUNE_THROW_IF((source.space().type() != SpaceType::finite_volume) - || (local_range_inside.space().type() != SpaceType::finite_volume), + DUNE_THROW_IF(local_range_inside.space().type() != SpaceType::finite_volume, Exceptions::operator_error, "Use LocalAdvectionDgBoundaryTreatmentByCustomExtrapolationOperator instead!"); - const auto& element = local_range_inside.element(); - const auto u = source.local_discrete_function(element); - const auto v = extrapolate_(intersection, - ReferenceElements<D, d - 1>::general(intersection.type()).position(0, 0), - numerical_flux_->flux(), - u->dofs(), - param); + if (numerical_flux_->x_dependent()) + x_in_intersection_coords_ = intersection.geometry().local(intersection.geometry().center()); + u_ = local_sources_[0]->evaluate(source_is_elementwise_constant_ ? CouplingOperatorType::static_x + : intersection.geometryInInside().center()); + v_ = extrapolate_(intersection, + ReferenceElements<D, d - 1>::general(intersection.type()).position(0, 0), + numerical_flux_->flux(), + u_, + param); const auto normal = intersection.centerUnitOuterNormal(); - const auto g = numerical_flux_->apply(u->dofs(), v, normal, param); + const auto g = numerical_flux_->apply(x_in_intersection_coords_, u_, v_, normal, param); const auto h_intersection = intersection.geometry().volume(); - const auto h_element = element.geometry().volume(); + const auto h_element = intersection.inside().geometry().volume(); for (size_t ii = 0; ii < m; ++ii) local_range_inside.dofs()[ii] += (g[ii] * h_intersection) / h_element; } // ... apply(...) +protected: + void post_bind(const I& inter) override + { + BaseType::post_bind(inter); + numerical_flux_->bind(inter); + } + private: + using BaseType::local_sources_; std::unique_ptr<NumericalFluxType> numerical_flux_; const LambdaType extrapolate_; + const bool source_is_elementwise_constant_; + mutable LocalIntersectionCoords x_in_intersection_coords_; + mutable StateType u_; + mutable StateType v_; }; // class LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator diff --git a/dune/gdt/local/operators/generic.hh b/dune/gdt/local/operators/generic.hh index 8f6c232b03c560f003d189e91a47a43bb9270af0..72869b7ec25034cf46652f905928ed7347d8abba 100644 --- a/dune/gdt/local/operators/generic.hh +++ b/dune/gdt/local/operators/generic.hh @@ -38,23 +38,37 @@ template <class SV, class RV = SV> class GenericLocalElementOperator : public LocalElementOperatorInterface<SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, RGV, RV> { - using ThisType = GenericLocalElementOperator<SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, RGV, RV>; + using ThisType = GenericLocalElementOperator; using BaseType = LocalElementOperatorInterface<SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, RGV, RV>; public: using typename BaseType::LocalRangeType; + using typename BaseType::LocalSourceType; using typename BaseType::SourceType; - using GenericFunctionType = std::function<void( - const SourceType& /*source*/, LocalRangeType& /*local_range*/, const XT::Common::Parameter& /*param*/)>; + using GenericFunctionType = std::function<void(const SourceType& /*source*/, + const std::vector<std::unique_ptr<LocalSourceType>>& /*local_source*/, + LocalRangeType& /*local_range*/, + const XT::Common::Parameter& /*param*/)>; + + // When using this constructor, source has to be set by a call to with_source before calling apply + GenericLocalElementOperator(GenericFunctionType func, + const size_t num_local_sources = 0, + const XT::Common::ParameterType& param_type = {}) + : BaseType(num_local_sources, param_type) + , func_(func) + {} - GenericLocalElementOperator(GenericFunctionType func, const XT::Common::ParameterType& param_type = {}) - : BaseType(param_type) + GenericLocalElementOperator(const SourceType& source, + GenericFunctionType func, + const size_t num_local_sources = 0, + const XT::Common::ParameterType& param_type = {}) + : BaseType(source, num_local_sources, param_type) , func_(func) {} GenericLocalElementOperator(const ThisType& other) - : BaseType(other.parameter_type()) + : BaseType(other) , func_(other.func_) {} @@ -63,11 +77,9 @@ public: return std::make_unique<ThisType>(*this); } - void apply(const SourceType& source, - LocalRangeType& local_range, - const XT::Common::Parameter& param = {}) const override final + void apply(LocalRangeType& local_range, const XT::Common::Parameter& param = {}) const override final { - func_(source, local_range, this->parse_parameter(param)); + func_(this->source(), this->local_sources(), local_range, this->parse_parameter(param)); } private: @@ -97,28 +109,41 @@ template <class I, class GenericLocalIntersectionOperator : public LocalIntersectionOperatorInterface<I, SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, IRGV, IRV, ORGV, ORV> { - using ThisType = GenericLocalIntersectionOperator<I, SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, IRGV, IRV, ORGV, ORV>; + using ThisType = GenericLocalIntersectionOperator; using BaseType = LocalIntersectionOperatorInterface<I, SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, IRGV, IRV, ORGV, ORV>; public: using typename BaseType::IntersectionType; using typename BaseType::LocalInsideRangeType; using typename BaseType::LocalOutsideRangeType; + using typename BaseType::LocalSourceType; using typename BaseType::SourceType; using GenericFunctionType = std::function<void(const SourceType& /*source*/, + const std::vector<std::unique_ptr<LocalSourceType>>& /*local_source*/, const IntersectionType& /*intersection*/, LocalInsideRangeType& /*local_range_inside*/, LocalOutsideRangeType& /*local_range_outside*/, const XT::Common::Parameter& /*param*/)>; - GenericLocalIntersectionOperator(GenericFunctionType func, const XT::Common::ParameterType& param_type = {}) - : BaseType(param_type) + // When using this constructor, source has to be set by a call to with_source before calling apply + GenericLocalIntersectionOperator(GenericFunctionType func, + const size_t num_local_sources = 1, + const XT::Common::ParameterType& param_type = {}) + : BaseType(num_local_sources, param_type) + , func_(func) + {} + + GenericLocalIntersectionOperator(const SourceType& source, + GenericFunctionType func, + const size_t num_local_sources = 1, + const XT::Common::ParameterType& param_type = {}) + : BaseType(source, num_local_sources, param_type) , func_(func) {} GenericLocalIntersectionOperator(const ThisType& other) - : BaseType(other.parameter_type()) + : BaseType(other) , func_(other.func_) {} @@ -127,13 +152,16 @@ public: return std::make_unique<ThisType>(*this); } - void apply(const SourceType& source, - const IntersectionType& intersection, - LocalInsideRangeType& local_range_inside, + void apply(LocalInsideRangeType& local_range_inside, LocalOutsideRangeType& local_range_outside, const XT::Common::Parameter& param = {}) const override final { - func_(source, intersection, local_range_inside, local_range_outside, this->parse_parameter(param)); + func_(this->source(), + this->local_sources(), + intersection, + local_range_inside, + local_range_outside, + this->parse_parameter(param)); } private: diff --git a/dune/gdt/local/operators/interfaces.hh b/dune/gdt/local/operators/interfaces.hh index de484154e36398e27d48ba556fcc1ecfc51c2cf5..408005b0247e1c74a0dc9b74b164de595837189f 100644 --- a/dune/gdt/local/operators/interfaces.hh +++ b/dune/gdt/local/operators/interfaces.hh @@ -20,7 +20,10 @@ #include <dune/xt/common/parameter.hh> #include <dune/xt/common/type_traits.hh> +#include <dune/xt/common/memory.hh> + #include <dune/xt/grid/type_traits.hh> +#include <dune/xt/grid/bound-object.hh> #include <dune/gdt/local/discretefunction.hh> #include <dune/gdt/discretefunction/default.hh> @@ -39,7 +42,9 @@ template <class SourceVector, class RangeField = SourceField, class RangeGridView = SourceGridView, class RangeVector = SourceVector> -class LocalElementOperatorInterface : public XT::Common::ParametricInterface +class LocalElementOperatorInterface + : public XT::Common::ParametricInterface + , public XT::Grid::ElementBoundObject<XT::Grid::extract_entity_t<SourceGridView>> { static_assert( std::is_same<XT::Grid::extract_entity_t<SourceGridView>, XT::Grid::extract_entity_t<RangeGridView>>::value, ""); @@ -50,7 +55,6 @@ public: static const constexpr size_t s_r = source_range_dim; static const constexpr size_t s_rC = source_range_dim_cols; using SR = SourceField; - using SourceType = ConstDiscreteFunction<SV, SGV, s_r, s_rC, SR>; using RV = RangeVector; using RGV = RangeGridView; @@ -63,18 +67,96 @@ public: using D = typename LocalRangeType::D; using E = typename LocalRangeType::E; - using ThisType = LocalElementOperatorInterface<SV, SGV, s_r, s_rC, SR, r_r, r_rC, RR, RGV, RV>; + using SourceType = XT::Functions::GridFunctionInterface<E, s_r, s_rC, SR>; + using LocalSourceType = typename SourceType::LocalFunctionType; + using DiscreteSourceType = ConstDiscreteFunction<SV, SGV, s_r, s_rC, SR>; + using SourceSpaceType = typename DiscreteSourceType::SpaceType; + + using ThisType = LocalElementOperatorInterface; + + // Allows construction without source, source has to be set by a call to with_source before calling apply + LocalElementOperatorInterface(const size_t num_local_sources = 1, const XT::Common::ParameterType& param_type = {}) + : XT::Common::ParametricInterface(param_type) + , source_() + , local_sources_(0) + { + for (size_t ii = 0; ii < num_local_sources; ++ii) + local_sources_.emplace_back(nullptr); + } + + LocalElementOperatorInterface(const SourceType& source, + const size_t num_local_sources = 1, + const XT::Common::ParameterType& param_type = {}) + : XT::Common::ParametricInterface(param_type) + , source_(source) + , local_sources_(0) + { + for (size_t ii = 0; ii < num_local_sources; ++ii) + local_sources_.emplace_back(source_.access().local_function()); + } - LocalElementOperatorInterface(const XT::Common::ParameterType& param_type = {}) + LocalElementOperatorInterface(const SourceSpaceType& source_space, + const SV& source_vector, + const size_t num_local_sources = 1, + const XT::Common::ParameterType& param_type = {}) : XT::Common::ParametricInterface(param_type) - {} + , source_(new DiscreteSourceType(source_space, source_vector)) + , local_sources_(0) + { + for (size_t ii = 0; ii < num_local_sources; ++ii) + local_sources_.emplace_back(source_.access().local_function()); + } + + LocalElementOperatorInterface(const ThisType& other) + : XT::Common::ParametricInterface(other) + , XT::Grid::ElementBoundObject<E>() + , source_(other.source_) + , local_sources_(0) + { + for (size_t ii = 0; ii < other.local_sources_.size(); ++ii) + local_sources_.emplace_back(other.local_sources_[ii] ? source_.access().local_function() : nullptr); + } virtual ~LocalElementOperatorInterface() = default; virtual std::unique_ptr<ThisType> copy() const = 0; - virtual void - apply(const SourceType& source, LocalRangeType& local_range, const XT::Common::Parameter& param = {}) const = 0; + virtual bool linear() const + { + return false; + } + + virtual void apply(LocalRangeType& local_range, const XT::Common::Parameter& param = {}) const = 0; + + virtual std::unique_ptr<ThisType> with_source(const SourceType& src) const + { + auto ret = copy(); + ret->source_ = XT::Common::ConstStorageProvider<SourceType>(src); + for (size_t ii = 0; ii < local_sources_.size(); ++ii) + ret->local_sources_[ii] = ret->source().local_function(); + return ret; + } + + const SourceType& source() const + { + return source_.access(); + } + + const std::vector<std::unique_ptr<LocalSourceType>>& local_sources() const + { + return local_sources_; + } + +protected: + // We are binding the first local_source to ele and leave the others unbound + void post_bind(const E& ele) override + { + if (local_sources_.size() > 0 && local_sources_[0]) + local_sources_[0]->bind(ele); + } + + XT::Common::ConstStorageProvider<SourceType> source_; + std::vector<std::unique_ptr<LocalSourceType>> local_sources_; }; // class LocalElementOperatorInterface @@ -91,7 +173,9 @@ template <class Intersection, class InsideRangeVector = SourceVector, class OutsideRangeGridView = InsideRangeGridView, class OutsideRangeVector = InsideRangeVector> -class LocalIntersectionOperatorInterface : public XT::Common::ParametricInterface +class LocalIntersectionOperatorInterface + : public XT::Common::ParametricInterface + , public XT::Grid::IntersectionBoundObject<Intersection> { static_assert(XT::Grid::is_intersection<Intersection>::value, ""); static_assert(std::is_same<typename Intersection::Entity, XT::Grid::extract_entity_t<InsideRangeGridView>>::value, @@ -99,10 +183,13 @@ class LocalIntersectionOperatorInterface : public XT::Common::ParametricInterfac static_assert(std::is_same<typename Intersection::Entity, XT::Grid::extract_entity_t<OutsideRangeGridView>>::value, ""); + using ThisType = LocalIntersectionOperatorInterface; + public: static const constexpr size_t d = Intersection::Entity::dimension; using D = typename Intersection::ctype; using I = Intersection; + using E = typename I::Entity; using IntersectionType = Intersection; using SV = SourceVector; @@ -110,7 +197,10 @@ public: static const constexpr size_t s_r = source_range_dim; static const constexpr size_t s_rC = source_range_dim_cols; using SF = SourceField; - using SourceType = ConstDiscreteFunction<SV, SGV, s_r, s_rC, SF>; + using SourceType = XT::Functions::GridFunctionInterface<E, s_r, s_rC, SF>; + using LocalSourceType = typename SourceType::LocalFunctionType; + using DiscreteSourceType = ConstDiscreteFunction<SV, SGV, s_r, s_rC, SF>; + using SourceSpaceType = typename DiscreteSourceType::SpaceType; using IRV = InsideRangeVector; using IRGV = InsideRangeGridView; @@ -123,25 +213,98 @@ public: using ORGV = OutsideRangeGridView; using LocalOutsideRangeType = LocalDiscreteFunction<ORV, ORGV, r_r, r_rC, RF>; - using ThisType = LocalIntersectionOperatorInterface<I, SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, IRGV, IRV, ORGV, ORV>; + // Allows construction without source, source has to be set by a call to with_source before calling apply + LocalIntersectionOperatorInterface(const size_t num_local_sources = 2, + const XT::Common::ParameterType& param_type = {}) + : XT::Common::ParametricInterface(param_type) + , source_() + , local_sources_(0) + { + for (size_t ii = 0; ii < num_local_sources; ++ii) + local_sources_.emplace_back(nullptr); + } + + LocalIntersectionOperatorInterface(const SourceType& src, + const size_t num_local_sources = 2, + const XT::Common::ParameterType& param_type = {}) + : XT::Common::ParametricInterface(param_type) + , source_(src) + , local_sources_(0) + { + for (size_t ii = 0; ii < num_local_sources; ++ii) + local_sources_.emplace_back(source_.access().local_function()); + } - LocalIntersectionOperatorInterface(const XT::Common::ParameterType& param_type = {}) + LocalIntersectionOperatorInterface(const SourceSpaceType& source_space, + const SV& source_vector, + const size_t num_local_sources = 2, + const XT::Common::ParameterType& param_type = {}) : XT::Common::ParametricInterface(param_type) - {} + , source_(new DiscreteSourceType(source_space, source_vector)) + , local_sources_(0) + { + for (size_t ii = 0; ii < num_local_sources; ++ii) + local_sources_.emplace_back(source_.access().local_function()); + } + + LocalIntersectionOperatorInterface(const ThisType& other) + : XT::Common::ParametricInterface(other) + , XT::Grid::IntersectionBoundObject<Intersection>(other) + , source_(other.source_) + , local_sources_(0) + { + for (size_t ii = 0; ii < other.local_sources_.size(); ++ii) + local_sources_.emplace_back(other.local_sources_[ii] ? source_.access().local_function() : nullptr); + } virtual ~LocalIntersectionOperatorInterface() = default; virtual std::unique_ptr<ThisType> copy() const = 0; + virtual bool linear() const + { + return false; + } + /** * \note Presumes that local_range_inside is already bound to intersection.inside() and local_range_outside is * already bound to intersection.outside()! **/ - virtual void apply(const SourceType& source, - const IntersectionType& intersection, - LocalInsideRangeType& local_range_inside, + virtual void apply(LocalInsideRangeType& local_range_inside, LocalOutsideRangeType& local_range_outside, const XT::Common::Parameter& param = {}) const = 0; + + virtual std::unique_ptr<ThisType> with_source(const SourceType& src) const + { + auto ret = copy(); + ret->source_ = XT::Common::ConstStorageProvider<SourceType>(src); + for (size_t ii = 0; ii < local_sources_.size(); ++ii) + ret->local_sources_[ii] = ret->source().local_function(); + return ret; + } + + const SourceType& source() const + { + return source_.access(); + } + + const std::vector<std::unique_ptr<LocalSourceType>>& local_sources() const + { + return local_sources_; + } + +protected: + // We are binding the first local_source to intersection.inside() and the second one to intersection.outside() + void post_bind(const I& inter) override + { + if (local_sources_.size() > 0 && local_sources_[0]) + local_sources_[0]->bind(inter.inside()); + if (local_sources_.size() > 1 && local_sources_[1]) + local_sources_[1]->bind(inter.outside()); + } + + XT::Common::ConstStorageProvider<SourceType> source_; + std::vector<std::unique_ptr<LocalSourceType>> local_sources_; }; // class LocalIntersectionOperatorInterface diff --git a/dune/gdt/norms.hh b/dune/gdt/norms.hh index 185a8e8e9eeb2ab634fcc455b75ca314b1378e30..0cf216524667e970899c220a823b6a9d82126dc2 100644 --- a/dune/gdt/norms.hh +++ b/dune/gdt/norms.hh @@ -16,7 +16,7 @@ #include <dune/xt/functions/interfaces/element-functions.hh> #include <dune/gdt/local/bilinear-forms/integrals.hh> -#include <dune/gdt/local/integrands/elliptic.hh> +#include <dune/gdt/local/integrands/laplace.hh> #include <dune/gdt/local/integrands/product.hh> #include <dune/gdt/operators/localizable-bilinear-form.hh> @@ -69,7 +69,6 @@ template <class GridViewType, class F, size_t r> std::enable_if_t<XT::Grid::is_view<GridViewType>::value, LocalizableBilinearFormBase<GridViewType, r, 1, F, F, 1, 1, F>> make_localizable_elliptic_product( const GridViewType& grid_view, - const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, 1, 1, F>& diffusion_factor, const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, GridViewType::dimension, GridViewType::dimension, @@ -81,42 +80,39 @@ make_localizable_elliptic_product( using E = XT::Grid::extract_entity_t<GridViewType>; auto localizable_product = make_localizable_bilinear_form(grid_view, left, right); localizable_product.append(LocalElementIntegralBilinearForm<E, r, 1, F, F, r, 1, F>( - LocalEllipticIntegrand<E, r, F>(diffusion_factor, diffusion_tensor), over_integrate)); + LocalLaplaceIntegrand<E, r, F>(diffusion_tensor), over_integrate)); return localizable_product; } template <class GridViewType, class F, size_t r> -std::enable_if_t<XT::Grid::is_view<GridViewType>::value, F> elliptic_product( - const GridViewType& grid_view, - const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, 1, 1, F>& diffusion_factor, - const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, - GridViewType::dimension, - GridViewType::dimension, - F>& diffusion_tensor, - const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, r, 1, F>& left, - const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, r, 1, F>& right, - const int over_integrate = 0) +std::enable_if_t<XT::Grid::is_view<GridViewType>::value, F> +elliptic_product(const GridViewType& grid_view, + const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, + GridViewType::dimension, + GridViewType::dimension, + F>& diffusion_tensor, + const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, r, 1, F>& left, + const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, r, 1, F>& right, + const int over_integrate = 0) { - auto product = - make_localizable_elliptic_product(grid_view, diffusion_factor, diffusion_tensor, left, right, over_integrate); + auto product = make_localizable_elliptic_product(grid_view, diffusion_tensor, left, right, over_integrate); product.assemble(); return product.result(); } template <class GridViewType, class F, size_t r> -std::enable_if_t<XT::Grid::is_view<GridViewType>::value, F> elliptic_norm( - const GridViewType& grid_view, - const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, 1, 1, F>& diffusion_factor, - const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, - GridViewType::dimension, - GridViewType::dimension, - F>& diffusion_tensor, - const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, r, 1, F>& func, - const int over_integrate = 0) +std::enable_if_t<XT::Grid::is_view<GridViewType>::value, F> +elliptic_norm(const GridViewType& grid_view, + const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, + GridViewType::dimension, + GridViewType::dimension, + F>& diffusion_tensor, + const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GridViewType>, r, 1, F>& func, + const int over_integrate = 0) { - return std::sqrt(elliptic_product(grid_view, diffusion_factor, diffusion_tensor, func, func, over_integrate)); + return std::sqrt(elliptic_product(grid_view, diffusion_tensor, func, func, over_integrate)); } diff --git a/dune/gdt/operators/advection-dg.hh b/dune/gdt/operators/advection-dg.hh index 621515384a2ac8f762f2c02012ed84c262ae5272..284b2c3d2e54ed15c810dbc08902fcadc718834f 100644 --- a/dune/gdt/operators/advection-dg.hh +++ b/dune/gdt/operators/advection-dg.hh @@ -59,11 +59,11 @@ static inline size_t advection_dg_artificial_viscosity_default_component() * * \sa OperatorInterface */ -template <class M, class SGV, size_t m = 1, class RGV = SGV> -class AdvectionDgOperator : public OperatorInterface<M, SGV, m, 1, m, 1, RGV> +template <class M, class AGV, size_t m = 1, class RGV = AGV, class SGV = AGV> +class AdvectionDgOperator : public LocalizableOperator<M, AGV, m, 1, m, 1, RGV, SGV> { - using ThisType = AdvectionDgOperator<M, SGV, m, RGV>; - using BaseType = OperatorInterface<M, SGV, m, 1, m, 1, RGV>; + using ThisType = AdvectionDgOperator; + using BaseType = LocalizableOperator<M, AGV, m, 1, m, 1, RGV, SGV>; protected: static const constexpr size_t d = SGV::dimension; @@ -73,9 +73,8 @@ public: using typename BaseType::F; using typename BaseType::V; - using NumericalFluxType = NumericalFluxInterface<d, m, F>; - using I = XT::Grid::extract_intersection_t<SGV>; + using NumericalFluxType = NumericalFluxInterface<I, d, m, F>; using BoundaryTreatmentByCustomNumericalFluxOperatorType = LocalAdvectionDgBoundaryTreatmentByCustomNumericalFluxOperator<I, V, SGV, m, F, F, RGV, V>; using BoundaryTreatmentByCustomExtrapolationOperatorType = @@ -96,39 +95,41 @@ public: const double& artificial_viscosity_nu_1 = advection_dg_artificial_viscosity_default_nu_1(), const double& artificial_viscosity_alpha_1 = advection_dg_artificial_viscosity_default_alpha_1(), const size_t artificial_viscosity_component = advection_dg_artificial_viscosity_default_component()) - : BaseType(numerical_flux.parameter_type()) - , assembly_grid_view_(assembly_grid_view) + : BaseType(assembly_grid_view, source_space, range_space) , numerical_flux_(numerical_flux.copy()) - , source_space_(source_space) - , range_space_(range_space) , periodicity_exception_(periodicity_exception.copy()) - , local_mass_matrix_provider_(assembly_grid_view_, range_space_) + , local_mass_matrix_provider_(assembly_grid_view, range_space) , artificial_viscosity_nu_1_(artificial_viscosity_nu_1) , artificial_viscosity_alpha_1_(artificial_viscosity_alpha_1) , artificial_viscosity_component_(artificial_viscosity_component) { // we assemble these once, to be used in each apply later on - auto walker = XT::Grid::make_walker(assembly_grid_view_); + auto walker = XT::Grid::make_walker(assembly_grid_view); walker.append(local_mass_matrix_provider_); walker.walk(/*use_tbb=*/true); - } + // element contributions + this->append( + LocalAdvectionDgVolumeOperator<V, SGV, m, F, F, RGV, V>(local_mass_matrix_provider_, numerical_flux_->flux())); + // contributions from inner intersections + this->append(LocalAdvectionDgCouplingOperator<I, V, SGV, m, F, F, RGV, V>( + local_mass_matrix_provider_, *numerical_flux_, /*compute_outside=*/false), + XT::Grid::ApplyOn::InnerIntersections<SGV>()); + // contributions from periodic boundaries + this->append(LocalAdvectionDgCouplingOperator<I, V, SGV, m, F, F, RGV, V>( + local_mass_matrix_provider_, *numerical_flux_, /*compute_outside=*/false), + *(XT::Grid::ApplyOn::PeriodicBoundaryIntersections<SGV>() && !(*periodicity_exception_))); + // artificial viscosity by shock capturing [DF2015, Sec. 8.5] + this->append(LocalAdvectionDgArtificialViscosityShockCapturingOperator<V, SGV, m, F, F, RGV, V>( + local_mass_matrix_provider_, + this->assembly_grid_view_, + artificial_viscosity_nu_1_, + artificial_viscosity_alpha_1_, + artificial_viscosity_component_)); + } // AdvectionDgOperator(...) AdvectionDgOperator(ThisType&& source) = default; - bool linear() const override final - { - return numerical_flux_->linear(); - } - - const SourceSpaceType& source_space() const override final - { - return source_space_; - } - - const RangeSpaceType& range_space() const override final - { - return range_space_; - } + using BaseType::append; /// \name Non-periodic boundary treatment /// \{ @@ -139,12 +140,11 @@ public: const XT::Common::ParameterType& boundary_treatment_parameter_type = {}, const XT::Grid::IntersectionFilter<SGV>& filter = XT::Grid::ApplyOn::BoundaryIntersections<SGV>()) { - boundary_treatments_by_custom_numerical_flux_.emplace_back( - new BoundaryTreatmentByCustomNumericalFluxOperatorType(local_mass_matrix_provider_, - numerical_boundary_treatment_flux, - numerical_boundary_treatment_flux_order, - boundary_treatment_parameter_type), - filter.copy()); + this->append(BoundaryTreatmentByCustomNumericalFluxOperatorType(local_mass_matrix_provider_, + numerical_boundary_treatment_flux, + numerical_boundary_treatment_flux_order, + boundary_treatment_parameter_type), + filter.copy()); return *this; } // ... append(...) @@ -152,174 +152,44 @@ public: const XT::Common::ParameterType& extrapolation_parameter_type = {}, const XT::Grid::IntersectionFilter<SGV>& filter = XT::Grid::ApplyOn::BoundaryIntersections<SGV>()) { - boundary_treatments_by_custom_extrapolation_.emplace_back( - new BoundaryTreatmentByCustomExtrapolationOperatorType( - local_mass_matrix_provider_, *numerical_flux_, extrapolation, extrapolation_parameter_type), - filter.copy()); + this->append(BoundaryTreatmentByCustomExtrapolationOperatorType( + local_mass_matrix_provider_, *numerical_flux_, extrapolation, extrapolation_parameter_type), + filter.copy()); return *this; } /// \} - void apply(const VectorType& source, VectorType& range, const XT::Common::Parameter& param = {}) const override - { - // some checks - DUNE_THROW_IF(!source.valid(), Exceptions::operator_error, "source contains inf or nan!"); - DUNE_THROW_IF(!(this->parameter_type() <= param.type()), - Exceptions::operator_error, - "this->parameter_type() = " << this->parameter_type() << "\n param.type() = " << param.type()); - range.set_all(0); - auto source_function = make_discrete_function(this->source_space_, source); - auto range_function = make_discrete_function(this->range_space_, range); - // set up the actual operator - auto localizable_op = make_localizable_operator(this->assembly_grid_view_, source_function, range_function); - // element contributions - localizable_op.append( - LocalAdvectionDgVolumeOperator<V, SGV, m, F, F, RGV, V>(local_mass_matrix_provider_, numerical_flux_->flux()), - param); - // contributions from inner intersections - localizable_op.append(LocalAdvectionDgCouplingOperator<I, V, SGV, m, F, F, RGV, V>( - local_mass_matrix_provider_, *numerical_flux_, /*compute_outside=*/false), - param, - XT::Grid::ApplyOn::InnerIntersections<SGV>()); - // contributions from periodic boundaries - localizable_op.append(LocalAdvectionDgCouplingOperator<I, V, SGV, m, F, F, RGV, V>( - local_mass_matrix_provider_, *numerical_flux_, /*compute_outside=*/false), - param, - *(XT::Grid::ApplyOn::PeriodicBoundaryIntersections<SGV>() && !(*periodicity_exception_))); - // contributions from other boundaries by custom numerical flux - for (const auto& boundary_treatment : boundary_treatments_by_custom_numerical_flux_) { - const auto& boundary_op = *boundary_treatment.first; - const auto& filter = *boundary_treatment.second; - localizable_op.append(boundary_op, param, filter); - } - // contributions from other boundaries by custom extrapolation - for (const auto& boundary_treatment : boundary_treatments_by_custom_extrapolation_) { - const auto& boundary_op = *boundary_treatment.first; - const auto& filter = *boundary_treatment.second; - localizable_op.append(boundary_op, param, filter); - } - // artificial viscosity by shock capturing [DF2015, Sec. 8.5] - localizable_op.append(LocalAdvectionDgArtificialViscosityShockCapturingOperator<V, SGV, m, F, F, RGV, V>( - local_mass_matrix_provider_, - this->assembly_grid_view_, - artificial_viscosity_nu_1_, - artificial_viscosity_alpha_1_, - artificial_viscosity_component_), - param); - // and apply it in a grid walk - localizable_op.assemble(/*use_tbb=*/true); - DUNE_THROW_IF(!range.valid(), Exceptions::operator_error, "range contains inf or nan!"); - } // ... apply(...) - - std::vector<std::string> jacobian_options() const override final - { - return {"finite-differences"}; - } - - XT::Common::Configuration jacobian_options(const std::string& type) const override final - { - DUNE_THROW_IF(type != this->jacobian_options().at(0), Exceptions::operator_error, "type = " << type); - return {{"type", type}, {"eps", "1e-7"}}; - } - - using BaseType::jacobian; - - void jacobian(const VectorType& source, - MatrixOperatorType& jacobian_op, - const XT::Common::Configuration& opts, - const XT::Common::Parameter& param = {}) const override final - { - // some checks - DUNE_THROW_IF(!source.valid(), Exceptions::operator_error, "source contains inf or nan!"); - DUNE_THROW_IF(!(this->parameter_type() <= param.type()), - Exceptions::operator_error, - "this->parameter_type() = " << this->parameter_type() << "\n param.type() = " << param.type()); - DUNE_THROW_IF(!opts.has_key("type"), Exceptions::operator_error, opts); - DUNE_THROW_IF(opts.get<std::string>("type") != jacobian_options().at(0), Exceptions::operator_error, opts); - const auto default_opts = jacobian_options(jacobian_options().at(0)); - const auto eps = opts.get("eps", default_opts.template get<double>("eps")); - const auto parameter = param + XT::Common::Parameter({"finite-difference-jacobians.eps", eps}); - // append the same local ops with the same filters as in apply() above - // element contributions - jacobian_op.append( - LocalAdvectionDgVolumeOperator<V, SGV, m, F, F, RGV, V>(local_mass_matrix_provider_, numerical_flux_->flux()), - source, - parameter); - // contributions from inner intersections - jacobian_op.append(LocalAdvectionDgCouplingOperator<I, V, SGV, m, F, F, RGV, V>( - local_mass_matrix_provider_, *numerical_flux_, /*compute_outside=*/false), - source, - parameter, - XT::Grid::ApplyOn::InnerIntersections<SGV>()); - // contributions from periodic boundaries - jacobian_op.append(LocalAdvectionDgCouplingOperator<I, V, SGV, m, F, F, RGV, V>( - local_mass_matrix_provider_, *numerical_flux_, /*compute_outside=*/false), - source, - parameter, - *(XT::Grid::ApplyOn::PeriodicBoundaryIntersections<SGV>() && !(*periodicity_exception_))); - // contributions from other boundaries by custom numerical flux - for (const auto& boundary_treatment : boundary_treatments_by_custom_numerical_flux_) { - const auto& boundary_op = *boundary_treatment.first; - const auto& filter = *boundary_treatment.second; - jacobian_op.append(boundary_op, source, parameter, filter); - } - // contributions from other boundaries by custom extrapolation - for (const auto& boundary_treatment : boundary_treatments_by_custom_extrapolation_) { - const auto& boundary_op = *boundary_treatment.first; - const auto& filter = *boundary_treatment.second; - jacobian_op.append(boundary_op, source, parameter, filter); - } - // artificial viscosity by shock capturing [DF2015, Sec. 8.5] - jacobian_op.append(LocalAdvectionDgArtificialViscosityShockCapturingOperator<V, SGV, m, F, F, RGV, V>( - local_mass_matrix_provider_, - this->assembly_grid_view_, - artificial_viscosity_nu_1_, - artificial_viscosity_alpha_1_, - artificial_viscosity_component_), - source, - param); - } // ... jacobian(...) - protected: - const SGV assembly_grid_view_; const std::unique_ptr<const NumericalFluxType> numerical_flux_; - const SourceSpaceType& source_space_; - const RangeSpaceType& range_space_; std::unique_ptr<XT::Grid::IntersectionFilter<SGV>> periodicity_exception_; LocalMassMatrixProvider<RGV, m, 1, F> local_mass_matrix_provider_; const double artificial_viscosity_nu_1_; const double artificial_viscosity_alpha_1_; const size_t artificial_viscosity_component_; - std::list<std::pair<std::unique_ptr<BoundaryTreatmentByCustomNumericalFluxOperatorType>, - std::unique_ptr<XT::Grid::IntersectionFilter<SGV>>>> - boundary_treatments_by_custom_numerical_flux_; - std::list<std::pair<std::unique_ptr<BoundaryTreatmentByCustomExtrapolationOperatorType>, - std::unique_ptr<XT::Grid::IntersectionFilter<SGV>>>> - boundary_treatments_by_custom_extrapolation_; }; // class AdvectionDgOperator -template <class MatrixType, class SGV, size_t m, class F, class RGV> -std::enable_if_t<XT::LA::is_matrix<MatrixType>::value, AdvectionDgOperator<MatrixType, SGV, m, RGV>> +template <class MatrixType, class AGV, size_t m, class F, class RGV, class SGV> +std::enable_if_t<XT::LA::is_matrix<MatrixType>::value, AdvectionDgOperator<MatrixType, AGV, m, RGV, SGV>> make_advection_dg_operator( - const SGV& assembly_grid_view, - const NumericalFluxInterface<SGV::dimension, m, F>& numerical_flux, + const AGV& assembly_grid_view, + const NumericalFluxInterface<XT::Grid::extract_intersection_t<AGV>, AGV::dimension, m, F>& numerical_flux, const SpaceInterface<SGV, m, 1, F>& source_space, const SpaceInterface<RGV, m, 1, F>& range_space, - const XT::Grid::IntersectionFilter<SGV>& periodicity_exception = XT::Grid::ApplyOn::NoIntersections<SGV>(), + const XT::Grid::IntersectionFilter<AGV>& periodicity_exception = XT::Grid::ApplyOn::NoIntersections<AGV>(), const double& artificial_viscosity_nu_1 = advection_dg_artificial_viscosity_default_nu_1(), const double& artificial_viscosity_alpha_1 = advection_dg_artificial_viscosity_default_alpha_1(), const size_t artificial_viscosity_component = advection_dg_artificial_viscosity_default_component()) { - return AdvectionDgOperator<MatrixType, SGV, m, RGV>(assembly_grid_view, - numerical_flux, - source_space, - range_space, - periodicity_exception, - artificial_viscosity_nu_1, - artificial_viscosity_alpha_1, - artificial_viscosity_component); + return AdvectionDgOperator<MatrixType, AGV, m, RGV, SGV>(assembly_grid_view, + numerical_flux, + source_space, + range_space, + periodicity_exception, + artificial_viscosity_nu_1, + artificial_viscosity_alpha_1, + artificial_viscosity_component); } diff --git a/dune/gdt/operators/advection-fv-entropybased.hh b/dune/gdt/operators/advection-fv-entropybased.hh new file mode 100644 index 0000000000000000000000000000000000000000..5b8462f3e6a846dea6d2cf424595d93bad2197fd --- /dev/null +++ b/dune/gdt/operators/advection-fv-entropybased.hh @@ -0,0 +1,186 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2017 - 2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_OPERATORS_FV_ENTROPYBASED_HH +#define DUNE_GDT_OPERATORS_FV_ENTROPYBASED_HH + +#include <dune/gdt/operators/interfaces.hh> + +namespace Dune { +namespace GDT { + + +template <class OperatorImp, class InverseHessianOperatorImp> +class EntropicCoordinatesOperator + : public OperatorInterface<typename OperatorImp::MatrixType, typename OperatorImp::SGV, OperatorImp::s_r> +{ + using BaseType = OperatorInterface<typename OperatorImp::MatrixType, typename OperatorImp::SGV, OperatorImp::s_r>; + +public: + using typename BaseType::RangeSpaceType; + using typename BaseType::SourceSpaceType; + using typename BaseType::VectorType; + + using OperatorType = OperatorImp; + using InverseHessianOperatorType = InverseHessianOperatorImp; + + EntropicCoordinatesOperator(const OperatorType& operator_in, + const InverseHessianOperatorType& inverse_hessian_operator) + : operator_(operator_in) + , inverse_hessian_operator_(inverse_hessian_operator) + {} + + bool linear() const override final + { + return false; + } + + const SourceSpaceType& source_space() const override final + { + return operator_.source_space(); + } + + const RangeSpaceType& range_space() const override final + { + return operator_.range_space(); + } + + void apply(const VectorType& source, VectorType& range, const XT::Common::Parameter& param) const override final + { + VectorType u_update = range; + std::fill(u_update.begin(), u_update.end(), 0.); + operator_.apply(source, u_update, param); + inverse_hessian_operator_.apply_inverse_hessian(source, u_update, range, param); + } + + const OperatorType& operator_; + const InverseHessianOperatorType& inverse_hessian_operator_; +}; // class EntropicCoordinatesOperator<...> + +template <class DensityOperatorImp, class AdvectionOperatorImp, class RhsOperatorImp, class InverseHessianOperatorImp> +class EntropicCoordinatesCombinedOperator + : public OperatorInterface<typename AdvectionOperatorImp::MatrixType, + typename AdvectionOperatorImp::SGV, + AdvectionOperatorImp::s_r> +{ + using BaseType = OperatorInterface<typename AdvectionOperatorImp::MatrixType, + typename AdvectionOperatorImp::SGV, + AdvectionOperatorImp::s_r>; + +public: + using typename BaseType::RangeSpaceType; + using typename BaseType::SourceSpaceType; + using typename BaseType::VectorType; + + using DensityOperatorType = DensityOperatorImp; + using AdvectionOperatorType = AdvectionOperatorImp; + using RhsOperatorType = RhsOperatorImp; + using InverseHessianOperatorType = InverseHessianOperatorImp; + + EntropicCoordinatesCombinedOperator(const DensityOperatorType& density_op, + const AdvectionOperatorType& advection_op, + const RhsOperatorType& rhs_op, + const InverseHessianOperatorType& inverse_hessian_operator) + : density_op_(density_op) + , advection_op_(advection_op) + , rhs_op_(rhs_op) + , inverse_hessian_operator_(inverse_hessian_operator) + {} + + bool linear() const override final + { + return false; + } + + const SourceSpaceType& source_space() const override final + { + return advection_op_.source_space(); + } + + const RangeSpaceType& range_space() const override final + { + return advection_op_.range_space(); + } + + void apply(const VectorType& source, VectorType& range, const XT::Common::Parameter& param) const override final + { + density_op_.apply(source, range, param); + VectorType u_update = range; + std::fill(u_update.begin(), u_update.end(), 0.); + advection_op_.apply(source, u_update, param); + u_update *= -1.; + rhs_op_.apply(source, u_update, param); + inverse_hessian_operator_.apply_inverse_hessian(source, u_update, range, param); + } + + const DensityOperatorType& density_op_; + const AdvectionOperatorType& advection_op_; + const RhsOperatorType& rhs_op_; + const InverseHessianOperatorType& inverse_hessian_operator_; +}; // class EntropicCoordinatesOperator<...> + + +template <class AdvectionOperatorImp, class EntropySolverImp> +class EntropyBasedMomentFvOperator + : public OperatorInterface<typename AdvectionOperatorImp::MatrixType, + typename AdvectionOperatorImp::SGV, + AdvectionOperatorImp::s_r> +{ + using BaseType = OperatorInterface<typename AdvectionOperatorImp::MatrixType, + typename AdvectionOperatorImp::SGV, + AdvectionOperatorImp::s_r>; + +public: + using typename BaseType::RangeSpaceType; + using typename BaseType::SourceSpaceType; + using typename BaseType::VectorType; + + using AdvectionOperatorType = AdvectionOperatorImp; + using EntropySolverType = EntropySolverImp; + + EntropyBasedMomentFvOperator(const AdvectionOperatorType& advection_operator, const EntropySolverType& entropy_solver) + : advection_operator_(advection_operator) + , entropy_solver_(entropy_solver) + {} + + bool linear() const override final + { + return false; + } + + const SourceSpaceType& source_space() const override final + { + return advection_operator_.source_space(); + } + + const RangeSpaceType& range_space() const override final + { + return advection_operator_.range_space(); + } + + void apply(const VectorType& source, VectorType& range, const XT::Common::Parameter& param) const override final + { + // solve optimization problems and regularize if necessary + VectorType regularized = range; + entropy_solver_.apply(source, regularized, param); + + std::fill(range.begin(), range.end(), 0.); + advection_operator_.apply(regularized, range, param); + } + + const AdvectionOperatorType& advection_operator_; + const EntropySolverType& entropy_solver_; +}; // class EntropyBasedMomentFvOperator<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_OPERATORS_FV_ENTROPYBASED_HH diff --git a/dune/gdt/operators/advection-fv.hh b/dune/gdt/operators/advection-fv.hh index ecd296021602d418383848ad55e23a1b387ac727..19cb4f456889f9f21ed13fb9b7c8196e0e8613a6 100644 --- a/dune/gdt/operators/advection-fv.hh +++ b/dune/gdt/operators/advection-fv.hh @@ -12,6 +12,8 @@ #ifndef DUNE_GDT_OPERATORS_ADVECTION_FV_HH #define DUNE_GDT_OPERATORS_ADVECTION_FV_HH +#include <dune/grid/common/partitionset.hh> + #include <dune/xt/common/type_traits.hh> #include <dune/xt/grid/type_traits.hh> #include <dune/xt/grid/filters.hh> @@ -36,23 +38,26 @@ namespace GDT { * * \sa OperatorInterface */ -template <class M, class SGV, size_t m = 1, class RGV = SGV> -class AdvectionFvOperator : public OperatorInterface<M, SGV, m, 1, m, 1, RGV> +template <class M, class AGV, size_t m = 1, class RGV = AGV, class SGV = AGV> +class AdvectionFvOperator : public LocalizableOperator<M, AGV, m, 1, m, 1, RGV, SGV> { - using ThisType = AdvectionFvOperator<M, SGV, m, RGV>; - using BaseType = OperatorInterface<M, SGV, m, 1, m, 1, RGV>; + using ThisType = AdvectionFvOperator; + using BaseType = LocalizableOperator<M, AGV, m, 1, m, 1, RGV, SGV>; public: + using BaseType::s_r; + using BaseType::s_rC; using typename BaseType::F; using typename BaseType::V; - using NumericalFluxType = NumericalFluxInterface<SGV::dimension, m, F>; - using I = XT::Grid::extract_intersection_t<SGV>; + using E = XT::Grid::extract_entity_t<SGV>; + using NumericalFluxType = NumericalFluxInterface<I, SGV::dimension, m, F>; using BoundaryTreatmentByCustomNumericalFluxOperatorType = LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator<I, V, SGV, m, F, F, RGV, V>; using BoundaryTreatmentByCustomExtrapolationOperatorType = LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator<I, V, SGV, m, F, F, RGV, V>; + using SourceType = XT::Functions::GridFunctionInterface<E, s_r, s_rC, F>; using typename BaseType::MatrixOperatorType; using typename BaseType::RangeSpaceType; @@ -65,30 +70,25 @@ public: const SourceSpaceType& source_space, const RangeSpaceType& range_space, const XT::Grid::IntersectionFilter<SGV>& periodicity_exception = XT::Grid::ApplyOn::NoIntersections<SGV>()) - : BaseType(numerical_flux.parameter_type()) - , assembly_grid_view_(assembly_grid_view) + : BaseType(assembly_grid_view, source_space, range_space) , numerical_flux_(numerical_flux.copy()) - , source_space_(source_space) - , range_space_(range_space) , periodicity_exception_(periodicity_exception.copy()) - {} - - AdvectionFvOperator(ThisType&& source) = default; - - bool linear() const override final { - return numerical_flux_->linear(); + // contributions from inner intersections + this->append(LocalAdvectionFvCouplingOperator<I, V, SGV, m, F, F, RGV, V>(*numerical_flux_), + XT::Grid::ApplyOn::InnerIntersectionsOnce<SGV>()); + // contributions from periodic boundaries + this->append(LocalAdvectionFvCouplingOperator<I, V, SGV, m, F, F, RGV, V>(*numerical_flux_), + *(XT::Grid::ApplyOn::PeriodicBoundaryIntersectionsOnce<SGV>() && !(*periodicity_exception_))); } - const SourceSpaceType& source_space() const override final - { - return source_space_; - } + AdvectionFvOperator(ThisType&& source) + : BaseType(std::move(source)) + , numerical_flux_(std::move(source.numerical_flux_)) + , periodicity_exception_(std::move(source.periodicity_exception_)) + {} - const RangeSpaceType& range_space() const override final - { - return range_space_; - } + using BaseType::append; /// \name Non-periodic boundary treatment /// \{ @@ -98,12 +98,9 @@ public: const XT::Common::ParameterType& boundary_treatment_parameter_type = {}, const XT::Grid::IntersectionFilter<SGV>& filter = XT::Grid::ApplyOn::BoundaryIntersections<SGV>()) { - boundary_treatments_by_custom_numerical_flux_.emplace_back(); - boundary_treatments_by_custom_numerical_flux_.back().first = - std::make_unique<BoundaryTreatmentByCustomNumericalFluxOperatorType>(numerical_boundary_treatment_flux, - boundary_treatment_parameter_type); - boundary_treatments_by_custom_numerical_flux_.back().second = - std::unique_ptr<XT::Grid::IntersectionFilter<SGV>>(filter.copy()); + this->append(BoundaryTreatmentByCustomNumericalFluxOperatorType(numerical_boundary_treatment_flux, + boundary_treatment_parameter_type), + filter); return *this; } @@ -111,134 +108,30 @@ public: const XT::Common::ParameterType& extrapolation_parameter_type = {}, const XT::Grid::IntersectionFilter<SGV>& filter = XT::Grid::ApplyOn::BoundaryIntersections<SGV>()) { - boundary_treatments_by_custom_extrapolation_.emplace_back(); - boundary_treatments_by_custom_extrapolation_.back().first = - std::make_unique<BoundaryTreatmentByCustomExtrapolationOperatorType>( - *numerical_flux_, extrapolation, extrapolation_parameter_type), - boundary_treatments_by_custom_extrapolation_.back().second = - std::unique_ptr<XT::Grid::IntersectionFilter<SGV>>(filter.copy()); + this->append(BoundaryTreatmentByCustomExtrapolationOperatorType( + *numerical_flux_, extrapolation, extrapolation_parameter_type), + filter); return *this; } /// \} - using BaseType::apply; - - void apply(const VectorType& source, VectorType& range, const XT::Common::Parameter& param = {}) const override final - { - // some checks - DUNE_THROW_IF(!source.valid(), Exceptions::operator_error, "source contains inf or nan!"); - DUNE_THROW_IF(!(this->parameter_type() <= param.type()), - Exceptions::operator_error, - "this->parameter_type() = " << this->parameter_type() << "\n param.type() = " << param.type()); - range.set_all(0); - const auto source_function = make_discrete_function(source_space_, source); - auto range_function = make_discrete_function(range_space_, range); - // set up the actual operator - auto localizable_op = make_localizable_operator(assembly_grid_view_, source_function, range_function); - // contributions from inner intersections - localizable_op.append(LocalAdvectionFvCouplingOperator<I, V, SGV, m, F, F, RGV, V>(*numerical_flux_), - param, - XT::Grid::ApplyOn::InnerIntersectionsOnce<SGV>()); - // contributions from periodic boundaries - localizable_op.append(LocalAdvectionFvCouplingOperator<I, V, SGV, m, F, F, RGV, V>(*numerical_flux_), - param, - *(XT::Grid::ApplyOn::PeriodicBoundaryIntersectionsOnce<SGV>() && !(*periodicity_exception_))); - // contributions from other boundaries by custom numerical flux - for (const auto& boundary_treatment : boundary_treatments_by_custom_numerical_flux_) { - const auto& boundary_op = *boundary_treatment.first; - const auto& filter = *boundary_treatment.second; - localizable_op.append(boundary_op, param, filter); - } - // contributions from other boundaries by custom extrapolation - for (const auto& boundary_treatment : boundary_treatments_by_custom_extrapolation_) { - const auto& boundary_op = *boundary_treatment.first; - const auto& filter = *boundary_treatment.second; - localizable_op.append(boundary_op, param, filter); - } - // do the actual work - localizable_op.assemble(/*use_tbb=*/true); - DUNE_THROW_IF(!range.valid(), Exceptions::operator_error, "range contains inf or nan!"); - } // ... apply(...) - - std::vector<std::string> jacobian_options() const override final - { - return {"finite-differences"}; - } - - XT::Common::Configuration jacobian_options(const std::string& type) const override final - { - DUNE_THROW_IF(type != this->jacobian_options().at(0), Exceptions::operator_error, "type = " << type); - return {{"type", type}, {"eps", "1e-7"}}; - } - - using BaseType::jacobian; - - void jacobian(const VectorType& source, - MatrixOperatorType& jacobian_op, - const XT::Common::Configuration& opts, - const XT::Common::Parameter& param = {}) const override final - { - // some checks - DUNE_THROW_IF(!source.valid(), Exceptions::operator_error, "source contains inf or nan!"); - DUNE_THROW_IF(!(this->parameter_type() <= param.type()), - Exceptions::operator_error, - "this->parameter_type() = " << this->parameter_type() << "\n param.type() = " << param.type()); - DUNE_THROW_IF(!opts.has_key("type"), Exceptions::operator_error, opts); - DUNE_THROW_IF(opts.get<std::string>("type") != jacobian_options().at(0), Exceptions::operator_error, opts); - const auto default_opts = jacobian_options(jacobian_options().at(0)); - const auto eps = opts.get("eps", default_opts.template get<double>("eps")); - const auto parameter = param + XT::Common::Parameter({"finite-difference-jacobians.eps", eps}); - // append the same local ops with the same filters as in apply() above - // contributions from inner intersections - jacobian_op.append(LocalAdvectionFvCouplingOperator<I, V, SGV, m, F, F, RGV, V>(*numerical_flux_), - source, - parameter, - XT::Grid::ApplyOn::InnerIntersectionsOnce<SGV>()); - // contributions from periodic boundaries - jacobian_op.append(LocalAdvectionFvCouplingOperator<I, V, SGV, m, F, F, RGV, V>(*numerical_flux_), - source, - parameter, - *(XT::Grid::ApplyOn::PeriodicBoundaryIntersectionsOnce<SGV>() && !(*periodicity_exception_))); - // contributions from other boundaries by custom numerical flux - for (const auto& boundary_treatment : boundary_treatments_by_custom_numerical_flux_) { - const auto& boundary_op = *boundary_treatment.first; - const auto& filter = *boundary_treatment.second; - jacobian_op.append(boundary_op, source, parameter, filter); - } - // contributions from other boundaries by custom extrapolation - for (const auto& boundary_treatment : boundary_treatments_by_custom_extrapolation_) { - const auto& boundary_op = *boundary_treatment.first; - const auto& filter = *boundary_treatment.second; - jacobian_op.append(boundary_op, source, parameter, filter); - } - } // ... jacobian(...) - private: - const SGV assembly_grid_view_; std::unique_ptr<const NumericalFluxType> numerical_flux_; - const SourceSpaceType& source_space_; - const RangeSpaceType& range_space_; std::unique_ptr<XT::Grid::IntersectionFilter<SGV>> periodicity_exception_; - std::list<std::pair<std::unique_ptr<BoundaryTreatmentByCustomNumericalFluxOperatorType>, - std::unique_ptr<XT::Grid::IntersectionFilter<SGV>>>> - boundary_treatments_by_custom_numerical_flux_; - std::list<std::pair<std::unique_ptr<BoundaryTreatmentByCustomExtrapolationOperatorType>, - std::unique_ptr<XT::Grid::IntersectionFilter<SGV>>>> - boundary_treatments_by_custom_extrapolation_; }; // class AdvectionFvOperator -template <class MatrixType, class SGV, size_t m, class F, class RGV> -std::enable_if_t<XT::LA::is_matrix<MatrixType>::value, AdvectionFvOperator<MatrixType, SGV, m, RGV>> +template <class MatrixType, class AGV, size_t m, class F, class RGV, class SGV> +std::enable_if_t<XT::LA::is_matrix<MatrixType>::value, AdvectionFvOperator<MatrixType, AGV, m, RGV, SGV>> make_advection_fv_operator( - const SGV& assembly_grid_view, - const NumericalFluxInterface<SGV::dimension, m, F>& numerical_flux, + const AGV& assembly_grid_view, + const NumericalFluxInterface<XT::Grid::extract_intersection_t<AGV>, AGV::dimension, m, F>& numerical_flux, const SpaceInterface<SGV, m, 1, F>& source_space, const SpaceInterface<RGV, m, 1, F>& range_space, - const XT::Grid::IntersectionFilter<SGV>& periodicity_exception = XT::Grid::ApplyOn::NoIntersections<SGV>()) + const XT::Grid::IntersectionFilter<AGV>& periodicity_exception = XT::Grid::ApplyOn::NoIntersections<AGV>()) { - return AdvectionFvOperator<MatrixType, SGV, m, RGV>( + return AdvectionFvOperator<MatrixType, AGV, m, RGV, SGV>( assembly_grid_view, numerical_flux, source_space, range_space, periodicity_exception); } diff --git a/dune/gdt/operators/advection-with-reconstruction.hh b/dune/gdt/operators/advection-with-reconstruction.hh new file mode 100644 index 0000000000000000000000000000000000000000..0fb6eb227585d62b33342be28323996de27914a1 --- /dev/null +++ b/dune/gdt/operators/advection-with-reconstruction.hh @@ -0,0 +1,142 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2017 - 2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_OPERATORS_ADVECTION_WITH_RECONSTRUCTION_HH +#define DUNE_GDT_OPERATORS_ADVECTION_WITH_RECONSTRUCTION_HH + +#include <dune/gdt/operators/interfaces.hh> + +#include "reconstruction/linear.hh" + +namespace Dune { +namespace GDT { + + +template <class AdvectionOperatorImp, class ReconstructionOperatorImp> +class AdvectionWithReconstructionOperator + : public OperatorInterface<typename AdvectionOperatorImp::MatrixType, + typename AdvectionOperatorImp::SourceSpaceType::GridViewType, + AdvectionOperatorImp::s_r> +{ + using BaseType = OperatorInterface<typename AdvectionOperatorImp::MatrixType, + typename AdvectionOperatorImp::SourceSpaceType::GridViewType, + AdvectionOperatorImp::s_r>; + +public: + using typename BaseType::RangeSpaceType; + using typename BaseType::SourceSpaceType; + using AdvectionOperatorType = AdvectionOperatorImp; + using ReconstructionOperatorType = ReconstructionOperatorImp; + using GridViewType = typename AdvectionOperatorType::SourceSpaceType::GridViewType; + static const size_t r = AdvectionOperatorType::s_r; + using VectorType = typename AdvectionOperatorType::VectorType; + using ReconstructionType = DiscreteFunction<VectorType, GridViewType, r>; + + AdvectionWithReconstructionOperator(const AdvectionOperatorType& advection_operator, + const ReconstructionOperatorType& reconstruction_operator) + : advection_operator_(advection_operator) + , reconstruction_operator_(reconstruction_operator) + , reconstruction_(reconstruction_operator.range_space().mapper().size()) + {} + + bool linear() const override final + { + return false; + } + + const SourceSpaceType& source_space() const override final + { + return reconstruction_operator_.source_space(); + } + + const RangeSpaceType& range_space() const override final + { + return advection_operator_.range_space(); + } + + void apply(const VectorType& source, VectorType& range, const XT::Common::Parameter& param) const override final + { + // do reconstruction + reconstruction_operator_.apply(source, reconstruction_, param); + + // apply advection operator + std::fill(range.begin(), range.end(), 0.); + advection_operator_.apply(reconstruction_, range, param); + } + + const AdvectionOperatorType& advection_operator_; + const ReconstructionOperatorType& reconstruction_operator_; + mutable VectorType reconstruction_; +}; // class AdvectionWithReconstructionOperator<...> + + +template <class AdvectionOperatorImp, class ReconstructionOperatorImp> +class AdvectionWithPointwiseReconstructionOperator + : public OperatorInterface<typename AdvectionOperatorImp::MatrixType, + typename AdvectionOperatorImp::SourceSpaceType::GridViewType, + AdvectionOperatorImp::s_r> +{ + using BaseType = OperatorInterface<typename AdvectionOperatorImp::MatrixType, + typename AdvectionOperatorImp::SourceSpaceType::GridViewType, + AdvectionOperatorImp::s_r>; + +public: + using typename BaseType::RangeSpaceType; + using typename BaseType::SourceSpaceType; + using AdvectionOperatorType = AdvectionOperatorImp; + using ReconstructionOperatorType = ReconstructionOperatorImp; + using GV = typename AdvectionOperatorType::SourceSpaceType::GridViewType; + static const size_t r = AdvectionOperatorType::s_r; + using VectorType = typename AdvectionOperatorType::VectorType; + + AdvectionWithPointwiseReconstructionOperator(const AdvectionOperatorType& advection_operator, + const ReconstructionOperatorType& reconstruction_operator) + : advection_operator_(advection_operator) + , reconstruction_operator_(reconstruction_operator) + {} + + bool linear() const override final + { + return false; + } + + const SourceSpaceType& source_space() const override final + { + return advection_operator_.source_space(); + } + + const RangeSpaceType& range_space() const override final + { + return advection_operator_.range_space(); + } + + void apply(const VectorType& source, VectorType& range, const XT::Common::Parameter& param) const override final + { + // do reconstruction + typename ReconstructionOperatorType::ReconstructedValuesType reconstructed_values( + source_space().grid_view().indexSet().size(0)); + typename ReconstructionOperatorType::ReconstructedFunctionType reconstructed_function(source_space().grid_view(), + reconstructed_values); + reconstruction_operator_.apply(source, reconstructed_function, param); + + // apply advection operator + std::fill(range.begin(), range.end(), 0.); + advection_operator_.apply(reconstructed_function, range, param); + } + + const AdvectionOperatorType& advection_operator_; + const ReconstructionOperatorType& reconstruction_operator_; +}; // class AdvectionWithReconstructionOperator<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_OPERATORS_ADVECTION_WITH_RECONSTRUCTION_HH diff --git a/dune/gdt/operators/constant.hh b/dune/gdt/operators/constant.hh index 80c58228f217eba4c3016b7cfadb23c960cf59f7..c32b52462ce4c246a2b17b1bfbc44b634d6d97e4 100644 --- a/dune/gdt/operators/constant.hh +++ b/dune/gdt/operators/constant.hh @@ -31,7 +31,7 @@ namespace GDT { template <class M, class SGV, size_t s_r = 1, size_t s_rC = 1, size_t r_r = s_r, size_t r_rC = s_rC, class RGV = SGV> class ConstantOperator : public OperatorInterface<M, SGV, s_r, s_rC, r_r, r_rC, RGV> { - using ThisType = ConstantOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; + using ThisType = ConstantOperator; using BaseType = OperatorInterface<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; public: diff --git a/dune/gdt/operators/identity.hh b/dune/gdt/operators/identity.hh index ce0c29e00775e5587ab50e77e513586e90eb0d80..34c98dd03fe04f1f49d306ce7ea76da75814eb13 100644 --- a/dune/gdt/operators/identity.hh +++ b/dune/gdt/operators/identity.hh @@ -31,7 +31,7 @@ namespace GDT { template <class M, class GV, size_t r = 1, size_t rC = 1> class IdentityOperator : public OperatorInterface<M, GV, r, rC> { - using ThisType = IdentityOperator<M, GV, r, rC>; + using ThisType = IdentityOperator; using BaseType = OperatorInterface<M, GV, r, rC>; public: diff --git a/dune/gdt/operators/interfaces.hh b/dune/gdt/operators/interfaces.hh index 4003ba4ec939e86ce1065259fb7ecb7f3d3e994f..e0eac6f609f250ceab627c88ffedb1f18581ff0d 100644 --- a/dune/gdt/operators/interfaces.hh +++ b/dune/gdt/operators/interfaces.hh @@ -133,6 +133,7 @@ public: using F = FieldType; using SGV = SourceGridView; + using E = XT::Grid::extract_entity_t<SGV>; static const constexpr size_t s_r = source_dim; static const constexpr size_t s_rC = source_dim_cols; @@ -141,6 +142,7 @@ public: static const constexpr size_t r_rC = range_dim_cols; using SourceSpaceType = SpaceInterface<SGV, s_r, s_rC, F>; + using SourceFunctionInterfaceType = XT::Functions::GridFunctionInterface<E, s_r, s_rC, F>; using SourceFunctionType = DiscreteFunction<V, SGV, s_r, s_rC, F>; using ConstSourceFunctionType = ConstDiscreteFunction<V, SGV, s_r, s_rC, F>; @@ -148,7 +150,7 @@ public: using RangeFunctionType = DiscreteFunction<V, RGV, r_r, r_rC, F>; using ConstRangeFunctionType = ConstDiscreteFunction<V, RGV, r_r, r_rC, F>; - using ThisType = OperatorInterface<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; + using ThisType = OperatorInterface; using MatrixOperatorType = MatrixOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; using ConstLincombOperatorType = ConstLincombOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; using LincombOperatorType = LincombOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; @@ -531,7 +533,7 @@ invert_options(some_type).get<std::string>("type") == some_type virtual VectorType apply(const VectorType& source, const XT::Common::Parameter& param = {}) const { - VectorType range(this->range_space().mapper().size(), 0); + VectorType range(this->range_space().mapper().size(), 0.); this->apply(source, range, param); return range; } diff --git a/dune/gdt/operators/ipdg-flux-reconstruction.hh b/dune/gdt/operators/ipdg-flux-reconstruction.hh index 92ac8825b392832bfae1a9bfadf98c4f9d398789..187ae6b157ffa1227256b853adbd0a47a189b18c 100644 --- a/dune/gdt/operators/ipdg-flux-reconstruction.hh +++ b/dune/gdt/operators/ipdg-flux-reconstruction.hh @@ -41,7 +41,7 @@ class IpdgFluxReconstructionOperator : public OperatorInterface<M, SGV, 1, 1, RG { static_assert(XT::Grid::is_view<AssemblyGridView>::value, ""); using BaseType = OperatorInterface<M, SGV, 1, 1, RGV::dimension, 1, RGV>; - using ThisType = IpdgFluxReconstructionOperator<M, AssemblyGridView, ipdg, SGV, RGV>; + using ThisType = IpdgFluxReconstructionOperator; public: using typename BaseType::F; diff --git a/dune/gdt/operators/lincomb.hh b/dune/gdt/operators/lincomb.hh index 772263af30ff0b878e1459f6a3d41e6c0dae7cce..6447a00cef2bb872afaedb6bb1942be1095ba7a7 100644 --- a/dune/gdt/operators/lincomb.hh +++ b/dune/gdt/operators/lincomb.hh @@ -28,7 +28,7 @@ namespace GDT { template <class M, class SGV, size_t s_r = 1, size_t s_rC = 1, size_t r_r = s_r, size_t r_rC = s_rC, class RGV = SGV> class ConstLincombOperator : public OperatorInterface<M, SGV, s_r, s_rC, r_r, r_rC, RGV> { - using ThisType = ConstLincombOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; + using ThisType = ConstLincombOperator; using BaseType = OperatorInterface<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; public: @@ -338,7 +338,7 @@ make_const_lincomb_operator(const SpaceInterface<GV, r, rC, F>& space) template <class M, class SGV, size_t s_r = 1, size_t s_rC = 1, size_t r_r = s_r, size_t r_rC = s_rC, class RGV = SGV> class LincombOperator : public ConstLincombOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV> { - using ThisType = LincombOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; + using ThisType = LincombOperator; using BaseType = ConstLincombOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; public: diff --git a/dune/gdt/operators/localizable-operator.hh b/dune/gdt/operators/localizable-operator.hh index bbc43dc2076cbaff181213db2e88d7d6c1d6f15b..4e915cda68de28400d3847111ec9ecc041d6cb35 100644 --- a/dune/gdt/operators/localizable-operator.hh +++ b/dune/gdt/operators/localizable-operator.hh @@ -11,6 +11,9 @@ #ifndef DUNE_GDT_OPERATORS_LOCALIZABLE_OPERATOR_HH #define DUNE_GDT_OPERATORS_LOCALIZABLE_OPERATOR_HH +#include <list> + +#include <dune/xt/common/deprecated.hh> #include <dune/xt/la/type_traits.hh> #include <dune/xt/grid/type_traits.hh> #include <dune/xt/grid/walker.hh> @@ -20,13 +23,17 @@ #include <dune/gdt/local/operators/generic.hh> #include <dune/gdt/local/operators/interfaces.hh> +#include "interfaces.hh" + namespace Dune { namespace GDT { /** - * \todo Rename this one to LocalizableDiscreteOperatorBase, create LocalizableOperatorBase which accepts a GridFunction - * as source, derive LocalizableDiscreteOperatorBase from LocalizableOperatorBase. + * \todo Create LocalizableOperatorApplicator which accepts a GridFunction as source, derive + * LocalizableDiscreteOperatorApplicator from LocalizableOperatorApplicator. + * + * \note Most likely, you want to use LocalizableOperator. */ template <class AssemblyGridView, class SourceVector, @@ -39,7 +46,7 @@ template <class AssemblyGridView, class RangeField = SourceField, class RangeGridView = SourceGridView, class RangeVector = SourceVector> -class LocalizableOperatorBase : public XT::Grid::Walker<AssemblyGridView> +class LocalizableDiscreteOperatorApplicator : public XT::Grid::Walker<AssemblyGridView> { static_assert(XT::Grid::is_view<AssemblyGridView>::value, ""); static_assert(XT::LA::is_vector<SourceVector>::value, ""); @@ -47,17 +54,17 @@ class LocalizableOperatorBase : public XT::Grid::Walker<AssemblyGridView> static_assert(XT::Grid::is_view<RangeGridView>::value, ""); static_assert(XT::LA::is_vector<RangeVector>::value, ""); - using ThisType = LocalizableOperatorBase<AssemblyGridView, - SourceVector, - source_range_dim, - source_range_dim_cols, - SourceField, - SourceGridView, - range_range_dim, - range_range_dim_cols, - RangeField, - RangeGridView, - RangeVector>; + using ThisType = LocalizableDiscreteOperatorApplicator<AssemblyGridView, + SourceVector, + source_range_dim, + source_range_dim_cols, + SourceField, + SourceGridView, + range_range_dim, + range_range_dim_cols, + RangeField, + RangeGridView, + RangeVector>; using BaseType = XT::Grid::Walker<AssemblyGridView>; public: @@ -66,10 +73,12 @@ public: using SV = SourceVector; using SGV = SourceGridView; + using E = XT::Grid::extract_entity_t<SGV>; static const constexpr size_t s_r = source_range_dim; static const constexpr size_t s_rC = source_range_dim_cols; using SF = SourceField; - using SourceType = ConstDiscreteFunction<SV, SGV, s_r, s_rC, SF>; + using DiscreteSourceType = ConstDiscreteFunction<SV, SGV, s_r, s_rC, SF>; + using SourceType = XT::Functions::GridFunctionInterface<E, s_r, s_rC, SF>; using RV = RangeVector; using RGV = RangeGridView; @@ -90,7 +99,7 @@ public: GenericLocalIntersectionOperator<I, SV, SGV, s_r, s_rC, SF, r_r, r_rC, RF, RGV, RV>; using GenericLocalIntersectionFunctionType = typename GenericLocalIntersectionOperatorType::GenericFunctionType; - LocalizableOperatorBase(AssemblyGridViewType assembly_grid_view, const SourceType& src, RangeType& rng) + LocalizableDiscreteOperatorApplicator(AssemblyGridViewType assembly_grid_view, const SourceType& src, RangeType& rng) : BaseType(assembly_grid_view) , source_(src) , range_(rng) @@ -122,7 +131,7 @@ public: const XT::Common::Parameter& param = {}, const ElementFilterType& filter = ApplyOnAllElements()) { - this->append(make_local_element_operator_applicator(local_operator, source_, range_, param).release(), filter); + this->append(make_local_element_operator_applicator(local_operator, range_, param).release(), filter); return *this; } @@ -130,7 +139,7 @@ public: const XT::Common::Parameter& param = {}, const ElementFilterType& filter = ApplyOnAllElements()) { - this->append(GenericLocalElementOperatorType(generic_function, param.type()), param, filter); + this->append(GenericLocalElementOperatorType(source(), generic_function, param.type()), param, filter); return *this; } @@ -139,7 +148,7 @@ public: const XT::Common::Parameter& param = {}, const IntersectionFilterType& filter = ApplyOnAllIntersections()) { - this->append(make_local_intersection_operator_applicator(local_operator, source_, range_, param).release(), filter); + this->append(make_local_intersection_operator_applicator(local_operator, range_, param).release(), filter); return *this; } @@ -147,7 +156,7 @@ public: const XT::Common::Parameter& param = {}, const IntersectionFilterType& filter = ApplyOnAllIntersections()) { - this->append(GenericLocalIntersectionFunctionType(generic_function, param.type()), param, filter); + this->append(GenericLocalIntersectionOperatorType(source(), generic_function, param.type()), param, filter); return *this; } @@ -164,8 +173,75 @@ protected: const SourceType& source_; RangeType& range_; bool assembled_; -}; // class LocalizableOperatorBase +}; // class LocalizableDiscreteOperatorApplicator + + +template <class AssemblyGridView, + class SourceVector, + size_t source_range_dim = 1, + size_t source_range_dim_cols = 1, + class SourceField = double, + class SourceGridView = AssemblyGridView, + size_t range_range_dim = source_range_dim, + size_t range_range_dim_cols = source_range_dim_cols, + class RangeField = SourceField, + class RangeGridView = SourceGridView, + class RangeVector = SourceVector> +using LocalizableOperatorBase DXT_DEPRECATED_MSG("Use LocalizableDiscreteOperatorApplicator instead (12.09.2019)!") = + LocalizableDiscreteOperatorApplicator<AssemblyGridView, + SourceVector, + source_range_dim, + source_range_dim_cols, + SourceField, + SourceGridView, + range_range_dim, + range_range_dim_cols, + RangeField, + RangeGridView, + RangeVector>; + + +template <class AGV, + class SV, + size_t s_r, + size_t s_rC, + class SF, + class SGV, + size_t r_r, + size_t r_rC, + class RF, + class RGV, + class RV> +std::enable_if_t<XT::Grid::is_layer<AGV>::value, + LocalizableDiscreteOperatorApplicator<AGV, SV, s_r, s_rC, SF, SGV, r_r, r_rC, RF, RGV, RV>> +make_localizable_operator_applicator(AGV assembly_grid_view, + const ConstDiscreteFunction<SV, SGV, s_r, s_rC, SF>& source, + DiscreteFunction<RV, RGV, r_r, r_rC, RF>& range) +{ + return LocalizableDiscreteOperatorApplicator<AGV, SV, s_r, s_rC, SF, SGV, r_r, r_rC, RF, RGV, RV>( + assembly_grid_view, source, range); +} +template <class AGV, + size_t s_r, + size_t s_rC, + class SF, + size_t r_r, + size_t r_rC, + class RF, + class RGV, + class RV, + class SV = RV> +std::enable_if_t<XT::Grid::is_layer<AGV>::value, + LocalizableDiscreteOperatorApplicator<AGV, SV, s_r, s_rC, SF, AGV, r_r, r_rC, RF, RGV, RV>> +make_localizable_operator_applicator( + AGV assembly_grid_view, + const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<AGV>, s_r, s_rC, SF>& source, + DiscreteFunction<RV, RGV, r_r, r_rC, RF>& range) +{ + return LocalizableDiscreteOperatorApplicator<AGV, SV, s_r, s_rC, SF, AGV, r_r, r_rC, RF, RGV, RV>( + assembly_grid_view, source, range); +} template <class AGV, class SV, @@ -180,15 +256,191 @@ template <class AGV, class RV> std::enable_if_t<XT::Grid::is_layer<AGV>::value, LocalizableOperatorBase<AGV, SV, s_r, s_rC, SF, SGV, r_r, r_rC, RF, RGV, RV>> -make_localizable_operator(AGV assembly_grid_view, - const ConstDiscreteFunction<SV, SGV, s_r, s_rC, SF>& source, - DiscreteFunction<RV, RGV, r_r, r_rC, RF>& range) +make_localizable_operator( + AGV assembly_grid_view, + const XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<SGV>, s_r, s_rC, SF>& source, + DiscreteFunction<RV, RGV, r_r, r_rC, RF>& range) { return LocalizableOperatorBase<AGV, SV, s_r, s_rC, SF, SGV, r_r, r_rC, RF, RGV, RV>( assembly_grid_view, source, range); } +/** + * \note See OperatorInterface for a description of the template arguments. + * + * \sa OperatorInterface + */ +template <class M, + class AssemblyGridView, + size_t s = 1, + size_t sC = 1, + size_t r = s, + size_t rC = sC, + class RGV = AssemblyGridView, + class SGV = AssemblyGridView> +class LocalizableOperator : public OperatorInterface<M, SGV, s, sC, r, rC, RGV> +{ + static_assert(XT::Grid::is_view<AssemblyGridView>::value, ""); + using ThisType = LocalizableOperator; + using BaseType = OperatorInterface<M, SGV, s, sC, r, rC, RGV>; + +public: + using AGV = AssemblyGridView; + using typename BaseType::F; + using typename BaseType::V; + + using I = XT::Grid::extract_intersection_t<SGV>; + + using typename BaseType::MatrixOperatorType; + using typename BaseType::RangeSpaceType; + using typename BaseType::SourceFunctionInterfaceType; + using typename BaseType::SourceSpaceType; + using typename BaseType::VectorType; + + using LocalElementOperatorType = LocalElementOperatorInterface<V, SGV, s, sC, F, r, rC, F, RGV, V>; + using LocalIntersectionOperatorType = LocalIntersectionOperatorInterface<I, V, SGV, s, sC, F, r, rC, F, RGV, V>; + + LocalizableOperator(const AGV& assembly_grid_view, + const SourceSpaceType& source_space, + const RangeSpaceType& range_space) + : BaseType() + , assembly_grid_view_(assembly_grid_view) + , source_space_(source_space) + , range_space_(range_space) + , linear_(true) + {} + + LocalizableOperator(ThisType&& source) = default; + + bool linear() const override final + { + return linear_; + } + + const SourceSpaceType& source_space() const override final + { + return source_space_; + } + + const RangeSpaceType& range_space() const override final + { + return range_space_; + } + + ThisType& append(const LocalElementOperatorType& local_operator, + const XT::Grid::ElementFilter<AGV>& filter = XT::Grid::ApplyOn::AllElements<AGV>()) + { + linear_ = linear_ && local_operator.linear(); + this->extend_parameter_type(local_operator.parameter_type()); + local_element_operators_.emplace_back(local_operator.copy(), filter.copy()); + return *this; + } + + ThisType& append(const LocalIntersectionOperatorType& local_operator, + const XT::Grid::IntersectionFilter<AGV>& filter = XT::Grid::ApplyOn::AllIntersections<AGV>()) + { + linear_ = linear_ && local_operator.linear(); + this->extend_parameter_type(local_operator.parameter_type()); + local_intersection_operators_.emplace_back(local_operator.copy(), filter.copy()); + return *this; + } + + using BaseType::apply; + + void apply(const SourceFunctionInterfaceType& source_function, + VectorType& range, + const XT::Common::Parameter& param = {}) const + { + DUNE_THROW_IF(!(this->parameter_type() <= param.type()), + Exceptions::operator_error, + "this->parameter_type() = " << this->parameter_type() << "\n param.type() = " << param.type()); + range.set_all(0); + auto range_function = make_discrete_function(this->range_space_, range); + // set up the actual operator + auto localizable_op = + make_localizable_operator_applicator(this->assembly_grid_view_, source_function, range_function); + // - element contributions + for (const auto& op_and_filter : local_element_operators_) { + const auto local_op = op_and_filter.first->with_source(source_function); + const auto& filter = *op_and_filter.second; + localizable_op.append(*local_op, param, filter); + } + // - intersection contributions + for (const auto& op_and_filter : local_intersection_operators_) { + const auto local_op = op_and_filter.first->with_source(source_function); + const auto& filter = *op_and_filter.second; + localizable_op.append(*local_op, param, filter); + } + // and apply it in a grid walk + localizable_op.assemble(/*use_tbb=*/true); + DUNE_THROW_IF(!range.valid(), Exceptions::operator_error, "range contains inf or nan!"); + } // ... apply(...) + + void apply(const VectorType& source, VectorType& range, const XT::Common::Parameter& param = {}) const override + { + DUNE_THROW_IF(!source.valid(), Exceptions::operator_error, "source contains inf or nan!"); + const auto source_function = make_discrete_function(this->source_space_, source); + apply(source_function, range, param); + } // ... apply(...) + + std::vector<std::string> jacobian_options() const override final + { + return {"finite-differences"}; + } + + XT::Common::Configuration jacobian_options(const std::string& type) const override final + { + DUNE_THROW_IF(type != this->jacobian_options().at(0), Exceptions::operator_error, "type = " << type); + return {{"type", type}, {"eps", "1e-7"}}; + } + + using BaseType::jacobian; + + void jacobian(const VectorType& source, + MatrixOperatorType& jacobian_op, + const XT::Common::Configuration& opts, + const XT::Common::Parameter& param = {}) const override final + { + // some checks + DUNE_THROW_IF(!source.valid(), Exceptions::operator_error, "source contains inf or nan!"); + DUNE_THROW_IF(!(this->parameter_type() <= param.type()), + Exceptions::operator_error, + "this->parameter_type() = " << this->parameter_type() << "\n param.type() = " << param.type()); + DUNE_THROW_IF(!opts.has_key("type"), Exceptions::operator_error, opts); + DUNE_THROW_IF(opts.get<std::string>("type") != jacobian_options().at(0), Exceptions::operator_error, opts); + const auto default_opts = jacobian_options(jacobian_options().at(0)); + const auto eps = opts.get("eps", default_opts.template get<double>("eps")); + const auto parameter = param + XT::Common::Parameter({"finite-difference-jacobians.eps", eps}); + // append the same local ops with the same filters as in apply() above + // - element contributions + const auto source_function = make_discrete_function(this->source_space_, source); + for (const auto& op_and_filter : local_element_operators_) { + const auto local_op = op_and_filter.first->with_source(source_function); + const auto& filter = *op_and_filter.second; + jacobian_op.append(*local_op, source, parameter, filter); + } + // - intersection contributions + for (const auto& op_and_filter : local_intersection_operators_) { + const auto local_op = op_and_filter.first->with_source(source_function); + const auto& filter = *op_and_filter.second; + jacobian_op.append(*local_op, source, parameter, filter); + } + } // ... jacobian(...) + +protected: + const AGV assembly_grid_view_; + const SourceSpaceType& source_space_; + const RangeSpaceType& range_space_; + bool linear_; + std::list<std::pair<std::unique_ptr<LocalElementOperatorType>, std::unique_ptr<XT::Grid::ElementFilter<AGV>>>> + local_element_operators_; + std::list< + std::pair<std::unique_ptr<LocalIntersectionOperatorType>, std::unique_ptr<XT::Grid::IntersectionFilter<AGV>>>> + local_intersection_operators_; +}; // class LocalizableOperator + + } // namespace GDT } // namespace Dune diff --git a/dune/gdt/operators/matrix-based.hh b/dune/gdt/operators/matrix-based.hh index 168360e0763d7a3d4b5bd8f7937f548d10788ab4..eaf035f265a5107b910b0d73509f5cc8993eb42c 100644 --- a/dune/gdt/operators/matrix-based.hh +++ b/dune/gdt/operators/matrix-based.hh @@ -46,7 +46,7 @@ namespace GDT { template <class M, class SGV, size_t s_r = 1, size_t s_rC = 1, size_t r_r = s_r, size_t r_rC = s_rC, class RGV = SGV> class ConstMatrixOperator : public OperatorInterface<M, SGV, s_r, s_rC, r_r, r_rC, RGV> { - using ThisType = ConstMatrixOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; + using ThisType = ConstMatrixOperator; using BaseType = OperatorInterface<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; public: @@ -221,7 +221,7 @@ class MatrixOperator , public ConstMatrixOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV> , public XT::Grid::Walker<SGV> { - using ThisType = MatrixOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; + using ThisType = MatrixOperator; using MatrixStorage = XT::Common::StorageProvider<M>; using OperatorBaseType = ConstMatrixOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>; using WalkerBaseType = XT::Grid::Walker<SGV>; @@ -293,6 +293,12 @@ public: FieldType scaling; + void clear() + { + WalkerBaseType::clear(); + assembled_ = false; + } + using WalkerBaseType::append; ThisType& append(const LocalElementBilinearFormInterface<E, r_r, r_rC, F, F, s_r, s_rC, F>& local_bilinear_form, @@ -379,7 +385,7 @@ public: const XT::Common::Configuration& opts, const XT::Common::Parameter& param = {}) const override { - DUNE_THROW_IF(!assembled_, Exceptions::operator_error, "This operator has to be assembled to povide a jacobian!"); + DUNE_THROW_IF(!assembled_, Exceptions::operator_error, "This operator has to be assembled to provide a jacobian!"); OperatorBaseType::jacobian(source, jacobian_op, opts, param); } diff --git a/dune/gdt/operators/oswald-interpolation.hh b/dune/gdt/operators/oswald-interpolation.hh index a250ef03548429c7c2ba023ab7e839ddb185f3fd..b719170145744576ef57798d635cd5cf17b43d9b 100644 --- a/dune/gdt/operators/oswald-interpolation.hh +++ b/dune/gdt/operators/oswald-interpolation.hh @@ -45,7 +45,7 @@ class OswaldInterpolationOperator : public OperatorInterface<M, SGV, dim, dim_co static_assert(dim == 1, "I did not think about this yet, feel free to implement!"); static_assert(dim_cols == 1, "I did not think about this yet, feel free to implement!"); using BaseType = OperatorInterface<M, SGV, dim, dim_cols, dim, dim_cols, RGV>; - using ThisType = OswaldInterpolationOperator<M, AssemblyGridView, dim, dim_cols, SGV, RGV>; + using ThisType = OswaldInterpolationOperator; public: using typename BaseType::RangeSpaceType; diff --git a/dune/gdt/operators/reconstruction/internal.hh b/dune/gdt/operators/reconstruction/internal.hh new file mode 100644 index 0000000000000000000000000000000000000000..4b7309a79ddc13c2f1a49a21ba34abdbae06d1d1 --- /dev/null +++ b/dune/gdt/operators/reconstruction/internal.hh @@ -0,0 +1,521 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2017 - 2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_OPERATORS_RECONSTRUCTION_INTERNAL_HH +#define DUNE_GDT_OPERATORS_RECONSTRUCTION_INTERNAL_HH + +#include <dune/xt/common/debug.hh> +#include <dune/xt/common/fvector.hh> +#include <dune/xt/common/lapacke.hh> +#include <dune/xt/common/matrix.hh> +#include <dune/xt/common/parameter.hh> + +#include <dune/xt/la/algorithms/qr.hh> +#include <dune/xt/la/eigen-solver.hh> + +#include <dune/gdt/operators/interfaces.hh> + +namespace Dune { +namespace GDT { +namespace internal { + + +template <class MatImp> +XT::Common::Configuration hyperbolic_default_eigensolver_options() +{ + using EigenSolverOptionsType = typename XT::LA::EigenSolverOptions<MatImp>; + using MatrixInverterOptionsType = typename XT::LA::MatrixInverterOptions<MatImp>; + XT::Common::Configuration eigensolver_options = EigenSolverOptionsType::options(EigenSolverOptionsType::types()[0]); + // XT::Common::Configuration eigensolver_options = EigenSolverOptionsType::options("shifted_qr"); + eigensolver_options["assert_eigendecomposition"] = "1e-6"; + eigensolver_options["assert_real_eigendecomposition"] = "1e-6"; + eigensolver_options["disable_checks"] = +#ifdef NDEBUG + "true"; +#else + "false"; +#endif + XT::Common::Configuration matrix_inverter_options = MatrixInverterOptionsType::options(); + matrix_inverter_options["post_check_is_left_inverse"] = "1e-6"; + matrix_inverter_options["post_check_is_right_inverse"] = "1e-6"; + eigensolver_options.add(matrix_inverter_options, "matrix-inverter"); + return eigensolver_options; +} // ... hyperbolic_default_eigensolver_options() + + +// Wrapper for thread-safe and consistent handling of the different jacobians (Usual matrices vs. block matrices in the +// partial moment case) +template <class AnalyticalFluxType, class MatrixImp, class VectorImp> +class EigenvectorWrapperBase +{ +public: + using MatrixType = MatrixImp; + using VectorType = VectorImp; + static constexpr size_t dimDomain = AnalyticalFluxType::r; + static constexpr size_t dimRange = AnalyticalFluxType::rC; + using RangeFieldType = typename AnalyticalFluxType::R; + using DomainType = FieldVector<RangeFieldType, dimDomain>; + using E = typename AnalyticalFluxType::E; + using LocalFluxType = typename AnalyticalFluxType::LocalFunctionType; + using FluxDomainType = XT::Common::FieldVector<typename AnalyticalFluxType::D, dimRange>; + + EigenvectorWrapperBase(const AnalyticalFluxType& analytical_flux, const bool flux_is_affine) + : analytical_flux_(analytical_flux) + , local_flux_(analytical_flux_.local_function()) + , flux_is_affine_(flux_is_affine) + , computed_(false) + {} + + virtual ~EigenvectorWrapperBase() {} + + virtual void compute_eigenvectors(const E& entity, + const DomainType& x_local, + const VectorType& u, + const XT::Common::Parameter& param) + { + if (!computed_ || !flux_is_affine_) { + compute_eigenvectors_impl(entity, x_local, u, param); + computed_ = true; + } + } + + virtual void compute_eigenvectors_impl(const E& entity, + const DomainType& x_local, + const VectorType& u, + const XT::Common::Parameter& param) = 0; + + virtual void apply_eigenvectors(const size_t dd, const VectorType& u, VectorType& ret) const = 0; + + virtual void apply_inverse_eigenvectors(const size_t dd, const VectorType& u, VectorType& ret) const = 0; + + virtual const MatrixType& eigenvectors(const size_t dd) const = 0; + + bool affine() const + { + return flux_is_affine_; + } + +protected: + const AnalyticalFluxType& analytical_flux_; + const std::unique_ptr<LocalFluxType> local_flux_; + const bool flux_is_affine_; + bool computed_; +}; // class EigenvectorWrapperBase<...> + +template <class AnalyticalFluxType, class MatrixImp, class VectorImp> +constexpr size_t EigenvectorWrapperBase<AnalyticalFluxType, MatrixImp, VectorImp>::dimDomain; + +template <class AnalyticalFluxType, class MatrixImp, class VectorImp> +constexpr size_t EigenvectorWrapperBase<AnalyticalFluxType, MatrixImp, VectorImp>::dimRange; + +// This class does not perform any computations, use this class if you want to reconstruct in ordinary coordinates +// instead of characteristic coordinates +template <class AnalyticalFluxType, class VectorImp> +class DummyEigenVectorWrapper : public EigenvectorWrapperBase<AnalyticalFluxType, int, VectorImp> +{ + using BaseType = EigenvectorWrapperBase<AnalyticalFluxType, int, VectorImp>; + +public: + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::MatrixType; + using typename BaseType::VectorType; + + DummyEigenVectorWrapper(const AnalyticalFluxType& analytical_flux, const bool flux_is_affine) + : BaseType(analytical_flux, flux_is_affine) + {} + + void apply_eigenvectors(const size_t /*dd*/, const VectorType& u, VectorType& ret) const override final + { + ret = u; + } + virtual void + apply_inverse_eigenvectors(const size_t /*dd*/, const VectorType& u, VectorType& ret) const override final + { + ret = u; + } + + virtual void compute_eigenvectors(const E& /*entity*/, + const DomainType& /*x_local*/, + const VectorType& /*u*/, + const XT::Common::Parameter& /*param*/) const override final + {} + + virtual void compute_eigenvectors_impl(const E& /*entity*/, + const DomainType& /*x_local*/, + const VectorType& /*u*/, + const XT::Common::Parameter& /*param*/) const override final + {} + + const MatrixType& eigenvectors(const size_t /*dd*/) const override final + { + DUNE_THROW(Dune::NotImplemented, "This class does not provide eigenvectors!"); + return zero_; + } + +private: + static const MatrixType zero_ = 0.; +}; + +template <class AnalyticalFluxType, + class MatrixType = XT::LA::CommonDenseMatrix<typename AnalyticalFluxType::R>, + class VectorType = FieldVector<typename AnalyticalFluxType::RangeFieldType, AnalyticalFluxType::rC>> +class EigenvectorWrapper : public EigenvectorWrapperBase<AnalyticalFluxType, MatrixType, VectorType> +{ + using BaseType = EigenvectorWrapperBase<AnalyticalFluxType, MatrixType, VectorType>; + +protected: + using V = XT::Common::VectorAbstraction<VectorType>; + using M = XT::Common::MatrixAbstraction<MatrixType>; + using EigenSolverType = typename XT::LA::EigenSolver<MatrixType>; + +public: + using BaseType::dimDomain; + using BaseType::dimRange; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::RangeFieldType; + using JacobianType = DynamicVector<MatrixType>; + + EigenvectorWrapper(const AnalyticalFluxType& analytical_flux, const bool flux_is_affine) + : BaseType(analytical_flux, flux_is_affine) + , work_(1) + , scale_(dimRange) + , rconde_(dimRange) + , rcondv_(dimRange) + , iwork_(2 * dimRange - 2) + , jacobian_(std::make_unique<JacobianType>(dimDomain, MatrixType(dimRange, dimRange, 0., 0))) + , eigenvectors_(std::make_unique<JacobianType>(dimDomain, MatrixType(dimRange, dimRange, 0., 0))) + , eigenvectors_rcond_(1.) + , eigenvalues_(std::vector<RangeFieldType>(dimRange)) + , QR_(std::make_unique<JacobianType>(dimDomain, MatrixType(dimRange, dimRange, 0., 0))) + , tau_(V::create(dimRange)) + { +#if HAVE_MKL || HAVE_LAPACKE + int ilo, ihi; + double norm; + if (M::storage_layout == XT::Common::StorageLayout::dense_row_major) { + // get optimal working size in work[0] (requested by lwork = -1) + int info = XT::Common::Lapacke::dgeevx_work(XT::Common::Lapacke::row_major(), + /*both diagonally scale and permute*/ 'B', + /*do_not_compute_left_eigenvectors:*/ 'N', + /*compute_right_eigenvectors:*/ 'V', + /*do not compute condition numbers*/ 'N', + static_cast<int>(dimRange), + M::data((*jacobian_)[0]), + static_cast<int>(dimRange), + &(eigenvalues_[0][0]), + &(dummy_complex_eigenvalues_[0]), + nullptr, + static_cast<int>(dimRange), + M::data((*eigenvectors_)[0]), + static_cast<int>(dimRange), + &ilo, + &ihi, + scale_.data(), + &norm, + rconde_.data(), + rcondv_.data(), + work_.data(), + -1, + iwork_.data()); + if (info != 0) + DUNE_THROW(Dune::XT::LA::Exceptions::eigen_solver_failed, "The lapack backend reported '" << info << "'!"); + work_.resize(static_cast<size_t>(work_[0] + 0.5)); + } +#endif + } + + virtual void compute_eigenvectors_impl(const E& entity, + const DomainType& x_local, + const VectorType& u, + const XT::Common::Parameter& param) override final + { + local_flux_->bind(entity); + try { + local_flux_->jacobian(x_local, u, *jacobian_, param); + for (size_t dd = 0; dd < dimDomain; ++dd) { + if (false) { + ; +#if HAVE_MKL || HAVE_LAPACKE + } else if (M::storage_layout == XT::Common::StorageLayout::dense_row_major) { + int ilo, ihi; + double norm; + int info = XT::Common::Lapacke::dgeevx_work(XT::Common::Lapacke::row_major(), + /*both diagonally scale and permute*/ 'B', + /*do not compute left eigenvectors*/ 'N', + /*compute right eigenvectors*/ 'V', + /*do not compute condition numbers*/ 'N', + static_cast<int>(dimRange), + M::data((*jacobian_)[dd]), + static_cast<int>(dimRange), + eigenvalues_[dd].data(), + &(dummy_complex_eigenvalues_[0]), + nullptr, + static_cast<int>(dimRange), + M::data((*eigenvectors_)[dd]), + static_cast<int>(dimRange), + &ilo, + &ihi, + scale_.data(), + &norm, + rconde_.data(), + rcondv_.data(), + work_.data(), + static_cast<int>(work_.size()), + iwork_.data()); + if (info != 0) + DUNE_THROW(Dune::MathError, "The lapack backend reported '" << info << "'!"); +#endif // HAVE_MKL || HAVE_LAPACKE + } else { + static auto eigensolver_options = hyperbolic_default_eigensolver_options<MatrixType>(); + const auto eigensolver = EigenSolverType((*jacobian_)[dd], &eigensolver_options); + (*eigenvectors_)[dd] = eigensolver.real_eigenvectors(); + eigenvalues_[dd] = eigensolver.real_eigenvalues(); + } + (*QR_)[dd] = (*eigenvectors_)[dd]; + XT::LA::qr((*QR_)[dd], tau_[dd], permutations_[dd]); +#if HAVE_MKL || HAVE_LAPACKE + int info = XT::Common::Lapacke::dtrcon(XT::Common::Lapacke::row_major(), + '1', + 'U', + 'N', + static_cast<int>(dimRange), + M::data((*QR_)[dd]), + static_cast<int>(dimRange), + &eigenvectors_rcond_); + if (info || eigenvectors_rcond_ < 1e-5) + DUNE_THROW(Dune::MathError, "Eigenvector condition too high!"); +#endif + } // dd + } catch (const Dune::MathError&) { + for (size_t dd = 0; dd < dimDomain; ++dd) { + // use scalar limiters, i.e. eigenvectors matrix is eye-matrix. + XT::LA::eye_matrix((*eigenvectors_)[dd]); + std::fill(eigenvalues_[dd].begin(), eigenvalues_[dd].end(), 1.); + (*QR_)[dd] = (*eigenvectors_)[dd]; + XT::LA::qr((*QR_)[dd], tau_[dd], permutations_[dd]); + } // dd + } + + // we do not need jacobian_ anymore if the flux is affine, so save memory + if (flux_is_affine_) + jacobian_ = nullptr; + } + + void apply_eigenvectors(const size_t dd, const VectorType& u, VectorType& ret) const override final + { + (*eigenvectors_)[dd].mv(u, ret); + } + + void apply_inverse_eigenvectors(const size_t dd, const VectorType& u, VectorType& ret) const override final + { + thread_local VectorType work = V::create(dimRange); + XT::LA::solve_qr_factorized((*QR_)[dd], tau_[dd], permutations_[dd], ret, u, &work); + } + + const MatrixType& eigenvectors(const size_t dd) const override final + { + return (*eigenvectors_)[dd]; + } + +protected: + using BaseType::computed_; + using BaseType::flux_is_affine_; + using BaseType::local_flux_; + std::vector<RangeFieldType> work_, scale_, rconde_, rcondv_; + std::vector<int> iwork_; + std::unique_ptr<JacobianType> jacobian_; + std::unique_ptr<JacobianType> eigenvectors_; + RangeFieldType eigenvectors_rcond_; + FieldVector<std::vector<RangeFieldType>, dimDomain> eigenvalues_; + FieldVector<RangeFieldType, dimRange> dummy_complex_eigenvalues_; + std::unique_ptr<JacobianType> QR_; + FieldVector<VectorType, dimDomain> tau_; + FieldVector<FieldVector<int, dimRange>, dimDomain> permutations_; +}; // class EigenvectorWrapper<...> + + +template <class AnalyticalFluxType, size_t block_size = (AnalyticalFluxType::r == 1) ? 2 : 4> +class BlockedEigenvectorWrapper + : public EigenvectorWrapperBase< + AnalyticalFluxType, + XT::Common::BlockedFieldMatrix<typename AnalyticalFluxType::R, AnalyticalFluxType::rC / block_size, block_size>, + XT::Common::BlockedFieldVector<typename AnalyticalFluxType::R, AnalyticalFluxType::rC / block_size, block_size>> +{ + using BaseType = EigenvectorWrapperBase< + AnalyticalFluxType, + XT::Common::BlockedFieldMatrix<typename AnalyticalFluxType::R, AnalyticalFluxType::rC / block_size, block_size>, + XT::Common::BlockedFieldVector<typename AnalyticalFluxType::R, AnalyticalFluxType::rC / block_size, block_size>>; + +public: + using BaseType::dimDomain; + using BaseType::dimRange; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::FluxDomainType; + using typename BaseType::MatrixType; + using typename BaseType::RangeFieldType; + using typename BaseType::VectorType; + using JacobianType = XT::Common::FieldVector<MatrixType, dimDomain>; + static constexpr size_t num_blocks = VectorType::num_blocks; + static_assert(dimRange % block_size == 0, "dimRange has to be a multiple of block_size"); + using BlockedIntVectorType = XT::Common::BlockedFieldVector<int, num_blocks, block_size>; + using LocalVectorType = typename VectorType::BlockType; + using LocalMatrixType = typename MatrixType::BlockType; + using EigenSolverType = typename XT::LA::EigenSolver<LocalMatrixType>; + using LocalM = typename XT::Common::MatrixAbstraction<LocalMatrixType>; + using LocalV = typename XT::Common::VectorAbstraction<LocalVectorType>; + using NonblockedJacobianType = DynamicVector<XT::LA::CommonDenseMatrix<RangeFieldType>>; + + BlockedEigenvectorWrapper(const AnalyticalFluxType& analytical_flux, const bool flux_is_affine) + : BaseType(analytical_flux, flux_is_affine) + , jacobian_(std::make_unique<JacobianType>()) + , nonblocked_jacobian_(std::make_unique<NonblockedJacobianType>( + dimDomain, XT::LA::CommonDenseMatrix<RangeFieldType>(dimRange, dimRange, 0., 0))) + { + std::fill_n(&(eigenvalues_[0][0]), dimDomain * num_blocks, std::vector<double>(block_size, 0.)); + } + + virtual void compute_eigenvectors_impl(const E& entity, + const DomainType& x_local, + const VectorType& u, + const XT::Common::Parameter& param) override final + { + local_flux_->bind(entity); + const FluxDomainType nonblocked_u = u.operator FluxDomainType(); + try { + local_flux_->jacobian(x_local, nonblocked_u, *nonblocked_jacobian_, param); + *jacobian_ = *nonblocked_jacobian_; + for (size_t dd = 0; dd < dimDomain; ++dd) { + for (size_t jj = 0; jj < num_blocks; ++jj) { + if (block_size == 2) { + const auto& jac = (*jacobian_)[dd].block(jj); + const auto trace = jac[0][0] + jac[1][1]; + const auto det = jac[0][0] * jac[1][1] - jac[0][1] * jac[1][0]; + const auto sqrt_val = std::sqrt(0.25 * trace * trace - det); + auto& eigvals = eigenvalues_[dd][jj]; + eigvals[0] = 0.5 * trace + sqrt_val; + eigvals[1] = 0.5 * trace - sqrt_val; + auto& eigvecs = eigenvectors_[dd].block(jj); + if (std::abs(jac[1][0]) > std::abs(jac[0][1])) { + if (XT::Common::FloatCmp::ne(jac[1][0], 0.)) { + eigvecs[0][0] = eigvals[0] - jac[1][1]; + eigvecs[0][1] = eigvals[1] - jac[1][1]; + eigvecs[1][0] = eigvecs[1][1] = jac[1][0]; + } else { + eigvecs[0][0] = eigvecs[1][1] = 1.; + eigvecs[0][1] = eigvecs[1][0] = 0.; + } + } else { + if (XT::Common::FloatCmp::ne(jac[0][1], 0.)) { + eigvecs[1][0] = eigvals[0] - jac[0][0]; + eigvecs[1][1] = eigvals[1] - jac[0][0]; + eigvecs[0][0] = eigvecs[0][1] = jac[0][1]; + } else { + eigvecs[0][0] = eigvecs[1][1] = 1.; + eigvecs[0][1] = eigvecs[1][0] = 0.; + } + } + // normalize such that the eigenvectors have norm 1 + for (size_t col = 0; col < 2; ++col) { + RangeFieldType two_norm = 0; + two_norm = std::sqrt(std::pow(eigvecs[0][col], 2) + std::pow(eigvecs[1][col], 2)); + for (size_t row = 0; row < 2; ++row) + eigvecs[row][col] /= two_norm; + } + } else { + // For the small matrices (usually 4x4) used here it causes a lot of overhead to call into LAPACK every + // time, so we just use our own eigensolver most of the time. Occasionally, however, our eigensolver fails + // where the LAPACK eigensolver succeeds (due to a superior shifting strategy), so in these cases we call + // LAPACK. + try { + XT::LA::internal::fmatrix_compute_real_eigenvalues_and_real_right_eigenvectors_using_qr( + (*jacobian_)[dd].block(jj), eigenvalues_[dd][jj], eigenvectors_[dd].block(jj)); + } catch (const Dune::MathError&) { + // Our own eigensolver failed, try the default one instead (Lapacke, Eigen or Numpy, if none of these is + // available, we solve again using our own eigensolver, which will throw the error again. + static auto eigensolver_options = hyperbolic_default_eigensolver_options<LocalMatrixType>(); + const auto eigensolver = EigenSolverType((*jacobian_)[dd].block(jj), &eigensolver_options); + eigenvectors_[dd].block(jj) = eigensolver.real_eigenvectors(); + eigenvalues_[dd][jj] = eigensolver.real_eigenvalues(); + } + } // else (block_size == 2) + QR_[dd].block(jj) = eigenvectors_[dd].block(jj); + XT::LA::qr(QR_[dd].block(jj), tau_[dd].block(jj), permutations_[dd].block(jj)); +#if HAVE_MKL || HAVE_LAPACKE + int info = XT::Common::Lapacke::dtrcon(XT::Common::Lapacke::row_major(), + '1', + 'U', + 'N', + static_cast<int>(block_size), + LocalM::data(QR_[dd].block(jj)), + static_cast<int>(block_size), + &eigenvectors_rcond_); + if (info || eigenvectors_rcond_ < 1e-5) + DUNE_THROW(Dune::MathError, "Eigenvector condition too high!"); +#endif + } // jj + } // dd + } catch (const Dune::MathError&) { + for (size_t dd = 0; dd < dimDomain; ++dd) { + for (size_t jj = 0; jj < num_blocks; ++jj) { + // use scalar limiters, i.e. eigenvectors matrix is eye-matrix. + XT::LA::eye_matrix(eigenvectors_[dd].block(jj)); + std::fill(eigenvalues_[dd][jj].begin(), eigenvalues_[dd][jj].end(), 1.); + QR_[dd].block(jj) = eigenvectors_[dd].block(jj); + XT::LA::qr(QR_[dd].block(jj), tau_[dd].block(jj), permutations_[dd].block(jj)); + } // jj + } // dd + } + + if (flux_is_affine_) { + jacobian_ = nullptr; + nonblocked_jacobian_ = nullptr; + } + } + + void apply_eigenvectors(const size_t dd, const VectorType& u, VectorType& ret) const override final + { + eigenvectors_[dd].mv(u, ret); + } + + void apply_inverse_eigenvectors(const size_t dd, const VectorType& u, VectorType& ret) const override final + { + LocalVectorType work; + for (size_t jj = 0; jj < num_blocks; ++jj) + XT::LA::solve_qr_factorized( + QR_[dd].block(jj), tau_[dd].block(jj), permutations_[dd].block(jj), ret.block(jj), u.block(jj), &work); + } + + const MatrixType& eigenvectors(const size_t dd) const override final + { + return eigenvectors_[dd]; + } + +protected: + using BaseType::flux_is_affine_; + using BaseType::local_flux_; + std::unique_ptr<JacobianType> jacobian_; + std::unique_ptr<NonblockedJacobianType> nonblocked_jacobian_; + FieldVector<FieldVector<std::vector<double>, num_blocks>, dimDomain> eigenvalues_; + FieldVector<MatrixType, dimDomain> eigenvectors_; + FieldVector<MatrixType, dimDomain> QR_; + FieldVector<VectorType, dimDomain> tau_; + RangeFieldType eigenvectors_rcond_; + FieldVector<BlockedIntVectorType, dimDomain> permutations_; +}; // BlockedEigenvectorWrapper<...> + + +} // namespace internal +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_OPERATORS_RECONSTRUCTION_INTERNAL_HH diff --git a/dune/gdt/operators/reconstruction/linear.hh b/dune/gdt/operators/reconstruction/linear.hh new file mode 100644 index 0000000000000000000000000000000000000000..52532936f8b9de44eda7cc46ca3e0112debda94b --- /dev/null +++ b/dune/gdt/operators/reconstruction/linear.hh @@ -0,0 +1,488 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2017 - 2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_OPERATORS_RECONSTRUCTION_LINEAR_HH +#define DUNE_GDT_OPERATORS_RECONSTRUCTION_LINEAR_HH + +#include <dune/geometry/quadraturerules.hh> + +#include <dune/xt/common/fvector.hh> +#include <dune/xt/common/parameter.hh> + +#include <dune/xt/grid/walker.hh> + +#include <dune/gdt/operators/interfaces.hh> +#include <dune/gdt/spaces/l2/discontinuous-lagrange.hh> +#include <dune/gdt/tools/discretevalued-grid-function.hh> + +#include "slopes.hh" +#include "internal.hh" + +namespace Dune { +namespace GDT { + + +template <class AnalyticalFluxType, class BoundaryValueType, class GV, class EigenvectorWrapperType> +class LinearSlopeElementFunctor : public XT::Grid::ElementFunctor<GV> +{ + using ThisType = LinearSlopeElementFunctor; + using BaseType = XT::Grid::ElementFunctor<GV>; + +public: + using typename BaseType::E; + using SlopeType = SlopeBase<E, EigenvectorWrapperType>; + using LocalVectorType = typename EigenvectorWrapperType::VectorType; + using StencilType = DynamicVector<LocalVectorType>; + using StencilsType = std::vector<StencilType>; + using DomainType = typename BoundaryValueType::DomainType; + using RangeType = typename BoundaryValueType::RangeReturnType; + static constexpr size_t d = BoundaryValueType::d; + static constexpr size_t stencil_size = 3; + + LinearSlopeElementFunctor(const GV& grid_view, + const std::vector<LocalVectorType>& source_values, + const BoundaryValueType& boundary_values, + const AnalyticalFluxType& analytical_flux, + const SlopeType& slope, + const XT::Common::Parameter& param, + const bool flux_is_affine = false) + + : grid_view_(grid_view) + , source_values_(source_values) + , boundary_values_(boundary_values) + , analytical_flux_(analytical_flux) + , slope_(slope.copy()) + , param_(param) + , eigenvector_wrapper_(analytical_flux, flux_is_affine) + , slopes_(d) + , stencils_(d, StencilType(stencil_size)) + {} + + LinearSlopeElementFunctor(const LinearSlopeElementFunctor& other) + : BaseType(other) + , grid_view_(other.grid_view_) + , source_values_(other.source_values_) + , boundary_values_(other.boundary_values_) + , analytical_flux_(other.analytical_flux_) + , slope_(other.slope_->copy()) + , param_(other.param_) + , eigenvector_wrapper_(analytical_flux_, other.eigenvector_wrapper_.affine()) + , slopes_(d) + , stencils_(d, StencilType(stencil_size)) + {} + + XT::Grid::ElementFunctor<GV>* copy() override final + { + return new ThisType(*this); + } + + ThisType* copy_derived() + { + return new ThisType(*this); + } + + void apply_local(const E& entity) override final + { + // In a MPI parallel run, if entity is on boundary of overlap, we do not have to reconstruct + if (!fill_stencils(entity)) + return; + + // get eigenvectors of flux + if (analytical_flux_.x_dependent()) + x_local_ = entity.geometry().local(entity.geometry().center()); + const auto entity_index = grid_view_.indexSet().index(entity); + eigenvector_wrapper_.compute_eigenvectors(entity, x_local_, source_values_[entity_index], param_); + + for (size_t dd = 0; dd < d; ++dd) { + // no need to reconstruct in all directions, as we are only regarding the center of the face, which will + // always have the same value assigned, independent of the slope in the other directions + slopes_[dd] = slope_->get(entity, stencils_[dd], eigenvector_wrapper_, dd); + } // dd + } + + const std::vector<RangeType>& slopes() const + { + return slopes_; + } + + const LocalVectorType& u_entity() const + { + return stencils_[0][1]; + } + +private: + bool fill_stencils(const E& entity) + { + const auto entity_index = grid_view_.indexSet().index(entity); + for (size_t dd = 0; dd < d; ++dd) + stencils_[dd][1] = source_values_[entity_index]; + for (const auto& intersection : Dune::intersections(grid_view_, entity)) { + const size_t dd = intersection.indexInInside() / 2; + const size_t index = (intersection.indexInInside() % 2) * 2; + if (intersection.boundary() && !intersection.neighbor()) // boundary intersections + stencils_[dd][index] = boundary_values_.evaluate(intersection.geometry().center()); + else if (intersection.neighbor()) // inner and periodic intersections + stencils_[dd][index] = source_values_[grid_view_.indexSet().index(intersection.outside())]; + else if (!intersection.neighbor() && !intersection.boundary()) // processor boundary + return false; + else + DUNE_THROW(Dune::NotImplemented, "This should not happen!"); + } // intersections + return true; + } // void fill_stencils(...) + + const GV& grid_view_; + const std::vector<LocalVectorType>& source_values_; + const BoundaryValueType& boundary_values_; + const AnalyticalFluxType& analytical_flux_; + std::unique_ptr<SlopeType> slope_; + const XT::Common::Parameter& param_; + EigenvectorWrapperType eigenvector_wrapper_; + DomainType x_local_; + std::vector<RangeType> slopes_; + StencilsType stencils_; +}; + +template <class AnalyticalFluxType, + class BoundaryValueType, + class GV, + class EigenvectorWrapperType = internal::EigenvectorWrapper<AnalyticalFluxType>> +class LocalPointwiseLinearReconstructionOperator : public XT::Grid::ElementFunctor<GV> +{ + using ThisType = LocalPointwiseLinearReconstructionOperator; + using BaseType = XT::Grid::ElementFunctor<GV>; + static constexpr size_t dimDomain = BoundaryValueType::d; + static constexpr size_t dimRange = BoundaryValueType::r; + using EntityType = typename GV::template Codim<0>::Entity; + using DomainType = typename BoundaryValueType::DomainType; + using RangeType = typename BoundaryValueType::RangeReturnType; + using RangeFieldType = typename BoundaryValueType::RangeFieldType; + using LocalVectorType = typename EigenvectorWrapperType::VectorType; + using SlopeType = SlopeBase<EntityType, EigenvectorWrapperType>; + using SlopeFunctorType = LinearSlopeElementFunctor<AnalyticalFluxType, BoundaryValueType, GV, EigenvectorWrapperType>; + using ReconstructedFunctionType = DiscreteValuedGridFunction<GV, dimRange, 1, RangeFieldType>; + +public: + explicit LocalPointwiseLinearReconstructionOperator(ReconstructedFunctionType& reconstructed_function, + const GV& grid_view, + const std::vector<LocalVectorType>& source_values, + const BoundaryValueType& boundary_values, + const AnalyticalFluxType& analytical_flux, + const SlopeType& slope, + const XT::Common::Parameter& param, + const bool flux_is_affine = false) + : slope_functor_(std::make_unique<SlopeFunctorType>( + grid_view, source_values, boundary_values, analytical_flux, slope, param, flux_is_affine)) + , reconstructed_function_(reconstructed_function) + {} + + LocalPointwiseLinearReconstructionOperator(const ThisType& other) + : BaseType(other) + , slope_functor_(other.slope_functor_->copy_derived()) + , reconstructed_function_(other.reconstructed_function_) + {} + + XT::Grid::ElementFunctor<GV>* copy() override final + { + return new ThisType(*this); + } + + void apply_local(const EntityType& entity) override final + { + slope_functor_->apply_local(entity); + // reconstructed function is f(x) = u_entity + slope_matrix * (x - (0.5, 0.5, 0.5, ...)) + auto& local_reconstructed_values = reconstructed_function_.local_values(entity); + const RangeType u_entity = slope_functor_->u_entity(); + for (size_t dd = 0; dd < dimDomain; ++dd) { + for (size_t ii = 0; ii < 2; ++ii) { + DomainType coord(0.5); + coord[dd] = ii; + local_reconstructed_values[coord] = u_entity + slope_functor_->slopes()[dd] * (ii - 0.5); + } // ii + } // dd + } // void apply_local(...) + +private: + std::unique_ptr<SlopeFunctorType> slope_functor_; + ReconstructedFunctionType& reconstructed_function_; +}; // class LocalPointwiseLinearReconstructionOperator + + +template <class AnalyticalFluxType, + class BoundaryValueType, + class GV, + class TargetSpaceType, + class TargetVectorType = typename XT::LA::Container<typename AnalyticalFluxType::R>::VectorType, + class EigenvectorWrapperType = internal::EigenvectorWrapper<AnalyticalFluxType>> +class LocalLinearReconstructionOperator : public XT::Grid::ElementFunctor<GV> +{ + using BaseType = XT::Grid::ElementFunctor<GV>; + static constexpr size_t dimDomain = BoundaryValueType::d; + static constexpr size_t dimRange = BoundaryValueType::r; + using EntityType = typename GV::template Codim<0>::Entity; + using RangeType = typename BoundaryValueType::RangeReturnType; + using RangeFieldType = typename BoundaryValueType::RangeFieldType; + using LocalVectorType = typename EigenvectorWrapperType::VectorType; + using SlopeType = SlopeBase<EntityType, EigenvectorWrapperType>; + using TargetType = DiscreteFunction<TargetVectorType, GV, dimRange, 1, RangeFieldType>; + using TargetBasisType = typename TargetType::SpaceType::GlobalBasisType::LocalizedType; + using LocalDofVectorType = typename TargetType::DofVectorType::LocalDofVectorType; + using SlopeFunctorType = LinearSlopeElementFunctor<AnalyticalFluxType, BoundaryValueType, GV, EigenvectorWrapperType>; + +public: + explicit LocalLinearReconstructionOperator(const std::vector<LocalVectorType>& source_values, + TargetSpaceType target_space, + TargetVectorType& target_vector, + const AnalyticalFluxType& analytical_flux, + const BoundaryValueType& boundary_values, + const SlopeType& slope, + const XT::Common::Parameter& param, + const bool flux_is_affine = false) + : slope_functor_(std::make_unique<SlopeFunctorType>( + target_space.grid_view(), source_values, boundary_values, analytical_flux, slope, param, flux_is_affine)) + , target_space_(target_space) + , target_vector_(target_vector) + , target_(target_space_, target_vector_, "range") + , target_basis_(target_.space().basis().localize()) + , local_dof_vector_(target_.dofs().localize()) + {} + + LocalLinearReconstructionOperator(const LocalLinearReconstructionOperator& other) + : BaseType(other) + , slope_functor_(other.slope_functor_->copy_derived()) + , target_space_(other.target_space_) + , target_vector_(other.target_vector_) + , target_(target_space_, target_vector_, "range") + , target_basis_(target_.space().basis().localize()) + , local_dof_vector_(target_.dofs().localize()) + {} + + XT::Grid::ElementFunctor<GV>* copy() override final + { + return new LocalLinearReconstructionOperator(*this); + } + + void apply_local(const EntityType& entity) override final + { + slope_functor_->apply_local(entity); + // reconstructed function is f(x) = u_entity + slope_matrix * (x - (0.5, 0.5, 0.5, ...)) + local_dof_vector_.bind(entity); + target_basis_->bind(entity); + const RangeType u_entity = slope_functor_->u_entity(); + target_basis_->interpolate( + [&](const auto& xx) { + auto ret = u_entity; + for (size_t dd = 0; dd < dimDomain; ++dd) + ret += slope_functor_->slopes()[dd] * (xx[dd] - 0.5); + return ret; + }, + 1, + local_dof_vector_); + } // void apply_local(...) + +private: + std::unique_ptr<SlopeFunctorType> slope_functor_; + TargetSpaceType target_space_; + TargetVectorType& target_vector_; + TargetType target_; + std::unique_ptr<TargetBasisType> target_basis_; + LocalDofVectorType local_dof_vector_; +}; // class LocalLinearReconstructionOperator + +template <class AnalyticalFluxImp, + class BoundaryValueImp, + class GV, + class MatrixImp = typename XT::LA::Container<typename AnalyticalFluxImp::R>::MatrixType, + class EigenvectorWrapperImp = internal::EigenvectorWrapper< + AnalyticalFluxImp, + FieldMatrix<typename BoundaryValueImp::R, BoundaryValueImp::r, BoundaryValueImp::r>, + FieldVector<typename BoundaryValueImp::R, BoundaryValueImp::r>>> +class LinearReconstructionOperator : public OperatorInterface<MatrixImp, GV, BoundaryValueImp::r> +{ + using BaseType = OperatorInterface<MatrixImp, GV, BoundaryValueImp::r>; + +public: + using typename BaseType::RangeSpaceType; + using typename BaseType::SourceSpaceType; + using typename BaseType::VectorType; + + using AnalyticalFluxType = AnalyticalFluxImp; + using BoundaryValueType = BoundaryValueImp; + using EigenvectorWrapperType = EigenvectorWrapperImp; + using LocalVectorType = typename EigenvectorWrapperType::VectorType; + using MatrixType = typename EigenvectorWrapperType::MatrixType; + using E = XT::Grid::extract_entity_t<GV>; + using SlopeType = SlopeBase<E, EigenvectorWrapperType>; + static constexpr size_t dimDomain = BoundaryValueType::d; + static constexpr size_t dimRange = BoundaryValueType::r; + using ReconstructionSpaceType = DiscontinuousLagrangeSpace<GV, dimRange, typename AnalyticalFluxType::R>; + + LinearReconstructionOperator(const AnalyticalFluxType& analytical_flux, + const BoundaryValueType& boundary_values, + const SourceSpaceType& source_space, + const SlopeType& slope = default_minmod_slope(), + const bool flux_is_affine = false) + : analytical_flux_(analytical_flux) + , boundary_values_(boundary_values) + , source_space_(source_space) + , range_space_(source_space_.grid_view(), 1) + , slope_(slope) + , flux_is_affine_(flux_is_affine) + {} + + bool linear() const override final + { + return false; + } + + const SourceSpaceType& source_space() const override final + { + return source_space_; + } + + const RangeSpaceType& range_space() const override final + { + return range_space_; + } + + void apply(const VectorType& source, VectorType& range, const XT::Common::Parameter& param) const override + { + // evaluate cell averages + const auto& grid_view = source_space_.grid_view(); + const auto& index_set = grid_view.indexSet(); + std::vector<LocalVectorType> source_values(index_set.size(0)); + auto source_func = make_discrete_function(source_space(), source); + const auto local_source = source_func.local_function(); + for (const auto& entity : Dune::elements(grid_view)) { + local_source->bind(entity); + const auto entity_index = index_set.index(entity); + source_values[entity_index] = local_source->evaluate(entity.geometry().local(entity.geometry().center())); + } + + // do reconstruction + auto local_reconstruction_operator = LocalLinearReconstructionOperator<AnalyticalFluxType, + BoundaryValueType, + GV, + ReconstructionSpaceType, + VectorType, + EigenvectorWrapperType>( + source_values, range_space_, range, analytical_flux_, boundary_values_, slope_, param, flux_is_affine_); + auto walker = XT::Grid::Walker<GV>(grid_view); + walker.append(local_reconstruction_operator); + walker.walk(true); + } // void apply(...) + +private: + static SlopeType& default_minmod_slope() + { + static MinmodSlope<E, EigenvectorWrapperType> minmod_slope_; + return minmod_slope_; + } + + const AnalyticalFluxType& analytical_flux_; + const BoundaryValueType& boundary_values_; + const SourceSpaceType& source_space_; + ReconstructionSpaceType range_space_; + const SlopeType& slope_; + const bool flux_is_affine_; +}; // class LinearReconstructionOperator<...> + + +// Does not reconstruct a full first-order DG function, but only stores the reconstructed values at the intersection +// centers. This avoids the interpolation in this operator and the evaluation of the reconstructed function in the +// finite volume operator which are both quite expensive for large dimRange. +template <class AnalyticalFluxImp, + class BoundaryValueImp, + class GV, + class VectorType, + class EigenvectorWrapperImp = internal::EigenvectorWrapper< + AnalyticalFluxImp, + FieldMatrix<typename BoundaryValueImp::R, BoundaryValueImp::r, BoundaryValueImp::r>, + FieldVector<typename BoundaryValueImp::R, BoundaryValueImp::r>>> +class PointwiseLinearReconstructionOperator +{ +public: + using AnalyticalFluxType = AnalyticalFluxImp; + using BoundaryValueType = BoundaryValueImp; + using EigenvectorWrapperType = EigenvectorWrapperImp; + using LocalVectorType = typename EigenvectorWrapperType::VectorType; + using E = XT::Grid::extract_entity_t<GV>; + using SlopeType = SlopeBase<E, EigenvectorWrapperType>; + using R = typename BoundaryValueType::R; + static constexpr size_t dimDomain = BoundaryValueType::d; + static constexpr size_t dimRange = BoundaryValueType::r; + using SpaceType = SpaceInterface<GV, dimRange, 1, R>; + using ReconstructedFunctionType = DiscreteValuedGridFunction<GV, dimRange, 1, R>; + using ReconstructedValuesType = std::vector<typename ReconstructedFunctionType::LocalFunctionValuesType>; + + PointwiseLinearReconstructionOperator(const AnalyticalFluxType& analytical_flux, + const BoundaryValueType& boundary_values, + const SpaceType& space, + const SlopeType& slope = default_minmod_slope(), + const bool flux_is_affine = false) + : analytical_flux_(analytical_flux) + , boundary_values_(boundary_values) + , space_(space) + , slope_(slope) + , flux_is_affine_(flux_is_affine) + {} + + bool linear() const + { + return false; + } + + const SpaceType& space() const + { + return space_; + } + + void apply(const VectorType& source, ReconstructedFunctionType& range, const XT::Common::Parameter& param) const + { + // evaluate cell averages + const auto& grid_view = space_.grid_view(); + const auto& index_set = grid_view.indexSet(); + std::vector<LocalVectorType> source_values(index_set.size(0)); + auto source_func = make_discrete_function(space_, source); + const auto local_source = source_func.local_function(); + for (const auto& entity : Dune::elements(grid_view)) { + local_source->bind(entity); + const auto entity_index = index_set.index(entity); + source_values[entity_index] = local_source->evaluate(entity.geometry().local(entity.geometry().center())); + } + + // do reconstruction + auto local_reconstruction_operator = + LocalPointwiseLinearReconstructionOperator<AnalyticalFluxType, BoundaryValueType, GV, EigenvectorWrapperType>( + range, grid_view, source_values, boundary_values_, analytical_flux_, slope_, param, flux_is_affine_); + auto walker = XT::Grid::Walker<GV>(grid_view); + walker.append(local_reconstruction_operator); + walker.walk(true); + } // void apply(...) + +private: + static SlopeType& default_minmod_slope() + { + static MinmodSlope<E, EigenvectorWrapperType> minmod_slope_; + return minmod_slope_; + } + + const AnalyticalFluxType& analytical_flux_; + const BoundaryValueType& boundary_values_; + const SpaceType& space_; + const SlopeType& slope_; + const bool flux_is_affine_; +}; // class PointwiseLinearReconstructionOperator<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_OPERATORS_RECONSTRUCTION_LINEAR_HH diff --git a/dune/gdt/operators/reconstruction/linear_kinetic.hh b/dune/gdt/operators/reconstruction/linear_kinetic.hh new file mode 100644 index 0000000000000000000000000000000000000000..863065af003aa8b78105b5309fbb00484c358676 --- /dev/null +++ b/dune/gdt/operators/reconstruction/linear_kinetic.hh @@ -0,0 +1,182 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2019) + +#ifndef DUNE_GDT_OPERATORS_RECONSTRUCTION_LINEAR_KINETIC_HH +#define DUNE_GDT_OPERATORS_RECONSTRUCTION_LINEAR_KINETIC_HH + +#include <dune/geometry/quadraturerules.hh> + +#include <dune/xt/common/fvector.hh> +#include <dune/xt/common/parameter.hh> + +#include <dune/xt/grid/walker.hh> + +#include <dune/gdt/operators/interfaces.hh> +#include <dune/gdt/spaces/l2/discontinuous-lagrange.hh> +#include <dune/gdt/tools/discretevalued-grid-function.hh> + +#include "slopes.hh" +#include "internal.hh" + +namespace Dune { +namespace GDT { + + +template <class GV, class AnalyticalFluxType, class BoundaryValueType, class LocalVectorType> +class LocalPointwiseLinearKineticReconstructionOperator : public XT::Grid::ElementFunctor<GV> +{ + using ThisType = LocalPointwiseLinearKineticReconstructionOperator; + using BaseType = XT::Grid::ElementFunctor<GV>; + static constexpr size_t dimDomain = BoundaryValueType::d; + static constexpr size_t dimRange = BoundaryValueType::r; + using EntityType = typename GV::template Codim<0>::Entity; + using RangeFieldType = typename BoundaryValueType::RangeFieldType; + static constexpr size_t stencil_size = 3; + using StencilType = XT::Common::FieldVector<size_t, stencil_size>; + using StencilsType = FieldVector<StencilType, dimDomain>; + using DomainType = typename BoundaryValueType::DomainType; + using RangeType = typename BoundaryValueType::RangeReturnType; + using ReconstructedFunctionType = DiscreteValuedGridFunction<GV, dimRange, 1, RangeFieldType>; + +public: + explicit LocalPointwiseLinearKineticReconstructionOperator(ReconstructedFunctionType& reconstructed_function, + const GV& grid_view, + const AnalyticalFluxType& analytical_flux, + const XT::Common::Parameter& param) + : reconstructed_function_(reconstructed_function) + , grid_view_(grid_view) + , analytical_flux_(analytical_flux) + , param_(param) + {} + + LocalPointwiseLinearKineticReconstructionOperator(const ThisType& other) + : BaseType(other) + , reconstructed_function_(other.reconstructed_function_) + , grid_view_(other.grid_view_) + , analytical_flux_(other.analytical_flux_) + , param_(other.param_) + {} + + XT::Grid::ElementFunctor<GV>* copy() override final + { + return new ThisType(*this); + } + + void apply_local(const EntityType& entity) override final + { + // In a MPI parallel run, if entity is on boundary of overlap, we do not have to reconstruct + if (!fill_stencils(entity)) + return; + + auto& local_reconstructed_values = reconstructed_function_.local_values(entity); + for (size_t dd = 0; dd < dimDomain; ++dd) + analytical_flux_.calculate_reconstructed_fluxes( + stencils_[dd], boundary_dirs_[dd], local_reconstructed_values, dd); + } // void apply_local(...) + +private: + bool fill_stencils(const EntityType& entity) + { + for (size_t dd = 0; dd < dimDomain; ++dd) + stencils_[dd][1] = grid_view_.indexSet().index(entity); + for (const auto& intersection : Dune::intersections(grid_view_, entity)) { + const size_t dd = intersection.indexInInside() / 2; + const size_t index = (intersection.indexInInside() % 2) * 2; + if (intersection.boundary() && !intersection.neighbor()) { // boundary intersections + stencils_[dd][index] = size_t(-1); + boundary_dirs_[dd][index] = intersection.indexInInside() % 2; + } else if (intersection.neighbor()) { // inner and periodic intersections { + stencils_[dd][index] = grid_view_.indexSet().index(intersection.outside()); + } else if (!intersection.neighbor() && !intersection.boundary()) { // processor boundary + return false; + } else { + DUNE_THROW(Dune::NotImplemented, "This should not happen!"); + } + } // intersections + return true; + } // void fill_stencils(...) + + ReconstructedFunctionType& reconstructed_function_; + const GV& grid_view_; + const AnalyticalFluxType& analytical_flux_; + const XT::Common::Parameter& param_; + StencilsType stencils_; + XT::Common::FieldVector<XT::Common::FieldVector<size_t, stencil_size>, dimDomain> boundary_dirs_; + +}; // class LocalPointwiseLinearKineticReconstructionOperator + +// Does not reconstruct a full first-order DG function, but only stores the reconstructed values at the intersection +// centers. This avoids the interpolation in this operator and the evaluation of the reconstructed function in the +// finite volume operator which are both quite expensive for large dimRange. +template <class GV, class BoundaryValueImp, class AnalyticalFluxType, class VectorType, class LocalVectorType> +class PointwiseLinearKineticReconstructionOperator +{ +public: + using BoundaryValueType = BoundaryValueImp; + using E = XT::Grid::extract_entity_t<GV>; + using EigenVectorWrapperType = internal::DummyEigenVectorWrapper<AnalyticalFluxType, LocalVectorType>; + using R = typename BoundaryValueType::R; + static constexpr size_t dimDomain = BoundaryValueType::d; + static constexpr size_t dimRange = BoundaryValueType::r; + using SpaceType = SpaceInterface<GV, dimRange, 1, R>; + using ReconstructedFunctionType = DiscreteValuedGridFunction<GV, dimRange, 1, R>; + using ReconstructedValuesType = std::vector<typename ReconstructedFunctionType::LocalFunctionValuesType>; + + PointwiseLinearKineticReconstructionOperator(const BoundaryValueType& boundary_values, + const SpaceType& space, + const AnalyticalFluxType& analytical_flux) + : boundary_values_(boundary_values) + , space_(space) + , analytical_flux_(analytical_flux) + {} + + bool linear() const + { + return false; + } + + const SpaceType& space() const + { + return space_; + } + + void apply(const VectorType& source, ReconstructedFunctionType& range, const XT::Common::Parameter& param) const + { + // evaluate cell averages + const auto& grid_view = space_.grid_view(); + const auto& index_set = grid_view.indexSet(); + std::vector<LocalVectorType> source_values(index_set.size(0)); + auto source_func = make_discrete_function(space_, source); + const auto local_source = source_func.local_function(); + for (const auto& entity : Dune::elements(grid_view)) { + local_source->bind(entity); + const auto entity_index = index_set.index(entity); + source_values[entity_index] = local_source->evaluate(entity.geometry().local(entity.geometry().center())); + } + + // do reconstruction + auto local_reconstruction_operator = + LocalPointwiseLinearKineticReconstructionOperator<GV, AnalyticalFluxType, BoundaryValueType, LocalVectorType>( + range, grid_view, analytical_flux_, param); + auto walker = XT::Grid::Walker<GV>(grid_view); + walker.append(local_reconstruction_operator); + walker.walk(true); + } // void apply(...) + +private: + const BoundaryValueType& boundary_values_; + const SpaceType& space_; + const AnalyticalFluxType& analytical_flux_; +}; // class PointwiseLinearKineticReconstructionOperator<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_OPERATORS_RECONSTRUCTION_LINEAR_KINETIC_HH diff --git a/dune/gdt/operators/reconstruction/slopes.hh b/dune/gdt/operators/reconstruction/slopes.hh new file mode 100644 index 0000000000000000000000000000000000000000..1819ad44fa0794686e795c922315aec2b79b679a --- /dev/null +++ b/dune/gdt/operators/reconstruction/slopes.hh @@ -0,0 +1,1128 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_OPERATORS_FV_SLOPES_HH +#define DUNE_GDT_OPERATORS_FV_SLOPES_HH + +#if HAVE_CLP +# include <coin/ClpSimplex.hpp> +#endif // HAVE_CLP + +#if HAVE_QHULL +# include <dune/xt/common/disable_warnings.hh> +# include <libqhullcpp/Qhull.h> +# include <libqhullcpp/QhullFacetList.h> +# include <dune/xt/common/reenable_warnings.hh> +#endif // HAVE_QHULL + +#include <dune/geometry/quadraturerules.hh> + +#include <dune/xt/common/float_cmp.hh> +#include <dune/xt/common/fvector.hh> +#include <dune/xt/common/parallel/threadstorage.hh> + +#include <dune/gdt/test/momentmodels/basisfunctions/partial_moments.hh> +#include <dune/gdt/test/momentmodels/entropyflux.hh> + +namespace Dune { +namespace GDT { + + +template <class E, class EigenVectorWrapperType, size_t stencil_size = 3> +class SlopeBase +{ +public: + virtual ~SlopeBase() = default; + + using VectorType = typename EigenVectorWrapperType::VectorType; + using MatrixType = typename EigenVectorWrapperType::MatrixType; + using StencilType = FieldVector<VectorType, stencil_size>; + + virtual SlopeBase* copy() const = 0; + + // at least one of the following two methods has to be implemented + // returns (limited) slope in ordinary coordinates + virtual VectorType + get(const E& entity, const StencilType& stencil, const EigenVectorWrapperType& eigenvectors, const size_t dd) const + { + VectorType slope_char = get_char(entity, stencil, eigenvectors, dd); + VectorType slope; + eigenvectors.apply_eigenvectors(dd, slope_char, slope); + return slope; + } + + // returns (limited) slope in characteristic coordinates + virtual VectorType get_char(const E& entity, + const StencilType& stencil, + const EigenVectorWrapperType& eigenvectors, + const size_t dd) const + { + VectorType slope = get(entity, stencil, eigenvectors, dd); + // convert to characteristic coordinates + VectorType slope_char; + eigenvectors.apply_inverse_eigenvectors(dd, slope, slope_char); + return slope_char; + } +}; + + +// Central slope without any limiting +template <class E, class EigenVectorWrapperType, size_t stencil_size> +class CentralSlope : public SlopeBase<E, EigenVectorWrapperType, stencil_size> +{ + using BaseType = SlopeBase<E, EigenVectorWrapperType, stencil_size>; + using ThisType = CentralSlope; + +public: + using typename BaseType::StencilType; + using typename BaseType::VectorType; + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get(const E& /*entity*/, + const StencilType& stencil, + const EigenVectorWrapperType& /*eigenvectors*/, + const size_t /*dd*/) const override final + { + const VectorType& u_left = stencil[0]; + const VectorType& u_right = stencil[2]; + return (u_right - u_left) / 2.; + } +}; + + +// Left slope without any limiting +template <class E, class EigenVectorWrapperType, size_t stencil_size> +class LeftSlope : public SlopeBase<E, EigenVectorWrapperType, stencil_size> +{ + using BaseType = SlopeBase<E, EigenVectorWrapperType, stencil_size>; + using ThisType = LeftSlope; + +public: + using typename BaseType::StencilType; + using typename BaseType::VectorType; + + BaseType* copy() const override final + { + return new ThisType(); + } + + virtual VectorType get(const E& /*entity*/, + const StencilType& stencil, + const EigenVectorWrapperType& /*eigenvectors*/, + const size_t /*dd*/) const override final + { + const VectorType& u_left = stencil[0]; + const VectorType& u = stencil[1]; + return u - u_left; + } +}; + + +// Right slope without any limiting +template <class E, class EigenVectorWrapperType, size_t stencil_size> +class RightSlope : public SlopeBase<E, EigenVectorWrapperType, stencil_size> +{ + using BaseType = SlopeBase<E, EigenVectorWrapperType, stencil_size>; + using ThisType = RightSlope; + +public: + using typename BaseType::StencilType; + using typename BaseType::VectorType; + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get(const E& /*entity*/, + const StencilType& stencil, + const EigenVectorWrapperType& /*eigenvectors*/, + const size_t /*dd*/) const override final + { + const VectorType& u = stencil[1]; + const VectorType& u_right = stencil[2]; + return u_right - u; + } +}; + + +// Zero slope +template <class E, class EigenVectorWrapperType, size_t stencil_size> +class NoSlope : public SlopeBase<E, EigenVectorWrapperType, stencil_size> +{ + using BaseType = SlopeBase<E, EigenVectorWrapperType, stencil_size>; + using ThisType = NoSlope; + using typename BaseType::VectorType; + +public: + using typename BaseType::StencilType; + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get(const E& /*entity*/, + const StencilType& /*stencil*/, + const EigenVectorWrapperType& /*eigenvectors*/, + const size_t /*dd*/) const override final + { + return VectorType(0.); + } +}; + + +template <class E, class EigenVectorWrapperType> +class MinmodSlope : public SlopeBase<E, EigenVectorWrapperType, 3> +{ + using BaseType = SlopeBase<E, EigenVectorWrapperType, 3>; + using ThisType = MinmodSlope; + using typename BaseType::VectorType; + +public: + using typename BaseType::StencilType; + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get_char(const E& /*entity*/, + const StencilType& stencil, + const EigenVectorWrapperType& eigenvectors, + const size_t dd) const override final + { + const VectorType slope_left = stencil[1] - stencil[0]; + const VectorType slope_right = stencil[2] - stencil[1]; + VectorType slope_left_char, slope_right_char; + eigenvectors.apply_inverse_eigenvectors(dd, slope_left, slope_left_char); + eigenvectors.apply_inverse_eigenvectors(dd, slope_right, slope_right_char); + return minmod(slope_left_char, slope_right_char); + } + + static VectorType minmod(const VectorType& first_slope, const VectorType& second_slope) + { + VectorType ret; + for (size_t ii = 0; ii < first_slope.size(); ++ii) + ret[ii] = XT::Common::minmod(first_slope[ii], second_slope[ii]); + return ret; + } +}; + + +template <class E, class EigenVectorWrapperType> +class McSlope : public SlopeBase<E, EigenVectorWrapperType, 3> +{ + using BaseType = SlopeBase<E, EigenVectorWrapperType, 3>; + using ThisType = McSlope; + using MinmodType = MinmodSlope<E, EigenVectorWrapperType>; + +public: + using typename BaseType::StencilType; + using typename BaseType::VectorType; + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get_char(const E& /*entity*/, + const StencilType& stencil, + const EigenVectorWrapperType& eigenvectors, + const size_t dd) const override final + { + const VectorType& u_left = stencil[0]; + const VectorType& u = stencil[1]; + const VectorType& u_right = stencil[2]; + const VectorType slope_left = (u - u_left) * 2.; + const VectorType slope_right = (u_right - u) * 2.; + const VectorType slope_center = (u_right - u_left) / 2.; + VectorType slope_left_char, slope_right_char, slope_center_char; + eigenvectors.apply_inverse_eigenvectors(dd, slope_left, slope_left_char); + eigenvectors.apply_inverse_eigenvectors(dd, slope_right, slope_right_char); + eigenvectors.apply_inverse_eigenvectors(dd, slope_center, slope_center_char); + const VectorType first_slope = MinmodType::minmod(slope_left_char, slope_right_char); + return MinmodType::minmod(first_slope, slope_center_char); + } +}; + + +template <class E, class EigenVectorWrapperType> +class SuperbeeSlope : public SlopeBase<E, EigenVectorWrapperType, 3> +{ + using BaseType = SlopeBase<E, EigenVectorWrapperType, 3>; + using ThisType = SuperbeeSlope; + using MinmodType = MinmodSlope<E, EigenVectorWrapperType>; + +public: + using typename BaseType::StencilType; + using typename BaseType::VectorType; + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get_char(const E& /*entity*/, + const StencilType& stencil, + const EigenVectorWrapperType& eigenvectors, + const size_t dd) const override final + { + const VectorType slope_left = stencil[1] - stencil[0]; + const VectorType slope_right = stencil[2] - stencil[1]; + VectorType slope_left_char, slope_right_char; + eigenvectors.apply_inverse_eigenvectors(dd, slope_left, slope_left_char); + eigenvectors.apply_inverse_eigenvectors(dd, slope_right, slope_right_char); + return superbee(slope_left_char, slope_right_char); + } + + static VectorType superbee(const VectorType& first_slope, const VectorType& second_slope) + { + VectorType ret(0.); + for (size_t ii = 0; ii < first_slope.size(); ++ii) + ret[ii] = superbee(first_slope[ii], second_slope[ii]); + return ret; + } +}; // class SuperbeeSlope + + +template <class GV, class MomentBasis> +class RealizabilityLimiterBase +{ +public: + using E = XT::Grid::extract_entity_t<GV>; + using EntropyFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + using StateType = typename EntropyFluxType::StateType; + + RealizabilityLimiterBase(const EntropyFluxType& entropy_flux) + : entropy_flux_(entropy_flux) + , local_flux_(entropy_flux_.derived_local_function()) + {} + + RealizabilityLimiterBase(const RealizabilityLimiterBase& other) + : entropy_flux_(other.entropy_flux_) + , local_flux_(entropy_flux_.derived_local_function()) + {} + + // Ensures we are able to solve the optimization problems for the reconstructed values without regularization. If + // optimization fails, we just set the slope to 0. + template <class VectorType> + void ensure_solvability(const E& entity, const VectorType& u, VectorType& slope) const + { + local_flux_->bind(entity); + try { + const auto u_left = u - slope * 0.5; + const auto u_right = u + slope * 0.5; + local_flux_->get_alpha(u_left, false); + local_flux_->get_alpha(u_right, false); + } catch (const Dune::MathError&) { + std::fill(slope.begin(), slope.end(), 0.); + } + } + +private: + const EntropyFluxType& entropy_flux_; + std::unique_ptr<typename EntropyFluxType::Localfunction> local_flux_; +}; + + +// Realizability limiter that ensures positivity of the components of u in noncharacteristic variables. Uses single +// limiter variable for all components. +template <class GV, + class MomentBasis, + class EigenVectorWrapperType, + class SlopeType = MinmodSlope<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType>> +class PositivityLimitedSlope + : public SlopeBase<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType, 3> + , public RealizabilityLimiterBase<GV, MomentBasis> +{ + using ThisType = PositivityLimitedSlope; + using RangeFieldType = typename MomentBasis::RangeFieldType; + static const size_t dimRange = MomentBasis::dimRange; + using RealizabilityBaseType = RealizabilityLimiterBase<GV, MomentBasis>; + using typename RealizabilityBaseType::E; + using typename RealizabilityBaseType::EntropyFluxType; + using BaseType = SlopeBase<E, EigenVectorWrapperType, 3>; + using typename BaseType::VectorType; + +public: + using typename BaseType::StencilType; + + // This limiter ensures u_i >= epsilon for all components u_i of u. + PositivityLimitedSlope(const EntropyFluxType& entropy_flux, const RangeFieldType epsilon = 0.) + : RealizabilityBaseType(entropy_flux) + , epsilon_(epsilon) + {} + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get(const E& entity, + const StencilType& stencil, + const EigenVectorWrapperType& eigenvectors, + const size_t dd) const override final + { + static const VectorType zero_vector(0.); + const VectorType& u_bar = stencil[1]; + if (!is_epsilon_realizable(u_bar, epsilon_)) + return zero_vector; + const VectorType slope = slope_limiter_.get(entity, stencil, eigenvectors, dd); + // this needs to be changed for other interface quadratures (see above) + const FieldVector<VectorType, 2> reconstructed_values{u_bar - 0.5 * slope, u_bar + 0.5 * slope}; + VectorType thetas(0.); + for (size_t kk = 0; kk < reconstructed_values.size(); ++kk) { + const VectorType& u = reconstructed_values[kk]; + for (size_t ii = 0; ii < u.size(); ++ii) { + if (u[ii] >= u_bar[ii]) + continue; + else if (u[ii] < epsilon_) + thetas[ii] = std::max(thetas[ii], (epsilon_ - u[ii]) / (u_bar[ii] - u[ii])); + } + } // kk + + const auto theta_max = *std::max_element(thetas.begin(), thetas.end()); + assert(XT::Common::FloatCmp::le(theta_max, 1.) && XT::Common::FloatCmp::ge(theta_max, 0.)); + VectorType ret = slope * (1 - theta_max); + this->ensure_solvability(entity, u_bar, ret); + return ret; + } + +private: + static bool is_epsilon_realizable(const VectorType& u, const RangeFieldType epsilon) + { + for (const auto& val : u) + if (val < epsilon) + return false; + return true; + } + + const RangeFieldType epsilon_; + const SlopeType slope_limiter_; +}; // class PositivityLimitedSlope<...> + + +// Realizability limiter that ensures positivity of the components of u in noncharacteristic variables. Uses single +// limiter variable for all components. +template <class GV, + class RangeFieldType, + size_t dimRange, + class EigenVectorWrapperType, + EntropyType entropy = EntropyType::MaxwellBoltzmann, + class SlopeType = MinmodSlope<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType>> +class Dg1dRealizabilityLimitedSlope + : public SlopeBase<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType, 3> + , public RealizabilityLimiterBase< + GV, + PartialMomentBasis<typename GV::ctype, 1, RangeFieldType, dimRange, 1, 1, 1, entropy>> +{ + using ThisType = Dg1dRealizabilityLimitedSlope; + using MomentBasis = Dune::GDT::PartialMomentBasis<RangeFieldType, 1, RangeFieldType, dimRange, 1, 1, 1, entropy>; + using RealizabilityBaseType = RealizabilityLimiterBase<GV, MomentBasis>; + using typename RealizabilityBaseType::E; + using typename RealizabilityBaseType::EntropyFluxType; + using BaseType = SlopeBase<E, EigenVectorWrapperType, 3>; + using typename BaseType::VectorType; + +public: + using typename BaseType::StencilType; + + // This limiter ensures u_i >= epsilon for all components u_i of u. + Dg1dRealizabilityLimitedSlope(const EntropyFluxType& entropy_flux, + const MomentBasis& basis_functions, + const RangeFieldType epsilon = 0.) + : RealizabilityBaseType(entropy_flux) + , basis_functions_(basis_functions) + , epsilon_(epsilon) + {} + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get(const E& entity, + const StencilType& stencil, + const EigenVectorWrapperType& eigenvectors, + const size_t dd) const override final + { + const VectorType slope = slope_limiter_.get(entity, stencil, eigenvectors, dd); + const VectorType& u_bar = stencil[1]; + const FieldVector<VectorType, 2> reconstructed_values{u_bar - slope * 0.5, u_bar + slope * 0.5}; + + VectorType thetas(0.); + for (size_t kk = 0; kk < reconstructed_values.size(); ++kk) { + const VectorType& u = reconstructed_values[kk]; + for (size_t ii = 0; ii < dimRange / 2; ++ii) { + const auto& u0 = u[2 * ii]; + const auto& u1 = u[2 * ii + 1]; + const auto& ubar0 = u_bar[2 * ii]; + const auto& ubar1 = u_bar[2 * ii + 1]; + const auto& vj = basis_functions_.partitioning()[ii]; + const auto& vjplus1 = basis_functions_.partitioning()[ii + 1]; + FieldVector<RangeFieldType, 3> thetas_ii; + if (!is_epsilon_realizable(ubar0, ubar1, vj, vjplus1, epsilon_)) { + thetas[2 * ii] = 1.; + } else { + thetas_ii[0] = (epsilon_ - u0) / (ubar0 - u0); + thetas_ii[1] = + (u0 * vj - u1 + epsilon_ * std::sqrt(std::pow(vj, 2) + 1)) / ((ubar1 - u1) - (ubar0 - u0) * vj); + thetas_ii[2] = (u0 * vjplus1 - u1 - epsilon_ * std::sqrt(std::pow(vjplus1, 2) + 1)) + / ((ubar1 - u1) - (ubar0 - u0) * vjplus1); + for (size_t ll = 0; ll < 3; ++ll) + if (thetas_ii[ll] >= 0. && thetas_ii[ll] <= 1.) + thetas[2 * ii] = std::max(thetas[2 * ii], thetas_ii[ll]); + } // else (!realizable) + thetas[2 * ii + 1] = thetas[2 * ii]; + } // ii + } // local_reconstructed_values + + VectorType ret; + for (size_t ii = 0; ii < dimRange; ++ii) { + assert(XT::Common::FloatCmp::le(thetas[ii], 1.) && XT::Common::FloatCmp::ge(thetas[ii], 0.)); + ret[ii] = slope[ii] * (1 - thetas[ii]); + } + this->ensure_solvability(entity, u_bar, ret); + return ret; + } + +private: + static bool is_epsilon_realizable(const RangeFieldType ubar0, + const RangeFieldType ubar1, + const RangeFieldType v0, + const RangeFieldType v1, + const RangeFieldType eps) + { + bool ret = (ubar0 >= eps) && (ubar1 <= v1 * ubar0 - eps * std::sqrt(std::pow(v1, 2) + 1)) + && (v0 * ubar0 + eps * std::sqrt(std::pow(v0, 2) + 1) <= ubar1); + return ret; + } + + const MomentBasis& basis_functions_; + const RangeFieldType epsilon_; + const SlopeType slope_limiter_; +}; // class Dg1dRealizabilityLimitedSlope<...> + + +#if HAVE_QHULL +// Realizability limiter that ensures that the limited values are within the convex hull of the quadrature points. Uses +// single limiter variable for all components. +template <class GV, + class MomentBasis, + class EigenVectorWrapperType, + class SlopeType = MinmodSlope<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType>> +class ConvexHullRealizabilityLimitedSlope + : public SlopeBase<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType, 3> + , public RealizabilityLimiterBase<GV, MomentBasis> +{ + using ThisType = ConvexHullRealizabilityLimitedSlope; + using RangeFieldType = typename MomentBasis::RangeFieldType; + static const size_t dimRange = MomentBasis::dimRange; + using RealizabilityBaseType = RealizabilityLimiterBase<GV, MomentBasis>; + using typename RealizabilityBaseType::E; + using typename RealizabilityBaseType::EntropyFluxType; + using BaseType = SlopeBase<E, EigenVectorWrapperType, 3>; + using typename BaseType::VectorType; + using PlaneCoefficientsType = typename std::vector<std::pair<VectorType, RangeFieldType>>; + +public: + using typename BaseType::StencilType; + + ConvexHullRealizabilityLimitedSlope(const EntropyFluxType& entropy_flux, + const MomentBasis& basis_functions, + const RangeFieldType epsilon = 0.) + : RealizabilityBaseType(entropy_flux) + , basis_functions_(basis_functions) + , epsilon_(epsilon) + { + calculate_plane_coefficients(); + } + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get(const E& entity, + const StencilType& stencil, + const EigenVectorWrapperType& eigenvectors, + const size_t dd) const override final + { + static const VectorType zero_vector(0.); + const VectorType& u_bar = stencil[1]; + if (!is_epsilon_realizable(u_bar, epsilon_)) + return zero_vector; + const VectorType slope = slope_limiter_.get(entity, stencil, eigenvectors, dd); + + const FieldVector<VectorType, 2> reconstructed_values{u_bar - 0.5 * slope, u_bar + 0.5 * slope}; + + RangeFieldType theta(-epsilon_); + for (size_t kk = 0; kk < reconstructed_values.size(); ++kk) { + const VectorType& u = reconstructed_values[kk]; + // rescale u_l, u_bar + auto u_bar_minus_u = u_bar - u; + const auto factor = std::max(basis_functions_.density(u), basis_functions_.density(u_bar)) / 2.; + u /= factor; + u_bar_minus_u /= factor; + + for (const auto& coeffs : plane_coefficients_) { + const auto& a = coeffs.first; + const auto& b = coeffs.second; + RangeFieldType theta_li = (b - a * u) / (a * u_bar_minus_u); + if (XT::Common::FloatCmp::le(theta_li, 1.)) + theta = std::max(theta, theta_li); + } // coeffs + } // kk + theta = std::min(epsilon_ + theta, 1.); + + assert(XT::Common::FloatCmp::le(theta, 1.) && XT::Common::FloatCmp::ge(theta, 0.)); + VectorType ret = slope * (1 - theta); + this->ensure_solvability(entity, u_bar, ret); + return ret; + } + +private: + // calculate half space representation of realizable set + void calculate_plane_coefficients() + { + using orgQhull::Qhull; + Qhull qhull; + const auto& quadrature = basis_functions_.quadratures().merged(); + std::vector<FieldVector<RangeFieldType, dimRange>> points(quadrature.size() + 1); + points[0] = FieldVector<RangeFieldType, dimRange>(0); + size_t ii = 1; + for (const auto& quad_point : quadrature) + points[ii++] = basis_functions_.evaluate(quad_point.position()); + std::cout << "Starting qhull..." << std::endl; + qhull.runQhull("Realizable set", int(dimRange), int(points.size()), &(points[0][0]), "Qt T1"); + std::cout << "qhull done" << std::endl; + // qhull.outputQhull("n"); + const auto facet_end = qhull.endFacet(); + plane_coefficients_ = std::make_shared<PlaneCoefficientsType>(qhull.facetList().count()); + ii = 0; + for (auto facet = qhull.beginFacet(); facet != facet_end; facet = facet.next(), ++ii) { + for (size_t jj = 0; jj < dimRange; ++jj) + plane_coefficients_[ii].first[jj] = *(facet.hyperplane().coordinates() + jj); + plane_coefficients_[ii].second = -facet.hyperplane().offset(); + } + } // void calculate_plane_coefficients() + + const MomentBasis& basis_functions_; + const RangeFieldType epsilon_; + const SlopeType slope_limiter_; + PlaneCoefficientsType plane_coefficients_; +}; // class ConvexHullRealizabilityLimitedSlope<...> + + +// Realizability limiter that ensures that the limited values are within the convex hull of the quadrature points. Uses +// single limiter variable for all components. +template <class GV, + class MomentBasis, + class EigenVectorWrapperType, + class SlopeType = MinmodSlope<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType>> +class DgConvexHullRealizabilityLimitedSlope + : public SlopeBase<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType, 3> + , public RealizabilityLimiterBase<GV, MomentBasis> +{ + using ThisType = DgConvexHullRealizabilityLimitedSlope; + using RangeFieldType = typename MomentBasis::RangeFieldType; + static const size_t dimRange = MomentBasis::dimRange; + static const size_t block_size = (MomentBasis::dimDomain == 1) ? 2 : 4; + static const size_t num_blocks = dimRange / block_size; + using RealizabilityBaseType = RealizabilityLimiterBase<GV, MomentBasis>; + using typename RealizabilityBaseType::E; + using typename RealizabilityBaseType::EntropyFluxType; + using BaseType = SlopeBase<E, EigenVectorWrapperType, 3>; + using typename BaseType::VectorType; + using BlockRangeType = typename VectorType::BlockType; + using BlockPlaneCoefficientsType = typename std::vector<std::pair<BlockRangeType, RangeFieldType>>; + using PlaneCoefficientsType = FieldVector<BlockPlaneCoefficientsType, num_blocks>; + +public: + using typename BaseType::StencilType; + + DgConvexHullRealizabilityLimitedSlope(const EntropyFluxType& entropy_flux, + const MomentBasis& basis_functions, + const RangeFieldType epsilon = 0.) + : RealizabilityBaseType(entropy_flux) + , basis_functions_(basis_functions) + , epsilon_(epsilon) + { + if (!basis_functions_.plane_coefficients()[0].size()) + basis_functions_.calculate_plane_coefficients(); + // replace the coefficients b by \tilde{b} = b - eps \twonorm(a) to guarantee distance of eps to boundary + plane_coefficients_ = basis_functions_.plane_coefficients(); + for (size_t jj = 0; jj < num_blocks; ++jj) + for (auto& coeff : plane_coefficients_[jj]) + coeff.second -= epsilon_ * coeff.first.two_norm(); + } + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get(const E& entity, + const StencilType& stencil, + const EigenVectorWrapperType& eigenvectors, + const size_t dd) const override final + { + const VectorType& u_bar = stencil[1]; + const VectorType slope = slope_limiter_.get(entity, stencil, eigenvectors, dd); + const FieldVector<VectorType, 2> reconstructed_values{u_bar - slope * 0.5, u_bar + slope * 0.5}; + + // vector to store thetas for each local reconstructed value + FieldVector<RangeFieldType, num_blocks> thetas(0.); + for (size_t kk = 0; kk < reconstructed_values.size(); ++kk) { + const VectorType& u = reconstructed_values[kk]; + for (size_t jj = 0; jj < num_blocks; ++jj) { + // Check realizability of u_bar in this block. The first condition avoids unnecessary repeated checking. + if (thetas[jj] == 1. || !is_epsilon_realizable(u_bar.block(jj), jj)) { + thetas[jj] = 1.; + continue; + } + thetas[jj] = std::max(thetas[jj], get_block_theta(u.block(jj), u_bar.block(jj), jj)); + } // jj + } // kk + + VectorType ret; + for (size_t jj = 0; jj < num_blocks; ++jj) { + assert(XT::Common::FloatCmp::le(thetas[jj], 1.) && XT::Common::FloatCmp::ge(thetas[jj], 0.)); + for (size_t ii = 0; ii < block_size; ++ii) + ret.block(jj)[ii] = slope.block(jj)[ii] * (1 - thetas[jj]); + } + this->ensure_solvability(entity, u_bar, ret); + return ret; + } // ... get(...) + +private: + bool is_epsilon_realizable(const BlockRangeType& u, const size_t jj) const + { + for (const auto& coeff : plane_coefficients_[jj]) + if (u * coeff.first > coeff.second) + return false; + return true; + } + + RangeFieldType get_block_theta(const BlockRangeType& u, const BlockRangeType& u_bar, const size_t jj) const + { + RangeFieldType theta(0.); + auto u_bar_minus_u = u_bar - u; + for (const auto& coeffs : plane_coefficients_[jj]) { + const auto& a = coeffs.first; + const auto& b = coeffs.second; + RangeFieldType theta_li = (b - a * u) / (a * u_bar_minus_u); + if (XT::Common::FloatCmp::le(theta_li, 1.)) + theta = std::max(theta, theta_li); + } // coeffs + return theta; + } // ... get_block_theta(...) + + const MomentBasis& basis_functions_; + const RangeFieldType epsilon_; + const SlopeType slope_limiter_; + PlaneCoefficientsType plane_coefficients_; +}; // class DgConvexHullRealizabilityLimitedSlope<...> + +#else // HAVE_QHULL + +template <class GV, + class MomentBasis, + class EigenVectorWrapperType, + class SlopeType = MinmodSlope<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType>> +class ConvexHullRealizabilityLimitedSlope +{ + static_assert(Dune::AlwaysFalse<MomentBasis>::value, "You are missing Qhull!"); +}; + +template <class GV, + class MomentBasis, + class EigenVectorWrapperType, + class SlopeType = MinmodSlope<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType>> +class DgConvexHullRealizabilityLimitedSlopeSlope +{ + static_assert(Dune::AlwaysFalse<MomentBasis>::value, "You are missing Qhull!"); +}; +#endif // HAVE_QHULL + +#if HAVE_CLP +// Characteristic component-wise realizability limiter that ensures positivity of the components of u in +// noncharacteristic variables by solving a linear program. +template <class GV, + class MomentBasis, + class EigenVectorWrapperType, + class SlopeType = MinmodSlope<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType>> +class LpPositivityLimitedSlope + : public SlopeBase<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType, 3> + , public RealizabilityLimiterBase<GV, MomentBasis> +{ + using ThisType = LpPositivityLimitedSlope; + using RangeFieldType = typename MomentBasis::RangeFieldType; + static const size_t dimRange = MomentBasis::dimRange; + using RealizabilityBaseType = RealizabilityLimiterBase<GV, MomentBasis>; + using typename RealizabilityBaseType::E; + using typename RealizabilityBaseType::EntropyFluxType; + using BaseType = SlopeBase<E, EigenVectorWrapperType, 3>; + using typename BaseType::MatrixType; + using typename BaseType::VectorType; + +public: + using typename BaseType::StencilType; + + LpPositivityLimitedSlope(const EntropyFluxType& entropy_flux, const RangeFieldType epsilon) + : RealizabilityBaseType(entropy_flux) + , epsilon_(epsilon) + {} + + LpPositivityLimitedSlope(const ThisType& other) + : BaseType(other) + , RealizabilityBaseType(other) + , epsilon_(other.epsilon_) + , A_tilde_transposed_(std::make_unique<MatrixType>(dimRange, dimRange)) + , slope_limiter_(other.slope_limiter_) + {} + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get(const E& entity, + const StencilType& stencil, + const EigenVectorWrapperType& eigenvectors, + const size_t dd) const override final + { + static const VectorType zero_vector(0.); + const VectorType& u_bar = stencil[1]; + if (!is_epsilon_realizable(u_bar, epsilon_)) + return zero_vector; + const VectorType slope_char = slope_limiter_.get_char(entity, stencil, eigenvectors, dd); + if (XT::Common::FloatCmp::eq(slope_char, zero_vector)) + return zero_vector; + FieldVector<VectorType, 2> thetas; + VectorType u_bar_char; + eigenvectors.apply_inverse_eigenvectors(dd, u_bar, u_bar_char); + const FieldVector<VectorType, 2> reconstructed_values{u_bar_char - 0.5 * slope_char, u_bar_char + 0.5 * slope_char}; + auto& A_tilde_transposed = *A_tilde_transposed_; + for (size_t kk = 0; kk < reconstructed_values.size(); ++kk) { + const VectorType& u_char = reconstructed_values[kk]; + thetas[kk] = solve_linear_program(u_char, u_bar_char, eigenvectors.eigenvectors(dd), A_tilde_transposed); + } // kk + + VectorType slope; + eigenvectors.apply_eigenvectors(dd, slope_char, slope); + for (size_t ii = 0; ii < dimRange; ++ii) { + const auto theta_max_ii = std::max(thetas[0][ii], thetas[1][ii]); + slope[ii] = slope[ii] * (1 - theta_max_ii); + } + this->ensure_solvability(entity, u_bar, slope); + return slope; + } + +private: + static bool is_epsilon_realizable(const VectorType& u, const RangeFieldType epsilon) + { + for (const auto& val : u) + if (val < epsilon) + return false; + return true; + } + + VectorType solve_linear_program(const VectorType& u_char, + const VectorType u_bar_char, + const MatrixType& A, + MatrixType& A_tilde_transposed) const + { + // calculate data + VectorType u; + A.mv(u_char, u); + VectorType u_minus_u_bar = u_char - u_bar_char; + for (size_t ii = 0; ii < dimRange; ++ii) + for (size_t jj = 0; jj < dimRange; ++jj) + A_tilde_transposed.set_entry(jj, ii, A.get_entry(ii, jj) * u_minus_u_bar[jj]); + + // Create LP with dimRange rows and columns */ + constexpr int num_rows = static_cast<int>(dimRange); + constexpr int num_cols = static_cast<int>(dimRange); + auto lp_ptr = std::make_unique<ClpSimplex>(false); + auto& lp = *lp_ptr; + + // set number of rows, columns will be added below + lp.resize(num_rows, 0); + + // Clp wants the row indices that are non-zero in each column. We have a dense matrix, so provide all indices + // 0..num_rows + std::array<int, num_rows> row_indices; + for (int ii = 0; ii < num_rows; ++ii) + row_indices[ii] = ii; + + // set columns + for (int jj = 0; jj < num_cols; ++jj) + lp.addColumn(num_rows, row_indices.data(), &(A_tilde_transposed[jj][0]), 0., 1., 1.); + + lp.setLogLevel(0); + + lp.setMaximumWallSeconds(60); + + // set rhs + for (int ii = 0; ii < num_rows; ++ii) + lp.setRowUpper(ii, u[ii] - epsilon_); + + // Now solve + VectorType ret; + lp.primal(); + const auto* thetas = lp.primalColumnSolution(); + for (size_t ii = 0; ii < dimRange; ++ii) + ret[ii] = thetas[ii]; + if (!lp.isProvenOptimal()) + std::fill(ret.begin(), ret.end(), 1.); + return ret; + } // void solve_linear_program(...) + + const RangeFieldType epsilon_; + mutable std::unique_ptr<MatrixType> A_tilde_transposed_; + const SlopeType slope_limiter_; +}; // class LpPositivityLimitedSlope<...> + +template <class GV, class MomentBasis, class EigenVectorWrapperType, class SlopeType> +constexpr size_t LpPositivityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType, SlopeType>::dimRange; + + +// Realizability limiter that solves a linear program to ensure the reconstructed values are still in the numerically +// realizable set, i.e. in the convex hull of basis evaluations. +template <class GV, + class MomentBasis, + class EigenVectorWrapperType, + class SlopeType = MinmodSlope<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType>> +class LpConvexhullRealizabilityLimitedSlope + : public SlopeBase<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType> + , public RealizabilityLimiterBase<GV, MomentBasis> +{ + using ThisType = LpConvexhullRealizabilityLimitedSlope; + using RangeFieldType = typename MomentBasis::RangeFieldType; + static constexpr size_t dimRange = MomentBasis::dimRange; + static_assert(dimRange < std::numeric_limits<int>::max(), ""); + static constexpr size_t num_rows = dimRange; + using RealizabilityBaseType = RealizabilityLimiterBase<GV, MomentBasis>; + using typename RealizabilityBaseType::E; + using typename RealizabilityBaseType::EntropyFluxType; + using BaseType = SlopeBase<E, EigenVectorWrapperType, 3>; + using typename BaseType::MatrixType; + using typename BaseType::VectorType; + +public: + using typename BaseType::StencilType; + + LpConvexhullRealizabilityLimitedSlope(const EntropyFluxType& entropy_flux, + const MomentBasis& basis_functions, + const RangeFieldType epsilon) + : RealizabilityBaseType(entropy_flux) + , epsilon_(epsilon) + , basis_functions_(basis_functions) + , basis_values_( + std::make_shared<std::vector<VectorType>>(XT::Data::merged_quadrature(basis_functions_.quadratures()).size())) + { + const auto& quadrature = XT::Data::merged_quadrature(basis_functions_.quadratures()); + for (size_t ii = 0; ii < quadrature.size(); ++ii) + (*basis_values_)[ii] = basis_functions.evaluate(quadrature[ii].position()); + } + + LpConvexhullRealizabilityLimitedSlope(const LpConvexhullRealizabilityLimitedSlope& other) + : BaseType(other) + , RealizabilityBaseType(other) + , epsilon_(other.epsilon_) + , basis_functions_(other.basis_functions_) + , basis_values_(other.basis_values_) + , lp_(nullptr) + , A_tilde_transposed_(std::make_unique<MatrixType>(dimRange, dimRange)) + , slope_limiter_(other.slope_limiter_) + {} + + BaseType* copy() const override final + { + return new ThisType(*this); + } + + virtual VectorType get(const E& entity, + const StencilType& stencil, + const EigenVectorWrapperType& eigenvectors, + const size_t dd) const override final + { + VectorType slope_char = slope_limiter_.get_char(entity, stencil, eigenvectors, dd); + static const VectorType zero_vector(0.); + if (XT::Common::FloatCmp::eq(slope_char, zero_vector)) + return zero_vector; + FieldVector<VectorType, 2> thetas; + const VectorType& u_bar = stencil[1]; + VectorType u_bar_char; + eigenvectors.apply_inverse_eigenvectors(dd, u_bar, u_bar_char); + const FieldVector<VectorType, 2> reconstructed_values_char{u_bar_char - 0.5 * slope_char, + u_bar_char + 0.5 * slope_char}; + auto& A_tilde_transposed = *A_tilde_transposed_; + for (size_t kk = 0; kk < reconstructed_values_char.size(); ++kk) + thetas[kk] = solve_linear_program( + reconstructed_values_char[kk], u_bar_char, eigenvectors.eigenvectors(dd), A_tilde_transposed); + for (size_t ii = 0; ii < dimRange; ++ii) { + auto theta_max_ii = std::max(thetas[0][ii], thetas[1][ii]); + if (theta_max_ii > 0.) + theta_max_ii = std::min(1., theta_max_ii + epsilon_); + slope_char[ii] = slope_char[ii] * (1 - theta_max_ii); + } + // Ensure positive density + // For that purpose, get slope in ordinary coordinates + VectorType slope; + eigenvectors.apply_eigenvectors(dd, slope_char, slope); + const FieldVector<VectorType, 2> reconstructed_values{u_bar - 0.5 * slope, u_bar + 0.5 * slope}; + RangeFieldType theta_pos(0); + for (size_t kk = 0; kk < reconstructed_values.size(); ++kk) { + const auto& u = reconstructed_values[kk]; + const auto density_u = basis_functions_.density(u); + const auto density_u_bar = basis_functions_.density(u_bar); + if (density_u >= density_u_bar) + continue; + else if (density_u < epsilon_) + theta_pos = std::max(theta_pos, (epsilon_ - density_u) / (density_u_bar - density_u)); + } // kk + slope *= 1 - theta_pos; + this->ensure_solvability(entity, u_bar, slope); + return slope; + } + +private: + void setup_linear_program() const + { + // We start with creating a model with dimRange rows and num_quad_points+1 columns */ + assert(basis_values_->size() + dimRange < std::numeric_limits<int>::max()); + size_t num_cols = basis_values_->size() + dimRange; /* variables are x_1, ..., x_{num_quad_points}, theta_1, + ..., theta_{dimRange} */ + lp_ = std::make_unique<ClpSimplex>(false); + auto& lp = *lp_; + // set number of rows + lp.resize(num_rows, 0); + + // set columns for quadrature points + assert(basis_values_->size() == num_cols - dimRange); + static auto row_indices = create_row_indices(); + for (size_t ii = 0; ii < num_cols - dimRange; ++ii) { + // First argument: number of elements in column + // Second/Third argument: indices/values of column entries + // Fourth/Fifth argument: lower/upper column bound, i.e. lower/upper bound for x_i. As all x_i should be + // positive, set to 0/inf, which is the default. + // Sixth argument: Prefactor in objective for x_i, this is 0 for all x_i, which is also the default; + lp.addColumn(static_cast<int>(num_rows), row_indices.data(), &((*basis_values_)[ii][0])); + } + + // add theta columns (set to random values, will be set correctly in solve_linear_program) + // The bounds for theta should be [0,1]. Also sets the prefactor in the objective to 1 for the thetas. + for (size_t ii = 0; ii < dimRange; ++ii) + lp.addColumn(static_cast<int>(num_rows), row_indices.data(), &((*basis_values_)[0][0]), 0., 1., 1.); + lp.setLogLevel(0); + } // void setup_linear_program() + + VectorType solve_linear_program(const VectorType& u_char, + const VectorType& u_bar_char, + const MatrixType& A, + MatrixType& A_tilde_transposed) const + { + // calculate data + VectorType u_minus_u_bar_char = u_char - u_bar_char; + VectorType u; + A.mv(u_char, u); + for (size_t ii = 0; ii < dimRange; ++ii) + for (size_t jj = 0; jj < dimRange; ++jj) + A_tilde_transposed.set_entry(jj, ii, A.get_entry(ii, jj) * u_minus_u_bar_char[jj]); + + // setup linear program + setup_linear_program(); + auto& lp = *lp_; + size_t num_cols = basis_values_->size() + dimRange; // see above + + // set rhs (equality constraints, so set both bounds equal) + for (size_t ii = 0; ii < num_rows; ++ii) { + lp.setRowLower(static_cast<int>(ii), u[ii]); + lp.setRowUpper(static_cast<int>(ii), u[ii]); + } + + // delete old theta columns. + FieldVector<int, dimRange> theta_columns; + for (size_t ii = 0; ii < dimRange; ++ii) + theta_columns[ii] = static_cast<int>(num_cols - dimRange + ii); + lp.deleteColumns(dimRange, &(theta_columns[0])); + + // set new theta columns + static auto row_indices = create_row_indices(); + for (size_t jj = 0; jj < dimRange; ++jj) + lp.addColumn(num_rows, row_indices.data(), &(A_tilde_transposed[jj][0]), 0., 1., 1.); + + // Now solve + lp.setMaximumWallSeconds(60); + lp.primal(); + const auto* thetas_ptr = lp.primalColumnSolution(); + VectorType thetas; + for (size_t ii = 0; ii < dimRange; ++ii) + thetas[ii] = thetas_ptr[ii]; + if (!lp.isProvenOptimal()) + std::fill(thetas.begin(), thetas.end(), 1.); + return thetas; + } + + // Clp wants the row indices that are non-zero in each column. We have a dense matrix, so provide all indices + // 0..num_rows + static std::array<int, num_rows> create_row_indices() + { + std::array<int, dimRange> ret; + for (size_t ii = 0; ii < dimRange; ++ii) + ret[ii] = static_cast<int>(ii); + return ret; + } + + const RangeFieldType epsilon_; + const MomentBasis& basis_functions_; + std::shared_ptr<std::vector<VectorType>> basis_values_; + mutable std::unique_ptr<ClpSimplex> lp_; + mutable std::unique_ptr<MatrixType> A_tilde_transposed_; + const SlopeType slope_limiter_; +}; + +template <class GV, class MomentBasis, class EigenVectorWrapperType, class SlopeType> +constexpr size_t LpConvexhullRealizabilityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType, SlopeType>::dimRange; + +#else // HAVE_CLP + +template <class GV, + class MomentBasis, + class EigenVectorWrapperType, + class SlopeType = MinmodSlope<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType>> +class LpPositivityLimitedSlope +{ + static_assert(Dune::AlwaysFalse<MomentBasis>::value, "You are missing Clp!"); +}; + +template <class GV, + class MomentBasis, + class EigenVectorWrapperType, + class SlopeType = MinmodSlope<XT::Grid::extract_entity_t<GV>, EigenVectorWrapperType>> +class LpConvexhullRealizabilityLimitedSlope +{ + static_assert(Dune::AlwaysFalse<MomentBasis>::value, "You are missing Clp!"); +}; + +#endif // HAVE_CLP + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_OPERATORS_FV_SLOPES_HH diff --git a/dune/gdt/spaces/basis/default.hh b/dune/gdt/spaces/basis/default.hh index 32ef1b0b3e13815615dc62efefd33a963260aa6f..62dedfe1d5781c896a896100272a3cd4f87ff90d 100644 --- a/dune/gdt/spaces/basis/default.hh +++ b/dune/gdt/spaces/basis/default.hh @@ -31,7 +31,7 @@ namespace GDT { template <class GV, size_t r = 1, size_t rC = 1, class R = double> class DefaultGlobalBasis : public GlobalBasisInterface<GV, r, rC, R> { - using ThisType = DefaultGlobalBasis<GV, r, rC, R>; + using ThisType = DefaultGlobalBasis; using BaseType = GlobalBasisInterface<GV, r, rC, R>; public: @@ -54,7 +54,7 @@ public: const int order) : grid_view_(grid_view) , local_finite_elements_(local_finite_elements) - , order_(order) + , fe_order_(order) , max_size_(0) {} @@ -74,7 +74,7 @@ public: { max_size_ = 0; for (const auto& gt : grid_view_.indexSet().types(0)) - max_size_ = std::max(max_size_, local_finite_elements_.get(gt, order_).size()); + max_size_ = std::max(max_size_, local_finite_elements_.get(gt, fe_order_).size()); } private: @@ -115,7 +115,7 @@ private: void post_bind(const ElementType& elemnt) override final { current_local_fe_ = XT::Common::ConstStorageProvider<LocalFiniteElementInterface<D, d, R, r, rC>>( - self_.local_finite_elements_.get(elemnt.geometry().type(), self_.order_)); + self_.local_finite_elements_.get(elemnt.geometry().type(), self_.fe_order_)); } public: @@ -206,7 +206,7 @@ private: const GridViewType& grid_view_; const FiniteElementFamilyType& local_finite_elements_; - const int order_; + const int fe_order_; size_t max_size_; }; // class DefaultGlobalBasis diff --git a/dune/gdt/spaces/basis/finite-volume.hh b/dune/gdt/spaces/basis/finite-volume.hh index 3eb09edc26108a14d4bece7037aadaeb0385ca80..ca2ab1c1d97a1a20a2c8a13c3e617a42d96d7cd8 100644 --- a/dune/gdt/spaces/basis/finite-volume.hh +++ b/dune/gdt/spaces/basis/finite-volume.hh @@ -27,7 +27,7 @@ namespace GDT { template <class GV, size_t r = 1, class R = double> class FiniteVolumeGlobalBasis : public GlobalBasisInterface<GV, r, 1, R> { - using ThisType = FiniteVolumeGlobalBasis<GV, r, R>; + using ThisType = FiniteVolumeGlobalBasis; using BaseType = GlobalBasisInterface<GV, r, 1, R>; public: @@ -247,11 +247,8 @@ private: { if (dofs.size() != r) dofs.resize(r); - for (unsigned int comp = 0; comp < r; ++comp) { - dofs[comp] = XT::Grid::element_integral<R>( - this->element(), [&](const auto& x) { return element_function(x)[comp]; }, order) - / this->element().geometry().volume(); - } + dofs = DynamicVector<R>(XT::Grid::element_integral<RangeType>(this->element(), element_function, order)); + dofs /= this->element().geometry().volume(); } // ... interpolate(...) private: diff --git a/dune/gdt/spaces/basis/raviart-thomas.hh b/dune/gdt/spaces/basis/raviart-thomas.hh index 8fd4c3269e9f4f9ee574d5a5fbb8c283b5fa2ec1..7eb71b4702a29895f4c8ad669bd199e4341270b7 100644 --- a/dune/gdt/spaces/basis/raviart-thomas.hh +++ b/dune/gdt/spaces/basis/raviart-thomas.hh @@ -37,7 +37,7 @@ namespace GDT { template <class GL, class R = double> class RaviartThomasGlobalBasis : public GlobalBasisInterface<GL, GL::dimension, 1, R> { - using ThisType = RaviartThomasGlobalBasis<GL, R>; + using ThisType = RaviartThomasGlobalBasis; using BaseType = GlobalBasisInterface<GL, GL::dimension, 1, R>; public: diff --git a/dune/gdt/spaces/h1/continuous-flattop.hh b/dune/gdt/spaces/h1/continuous-flattop.hh new file mode 100644 index 0000000000000000000000000000000000000000..cbaa5809601d34be3054586cb047e3b5bf0aa2c9 --- /dev/null +++ b/dune/gdt/spaces/h1/continuous-flattop.hh @@ -0,0 +1,178 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#ifndef DUNE_GDT_SPACES_H1_CONTINUOUS_FLATTOP_HH +#define DUNE_GDT_SPACES_H1_CONTINUOUS_FLATTOP_HH + +#include <memory> +//#include <vector> + +//#include <dune/common/typetraits.hh> + +//#include <dune/geometry/type.hh> + +#include <dune/grid/common/gridview.hh> + +//#include <dune/xt/common/exceptions.hh> +//#include <dune/xt/grid/type_traits.hh> + +#include <dune/gdt/local/finite-elements/flattop.hh> +#include <dune/gdt/spaces/basis/default.hh> +#include <dune/gdt/spaces/mapper/continuous.hh> +#include <dune/gdt/spaces/interface.hh> + +namespace Dune { +namespace GDT { + + +/** + * \sa make_local_lagrange_finite_element + */ +template <class GV, size_t r = 1, class R = double> +class ContinuousFlatTopSpace : public SpaceInterface<GV, r, 1, R> +{ + using ThisType = ContinuousFlatTopSpace; + using BaseType = SpaceInterface<GV, r, 1, R>; + +public: + using BaseType::d; + using typename BaseType::D; + using typename BaseType::GlobalBasisType; + using typename BaseType::GridViewType; + using typename BaseType::LocalFiniteElementFamilyType; + using typename BaseType::MapperType; + +private: + using MapperImplementation = ContinuousMapper<GridViewType, LocalFiniteElementFamilyType>; + using GlobalBasisImplementation = DefaultGlobalBasis<GridViewType, r, 1, R>; + +public: + ContinuousFlatTopSpace(GridViewType grd_vw, const int fe_order, const D& overlap = 0.5) + : grid_view_(grd_vw) + , fe_order_(fe_order) + , local_finite_elements_(std::make_unique<LocalFlatTopFiniteElementFamily<D, d, R, r>>(overlap)) + , mapper_(nullptr) + , basis_(nullptr) + { + this->update_after_adapt(); + } + + ContinuousFlatTopSpace(const ThisType&) = default; + ContinuousFlatTopSpace(ThisType&&) = default; + + ThisType& operator=(const ThisType&) = delete; + ThisType& operator=(ThisType&&) = delete; + + const GridViewType& grid_view() const override final + { + return grid_view_; + } + + const MapperType& mapper() const override final + { + assert(mapper_ && "This must not happen!"); + return *mapper_; + } + + const GlobalBasisType& basis() const override final + { + assert(basis_ && "This must not happen!"); + return *basis_; + } + + const LocalFiniteElementFamilyType& finite_elements() const override final + { + return *local_finite_elements_; + } + + SpaceType type() const override final + { + return SpaceType::continuous_lagrange; + } + + int min_polorder() const override final + { + return fe_order_; + } + + int max_polorder() const override final + { + return fe_order_ + 1; + } + + bool continuous(const int diff_order) const override final + { + return diff_order == 0; + } + + bool continuous_normal_components() const override final + { + return true; + } + + bool is_lagrangian() const override final + { + return true; + } + + void update_after_adapt() override final + { + // check: the mapper does not work for non-conforming intersections + if (d == 3 && grid_view_.indexSet().types(0).size() != 1) + DUNE_THROW(Exceptions::space_error, + "in ContinuousFlatTopSpace: non-conforming intersections are not (yet) " + "supported, and more than one element type in 3d leads to non-conforming intersections!"); + // create/update mapper ... + if (mapper_) + mapper_->update_after_adapt(); + else + mapper_ = std::make_unique<MapperImplementation>(grid_view_, *local_finite_elements_, fe_order_); + // ... and basis + if (basis_) + basis_->update_after_adapt(); + else + basis_ = std::make_unique<GlobalBasisImplementation>(grid_view_, *local_finite_elements_, fe_order_); + this->create_communicator(); + } // ... update_after_adapt(...) + +private: + const GridViewType grid_view_; + const int fe_order_; + std::unique_ptr<const LocalFlatTopFiniteElementFamily<D, d, R, r>> local_finite_elements_; + std::unique_ptr<MapperImplementation> mapper_; + std::unique_ptr<GlobalBasisImplementation> basis_; +}; // class ContinuousFlatTopSpace + + +/** + * \sa ContinuousFlatTopSpace + */ +template <size_t r, class GV, class R = double> +ContinuousFlatTopSpace<GV, r, R> +make_continuous_flattop_space(GV grid_view, const int order, const double& overlap = 0.5) +{ + return ContinuousFlatTopSpace<GV, r, R>(grid_view, order, overlap); +} + + +/** + * \sa ContinuousFlatTopSpace + */ +template <class GV, class R = double> +ContinuousFlatTopSpace<GV, 1, R> +make_continuous_flattop_space(GV grid_view, const int order, const double& overlap = 0.5) +{ + return ContinuousFlatTopSpace<GV, 1, R>(grid_view, order, overlap); +} + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_SPACES_H1_CONTINUOUS_FLATTOP_HH diff --git a/dune/gdt/spaces/h1/continuous-lagrange.hh b/dune/gdt/spaces/h1/continuous-lagrange.hh index 8e101a2ee241701b92f9c260e10e49654a613685..54b54488221774c4c361a854df4795ad6abfcfa5 100644 --- a/dune/gdt/spaces/h1/continuous-lagrange.hh +++ b/dune/gdt/spaces/h1/continuous-lagrange.hh @@ -61,13 +61,13 @@ public: using typename BaseType::MapperType; private: - using MapperImplementation = ContinuousMapper<GridViewType, LocalFiniteElementFamilyType, r>; + using MapperImplementation = ContinuousMapper<GridViewType, LocalFiniteElementFamilyType>; using GlobalBasisImplementation = DefaultGlobalBasis<GridViewType, r, 1, R>; public: ContinuousLagrangeSpace(GridViewType grd_vw, const int order) : grid_view_(grd_vw) - , order_(order) + , fe_order_(order) , local_finite_elements_(std::make_unique<LocalLagrangeFiniteElementFamily<D, d, R, r>>()) , mapper_(nullptr) , basis_(nullptr) @@ -75,7 +75,21 @@ public: this->update_after_adapt(); } - ContinuousLagrangeSpace(const ThisType&) = default; + ContinuousLagrangeSpace(const ThisType& other) + : grid_view_(other.grid_view_) + , fe_order_(other.fe_order_) + , local_finite_elements_(std::make_unique<LocalLagrangeFiniteElementFamily<D, d, R, r>>()) + , mapper_(nullptr) + , basis_(nullptr) + { + this->update_after_adapt(); + } + + BaseType* copy() const override final + { + return new ThisType(*this); + } + ContinuousLagrangeSpace(ThisType&&) = default; ThisType& operator=(const ThisType&) = delete; @@ -110,12 +124,12 @@ public: int min_polorder() const override final { - return order_; + return fe_order_; } int max_polorder() const override final { - return order_; + return fe_order_; } bool continuous(const int diff_order) const override final @@ -144,18 +158,20 @@ public: if (mapper_) mapper_->update_after_adapt(); else - mapper_ = std::make_unique<MapperImplementation>(grid_view_, *local_finite_elements_, order_); + mapper_ = std::make_unique<MapperImplementation>(grid_view_, *local_finite_elements_, fe_order_); // ... and basis if (basis_) basis_->update_after_adapt(); else - basis_ = std::make_unique<GlobalBasisImplementation>(grid_view_, *local_finite_elements_, order_); + basis_ = std::make_unique<GlobalBasisImplementation>(grid_view_, *local_finite_elements_, fe_order_); this->create_communicator(); } // ... update_after_adapt(...) private: const GridViewType grid_view_; - const int order_; + const int fe_order_; + int min_polorder_; + int max_polorder_; std::unique_ptr<const LocalLagrangeFiniteElementFamily<D, d, R, r>> local_finite_elements_; std::unique_ptr<MapperImplementation> mapper_; std::unique_ptr<GlobalBasisImplementation> basis_; diff --git a/dune/gdt/spaces/hdiv/raviart-thomas.hh b/dune/gdt/spaces/hdiv/raviart-thomas.hh index f780f2cb9395a9b00ada04557bcac627412e7cb5..fbdd20a47c0b4035f08081d224133fe762afc158 100644 --- a/dune/gdt/spaces/hdiv/raviart-thomas.hh +++ b/dune/gdt/spaces/hdiv/raviart-thomas.hh @@ -49,7 +49,7 @@ namespace GDT { template <class GV, class R = double> class RaviartThomasSpace : public SpaceInterface<GV, GV::dimension, 1, R> { - using ThisType = RaviartThomasSpace<GV, R>; + using ThisType = RaviartThomasSpace; using BaseType = SpaceInterface<GV, GV::dimension, 1, R>; public: @@ -80,7 +80,23 @@ public: this->update_after_adapt(); } - RaviartThomasSpace(const ThisType&) = default; + RaviartThomasSpace(const ThisType& other) + : grid_view_(other.grid_view_) + , order_(other.order_) + , local_finite_elements_(std::make_unique<const LocalRaviartThomasFiniteElementFamily<D, d, R>>()) + , element_indices_(grid_view_) + , fe_data_() + , mapper_(nullptr) + , basis_(nullptr) + { + this->update_after_adapt(); + } + + BaseType* copy() const override final + { + return new ThisType(*this); + } + RaviartThomasSpace(ThisType&&) = default; ThisType& operator=(const ThisType&) = delete; diff --git a/dune/gdt/spaces/interface.hh b/dune/gdt/spaces/interface.hh index 21d6248538254a5dc9baf65199e1caa5ec2707d8..535baed8904435e94e7c3ab3555499df1baa28f1 100644 --- a/dune/gdt/spaces/interface.hh +++ b/dune/gdt/spaces/interface.hh @@ -48,6 +48,7 @@ template <class GridView, size_t range_dim = 1, size_t range_dim_columns = 1, cl class SpaceInterface { static_assert(XT::Grid::is_view<GridView>::value, ""); + using ThisType = SpaceInterface; public: using GridViewType = GridView; @@ -73,6 +74,8 @@ public: , adapted_(false) {} + virtual ThisType* copy() const = 0; + virtual ~SpaceInterface() = default; /// \name These methods provide most functionality, they have to be implemented. diff --git a/dune/gdt/spaces/l2/discontinuous-lagrange.hh b/dune/gdt/spaces/l2/discontinuous-lagrange.hh index 793fdfe37edd5fcbd07e37347068eadd44e88d81..23c8fee7a3d376b9ba11883754a3f184255b5f84 100644 --- a/dune/gdt/spaces/l2/discontinuous-lagrange.hh +++ b/dune/gdt/spaces/l2/discontinuous-lagrange.hh @@ -59,7 +59,7 @@ namespace GDT { template <class GV, size_t r = 1, class R = double> class DiscontinuousLagrangeSpace : public SpaceInterface<GV, r, 1, R> { - using ThisType = DiscontinuousLagrangeSpace<GV, r, R>; + using ThisType = DiscontinuousLagrangeSpace; using BaseType = SpaceInterface<GV, r, 1, R>; public: @@ -75,7 +75,7 @@ private: using GlobalBasisImplementation = DefaultGlobalBasis<GridViewType, r, 1, R>; public: - DiscontinuousLagrangeSpace(GridViewType grd_vw, const int order) + DiscontinuousLagrangeSpace(GridViewType grd_vw, const int order = 1) : grid_view_(grd_vw) , order_(order) , local_finite_elements_(std::make_unique<const LocalLagrangeFiniteElementFamily<D, d, R, r>>()) @@ -85,7 +85,21 @@ public: this->update_after_adapt(); } - DiscontinuousLagrangeSpace(const ThisType&) = default; + DiscontinuousLagrangeSpace(const ThisType& other) + : grid_view_(other.grid_view_) + , order_(other.order_) + , local_finite_elements_(std::make_unique<const LocalLagrangeFiniteElementFamily<D, d, R, r>>()) + , mapper_(nullptr) + , basis_(nullptr) + { + this->update_after_adapt(); + } + + BaseType* copy() const override final + { + return new ThisType(*this); + } + DiscontinuousLagrangeSpace(ThisType&&) = default; ThisType& operator=(const ThisType&) = delete; diff --git a/dune/gdt/spaces/l2/finite-volume.hh b/dune/gdt/spaces/l2/finite-volume.hh index 226e057be7880db8dc041ba055d33c1e8353a0eb..25910b5c90b549586bcfbc97d792fbb87c751f24 100644 --- a/dune/gdt/spaces/l2/finite-volume.hh +++ b/dune/gdt/spaces/l2/finite-volume.hh @@ -38,7 +38,7 @@ class FiniteVolumeSpace template <class GV, size_t r, class R> class FiniteVolumeSpace<GV, r, 1, R> : public SpaceInterface<GV, r, 1, R> { - using ThisType = FiniteVolumeSpace<GV, r, 1, R>; + using ThisType = FiniteVolumeSpace; using BaseType = SpaceInterface<GV, r, 1, R>; public: @@ -65,7 +65,20 @@ public: this->update_after_adapt(); } - FiniteVolumeSpace(const ThisType&) = default; + FiniteVolumeSpace(const ThisType& other) + : grid_view_(other.grid_view_) + , local_finite_elements_(std::make_unique<const LocalLagrangeFiniteElementFamily<D, d, R, r>>()) + , mapper_(grid_view_) + , basis_(grid_view_) + { + this->update_after_adapt(); + } + + BaseType* copy() const override final + { + return new ThisType(*this); + } + FiniteVolumeSpace(ThisType&&) = default; ThisType& operator=(const ThisType&) = delete; diff --git a/dune/gdt/spaces/mapper/continuous.hh b/dune/gdt/spaces/mapper/continuous.hh index 9b8df2613fd112bd8c67117392671011ff794077..82135969b8155f2c33a5357b0a4aa66c332d7e2b 100644 --- a/dune/gdt/spaces/mapper/continuous.hh +++ b/dune/gdt/spaces/mapper/continuous.hh @@ -29,11 +29,11 @@ namespace Dune { namespace GDT { -template <class GV, class LocalFiniteElementFamily, size_t basis_functions_per_subentity = 1> +template <class GV, class LocalFiniteElementFamily> class ContinuousMapper : public MapperInterface<GV> { static_assert(is_local_finite_element_family<LocalFiniteElementFamily>::value, ""); - using ThisType = ContinuousMapper<GV, LocalFiniteElementFamily, basis_functions_per_subentity>; + using ThisType = ContinuousMapper; using BaseType = MapperInterface<GV>; template <int d> @@ -62,15 +62,23 @@ public: using typename BaseType::ElementType; using typename BaseType::GridViewType; - ContinuousMapper(const GridViewType& grd_vw, const LocalFiniteElementFamily& local_finite_elements, const int order) + ContinuousMapper(const GridViewType& grd_vw, + const LocalFiniteElementFamily& local_finite_elements, + const int fe_order) : grid_view_(grd_vw) , local_finite_elements_(local_finite_elements) - , order_(order) + , fe_order_(fe_order) , max_local_size_(0) , mapper_(grid_view_, [&](const auto& geometry_type, const auto /*grid_dim*/) { - return all_DoF_attached_geometry_types_.count(geometry_type) > 0; + return (all_DoF_attached_geometry_types_.count(geometry_type) > 0) ? geometry_type_to_local_size_[geometry_type] + : 0; }) { + if (d >= 2 && fe_order_ >= 3 && !XT::Grid::is_cube_alugrid<typename GV::Grid>::value + && !XT::Grid::is_yaspgrid<typename GV::Grid>::value && !XT::Grid::is_uggrid<typename GV::Grid>::value) + DUNE_THROW(Dune::NotImplemented, + "For order > 2, there are problems with the local-to-global mapping on some grids, see the comment in " + "the global_index method!"); this->update_after_adapt(); } @@ -88,12 +96,12 @@ public: const LocalFiniteElementCoefficientsInterface<D, d>& local_coefficients(const GeometryType& geometry_type) const override final { - return local_finite_elements_.get(geometry_type, order_).coefficients(); + return local_finite_elements_.get(geometry_type, fe_order_).coefficients(); } size_t size() const override final { - return basis_functions_per_subentity * mapper_.size(); + return mapper_.size(); } size_t max_local_size() const override final @@ -113,8 +121,19 @@ public: DUNE_THROW(Exceptions::mapper_error, "local_size(element) = " << coeffs.size() << "\n local_index = " << local_index); const auto& local_key = coeffs.local_key(local_index); - return basis_functions_per_subentity * mapper_.subIndex(element, local_key.subEntity(), local_key.codim()) - + local_key.index(); + // TODO: If there are several DoFs on one subEntity (which is the case e.g. for third order lagrange elements), this + // mapping only works if the DoFs are numbered consistently between the elements. For example, if there are two DoFs + // on a shared edge between to codim 0 elements, the local_key.index() has to be the same for the same DoF in both + // elements. This does not seem to be the case for the simplex grids, the same DoF might be assigned the index 0 in + // one element and index 1 in the other element. Fixing this could be done by assigning an orientation to the edge + // by looking at the (indices of the) vertices of the edge and reordering the local indices if the orientation is + // not the same in all elements sharing the subentity. +#ifndef NDEBUG + if (d >= 2 && fe_order_ >= 3) + assert(element.geometry().type() == Dune::GeometryTypes::cube(d) + && "Not implemented for this element, see comment above!"); +#endif + return mapper_.subIndex(element, local_key.subEntity(), local_key.codim()) + local_key.index(); } // ... mapToGlobal(...) using BaseType::global_indices; @@ -128,8 +147,7 @@ public: indices.resize(local_sz, 0); for (size_t ii = 0; ii < local_sz; ++ii) { const auto& local_key = coeffs.local_key(ii); - indices[ii] = basis_functions_per_subentity * mapper_.subIndex(element, local_key.subEntity(), local_key.codim()) - + local_key.index(); + indices[ii] = mapper_.subIndex(element, local_key.subEntity(), local_key.codim()) + local_key.index(); } } // ... globalIndices(...) @@ -142,24 +160,21 @@ public: // collect all entities (for all codims) which are used to attach DoFs to all_DoF_attached_geometry_types_.clear(); for (auto&& geometry_type : grid_view_.indexSet().types(0)) { - const auto& finite_element = local_finite_elements_.get(geometry_type, order_); + const auto& finite_element = local_finite_elements_.get(geometry_type, fe_order_); max_local_size_ = std::max(max_local_size_, finite_element.size()); // loop over all keys of this finite element const auto& reference_element = ReferenceElements<D, d>::general(geometry_type); const auto& coeffs = finite_element.coefficients(); + const auto& local_key_indices = coeffs.local_key_indices(); for (size_t ii = 0; ii < coeffs.size(); ++ii) { const auto& local_key = coeffs.local_key(ii); - // Currently only works if each subEntity has exactly basis_functions_per_subentity DoFs, if there is a variable - // number of DoFs per element we would need to do more complicated things in the global index mapping. - DUNE_THROW_IF(!(local_key.index() < basis_functions_per_subentity), - Exceptions::mapper_error, - "This case is not covered yet, when we have a variable number of DoFs per (sub)entity!"); // find the (sub)entity for this key const auto sub_entity = local_key.subEntity(); const auto codim = local_key.codim(); const auto& subentity_geometry_type = reference_element.type(sub_entity, codim); // and add the respective geometry type all_DoF_attached_geometry_types_.insert(subentity_geometry_type); + geometry_type_to_local_size_[subentity_geometry_type] = local_key_indices[codim][sub_entity].size(); } } DUNE_THROW_IF(all_DoF_attached_geometry_types_.size() == 0, @@ -171,9 +186,11 @@ public: private: const GridViewType& grid_view_; const LocalFiniteElementFamily& local_finite_elements_; - const int order_; + const int fe_order_; + size_t global_size_; size_t max_local_size_; std::set<GeometryType> all_DoF_attached_geometry_types_; + std::map<GeometryType, size_t> geometry_type_to_local_size_; Implementation mapper_; }; // class ContinuousMapper diff --git a/dune/gdt/spaces/mapper/discontinuous.hh b/dune/gdt/spaces/mapper/discontinuous.hh index d38e36c9f3eaedc5aaa1170d447f966352a87cb9..4b8758b8a8007fc1a35aff237fffb9ff56942b6c 100644 --- a/dune/gdt/spaces/mapper/discontinuous.hh +++ b/dune/gdt/spaces/mapper/discontinuous.hh @@ -31,7 +31,7 @@ template <class GV, class LocalFiniteElementFamily> class DiscontinuousMapper : public MapperInterface<GV> { static_assert(is_local_finite_element_family<LocalFiniteElementFamily>::value, ""); - using ThisType = DiscontinuousMapper<GV, LocalFiniteElementFamily>; + using ThisType = DiscontinuousMapper; using BaseType = MapperInterface<GV>; public: diff --git a/dune/gdt/spaces/mapper/finite-volume.hh b/dune/gdt/spaces/mapper/finite-volume.hh index af1fc28a5af3db16dabc15fc2e84dd893051e166..e6ffe681bfb5df8176ced1530999bcd0ead206cc 100644 --- a/dune/gdt/spaces/mapper/finite-volume.hh +++ b/dune/gdt/spaces/mapper/finite-volume.hh @@ -32,7 +32,7 @@ class FiniteVolumeMapper : public MapperInterface<GV> { static_assert(rC == 1, "The FiniteVolumeMapper is not yet available for rC > 1!"); - using ThisType = FiniteVolumeMapper<GV, r, rC>; + using ThisType = FiniteVolumeMapper; using BaseType = MapperInterface<GV>; public: diff --git a/dune/gdt/test/burgers/base.hh b/dune/gdt/test/burgers/base.hh index 48e0f503a6bc80c3e65ad88c59abee072956d7cb..bfff979eb6fa8551f239f041f87265a43182cc1c 100644 --- a/dune/gdt/test/burgers/base.hh +++ b/dune/gdt/test/burgers/base.hh @@ -135,7 +135,7 @@ protected: this->num_additional_refinements_for_reference_ = 2; } - virtual void compute_reference_solution() override + void compute_reference_solution() override { auto& self = *this; auto st = self.space_type_; diff --git a/dune/gdt/test/burgers/burgers__1d__explicit__dg_p1.cc b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p1.cc index 280532c5af1a6bbcd37a10c5f389d0a99479a8a8..684623d91ba853aff9e11b8cea31c5531ff676d6 100644 --- a/dune/gdt/test/burgers/burgers__1d__explicit__dg_p1.cc +++ b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p1.cc @@ -26,9 +26,12 @@ using Burgers1dExplicitDgP1Test = BurgersExplicitTest<YASP_1D_EQUIDISTANT_OFFSET TEST_F(Burgers1dExplicitDgP1Test, periodic_boundaries__numerical_engquist_osher_flux) { this->visualization_steps_ = DXTC_TEST_CONFIG_GET("setup.visualization_steps", 0); + this->num_refinements_ = DXTC_TEST_CONFIG_GET("setup.num_refinements", 2); + this->num_additional_refinements_for_reference_ = + DXTC_TEST_CONFIG_GET("setup.num_additional_refinements_for_reference", 2); this->space_type_ = "dg_p1"; this->numerical_flux_type_ = "engquist_osher"; - /*const auto actual_results =*/this->run(); - // const auto expected_results = DXTC_TEST_CONFIG_SUB("results"); - // XT::Test::check_eoc_study_for_success(expected_results, actual_results); + const auto actual_results = this->run(); + const auto expected_results = DXTC_TEST_CONFIG_SUB("results"); + XT::Test::check_eoc_study_for_success(expected_results, actual_results); } diff --git a/dune/gdt/test/burgers/burgers__1d__explicit__dg_p1.mini b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p1.mini new file mode 100644 index 0000000000000000000000000000000000000000..d0efcd0112b5664e053f6662bcdf4456cbd2f7fe --- /dev/null +++ b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p1.mini @@ -0,0 +1,14 @@ +__name = Burgers1dExplicitDgP1Test + +[Burgers1dExplicitDgP1Test.periodic_boundaries__numerical_engquist_osher_flux.setup] +visualization_steps = 0 +num_refinements = 1 +num_additional_refinements_for_reference = 1 + +[Burgers1dExplicitDgP1Test.periodic_boundaries__numerical_engquist_osher_flux.results] +target.h = [6.25e-02 3.12e-02] +norm.L_infty_L_2 = [7.47e-02 6.21e-02] +quantity.rel_mass_conserv_error = [0.00e+00 0.00e+00] +quantity.num_timesteps = [5.00e+01 9.90e+01] +quantity.CFL = [4.82e-01 5.09e-01] + diff --git a/dune/gdt/test/burgers/burgers__1d__explicit__dg_p2.cc b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p2.cc index 9d5462ba4f90db8b5f58610e7dddb042c2919549..b07a6f81dce079f27cf29526beded2122d75f543 100644 --- a/dune/gdt/test/burgers/burgers__1d__explicit__dg_p2.cc +++ b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p2.cc @@ -28,11 +28,12 @@ using Burgers1dExplicitDgP2Test = BurgersExplicitTest<YASP_1D_EQUIDISTANT_OFFSET TEST_F(Burgers1dExplicitDgP2Test, periodic_boundaries__numerical_engquist_osher_flux) { this->visualization_steps_ = DXTC_TEST_CONFIG_GET("setup.visualization_steps", 0); - this->num_refinements_ = 2; - this->num_additional_refinements_for_reference_ = 3; + this->num_refinements_ = DXTC_TEST_CONFIG_GET("setup.num_refinements", 2); + this->num_additional_refinements_for_reference_ = + DXTC_TEST_CONFIG_GET("setup.num_additional_refinements_for_reference", 2); this->space_type_ = "dg_p2"; this->numerical_flux_type_ = "engquist_osher"; - /*const auto actual_results =*/this->run(); - // const auto expected_results = DXTC_TEST_CONFIG_SUB("results"); - // XT::Test::check_eoc_study_for_success(expected_results, actual_results); + const auto actual_results = this->run(); + const auto expected_results = DXTC_TEST_CONFIG_SUB("results"); + XT::Test::check_eoc_study_for_success(expected_results, actual_results); } diff --git a/dune/gdt/test/burgers/burgers__1d__explicit__dg_p2.mini b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p2.mini new file mode 100644 index 0000000000000000000000000000000000000000..ac2477a2bb999115cf7c060a1fd9bb39f207cf90 --- /dev/null +++ b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p2.mini @@ -0,0 +1,14 @@ +__name = Burgers1dExplicitDgP2Test + +[Burgers1dExplicitDgP2Test.periodic_boundaries__numerical_engquist_osher_flux.setup] +visualization_steps = 0 +num_refinements = 1 +num_additional_refinements_for_reference = 1 + +[Burgers1dExplicitDgP2Test.periodic_boundaries__numerical_engquist_osher_flux.results] +target.h = [6.25e-02 3.12e-02] +norm.L_infty_L_2 = [7.41e-02 6.14e-02] +quantity.rel_mass_conserv_error = [0.00e+00 0.00e+00] +quantity.num_timesteps = [1.32e+02 2.57e+02] +quantity.CFL = [1.94e-01 1.98e-01] + diff --git a/dune/gdt/test/burgers/burgers__1d__explicit__dg_p3.cc b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p3.cc index 74a4b256535098957fe0b1a6aed0e785e3f70de8..3f3bfafa277b3562626da9fa2c2122b5e18779e5 100644 --- a/dune/gdt/test/burgers/burgers__1d__explicit__dg_p3.cc +++ b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p3.cc @@ -28,11 +28,12 @@ using Burgers1dExplicitDgP3Test = BurgersExplicitTest<YASP_1D_EQUIDISTANT_OFFSET TEST_F(Burgers1dExplicitDgP3Test, periodic_boundaries__numerical_engquist_osher_flux) { this->visualization_steps_ = DXTC_TEST_CONFIG_GET("setup.visualization_steps", 0); - this->num_refinements_ = 2; - this->num_additional_refinements_for_reference_ = 3; + this->num_refinements_ = DXTC_TEST_CONFIG_GET("setup.num_refinements", 2); + this->num_additional_refinements_for_reference_ = + DXTC_TEST_CONFIG_GET("setup.num_additional_refinements_for_reference", 2); this->space_type_ = "dg_p3"; this->numerical_flux_type_ = "engquist_osher"; - /*const auto actual_results =*/this->run(); - // const auto expected_results = DXTC_TEST_CONFIG_SUB("results"); - // XT::Test::check_eoc_study_for_success(expected_results, actual_results); + const auto actual_results = this->run(); + const auto expected_results = DXTC_TEST_CONFIG_SUB("results"); + XT::Test::check_eoc_study_for_success(expected_results, actual_results); } diff --git a/dune/gdt/test/burgers/burgers__1d__explicit__dg_p3.mini b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p3.mini new file mode 100644 index 0000000000000000000000000000000000000000..c1a47eee92afad51f48f519d43ab9eb811b03497 --- /dev/null +++ b/dune/gdt/test/burgers/burgers__1d__explicit__dg_p3.mini @@ -0,0 +1,14 @@ +__name = Burgers1dExplicitDgP3Test + +[Burgers1dExplicitDgP3Test.periodic_boundaries__numerical_engquist_osher_flux.setup] +visualization_steps = 0 +num_refinements = 1 +num_additional_refinements_for_reference = 1 + +[Burgers1dExplicitDgP3Test.periodic_boundaries__numerical_engquist_osher_flux.results] +target.h = [6.25e-02 3.12e-02] +norm.L_infty_L_2 = [7.72e-02 6.07e-02] +quantity.rel_mass_conserv_error = [5.61e-15 1.03e-14] +quantity.num_timesteps = [2.92e+02 6.07e+02] +quantity.CFL = [8.70e-02 8.32e-02] + diff --git a/dune/gdt/test/instationary-eocstudies/base.hh b/dune/gdt/test/instationary-eocstudies/base.hh index 61c9b450b439b6fb4b55d056dd0817d15326f6ae..e82f500f66981402d5d9864d1ac04742a4642eb8 100644 --- a/dune/gdt/test/instationary-eocstudies/base.hh +++ b/dune/gdt/test/instationary-eocstudies/base.hh @@ -102,17 +102,17 @@ public: , reference_solution_on_reference_grid_(nullptr) {} - virtual size_t num_refinements() const override + size_t num_refinements() const override { return num_refinements_; } - virtual std::vector<std::string> targets() const override + std::vector<std::string> targets() const override { return {"h"}; } - virtual std::vector<std::string> norms() const override + std::vector<std::string> norms() const override { // We currently support the following temporal norms: // L_infty @@ -123,12 +123,12 @@ public: return {"L_infty/L_2"}; } - virtual std::vector<std::pair<std::string, std::string>> estimates() const override + std::vector<std::pair<std::string, std::string>> estimates() const override { return {}; } - virtual std::vector<std::string> quantities() const override + std::vector<std::string> quantities() const override { std::vector<std::string> ret = {"time to solution (s)", "rel mass conserv error", "num timesteps"}; if (this->adaptive_timestepping()) { @@ -140,7 +140,7 @@ public: return ret; } // ... quantities(...) - virtual std::string discretization_info_title() const override + std::string discretization_info_title() const override { return " |grid| | #DoFs"; } @@ -151,7 +151,7 @@ protected: virtual std::unique_ptr<S> make_space(const GP& current_grid) = 0; public: - virtual std::string discretization_info(const size_t refinement_level) override + std::string discretization_info(const size_t refinement_level) override { if (current_refinement_ != refinement_level) { // clear the current state diff --git a/dune/gdt/test/instationary-eocstudies/hyperbolic-nonconforming.hh b/dune/gdt/test/instationary-eocstudies/hyperbolic-nonconforming.hh index c82b72dd4a92aabaabaf64923399cf27cd959c4a..2a15923d79e23e2828edb6e205f56a30ed265e6b 100644 --- a/dune/gdt/test/instationary-eocstudies/hyperbolic-nonconforming.hh +++ b/dune/gdt/test/instationary-eocstudies/hyperbolic-nonconforming.hh @@ -60,9 +60,10 @@ protected: using typename BaseType::R; using typename BaseType::S; using typename BaseType::V; + using I = XT::Grid::extract_intersection_t<GV>; using F = XT::Functions::FunctionInterface<m, d, m>; - using NF = NumericalFluxInterface<d, m>; + using NF = NumericalFluxInterface<I, d, m>; public: InstationaryNonconformingHyperbolicEocStudy( @@ -89,7 +90,7 @@ protected: virtual DF make_initial_values(const S& space) = 0; - virtual std::unique_ptr<S> make_space(const GP& current_grid) override + std::unique_ptr<S> make_space(const GP& current_grid) override { if (space_type_ == "fv") return std::make_unique<FiniteVolumeSpace<GV, m>>(XT::Grid::make_periodic_grid_layer(current_grid.leaf_view())); @@ -103,17 +104,17 @@ protected: } } // ... make_space(...) - virtual std::unique_ptr<O> make_lhs_operator(const S& space) override + std::unique_ptr<O> make_lhs_operator(const S& space) override { std::unique_ptr<NF> numerical_flux; if (numerical_flux_type_ == "upwind") - numerical_flux = std::make_unique<NumericalUpwindFlux<d, m>>(flux()); + numerical_flux = std::make_unique<NumericalUpwindFlux<I, d, m>>(flux()); else if (numerical_flux_type_ == "vijayasundaram") - numerical_flux = std::make_unique<NumericalVijayasundaramFlux<d, m>>(flux()); + numerical_flux = std::make_unique<NumericalVijayasundaramFlux<I, d, m>>(flux()); else if (numerical_flux_type_ == "lax_friedrichs") - numerical_flux = std::make_unique<NumericalLaxFriedrichsFlux<d, m>>(flux()); + numerical_flux = std::make_unique<NumericalLaxFriedrichsFlux<I, d, m>>(flux()); else if (numerical_flux_type_ == "engquist_osher") - numerical_flux = std::make_unique<NumericalEngquistOsherFlux<d, m>>(flux()); + numerical_flux = std::make_unique<NumericalEngquistOsherFlux<I, d, m>>(flux()); else { DUNE_THROW(XT::Common::Exceptions::wrong_input_given, "numerical_flux_type_ = " << numerical_flux_type_); return nullptr; diff --git a/dune/gdt/test/integrands/integrands.hh b/dune/gdt/test/integrands/integrands.hh new file mode 100644 index 0000000000000000000000000000000000000000..48f5845a49797175c139f3140c0e642d6c7802c8 --- /dev/null +++ b/dune/gdt/test/integrands/integrands.hh @@ -0,0 +1,183 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2019) + +#ifndef DUNE_GDT_TEST_INTEGRANDS_INTEGRANDS_HH +#define DUNE_GDT_TEST_INTEGRANDS_INTEGRANDS_HH + +#include <array> + +#include <dune/geometry/quadraturerules.hh> +#include <dune/geometry/type.hh> + +#include <dune/xt/common/test/gtest/gtest.h> +#include <dune/xt/common/fvector.hh> + +#include <dune/xt/grid/gridprovider.hh> +#include <dune/xt/grid/grids.hh> +#include <dune/xt/grid/type_traits.hh> + +#include <dune/xt/functions/generic/element-function.hh> +#include <dune/xt/functions/generic/function.hh> +#include <dune/xt/functions/generic/grid-function.hh> + +#include <dune/gdt/operators/matrix-based.hh> +#include <dune/gdt/spaces/h1/continuous-lagrange.hh> +#include <dune/gdt/tools/sparsity-pattern.hh> + +namespace Dune { +namespace GDT { +namespace Test { + + +template <class G> +struct IntegrandTest : public ::testing::Test +{ + static_assert(XT::Grid::is_grid<G>::value, ""); + + using GV = typename G::LeafGridView; + using D = typename GV::ctype; + static const constexpr size_t d = GV::dimension; + using E = XT::Grid::extract_entity_t<GV>; + using I = XT::Grid::extract_intersection_t<GV>; + using LocalScalarBasisType = XT::Functions::GenericElementFunctionSet<E, 1, 1>; + using DomainType = typename LocalScalarBasisType::DomainType; + using ScalarRangeType = typename LocalScalarBasisType::RangeType; + using ScalarJacobianType = typename LocalScalarBasisType::DerivativeRangeType; + using LocalVectorBasisType = XT::Functions::GenericElementFunctionSet<E, 2, 1>; + using VectorRangeType = typename LocalVectorBasisType::RangeType; + using VectorJacobianType = typename LocalVectorBasisType::DerivativeRangeType; + using MatrixType = typename XT::LA::Container<double, XT::LA::default_sparse_backend>::MatrixType; + + std::shared_ptr<XT::Grid::GridProvider<G>> grid_provider_; + std::shared_ptr<LocalScalarBasisType> scalar_ansatz_; + std::shared_ptr<LocalScalarBasisType> scalar_test_; + std::shared_ptr<LocalVectorBasisType> vector_ansatz_; + std::shared_ptr<LocalVectorBasisType> vector_test_; + static constexpr bool is_simplex_grid_ = XT::Grid::is_uggrid<G>::value || XT::Grid::is_simplex_alugrid<G>::value; + + virtual std::shared_ptr<XT::Grid::GridProvider<G>> make_grid() + { + return std::make_shared<XT::Grid::GridProvider<G>>( + XT::Grid::make_cube_grid<G>(XT::Common::from_string<FieldVector<double, d>>("[0 0 0 0]"), + XT::Common::from_string<FieldVector<double, d>>("[3 1 1 1]"), + XT::Common::from_string<std::array<unsigned int, d>>("[9 2 2 2]"))); + } + + void SetUp() override + { + grid_provider_ = make_grid(); + // {x, x^2 y} + scalar_ansatz_ = std::make_shared<LocalScalarBasisType>( + /*size = */ 2, + /*ord = */ 3, + /*evaluate = */ + [](const DomainType& x, std::vector<ScalarRangeType>& ret, const XT::Common::Parameter&) { + ret = {{x[0]}, {std::pow(x[0], 2) * x[1]}}; + }, + /*param_type = */ XT::Common::ParameterType{}, + /*jacobian = */ + [](const DomainType& x, std::vector<ScalarJacobianType>& ret, const XT::Common::Parameter&) { + // jacobians both only have a single row + ret[0][0] = {1., 0.}; + ret[1][0] = {2. * x[0] * x[1], std::pow(x[0], 2)}; + }); + // {y, x y^3} + scalar_test_ = std::make_shared<LocalScalarBasisType>( + /*size = */ 2, + /*ord = */ 4, + /*evaluate = */ + [](const DomainType& x, std::vector<ScalarRangeType>& ret, const XT::Common::Parameter&) { + ret = {{x[1]}, {x[0] * std::pow(x[1], 3)}}; + }, + /*param_type = */ XT::Common::ParameterType{}, + /*jacobian = */ + [](const DomainType& x, std::vector<ScalarJacobianType>& ret, const XT::Common::Parameter&) { + // jacobians both only have a single row + ret[0][0] = {0., 1.}; + ret[1][0] = {std::pow(x[1], 3), 3 * x[0] * std::pow(x[1], 2)}; + }); + // { (x,y)^T, (x^2, y^2)^T} + vector_ansatz_ = std::make_shared<LocalVectorBasisType>( + /*size = */ 2, + /*ord = */ 2, + /*evaluate = */ + [](const DomainType& x, std::vector<VectorRangeType>& ret, const XT::Common::Parameter&) { + ret = {{x[0], x[1]}, {std::pow(x[0], 2), std::pow(x[1], 2)}}; + }, + /*param_type = */ XT::Common::ParameterType{}, + /*jacobian = */ + [](const DomainType& x, std::vector<VectorJacobianType>& ret, const XT::Common::Parameter&) { + // jacobian of first function + ret[0][0] = {1., 0.}; + ret[0][1] = {0., 1.}; + // jacobian of second function + ret[1][0] = {2 * x[0], 0.}; + ret[1][1] = {0., 2 * x[1]}; + }); + // { (x,y)^T, (x^2, y^2)^T} + vector_test_ = std::make_shared<LocalVectorBasisType>( + /*size = */ 2, + /*ord = */ 2, + /*evaluate = */ + [](const DomainType& x, std::vector<VectorRangeType>& ret, const XT::Common::Parameter&) { + ret = {{1, 2}, {x[0] * x[1], x[0] + x[1]}}; + }, + /*param_type = */ XT::Common::ParameterType{}, + /*jacobian = */ + [](const DomainType& x, std::vector<VectorJacobianType>& ret, const XT::Common::Parameter&) { + // jacobian of first function + ret[0][0] = {0., 0.}; + ret[0][1] = {0., 0.}; + // jacobian of second function + ret[1][0] = {x[1], x[0]}; + ret[1][1] = {1., 1.}; + }); + } // ... SetUp(...) + + virtual void is_constructable() = 0; +}; // struct IntegrandTest + + +} // namespace Test +} // namespace GDT +} // namespace Dune + + +using Grids2D = ::testing::Types<YASP_2D_EQUIDISTANT_OFFSET +#if HAVE_DUNE_ALUGRID + , + ALU_2D_SIMPLEX_CONFORMING, + ALU_2D_SIMPLEX_NONCONFORMING, + ALU_2D_CUBE +#endif +#if HAVE_DUNE_UGGRID || HAVE_UG + , + UG_2D +#endif +#if HAVE_ALBERTA + , + ALBERTA_2D +#endif + >; + +DUNE_XT_COMMON_TYPENAME(YASP_2D_EQUIDISTANT_OFFSET) +#if HAVE_DUNE_ALUGRID +DUNE_XT_COMMON_TYPENAME(ALU_2D_SIMPLEX_CONFORMING) +DUNE_XT_COMMON_TYPENAME(ALU_2D_SIMPLEX_NONCONFORMING) +DUNE_XT_COMMON_TYPENAME(ALU_2D_CUBE) +#endif +#if HAVE_DUNE_UGGRID || HAVE_UG +DUNE_XT_COMMON_TYPENAME(UG_2D) +#endif +#if HAVE_ALBERTA +DUNE_XT_COMMON_TYPENAME(ALBERTA_2D) +#endif + + +#endif // DUNE_GDT_TEST_INTEGRANDS_INTEGRANDS_HH diff --git a/dune/gdt/test/integrands/integrands_div.cc b/dune/gdt/test/integrands/integrands_div.cc new file mode 100644 index 0000000000000000000000000000000000000000..f91bc2c5b4d215233179d1f0e7bd9da219e455a0 --- /dev/null +++ b/dune/gdt/test/integrands/integrands_div.cc @@ -0,0 +1,152 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2019) + +#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! + +#include <dune/gdt/local/integrands/div.hh> + +#include <dune/gdt/test/integrands/integrands.hh> + +namespace Dune { +namespace GDT { +namespace Test { + + +template <class G> +struct DivIntegrandTest : public IntegrandTest<G> +{ + using BaseType = IntegrandTest<G>; + using BaseType::d; + using typename BaseType::D; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::GV; + using typename BaseType::MatrixType; + using typename BaseType::VectorJacobianType; + using TestDivIntegrandType = LocalElementAnsatzValueTestDivProductIntegrand<E>; + using AnsatzDivIntegrandType = LocalElementAnsatzDivTestValueProductIntegrand<E>; + + virtual void is_constructable() override final + { + TestDivIntegrandType test_div_integrand1; + TestDivIntegrandType test_div_integrand2(1.); + const XT::Functions::GenericGridFunction<E, 1> scalar_grid_function( + 2, [](const E&) {}, [](const DomainType& x, const XT::Common::Parameter&) { return x[0] * x[1]; }); + TestDivIntegrandType test_div_integrand3(scalar_grid_function); + const XT::Functions::GenericFunction<d, 1> scalar_function( + 2, [](const DomainType& x, const XT::Common::Parameter&) { return x[0] * x[1]; }); + TestDivIntegrandType test_div_integrand4(scalar_function); + DUNE_UNUSED_PARAMETER(test_div_integrand1); + DUNE_UNUSED_PARAMETER(test_div_integrand2); + DUNE_UNUSED_PARAMETER(test_div_integrand3); + DUNE_UNUSED_PARAMETER(test_div_integrand4); + AnsatzDivIntegrandType ansatz_div_integrand1; + AnsatzDivIntegrandType ansatz_div_integrand2(1.); + AnsatzDivIntegrandType ansatz_div_integrand3(scalar_grid_function); + AnsatzDivIntegrandType ansatz_div_integrand4(scalar_function); + DUNE_UNUSED_PARAMETER(ansatz_div_integrand1); + DUNE_UNUSED_PARAMETER(ansatz_div_integrand2); + DUNE_UNUSED_PARAMETER(ansatz_div_integrand3); + DUNE_UNUSED_PARAMETER(ansatz_div_integrand4); + } + + virtual void evaluates_correctly() + { + const XT::Functions::GenericGridFunction<E, 1> inducing_function( + 2, [](const E&) {}, [](const DomainType& x, const XT::Common::Parameter&) { return x[0] * x[1]; }); + TestDivIntegrandType test_div_integrand(inducing_function); + AnsatzDivIntegrandType ansatz_div_integrand(inducing_function); + const auto element = *(grid_provider_->leaf_view().template begin<0>()); + test_div_integrand.bind(element); + ansatz_div_integrand.bind(element); + const auto test_div_integrand_order = test_div_integrand.order(*vector_test_, *scalar_ansatz_); + const auto ansatz_div_integrand_order = ansatz_div_integrand.order(*scalar_test_, *vector_ansatz_); + DynamicMatrix<D> test_div_result(2, 2, 0.); + DynamicMatrix<D> ansatz_div_result(2, 2, 0.); + for (const auto& quadrature_point : Dune::QuadratureRules<D, d>::rule( + element.geometry().type(), std::max(test_div_integrand_order, ansatz_div_integrand_order))) { + const auto& x = quadrature_point.position(); + test_div_integrand.evaluate(*vector_test_, *scalar_ansatz_, x, test_div_result); + ansatz_div_integrand.evaluate(*scalar_test_, *vector_ansatz_, x, ansatz_div_result); + DynamicMatrix<D> expected_result_test_div{{0, 0}, {x[0] * (x[1] + 1), std::pow(x[0], 2) * x[1] * (x[1] + 1)}}; + DynamicMatrix<D> expected_result_ansatz_div{ + {2 * x[1], 2 * (x[0] + x[1]) * x[1]}, + {2 * x[0] * std::pow(x[1], 3), 2 * (x[0] + x[1]) * x[0] * std::pow(x[1], 3)}}; + expected_result_test_div *= x[0] * x[1]; + expected_result_ansatz_div *= x[0] * x[1]; + for (size_t ii = 0; ii < 2; ++ii) { + for (size_t jj = 0; jj < 2; ++jj) { + EXPECT_DOUBLE_EQ(expected_result_test_div[ii][jj], test_div_result[ii][jj]); + EXPECT_DOUBLE_EQ(expected_result_ansatz_div[ii][jj], ansatz_div_result[ii][jj]); + } // jj + } // ii + } // quadrature points + } // ... evaluates_correctly() + + virtual void is_integrated_correctly() + { + TestDivIntegrandType test_div_integrand(1.); + AnsatzDivIntegrandType ansatz_div_integrand(1.); + const auto& grid_view = grid_provider_->leaf_view(); + const auto scalar_space = make_continuous_lagrange_space<1>(grid_view, /*polorder=*/2); + const auto vector_space = make_continuous_lagrange_space<d>(grid_view, /*polorder=*/2); + const auto m = scalar_space.mapper().size(); + const auto n = vector_space.mapper().size(); + MatrixType test_div_mat(n, m, make_element_sparsity_pattern(vector_space, scalar_space, grid_view)); + MatrixType ansatz_div_mat(m, n, make_element_sparsity_pattern(scalar_space, vector_space, grid_view)); + MatrixOperator<MatrixType, GV, 1, 1, d, 1> test_div_op(grid_view, scalar_space, vector_space, test_div_mat); + MatrixOperator<MatrixType, GV, d, 1, 1, 1> ansatz_div_op(grid_view, vector_space, scalar_space, ansatz_div_mat); + test_div_op.append(LocalElementIntegralBilinearForm<E, d, 1, double, double, 1, 1>(test_div_integrand)); + test_div_op.assemble(true); + ansatz_div_op.append(LocalElementIntegralBilinearForm<E, 1, 1, double, double, d, 1>(ansatz_div_integrand)); + ansatz_div_op.assemble(true); + EXPECT_TRUE(XT::Common::FloatCmp::eq(test_div_mat, XT::Common::transposed(ansatz_div_mat), 1e-14, 1e-14)); + const auto mat_data_ptr = XT::Common::serialize_rowwise(test_div_mat); + const auto min_entry = *std::min_element(mat_data_ptr.get(), mat_data_ptr.get() + n * m); + const auto max_entry = *std::max_element(mat_data_ptr.get(), mat_data_ptr.get() + n * m); + const auto square_sum = std::accumulate( + mat_data_ptr.get(), mat_data_ptr.get() + n * m, 0., [](const auto& a, const auto& b) { return a + b * b; }); + EXPECT_NEAR((is_simplex_grid_ ? -0.133333333333333 : -0.177777777777778), min_entry, 1e-13); + EXPECT_NEAR((is_simplex_grid_ ? 0.133333333333333 : 0.177777777777778), max_entry, 1e-13); + EXPECT_NEAR((is_simplex_grid_ ? 4.515925925925922 : 4.589465020576143), square_sum, 1e-13); + // std::cout << XT::Common::to_string(test_div_mat, 15) << std::endl; + } + + using BaseType::grid_provider_; + using BaseType::is_simplex_grid_; + using BaseType::scalar_ansatz_; + using BaseType::scalar_test_; + using BaseType::vector_ansatz_; + using BaseType::vector_test_; +}; // struct DivIntegrandTest + + +} // namespace Test +} // namespace GDT +} // namespace Dune + + +template <class G> +using DivIntegrandTest = Dune::GDT::Test::DivIntegrandTest<G>; +TYPED_TEST_CASE(DivIntegrandTest, Grids2D); + +TYPED_TEST(DivIntegrandTest, is_constructable) +{ + this->is_constructable(); +} + +TYPED_TEST(DivIntegrandTest, evaluates_correctly) +{ + this->evaluates_correctly(); +} + +TYPED_TEST(DivIntegrandTest, integrates_correctly) +{ + this->is_integrated_correctly(); +} diff --git a/dune/gdt/test/integrands/integrands_gradient_value.cc b/dune/gdt/test/integrands/integrands_gradient_value.cc new file mode 100644 index 0000000000000000000000000000000000000000..91e05dc29019aee4116250e196f03d2a24c74e69 --- /dev/null +++ b/dune/gdt/test/integrands/integrands_gradient_value.cc @@ -0,0 +1,206 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2019) + +#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! + +#include <dune/geometry/quadraturerules.hh> + +#include <dune/xt/functions/generic/function.hh> +#include <dune/xt/functions/generic/grid-function.hh> + +#include <dune/gdt/local/integrands/gradient-value.hh> + +#include <dune/gdt/test/integrands/integrands.hh> + +namespace Dune { +namespace GDT { +namespace Test { + + +template <class G> +struct GradientValueIntegrandTest : public IntegrandTest<G> +{ + using BaseType = IntegrandTest<G>; + using BaseType::d; + using typename BaseType::D; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::GV; + using typename BaseType::MatrixType; + using typename BaseType::VectorJacobianType; + using ScalarIntegrandType = LocalElementGradientValueIntegrand<E, 1>; + using ScalarIntegrandTestGradType = LocalElementGradientValueIntegrand<E, 1, 1, D, D, D, true>; + using VectorIntegrandType = LocalElementGradientValueIntegrand<E, d>; + using VectorIntegrandTestGradType = LocalElementGradientValueIntegrand<E, d, 1, D, D, D, true>; + + virtual void is_constructable() override final + { + const XT::Functions::GenericGridFunction<E, d> vector_grid_function( + 2, + [](const E&) {}, + [](const DomainType& x, const XT::Common::Parameter&) { + return FieldVector<D, d>{{x[0], x[0] * x[1]}}; + }); + const XT::Functions::GenericFunction<d, d> vector_function(2, + [](const DomainType& x, const XT::Common::Parameter&) { + return FieldVector<D, d>{{x[0], x[0] * x[1]}}; + }); + ScalarIntegrandType scalar_integrand1(vector_grid_function); + ScalarIntegrandType scalar_integrand2(vector_function); + DUNE_UNUSED_PARAMETER(scalar_integrand1); + DUNE_UNUSED_PARAMETER(scalar_integrand2); + VectorIntegrandType vector_integrand1(vector_grid_function); + VectorIntegrandType vector_integrand2(vector_function); + DUNE_UNUSED_PARAMETER(vector_integrand1); + DUNE_UNUSED_PARAMETER(vector_integrand2); + } + + virtual void evaluates_correctly_for_scalar_bases() + { + const XT::Functions::GenericGridFunction<E, d> vector_grid_function( + 2, + [](const E&) {}, + [](const DomainType& x, const XT::Common::Parameter&) { + return FieldVector<D, d>{{x[0], x[0] * x[1]}}; + }); + ScalarIntegrandType scalar_integrand(vector_grid_function); + ScalarIntegrandTestGradType scalar_integrand2(vector_grid_function); + const auto element = *(grid_provider_->leaf_view().template begin<0>()); + scalar_integrand.bind(element); + scalar_integrand2.bind(element); + const auto integrand_order = scalar_integrand.order(*scalar_test_, *scalar_ansatz_); + const auto integrand_order2 = scalar_integrand2.order(*scalar_test_, *scalar_ansatz_); + DynamicMatrix<D> result(2, 2, 0.); + DynamicMatrix<D> result2(2, 2, 0.); + for (const auto& quadrature_point : + Dune::QuadratureRules<D, d>::rule(element.geometry().type(), std::max(integrand_order, integrand_order2))) { + const auto& x = quadrature_point.position(); + scalar_integrand.evaluate(*scalar_test_, *scalar_ansatz_, x, result); + scalar_integrand2.evaluate(*scalar_test_, *scalar_ansatz_, x, result2); + DynamicMatrix<D> expected_result{ + {x[0] * x[1], (2 + x[0]) * std::pow(x[0] * x[1], 2)}, + {std::pow(x[0] * x[1], 2) * x[1], (2 * x[1] + x[0] * x[1]) * std::pow(x[0] * x[1], 3)}}; + DynamicMatrix<D> expected_result2{{std::pow(x[0], 2) * x[1], std::pow(x[0] * x[1], 2) * x[0]}, + {std::pow(x[1], 3) * (std::pow(x[0], 2) + 3 * std::pow(x[0], 3)), + std::pow(x[1], 4) * (std::pow(x[0], 3) + 3 * std::pow(x[0], 4))}}; + for (size_t ii = 0; ii < 2; ++ii) { + for (size_t jj = 0; jj < 2; ++jj) { + EXPECT_DOUBLE_EQ(expected_result[ii][jj], result[ii][jj]); + EXPECT_DOUBLE_EQ(expected_result2[ii][jj], result2[ii][jj]); + } // jj + } // ii + } // quad_points + } + + virtual void evaluates_correctly_for_vector_bases() + { + const XT::Functions::GenericGridFunction<E, d> vector_grid_function( + 2, + [](const E&) {}, + [](const DomainType& x, const XT::Common::Parameter&) { + return FieldVector<D, d>{{x[0], x[0] * x[1]}}; + }); + VectorIntegrandType integrand(vector_grid_function); + VectorIntegrandTestGradType integrand2(vector_grid_function); + const auto element = *(grid_provider_->leaf_view().template begin<0>()); + integrand.bind(element); + integrand2.bind(element); + const auto integrand_order = integrand.order(*vector_test_, *vector_ansatz_); + const auto integrand_order2 = integrand2.order(*vector_test_, *vector_ansatz_); + DynamicMatrix<D> result(2, 2, 0.); + DynamicMatrix<D> result2(2, 2, 0.); + for (const auto& quadrature_point : + Dune::QuadratureRules<D, d>::rule(element.geometry().type(), std::max(integrand_order, integrand_order2))) { + const auto& x = quadrature_point.position(); + integrand.evaluate(*vector_test_, *vector_ansatz_, x, result); + integrand2.evaluate(*vector_test_, *vector_ansatz_, x, result2); + DynamicMatrix<D> expected_result{{x[0] * (1 + 2 * x[1]), 2 * std::pow(x[0], 2) + 4 * x[0] * std::pow(x[1], 2)}, + {2 * std::pow(x[0], 2) * x[1] + x[0] * std::pow(x[1], 2), + 2 * std::pow(x[0], 3) * x[1] + 2 * x[0] * std::pow(x[1], 2) * (x[0] + x[1])}}; + DynamicMatrix<D> expected_result2{ + {0, 0}, + {x[1] * (x[0] + std::pow(x[0], 2) + std::pow(x[0], 3)) + x[0] * std::pow(x[1], 2), + x[1] * (std::pow(x[0], 3) + std::pow(x[0], 4)) + x[0] * (std::pow(x[1], 2) + std::pow(x[1], 3))}}; + for (size_t ii = 0; ii < 2; ++ii) { + for (size_t jj = 0; jj < 2; ++jj) { + EXPECT_DOUBLE_EQ(expected_result[ii][jj], result[ii][jj]); + EXPECT_DOUBLE_EQ(expected_result2[ii][jj], result2[ii][jj]); + } // jj + } // ii + } // quad_points + } + + virtual void is_integrated_correctly() + { + const XT::Functions::GenericFunction<d, d> vector_function( + 0, [](const DomainType& /*x*/, const XT::Common::Parameter&) { + return FieldVector<D, d>{{1., 1.}}; + }); + VectorIntegrandType ansatz_grad_integrand(vector_function); + VectorIntegrandTestGradType test_grad_integrand(vector_function); + const auto& grid_view = grid_provider_->leaf_view(); + const auto space = make_continuous_lagrange_space<d>(grid_view, /*polorder=*/2); + const auto n = space.mapper().size(); + MatrixType test_grad_mat(n, n, make_element_sparsity_pattern(space, space, grid_view)); + MatrixType ansatz_grad_mat(n, n, make_element_sparsity_pattern(space, space, grid_view)); + MatrixOperator<MatrixType, GV, d, 1, d, 1> test_grad_op(grid_view, space, space, test_grad_mat); + MatrixOperator<MatrixType, GV, d, 1, d, 1> ansatz_grad_op(grid_view, space, space, ansatz_grad_mat); + test_grad_op.append(LocalElementIntegralBilinearForm<E, d, 1, double, double, d, 1>{test_grad_integrand}); + test_grad_op.assemble(true); + ansatz_grad_op.append(LocalElementIntegralBilinearForm<E, d, 1, double, double, d, 1>{ansatz_grad_integrand}); + ansatz_grad_op.assemble(true); + EXPECT_TRUE(XT::Common::FloatCmp::eq(test_grad_mat, XT::Common::transposed(ansatz_grad_mat), 1e-14, 1e-14)); + const auto mat_data_ptr = XT::Common::serialize_rowwise(test_grad_mat); + const auto min_entry = *std::min_element(mat_data_ptr.get(), mat_data_ptr.get() + n * n); + const auto max_entry = *std::max_element(mat_data_ptr.get(), mat_data_ptr.get() + n * n); + const auto square_sum = std::accumulate( + mat_data_ptr.get(), mat_data_ptr.get() + n * n, 0., [](const auto& a, const auto& b) { return a + b * b; }); + EXPECT_NEAR((is_simplex_grid_ ? -0.133333333333333 : -0.177777777777778), min_entry, 1e-13); + EXPECT_NEAR((is_simplex_grid_ ? 0.133333333333333 : 0.177777777777778), max_entry, 1e-13); + EXPECT_NEAR((is_simplex_grid_ ? 5.208148148148139 : 9.178930041152277), square_sum, 1e-13); + // std::cout << XT::Common::to_string(test_grad_mat, 15) << std::endl; + } + + using BaseType::grid_provider_; + using BaseType::is_simplex_grid_; + using BaseType::scalar_ansatz_; + using BaseType::scalar_test_; + using BaseType::vector_ansatz_; + using BaseType::vector_test_; +}; // struct GradientValueIntegrandTest + + +} // namespace Test +} // namespace GDT +} // namespace Dune + + +template <class G> +using GradientValueIntegrandTest = Dune::GDT::Test::GradientValueIntegrandTest<G>; +TYPED_TEST_CASE(GradientValueIntegrandTest, Grids2D); + +TYPED_TEST(GradientValueIntegrandTest, is_constructable) +{ + this->is_constructable(); +} + +TYPED_TEST(GradientValueIntegrandTest, evaluates_correctly_for_scalar_bases) +{ + this->evaluates_correctly_for_scalar_bases(); +} + +TYPED_TEST(GradientValueIntegrandTest, evaluates_correctly_for_vector_bases) +{ + this->evaluates_correctly_for_vector_bases(); +} + +TYPED_TEST(GradientValueIntegrandTest, is_integrated_correctly) +{ + this->is_integrated_correctly(); +} diff --git a/dune/gdt/test/integrands/integrands_laplace.cc b/dune/gdt/test/integrands/integrands_laplace.cc new file mode 100644 index 0000000000000000000000000000000000000000..f1363386af5b29c05926075e7b1a7978de5ef571 --- /dev/null +++ b/dune/gdt/test/integrands/integrands_laplace.cc @@ -0,0 +1,181 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2019) + +#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! + +#include <dune/xt/common/matrix.hh> + +#include <dune/xt/la/container/eye-matrix.hh> + +#include <dune/xt/functions/generic/function.hh> +#include <dune/xt/functions/generic/grid-function.hh> + +#include <dune/gdt/local/integrands/laplace.hh> + +#include <dune/gdt/test/integrands/integrands.hh> + +namespace Dune { +namespace GDT { +namespace Test { + + +template <class G> +struct LaplaceIntegrandTest : public IntegrandTest<G> +{ + using BaseType = IntegrandTest<G>; + using BaseType::d; + using typename BaseType::D; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::GV; + using typename BaseType::MatrixType; + using typename BaseType::VectorJacobianType; + using ScalarIntegrandType = LocalLaplaceIntegrand<E, 1>; + using VectorIntegrandType = LocalLaplaceIntegrand<E, d>; + + virtual void SetUp() override + { + BaseType::SetUp(); + diffusion_tensor_ = std::make_shared<XT::Functions::GenericGridFunction<E, 2, 2>>( + 3, + [](const E&) {}, + [](const DomainType& x, const XT::Common::Parameter&) { + VectorJacobianType ret{{x[0], x[1]}, {1., 2.}}; + ret *= x[0] * x[1]; + return ret; + }); + } + + virtual void is_constructable() override final + { + ScalarIntegrandType scalar_integrand1; + ScalarIntegrandType scalar_integrand2(XT::LA::eye_matrix<FieldMatrix<D, d, d>>(d, d)); + const XT::Functions::GenericFunction<d, 2, 2> matrix_function( + 1, [](const DomainType& x, const XT::Common::Parameter&) { + return VectorJacobianType{{x[0], x[1]}, {1., 2.}}; + }); + ScalarIntegrandType scalar_integrand3(matrix_function); + ScalarIntegrandType scalar_integrand4(*diffusion_tensor_); + DUNE_UNUSED_PARAMETER(scalar_integrand1); + DUNE_UNUSED_PARAMETER(scalar_integrand2); + DUNE_UNUSED_PARAMETER(scalar_integrand3); + DUNE_UNUSED_PARAMETER(scalar_integrand4); + VectorIntegrandType vector_integrand1; + VectorIntegrandType vector_integrand2(XT::LA::eye_matrix<FieldMatrix<D, d, d>>(d, d)); + VectorIntegrandType vector_integrand3(matrix_function); + VectorIntegrandType vector_integrand4(*diffusion_tensor_); + DUNE_UNUSED_PARAMETER(vector_integrand1); + DUNE_UNUSED_PARAMETER(vector_integrand2); + DUNE_UNUSED_PARAMETER(vector_integrand3); + DUNE_UNUSED_PARAMETER(vector_integrand4); + } + + virtual void evaluates_correctly_for_scalar_bases() + { + ScalarIntegrandType scalar_integrand(*diffusion_tensor_); + const auto element = *(grid_provider_->leaf_view().template begin<0>()); + scalar_integrand.bind(element); + const auto integrand_order = scalar_integrand.order(*scalar_test_, *scalar_ansatz_); + DynamicMatrix<D> result(2, 2, 0.); + for (const auto& quadrature_point : Dune::QuadratureRules<D, d>::rule(element.geometry().type(), integrand_order)) { + const auto& x = quadrature_point.position(); + scalar_integrand.evaluate(*scalar_test_, *scalar_ansatz_, x, result); + DynamicMatrix<D> expected_result{ + {1, 2 * (x[0] * x[1] + std::pow(x[0], 2))}, + {x[0] * std::pow(x[1], 3) + 3 * x[0] * std::pow(x[1], 2), + 3 * std::pow(x[0], 2) * std::pow(x[1], 4) + + 6 * (std::pow(x[0], 2) * std::pow(x[1], 3) + std::pow(x[0], 3) * std::pow(x[1], 2))}}; + expected_result *= x[0] * x[1]; + for (size_t ii = 0; ii < 2; ++ii) + for (size_t jj = 0; jj < 2; ++jj) + EXPECT_DOUBLE_EQ(expected_result[ii][jj], result[ii][jj]); + } + } + + virtual void evaluates_correctly_for_vector_bases() + { + VectorIntegrandType integrand(*diffusion_tensor_); + const auto element = *(grid_provider_->leaf_view().template begin<0>()); + integrand.bind(element); + const auto integrand_order = integrand.order(*vector_test_, *vector_ansatz_); + DynamicMatrix<D> result(2, 2, 0.); + for (const auto& quadrature_point : Dune::QuadratureRules<D, d>::rule(element.geometry().type(), integrand_order)) { + const auto& x = quadrature_point.position(); + integrand.evaluate(*vector_test_, *vector_ansatz_, x, result); + DynamicMatrix<D> expected_result{ + {0., 0.}, + {x[0] * x[1] + x[0] + x[1] + 2, + 2 * (std::pow(x[0], 2) * x[1] + std::pow(x[1], 2) + std::pow(x[0], 2) + 2 * x[1])}}; + expected_result *= x[0] * x[1]; + for (size_t ii = 1; ii < 2; ++ii) + for (size_t jj = 0; jj < 2; ++jj) { + EXPECT_DOUBLE_EQ(expected_result[ii][jj], result[ii][jj]); + } + } + } + + virtual void is_integrated_correctly() + { + ScalarIntegrandType integrand(1.); + const auto& grid_view = grid_provider_->leaf_view(); + // std::string grid_name = XT::Common::Typename<G>::value(); + const auto space = make_continuous_lagrange_space<1>(grid_view, /*polorder=*/2); + const auto n = space.mapper().size(); + MatrixType stiffness_matrix(n, n, make_element_sparsity_pattern(space, space, grid_view)); + MatrixOperator<MatrixType, GV, 1> laplace_operator(grid_view, space, space, stiffness_matrix); + laplace_operator.append(LocalElementIntegralBilinearForm<E, 1>(integrand)); + laplace_operator.assemble(true); + const auto mat_data_ptr = XT::Common::serialize_rowwise(stiffness_matrix); + const auto min_entry = *std::min_element(mat_data_ptr.get(), mat_data_ptr.get() + n * n); + const auto max_entry = *std::max_element(mat_data_ptr.get(), mat_data_ptr.get() + n * n); + const auto square_sum = std::accumulate( + mat_data_ptr.get(), mat_data_ptr.get() + n * n, 0., [](const auto& a, const auto& b) { return a + b * b; }); + EXPECT_NEAR((is_simplex_grid_ ? -2. : -1.896296296296300), min_entry, 1e-13); + EXPECT_NEAR((is_simplex_grid_ ? 5.777777777777780 : 6.162962962962970), max_entry, 1e-13); + EXPECT_NEAR((is_simplex_grid_ ? 2481.524691358029 : 1704.099039780521), square_sum, 5e-12); + // std::cout << XT::Common::to_string(stiffness_matrix, 15) << std::endl; + } + + using BaseType::grid_provider_; + using BaseType::is_simplex_grid_; + using BaseType::scalar_ansatz_; + using BaseType::scalar_test_; + using BaseType::vector_ansatz_; + using BaseType::vector_test_; + std::shared_ptr<XT::Functions::GenericGridFunction<E, 2, 2>> diffusion_tensor_; +}; // struct LaplaceIntegrandTest + + +} // namespace Test +} // namespace GDT +} // namespace Dune + + +template <class G> +using LaplaceIntegrandTest = Dune::GDT::Test::LaplaceIntegrandTest<G>; +TYPED_TEST_CASE(LaplaceIntegrandTest, Grids2D); + +TYPED_TEST(LaplaceIntegrandTest, is_constructable) +{ + this->is_constructable(); +} +TYPED_TEST(LaplaceIntegrandTest, evaluates_correctly_for_scalar_bases) +{ + this->evaluates_correctly_for_scalar_bases(); +} + +TYPED_TEST(LaplaceIntegrandTest, evaluates_correctly_for_vector_bases) +{ + this->evaluates_correctly_for_vector_bases(); +} + +TYPED_TEST(LaplaceIntegrandTest, is_integrated_correctly) +{ + this->is_integrated_correctly(); +} diff --git a/dune/gdt/test/integrands/integrands_product.cc b/dune/gdt/test/integrands/integrands_product.cc new file mode 100644 index 0000000000000000000000000000000000000000..a848d262e648782e0534326be56af5d379cb21e9 --- /dev/null +++ b/dune/gdt/test/integrands/integrands_product.cc @@ -0,0 +1,172 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2019) + +#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! + +#include <dune/gdt/local/integrands/product.hh> + +#include <dune/gdt/test/integrands/integrands.hh> + +namespace Dune { +namespace GDT { +namespace Test { + + +template <class G> +struct ProductIntegrandTest : public IntegrandTest<G> +{ + using BaseType = IntegrandTest<G>; + using BaseType::d; + using typename BaseType::D; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::GV; + using typename BaseType::MatrixType; + using typename BaseType::VectorJacobianType; + using ScalarIntegrandType = LocalElementProductIntegrand<E, 1>; + using VectorIntegrandType = LocalElementProductIntegrand<E, d>; + + virtual void is_constructable() override final + { + ScalarIntegrandType scalar_integrand1; + ScalarIntegrandType scalar_integrand2(1.); + const XT::Functions::GenericGridFunction<E, 1> scalar_grid_function( + 2, [](const E&) {}, [](const DomainType& x, const XT::Common::Parameter&) { return x[0] * x[1]; }); + ScalarIntegrandType scalar_integrand3(scalar_grid_function); + const XT::Functions::GenericFunction<d, 1> scalar_function( + 2, [](const DomainType& x, const XT::Common::Parameter&) { return x[0] * x[1]; }); + ScalarIntegrandType scalar_integrand4(scalar_function); + DUNE_UNUSED_PARAMETER(scalar_integrand1); + DUNE_UNUSED_PARAMETER(scalar_integrand2); + DUNE_UNUSED_PARAMETER(scalar_integrand3); + DUNE_UNUSED_PARAMETER(scalar_integrand4); + VectorIntegrandType vector_integrand1; + VectorIntegrandType vector_integrand2(1.); + VectorIntegrandType vector_integrand3(scalar_grid_function); + VectorIntegrandType vector_integrand4(scalar_function); + const XT::Functions::GenericGridFunction<E, 2, 2> matrix_grid_function( + 1, + [](const E&) {}, + [](const DomainType& x, const XT::Common::Parameter&) { + return VectorJacobianType{{x[0], x[1]}, {1., 2.}}; + }); + VectorIntegrandType vector_integrand5(matrix_grid_function); + DUNE_UNUSED_PARAMETER(vector_integrand1); + DUNE_UNUSED_PARAMETER(vector_integrand2); + DUNE_UNUSED_PARAMETER(vector_integrand3); + DUNE_UNUSED_PARAMETER(vector_integrand4); + DUNE_UNUSED_PARAMETER(vector_integrand5); + } + + virtual void evaluates_correctly_for_scalar_bases() + { + const XT::Functions::GenericGridFunction<E, 1> scalar_inducing_function( + 2, [](const E&) {}, [](const DomainType& x, const XT::Common::Parameter&) { return x[0] * x[1]; }); + ScalarIntegrandType scalar_integrand(scalar_inducing_function); + const auto element = *(grid_provider_->leaf_view().template begin<0>()); + scalar_integrand.bind(element); + const auto integrand_order = scalar_integrand.order(*scalar_test_, *scalar_ansatz_); + DynamicMatrix<D> result(2, 2, 0.); + for (const auto& quadrature_point : Dune::QuadratureRules<D, d>::rule(element.geometry().type(), integrand_order)) { + const auto& x = quadrature_point.position(); + scalar_integrand.evaluate(*scalar_test_, *scalar_ansatz_, x, result); + DynamicMatrix<D> expected_result{{std::pow(x[0] * x[1], 2), std::pow(x[0] * x[1], 3)}, + {std::pow(x[0], 3) * std::pow(x[1], 4), std::pow(x[0], 4) * std::pow(x[1], 5)}}; + for (size_t ii = 0; ii < 2; ++ii) + for (size_t jj = 0; jj < 2; ++jj) + EXPECT_DOUBLE_EQ(expected_result[ii][jj], result[ii][jj]); + } + } + + virtual void evaluates_correctly_for_vector_bases() + { + const XT::Functions::GenericGridFunction<E, 2, 2> inducing_function( + 1, + [](const E&) {}, + [](const DomainType& x, const XT::Common::Parameter&) { + return VectorJacobianType{{x[0], x[1]}, {1., 2.}}; + }); + VectorIntegrandType integrand(inducing_function); + const auto element = *(grid_provider_->leaf_view().template begin<0>()); + integrand.bind(element); + const auto integrand_order = integrand.order(*vector_test_, *vector_ansatz_); + DynamicMatrix<D> result(2, 2, 0.); + for (const auto& quadrature_point : Dune::QuadratureRules<D, d>::rule(element.geometry().type(), integrand_order)) { + const auto& x = quadrature_point.position(); + integrand.evaluate(*vector_test_, *vector_ansatz_, x, result); + DynamicMatrix<D> expected_result{{std::pow(x[0], 2) + 2 * x[0] * x[1] + 5 * x[1], + std::pow(x[0], 3) + 2 * std::pow(x[0], 2) * x[1] + 5 * std::pow(x[1], 2)}, + {std::pow(x[0], 3) * x[1] + std::pow(x[0], 2) * x[1] + + 2 * x[0] * std::pow(x[1], 2) + 2 * x[0] * x[1] + 2 * std::pow(x[1], 2), + std::pow(x[0], 4) * x[1] + std::pow(x[0], 3) * x[1] + + std::pow(x[0], 2) * std::pow(x[1], 2) + x[0] * std::pow(x[1], 3) + + +2 * x[0] * std::pow(x[1], 2) + 2 * std::pow(x[1], 3)}}; + for (size_t ii = 0; ii < 2; ++ii) + for (size_t jj = 0; jj < 2; ++jj) + EXPECT_DOUBLE_EQ(expected_result[ii][jj], result[ii][jj]); + } + } + + virtual void is_integrated_correctly() + { + ScalarIntegrandType integrand(1.); + const auto& grid_view = grid_provider_->leaf_view(); + const auto space = make_continuous_lagrange_space<1>(grid_view, /*polorder=*/2); + const auto n = space.mapper().size(); + MatrixType mass_matrix(n, n, make_element_sparsity_pattern(space, space, grid_view)); + MatrixOperator<MatrixType, GV, 1> product_operator(grid_view, space, space, mass_matrix); + product_operator.append(LocalElementIntegralBilinearForm<E, 1>(integrand)); + product_operator.assemble(true); + const auto mat_data_ptr = XT::Common::serialize_rowwise(mass_matrix); + const auto min_entry = *std::min_element(mat_data_ptr.get(), mat_data_ptr.get() + n * n); + const auto max_entry = *std::max_element(mat_data_ptr.get(), mat_data_ptr.get() + n * n); + const auto square_sum = std::accumulate( + mat_data_ptr.get(), mat_data_ptr.get() + n * n, 0., [](const auto& a, const auto& b) { return a + b * b; }); + EXPECT_NEAR((is_simplex_grid_ ? -0.001851851851852 : -0.002962962962963), min_entry, 1e-13); + EXPECT_NEAR((is_simplex_grid_ ? 0.029629629629630 : 0.047407407407407), max_entry, 1e-13); + EXPECT_NEAR((is_simplex_grid_ ? 0.058804012345679 : 0.066475994513031), square_sum, 1e-13); + // std::cout << XT::Common::to_string(mass_matrix, 15) << std::endl; + } + + using BaseType::grid_provider_; + using BaseType::is_simplex_grid_; + using BaseType::scalar_ansatz_; + using BaseType::scalar_test_; + using BaseType::vector_ansatz_; + using BaseType::vector_test_; +}; // struct ProductIntegrandTest + + +} // namespace Test +} // namespace GDT +} // namespace Dune + + +template <class G> +using ProductIntegrandTest = Dune::GDT::Test::ProductIntegrandTest<G>; +TYPED_TEST_CASE(ProductIntegrandTest, Grids2D); + +TYPED_TEST(ProductIntegrandTest, is_constructable) +{ + this->is_constructable(); +} +TYPED_TEST(ProductIntegrandTest, evaluates_correctly_for_scalar_bases) +{ + this->evaluates_correctly_for_scalar_bases(); +} + +TYPED_TEST(ProductIntegrandTest, evaluates_correctly_for_vector_bases) +{ + this->evaluates_correctly_for_vector_bases(); +} + +TYPED_TEST(ProductIntegrandTest, is_integrated_correctly) +{ + this->is_integrated_correctly(); +} diff --git a/dune/gdt/test/integrands/integrands_symmetric_elliptic.cc b/dune/gdt/test/integrands/integrands_symmetric_elliptic.cc new file mode 100644 index 0000000000000000000000000000000000000000..62db03b333dbefb701f835fef013f5a02df22617 --- /dev/null +++ b/dune/gdt/test/integrands/integrands_symmetric_elliptic.cc @@ -0,0 +1,120 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2019) + +#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! + +#include <dune/gdt/local/integrands/symmetrized-laplace.hh> + +#include <dune/gdt/test/integrands/integrands.hh> + +namespace Dune { +namespace GDT { +namespace Test { + + +template <class G> +struct SymmetrizedLaplaceIntegrandTest : public IntegrandTest<G> +{ + using BaseType = IntegrandTest<G>; + using BaseType::d; + using typename BaseType::D; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::GV; + using typename BaseType::LocalVectorBasisType; + using typename BaseType::VectorJacobianType; + using typename BaseType::VectorRangeType; + using VectorIntegrandType = LocalSymmetrizedLaplaceIntegrand<E>; + + virtual void SetUp() override + { + BaseType::SetUp(); + diffusion_factor_ = std::make_shared<XT::Functions::GenericGridFunction<E, 1>>( + 2, [](const E&) {}, [](const DomainType& x, const XT::Common::Parameter&) { return x[0] * x[1]; }); + // { (x,x+y)^T, (x^2, x^2 + y^2)^T} + vector_ansatz_ = std::make_shared<LocalVectorBasisType>( + /*size = */ 2, + /*ord = */ 2, + /*evaluate = */ + [](const DomainType& x, std::vector<VectorRangeType>& ret, const XT::Common::Parameter&) { + ret = {{x[0], x[0] + x[1]}, {std::pow(x[0], 2), std::pow(x[0], 2) + std::pow(x[1], 2)}}; + }, + /*param_type = */ XT::Common::ParameterType{}, + /*jacobian = */ + [](const DomainType& x, std::vector<VectorJacobianType>& ret, const XT::Common::Parameter&) { + // jacobian of first function + ret[0][0] = {1., 0.}; + ret[0][1] = {1., 1.}; + // jacobian of second function + ret[1][0] = {2 * x[0], 0.}; + ret[1][1] = {2 * x[0], 2 * x[1]}; + }); + } + + virtual void is_constructable() override final + { + VectorIntegrandType vector_integrand1; + VectorIntegrandType vector_integrand2(1.); + const XT::Functions::GenericFunction<d, 1> scalar_function( + 2, [](const DomainType& x, const XT::Common::Parameter&) { return x[0] * x[1]; }); + VectorIntegrandType vector_integrand3(scalar_function); + VectorIntegrandType vector_integrand4(*diffusion_factor_); + DUNE_UNUSED_PARAMETER(vector_integrand1); + DUNE_UNUSED_PARAMETER(vector_integrand2); + DUNE_UNUSED_PARAMETER(vector_integrand3); + DUNE_UNUSED_PARAMETER(vector_integrand4); + } + + virtual void evaluates_correctly() + { + VectorIntegrandType integrand(*diffusion_factor_); + const auto element = *(grid_provider_->leaf_view().template begin<0>()); + integrand.bind(element); + const auto integrand_order = integrand.order(*vector_test_, *vector_ansatz_); + DynamicMatrix<D> result(2, 2, 0.); + for (const auto& quadrature_point : Dune::QuadratureRules<D, d>::rule(element.geometry().type(), integrand_order)) { + const auto& x = quadrature_point.position(); + integrand.evaluate(*vector_test_, *vector_ansatz_, x, result); + DynamicMatrix<D> expected_result{ + {0., 0.}, {x[1] + 0.5 * x[0] + 1.5, 2 * x[0] * x[1] + std::pow(x[0], 2) + x[0] + 2 * x[1]}}; + expected_result *= x[0] * x[1]; + for (size_t ii = 1; ii < 2; ++ii) + for (size_t jj = 0; jj < 2; ++jj) { + EXPECT_DOUBLE_EQ(expected_result[ii][jj], result[ii][jj]); + } + } + } + + using BaseType::grid_provider_; + using BaseType::scalar_ansatz_; + using BaseType::scalar_test_; + using BaseType::vector_ansatz_; + using BaseType::vector_test_; + std::shared_ptr<XT::Functions::GenericGridFunction<E, 1>> diffusion_factor_; +}; // struct SymmetrizedLaplaceIntegrandTest + + +} // namespace Test +} // namespace GDT +} // namespace Dune + + +template <class G> +using SymmetrizedLaplaceIntegrandTest = Dune::GDT::Test::SymmetrizedLaplaceIntegrandTest<G>; +TYPED_TEST_CASE(SymmetrizedLaplaceIntegrandTest, Grids2D); + +TYPED_TEST(SymmetrizedLaplaceIntegrandTest, is_constructable) +{ + this->is_constructable(); +} + +TYPED_TEST(SymmetrizedLaplaceIntegrandTest, evaluates_correctly) +{ + this->evaluates_correctly(); +} diff --git a/dune/gdt/test/interpolations/default.hh b/dune/gdt/test/interpolations/default.hh new file mode 100644 index 0000000000000000000000000000000000000000..66fe62faa9d85833d7de6f04482d42d031c32768 --- /dev/null +++ b/dune/gdt/test/interpolations/default.hh @@ -0,0 +1,122 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#ifndef DUNE_GDT_TEST_INTERPOLATIONS_DEFAULT_HH +#define DUNE_GDT_TEST_INTERPOLATIONS_DEFAULT_HH + +#include <dune/xt/common/fvector.hh> +#include <dune/xt/common/fmatrix.hh> +#include <dune/xt/common/string.hh> +#include <dune/xt/common/test/gtest/gtest.h> +#include <dune/xt/common/test/common.hh> +#include <dune/xt/grid/boundaryinfo/normalbased.hh> +#include <dune/xt/grid/gridprovider/cube.hh> +#include <dune/xt/grid/structuredgridfactory.hh> +#include <dune/xt/grid/type_traits.hh> +#include <dune/xt/functions/constant.hh> +#include <dune/xt/functions/generic/function.hh> + +#include <dune/gdt/discretefunction/default.hh> +#include <dune/gdt/interpolations/boundary.hh> +#include <dune/gdt/local/bilinear-forms/integrals.hh> +#include <dune/gdt/local/integrands/product.hh> +#include <dune/gdt/norms.hh> +#include <dune/gdt/spaces/h1/continuous-lagrange.hh> + +namespace Dune { +namespace GDT { +namespace Test { + + +template <class G> +struct DefaultInterpolationOnLeafViewTest : public ::testing::Test +{ + static_assert(XT::Grid::is_grid<G>::value, ""); + + using GV = typename G::LeafGridView; + using D = typename GV::ctype; + static const constexpr size_t d = GV::dimension; + using E = XT::Grid::extract_entity_t<GV>; + using I = XT::Grid::extract_intersection_t<GV>; + using M = XT::LA::IstlRowMajorSparseMatrix<double>; + using V = XT::LA::IstlDenseVector<double>; + + std::shared_ptr<XT::Grid::GridProvider<G>> grid_provider; + std::shared_ptr<XT::Functions::GenericFunction<d>> source; + std::shared_ptr<ContinuousLagrangeSpace<GV>> space; + std::shared_ptr<DiscreteFunction<V, GV>> range; + + virtual std::shared_ptr<XT::Grid::GridProvider<G>> make_grid() + { + return std::make_shared<XT::Grid::GridProvider<G>>( + XT::Grid::make_cube_grid<G>(XT::Common::from_string<FieldVector<double, d>>("[-1 0 0 0]"), + XT::Common::from_string<FieldVector<double, d>>("[1 1 1 1]"), + XT::Common::from_string<std::array<unsigned int, d>>("[5 5 5 2]"))); + } + + void SetUp() override + { + grid_provider = make_grid(); + space = + std::make_shared<ContinuousLagrangeSpace<GV>>(make_continuous_lagrange_space(grid_provider->leaf_view(), 2)); + source = std::make_shared<XT::Functions::GenericFunction<d>>( + [](const auto&) { return 2; }, + [](const auto& x, const auto&) { + const auto x_dependent = 2 * std::pow(x[0], 2) - x[0] + 3; + const auto xy_dependent = x_dependent + x[0] * x[1] + 0.5 * x[1] - std::pow(x[1], 2); + const auto xyz_dependent = xy_dependent + 0.5 * std::pow(x[2], 2) + x[2] * x[0] - 3 * x[2] * x[1]; + if (d == 1) + return x_dependent; + else if (d == 2) + return xy_dependent; + else + return xyz_dependent; + }, + "second order polynomial", + XT::Common::ParameterType{}, + [](const auto& x, const auto&) { + const std::vector<double> x_dependent_jacobian{4 * x[0] - 1, 0, 0, 0}; + const std::vector<double> y_dependent_jacobian{x[1], x[0] + 0.5 - 2 * x[1], 0, 0}; + const std::vector<double> z_dependent_jacobian{x[2], -3 * x[2], x[2] + x[0] - 3 * x[1], 0}; + XT::Common::FieldMatrix<double, 1, d> jacobian; + for (size_t ii = 0; ii < d; ++ii) { + jacobian[0][ii] = x_dependent_jacobian[ii]; + if (d >= 2) + jacobian[0][ii] += y_dependent_jacobian[ii]; + if (d >= 3) + jacobian[0][ii] += z_dependent_jacobian[ii]; + } + return jacobian; + }); + range = std::make_shared<DiscreteFunction<V, GV>>(*space); + } // ... SetUp(...) + + void interpolates_correctly(const double expected_l2_error = 1e-14) + { + default_interpolation(*source, *range, space->grid_view()); + const auto l2_error = l2_norm(space->grid_view(), source->template as_grid_function<E>() - *range); + EXPECT_LT(l2_error, expected_l2_error) + << "XT::Common::Test::get_unique_test_name() = '" << XT::Common::Test::get_unique_test_name() << "'"; + const auto local_range = range->local_discrete_function(); + for (auto&& element : Dune::elements(space->grid_view())) { + local_range->bind(element); + const auto center = element.geometry().center(); + const auto range_jacobian = local_range->jacobian(element.geometry().local(center)); + const auto expected_jacobian = source->jacobian(center); + EXPECT_LT((range_jacobian - expected_jacobian)[0].two_norm(), expected_l2_error); + } + } // ... interpolates_correctly(...) +}; // struct DefaultInterpolationOnLeafViewTest + + +} // namespace Test +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_TEST_INTERPOLATIONS_DEFAULT_HH diff --git a/dune/gdt/test/interpolations/interpolations_default__cubic_2d_grids.cc b/dune/gdt/test/interpolations/interpolations_default__cubic_2d_grids.cc new file mode 100644 index 0000000000000000000000000000000000000000..b2578937ed784aeaf8586bd3c772d5172cdc2c5e --- /dev/null +++ b/dune/gdt/test/interpolations/interpolations_default__cubic_2d_grids.cc @@ -0,0 +1,35 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! + +#include <dune/xt/grid/grids.hh> + +#include "default.hh" + + +using Cubic2dGrids = ::testing::Types<YASP_2D_EQUIDISTANT_OFFSET +#if HAVE_DUNE_ALUGRID + , + ALU_2D_CUBE +#endif +#if HAVE_DUNE_UGGRID + , + UG_2D +#endif + >; + + +template <class G> +using InterpolationTest = Dune::GDT::Test::DefaultInterpolationOnLeafViewTest<G>; +TYPED_TEST_CASE(InterpolationTest, Cubic2dGrids); +TYPED_TEST(InterpolationTest, interpolates_correctly) +{ + this->interpolates_correctly(4e-14); +} diff --git a/dune/gdt/test/interpolations/interpolations_default__cubic_3d_grids.cc b/dune/gdt/test/interpolations/interpolations_default__cubic_3d_grids.cc new file mode 100644 index 0000000000000000000000000000000000000000..2d9dee9a032bde6445fe2d471e76272947fe60e3 --- /dev/null +++ b/dune/gdt/test/interpolations/interpolations_default__cubic_3d_grids.cc @@ -0,0 +1,35 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! + +#include <dune/xt/grid/grids.hh> + +#include "default.hh" + + +using Cubic3dGrids = ::testing::Types<YASP_3D_EQUIDISTANT_OFFSET +#if HAVE_DUNE_ALUGRID + , + ALU_3D_CUBE +#endif +#if HAVE_DUNE_UGGRID + , + UG_3D +#endif + >; + + +template <class G> +using InterpolationTest = Dune::GDT::Test::DefaultInterpolationOnLeafViewTest<G>; +TYPED_TEST_CASE(InterpolationTest, Cubic3dGrids); +TYPED_TEST(InterpolationTest, interpolates_correctly) +{ + this->interpolates_correctly(2e-13); +} diff --git a/dune/gdt/test/stokes/stokes-testcase1.cc b/dune/gdt/test/interpolations/interpolations_default__cubic_4d_grids.cc similarity index 50% rename from dune/gdt/test/stokes/stokes-testcase1.cc rename to dune/gdt/test/interpolations/interpolations_default__cubic_4d_grids.cc index 0124c1af018b57a54d8b801e488014479a163454..832fde0632bd52eff4abc72e33a63d5a95232042 100644 --- a/dune/gdt/test/stokes/stokes-testcase1.cc +++ b/dune/gdt/test/interpolations/interpolations_default__cubic_4d_grids.cc @@ -5,30 +5,22 @@ // or GPL-2.0+ (http://opensource.org/licenses/gpl-license) // with "runtime exception" (http://www.dune-project.org/license.html) // Authors: -// Tobias Leibner (2019) - -#define DUNE_XT_COMMON_TEST_MAIN_ENABLE_TIMED_LOGGING 1 -#define DUNE_XT_COMMON_TEST_MAIN_ENABLE_INFO_LOGGING 1 - -#define DUNE_XT_COMMON_TEST_MAIN_CATCH_EXCEPTIONS 1 +// Felix Schindler (2019) #include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! #include <dune/xt/grid/grids.hh> -#include <dune/gdt/test/stokes/stokes-taylorhood.hh> +#include "default.hh" -#if HAVE_DUNE_ISTL -using namespace Dune; -using namespace Dune::GDT::Test; +using Cubic4dGrids = ::testing::Types<YASP_4D_EQUIDISTANT_OFFSET>; -using StokesTest = StokesTestcase1<YASP_2D_EQUIDISTANT_OFFSET>; -// using StokesTest = StokesTestcase1<ALU_2D_SIMPLEX_CONFORMING>; -// using StokesTest = StokesTestcase1<UG_2D>; -TEST_F(StokesTest, run) + +template <class G> +using InterpolationTest = Dune::GDT::Test::DefaultInterpolationOnLeafViewTest<G>; +TYPED_TEST_CASE(InterpolationTest, Cubic4dGrids); +TYPED_TEST(InterpolationTest, interpolates_correctly) { - this->run(); + this->interpolates_correctly(6e-13); } - -#endif // HAVE_DUNE_ISTL diff --git a/dune/gdt/test/interpolations/interpolations_default__simplicial_1d_grids.cc b/dune/gdt/test/interpolations/interpolations_default__simplicial_1d_grids.cc new file mode 100644 index 0000000000000000000000000000000000000000..78c2e9ba041e1ee3451fdc520eef6c903a7dcc0a --- /dev/null +++ b/dune/gdt/test/interpolations/interpolations_default__simplicial_1d_grids.cc @@ -0,0 +1,26 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! + +#include <dune/xt/grid/grids.hh> + +#include "default.hh" + + +using Simplicial1dGrids = ::testing::Types<ONED_1D, YASP_1D_EQUIDISTANT_OFFSET>; + + +template <class G> +using InterpolationTest = Dune::GDT::Test::DefaultInterpolationOnLeafViewTest<G>; +TYPED_TEST_CASE(InterpolationTest, Simplicial1dGrids); +TYPED_TEST(InterpolationTest, interpolates_correctly) +{ + this->interpolates_correctly(); +} diff --git a/dune/gdt/test/interpolations/interpolations_default__simplicial_2d_grids.cc b/dune/gdt/test/interpolations/interpolations_default__simplicial_2d_grids.cc new file mode 100644 index 0000000000000000000000000000000000000000..f292951c7ed7e35470fe3ee25d6858d2b00d43c8 --- /dev/null +++ b/dune/gdt/test/interpolations/interpolations_default__simplicial_2d_grids.cc @@ -0,0 +1,37 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! + +#include <dune/xt/grid/grids.hh> + +#include "default.hh" + + +using Simplicial2dGrids = ::testing::Types< +#if HAVE_DUNE_ALUGRID + ALU_2D_SIMPLEX_CONFORMING, + ALU_2D_SIMPLEX_NONCONFORMING +#endif +#if HAVE_DUNE_ALUGRID && HAVE_DUNE_UGGRID + , +#endif +#if HAVE_DUNE_UGGRID + UG_2D +#endif + >; + + +template <class G> +using InterpolationTest = Dune::GDT::Test::DefaultInterpolationOnLeafViewTest<G>; +TYPED_TEST_CASE(InterpolationTest, Simplicial2dGrids); +TYPED_TEST(InterpolationTest, interpolates_correctly) +{ + this->interpolates_correctly(); +} diff --git a/dune/gdt/test/interpolations/interpolations_default__simplicial_3d_grids.cc b/dune/gdt/test/interpolations/interpolations_default__simplicial_3d_grids.cc new file mode 100644 index 0000000000000000000000000000000000000000..e632f3f44bcf6edf69186a76c141fd6cfb8006ce --- /dev/null +++ b/dune/gdt/test/interpolations/interpolations_default__simplicial_3d_grids.cc @@ -0,0 +1,37 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! + +#include <dune/xt/grid/grids.hh> + +#include "default.hh" + + +using Simplicial3dGrids = ::testing::Types< +#if HAVE_DUNE_ALUGRID + ALU_3D_SIMPLEX_CONFORMING, + ALU_3D_SIMPLEX_NONCONFORMING +#endif +#if HAVE_DUNE_ALUGRID && HAVE_DUNE_UGGRID + , +#endif +#if HAVE_DUNE_UGGRID + UG_3D +#endif + >; + + +template <class G> +using InterpolationTest = Dune::GDT::Test::DefaultInterpolationOnLeafViewTest<G>; +TYPED_TEST_CASE(InterpolationTest, Simplicial3dGrids); +TYPED_TEST(InterpolationTest, interpolates_correctly) +{ + this->interpolates_correctly(3e-14); +} diff --git a/dune/gdt/test/inviscid-compressible-flow/base.hh b/dune/gdt/test/inviscid-compressible-flow/base.hh index e2d62700d27beeb31c8bae73ae692ba7bab99f44..2f8a45915044ede32c06c74c8687d1266d0379c2 100644 --- a/dune/gdt/test/inviscid-compressible-flow/base.hh +++ b/dune/gdt/test/inviscid-compressible-flow/base.hh @@ -96,6 +96,7 @@ protected: using typename BaseType::F; using typename BaseType::GP; using typename BaseType::GV; + using typename BaseType::I; using typename BaseType::M; using typename BaseType::O; using typename BaseType::R; @@ -153,9 +154,9 @@ protected: { auto& self = *this; const auto& euler_tools = this->access().euler_tools; - const NumericalVijayasundaramFlux<d, m> numerical_flux( + const NumericalVijayasundaramFlux<I, d, m> numerical_flux( self.flux(), - /*flux_eigen_decomposition=*/[&](const auto& /*f*/, const auto& w, const auto& n, const auto& + /*flux_eigen_decomposition=*/[&](const auto& /*local_f*/, const auto& w, const auto& n, const auto& /*param*/) { return std::make_tuple(euler_tools.eigenvalues_flux_jacobian(w, n), euler_tools.eigenvectors_flux_jacobian(w, n), diff --git a/python/dune/gdt/operators/elliptic/istl.cc b/dune/gdt/test/momentmodels/basisfunctions.hh similarity index 53% rename from python/dune/gdt/operators/elliptic/istl.cc rename to dune/gdt/test/momentmodels/basisfunctions.hh index 46fa5046cd590d34775190a53807d30ab82fea8a..bdb8e4cb1d1bf7137ea67b20b6922000f2c0ce04 100644 --- a/python/dune/gdt/operators/elliptic/istl.cc +++ b/dune/gdt/test/momentmodels/basisfunctions.hh @@ -5,17 +5,15 @@ // or GPL-2.0+ (http://opensource.org/licenses/gpl-license) // with "runtime exception" (http://www.dune-project.org/license.html) // Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) +// Rene Milk (2018) +// Tobias Leibner (2017) -#include "config.h" +#ifndef DUNE_GDT_MOMENTMODELS_BASISFUNCTIONS_HH +#define DUNE_GDT_MOMENTMODELS_BASISFUNCTIONS_HH -#if HAVE_DUNE_PYBINDXI +#include "basisfunctions/legendre.hh" +#include "basisfunctions/hatfunctions.hh" +#include "basisfunctions/partial_moments.hh" +#include "basisfunctions/spherical_harmonics.hh" -# include <python/dune/gdt/operators/elliptic/bindings.hh> - - -DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_ISTL(template); - - -#endif // HAVE_DUNE_PYBINDXI +#endif // DUNE_GDT_MOMENTMODELS_BASISFUNCTIONS_HH diff --git a/dune/gdt/test/momentmodels/basisfunctions/hatfunctions.hh b/dune/gdt/test/momentmodels/basisfunctions/hatfunctions.hh new file mode 100644 index 0000000000000000000000000000000000000000..c5929c639cfb08838616a6516f62b6eeeb35f104 --- /dev/null +++ b/dune/gdt/test/momentmodels/basisfunctions/hatfunctions.hh @@ -0,0 +1,752 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_HATFUNCTIONS_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_HATFUNCTIONS_HH + +#include <vector> +#include <string> + +#include <dune/xt/common/fmatrix.hh> + +#include <dune/gdt/test/momentmodels/triangulation.hh> + +#include "interface.hh" + +namespace Dune { +namespace GDT { + + +template <class DomainFieldType, + size_t dimDomain, + class RangeFieldType, + size_t dimRange, + size_t dimRangeCols = 1, + size_t dimFlux = dimDomain, + EntropyType entropy = EntropyType::MaxwellBoltzmann> +class HatFunctionMomentBasis +{ + // static_assert(false, "Not implemented for this dimension!"); +}; + +template <class DomainFieldType, + class RangeFieldType, + size_t rangeDim, + size_t rangeDimCols, + size_t fluxDim, + EntropyType entropy> +class HatFunctionMomentBasis<DomainFieldType, 1, RangeFieldType, rangeDim, rangeDimCols, fluxDim, entropy> + : public MomentBasisInterface<DomainFieldType, 1, RangeFieldType, rangeDim, rangeDimCols, fluxDim, entropy> +{ +public: + static const size_t dimDomain = 1; + static const size_t dimRange = rangeDim; + static const size_t dimRangeCols = rangeDimCols; + static const size_t num_intervals = dimRange - 1; + +private: + using BaseType = + MomentBasisInterface<DomainFieldType, dimDomain, RangeFieldType, dimRange, dimRangeCols, fluxDim, entropy>; + +public: + using typename BaseType::DomainType; + using typename BaseType::DynamicRangeType; + using typename BaseType::MatrixType; + using typename BaseType::QuadraturesType; + using typename BaseType::RangeType; + using typename BaseType::SphericalTriangulationType; + using typename BaseType::StringifierType; + using typename BaseType::VisualizerType; + using PartitioningType = typename BaseType::Partitioning1dType; + template <class DiscreteFunctionType> + + static std::string static_id() + { + return "hatfunctions"; + } + + static size_t default_quad_order() + { + return 15; + } + + using BaseType::default_quad_refinements; + + HatFunctionMomentBasis(const QuadraturesType& quadratures) + : BaseType(quadratures) + , partitioning_(BaseType::create_1d_partitioning(num_intervals)) + { + BaseType::initialize_base_values(); + } + + HatFunctionMomentBasis(const SphericalTriangulationType& /*triangulation*/, const QuadraturesType& quadratures) + : HatFunctionMomentBasis(quadratures) + {} + + HatFunctionMomentBasis(const size_t quad_order = default_quad_order(), + const size_t quad_refinements = default_quad_refinements()) + : BaseType(BaseType::gauss_lobatto_quadratures(num_intervals, quad_order, quad_refinements)) + , partitioning_(BaseType::create_1d_partitioning(num_intervals)) + { + BaseType::initialize_base_values(); + } + + DynamicRangeType evaluate(const DomainType& v) const override final + { + DynamicRangeType ret(dimRange, 0); + const auto& mu = partitioning_; + for (size_t ii = 0; ii < dimRange; ++ii) { + if (ii < num_intervals && XT::Common::FloatCmp::ge(v[0], mu[ii]) && XT::Common::FloatCmp::le(v[0], mu[ii + 1])) + ret[ii] = (v - mu[ii + 1]) / (mu[ii] - mu[ii + 1]); + if (ii > 0 && XT::Common::FloatCmp::ge(v[0], mu[ii - 1]) && XT::Common::FloatCmp::le(v[0], mu[ii])) + ret[ii] = (v - mu[ii - 1]) / (mu[ii] - mu[ii - 1]); + } + return ret; + } // ... evaluate(...) + + DynamicRangeType evaluate(const DomainType& v, const size_t interval_index) const override final + { + DynamicRangeType ret(dimRange, 0); + const auto& mu = partitioning_; + ret[interval_index] = (v - mu[interval_index + 1]) / (mu[interval_index] - mu[interval_index + 1]); + ret[interval_index + 1] = (v - mu[interval_index]) / (mu[interval_index + 1] - mu[interval_index]); + return ret; + } // ... evaluate(...) + + XT::Common::FieldVector<RangeFieldType, 2> evaluate_on_interval(const DomainType& v, + const size_t interval_index) const + { + XT::Common::FieldVector<RangeFieldType, 2> ret; + const auto& mu = partitioning_; + ret[0] = (v - mu[interval_index + 1]) / (mu[interval_index] - mu[interval_index + 1]); + ret[1] = (v - mu[interval_index]) / (mu[interval_index + 1] - mu[interval_index]); + return ret; + } // ... evaluate(...) + + DynamicRangeType integrated() const override final + { + DynamicRangeType ret(dimRange, 0); + const auto& mu = partitioning_; + ret[0] = mu[1] - mu[0]; + for (size_t ii = 1; ii < num_intervals; ++ii) + ret[ii] = mu[ii + 1] - mu[ii - 1]; + ret[num_intervals] = mu[num_intervals] - mu[num_intervals - 1]; + ret *= 0.5; + return ret; + } + + // returns matrix with entries <h_i h_j> + MatrixType mass_matrix() const override final + { + MatrixType ret(dimRange, dimRange, 0); + const auto& mu = partitioning_; + ret[0][0] = (mu[1] - mu[0]) / 3.; + for (size_t rr = 0; rr < dimRange; ++rr) { + if (rr > 0 && rr < num_intervals) + ret[rr][rr] = (mu[rr + 1] - mu[rr - 1]) / 3.; + if (rr > 0) + ret[rr][rr - 1] = (mu[rr] - mu[rr - 1]) / 6.; + if (rr < num_intervals) + ret[rr][rr + 1] = (mu[rr + 1] - mu[rr]) / 6.; + } + ret[num_intervals][num_intervals] = (mu[num_intervals] - mu[num_intervals - 1]) / 3.; + return ret; + } + + MatrixType mass_matrix_inverse() const override final + { + return tridiagonal_matrix_inverse<RangeFieldType, dimRange>(mass_matrix()); + } + + // returns matrix with entries <v h_i h_j> + FieldVector<MatrixType, 1> flux_matrix() const override final + { + MatrixType ret(dimRange, dimRange, 0.); + const auto& mu = partitioning_; + ret[0][0] = (std::pow(mu[1], 2) + 2 * mu[1] * mu[0] - 3 * std::pow(mu[0], 2)) / 12.; + for (size_t rr = 0; rr < dimRange; ++rr) { + if (rr > 0 && rr < num_intervals) + ret[rr][rr] = + (std::pow(mu[rr + 1], 2) + 2 * mu[rr + 1] * mu[rr] - 2 * mu[rr] * mu[rr - 1] - std::pow(mu[rr - 1], 2)) + / 12.; + if (rr > 0) + ret[rr][rr - 1] = (std::pow(mu[rr], 2) - std::pow(mu[rr - 1], 2)) / 12.; + if (rr < num_intervals) + ret[rr][rr + 1] = (std::pow(mu[rr + 1], 2) - std::pow(mu[rr], 2)) / 12.; + } + ret[num_intervals][num_intervals] = + (3 * std::pow(mu[num_intervals], 2) - 2 * mu[num_intervals] * mu[num_intervals - 1] + - std::pow(mu[num_intervals - 1], 2)) + / 12.; + return ret; + } + + // returns V M^-1 where the matrix V has entries <v h_i h_j>_- and <v h_i h_j>_+ + FieldVector<FieldVector<MatrixType, 2>, 1> kinetic_flux_matrices() const override final + { + FieldVector<FieldVector<MatrixType, 2>, 1> ret(FieldVector<MatrixType, 2>(MatrixType(dimRange, dimRange, 0.))); + auto mm_with_v = flux_matrix(); + auto& ret_neg = ret[0][0]; + auto& ret_pos = ret[0][1]; + size_t N = dimRange; + const auto& mu = partitioning_; + for (size_t nn = 0; nn < N; ++nn) { + for (size_t mm = (nn > 0 ? nn - 1 : 0); mm <= (nn < N - 1 ? nn + 1 : nn); ++mm) { + if (N % 2) { + if (nn < N / 2 || mm < N / 2) + ret_neg[nn][mm] = mm_with_v[0][nn][mm]; + else if (nn > N / 2 || mm > N / 2) + ret_pos[nn][mm] = mm_with_v[0][nn][mm]; + else { // nn == mm == N/2 + ret_neg[nn][mm] = -std::pow(mu[mm - 1], 2) / 12.; + ret_pos[nn][mm] = std::pow(mu[mm + 1], 2) / 12.; + } + } else { + if (nn < N / 2 - 1 || mm < N / 2 - 1) + ret_neg[nn][mm] = mm_with_v[0][nn][mm]; + else if (nn > N / 2 || mm > N / 2) + ret_pos[nn][mm] = mm_with_v[0][nn][mm]; + else if (nn == N / 2 && mm == nn) { + ret_neg[nn][mm] = -std::pow(mu[mm], 2) / 48.; + ret_pos[nn][mm] = (5 * std::pow(mu[mm], 2) + 8 * mu[mm] * mu[mm + 1] + 4 * std::pow(mu[mm + 1], 2)) / 48.; + } else if (nn == N / 2 - 1 && mm == nn) { + ret_neg[nn][mm] = (-5 * std::pow(mu[mm], 2) - 8 * mu[mm] * mu[mm - 1] - 4 * std::pow(mu[mm - 1], 2)) / 48.; + ret_pos[nn][mm] = std::pow(mu[mm], 2) / 48.; + } else { // (((mm == N / 2 && nn == N / 2 - 1) || (mm == N / 2 - 1 && nn == N / 2))) { + ret_neg[nn][mm] = -std::pow(mu[mm], 2) / 16.; + ret_pos[nn][mm] = std::pow(mu[mm], 2) / 16.; + } + } // else (N % 2) + } // mm + } // nn + // apply M^{-1} from the right + const auto M = std::make_unique<XT::Common::FieldMatrix<RangeFieldType, dimRange, dimRange>>(mass_matrix()); + MatrixType tmp_mat = ret_neg; + for (size_t rr = 0; rr < dimRange; ++rr) + M->solve(ret_neg[rr], tmp_mat[rr]); + tmp_mat = ret_pos; + for (size_t rr = 0; rr < dimRange; ++rr) + M->solve(ret_pos[rr], tmp_mat[rr]); + return ret; + } + + MatrixType reflection_matrix(const DomainType& n) const override final + { + MatrixType ret(dimRange, dimRange, 0); + for (size_t ii = 0; ii < dimDomain; ++ii) + if (XT::Common::FloatCmp::ne(n[ii], 0.)) + if (XT::Common::FloatCmp::ne(std::abs(n[ii]), 1.)) + DUNE_THROW(NotImplemented, "Implemented only for +-e_i where e_i is the i-th canonical basis vector!"); + const auto mass_mat = mass_matrix(); + for (size_t ii = 0; ii < dimRange; ++ii) + for (size_t jj = 0; jj < dimRange; ++jj) + ret[ii][jj] = mass_mat[ii][num_intervals - jj]; + ret.rightmultiply(mass_matrix_inverse()); +#ifndef NDEBUG + for (size_t ii = 0; ii < dimRange; ++ii) + for (size_t jj = 0; jj < dimRange; ++jj) + if (std::isnan(ret[ii][jj]) || std::isinf(ret[ii][jj])) + DUNE_THROW(Dune::MathError, + "Calculation of reflection matrix failed for normal n = " + XT::Common::to_string(n)); +#endif + return ret; + } + + static StringifierType stringifier() + { + return [](const RangeType& val) { + RangeFieldType psi(0); + for (const auto& entry : val) + psi += entry; + return XT::Common::to_string(psi, 15); + }; + } // ... stringifier() + + const PartitioningType& partitioning() const + { + return partitioning_; + } + + DynamicRangeType alpha_one() const override final + { + return DynamicRangeType(dimRange, 1.); + } + + RangeFieldType density(const DynamicRangeType& u) const override final + { + return std::accumulate(u.begin(), u.end(), RangeFieldType(0)); + } + + using BaseType::u_iso; + + void ensure_min_density(DynamicRangeType& u, const RangeFieldType min_density) const override final + { + const auto u_iso_min = u_iso() * min_density; + for (size_t ii = 0; ii < dimRange; ++ii) + if (u[ii] < u_iso_min[ii]) + u[ii] = u_iso_min[ii]; + } + + void ensure_min_density(RangeType& u, const RangeFieldType min_density) const override final + { + const auto u_iso_min = u_iso() * min_density; + for (size_t ii = 0; ii < dimRange; ++ii) + if (u[ii] < u_iso_min[ii]) + u[ii] = u_iso_min[ii]; + } + + std::string short_id() const override final + { + return "hf"; + } + + std::string mn_name() const override final + { + return "hfm" + XT::Common::to_string(dimRange); + } + + std::string pn_name() const override final + { + return "hfp" + XT::Common::to_string(dimRange); + } + + // get indices of all faces that contain point v + std::vector<size_t> get_face_indices(const DomainType& v) const + { + std::vector<size_t> face_indices; + for (size_t jj = 0; jj < partitioning_.size() - 1; ++jj) + if (XT::Common::FloatCmp::ge(v[0], partitioning_[jj]) && XT::Common::FloatCmp::le(v[0], partitioning_[jj + 1])) + face_indices.push_back(jj); + assert(face_indices.size()); + return face_indices; + } + +private: + const PartitioningType partitioning_; +}; // class HatFunctionMomentBasis<DomainFieldType, 1, ...> + +template <class DomainFieldType, + class RangeFieldType, + size_t rangeDim, + size_t rangeDimCols, + size_t fluxDim, + EntropyType entropy> +constexpr size_t + HatFunctionMomentBasis<DomainFieldType, 1, RangeFieldType, rangeDim, rangeDimCols, fluxDim, entropy>::dimRange; + +template <class DomainFieldType, class RangeFieldType, size_t refinements, size_t fluxDim, EntropyType entropy> +class HatFunctionMomentBasis<DomainFieldType, 3, RangeFieldType, refinements, 1, fluxDim, entropy> + : public MomentBasisInterface<DomainFieldType, + 3, + RangeFieldType, + OctaederStatistics<refinements>::num_vertices(), + 1, + fluxDim, + entropy> +{ +public: + static constexpr size_t dimDomain = 3; + static constexpr size_t dimRange = OctaederStatistics<refinements>::num_vertices(); + static constexpr size_t dimRangeCols = 1; + static constexpr size_t dimFlux = fluxDim; + static constexpr size_t num_refinements = refinements; + +private: + using BaseType = + MomentBasisInterface<DomainFieldType, dimDomain, RangeFieldType, dimRange, dimRangeCols, dimFlux, entropy>; + using ThisType = HatFunctionMomentBasis; + +public: + using TriangulationType = typename BaseType::SphericalTriangulationType; + using typename BaseType::DomainType; + using typename BaseType::DynamicRangeType; + using typename BaseType::MatrixType; + using typename BaseType::MergedQuadratureIterator; + using typename BaseType::QuadraturesType; + using typename BaseType::RangeType; + using typename BaseType::StringifierType; + using typename BaseType::VisualizerType; + using LocalMatrixType = XT::Common::FieldMatrix<RangeFieldType, 3, 3>; + + using BaseType::barycentre_rule; + using BaseType::is_negative; + + static size_t default_quad_order() + { + return refinements == 0 ? 15 : 9; + } + + using BaseType::default_quad_refinements; + + HatFunctionMomentBasis(const QuadraturesType& quadratures) + : BaseType(refinements, quadratures) + { + assert(triangulation_.vertices().size() == dimRange); + BaseType::initialize_base_values(); + } + + HatFunctionMomentBasis(const TriangulationType& triangulation, const QuadraturesType& quadratures) + : BaseType(triangulation, quadratures) + { + assert(triangulation_.vertices().size() == dimRange); + BaseType::initialize_base_values(); + } + + HatFunctionMomentBasis(const size_t quad_refinements, + const QuadratureRule<RangeFieldType, 2>& reference_quadrature_rule) + : BaseType(refinements) + { + quadratures_ = triangulation_.quadrature_rules(quad_refinements, reference_quadrature_rule); + assert(triangulation_.vertices().size() == dimRange); + BaseType::initialize_base_values(); + } + + HatFunctionMomentBasis(const size_t quad_order = default_quad_order(), + const size_t quad_refinements = default_quad_refinements()) + : BaseType(refinements) + { + const QuadratureRule<RangeFieldType, 2> reference_quadrature_rule = + XT::Data::FeketeQuadrature<DomainFieldType>::get(quad_order); + quadratures_ = triangulation_.quadrature_rules(quad_refinements, reference_quadrature_rule); + assert(triangulation_.vertices().size() == dimRange); + BaseType::initialize_base_values(); + } + + DynamicRangeType evaluate(const DomainType& v) const override + { + DynamicRangeType ret(dimRange, 0); + bool success = false; + // walk over faces + for (const auto& face : triangulation_.faces()) { + const auto& vertices = face->vertices(); + DomainType barycentric_coords(0); + success = calculate_barycentric_coordinates(v, vertices, barycentric_coords); + if (success) { + for (size_t ii = 0; ii < 3; ++ii) + ret[vertices[ii]->index()] = barycentric_coords[ii]; + break; + } + } // faces + assert(success); + return ret; + } // ... evaluate(...) + + DynamicRangeType evaluate(const DomainType& v, const size_t face_index) const override final + { + DynamicRangeType ret(dimRange, 0); + auto barycentric_coords = evaluate_on_face(v, face_index); + const auto& vertices = triangulation_.faces()[face_index]->vertices(); + for (size_t ii = 0; ii < 3; ++ii) + ret[vertices[ii]->index()] = barycentric_coords[ii]; + return ret; + } // ... evaluate(...) + + DomainType evaluate_on_face(const DomainType& v, const size_t face_index) const + { + DomainType ret(0); + const auto& face = triangulation_.faces()[face_index]; + const auto& vertices = face->vertices(); + bool success = calculate_barycentric_coordinates(v, vertices, ret); + assert(success); +#ifdef NDEBUG + static_cast<void>(success); +#endif + return ret; + } // ... evaluate(...) + + static StringifierType stringifier() + { + return [](const RangeType& val) { + RangeFieldType psi(0); + for (const auto& entry : val) + psi += entry; + return XT::Common::to_string(psi, 15); + }; + } // ... stringifier() + + const TriangulationType& triangulation() const + { + return triangulation_; + } + + RangeFieldType unit_ball_volume() const override final + { + return BaseType::unit_ball_volume_quad(); + } + + DynamicRangeType alpha_one() const override final + { + return DynamicRangeType(dimRange, 1.); + } + + template <class Vec> + std::enable_if_t<XT::Common::is_vector<Vec>::value, void> alpha_one(Vec& ret) const + { + for (size_t ii = 0; ii < ret.size(); ++ii) + XT::Common::VectorAbstraction<Vec>::set_entry(ret, ii, 1.); + } + + RangeFieldType density(const DynamicRangeType& u) const override final + { + return std::accumulate(u.begin(), u.end(), 0.); + } + + template <class Vec> + std::enable_if_t<XT::Common::is_vector<Vec>::value && !std::is_same<Vec, DynamicRangeType>::value, RangeFieldType> + density(const Vec& u) const + { + RangeFieldType ret(0.); + for (size_t ii = 0; ii < u.size(); ++ii) + ret += XT::Common::VectorAbstraction<Vec>::get_entry(u, ii); + return ret; + } + + std::string short_id() const override final + { + return "hf"; + } + + std::string mn_name() const override final + { + return "hfm" + XT::Common::to_string(dimRange); + } + + std::string pn_name() const override final + { + return "hfp" + XT::Common::to_string(dimRange); + } + + // get indices of all faces that contain point v + std::vector<size_t> get_face_indices(const DomainType& v) const + { + return triangulation_.get_face_indices(v); + } + + // calculates <b(v) dirac(v-dirac_position)> + DynamicRangeType integrate_dirac_at(const DomainType& dirac_position) const + { + return evaluate(dirac_position); + } + + using BaseType::u_iso; + + template <class Vec> + std::enable_if_t<XT::Common::is_vector<Vec>::value, void> u_iso(Vec& ret) const + { + auto ret_range = u_iso(); + using V = XT::Common::VectorAbstraction<Vec>; + for (size_t ii = 0; ii < dimRange; ++ii) + V::set_entry(ret, ii, ret_range[ii]); + } + + void ensure_min_density(DynamicRangeType& u, const RangeFieldType min_density) const override final + { + const auto u_iso_min = u_iso() * min_density; + for (size_t ii = 0; ii < dimRange; ++ii) + if (u[ii] < u_iso_min[ii]) + u[ii] = u_iso_min[ii]; + } + + void ensure_min_density(RangeType& u, const RangeFieldType min_density) const override final + { + const auto u_iso_min = u_iso() * min_density; + for (size_t ii = 0; ii < dimRange; ++ii) + if (u[ii] < u_iso_min[ii]) + u[ii] = u_iso_min[ii]; + } + + virtual DynamicRangeType + get_moment_vector(const std::function<RangeFieldType(DomainType, bool)>& psi) const override final + { + DynamicRangeType ret(dimRange, 0.); + const auto merged_quads = XT::Data::merged_quadrature(quadratures_); + for (auto it = merged_quads.begin(); it != merged_quads.end(); ++it) { + const auto face_index = it.first_index(); + const auto& vertices = triangulation_.faces()[face_index]->vertices(); + const auto& quad_point = *it; + const auto& v = quad_point.position(); + const auto val = evaluate_on_face(v, face_index); + const auto factor = psi(v, is_negative(it)) * quad_point.weight(); + for (size_t ii = 0; ii < 3; ++ii) + ret[vertices[ii]->index()] += val[ii] * factor; + } + return ret; + } + +protected: + template <class VertexVectorType> + bool calculate_barycentric_coordinates(const DomainType& v, const VertexVectorType& vertices, DomainType& ret) const + { + if (XT::Common::FloatCmp::ne(v.two_norm2(), 1.)) + DUNE_THROW(Dune::MathError, "Wrong input given!"); + Dune::FieldMatrix<RangeFieldType, 3, 3> gradients(0); + for (size_t ii = 0; ii < 3; ++ii) { + // copy vertices to gradients + gradients[ii] = vertices[ii]->position(); + const auto scalar_prod = v * gradients[ii]; + // if v is not on the same half space of the sphere as the vertices, return false + // assumes the triangulation is fine enough that vertices[ii]*vertices[jj] >= 0 for all triangles + if (XT::Common::FloatCmp::lt(scalar_prod, 0.)) + return false; + else if (XT::Common::FloatCmp::ge(scalar_prod, 1.)) { + ret *= 0.; + ret[ii] = 1.; + return true; + } + auto v_scaled = v; + v_scaled *= scalar_prod; + gradients[ii] -= v_scaled; + // scale with factor + auto denominator = std::sqrt(1. - std::pow(scalar_prod, 2)); + if (std::isnan(denominator)) + DUNE_THROW(Dune::MathError, "NaN in evaluation!"); + if (std::isnan(std::acos(scalar_prod))) + DUNE_THROW(Dune::MathError, "wrong value of scalar_prod!"); + gradients[ii] *= XT::Common::FloatCmp::eq(denominator, 0.) ? 0. : std::acos(scalar_prod) / denominator; + } // ii + // Calculate barycentric coordinates for 0 w.r.t to the points g_i = gradients[i] + // For that purpose, solve the overdetermined system A (h0 h1)^T = b + // for the matrix A = (g_0-g_2 g_1-g_2) and the right-hand side b = -g_2. + // The solution is (A^T A)^{-1} A^T b. + // The third coordinate is calculated from the condition h0+h1+h2=1. + Dune::XT::Common::FieldMatrix<RangeFieldType, 3, 2> A; + Dune::XT::Common::FieldMatrix<RangeFieldType, 2, 3> AT; + Dune::XT::Common::FieldVector<RangeFieldType, 2> solution; + AT[0] = gradients[0]; + AT[1] = gradients[1]; + AT[0] -= gradients[2]; + AT[1] -= gradients[2]; + for (size_t ii = 0; ii < 3; ++ii) + for (size_t jj = 0; jj < 2; ++jj) + A[ii][jj] = AT[jj][ii]; + Dune::XT::Common::FieldMatrix<RangeFieldType, 2, 2> AT_A = AT.rightmultiplyany(A); + gradients[2] *= -1; + Dune::XT::Common::FieldVector<RangeFieldType, 2> AT_b; + AT.mv(gradients[2], AT_b); + AT_A.solve(solution, AT_b); + ret[0] = solution[0]; + ret[1] = solution[1]; + ret[2] = 1. - ret[0] - ret[1]; + if (XT::Common::FloatCmp::lt(ret[0], 0., 1e-14, 1e-14) || XT::Common::FloatCmp::lt(ret[1], 0., 1e-14, 1e-14) + || XT::Common::FloatCmp::lt(ret[2], 0., 1e-14, 1e-14)) + return false; + // we already checked the values are close to 0, now remove negative values stemming from numerical inaccuracies + for (size_t ii = 0; ii < 3; ++ii) + if (ret[ii] < 0.) + ret[ii] = 0.; + return true; + } // bool calculate_barycentric_coordinates(...) + + static std::vector<size_t> create_face_decomposition(const size_t num_faces, const size_t num_threads) + { + std::vector<size_t> ret(num_threads + 1); + for (size_t ii = 0; ii < num_threads; ++ii) + ret[ii] = num_faces / num_threads * ii; + ret[num_threads] = num_faces; + return ret; + } + + virtual void parallel_quadrature(const QuadraturesType& quadratures, + MatrixType& matrix, + const size_t v_index, + const bool reflecting = false) const override final + { + const auto& faces = triangulation_.faces(); + size_t num_threads = std::min(XT::Common::threadManager().max_threads(), faces.size()); + const auto decomposition = create_face_decomposition(faces.size(), num_threads); + std::vector<std::thread> threads(num_threads); + // Launch a group of threads + std::vector<LocalMatrixType> local_matrices(faces.size(), LocalMatrixType(0.)); + for (size_t ii = 0; ii < num_threads; ++ii) + threads[ii] = std::thread(&ThisType::calculate_in_thread_hat, + this, + std::ref(local_matrices), + std::cref(quadratures), + v_index, + std::cref(decomposition), + ii, + reflecting); + // Join the threads with the main thread + for (size_t ii = 0; ii < num_threads; ++ii) + threads[ii].join(); + // add local matrices + matrix *= 0.; + for (size_t ii = 0; ii < num_threads; ++ii) { + for (size_t face_index = decomposition[ii]; face_index < decomposition[ii + 1]; ++face_index) { + const auto& face = faces[face_index]; + const auto& vertices = face->vertices(); + for (size_t nn = 0; nn < 3; ++nn) + for (size_t mm = 0; mm < 3; ++mm) + matrix[vertices[nn]->index()][vertices[mm]->index()] += local_matrices[face_index][nn][mm]; + } // faces + } // threads + } // void parallel_quadrature(...) + + virtual void calculate_in_thread_hat(std::vector<LocalMatrixType>& local_matrices, + const QuadraturesType& quadratures, + const size_t v_index, + const std::vector<size_t>& decomposition, + const size_t ii, + const bool reflecting) const + { + const auto& reflected_indices = triangulation_.reflected_face_indices(); + for (size_t face_index = decomposition[ii]; face_index < decomposition[ii + 1]; ++face_index) { + for (const auto& quad_point : quadratures[face_index]) { + const auto& v = quad_point.position(); + const auto basis_evaluated = evaluate_on_face(v, face_index); + auto basis_reflected = basis_evaluated; + if (reflecting) { + auto v_reflected = v; + v_reflected[v_index] *= -1.; + const size_t reflected_index = reflected_indices.size() ? reflected_indices[face_index][v_index] : 0; + basis_reflected = evaluate_on_face(v_reflected, reflected_index); + } + const auto& weight = quad_point.weight(); + const auto factor = (reflecting || v_index == size_t(-1)) ? 1. : v[v_index]; + for (size_t nn = 0; nn < 3; ++nn) + for (size_t mm = 0; mm < 3; ++mm) + local_matrices[face_index][nn][mm] += + basis_evaluated[nn] * (reflecting ? basis_reflected[mm] : basis_evaluated[mm]) * factor * weight; + } // quad_points + } // faces + } // void calculate_in_thread(...) + + virtual void integrated_initializer_thread(DynamicRangeType& local_range, + const std::vector<MergedQuadratureIterator>& decomposition, + const size_t ii) const override final + { + const auto& faces = triangulation_.faces(); + for (auto it = decomposition[ii]; it != decomposition[ii + 1]; ++it) { + const auto face_index = it.first_index(); + const auto& vertices = faces[face_index]->vertices(); + const auto& quad_point = *it; + DomainType basis_evaluated = evaluate_on_face(quad_point.position(), face_index); + basis_evaluated *= quad_point.weight(); + for (size_t nn = 0; nn < 3; ++nn) + local_range[vertices[nn]->index()] += basis_evaluated[nn]; + } // jj + } // void calculate_in_thread(...) + + using BaseType::quadratures_; + using BaseType::triangulation_; +}; // class HatFunctionMomentBasis<DomainFieldType, 3, ...> + +template <class DomainFieldType, class RangeFieldType, size_t rangeDim, size_t fluxDim, EntropyType entropy> +constexpr size_t HatFunctionMomentBasis<DomainFieldType, 3, RangeFieldType, rangeDim, 1, fluxDim, entropy>::dimRange; + +template <class DomainFieldType, class RangeFieldType, size_t rangeDim, size_t fluxDim, EntropyType entropy> +constexpr size_t + HatFunctionMomentBasis<DomainFieldType, 3, RangeFieldType, rangeDim, 1, fluxDim, entropy>::num_refinements; + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_HATFUNCTIONS_HH diff --git a/dune/gdt/test/momentmodels/basisfunctions/interface.hh b/dune/gdt/test/momentmodels/basisfunctions/interface.hh new file mode 100644 index 0000000000000000000000000000000000000000..7502c0c131ea85ec2f7e8566099249edbe77a408 --- /dev/null +++ b/dune/gdt/test/momentmodels/basisfunctions/interface.hh @@ -0,0 +1,578 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2019) + +#ifndef DUNE_GDT_MOMENTMODELS_BASISFUNCTIONS_INTERFACE_HH +#define DUNE_GDT_MOMENTMODELS_BASISFUNCTIONS_INTERFACE_HH + +#include <memory> +#include <vector> +#include <string> + +#include <dune/xt/common/math.hh> +#include <dune/xt/common/string.hh> +#include <dune/xt/common/tuple.hh> + +#include <dune/xt/data/quadratures.hh> +#include <dune/xt/data/spherical_quadratures.hh> + +#include <dune/gdt/discretefunction/default.hh> +#include <dune/gdt/test/momentmodels/triangulation.hh> + +namespace Dune { +namespace GDT { + + +// see https://en.wikipedia.org/wiki/Tridiagonal_matrix#Inversion +template <class FieldType, int rows> +Dune::DynamicMatrix<FieldType> tridiagonal_matrix_inverse(const DynamicMatrix<FieldType>& matrix) +{ + typedef Dune::DynamicMatrix<FieldType> MatrixType; + size_t cols = rows; +#ifndef NDEBUG + for (size_t rr = 0; rr < rows; ++rr) + for (size_t cc = 0; cc < cols; ++cc) + if ((cc > rr + 1 || cc + 1 < rr) && XT::Common::FloatCmp::ne(matrix[rr][cc], 0.)) + DUNE_THROW(XT::Common::Exceptions::you_are_using_this_wrong, "Matrix has to be tridiagonal!"); +#endif // NDEBUG + MatrixType ret(rows, rows, 0); + Dune::FieldVector<FieldType, rows + 1> a(0), b(0), c(0), theta(0); + Dune::FieldVector<FieldType, rows + 2> phi(0); + for (size_t ii = 1; ii < rows + 1; ++ii) { + a[ii] = matrix[ii - 1][ii - 1]; + if (ii < rows) { + b[ii] = matrix[ii - 1][ii]; + c[ii] = matrix[ii][ii - 1]; + } + } + theta[0] = 1; + theta[1] = a[1]; + for (size_t ii = 2; ii < rows + 1; ++ii) + theta[ii] = a[ii] * theta[ii - 1] - b[ii - 1] * c[ii - 1] * theta[ii - 2]; + phi[rows + 1] = 1; + phi[rows] = a[rows]; + for (size_t ii = rows - 1; ii > 0; --ii) + phi[ii] = a[ii] * phi[ii + 1] - b[ii] * c[ii] * phi[ii + 2]; + for (size_t ii = 1; ii < rows + 1; ++ii) { + for (size_t jj = 1; jj < cols + 1; ++jj) { + if (ii == jj) + ret[ii - 1][jj - 1] = theta[ii - 1] * phi[jj + 1] / theta[rows]; + else if (ii < jj) { + ret[ii - 1][jj - 1] = std::pow(-1, ii + jj) * theta[ii - 1] * phi[jj + 1] / theta[rows]; + for (size_t kk = ii; kk < jj; ++kk) + ret[ii - 1][jj - 1] *= b[kk]; + } else if (ii > jj) { + ret[ii - 1][jj - 1] = std::pow(-1, ii + jj) * theta[jj - 1] * phi[ii + 1] / theta[rows]; + for (size_t kk = jj; kk < ii; ++kk) + ret[ii - 1][jj - 1] *= c[kk]; + } + } // jj + } // ii +#ifndef NDEBUG + for (size_t ii = 0; ii < rows; ++ii) + for (size_t jj = 0; jj < cols; ++jj) + if (std::isnan(ret[ii][jj]) || std::isinf(ret[ii][jj])) + DUNE_THROW(Dune::MathError, "Inversion of triangular matrix failed!"); +#endif + return ret; +} // ... tridiagonal_matrix_inverse(...) + +// After each refinement step: +// num_vertices_new = num_vertices_old + num_intersections_old +// num_intersections_new = 2*num_intersections_old + 3*num_faces_old +// num_faces_new = 4*num_faces_old +// Initially, there are 6 vertices, 12 intersections and 8 faces. +template <size_t refinements> +struct OctaederStatistics +{ + static constexpr size_t constexpr_pow(size_t base, size_t exponent) + { + return (exponent == 0) ? 1 : (base * constexpr_pow(base, exponent - 1)); + } + + static constexpr size_t num_faces() + { + return 8 * constexpr_pow(4, refinements); + } + + static constexpr size_t num_intersections() + { + return 2 * OctaederStatistics<refinements - 1>::num_intersections() + + 3 * OctaederStatistics<refinements - 1>::num_faces(); + } + + static constexpr size_t num_vertices() + { + return OctaederStatistics<refinements - 1>::num_vertices() + + OctaederStatistics<refinements - 1>::num_intersections(); + } +}; + +template <> +struct OctaederStatistics<0> +{ + static constexpr size_t num_faces() + { + return 8; + } + + static constexpr size_t num_intersections() + { + return 12; + } + + static constexpr size_t num_vertices() + { + return 6; + } +}; + + +enum class EntropyType +{ + MaxwellBoltzmann, + BoseEinstein +}; + + +template <class DomainFieldImp, + size_t domainDim, + class RangeFieldImp, + size_t rangeDim, + size_t rangeDimCols = 1, + size_t fluxDim = domainDim, + EntropyType entrpy = EntropyType::MaxwellBoltzmann> +class MomentBasisInterface +{ +public: + static const size_t dimDomain = domainDim; + static const size_t dimRange = rangeDim; + static const size_t dimRangeCols = rangeDimCols; + static const size_t dimFlux = fluxDim; + static const size_t d = domainDim; + static const size_t r = rangeDim; + static const size_t rC = rangeDimCols; + static const size_t d_flux = fluxDim; + static const EntropyType entropy = entrpy; + using D = DomainFieldImp; + using R = RangeFieldImp; + + using DomainFieldType = DomainFieldImp; + using DomainType = FieldVector<DomainFieldType, dimDomain>; + using RangeFieldType = RangeFieldImp; + using MatrixType = DynamicMatrix<RangeFieldType>; + using RangeType = typename XT::Functions::RangeTypeSelector<RangeFieldType, dimRange, dimRangeCols>::type; + using DynamicRangeType = DynamicVector<RangeFieldType>; + using QuadratureType = QuadratureRule<DomainFieldType, dimDomain>; + using QuadraturesType = std::vector<QuadratureType>; + using VisualizerType = XT::Functions::VisualizerInterface<dimRange, dimRangeCols, RangeFieldType>; + using StringifierType = std::function<std::string(const RangeType&)>; + using Partitioning1dType = std::vector<RangeFieldType>; + using SphericalTriangulationType = SphericalTriangulation<RangeFieldType>; + using MergedQuadratureIterator = + typename XT::Data::MergedQuadrature<RangeFieldType, dimDomain>::MergedQuadratureIterator; + + static size_t default_quad_order() + { + DUNE_THROW(Dune::NotImplemented, "Please overwrite this function in derived classes!"); + return 0; + } + + static size_t default_quad_refinements() + { + return 0; + } + + MomentBasisInterface(const QuadraturesType& quadratures = QuadraturesType()) + : triangulation_(stored_triangulation_) + , quadratures_(quadratures) + {} + + MomentBasisInterface(const size_t refinements, const QuadraturesType& quadratures = QuadraturesType()) + : stored_triangulation_(refinements) + , triangulation_(stored_triangulation_) + , quadratures_(quadratures) + {} + + MomentBasisInterface(const SphericalTriangulationType& triangulation, const QuadraturesType& quadratures) + : triangulation_(triangulation) + , quadratures_(quadratures) + {} + + virtual ~MomentBasisInterface() {} + + virtual DynamicRangeType evaluate(const DomainType& v) const = 0; + + virtual DynamicRangeType evaluate(const DomainType& v, const size_t /*face_index*/) const + { + return evaluate(v); + } + + // returns <b>, where b is the basis functions vector + virtual DynamicRangeType integrated() const + { + return integrated_; + } + + virtual MatrixType mass_matrix() const + { + MatrixType M(dimRange, dimRange, 0.); + parallel_quadrature(quadratures_, M, size_t(-1)); + return M; + } // ... mass_matrix() + + virtual MatrixType mass_matrix_inverse() const + { + auto ret = mass_matrix(); + ret.invert(); + return ret; + } + + virtual DynamicRangeType get_moment_vector(const std::function<RangeFieldType(DomainType, bool)>& psi) const + { + DynamicRangeType ret(dimRange, 0.); + const auto merged_quads = XT::Data::merged_quadrature(quadratures()); + for (auto it = merged_quads.begin(); it != merged_quads.end(); ++it) { + const auto& quad_point = *it; + const auto& v = quad_point.position(); + ret += evaluate(v, it.first_index()) * psi(v, is_negative(it)) * quad_point.weight(); + } + return ret; + } + + virtual bool is_negative(const MergedQuadratureIterator& /*it*/) const + { + return false; + } + + virtual FieldVector<MatrixType, dimFlux> flux_matrix() const + { + FieldVector<MatrixType, dimFlux> B(MatrixType(dimRange, dimRange, 0)); + for (size_t dd = 0; dd < dimFlux; ++dd) + parallel_quadrature(quadratures_, B[dd], dd); + return B; + } + + virtual std::unique_ptr<VisualizerType> visualizer() const + { + return std::make_unique<XT::Functions::GenericVisualizer<dimRange, dimRangeCols, RangeFieldType>>( + 1, [this](const int /*comp*/, const RangeType& val) { return this->density(val); }); + } + + // returns V M^-1 where the matrix V has entries <v h_i h_j>_- and <v h_i h_j>_+ + virtual FieldVector<FieldVector<MatrixType, 2>, dimFlux> kinetic_flux_matrices() const + { + const auto M = std::make_unique<XT::Common::FieldMatrix<RangeFieldType, dimRange, dimRange>>(mass_matrix()); + FieldVector<FieldVector<MatrixType, 2>, dimFlux> B_kinetic( + FieldVector<MatrixType, 2>(MatrixType(dimRange, dimRange, 0.))); + MatrixType tmp_mat(dimRange, dimRange, 0.); + for (size_t dd = 0; dd < dimFlux; ++dd) { + QuadraturesType neg_quadratures(quadratures_.size()); + QuadraturesType pos_quadratures(quadratures_.size()); + get_pos_and_neg_quadratures(neg_quadratures, pos_quadratures, dd); + parallel_quadrature(neg_quadratures, tmp_mat, dd); + for (size_t rr = 0; rr < dimRange; ++rr) + M->solve(B_kinetic[dd][0][rr], tmp_mat[rr]); + parallel_quadrature(pos_quadratures, tmp_mat, dd); + for (size_t rr = 0; rr < dimRange; ++rr) + M->solve(B_kinetic[dd][1][rr], tmp_mat[rr]); + } // dd + return B_kinetic; + } // ... kinetic_flux_matrices() + + virtual MatrixType reflection_matrix(const DomainType& n) const + { + MatrixType ret(dimRange, dimRange, 0); + size_t direction; + for (size_t ii = 0; ii < dimDomain; ++ii) { + if (XT::Common::FloatCmp::ne(n[ii], 0.)) { + direction = ii; + if (XT::Common::FloatCmp::ne(std::abs(n[ii]), 1.)) + DUNE_THROW(NotImplemented, "Implemented only for +-e_i where e_i is the i-th canonical basis vector!"); + } + } + parallel_quadrature(quadratures_, ret, direction, true); + ret.rightmultiply(mass_matrix_inverse()); + // We need the exact reflection matrix to guarantee Q-realizability, the matrix should only contain 0, +-1, so just + // ensure it does + for (size_t ii = 0; ii < dimRange; ++ii) { + for (size_t jj = 0; jj < dimRange; ++jj) { + if (std::abs(ret[ii][jj]) > 0.99 && std::abs(ret[ii][jj]) < 1.01) + ret[ii][jj] = ret[ii][jj] / std::abs(ret[ii][jj]); + else if (std::abs(ret[ii][jj]) < 0.01) + ret[ii][jj] = 0; + else + DUNE_THROW(Dune::MathError, "Invalid reflection matrix!"); + } + } + return ret; + } + + // return alpha s.t. alpha_one * b(v) == 1 for all v + virtual DynamicRangeType alpha_one() const = 0; + + // returns alpha s.t. the distribution is isotropic and has density rho + virtual DynamicRangeType alpha_iso(const RangeFieldType rho = 1.) const + { + const auto scale_factor = rho / density(integrated()); + if (entropy == EntropyType::MaxwellBoltzmann) + return alpha_one() * std::log(scale_factor); + else + return alpha_one() * std::log(scale_factor / (scale_factor + 1)); + } + + virtual RangeFieldType density(const DynamicRangeType& u) const = 0; + + virtual void ensure_min_density(DynamicRangeType& u, const RangeFieldType min_density) const + { + if (density(u) < min_density) + u = u_iso() * min_density; + } + + virtual void ensure_min_density(RangeType& u, const RangeFieldType min_density) const + { + if (density(u) < min_density) { + u = u_iso(); + u *= min_density; + } + } + + // Volume of integration domain. For the Mn models it is important that u_iso has density 1. If the basis is exactly + // integrated, we thus use the exact unit ball volume. If the basis is only integrated by quadrature, we have to use + // <1> as volume to get a density of 1. + virtual RangeFieldType unit_ball_volume() const + { + return unit_ball_volume_exact(); + } + + virtual DynamicRangeType u_iso() const + { + return u_iso_; + } + + virtual std::string short_id() const = 0; + + virtual std::string mn_name() const = 0; + + virtual std::string pn_name() const = 0; + + static QuadratureRule<RangeFieldType, 2> barycentre_rule() + { + Dune::QuadratureRule<RangeFieldType, 2> ret; + ret.push_back(Dune::QuadraturePoint<RangeFieldType, 2>({1. / 3., 1. / 3.}, 0.5)); + return ret; + } + + static Partitioning1dType create_1d_partitioning(const size_t num_intervals) + { + Partitioning1dType ret(num_intervals + 1); + for (size_t ii = 0; ii <= num_intervals; ++ii) + ret[ii] = -1. + (2. * ii) / num_intervals; + return ret; + } + + const QuadraturesType& quadratures() const + { + return quadratures_; + } + + // A Gauss-Lobatto quadrature on each interval + template <size_t dD = dimDomain> + static std::enable_if_t<dD == 1, QuadraturesType> gauss_lobatto_quadratures(const size_t num_intervals, + const size_t quad_order, + const size_t additional_refinements = 0) + { + QuadraturesType ret(num_intervals); + const auto quads_per_interval = std::pow(2, additional_refinements); + const auto quadrature_boundaries = create_1d_partitioning(num_intervals * quads_per_interval); + // quadrature on reference interval [0, 1] + const auto reference_quadrature = XT::Data::GaussLobattoQuadrature<DomainFieldType>::get(quad_order); + // map to quadrature on interval [a, b] by + // x_i -> (1-x_i) a + x_i b + // w_i -> w_i * (b-a) + for (size_t ii = 0; ii < num_intervals; ++ii) { + for (size_t jj = 0; jj < quads_per_interval; ++jj) { + for (const auto& quad_point : reference_quadrature) { + const auto& x = quad_point.position()[0]; + const auto& a = quadrature_boundaries[ii * quads_per_interval + jj]; + const auto& b = quadrature_boundaries[ii * quads_per_interval + jj + 1]; + const auto pos = (1 - x) * a + x * b; + const auto weight = quad_point.weight() * (b - a); + ret[ii].emplace_back(pos, weight); + } // quad_points + } // jj + } // quad_cells + return ret; + } + + template <size_t dD = dimDomain> + static std::enable_if_t<dD == 3, QuadraturesType> lebedev_quadrature(const size_t quad_order) + { + return QuadraturesType(1, XT::Data::LebedevQuadrature<DomainFieldType, true>::get(quad_order)); + } + + static RangeFieldType unit_ball_volume_exact() + { + if (dimDomain == 1) + return 2; + else if (dimDomain == 2) + return 2 * M_PI; + else if (dimDomain == 3) + return 4 * M_PI; + else { + DUNE_THROW(NotImplemented, ""); + return 0; + } + } + + RangeFieldType unit_ball_volume_quad() const + { + RangeFieldType ret(0.); + for (const auto& quad_point : XT::Data::merged_quadrature(quadratures_)) + ret += quad_point.weight(); + return ret; + } + +protected: + void initialize_base_values() + { + integrated_ = integrated_initializer(quadratures_); + u_iso_ = integrated() / density(integrated()); + } + + void + get_pos_and_neg_quadratures(QuadraturesType& neg_quadratures, QuadraturesType& pos_quadratures, const size_t dd) const + { + for (size_t ii = 0; ii < quadratures_.size(); ++ii) { + for (const auto& quad_point : quadratures_[ii]) { + const auto& v = quad_point.position(); + const auto& weight = quad_point.weight(); + // if v[dd] = 0 the quad_point does not contribute to the integral + if (v[dd] > 0.) + pos_quadratures[ii].emplace_back(v, weight); + else if (v[dd] < 0.) + neg_quadratures[ii].emplace_back(v, weight); + } // quad_points + } // quadratures + } + + static std::vector<MergedQuadratureIterator> create_decomposition(const QuadraturesType& quadratures, + const size_t num_threads) + { + const size_t size = XT::Data::merged_quadrature(quadratures).size(); + std::vector<MergedQuadratureIterator> ret(num_threads + 1); + for (size_t ii = 0; ii < num_threads; ++ii) + ret[ii] = XT::Data::merged_quadrature(quadratures).iterator(size / num_threads * ii); + ret[num_threads] = XT::Data::merged_quadrature(quadratures).iterator(size); + return ret; + } + + virtual void parallel_quadrature(const QuadraturesType& quadratures, + MatrixType& matrix, + const size_t v_index, + const bool reflecting = false) const + { + size_t num_threads = + std::min(XT::Common::threadManager().max_threads(), XT::Data::merged_quadrature(quadratures).size()); + auto decomposition = create_decomposition(quadratures, num_threads); + std::vector<std::thread> threads(num_threads); + // Launch a group of threads + std::vector<MatrixType> local_matrices(num_threads, MatrixType(matrix.N(), matrix.M(), 0.)); + for (size_t ii = 0; ii < num_threads; ++ii) + threads[ii] = std::thread(&MomentBasisInterface::calculate_in_thread, + this, + std::ref(local_matrices[ii]), + v_index, + std::cref(decomposition), + ii, + reflecting); + // Join the threads with the main thread + for (size_t ii = 0; ii < num_threads; ++ii) + threads[ii].join(); + // add local matrices + matrix *= 0.; + for (size_t ii = 0; ii < num_threads; ++ii) + matrix += local_matrices[ii]; + } // void parallel_quadrature(...) + + virtual void calculate_in_thread(MatrixType& local_matrix, + const size_t v_index, + const std::vector<MergedQuadratureIterator>& decomposition, + const size_t ii, + const bool reflecting) const + { + const auto& reflected_indices = triangulation_.reflected_face_indices(); + for (auto it = decomposition[ii]; it != decomposition[ii + 1]; ++it) { + const auto& quad_point = *it; + const auto& v = quad_point.position(); + const auto basis_evaluated = evaluate(v, it.first_index()); + auto basis_reflected = basis_evaluated; + if (reflecting) { + auto v_reflected = v; + v_reflected[v_index] *= -1.; + // If the basis functions have a triangulation, get index of reflected triangle. Otherwise set to 0, will be + // ignored. + const size_t reflected_index = reflected_indices.size() ? reflected_indices[it.first_index()][v_index] : 0; + basis_reflected = evaluate(v_reflected, reflected_index); + } + const auto& weight = quad_point.weight(); + const auto factor = (reflecting || v_index == size_t(-1)) ? 1. : v[v_index]; + for (size_t nn = 0; nn < local_matrix.N(); ++nn) + for (size_t mm = 0; mm < local_matrix.M(); ++mm) + local_matrix[nn][mm] += + basis_evaluated[nn] * (reflecting ? basis_reflected[mm] : basis_evaluated[mm]) * factor * weight; + } + } // void calculate_in_thread(...) + + virtual DynamicRangeType integrated_initializer(const QuadraturesType& quadratures) const + { + size_t num_threads = + std::min(XT::Common::threadManager().max_threads(), XT::Data::merged_quadrature(quadratures).size()); + auto decomposition = create_decomposition(quadratures, num_threads); + std::vector<std::thread> threads(num_threads); + std::vector<DynamicRangeType> local_vectors(num_threads, DynamicRangeType(dimRange, 0.)); + for (size_t ii = 0; ii < num_threads; ++ii) + threads[ii] = std::thread(&MomentBasisInterface::integrated_initializer_thread, + this, + std::ref(local_vectors[ii]), + std::cref(decomposition), + ii); + // Join the threads with the main thread + for (size_t ii = 0; ii < num_threads; ++ii) + threads[ii].join(); + // add local matrices + DynamicRangeType ret(dimRange, 0.); + for (size_t ii = 0; ii < num_threads; ++ii) + ret += local_vectors[ii]; + return ret; + } + + virtual void integrated_initializer_thread(DynamicRangeType& local_range, + const std::vector<MergedQuadratureIterator>& decomposition, + const size_t ii) const + { + for (auto it = decomposition[ii]; it != decomposition[ii + 1]; ++it) { + const auto& quad_point = *it; + auto basis_evaluated = evaluate(quad_point.position(), it.first_index()); + basis_evaluated *= quad_point.weight(); + local_range += basis_evaluated; + } // jj + } // void calculate_in_thread(...) + + SphericalTriangulationType stored_triangulation_; + const SphericalTriangulationType& triangulation_; + QuadraturesType quadratures_; + DynamicRangeType integrated_; + DynamicRangeType u_iso_; +}; + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_MOMENTMODELS_BASISFUNCTIONS_INTERFACE_HH diff --git a/dune/gdt/test/momentmodels/basisfunctions/legendre.hh b/dune/gdt/test/momentmodels/basisfunctions/legendre.hh new file mode 100644 index 0000000000000000000000000000000000000000..2f7fba60e061ef974bb48e5dcb83134c9d51187f --- /dev/null +++ b/dune/gdt/test/momentmodels/basisfunctions/legendre.hh @@ -0,0 +1,254 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_LEGENDRE_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_LEGENDRE_HH + +#include "interface.hh" + +namespace Dune { +namespace GDT { + + +template <class DomainFieldType, + class RangeFieldType, + size_t order, + size_t dimRangeCols = 1, + EntropyType entropy = EntropyType::MaxwellBoltzmann> +class LegendreMomentBasis + : public MomentBasisInterface<DomainFieldType, 1, RangeFieldType, order + 1, dimRangeCols, 1, entropy> +{ +public: + static const size_t dimDomain = 1; + static const size_t dimRange = order + 1; + static const size_t num_intervals = size_t(-1); + +private: + typedef MomentBasisInterface<DomainFieldType, dimDomain, RangeFieldType, dimRange, dimRangeCols, 1, entropy> BaseType; + +public: + using typename BaseType::DomainType; + using typename BaseType::DynamicRangeType; + using typename BaseType::MatrixType; + using typename BaseType::QuadraturesType; + using typename BaseType::RangeType; + using typename BaseType::SphericalTriangulationType; + using typename BaseType::StringifierType; + + LegendreMomentBasis(const QuadraturesType& quadratures) + : BaseType(quadratures) + { + BaseType::initialize_base_values(); + } + + LegendreMomentBasis(const SphericalTriangulationType& /*triangulation*/, const QuadraturesType& quadratures) + : LegendreMomentBasis(quadratures) + {} + + static size_t default_quad_order() + { + return 2 * order + 40; + } + + static size_t default_quad_refinements() + { + return 1; + } + + LegendreMomentBasis(const size_t quad_order = default_quad_order(), + const size_t quad_refinements = default_quad_refinements()) + : BaseType(BaseType::gauss_lobatto_quadratures(std::pow(2, quad_refinements), quad_order)) + { + BaseType::initialize_base_values(); + } + + static std::string static_id() + { + return "legendre"; + } + + using BaseType::evaluate; + + DynamicRangeType evaluate(const DomainType& v) const override + { + DynamicRangeType ret(dimRange); + ret[0] = 1.; + if (dimRange > 1) + ret[1] = v[0]; + for (size_t ii = 2; ii < dimRange; ++ii) + ret[ii] = ((2. * ii - 1.) * v[0] * ret[ii - 1] - (ii - 1.) * ret[ii - 2]) / ii; + return ret; + } // ... evaluate(...) + + DynamicRangeType integrated_exactly() const + { + DynamicRangeType ret(dimRange, 0.); + ret[0] = 2; + return ret; + } + + MatrixType mass_matrix() const override + { + MatrixType M(dimRange, dimRange, 0.); + for (size_t rr = 0; rr < dimRange; ++rr) + M[rr][rr] = 2. / (2. * rr + 1.); + return M; + } + + MatrixType mass_matrix_inverse() const override + { + MatrixType Minv(dimRange, dimRange, 0.); + for (size_t rr = 0; rr < dimRange; ++rr) + Minv[rr][rr] = (2. * rr + 1.) / 2.; + return Minv; + } + + FieldVector<MatrixType, dimDomain> flux_matrix() const override + { + MatrixType B(dimRange, dimRange, 0); + for (size_t rr = 0; rr < dimRange; ++rr) { + for (size_t cc = 0; cc < dimRange; ++cc) { + if (cc == rr - 1) + B[rr][cc] = 2. * rr / (4. * rr * rr - 1.); + else if (cc == rr + 1) + B[rr][cc] = (2. * rr + 2.) / ((2. * rr + 1.) * (2. * rr + 3)); + } + } + return B; + } + + // returns V M^-1 where the matrix V has entries <v h_i h_j>_- and <v h_i h_j>_+ + FieldVector<FieldVector<MatrixType, 2>, 1> kinetic_flux_matrices() const override final + { + FieldVector<FieldVector<MatrixType, 2>, 1> ret(FieldVector<MatrixType, 2>(MatrixType(dimRange, dimRange, 0.))); + auto mm_with_v = flux_matrix(); + auto& ret_neg = ret[0][0]; + auto& ret_pos = ret[0][1]; + MatrixType mass_matrix_pos(dimRange + 1, dimRange + 1, 0.); // we need to calculate up to P_N + size_t N = dimRange; + // calculate <P_n P_m>_+ first + for (size_t nn = 0; nn <= N; ++nn) { + for (size_t mm = 0; mm <= N; ++mm) { + if ((nn + mm) % 2) { // nn and mm have different parity + if (nn % 2) // n odd + mass_matrix_pos[nn][mm] = fmn(static_cast<int>(mm), static_cast<int>(nn)); + else // n even + mass_matrix_pos[nn][mm] = fmn(static_cast<int>(nn), static_cast<int>(mm)); + } else { // nn and mm are both odd or both even + mass_matrix_pos[nn][mm] = (nn == mm) ? 1. / (2. * nn + 1.) : 0.; + } + } // mm + } // nn + // now calculate <v P_n P_m>_+ and <v P_n P_m>_- + for (size_t nn = 0; nn < N; ++nn) { + for (size_t mm = 0; mm < N; ++mm) { + ret_pos[nn][mm] = (nn + 1.) / (2. * nn + 1.) * mass_matrix_pos[nn + 1][mm] + + ((nn > 0) ? nn / (2. * nn + 1.) * mass_matrix_pos[nn - 1][mm] : 0.); + ret_neg[nn][mm] = mm_with_v[0][nn][mm] - ret_pos[nn][mm]; + } // mm + } // nn + // apply M^{-1} from the right + ret_neg.rightmultiply(mass_matrix_inverse()); + ret_pos.rightmultiply(mass_matrix_inverse()); + return ret; + } + + MatrixType reflection_matrix(const DomainType& n) const override final + { + MatrixType ret(dimRange, dimRange, 0); + for (size_t ii = 0; ii < dimDomain; ++ii) + if (XT::Common::FloatCmp::ne(n[ii], 0.)) + if (XT::Common::FloatCmp::ne(std::abs(n[ii]), 1.)) + DUNE_THROW(NotImplemented, "Implemented only for +-e_i where e_i is the i-th canonical basis vector!"); + const auto mass_mat = mass_matrix(); + for (size_t ii = 0; ii < dimRange; ++ii) + for (size_t jj = 0; jj < dimRange; ++jj) + ret[ii][jj] = std::pow(-1, ii) * mass_mat[ii][jj]; + ret.rightmultiply(mass_matrix_inverse()); + return ret; + } + + MatrixType S() const + { + MatrixType S(dimRange, dimRange, 0); + for (size_t rr = 0; rr < dimRange; ++rr) + S[rr][rr] = -2. * rr * (rr + 1.) / (2 * rr + 1); + return S; + } + + static StringifierType stringifier() + { + return [](const RangeType& val) { return XT::Common::to_string(val[0], 15); }; + } // ... stringifier() + + DynamicRangeType alpha_one() const override final + { + DynamicRangeType ret(dimRange, 0.); + ret[0] = 1.; + return ret; + } + + RangeFieldType density(const DynamicRangeType& u) const override final + { + return u[0]; + } + + std::string short_id() const override final + { + return ""; + } + + std::string mn_name() const override final + { + return "m" + XT::Common::to_string(order); + } + + std::string pn_name() const override final + { + return "p" + XT::Common::to_string(order); + } + +private: + static RangeFieldType fmn(const int m, const int n) + { + assert(!(m % 2)); + assert(n % 2); + // The factorials overflow for large m or n, so do it more complicated + // return (std::pow(-1., (m + n + 1) / 2) * XT::Common::factorial(m) * XT::Common::factorial(n)) + // / (std::pow(2., m + n - 1) * (m - n) * (m + n + 1) * std::pow(XT::Common::factorial(m / 2), 2) + // * std::pow(XT::Common::factorial((n - 1) / 2), 2)); + + RangeFieldType ret = 1; + int m_factor = m; + int n_factor = n; + int m_divisor = m / 2; + int n_divisor = (n - 1) / 2; + size_t max_mn = static_cast<size_t>(std::max(m, n)); + FieldVector<std::vector<RangeFieldType>, 4> factors((std::vector<RangeFieldType>(max_mn))); + assert(std::max(m, n) >= 0); + for (size_t ii = 0; ii < max_mn; ++ii) { + factors[0][ii] = m_factor > 0 ? m_factor-- : 1.; + factors[1][ii] = n_factor > 0 ? n_factor-- : 1.; + factors[2][ii] = m_divisor > 0 ? 1. / std::pow(m_divisor--, 2) : 1.; + factors[3][ii] = n_divisor > 0 ? 1. / std::pow(n_divisor--, 2) : 1.; + } + for (size_t ii = 0; ii < max_mn; ++ii) { + ret *= factors[0][ii] * factors[1][ii] * factors[2][ii] * factors[3][ii] / 2.; + } + ret *= std::pow(-1., (m + n + 1) / 2) / ((m - n) * (m + n + 1) * std::pow(2., m + n - 1 - std::max(m, n))); + return ret; + } // ... fmn(...) +}; // class LegendreMomentBasis<DomainFieldType, 1, ...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_LEGENDRE_HH diff --git a/dune/gdt/test/momentmodels/basisfunctions/partial_moments.hh b/dune/gdt/test/momentmodels/basisfunctions/partial_moments.hh new file mode 100644 index 0000000000000000000000000000000000000000..2c5b7ff8c530e65ad6532ce8c8dc74dc7ab37e8b --- /dev/null +++ b/dune/gdt/test/momentmodels/basisfunctions/partial_moments.hh @@ -0,0 +1,839 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_PARTIALMOMENTS_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_PARTIALMOMENTS_HH + +#include <boost/iostreams/stream.hpp> +#include <boost/iostreams/device/null.hpp> + +#if HAVE_QHULL +# include <dune/xt/common/disable_warnings.hh> +# include <libqhullcpp/Qhull.h> +# include <libqhullcpp/QhullFacetList.h> +# include <dune/xt/common/reenable_warnings.hh> +#endif // HAVE_QHULL + +#include <dune/xt/common/fvector.hh> + +#include "interface.hh" + +namespace Dune { +namespace GDT { + + +template <class DomainFieldType, + size_t dimDomain, + class RangeFieldType, + size_t dimRange, + size_t dimRangeCols = 1, + size_t dimFlux = dimDomain, + size_t order = 1, + EntropyType entropy = EntropyType::MaxwellBoltzmann> +class PartialMomentBasis +{ + // static_assert(false, "Not implemented for this combination of dimension and order!"); +}; + +template <class DomainFieldType, + class RangeFieldType, + size_t rangeDim, + size_t rangeDimCols, + size_t dimFlux, + EntropyType entropy> +class PartialMomentBasis<DomainFieldType, 1, RangeFieldType, rangeDim, rangeDimCols, dimFlux, 1, entropy> + : public MomentBasisInterface<DomainFieldType, 1, RangeFieldType, rangeDim, rangeDimCols, dimFlux, entropy> +{ +public: + static constexpr size_t dimDomain = 1; + static constexpr size_t dimRange = rangeDim; + static constexpr size_t dimRangeCols = rangeDimCols; + static_assert(!(dimRange % 2), "dimRange has to be even!"); + static constexpr size_t num_intervals = dimRange / 2; + +private: + using BaseType = + MomentBasisInterface<DomainFieldType, dimDomain, RangeFieldType, dimRange, dimRangeCols, dimFlux, entropy>; + +public: + using typename BaseType::DomainType; + using typename BaseType::DynamicRangeType; + using typename BaseType::MatrixType; + using typename BaseType::QuadraturesType; + using typename BaseType::RangeType; + using typename BaseType::SphericalTriangulationType; + using typename BaseType::StringifierType; + using typename BaseType::VisualizerType; + using LocalVectorType = FieldVector<RangeFieldType, 2>; + using PartitioningType = typename BaseType::Partitioning1dType; + + static std::string static_id() + { + return "pcw"; + } + + static size_t default_quad_order() + { + return 15; + } + + using BaseType::default_quad_refinements; + + PartialMomentBasis(const QuadraturesType& quadratures) + : BaseType(quadratures) + , partitioning_(BaseType::create_1d_partitioning(num_intervals)) + { + BaseType::initialize_base_values(); + } + + PartialMomentBasis(const SphericalTriangulationType& /*triangulation*/, const QuadraturesType& quadratures) + : PartialMomentBasis(quadratures) + {} + + PartialMomentBasis(const size_t quad_order = default_quad_order(), + const size_t quad_refinements = default_quad_refinements()) + : BaseType(BaseType::gauss_lobatto_quadratures(num_intervals, quad_order, quad_refinements)) + , partitioning_(BaseType::create_1d_partitioning(num_intervals)) + { + BaseType::initialize_base_values(); + } + + DynamicRangeType evaluate(const DomainType& v) const override final + { + for (size_t ii = 0; ii < num_intervals; ++ii) + if (XT::Common::FloatCmp::ge(v[0], partitioning_[ii]) && XT::Common::FloatCmp::le(v[0], partitioning_[ii + 1])) + return evaluate(v, ii); + DUNE_THROW(Dune::MathError, "v has to be between -1 and 1!"); + return DynamicRangeType(); + } // ... evaluate(...) + + // evaluate on interval ii + DynamicRangeType evaluate(const DomainType& v, const size_t ii) const override final + { + DynamicRangeType ret(dimRange, 0); + const auto local_ret = evaluate_on_interval(v, ii); + ret[2 * ii] = local_ret[0]; + ret[2 * ii + 1] = local_ret[1]; + return ret; + } // ... evaluate(...) + + LocalVectorType evaluate_on_interval(const DomainType& v, const size_t /*ii*/) const + { + return LocalVectorType{{1, v[0]}}; + } // ... evaluate(...) + + LocalVectorType evaluate_on_face(const DomainType& v, const size_t ii) const + { + return evaluate_on_interval(v, ii); + } // ... evaluate(...) + + DynamicRangeType integrated() const override final + { + DynamicRangeType ret(dimRange, 0); + for (size_t ii = 0; ii < num_intervals; ++ii) { + ret[2 * ii] = partitioning_[ii + 1] - partitioning_[ii]; + ret[2 * ii + 1] = (std::pow(partitioning_[ii + 1], 2) - std::pow(partitioning_[ii], 2)) / 2.; + } + return ret; + } + + virtual bool + is_negative(const typename XT::Data::MergedQuadrature<RangeFieldType, dimDomain>::MergedQuadratureIterator& it) + const override final + { + return it.first_index() < num_intervals / 2; + } + + // returns matrix with entries <h_i h_j> + MatrixType mass_matrix() const override final + { + MatrixType M(dimRange, dimRange, 0.); + for (size_t ii = 0; ii < num_intervals; ++ii) { + M[2 * ii][2 * ii] = partitioning_[ii + 1] - partitioning_[ii]; + M[2 * ii + 1][2 * ii + 1] = (std::pow(partitioning_[ii + 1], 3) - std::pow(partitioning_[ii], 3)) / 3.; + M[2 * ii][2 * ii + 1] = (std::pow(partitioning_[ii + 1], 2) - std::pow(partitioning_[ii], 2)) / 2.; + M[2 * ii + 1][2 * ii] = M[2 * ii][2 * ii + 1]; + } + return M; + } + + MatrixType mass_matrix_inverse() const override final + { + return tridiagonal_matrix_inverse<RangeFieldType, dimRange>(mass_matrix()); + } + + // returns matrix with entries <v h_i h_j> + FieldVector<MatrixType, dimDomain> flux_matrix() const override final + { + MatrixType B(dimRange, dimRange, 0.); + for (size_t ii = 0; ii < num_intervals; ++ii) { + B[2 * ii][2 * ii] = (std::pow(partitioning_[ii + 1], 2) - std::pow(partitioning_[ii], 2)) / 2.; + B[2 * ii + 1][2 * ii + 1] = (std::pow(partitioning_[ii + 1], 4) - std::pow(partitioning_[ii], 4)) / 4.; + B[2 * ii][2 * ii + 1] = (std::pow(partitioning_[ii + 1], 3) - std::pow(partitioning_[ii], 3)) / 3.; + B[2 * ii + 1][2 * ii] = B[2 * ii][2 * ii + 1]; + } + return FieldVector<MatrixType, dimDomain>(B); + } + + // returns V M^-1 where the matrix V has entries <v h_i h_j>_- and <v h_i h_j>_+ + FieldVector<FieldVector<MatrixType, 2>, 1> kinetic_flux_matrices() const override final + { + FieldVector<FieldVector<MatrixType, 2>, 1> ret(FieldVector<MatrixType, 2>(MatrixType(dimRange, dimRange, 0.))); + auto mm_with_v = flux_matrix(); + auto& ret_neg = ret[0][0]; + auto& ret_pos = ret[0][1]; + for (size_t ii = 0; ii < num_intervals; ++ii) { + if (num_intervals % 2) { + // if there is an odd number of intervals, the middle interval is split in 2 parts + // copy other intervals + for (size_t nn = 0; nn < num_intervals - 1; ++nn) + for (size_t mm = 0; mm < num_intervals - 1; ++mm) + ret_neg[nn][mm] = mm_with_v[0][nn][mm]; + for (size_t nn = num_intervals + 1; nn < dimRange; ++nn) + for (size_t mm = num_intervals + 1; mm < dimRange; ++mm) + ret_pos[nn][mm] = mm_with_v[0][nn][mm]; + // treat middle interval + // mixed integrals are symmetric, so ret_pos and ret_neg both get half of it + ret_neg[num_intervals - 1][num_intervals] = mm_with_v[0][num_intervals - 1][num_intervals] / 2; + ret_neg[num_intervals][num_intervals - 1] = mm_with_v[0][num_intervals][num_intervals - 1] / 2; + ret_pos[num_intervals - 1][num_intervals] = mm_with_v[0][num_intervals - 1][num_intervals] / 2; + ret_pos[num_intervals][num_intervals - 1] = mm_with_v[0][num_intervals][num_intervals - 1] / 2; + // integral corresponding to constant basis function + ret_neg[num_intervals - 1][num_intervals - 1] = -std::pow(partitioning_[num_intervals / 2], 2) / 2; + ret_pos[num_intervals - 1][num_intervals - 1] = std::pow(partitioning_[num_intervals / 2], 2) / 2; + // integral corresponding to v basis function + ret_neg[num_intervals][num_intervals] = -std::pow(partitioning_[num_intervals / 2], 4) / 4; + ret_pos[num_intervals][num_intervals] = std::pow(partitioning_[num_intervals / 2], 4) / 4; + } else { + // if there is an even number of intervals, the matrix is just split up in upper and lower part + for (size_t nn = 0; nn < num_intervals; ++nn) + for (size_t mm = 0; mm < num_intervals; ++mm) + ret_neg[nn][mm] = mm_with_v[0][nn][mm]; + for (size_t nn = num_intervals; nn < dimRange; ++nn) + for (size_t mm = num_intervals; mm < dimRange; ++mm) + ret_pos[nn][mm] = mm_with_v[0][nn][mm]; + } + } // nn + // apply M^{-1} from the right + const auto M = std::make_unique<XT::Common::FieldMatrix<RangeFieldType, dimRange, dimRange>>(mass_matrix()); + MatrixType tmp_mat = ret_neg; + for (size_t rr = 0; rr < dimRange; ++rr) + M->solve(ret_neg[rr], tmp_mat[rr]); + tmp_mat = ret_pos; + for (size_t rr = 0; rr < dimRange; ++rr) + M->solve(ret_pos[rr], tmp_mat[rr]); + return ret; + } + + MatrixType reflection_matrix(const DomainType& n) const override final + { + MatrixType ret(dimRange, dimRange, 0); + for (size_t ii = 0; ii < dimDomain; ++ii) + if (XT::Common::FloatCmp::ne(n[ii], 0.)) + if (XT::Common::FloatCmp::ne(std::abs(n[ii]), 1.)) + DUNE_THROW(NotImplemented, "Implemented only for +-e_i where e_i is the i-th canonical basis vector!"); + const auto mass_mat = mass_matrix(); + for (size_t ii = 0; ii < dimRange; ++ii) { + for (size_t jj = 0; jj < num_intervals; ++jj) { + ret[ii][2 * jj] = mass_mat[ii][dimRange - 1 - (2 * jj + 1)]; + ret[ii][2 * jj + 1] = -mass_mat[ii][dimRange - 1 - 2 * jj]; + } + } + ret.rightmultiply(mass_matrix_inverse()); + return ret; + } + + static StringifierType stringifier() + { + return [](const RangeType& val) { + RangeFieldType psi(0); + for (size_t ii = 0; ii < dimRange; ii += 2) + psi += val[ii]; + return XT::Common::to_string(psi, 15); + }; + } // ... stringifier() + + const PartitioningType& partitioning() const + { + return partitioning_; + } + + DynamicRangeType alpha_one() const override final + { + DynamicRangeType ret(dimRange, 0); + for (size_t ii = 0; ii < dimRange; ii += 2) + ret[ii] = 1.; + return ret; + } + + RangeFieldType density(const DynamicRangeType& u) const override final + { + RangeFieldType ret(0.); + for (size_t ii = 0; ii < dimRange; ii += 2) { + ret += u[ii]; + } + return ret; + } + + RangeFieldType density(const RangeType& u) const + { + RangeFieldType ret(0.); + for (size_t ii = 0; ii < dimRange; ii += 2) { + ret += u[ii]; + } + return ret; + } + + RangeFieldType density(const XT::Common::BlockedFieldVector<RangeFieldType, num_intervals, 2>& u) const + { + RangeFieldType ret(0.); + for (size_t jj = 0; jj < num_intervals; ++jj) + ret += u.block(jj)[0]; + return ret; + } + + RangeFieldType min_density(const XT::Common::BlockedFieldVector<RangeFieldType, num_intervals, 2>& u) const + { + RangeFieldType ret(u.block(0)[0]); + for (size_t jj = 1; jj < num_intervals; ++jj) + ret = std::min(ret, u.block(jj)[0]); + return ret; + } + + using BaseType::u_iso; + + // For the partial moments, we might not be able to solve the optimization problem for some moments where the density + // on one interval/spherical triangle is very low. The overall density might be much higher than the density on that + // triangle, so we specialize this function. + void ensure_min_density(DynamicRangeType& u, const RangeFieldType min_density) const override final + { + const auto u_iso_min = u_iso() * min_density; + for (size_t jj = 0; jj < num_intervals; ++jj) { + if (u[2 * jj] < u_iso_min[2 * jj]) { + u[2 * jj] = u_iso_min[2 * jj]; + u[2 * jj + 1] = u_iso_min[2 * jj + 1]; + } + } + } + + void ensure_min_density(RangeType& u, const RangeFieldType min_density) const override final + { + const auto u_iso_min = u_iso() * min_density; + for (size_t jj = 0; jj < num_intervals; ++jj) { + if (u[2 * jj] < u_iso_min[2 * jj]) { + u[2 * jj] = u_iso_min[2 * jj]; + u[2 * jj + 1] = u_iso_min[2 * jj + 1]; + } + } + } + + std::string short_id() const override final + { + return "pm"; + } + + std::string mn_name() const override final + { + return "pmm" + XT::Common::to_string(dimRange); + } + + std::string pn_name() const override final + { + return "pmp" + XT::Common::to_string(dimRange); + } + + // get indices of all faces that contain point + std::vector<size_t> get_face_indices(const DomainType& v) const + { + std::vector<size_t> face_indices; + for (size_t jj = 0; jj < partitioning_.size() - 1; ++jj) + if (XT::Common::FloatCmp::ge(v[0], partitioning_[jj]) && XT::Common::FloatCmp::le(v[0], partitioning_[jj + 1])) + face_indices.push_back(jj); + assert(face_indices.size()); + return face_indices; + } + +private: + const PartitioningType partitioning_; + using BaseType::quadratures_; +}; // class PartialMomentBasis<DomainFieldType, 1, ...> + +template <class DomainFieldType, + class RangeFieldType, + size_t rangeDim, + size_t rangeDimCols, + size_t dimFlux, + EntropyType entropy> +constexpr size_t + PartialMomentBasis<DomainFieldType, 1, RangeFieldType, rangeDim, rangeDimCols, dimFlux, 1, entropy>::dimRange; + +template <class DomainFieldType, class RangeFieldType, size_t refinements, size_t dimFlux, EntropyType entropy> +class PartialMomentBasis<DomainFieldType, 3, RangeFieldType, refinements, 1, dimFlux, 1, entropy> + : public MomentBasisInterface<DomainFieldType, + 3, + RangeFieldType, + OctaederStatistics<refinements>::num_faces() * 4, + 1, + dimFlux, + entropy> +{ +public: + static const size_t dimDomain = 3; + static const size_t dimRange = OctaederStatistics<refinements>::num_faces() * 4; + static const size_t dimRangeCols = 1; + static constexpr size_t block_size = 4; + static constexpr size_t num_blocks = dimRange / block_size; + static constexpr size_t num_refinements = refinements; + +private: + using BaseType = + MomentBasisInterface<DomainFieldType, dimDomain, RangeFieldType, dimRange, dimRangeCols, dimFlux, entropy>; + using ThisType = PartialMomentBasis; + +public: + using TriangulationType = typename BaseType::SphericalTriangulationType; + using typename BaseType::DomainType; + using typename BaseType::DynamicRangeType; + using typename BaseType::MatrixType; + using typename BaseType::QuadraturesType; + using typename BaseType::QuadratureType; + using typename BaseType::RangeType; + using typename BaseType::StringifierType; + using typename BaseType::VisualizerType; + using BlockRangeType = XT::Common::FieldVector<RangeFieldType, block_size>; + using BlockPlaneCoefficientsType = typename std::vector<std::pair<BlockRangeType, RangeFieldType>>; + using PlaneCoefficientsType = XT::Common::FieldVector<BlockPlaneCoefficientsType, num_blocks>; + using BlockMatrixType = XT::Common::BlockedFieldMatrix<RangeFieldType, num_blocks, block_size, block_size>; + using LocalMatrixType = typename BlockMatrixType::BlockType; + using LocalVectorType = XT::Common::FieldVector<RangeFieldType, block_size>; + + using BaseType::barycentre_rule; + + static size_t default_quad_order() + { + return refinements == 0 ? 15 : 9; + } + + using BaseType::default_quad_refinements; + + PartialMomentBasis(const QuadraturesType& quadratures) + : BaseType(refinements, quadratures) + { + assert(4 * triangulation_.faces().size() == dimRange); + BaseType::initialize_base_values(); + } + + PartialMomentBasis(const size_t quad_refinements, const QuadratureRule<RangeFieldType, 2>& reference_quadrature_rule) + : BaseType(refinements) + { + quadratures_ = triangulation_.quadrature_rules(quad_refinements, reference_quadrature_rule); + assert(4 * triangulation_.faces().size() == dimRange); + BaseType::initialize_base_values(); + } + + PartialMomentBasis(const TriangulationType& triangulation, const QuadraturesType& quadratures) + : BaseType(triangulation, quadratures) + { + assert(4 * triangulation_.faces().size() == dimRange); + BaseType::initialize_base_values(); + } + + PartialMomentBasis(const size_t quad_order = default_quad_order(), + const size_t quad_refinements = default_quad_refinements()) + : BaseType(refinements) + { + const QuadratureRule<RangeFieldType, 2> reference_quadrature_rule = + XT::Data::FeketeQuadrature<DomainFieldType>::get(quad_order); + quadratures_ = triangulation_.quadrature_rules(quad_refinements, reference_quadrature_rule); + assert(4 * triangulation_.faces().size() == dimRange); + BaseType::initialize_base_values(); + } + + DynamicRangeType evaluate(const DomainType& v) const override final + { + DynamicRangeType ret(dimRange, 0); + const auto face_indices = triangulation_.get_face_indices(v); + if (face_indices.size() != 1) + DUNE_THROW(Dune::MathError, + "Either v is not on the unit sphere or on a boundary between triangles where pointwise evaluation is " + "not defined for this basis!"); + return evaluate(v, face_indices[0]); + } // ... evaluate(...) + + // evaluate on spherical triangle face_index + DynamicRangeType evaluate(const DomainType& v, const size_t face_index) const override final + { + DynamicRangeType ret(dimRange, 0); + const auto local_eval = evaluate_on_face(v, face_index); + assert(4 * face_index + 3 < ret.size()); + for (size_t ii = 0; ii < 4; ++ii) + ret[4 * face_index + ii] = local_eval[ii]; + return ret; + } // ... evaluate(...) + + // evaluate on spherical triangle face_index + LocalVectorType evaluate_on_face(const DomainType& v, const size_t /*face_index*/) const + { + LocalVectorType ret; + ret[0] = 1.; + for (size_t ii = 1; ii < 4; ++ii) + ret[ii] = v[ii - 1]; + return ret; + } // ... evaluate(...) + + static StringifierType stringifier() + { + return [](const DynamicRangeType& val) { + RangeFieldType psi(0); + for (size_t ii = 0; ii < dimRange; ii += 4) + psi += val[ii]; + return XT::Common::to_string(psi, 15); + }; + } // ... stringifier() + + RangeFieldType unit_ball_volume() const override final + { + return BaseType::unit_ball_volume_quad(); + } + + DynamicRangeType alpha_one() const override final + { + DynamicRangeType ret(dimRange, 0.); + for (size_t ii = 0; ii < dimRange; ii += 4) + ret[ii] = 1.; + return ret; + } + + virtual RangeFieldType density(const RangeType& u) const + { + RangeFieldType ret(0.); + for (size_t ii = 0; ii < dimRange; ii += 4) + ret += u[ii]; + return ret; + } + + RangeFieldType density(const DynamicRangeType& u) const override final + { + RangeFieldType ret(0.); + for (size_t ii = 0; ii < dimRange; ii += 4) + ret += u[ii]; + return ret; + } + + RangeFieldType density(const XT::Common::BlockedFieldVector<RangeFieldType, dimRange / 4, 4>& u) const + { + RangeFieldType ret(0.); + for (size_t jj = 0; jj < dimRange / 4; ++jj) + ret += u.block(jj)[0]; + return ret; + } + + RangeFieldType min_density(const XT::Common::BlockedFieldVector<RangeFieldType, dimRange / 4, 4>& u) const + { + RangeFieldType ret(u.block(0)[0]); + for (size_t jj = 1; jj < dimRange / 4; ++jj) + ret = std::min(ret, u.block(jj)[0]); + return ret; + } + + using BaseType::u_iso; + + // For the partial moments, we might not be able to solve the optimization problem for some moments where the density + // on one interval/spherical triangle is very low. The overall density might be much higher than the density on that + // triangle, so we specialize this function. + void ensure_min_density(DynamicRangeType& u, const RangeFieldType min_density) const override final + { + const auto u_iso_min = u_iso() * min_density; + for (size_t jj = 0; jj < num_blocks; ++jj) { + const auto block_density = u[4 * jj]; + if (block_density < u_iso_min[4 * jj]) { + for (size_t ii = 0; ii < block_size; ++ii) + u[4 * jj + ii] = u_iso_min[4 * jj + ii]; + } + } + } + + // For the partial moments, we might not be able to solve the optimization problem for some moments where the density + // on one interval/spherical triangle is very low. The overall density might be much higher than the density on that + // triangle, so we specialize this function. + void ensure_min_density(RangeType& u, const RangeFieldType min_density) const override final + { + const auto u_iso_min = u_iso() * min_density; + for (size_t jj = 0; jj < num_blocks; ++jj) { + const auto block_density = u[4 * jj]; + if (block_density < u_iso_min[4 * jj]) { + for (size_t ii = 0; ii < block_size; ++ii) + u[4 * jj + ii] = u_iso_min[4 * jj + ii]; + } + } + } + + std::string short_id() const override final + { + return "pm"; + } + + std::string mn_name() const override final + { + return "pmm" + XT::Common::to_string(dimRange); + } + + std::string pn_name() const override final + { + return "pmp" + XT::Common::to_string(dimRange); + } + + std::vector<size_t> get_face_indices(const DomainType& v) const + { + return triangulation_.get_face_indices(v); + } + + const TriangulationType& triangulation() const + { + return triangulation_; + } + + // calculates <b(v) dirac(v-dirac_position)> + DynamicRangeType integrate_dirac_at(const DomainType& dirac_position) const + { + size_t num_faces; + auto ret = evaluate(dirac_position, true, num_faces); + if (dirac_position == DomainType{1, 0, 0}) + DXT_ASSERT(num_faces == 4); + return ret; + } + + const PlaneCoefficientsType& plane_coefficients() const + { + return plane_coefficients_; + } + + // calculate half space representation of realizable set + void calculate_plane_coefficients() const + { + XT::Common::FieldVector<std::vector<XT::Common::FieldVector<RangeFieldType, block_size>>, num_blocks> points; + for (size_t jj = 0; jj < num_blocks; ++jj) { + points[jj].resize(quadratures_[jj].size() + 1); + for (size_t ll = 0; ll < quadratures_[jj].size(); ++ll) { + const auto val = evaluate(quadratures_[jj][ll].position(), jj); + for (size_t ii = 0; ii < block_size; ++ii) + points[jj][ll][ii] = val[block_size * jj + ii]; + } // ll + points[jj][quadratures_[jj].size()] = XT::Common::FieldVector<RangeFieldType, block_size>(0.); + } + std::vector<std::thread> threads(num_blocks); + // Calculate plane coefficients for each block in a separate thread + for (size_t jj = 0; jj < num_blocks; ++jj) + threads[jj] = std::thread(&ThisType::calculate_plane_coefficients_block, this, std::ref(points[jj]), jj); + // Join the threads with the main thread + for (size_t jj = 0; jj < num_blocks; ++jj) + threads[jj].join(); + } + + virtual DynamicRangeType + get_moment_vector(const std::function<RangeFieldType(DomainType, bool)>& psi) const override final + { + DynamicRangeType ret(dimRange, 0); + for (size_t jj = 0; jj < quadratures_.size(); ++jj) { + const size_t offset = jj * block_size; + for (const auto& quad_point : quadratures_[jj]) { + const auto& v = quad_point.position(); + const auto basis_val = evaluate_on_face(v, jj); + const auto psi_val = psi(v, false); + const auto factor = psi_val * quad_point.weight(); + for (size_t ii = 0; ii < block_size; ++ii) + ret[offset + ii] += basis_val[ii] * factor; + } + } + return ret; + } + + std::unique_ptr<BlockMatrixType> block_mass_matrix() const + { + auto block_matrix = std::make_unique<BlockMatrixType>(); + parallel_quadrature_blocked(quadratures_, *block_matrix, size_t(-1)); + return block_matrix; + } // ... mass_matrix() + + MatrixType mass_matrix() const override final + { + return block_mass_matrix()->convert_to_dynamic_matrix(); + } // ... mass_matrix() + + FieldVector<MatrixType, dimFlux> flux_matrix() const override final + { + FieldVector<MatrixType, dimFlux> B(MatrixType(dimRange, dimRange, 0)); + BlockMatrixType block_matrix; + for (size_t dd = 0; dd < dimFlux; ++dd) { + parallel_quadrature_blocked(quadratures_, block_matrix, dd); + B[dd] = block_matrix.convert_to_dynamic_matrix(); + } + return B; + } + + // returns V M^-1 where V has entries <v h_i h_j>_- and <v h_i h_j>_+ + FieldVector<FieldVector<MatrixType, 2>, dimFlux> kinetic_flux_matrices() const override final + { + FieldVector<FieldVector<MatrixType, 2>, dimFlux> B_kinetic( + FieldVector<MatrixType, 2>(MatrixType(dimRange, dimRange, 0.))); + BlockMatrixType block_matrix; + const auto mass_matrix = block_mass_matrix(); + for (size_t dd = 0; dd < dimFlux; ++dd) { + QuadraturesType neg_quadratures(quadratures_.size()); + QuadraturesType pos_quadratures(quadratures_.size()); + BaseType::get_pos_and_neg_quadratures(neg_quadratures, pos_quadratures, dd); + parallel_quadrature_blocked(neg_quadratures, block_matrix, dd); + apply_invM_from_right(*mass_matrix, block_matrix, B_kinetic[dd][0]); + parallel_quadrature_blocked(pos_quadratures, block_matrix, dd); + apply_invM_from_right(*mass_matrix, block_matrix, B_kinetic[dd][1]); + } // dd + return B_kinetic; + } // ... kinetic_flux_matrices() + + +private: + void calculate_plane_coefficients_block(std::vector<XT::Common::FieldVector<RangeFieldType, block_size>>& points, + const size_t jj) const + { +#if HAVE_QHULL + orgQhull::Qhull qhull; + // ignore output + boost::iostreams::stream<boost::iostreams::null_sink> null_ostream((boost::iostreams::null_sink())); + qhull.setOutputStream(&null_ostream); + qhull.setErrorStream(&null_ostream); + // calculate convex hull + assert(points.size() < std::numeric_limits<int>::max()); + qhull.runQhull( + "Realizable set", static_cast<int>(block_size), static_cast<int>(points.size()), &(points[0][0]), "Qt T1"); + const auto facet_end = qhull.endFacet(); + BlockPlaneCoefficientsType block_plane_coefficients(qhull.facetList().count()); + // std::cout << "num_vertices: " << qhull.vertexList().count() << std::endl; + size_t ll = 0; + for (auto facet = qhull.beginFacet(); facet != facet_end; facet = facet.next(), ++ll) { + for (size_t ii = 0; ii < block_size; ++ii) + block_plane_coefficients[ll].first[ii] = *(facet.hyperplane().coordinates() + ii); + block_plane_coefficients[ll].second = -facet.hyperplane().offset(); + } // ii + // discard duplicate facets (qhull triangulates output, so there may be several facets on the same hyperplane) + using CoeffType = typename BlockPlaneCoefficientsType::value_type; + std::sort(block_plane_coefficients.begin(), + block_plane_coefficients.end(), + [](const CoeffType& first, const CoeffType& second) { + // Check component-wise if first.a[ii] < second.a[ii]. If they are equal, check next component. + for (size_t ii = 0; ii < block_size; ++ii) { + if (XT::Common::FloatCmp::lt(first.first[ii], second.first[ii])) + return true; + else if (XT::Common::FloatCmp::gt(first.first[ii], second.first[ii])) + return false; + } + // first.a and second.a are equal, check first.b and second.b + if (XT::Common::FloatCmp::lt(first.second, second.second)) + return true; + return false; + }); + static const auto pair_float_cmp = [](const CoeffType& first, const CoeffType& second) { + return XT::Common::FloatCmp::eq(first.first, second.first) + && XT::Common::FloatCmp::eq(first.second, second.second); + }; + block_plane_coefficients.erase( + std::unique(block_plane_coefficients.begin(), block_plane_coefficients.end(), pair_float_cmp), + block_plane_coefficients.end()); + // discard facets belonging to the condition u0 < 1, i.e. with a = (1, 0, 0, ...) and b = 1 + CoeffType coeff_to_erase{BlockRangeType(0), 1.}; + coeff_to_erase.first[0] = 1.; + auto coeff_to_erase_it = + std::find_if(block_plane_coefficients.begin(), + block_plane_coefficients.end(), + [&coeff_to_erase](const CoeffType& coeff) { return pair_float_cmp(coeff, coeff_to_erase); }); + if (coeff_to_erase_it == block_plane_coefficients.end()) + DUNE_THROW(Dune::MathError, "There should be such a coefficient!"); + block_plane_coefficients.erase(coeff_to_erase_it); + plane_coefficients_[jj] = block_plane_coefficients; +#else // HAVE_QHULL + DUNE_UNUSED_PARAMETER(points); + DUNE_UNUSED_PARAMETER(jj); + DUNE_THROW(Dune::NotImplemented, "You are missing Qhull!"); +#endif // HAVE_QHULL + } + + void + parallel_quadrature_blocked(const QuadraturesType& quadratures, BlockMatrixType& matrix, const size_t v_index) const + { + const size_t num_threads = std::min(XT::Common::threadManager().max_threads(), num_blocks); + std::vector<std::thread> threads(num_threads); + // Launch a group of threads + size_t blocks_done = 0; + while (blocks_done < num_blocks) { + size_t inner_loop_count = std::min(num_threads, num_blocks - blocks_done); + for (size_t jj = 0; jj < inner_loop_count; ++jj) + threads[jj] = std::thread(&ThisType::calculate_block_in_thread, + this, + std::cref(quadratures[blocks_done + jj]), + std::ref(matrix.block(blocks_done + jj)), + v_index, + blocks_done + jj); + // Join the threads with the main thread + for (size_t jj = 0; jj < inner_loop_count; ++jj) + threads[jj].join(); + blocks_done += inner_loop_count; + } + } // void parallel_quadrature(...) + + void calculate_block_in_thread(const QuadratureType& quadrature, + LocalMatrixType& local_matrix, + const size_t v_index, + const size_t jj) const + { + local_matrix *= 0.; + for (const auto& quad_point : quadrature) { + const auto& v = quad_point.position(); + const auto basis_evaluated = evaluate(v, jj); + const auto& weight = quad_point.weight(); + const auto factor = v_index == size_t(-1) ? 1. : v[v_index]; + for (size_t nn = 0; nn < local_matrix.N(); ++nn) + for (size_t mm = 0; mm < local_matrix.M(); ++mm) + local_matrix[nn][mm] += + basis_evaluated[jj * block_size + nn] * basis_evaluated[jj * block_size + mm] * factor * weight; + } + } // void calculate_in_thread(...) + + void apply_invM_from_right(const BlockMatrixType& M, BlockMatrixType& V, MatrixType& ret) const + { + LocalVectorType local_vec; + for (size_t jj = 0; jj < num_blocks; ++jj) { + for (size_t rr = 0; rr < block_size; ++rr) { + M.block(jj).solve(local_vec, V.block(jj)[rr]); + V.block(jj)[rr] = local_vec; + } // rr + } // jj + ret = V.convert_to_dynamic_matrix(); + } + + using BaseType::quadratures_; + using BaseType::triangulation_; + mutable PlaneCoefficientsType plane_coefficients_; +}; // class PartialMomentBasis<DomainFieldType, 3, ...> + +template <class DomainFieldType, class RangeFieldType, size_t refinements, size_t dimFlux, EntropyType entropy> +constexpr size_t PartialMomentBasis<DomainFieldType, 3, RangeFieldType, refinements, 1, dimFlux, 1, entropy>::dimRange; + +template <class DomainFieldType, class RangeFieldType, size_t refinements, size_t dimFlux, EntropyType entropy> +constexpr size_t + PartialMomentBasis<DomainFieldType, 3, RangeFieldType, refinements, 1, dimFlux, 1, entropy>::num_blocks; + +template <class DomainFieldType, class RangeFieldType, size_t refinements, size_t dimFlux, EntropyType entropy> +constexpr size_t + PartialMomentBasis<DomainFieldType, 3, RangeFieldType, refinements, 1, dimFlux, 1, entropy>::num_refinements; + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_PARTIALMOMENTS_HH diff --git a/dune/gdt/test/momentmodels/basisfunctions/spherical_harmonics.hh b/dune/gdt/test/momentmodels/basisfunctions/spherical_harmonics.hh new file mode 100644 index 0000000000000000000000000000000000000000..f2507df61b570c7a0cfc9860cb7a80f1eecd0e83 --- /dev/null +++ b/dune/gdt/test/momentmodels/basisfunctions/spherical_harmonics.hh @@ -0,0 +1,623 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_BASISFUNCTIONS_SPHERICALHARMONICS_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_BASISFUNCTIONS_SPHERICALHARMONICS_HH + +#include <boost/math/special_functions/legendre.hpp> +#include <boost/math/special_functions/spherical_harmonic.hpp> + +#include <dune/xt/common/coordinates.hh> + +#include "interface.hh" + +namespace Dune { +namespace GDT { + + +// TODO: use complex arithmetic, currently only usable for Pn Models in 2D, test for only_positive = false +template <class DomainFieldType, + class RangeFieldType, + size_t order, + size_t fluxDim = 3, + bool only_positive = true, + EntropyType entropy = EntropyType::MaxwellBoltzmann> +class SphericalHarmonicsMomentBasis + : public MomentBasisInterface<DomainFieldType, + 3, + RangeFieldType, + only_positive ? ((order + 1) * (order + 2)) / 2 : (order + 1) * (order + 1), + 1, + fluxDim, + entropy> +{ +public: + static const size_t dimDomain = 3; + static const size_t dimRange = only_positive ? ((order + 1) * (order + 2)) / 2 : (order + 1) * (order + 1); + static const size_t dimRangeCols = 1; + static const size_t dimFlux = fluxDim; + static const size_t num_refinements = 0; + +private: + using BaseType = MomentBasisInterface<DomainFieldType, dimDomain, RangeFieldType, dimRange, 1, dimFlux, entropy>; + +public: + using typename BaseType::DomainType; + using typename BaseType::DynamicRangeType; + using typename BaseType::MatrixType; + using typename BaseType::QuadraturesType; + using typename BaseType::RangeType; + using typename BaseType::SphericalTriangulationType; + using typename BaseType::StringifierType; + static_assert(order <= std::numeric_limits<int>::max(), ""); + + static size_t default_quad_order() + { + return 2 * order + 8; + } + + using BaseType::default_quad_refinements; + + SphericalHarmonicsMomentBasis(const QuadraturesType& quadratures) + : BaseType(quadratures) + { + BaseType::initialize_base_values(); + } + + SphericalHarmonicsMomentBasis(const SphericalTriangulationType& triangulation, const QuadraturesType& quadratures) + : BaseType(triangulation, quadratures) + { + BaseType::initialize_base_values(); + } + + SphericalHarmonicsMomentBasis(const size_t quad_order = default_quad_order(), + const size_t DXTC_DEBUG_ONLY(quad_refinements) = default_quad_refinements()) + : BaseType(XT::Data::OctantQuadratures<DomainFieldType>::get(quad_order)) + { + assert(quad_refinements == 0 && "Refinement of the quadrature intervals not implemented for this basis!"); + BaseType::initialize_base_values(); + } + + using BaseType::evaluate; + + DynamicRangeType evaluate(const DomainType& v) const override + { + const auto v_spherical = XT::Common::CoordinateConverter<DomainFieldType>::to_spherical(v); + return evaluate_in_spherical_coords(v_spherical); + } // ... evaluate(...) + + DynamicRangeType evaluate_in_spherical_coords(const FieldVector<DomainFieldType, 2>& coords) const + { + const DomainFieldType theta = coords[0]; + const DomainFieldType phi = coords[1]; + DynamicRangeType ret(dimRange, 0.); + // TODO: use complex arithmetic, remove real() call + for (unsigned int ll = 0; ll <= static_cast<unsigned int>(order); ++ll) + for (int mm = only_positive ? 0 : -static_cast<int>(ll); mm <= static_cast<int>(ll); ++mm) + ret[helper<only_positive>::pos(ll, mm)] = boost::math::spherical_harmonic(ll, mm, theta, phi).real(); + return ret; + } // ... evaluate(...) + + DynamicRangeType integrated() const override final + { + DynamicRangeType ret(dimRange, 0.); + ret[0] = std::sqrt(4. * M_PI); + return ret; + } + + MatrixType mass_matrix() const override + { + MatrixType M(dimRange, dimRange, 0); + for (size_t rr = 0; rr < dimRange; ++rr) + M[rr][rr] = 1; + return M; + } + + MatrixType mass_matrix_inverse() const override + { + return mass_matrix(); + } + + FieldVector<MatrixType, dimFlux> flux_matrix() const override + { + FieldVector<MatrixType, dimFlux> ret(MatrixType(dimRange, dimRange, 0)); + ret[0] = create_Bx(); + ret[1] = create_Bz(); + // if (dimFlux == 3) + // ret[2] = create_By(); + return ret; + } // ... flux_matrix() + + static StringifierType stringifier() + { + return [](const RangeType& val) { return XT::Common::to_string(val[0] * std::sqrt(4 * M_PI), 15); }; + } // ... stringifier() + + DynamicRangeType alpha_one() const override final + { + DynamicRangeType ret(dimRange, 0.); + ret[0] = std::sqrt(4. * M_PI); + return ret; + } + + RangeFieldType density(const DynamicRangeType& u) const override final + { + return u[0] * std::sqrt(4 * M_PI); + } + + std::string short_id() const override final + { + return ""; + } + + std::string mn_name() const override final + { + return "m" + XT::Common::to_string(order); + } + + std::string pn_name() const override final + { + return "p" + XT::Common::to_string(order); + } + +private: + static RangeFieldType A_lm(const int l, const int m) + { + assert(std::abs(m) <= l); + return std::sqrt((l + m) * (l - m) / ((2. * l + 1.) * (2. * l - 1.))); + } + + static RangeFieldType B_lm(const int l, const int m) + { + assert(std::abs(m) <= l); + return std::sqrt((l + m) * (l + m - 1.) / ((2. * l + 1.) * (2. * l - 1.))); + } + + static MatrixType create_Bx() + { + MatrixType Bx(dimRange, dimRange, 0); + const auto& pos = helper<only_positive>::pos; + for (int l1 = 0; l1 <= static_cast<int>(order); ++l1) { + for (int m1 = only_positive ? 0 : -int(l1); std::abs(m1) <= l1; ++m1) { + for (int l2 = 0; l2 <= static_cast<int>(order); ++l2) { + for (int m2 = -int(l2); std::abs(m2) <= l2; ++m2) { + size_t row = pos(l1, m1); + size_t col = pos(l2, only_positive ? std::abs(m2) : m2); + RangeFieldType factor = !only_positive ? 1. : (m2 < 0 ? std::pow(-1., m2) : 1.); + if (l1 == l2 + 1 && m1 == m2 + 1) + Bx[row][col] += -0.5 * factor * B_lm(l2 + 1, m2 + 1); + if (l1 == l2 - 1 && m1 == m2 + 1) + Bx[row][col] += 0.5 * factor * B_lm(l2, -m2); + if (l1 == l2 + 1 && m1 == m2 - 1) + Bx[row][col] += 0.5 * factor * B_lm(l2 + 1, -m2 - 1); + if (l1 == l2 - 1 && m1 == m2 - 1) + Bx[row][col] += -0.5 * factor * B_lm(l2, m2); + } // m2 + } // l2 + } // m1 + } // l1 + return Bx; + } // ... create_Bx() + + // static MatrixType create_By() + // { + // MatrixType By(dimRange, dimRange, 0); + // const auto& pos = helper<only_positive>::pos; + // for (size_t l1 = 0; l1 <= order; ++l1) { + // for (int m1 = only_positive ? 0 : -l1; size_t(std::abs(m1)) <= l1; ++m1) { + // for (size_t l2 = 0; l2 <= order; ++l2) { + // for (int m2 = -int(l2); size_t(std::abs(m2)) <= l2; ++m2) { + // size_t row = pos(l1, m1); + // size_t col = pos(l2, only_positive ? std::abs(m2) : m2); + // RangeFieldType factor = !only_positive ? 1. : (m2 < 0 ? std::pow(-1., m2) : 1.); + // if (l1 == l2 + 1 && m1 == m2 + 1) + // By[row][col] += 0.5 * factor * std::complex<RangeFieldType>(0, 1) * B_lm(l2 + 1, m2 + 1); + // if (l1 == l2 - 1 && m1 == m2 + 1) + // By[row][col] += -0.5 * factor * std::complex<RangeFieldType>(0, 1) * B_lm(l2, -m2); + // if (l1 == l2 + 1 && m1 == m2 - 1) + // By[row][col] += 0.5 * factor * std::complex<RangeFieldType>(0, 1) * B_lm(l2 + 1, -m2 - 1); + // if (l1 == l2 - 1 && m1 == m2 - 1) + // By[row][col] += -0.5 * factor * std::complex<RangeFieldType>(0, 1) * B_lm(l2, m2); + // } // m2 + // } // l2 + // } // m1 + // } // l1 + // return By; + // } // ... create_By() + + static MatrixType create_Bz() + { + MatrixType Bz(dimRange, dimRange, 0); + const auto& pos = helper<only_positive>::pos; + for (int l1 = 0; l1 <= static_cast<int>(order); ++l1) { + for (int m1 = only_positive ? 0. : -l1; std::abs(m1) <= l1; ++m1) { + for (int l2 = 0; l2 <= static_cast<int>(order); ++l2) { + size_t row = pos(l1, m1); + if (l1 == l2 + 1 && std::abs(m1) < l1) { + size_t col = pos(l2, m1); // m1 == m2, else matrix entry is 0 + Bz[row][col] += A_lm(l2 + 1, m1); + } + if (l1 == l2 - 1) { + size_t col = pos(l2, m1); // m1 == m2, else matrix entry is 0 + Bz[row][col] += A_lm(l2, m1); + } + } // l2 + } // m1 + } // l1 + return Bz; + } + + template <bool positive, class anything = void> + struct helper + { + // Converts a pair (l, m) to a vector index. The vector is ordered by l first, then by m. + // Each l has 2l+1 values of m, so (l, m) has position + // (\sum_{k=0}^{l-1} (2k+1)) + (m+l) = l^2 + m + l + static size_t pos(const int l, const int m) + { + const int ret = (l * l + m + l); + assert(ret >= 0 && std::abs(m) <= l); + return static_cast<size_t>(ret); + } + }; + + template <class anything> + struct helper<true, anything> + { + // Converts a pair (l, m) to a vector index. The vector is ordered by l first, then by m. + // Each l has l+1 non-negative values of m, so (l, m) has position + // (\sum_{k=0}^{l-1} (l+1)) + m = l(l+1)/2 + m + static size_t pos(const int l, const int m) + { + const int ret = l * (l + 1) / 2 + m; + assert(std::abs(m) <= l && ret >= 0); + return static_cast<size_t>(ret); + } + }; +}; // class SphericalHarmonicsMomentBasis<DomainFieldType, 3, ...> + +template <class DomainFieldType, + class RangeFieldType, + size_t order, + size_t fluxDim, + bool only_positive, + EntropyType entropy> +const size_t SphericalHarmonicsMomentBasis<DomainFieldType, RangeFieldType, order, fluxDim, only_positive, entropy>:: + num_refinements; + + +template <class DomainFieldType, + class RangeFieldType, + size_t order, + size_t fluxDim = 3, + bool only_even = false, + EntropyType entropy = EntropyType::MaxwellBoltzmann> +class RealSphericalHarmonicsMomentBasis + : public MomentBasisInterface<DomainFieldType, + 3, + RangeFieldType, + only_even ? ((order + 1) * (order + 2)) / 2 : (order + 1) * (order + 1), + 1, + fluxDim, + entropy> +{ +public: + static const size_t dimDomain = 3; + static const size_t dimFlux = fluxDim; + static const size_t dimRange = only_even ? ((order + 1) * (order + 2)) / 2 : (order + 1) * (order + 1); + static const size_t dimRangeCols = 1; + static const size_t num_refinements = 0; + +private: + using BaseType = MomentBasisInterface<DomainFieldType, dimDomain, RangeFieldType, dimRange, 1, dimFlux, entropy>; + +public: + using typename BaseType::DomainType; + using typename BaseType::DynamicRangeType; + using typename BaseType::MatrixType; + using typename BaseType::QuadraturesType; + using typename BaseType::RangeType; + using typename BaseType::SphericalTriangulationType; + using typename BaseType::StringifierType; + + static size_t default_quad_order() + { + return 2 * order + 8; + } + + using BaseType::default_quad_refinements; + + RealSphericalHarmonicsMomentBasis(const QuadraturesType& quadratures) + : BaseType(quadratures) + { + BaseType::initialize_base_values(); + } + + RealSphericalHarmonicsMomentBasis(const SphericalTriangulationType& triangulation, const QuadraturesType& quadratures) + : BaseType(triangulation, quadratures) + { + BaseType::initialize_base_values(); + } + + RealSphericalHarmonicsMomentBasis(const size_t quad_order = default_quad_order(), + const size_t DXTC_DEBUG_ONLY(quad_refinements) = default_quad_refinements()) + : BaseType(XT::Data::OctantQuadratures<DomainFieldType>::get(quad_order)) + { + assert(quad_refinements == 0 && "Refinement of the quadrature intervals not implemented for this basis!"); + BaseType::initialize_base_values(); + } + + using BaseType::evaluate; + + DynamicRangeType evaluate(const DomainType& v) const override + { + const auto v_spherical = XT::Common::CoordinateConverter<DomainFieldType>::to_spherical(v); + return evaluate_in_spherical_coords(v_spherical); + } // ... evaluate(...) + + DynamicRangeType evaluate_in_spherical_coords(const FieldVector<DomainFieldType, 2>& coords) const + { + const DomainFieldType theta = coords[0]; + const DomainFieldType phi = coords[1]; + DynamicRangeType ret(dimRange, 0.); + for (int ll = 0; ll <= static_cast<int>(order); ++ll) + for (int mm = -ll; mm <= ll; ++mm) + if (!only_even || !((mm + ll) % 2)) + ret[helper<only_even>::pos(ll, mm)] = evaluate_lm(theta, phi, ll, mm); + return ret; + } // ... evaluate(...) + + DynamicRangeType integrated_exactly() const + { + DynamicRangeType ret(dimRange, 0.); + ret[0] = std::sqrt(4. * M_PI); + return ret; + } + + MatrixType mass_matrix() const override + { + MatrixType M(dimRange, dimRange, 0.); + for (size_t rr = 0; rr < dimRange; ++rr) + M[rr][rr] = 1; + return M; + } + + MatrixType mass_matrix_inverse() const override + { + return mass_matrix(); + } + + FieldVector<MatrixType, dimFlux> flux_matrix() const override + { + FieldVector<MatrixType, dimFlux> ret(MatrixType(dimRange, dimRange, 0)); + ret[0] = create_Bx(); + ret[1] = create_By(); + if (dimFlux == 3) + ret[2] = create_Bz(); + return ret; + } // ... flux_matrix() + + static StringifierType stringifier() + { + return [](const RangeType& val) { return XT::Common::to_string(val[0] * std::sqrt(4 * M_PI), 15); }; + } // ... stringifier() + + DynamicRangeType alpha_one() const override final + { + DynamicRangeType ret(dimRange, 0.); + ret[0] = std::sqrt(4. * M_PI); + return ret; + } + + RangeFieldType density(const DynamicRangeType& u) const override final + { + return u[0] * std::sqrt(4 * M_PI); + } + + std::string short_id() const override final + { + return ""; + } + + std::string mn_name() const override final + { + return "m" + XT::Common::to_string(order); + } + + std::string pn_name() const override final + { + return "p" + XT::Common::to_string(order); + } + + DynamicRangeType integrate_dirac_at(const DomainType& dirac_position) const + { + return evaluate(dirac_position); + } + +private: + static RangeFieldType A_lm(const int l, const int m) + { + assert(std::abs(m) <= l); + return std::sqrt((l + m) * (l - m) / ((2. * l + 1.) * (2. * l - 1.))); + } + + static RangeFieldType B_lm(const int l, const int m) + { + assert(std::abs(m) <= l); + return std::sqrt((l + m) * (l + m - 1.) / ((2. * l + 1.) * (2. * l - 1.))); + } + + static MatrixType create_Bx() + { + MatrixType Bx(dimRange, dimRange, 0.); + const auto& pos = helper<only_even>::pos; + for (int l1 = 0; l1 <= static_cast<int>(order); ++l1) { + for (int m1 = -int(l1); std::abs(m1) <= l1; ++m1) { + for (int l2 = 0; l2 <= static_cast<int>(order); ++l2) { + for (int m2 = -int(l2); std::abs(m2) <= l2; ++m2) { + if (!only_even || (!((m1 + l1) % 2) && !((m2 + l2) % 2))) { + if (l1 == l2 - 1 && m1 == m2 - 1 && m2 > 0) + Bx[pos(l1, m1)][pos(l2, m2)] += 0.5 * std::sqrt(1. + (m2 == 1)) * B_lm(l2, m2); + if (l1 == l2 + 1 && m1 == m2 - 1 && m2 > 0) + Bx[pos(l1, m1)][pos(l2, m2)] += -0.5 * std::sqrt(1. + (m2 == 1)) * B_lm(l2 + 1, -m2 + 1); + if (l1 == l2 - 1 && m1 == m2 + 1 && m2 > 0) + Bx[pos(l1, m1)][pos(l2, m2)] += -0.5 * B_lm(l2, -m2); + if (l1 == l2 + 1 && m1 == m2 + 1 && m2 > 0) + Bx[pos(l1, m1)][pos(l2, m2)] += 0.5 * B_lm(l2 + 1, m2 + 1); + if (l1 == l2 - 1 && m1 == m2 + 1 && m2 < 0) + Bx[pos(l1, m1)][pos(l2, m2)] += 0.5 * (1. - (-m2 == 1)) * B_lm(l2, -m2); + if (l1 == l2 + 1 && m1 == m2 + 1 && m2 < 0) + Bx[pos(l1, m1)][pos(l2, m2)] += -0.5 * (1. - (-m2 == 1)) * B_lm(l2 + 1, m2 + 1); + if (l1 == l2 - 1 && m1 == m2 - 1 && m2 < 0) + Bx[pos(l1, m1)][pos(l2, m2)] += -0.5 * B_lm(l2, m2); + if (l1 == l2 + 1 && m1 == m2 - 1 && m2 < 0) + Bx[pos(l1, m1)][pos(l2, m2)] += 0.5 * B_lm(l2 + 1, -m2 + 1); + if (l1 == l2 - 1 && m1 == 1 && m2 == 0) + Bx[pos(l1, m1)][pos(l2, m2)] += -1. / std::sqrt(2.) * B_lm(l2, 0); + if (l1 == l2 + 1 && m1 == 1 && m2 == 0) + Bx[pos(l1, m1)][pos(l2, m2)] += 1. / std::sqrt(2.) * B_lm(l2 + 1, 1); + } + } // m2 + } // l2 + } // m1 + } // l1 + return Bx; + } + + static MatrixType create_By() + { + MatrixType By(dimRange, dimRange, 0.); + const auto& pos = helper<only_even>::pos; + for (int l1 = 0; l1 <= static_cast<int>(order); ++l1) { + for (int m1 = -int(l1); std::abs(m1) <= l1; ++m1) { + for (int l2 = 0; l2 <= static_cast<int>(order); ++l2) { + for (int m2 = -int(l2); std::abs(m2) <= l2; ++m2) { + if (!only_even || (!((m1 + l1) % 2) && !((m2 + l2) % 2))) { + if (l1 == l2 + 1 && m1 == -m2 + 1 && m2 > 0) + By[pos(l1, m1)][pos(l2, m2)] += 0.5 * (1. - (m2 == 1)) * B_lm(l2 + 1, -m2 + 1); + if (l1 == l2 - 1 && m1 == -m2 + 1 && m2 > 0) + By[pos(l1, m1)][pos(l2, m2)] += -0.5 * (1. - (m2 == 1)) * B_lm(l2, m2); + if (l1 == l2 - 1 && m1 == -m2 - 1 && m2 > 0) + By[pos(l1, m1)][pos(l2, m2)] += -0.5 * B_lm(l2, -m2); + if (l1 == l2 + 1 && m1 == -m2 - 1 && m2 > 0) + By[pos(l1, m1)][pos(l2, m2)] += 0.5 * B_lm(l2 + 1, m2 + 1); + if (l1 == l2 - 1 && m1 == -m2 - 1 && m2 < 0) + By[pos(l1, m1)][pos(l2, m2)] += 0.5 * std::sqrt(1. + (-m2 == 1)) * B_lm(l2, -m2); + if (l1 == l2 + 1 && m1 == -m2 - 1 && m2 < 0) + By[pos(l1, m1)][pos(l2, m2)] += -0.5 * std::sqrt(1. + (-m2 == 1)) * B_lm(l2 + 1, m2 + 1); + if (l1 == l2 - 1 && m1 == -m2 + 1 && m2 < 0) + By[pos(l1, m1)][pos(l2, m2)] += 0.5 * B_lm(l2, m2); + if (l1 == l2 + 1 && m1 == -m2 + 1 && m2 < 0) + By[pos(l1, m1)][pos(l2, m2)] += -0.5 * B_lm(l2 + 1, -m2 + 1); + if (l1 == l2 - 1 && m1 == -1 && m2 == 0) + By[pos(l1, m1)][pos(l2, m2)] += -1. / std::sqrt(2.) * B_lm(l2, 0); + if (l1 == l2 + 1 && m1 == -1 && m2 == 0) + By[pos(l1, m1)][pos(l2, m2)] += 1. / std::sqrt(2.) * B_lm(l2 + 1, 1); + } + } // m2 + } // l2 + } // m1 + } // l1 + return By; + } // ... create_By() + + static MatrixType create_Bz() + { + MatrixType Bz(dimRange, dimRange, 0); + const auto& pos = helper<only_even>::pos; + for (int l1 = 0; l1 <= static_cast<int>(order); ++l1) { + for (int m1 = -l1; std::abs(m1) <= l1; ++m1) { + for (int l2 = 0; l2 <= static_cast<int>(order); ++l2) { + for (int m2 = -l2; std::abs(m2) <= l2; ++m2) { + if (!only_even || (!((m1 + l1) % 2) && !((m2 + l2) % 2))) { + if (m1 == m2 && l1 == l2 + 1) + Bz[pos(l1, m1)][pos(l2, m2)] += A_lm(l2 + 1, m2); + if (m1 == m2 && l1 == l2 - 1) + Bz[pos(l1, m1)][pos(l2, m2)] += A_lm(l2, m2); + } + } // m2 + } // l2 + } // m1 + } // l1 + return Bz; + } // ... create_Bz() + + template <bool even, class anything = void> + struct helper + { + // Converts a pair (l, m) to a vector index. The vector is ordered by l first, then by m. + // Each l has 2l+1 values of m, so (l, m) has position + // (\sum_{k=0}^{l-1} (2k+1)) + (m+l) = l^2 + m + l + static size_t pos(const int l, const int m) + { + const int ret = l * l + m + l; + assert(ret >= 0 && std::abs(m) <= l); + return static_cast<size_t>(ret); + } + }; + + template <class anything> + struct helper<true, anything> + { + // Converts a pair (l, m) to a vector index. The vector is ordered by l first, then by m. + // Each l has l+1 values of m (as only m s.t. m+l is even are considered), so (l, m) has position + // (\sum_{k=0}^{l-1} (k+1)) + (m+l)/2 = l(l+1)/2 + (l+m)/2 + static size_t pos(const int l, const int m) + { + const int ret = l * (l + 1) / 2 + (m + l) / 2; + assert(std::abs(m) <= l && ret >= 0); + return static_cast<size_t>(ret); + } + }; + + // Notation from Garrett, Hauck, "A Comparison of Moment Closures for Linear Kinetic Transport Equations: The Line + // Source Benchmark", + // http://www.tandfonline.com/doi/full/10.1080/00411450.2014.910226?src=recsys&, Section 4.1 + RangeFieldType N_lm(const int l, const int m) const + { + static constexpr auto frac_4pi = 1. / (4. * M_PI); + assert(l >= 0 && m >= 0 && m <= l); + // return std::sqrt((2. * l + 1.) * XT::Common::factorial(l - m) / (XT::Common::factorial(l + m) * 4. * M_PI)); + auto factor = 1.; + for (int ii = l - m + 1; ii <= l + m; ++ii) + factor *= ii; + factor = 1. / factor; + return std::sqrt((2. * l + 1.) * factor * frac_4pi); + } + + RangeFieldType evaluate_lm(const DomainFieldType theta, const DomainFieldType phi, const int l, const int m) const + { + const auto cos_theta = std::cos(theta); + assert(l >= 0 && std::abs(m) <= l); + if (m < 0) + return std::sqrt(2) * N_lm(l, -m) * boost::math::legendre_p(l, -m, cos_theta) * std::sin(-m * phi); + else if (m == 0) + return N_lm(l, 0) * boost::math::legendre_p(l, 0, cos_theta); + else + return std::sqrt(2) * N_lm(l, m) * boost::math::legendre_p(l, m, cos_theta) * std::cos(m * phi); + } + + using BaseType::quadratures_; +}; // class RealSphericalHarmonicsMomentBasis<DomainFieldType, 3, ...> + +template <class DomainFieldType, + class RangeFieldType, + size_t order, + size_t fluxDim, + bool only_even, + EntropyType entropy> +const size_t RealSphericalHarmonicsMomentBasis<DomainFieldType, RangeFieldType, order, fluxDim, only_even, entropy>:: + num_refinements; + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_BASISFUNCTIONS_SPHERICALHARMONICS_HH diff --git a/dune/gdt/test/momentmodels/density_evaluations.hh b/dune/gdt/test/momentmodels/density_evaluations.hh new file mode 100644 index 0000000000000000000000000000000000000000..ff863a98f33d8520c67ada453c52eb1ca61aa87b --- /dev/null +++ b/dune/gdt/test/momentmodels/density_evaluations.hh @@ -0,0 +1,177 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2018) + +#ifndef DUNE_GDT_MOMENTMODELS_DENSITYEVALUATOR_HH +#define DUNE_GDT_MOMENTMODELS_DENSITYEVALUATOR_HH + +#include <string> +#include <functional> + +#include <dune/xt/grid/functors/interfaces.hh> +#include <dune/xt/common/parameter.hh> + +#include <dune/gdt/discretefunction/default.hh> +#include <dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh> +#include <dune/gdt/operators/interfaces.hh> +#include <dune/gdt/type_traits.hh> + +namespace Dune { +namespace GDT { + + +template <class SpaceType, class VectorType, class MomentBasis, SlopeLimiterType slope> +class LocalDensityEvaluator : public XT::Grid::ElementFunctor<typename SpaceType::GridViewType> +{ + using BaseType = XT::Grid::ElementFunctor<typename SpaceType::GridViewType>; + +public: + using GridViewType = typename SpaceType::GridViewType; + using EntityType = typename GridViewType::template Codim<0>::Entity; + using IndexSetType = typename GridViewType::IndexSet; + using EntropyFluxType = EntropyBasedFluxEntropyCoordsFunction<GridViewType, MomentBasis, slope>; + using RangeFieldType = typename EntropyFluxType::RangeFieldType; + static const size_t dimFlux = EntropyFluxType::dimFlux; + static const size_t dimRange = EntropyFluxType::basis_dimRange; + using DiscreteFunctionType = DiscreteFunction<VectorType, GridViewType, dimRange, 1, RangeFieldType>; + using ConstDiscreteFunctionType = ConstDiscreteFunction<VectorType, GridViewType, dimRange, 1, RangeFieldType>; + using DomainType = FieldVector<RangeFieldType, dimFlux>; + using BoundaryDistributionType = std::function<std::function<RangeFieldType(const DomainType&)>(const DomainType&)>; + + explicit LocalDensityEvaluator(const SpaceType& space, + const VectorType& alpha_dofs, + EntropyFluxType& analytical_flux, + const BoundaryDistributionType& boundary_distribution, + const RangeFieldType min_acceptable_density, + const XT::Common::Parameter& param) + : space_(space) + , alpha_(space_, alpha_dofs, "alpha") + , local_alpha_(alpha_.local_discrete_function()) + , analytical_flux_(analytical_flux) + , boundary_distribution_(boundary_distribution) + , min_acceptable_density_(min_acceptable_density) + , param_(param) + , index_set_(space_.grid_view().indexSet()) + {} + + explicit LocalDensityEvaluator(LocalDensityEvaluator& other) + : BaseType(other) + , space_(other.space_) + , alpha_(space_, other.alpha_.dofs().vector(), "source") + , local_alpha_(alpha_.local_discrete_function()) + , analytical_flux_(other.analytical_flux_) + , boundary_distribution_(other.boundary_distribution_) + , min_acceptable_density_(other.min_acceptable_density_) + , param_(other.param_) + , index_set_(space_.grid_view().indexSet()) + {} + + XT::Grid::ElementFunctor<GridViewType>* copy() override final + { + return new LocalDensityEvaluator(*this); + } + + void apply_local(const EntityType& entity) override final + { + local_alpha_->bind(entity); + const auto entity_index = index_set_.index(entity); + XT::Common::FieldVector<RangeFieldType, dimRange> alpha; + for (size_t ii = 0; ii < dimRange; ++ii) + alpha[ii] = local_alpha_->dofs().get_entry(ii); + analytical_flux_.store_evaluations(entity_index, alpha); + for (auto&& intersection : Dune::intersections(space_.grid_view(), entity)) + if (intersection.boundary()) + analytical_flux_.store_boundary_evaluations( + boundary_distribution_(intersection.geometry().center()), entity_index, intersection.indexInInside()); + analytical_flux_.set_eta_ast_pointers(); + } // void apply_local(...) + +private: + const SpaceType& space_; + const ConstDiscreteFunctionType alpha_; + std::unique_ptr<typename ConstDiscreteFunctionType::ConstLocalDiscreteFunctionType> local_alpha_; + EntropyFluxType& analytical_flux_; + const BoundaryDistributionType& boundary_distribution_; + const RangeFieldType min_acceptable_density_; + const XT::Common::Parameter& param_; + const typename SpaceType::GridViewType::IndexSet& index_set_; +}; // class LocalDensityEvaluator<...> + +template <class MomentBasisImp, + class SpaceImp, + SlopeLimiterType slope, + class MatrixType = typename XT::LA::Container<typename MomentBasisImp::RangeFieldType>::MatrixType> +class DensityEvaluator + : public OperatorInterface<MatrixType, typename SpaceImp::GridViewType, MomentBasisImp::dimRange, 1> +{ + using BaseType = OperatorInterface<MatrixType, typename SpaceImp::GridViewType, MomentBasisImp::dimRange, 1>; + +public: + using typename BaseType::VectorType; + using MomentBasis = MomentBasisImp; + using SpaceType = SpaceImp; + using SourceSpaceType = SpaceImp; + using RangeSpaceType = SpaceImp; + using EntropyFluxType = EntropyBasedFluxEntropyCoordsFunction<typename SpaceType::GridViewType, MomentBasis, slope>; + using RangeFieldType = typename MomentBasis::RangeFieldType; + using LocalDensityEvaluatorType = LocalDensityEvaluator<SpaceType, VectorType, MomentBasis, slope>; + using BoundaryDistributionType = typename LocalDensityEvaluatorType::BoundaryDistributionType; + + DensityEvaluator(EntropyFluxType& analytical_flux, + const SpaceType& space, + const BoundaryDistributionType& boundary_distribution, + const RangeFieldType min_acceptable_density) + : analytical_flux_(analytical_flux) + , space_(space) + , boundary_distribution_(boundary_distribution) + , min_acceptable_density_(min_acceptable_density) + {} + + bool linear() const override final + { + return false; + } + + const SourceSpaceType& source_space() const override final + { + return space_; + } + + const RangeSpaceType& range_space() const override final + { + return space_; + } + + void + apply(const VectorType& alpha, VectorType& /*range*/, const XT::Common::Parameter& param = {}) const override final + { + analytical_flux_.exp_evaluations().resize(space_.grid_view().size(0)); + if (EntropyFluxType::entropy != EntropyType::MaxwellBoltzmann) { + analytical_flux_.eta_ast_prime_evaluations().resize(space_.grid_view().size(0)); + analytical_flux_.eta_ast_twoprime_evaluations().resize(space_.grid_view().size(0)); + } + analytical_flux_.boundary_distribution_evaluations().resize(space_.grid_view().size(0)); + LocalDensityEvaluatorType local_density_evaluator( + space_, alpha, analytical_flux_, boundary_distribution_, min_acceptable_density_, param); + auto walker = XT::Grid::Walker<typename SpaceType::GridViewType>(space_.grid_view()); + walker.append(local_density_evaluator); + walker.walk(true); + } // void apply(...) + +private: + EntropyFluxType& analytical_flux_; + const SpaceType& space_; + const BoundaryDistributionType& boundary_distribution_; + const RangeFieldType min_acceptable_density_; +}; // class DensityEvaluator<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_MOMENTMODELS_DENSITYEVALUATOR_HH diff --git a/dune/gdt/test/momentmodels/entropic-coords-mn-discretization.hh b/dune/gdt/test/momentmodels/entropic-coords-mn-discretization.hh new file mode 100644 index 0000000000000000000000000000000000000000..9ea77ad2e2ac1c2baab6f9aca873b94b71c9d671 --- /dev/null +++ b/dune/gdt/test/momentmodels/entropic-coords-mn-discretization.hh @@ -0,0 +1,376 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +#ifndef DUNE_GDT_TEST_HYPERBOLIC_ENTROPIC_COORDS_MN_DISCRETIZATION_HH +#define DUNE_GDT_TEST_HYPERBOLIC_ENTROPIC_COORDS_MN_DISCRETIZATION_HH + +#include <chrono> + +#include <dune/xt/common/parallel/threadmanager.hh> +#include <dune/xt/common/string.hh> +#include <dune/xt/common/test/gtest/gtest.h> + +#include <dune/xt/grid/information.hh> +#include <dune/xt/grid/gridprovider.hh> + +#include <dune/xt/la/container.hh> + +#include <dune/gdt/discretefunction/default.hh> +#include <dune/gdt/interpolations/default.hh> +#include <dune/gdt/local/numerical-fluxes/kinetic.hh> +#include <dune/gdt/local/operators/advection-fv.hh> +#include <dune/gdt/local/operators/generic.hh> +#include <dune/gdt/operators/advection-fv.hh> +#include <dune/gdt/operators/advection-fv-entropybased.hh> +#include <dune/gdt/operators/localizable-operator.hh> +#include <dune/gdt/operators/reconstruction/linear_kinetic.hh> +#include <dune/gdt/spaces/l2/finite-volume.hh> +#include <dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh> +#include <dune/gdt/test/momentmodels/entropyflux.hh> +#include <dune/gdt/test/momentmodels/hessianinverter.hh> +#include <dune/gdt/test/momentmodels/density_evaluations.hh> +#include <dune/gdt/tools/timestepper/adaptive-rungekutta.hh> +#include <dune/gdt/tools/timestepper/explicit-rungekutta.hh> +#include <dune/gdt/tools/timestepper/fractional-step.hh> +#include <dune/gdt/tools/timestepper/matrix-exponential-kinetic-isotropic.hh> + +#include <dune/gdt/test/momentmodels/kineticequation.hh> + +#include "pn-discretization.hh" + +template <class TestCaseType> +struct HyperbolicEntropicCoordsMnDiscretization +{ + // returns: (l1norm, l2norm, linfnorm, MPI rank) + static std::pair<Dune::FieldVector<double, 3>, int> run(size_t num_save_steps = 1, + size_t num_output_steps = 0, + size_t quad_order = size_t(-1), + size_t quad_refinements = size_t(-1), + std::string grid_size = "", + size_t overlap_size = 2, + double t_end = 0., + std::string filename = "", + bool /*disable_thread_cache*/ = false) + { + using namespace Dune; + using namespace Dune::GDT; + + //******************* get typedefs and constants from ProblemType **********************// + using MomentBasis = typename TestCaseType::MomentBasis; + using DiscreteFunctionType = typename TestCaseType::DiscreteFunctionType; + using GridType = typename TestCaseType::GridType; + using SpaceType = typename TestCaseType::SpaceType; + using AdvectionSourceSpaceType = typename TestCaseType::AdvectionSourceSpaceType; + using GV = typename TestCaseType::GridViewType; + // using E = XT::Grid::extract_entity_t<GV>; + using I = XT::Grid::extract_intersection_t<GV>; + using ProblemType = typename TestCaseType::ProblemType; + using RangeFieldType = typename MomentBasis::RangeFieldType; + using BoundaryValueType = typename ProblemType::BoundaryValueType; + static constexpr size_t dimDomain = MomentBasis::dimDomain; + static constexpr size_t dimRange = MomentBasis::dimRange; + using MatrixType = typename XT::LA::Container<RangeFieldType>::MatrixType; + using VectorType = typename XT::LA::Container<RangeFieldType>::VectorType; + using GenericFunctionType = XT::Functions::GenericFunction<dimDomain, dimRange, 1, RangeFieldType>; + using DomainType = FieldVector<RangeFieldType, dimDomain>; + using RangeType = FieldVector<RangeFieldType, dimRange>; + // static const RangeFieldType scale_factor = 1e2; + + //******************* create grid and FV space *************************************** + auto grid_config = ProblemType::default_grid_cfg(); + if (!grid_size.empty()) + grid_config["num_elements"] = grid_size; + grid_config["overlap_size"] = XT::Common::to_string(overlap_size); + const auto grid_ptr = + Dune::XT::Grid::CubeGridProviderFactory<GridType>::create(grid_config, MPIHelper::getCommunicator()).grid_ptr(); + assert(grid_ptr->comm().size() == 1 || grid_ptr->overlapSize(0) > 0); + const GV grid_view(grid_ptr->leafGridView()); + const SpaceType fv_space(grid_view); + const AdvectionSourceSpaceType advection_source_space(grid_view); + + //******************* create EquationType object *************************************** + std::shared_ptr<const MomentBasis> basis_functions = std::make_shared<const MomentBasis>( + quad_order == size_t(-1) ? MomentBasis::default_quad_order() : quad_order, + quad_refinements == size_t(-1) ? MomentBasis::default_quad_refinements() : quad_refinements); + const std::unique_ptr<ProblemType> problem_ptr = + XT::Common::make_unique<ProblemType>(*basis_functions, grid_view, grid_config); + const auto& problem = *problem_ptr; + const auto initial_values_u = problem.initial_values(); + const auto boundary_values_u = problem.boundary_values(); + const auto boundary_distribution = problem.boundary_distribution(); + + using AnalyticalFluxType = typename ProblemType::FluxType; + constexpr SlopeLimiterType slope = + TestCaseType::reconstruction ? SlopeLimiterType::minmod : SlopeLimiterType::no_slope; + using EntropyFluxType = EntropyBasedFluxEntropyCoordsFunction<GV, MomentBasis, slope>; + using OldEntropyFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + auto flux = problem.flux(); + auto* entropy_flux = dynamic_cast<OldEntropyFluxType*>(flux.get()); + auto analytical_flux = std::make_unique<EntropyFluxType>(*entropy_flux); + const RangeFieldType CFL = problem.CFL(); + + // calculate boundary values for alpha + std::map<DomainType, RangeType, XT::Common::FieldVectorFloatLess> alpha_boundary_vals; + for (const auto& element : Dune::elements(grid_view)) + for (const auto& intersection : Dune::intersections(grid_view, element)) + if (intersection.boundary()) { + const auto x = intersection.geometry().center(); + const auto u = boundary_values_u->evaluate(x); + alpha_boundary_vals.insert(std::make_pair(x, analytical_flux->get_alpha(u))); + } + GenericFunctionType boundary_values_alpha( + 1, [&](const DomainType& x, const XT::Common::Parameter&) { return alpha_boundary_vals[x]; }); + + + // ***************** project initial values to discrete function ********************* + // create a discrete function for the solution + DiscreteFunctionType u(fv_space, "solution"); + DiscreteFunctionType alpha(fv_space, "solution"); + // project initial values + default_interpolation(*initial_values_u, u, grid_view); + + // convert initial values to alpha + const auto u_local_func = u.local_discrete_function(); + const auto alpha_local_func = alpha.local_discrete_function(); + XT::Common::FieldVector<RangeFieldType, dimRange> u_local; + for (auto&& element : Dune::elements(grid_view)) { + u_local_func->bind(element); + alpha_local_func->bind(element); + for (size_t ii = 0; ii < dimRange; ++ii) + u_local[ii] = u_local_func->dofs().get_entry(ii); + const auto alpha_local = analytical_flux->get_alpha(u_local); + for (size_t ii = 0; ii < dimRange; ++ii) + alpha_local_func->dofs().set_entry(ii, alpha_local[ii]); + } + + // ******************** choose flux and rhs operator and timestepper ****************************************** + + using AdvectionOperatorType = AdvectionFvOperator<MatrixType, GV, dimRange>; + using HessianInverterType = EntropicHessianInverter<MomentBasis, SpaceType, slope>; +#if 0 + using ReconstructionOperatorType = PointwiseLinearReconstructionNoCharOperator< + GV, + BoundaryValueType, + EntropyFluxType, + VectorType, + RangeType>; +#else + using ReconstructionOperatorType = + PointwiseLinearKineticReconstructionOperator<GV, BoundaryValueType, EntropyFluxType, VectorType, RangeType>; +#endif + using ReconstructionAdvectionOperatorType = + AdvectionWithPointwiseReconstructionOperator<AdvectionOperatorType, ReconstructionOperatorType>; + using NonEntropicAdvectionOperatorType = ReconstructionAdvectionOperatorType; + // using FvOperatorType = EntropicCoordinatesOperator< + // NonEntropicAdvectionOperatorType, + // HessianInverterType>; + using NonEntropicRhsOperatorType = LocalizableOperator<MatrixType, GV, dimRange>; + // using RhsOperatorType = EntropicCoordinatesOperator<NonEntropicRhsOperatorType, HessianInverterType>; + using DensityOperatorType = DensityEvaluator<MomentBasis, SpaceType, slope>; + using CombinedOperatorType = EntropicCoordinatesCombinedOperator<DensityOperatorType, + NonEntropicAdvectionOperatorType, + NonEntropicRhsOperatorType, + HessianInverterType>; + + // using OperatorTimeStepperType = + // ExplicitRungeKuttaTimeStepper<FvOperatorType, + // DiscreteFunctionType, + // TimeStepperMethods::explicit_euler>; + // using RhsTimeStepperType = + // ExplicitRungeKuttaTimeStepper<RhsOperatorType, + // DiscreteFunctionType, + // TimeStepperMethods::explicit_euler>; + + // using OperatorTimeStepperType = + // AdaptiveRungeKuttaTimeStepper<FvOperatorType, + // DiscreteFunctionType>; + // using RhsTimeStepperType = + // AdaptiveRungeKuttaTimeStepper<RhsOperatorType, + // DiscreteFunctionType>; + + // using TimeStepperType = FractionalTimeStepper<OperatorTimeStepperType, RhsTimeStepperType>; + + using TimeStepperType = + AdaptiveRungeKuttaTimeStepper<CombinedOperatorType, DiscreteFunctionType, TimeStepperMethods::dormand_prince>; + + // *************** Calculate dx and initial dt ************************************** + Dune::XT::Grid::Dimensions<GV> dimensions(grid_view); + RangeFieldType dx = dimensions.entity_width.max(); + if (dimDomain == 2) + dx /= std::sqrt(2); + if (dimDomain == 3) + dx /= std::sqrt(3); + RangeFieldType dt = CFL * dx; + + // *********************** create operators and timesteppers ************************************ + NumericalKineticFlux<GV, MomentBasis, EntropyFluxType> numerical_flux(*analytical_flux, *basis_functions); + AdvectionOperatorType advection_operator(grid_view, numerical_flux, advection_source_space, fv_space); + + // boundary treatment + using BoundaryOperator = + LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator<I, VectorType, GV, dimRange>; + using LambdaType = typename BoundaryOperator::LambdaType; + using StateType = typename BoundaryOperator::StateType; + + // calculate boundary kinetic fluxes + // apply density_operator first to store boundary_evaluations + const double min_acceptable_density = problem.psi_vac() / 10; + DensityOperatorType density_operator(*analytical_flux, fv_space, boundary_distribution, min_acceptable_density); + density_operator.apply(alpha.dofs().vector(), alpha.dofs().vector()); + + // store boundary fluxes + std::map<DomainType, RangeType, XT::Common::FieldVectorFloatLess> boundary_fluxes; + for (const auto& element : Dune::elements(grid_view)) + for (const auto& intersection : Dune::intersections(grid_view, element)) + if (intersection.boundary()) { + const auto x = intersection.geometry().center(); + const auto dd = intersection.indexInInside() / 2; + const auto boundary_flux = problem.kinetic_boundary_flux(x, intersection.centerUnitOuterNormal()[dd], dd); + boundary_fluxes.insert(std::make_pair(x, boundary_flux)); + } + GenericFunctionType boundary_kinetic_fluxes( + 1, [&](const DomainType& x, const XT::Common::Parameter&) { return boundary_fluxes[x]; }); + + + LambdaType boundary_lambda = + [&](const I& intersection, + const FieldVector<RangeFieldType, dimDomain - 1>& xx_in_reference_intersection_coordinates, + const AnalyticalFluxType& /*flux*/, + const StateType& /*u*/, + const XT::Common::Parameter& /*param*/) { + return boundary_kinetic_fluxes.evaluate( + intersection.geometry().global(xx_in_reference_intersection_coordinates)); + }; + XT::Grid::ApplyOn::NonPeriodicBoundaryIntersections<GV> filter; + advection_operator.append(boundary_lambda, {}, filter); + + ReconstructionOperatorType reconstruction_operator(boundary_values_alpha, fv_space, *analytical_flux); + ReconstructionAdvectionOperatorType reconstruction_advection_operator(advection_operator, reconstruction_operator); + + if (XT::Common::is_zero(t_end)) + t_end = problem.t_end(); + + if (!filename.empty()) + filename += "_"; + filename += "minmod_"; + filename += ProblemType::static_id(); + filename += "_grid_" + grid_config["num_elements"]; + filename += "_tend_" + XT::Common::to_string(t_end); + filename += "_quad_" + XT::Common::to_string(quad_order); + filename += TestCaseType::reconstruction ? "_ord2" : "_ord1"; + filename += "_" + basis_functions->mn_name(); + + HessianInverterType hessian_inverter(*analytical_flux, fv_space); + auto& non_entropic_advection_operator = reconstruction_advection_operator; + + const auto u_iso = basis_functions->u_iso(); + const auto basis_integrated = basis_functions->integrated(); + const auto sigma_a = problem.sigma_a(); + const auto sigma_s = problem.sigma_s(); + const auto Q = problem.Q(); + auto rhs_func = [&](const auto& /*source*/, + const auto& /*local_source*/, + auto& local_range, + const Dune::XT::Common::Parameter& /*param*/) { + const auto& element = local_range.element(); + const auto center = element.geometry().center(); + const auto u_elem = analytical_flux->get_u(fv_space.grid_view().indexSet().index(element)); + const auto sigma_a_value = sigma_a->evaluate(center)[0]; + const auto sigma_s_value = sigma_s->evaluate(center)[0]; + const auto sigma_t_value = sigma_a_value + sigma_s_value; + const auto Q_value = Q->evaluate(center)[0]; + auto ret = u_elem * (-sigma_t_value); + ret += u_iso * basis_functions->density(u_elem) * sigma_s_value; + ret += basis_integrated * Q_value; + for (size_t ii = 0; ii < local_range.dofs().size(); ++ii) + local_range.dofs()[ii] += ret[ii]; + }; + NonEntropicRhsOperatorType non_entropic_rhs_operator(grid_view, fv_space, fv_space); + non_entropic_rhs_operator.append(GenericLocalElementOperator<VectorType, GV, dimRange>(rhs_func)); + // RhsOperatorType rhs_operator(non_entropic_rhs_operator, hessian_inverter); + CombinedOperatorType combined_operator( + density_operator, non_entropic_advection_operator, non_entropic_rhs_operator, hessian_inverter); + + // ******************************** do the time steps *********************************************************** + // OperatorTimeStepperType timestepper_op(fv_operator, alpha, -1.0); + // RhsTimeStepperType timestepper_rhs(rhs_operator, alpha, 1.0); + // TimeStepperType timestepper(timestepper_op, timestepper_rhs); + TimeStepperType timestepper(combined_operator, alpha, 1.); + + auto begin_time = std::chrono::steady_clock::now(); + auto visualizer = std::make_unique<XT::Functions::GenericVisualizer<dimRange, 1, double>>( + 1, [&basis_functions, &analytical_flux](const int /*comp*/, const auto& val) { + return basis_functions->density(analytical_flux->get_u(val)); + }); + timestepper.solve(t_end, + dt, + num_save_steps, + num_output_steps, + false, + true, + true, + false, + filename, + *visualizer, + basis_functions->stringifier()); + auto end_time = std::chrono::steady_clock::now(); + std::chrono::duration<double> time_diff = end_time - begin_time; + if (grid_view.comm().rank() == 0) + std::cout << "Solving took: " << XT::Common::to_string(time_diff.count(), 15) << " s" << std::endl; + + auto ret = std::make_pair(FieldVector<double, 3>(0.), int(0)); + double& l1norm = ret.first[0]; + double& l2norm = ret.first[1]; + double& linfnorm = ret.first[2]; + ret.second = grid_view.comm().rank(); + const auto& current_sol = timestepper.current_solution(); + const auto local_sol = current_sol.local_function(); + for (const auto& entity : elements(grid_view, Dune::Partitions::interior)) { + local_sol->bind(entity); + const auto val = local_sol->evaluate(entity.geometry().local(entity.geometry().center())); + RangeFieldType psi = basis_functions->density(val); + l1norm += std::abs(psi) * entity.geometry().volume(); + l2norm += std::pow(psi, 2) * entity.geometry().volume(); + linfnorm = std::max(std::abs(psi), linfnorm); + } + l1norm = grid_view.comm().sum(l1norm); + l2norm = grid_view.comm().sum(l2norm); + linfnorm = grid_view.comm().max(linfnorm); + l2norm = std::sqrt(l2norm); + return ret; + } +}; + +template <class TestCaseType> +struct HyperbolicEntropicCoordsMnTest + : public HyperbolicEntropicCoordsMnDiscretization<TestCaseType> + , public ::testing::Test +{ + void run() + { + auto norms = HyperbolicEntropicCoordsMnDiscretization<TestCaseType>::run( + 1, + 0, + TestCaseType::quad_order, + TestCaseType::quad_refinements, + "", + 2, + TestCaseType::t_end, + "test_kinetic", + Dune::GDT::is_full_moment_basis<typename TestCaseType::MomentBasis>::value) + .first; + const double l1norm = norms[0]; + const double l2norm = norms[1]; + const double linfnorm = norms[2]; + using ResultsType = typename TestCaseType::ExpectedResultsType; + EXPECT_NEAR(ResultsType::l1norm, l1norm, ResultsType::l1norm * ResultsType::tol); + EXPECT_NEAR(ResultsType::l2norm, l2norm, ResultsType::l2norm * ResultsType::tol); + EXPECT_NEAR(ResultsType::linfnorm, linfnorm, ResultsType::linfnorm * ResultsType::tol); + } +}; + +#endif // DUNE_GDT_TEST_HYPERBOLIC_ENTROPIC_COORDS_MN_DISCRETIZATION_HH diff --git a/dune/gdt/test/momentmodels/entropyflux.hh b/dune/gdt/test/momentmodels/entropyflux.hh new file mode 100644 index 0000000000000000000000000000000000000000..e10a013de0dc4bf2225b651a554e3d0aea6bb396 --- /dev/null +++ b/dune/gdt/test/momentmodels/entropyflux.hh @@ -0,0 +1,362 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2017 - 2018) +// Tobias Leibner (2016 - 2017) +// +// Contributors: Tobias Leibner + +#ifndef DUNE_GDT_LOCAL_FLUXES_ENTROPYBASED_HH +#define DUNE_GDT_LOCAL_FLUXES_ENTROPYBASED_HH + +#include <list> +#include <memory> + +#include <dune/xt/common/float_cmp.hh> +#include <dune/xt/common/vector_less.hh> + +#include <dune/xt/functions/interfaces/flux-function.hh> + +#include <dune/gdt/test/momentmodels/basisfunctions.hh> +#include <dune/gdt/test/momentmodels/entropyflux_implementations.hh> + +namespace Dune { +namespace GDT { + + +// Caches a specified number of (u, alpha) pairs. If the cache is full and another pair is added, the oldest existing +// pair is dropped. +template <class KeyVectorType, class ValueVectorType> +class EntropyLocalCache +{ +public: + using MapType = typename std::map<KeyVectorType, ValueVectorType, XT::Common::VectorLess>; + using IteratorType = typename MapType::iterator; + using ConstIteratorType = typename MapType::const_iterator; + using RangeFieldType = typename XT::Common::VectorAbstraction<KeyVectorType>::ScalarType; + + EntropyLocalCache(const size_t capacity = 0) + : capacity_(capacity) + {} + + void insert(const KeyVectorType& u, const ValueVectorType& alpha) + { + cache_.insert(std::make_pair(u, alpha)); + keys_.push_back(u); + if (cache_.size() > capacity_) { + cache_.erase(keys_.front()); + keys_.pop_front(); + } + } + + std::pair<RangeFieldType, ConstIteratorType> find_closest(const KeyVectorType& u) const + { + ConstIteratorType ret = cache_.begin(); + if (ret == end()) + return std::make_pair(std::numeric_limits<RangeFieldType>::max(), ret); + auto diff = u - ret->first; + // use infinity_norm as distance + RangeFieldType distance = infinity_norm(diff); + auto it = ret; + while (++it != end()) { + if (XT::Common::FloatCmp::eq(distance, 0.)) + break; + diff = u - it->first; + RangeFieldType new_distance = infinity_norm(diff); + if (new_distance < distance) { + distance = new_distance; + ret = it; + } + } + return std::make_pair(distance, ret); + } + + IteratorType begin() + { + return cache_.begin(); + } + + ConstIteratorType begin() const + { + return cache_.begin(); + } + + IteratorType end() + { + return cache_.end(); + } + + ConstIteratorType end() const + { + return cache_.end(); + } + +private: + static RangeFieldType infinity_norm(const KeyVectorType& vec) + { + RangeFieldType ret = std::abs(vec[0]); + for (size_t ii = 1; ii < vec.size(); ++ii) + ret = std::max(ret, std::abs(vec[ii])); + return ret; + } + + size_t capacity_; + MapType cache_; + std::list<KeyVectorType> keys_; +}; + + +// This flux function only does the caching, which is used for providing a good initial guess and to avoid solving the +// same optimization problem twice. The actual implementations of the optimization algorithm are in +// entropyflux_implementations.hh +template <class GridViewImp, class MomentBasisImp> +class EntropyBasedFluxFunction + : public XT::Functions::FluxFunctionInterface<XT::Grid::extract_entity_t<GridViewImp>, + MomentBasisImp::dimRange, + MomentBasisImp::dimFlux, + MomentBasisImp::dimRange, + typename MomentBasisImp::R> +{ + using BaseType = typename XT::Functions::FluxFunctionInterface<XT::Grid::extract_entity_t<GridViewImp>, + MomentBasisImp::dimRange, + MomentBasisImp::dimFlux, + MomentBasisImp::dimRange, + typename MomentBasisImp::R>; + using ThisType = EntropyBasedFluxFunction; + +public: + using GridViewType = GridViewImp; + using MomentBasis = MomentBasisImp; + using IndexSetType = typename GridViewType::IndexSet; + static const size_t dimFlux = MomentBasis::dimFlux; + static const size_t basis_dimRange = MomentBasis::dimRange; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::LocalFunctionType; + using typename BaseType::RangeFieldType; + using typename BaseType::StateType; + using ImplementationType = EntropyBasedFluxImplementation<MomentBasis>; + using AlphaReturnType = typename ImplementationType::AlphaReturnType; + using VectorType = typename ImplementationType::VectorType; + using LocalCacheType = EntropyLocalCache<StateType, VectorType>; + static const size_t cache_size = 4 * dimFlux + 2; + + explicit EntropyBasedFluxFunction( + const GridViewType& grid_view, + const MomentBasis& basis_functions, + const RangeFieldType tau = 1e-9, + const bool disable_realizability_check = false, + const RangeFieldType epsilon_gamma = 0.01, + const RangeFieldType chi = 0.5, + const RangeFieldType xi = 1e-3, + const std::vector<RangeFieldType> r_sequence = {0, 1e-8, 1e-6, 1e-4, 1e-3, 1e-2, 5e-2, 0.1, 0.5, 1}, + const size_t k_0 = 500, + const size_t k_max = 1000, + const RangeFieldType epsilon = std::pow(2, -52)) + : index_set_(grid_view.indexSet()) + , use_thread_cache_(true) + , use_entity_cache_(true) + , entity_caches_(index_set_.size(0), LocalCacheType(cache_size)) + , mutexes_(index_set_.size(0)) + , implementation_(std::make_shared<ImplementationType>( + basis_functions, tau, disable_realizability_check, epsilon_gamma, chi, xi, r_sequence, k_0, k_max, epsilon)) + {} + + void enable_thread_cache() + { + use_thread_cache_ = true; + } + + void disable_thread_cache() + { + use_thread_cache_ = false; + } + + void enable_entity_cache() + { + use_entity_cache_ = true; + } + + void disable_entity_cache() + { + use_entity_cache_ = false; + } + + static const constexpr bool available = true; + + class Localfunction : public LocalFunctionType + { + using BaseType = LocalFunctionType; + + public: + using typename BaseType::DynamicJacobianRangeType; + using typename BaseType::E; + using typename BaseType::RangeReturnType; + + Localfunction(const IndexSetType& index_set, + std::vector<LocalCacheType>& entity_caches, + const bool use_thread_cache, + const bool use_entity_cache, + std::vector<std::mutex>& mutexes, + const ImplementationType& implementation) + : index_set_(index_set) + , thread_cache_(cache_size) + , entity_caches_(entity_caches) + , use_thread_cache_(use_thread_cache) + , use_entity_cache_(use_entity_cache) + , mutexes_(mutexes) + , implementation_(implementation) + {} + + void post_bind(const E& element) override final + { + const auto index = index_set_.index(element); + entity_cache_ = &(entity_caches_[index]); + mutex_ = &(mutexes_[index]); + } + + int order(const XT::Common::Parameter&) const override final + { + return 1.; + } + + std::unique_ptr<AlphaReturnType> get_alpha(const StateType& u, const bool regularize) const + { + // find starting point. Candidates: alpha_iso and the entries in the two caches + std::lock_guard<std::mutex> DUNE_UNUSED(guard)(*mutex_); + const auto& basis_functions = implementation_.basis_functions(); + static const auto u_iso = basis_functions.u_iso(); + const auto density = basis_functions.density(u); + const auto alpha_iso = basis_functions.alpha_iso(density); + const auto u_iso_scaled = u_iso * density; + // calculate (inf-norm) distance to isotropic moment with same density + RangeFieldType distance = (u - u_iso_scaled).infinity_norm(); + VectorType alpha_start = XT::Common::convert_to<VectorType>(alpha_iso); + if (!XT::Common::FloatCmp::eq(distance, 0.) && use_entity_cache_) { + // calculate distance to closest moment in entity_cache + const auto entity_cache_dist_and_it = entity_cache_->find_closest(u); + const auto& entity_cache_dist = entity_cache_dist_and_it.first; + if (entity_cache_dist < distance) { + distance = entity_cache_dist; + alpha_start = entity_cache_dist_and_it.second->second; + } + if (!XT::Common::FloatCmp::eq(distance, 0.) && use_thread_cache_) { + // calculate distance to closest moment in thread_cache + const auto thread_cache_dist_and_it = thread_cache_.find_closest(u); + const auto& thread_cache_dist = thread_cache_dist_and_it.first; + if (thread_cache_dist < distance) { + distance = thread_cache_dist; + alpha_start = thread_cache_dist_and_it.second->second; + } + } + } + // If alpha_start is already the solution, we are finished. Else start optimization. + if (XT::Common::FloatCmp::eq(distance, 0.)) { + return std::make_unique<AlphaReturnType>(std::make_pair(alpha_start, std::make_pair(u, 0.))); + } else { + auto ret = implementation_.get_alpha(u, alpha_start, regularize); + if (use_entity_cache_) + entity_cache_->insert(ret->second.first, ret->first); + if (use_thread_cache_) + thread_cache_.insert(ret->second.first, ret->first); + return ret; + } + } + + virtual RangeReturnType evaluate(const DomainType& /*point_in_reference_element*/, + const StateType& u, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = get_alpha(u, true)->first; + return implementation_.evaluate_with_alpha(alpha); + } + + virtual void jacobian(const DomainType& /*point_in_reference_element*/, + const StateType& u, + DynamicJacobianRangeType& result, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = get_alpha(u, true)->first; + implementation_.jacobian_with_alpha(alpha, result); + } // ... jacobian(...) + + private: + const IndexSetType& index_set_; + mutable LocalCacheType thread_cache_; + std::vector<LocalCacheType>& entity_caches_; + const bool use_thread_cache_; + const bool use_entity_cache_; + std::vector<std::mutex>& mutexes_; + const ImplementationType& implementation_; + LocalCacheType* entity_cache_; + std::mutex* mutex_; + }; // class Localfunction + + bool x_dependent() const override final + { + return false; + } + + std::unique_ptr<LocalFunctionType> local_function() const override final + { + return std::make_unique<Localfunction>( + index_set_, entity_caches_, use_thread_cache_, use_entity_cache_, mutexes_, *implementation_); + } + + virtual std::unique_ptr<Localfunction> derived_local_function() const + { + return std::make_unique<Localfunction>( + index_set_, entity_caches_, use_thread_cache_, use_entity_cache_, mutexes_, *implementation_); + } + + StateType evaluate_kinetic_flux(const E& inside_entity, + const E& outside_entity, + const StateType& u_i, + const StateType& u_j, + const DomainType& n_ij, + const size_t dd) const + { + // calculate \sum_{i=1}^d < \omega_i m G_\alpha(u) > n_i + const auto local_func = derived_local_function(); + local_func->bind(inside_entity); + const auto alpha_i = local_func->get_alpha(u_i, true)->first; + local_func->bind(outside_entity); + const auto alpha_j = local_func->get_alpha(u_j, true)->first; + return implementation_->evaluate_kinetic_flux_with_alphas(alpha_i, alpha_j, n_ij, dd); + } // StateType evaluate_kinetic_flux(...) + + // Returns alpha(u), starting from alpha_iso. To get better performance when calculating several alphas, use + // Localfunction's get_alpha + std::unique_ptr<AlphaReturnType> get_alpha(const StateType& u, const bool regularize) const + { + const auto& basis_functions = implementation_->basis_functions(); + const auto density = basis_functions.density(u); + auto alpha_iso = implementation_->get_isotropic_alpha(density); + return implementation_->get_alpha(u, *alpha_iso, regularize); + } + + const MomentBasis& basis_functions() const + { + return implementation_->basis_functions(); + } + + const IndexSetType& index_set_; + bool use_thread_cache_; + bool use_entity_cache_; + mutable std::vector<LocalCacheType> entity_caches_; + mutable std::vector<std::mutex> mutexes_; + std::shared_ptr<ImplementationType> implementation_; +}; + +template <class GridViewImp, class MomentBasisImp> +const size_t EntropyBasedFluxFunction<GridViewImp, MomentBasisImp>::cache_size; + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_LOCAL_FLUXES_ENTROPYBASED_HH diff --git a/dune/gdt/test/momentmodels/entropyflux_implementations.hh b/dune/gdt/test/momentmodels/entropyflux_implementations.hh new file mode 100644 index 0000000000000000000000000000000000000000..bfaabadb6ec1218add42a7dcc23891e9ffe7aa6f --- /dev/null +++ b/dune/gdt/test/momentmodels/entropyflux_implementations.hh @@ -0,0 +1,4613 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2017 - 2018) +// Tobias Leibner (2016 - 2017) +// +// Contributors: Tobias Leibner + +#ifndef DUNE_GDT_MOMENTMODELS_ENTROPYFLUX_IMPLEMENTATIONS_HH +#define DUNE_GDT_MOMENTMODELS_ENTROPYFLUX_IMPLEMENTATIONS_HH + +#include <algorithm> +#include <cmath> +#include <list> +#include <memory> + +#include <boost/align/aligned_allocator.hpp> + +#include <dune/geometry/quadraturerules.hh> + +#include <dune/xt/common/debug.hh> +#include <dune/xt/common/fmatrix.hh> +#include <dune/xt/common/fvector.hh> +#include <dune/xt/common/lapacke.hh> +#include <dune/xt/common/cblas.hh> +#include <dune/xt/common/mkl.hh> +#include <dune/xt/common/math.hh> +#include <dune/xt/common/memory.hh> +#include <dune/xt/common/parallel/threadstorage.hh> +#include <dune/xt/common/vector_less.hh> + +#include <dune/xt/la/algorithms/cholesky.hh> +#include <dune/xt/la/algorithms/solve_sym_tridiag_posdef.hh> +#include <dune/xt/la/container/common.hh> +#include <dune/xt/la/container/conversion.hh> +#include <dune/xt/la/container/eye-matrix.hh> +#include <dune/xt/la/container/pattern.hh> + +#include <dune/xt/functions/interfaces/function.hh> + +#include <dune/gdt/test/momentmodels/basisfunctions.hh> +#include <dune/gdt/type_traits.hh> + +#include "config.h" + +#if HAVE_CLP +# include <coin/ClpSimplex.hpp> +#endif // HAVE_CLP + +namespace Dune { +namespace GDT { + + +template <class T> +std::enable_if_t<std::is_arithmetic<T>::value, T> superbee(const T first_slope, const T second_slope) +{ + return XT::Common::maxmod(XT::Common::minmod(first_slope, 2. * second_slope), + XT::Common::minmod(2. * first_slope, second_slope)); +} + + +// choose specializations +#ifndef ENTROPY_FLUX_UNSPECIALIZED_USE_ADAPTIVE_CHANGE_OF_BASIS +# define ENTROPY_FLUX_UNSPECIALIZED_USE_ADAPTIVE_CHANGE_OF_BASIS 1 +#endif + +#ifndef ENTROPY_FLUX_USE_PARTIAL_MOMENTS_SPECIALIZATION +# define ENTROPY_FLUX_USE_PARTIAL_MOMENTS_SPECIALIZATION 1 +#endif + +#ifndef ENTROPY_FLUX_USE_3D_HATFUNCTIONS_SPECIALIZATION +# define ENTROPY_FLUX_USE_3D_HATFUNCTIONS_SPECIALIZATION 1 +#endif + +#ifndef ENTROPY_FLUX_USE_1D_HATFUNCTIONS_SPECIALIZATION +# define ENTROPY_FLUX_USE_1D_HATFUNCTIONS_SPECIALIZATION 1 +#endif + +#ifndef ENTROPY_FLUX_1D_HATFUNCTIONS_USE_ANALYTICAL_INTEGRALS +# define ENTROPY_FLUX_1D_HATFUNCTIONS_USE_ANALYTICAL_INTEGRALS 0 +#endif + + +enum class SlopeLimiterType +{ + minmod, + superbee, + mc, + no_slope +}; + + +/** + * Unspecialized implementation, should work with all bases + */ +template <class MomentBasisImp> +class EntropyBasedFluxImplementationUnspecializedBase + : public XT::Functions::FunctionInterface<MomentBasisImp::dimRange, + MomentBasisImp::dimFlux, + MomentBasisImp::dimRange, + typename MomentBasisImp::R> +{ + using BaseType = typename XT::Functions::FunctionInterface<MomentBasisImp::dimRange, + MomentBasisImp::dimFlux, + MomentBasisImp::dimRange, + typename MomentBasisImp::R>; + using ThisType = EntropyBasedFluxImplementationUnspecializedBase; + +public: + using MomentBasis = MomentBasisImp; + static const size_t dimFlux = MomentBasis::dimFlux; + static const size_t basis_dimRange = MomentBasis::dimRange; + using typename BaseType::DomainFieldType; + using BasisDomainType = typename MomentBasis::DomainType; + using FluxDomainType = FieldVector<DomainFieldType, dimFlux>; + using typename BaseType::DomainType; + using typename BaseType::DynamicDerivativeRangeType; + using typename BaseType::DynamicRowDerivativeRangeType; + using typename BaseType::RangeFieldType; + using typename BaseType::RangeReturnType; + // make matrices a little larger to align to 64 byte boundary + static constexpr size_t matrix_num_cols = + basis_dimRange % 8 ? basis_dimRange : basis_dimRange + (8 - basis_dimRange % 8); + using MatrixType = XT::Common::FieldMatrix<RangeFieldType, basis_dimRange, basis_dimRange>; + using VectorType = XT::Common::FieldVector<RangeFieldType, basis_dimRange>; + using DynamicRangeType = DynamicVector<RangeFieldType>; + using BasisValuesMatrixType = XT::LA::CommonDenseMatrix<RangeFieldType>; + using AlphaReturnType = std::pair<VectorType, std::pair<DomainType, RangeFieldType>>; + using QuadraturePointsType = std::vector<BasisDomainType, boost::alignment::aligned_allocator<BasisDomainType, 64>>; + using QuadratureWeightsType = std::vector<RangeFieldType, boost::alignment::aligned_allocator<RangeFieldType, 64>>; + static const EntropyType entropy = MomentBasis::entropy; + + explicit EntropyBasedFluxImplementationUnspecializedBase(const MomentBasis& basis_functions, + const RangeFieldType tau, + const bool disable_realizability_check, + const RangeFieldType epsilon_gamma, + const RangeFieldType chi, + const RangeFieldType xi, + const std::vector<RangeFieldType> r_sequence, + const size_t k_0, + const size_t k_max, + const RangeFieldType epsilon) + : basis_functions_(basis_functions) + , quad_points_(XT::Data::merged_quadrature(basis_functions_.quadratures()).size()) + , quad_weights_(quad_points_.size()) + , M_(quad_points_.size(), matrix_num_cols, 0., 0) + , tau_(tau) + , disable_realizability_check_(disable_realizability_check) + , epsilon_gamma_(epsilon_gamma) + , chi_(chi) + , xi_(xi) + , r_sequence_(r_sequence) + , k_0_(k_0) + , k_max_(k_max) + , epsilon_(epsilon) + , realizability_helper_(basis_functions_, + quad_points_, + disable_realizability_check_ +#if HAVE_CLP + , + lp_ +#endif + ) + { + size_t ll = 0; + for (const auto& quad_point : XT::Data::merged_quadrature(basis_functions_.quadratures())) { + quad_points_[ll] = quad_point.position(); + quad_weights_[ll] = quad_point.weight(); + ++ll; + } + // Join duplicate quad_points. For that purpose, first sort the vectors + const auto permutation = get_sort_permutation(quad_points_, XT::Common::VectorFloatLess{}); + apply_permutation_in_place(quad_points_, permutation); + apply_permutation_in_place(quad_weights_, permutation); + // Now join duplicate quad_points by removing all quad_points with the same position except one and adding the + // weights of the removed points to the remaining point + join_duplicate_quadpoints(quad_points_, quad_weights_); + assert(quad_points_.size() == quad_weights_.size()); + // evaluate basis functions and store in matrix + M_.resize(quad_points_.size(), matrix_num_cols); + for (ll = 0; ll < quad_points_.size(); ++ll) { + const auto val = basis_functions_.evaluate(quad_points_[ll]); + for (size_t ii = 0; ii < basis_dimRange; ++ii) + M_.set_entry(ll, ii, val[ii]); + } + } + + + // ============================================================================================ + // ============================= FunctionInterface methods ==================================== + // ============================================================================================ + + + int order(const XT::Common::Parameter& /*param*/ = {}) const override + { + return 1; + } + + virtual RangeReturnType evaluate(const DomainType& u, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = get_alpha(u, *get_isotropic_alpha(u), true)->first; + return evaluate_with_alpha(alpha); + } + + virtual RangeReturnType evaluate_with_alpha(const DomainType& alpha) const + { + RangeReturnType ret(0.); + auto& eta_ast_prime_vals = working_storage(); + evaluate_eta_ast_prime(alpha, M_, eta_ast_prime_vals); + for (size_t dd = 0; dd < dimFlux; ++dd) { + // calculate ret[dd] = < omega[dd] m G_\alpha(u) > + for (size_t ll = 0; ll < quad_weights_.size(); ++ll) { + const auto factor = eta_ast_prime_vals[ll] * quad_weights_[ll] * quad_points_[ll][dd]; + for (size_t ii = 0; ii < basis_dimRange; ++ii) + ret[dd][ii] += M_.get_entry(ll, ii) * factor; + } // ll + } // dd + return ret; + } // void evaluate(...) + + virtual void jacobian(const DomainType& u, + DynamicDerivativeRangeType& result, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = get_alpha(u, *get_isotropic_alpha(u), true)->first; + jacobian_with_alpha(alpha, result); + } + + virtual void jacobian_with_alpha(const DomainType& alpha, DynamicDerivativeRangeType& result) const + { + thread_local auto H = XT::Common::make_unique<MatrixType>(); + calculate_hessian(alpha, M_, *H); + for (size_t dd = 0; dd < dimFlux; ++dd) + row_jacobian(dd, M_, *H, result[dd], dd > 0); + } + + void row_jacobian(const size_t row, + const BasisValuesMatrixType& M, + MatrixType& H, + DynamicRowDerivativeRangeType& ret, + bool L_calculated = false) const + { + assert(row < dimFlux); + calculate_J(M, ret, row); + calculate_J_Hinv(ret, H, L_calculated); + } // void partial_u_col(...) + + + // ============================================================================================ + // ============ Evaluations of ansatz distribution, moments, hessian etc. ===================== + // ============================================================================================ + + + // Solves the minimum entropy optimization problem for u. + // returns (alpha, (actual_u, r)), where r is the regularization parameter and actual_u the regularized u + virtual std::unique_ptr<AlphaReturnType> + get_alpha(const DomainType& u, const DomainType& alpha_in, const bool regularize) const = 0; + + std::unique_ptr<AlphaReturnType> get_alpha(const DomainType& u) const + { + return get_alpha(u, *get_isotropic_alpha(u), true); + } + + // returns density rho = < eta_ast_prime(beta_in * b(v)) > + RangeFieldType get_rho(const DomainType& beta_in, const BasisValuesMatrixType& M) const + { + auto& eta_ast_prime_vals = working_storage(); + evaluate_eta_ast_prime(beta_in, M, eta_ast_prime_vals); + return std::inner_product( + quad_weights_.begin(), quad_weights_.end(), eta_ast_prime_vals.begin(), RangeFieldType(0.)); + } + + // returns < eta_ast(beta_in * b(v)) > + RangeFieldType get_eta_ast_integrated(const DomainType& beta_in, const BasisValuesMatrixType& M) const + { + auto& eta_ast_vals = working_storage(); + evaluate_eta_ast(beta_in, M, eta_ast_vals); + return std::inner_product(quad_weights_.begin(), quad_weights_.end(), eta_ast_vals.begin(), RangeFieldType(0.)); + } + + // returns < b \eta_{\ast}^{\prime}(\alpha^T b(v)) > + DomainType get_u(const DomainType& alpha) const + { + DomainType ret; + calculate_u(alpha, M_, ret); + return ret; + } + + DomainType get_u(const QuadratureWeightsType& eta_ast_prime_vals) const + { + DomainType ret(0.); + const size_t num_quad_points = quad_weights_.size(); + for (size_t ll = 0; ll < num_quad_points; ++ll) { + const auto factor_ll = eta_ast_prime_vals[ll] * quad_weights_[ll]; + const auto* basis_ll = &(M_.get_entry_ref(ll, 0.)); + for (size_t ii = 0; ii < basis_dimRange; ++ii) + ret[ii] += basis_ll[ii] * factor_ll; + } // ll + return ret; + } + + // calculate ret = < b eta_ast_prime(beta_in * b) > + void calculate_u(const DomainType& beta_in, + const BasisValuesMatrixType& M, + DomainType& ret, + bool same_beta = false, + bool only_first_component = false) const + { + auto& eta_ast_prime_vals = working_storage(); + if (!same_beta) + evaluate_eta_ast_prime(beta_in, M, eta_ast_prime_vals); + std::fill(ret.begin(), ret.end(), 0.); + const size_t num_quad_points = quad_weights_.size(); + for (size_t ll = 0; ll < num_quad_points; ++ll) { + const auto factor_ll = eta_ast_prime_vals[ll] * quad_weights_[ll]; + const auto* basis_ll = &(M.get_entry_ref(ll, 0.)); + for (size_t ii = 0; ii < (only_first_component ? 1 : basis_dimRange); ++ii) + ret[ii] += basis_ll[ii] * factor_ll; + } // ll + } + + void calculate_hessian(const DomainType& alpha, + const BasisValuesMatrixType& M, + MatrixType& H, + const bool use_stored_data = false) const + { + auto& eta_ast_twoprime_values = working_storage(); + if (!use_stored_data) + evaluate_eta_ast_twoprime(alpha, M, eta_ast_twoprime_values); + calculate_hessian(eta_ast_twoprime_values, M, H); + } // void calculate_hessian(...) + + void calculate_hessian(const QuadratureWeightsType& eta_ast_twoprime_vals, + const BasisValuesMatrixType& M, + MatrixType& H) const + { + std::fill(H.begin(), H.end(), 0.); + const size_t num_quad_points = quad_weights_.size(); + // matrix is symmetric, we only use lower triangular part + for (size_t ll = 0; ll < num_quad_points; ++ll) { + auto factor_ll = eta_ast_twoprime_vals[ll] * quad_weights_[ll]; + const auto* basis_ll = &(M.get_entry_ref(ll, 0.)); + for (size_t ii = 0; ii < basis_dimRange; ++ii) { + auto* H_row = &(H[ii][0]); + const auto factor_ll_ii = basis_ll[ii] * factor_ll; + for (size_t kk = 0; kk <= ii; ++kk) { + H_row[kk] += basis_ll[kk] * factor_ll_ii; + } // kk + } // ii + } // ll + } // void calculate_hessian(...) + + void apply_inverse_hessian(const QuadratureWeightsType& eta_ast_twoprime_vals, + const DomainType& u, + DomainType& Hinv_u) const + { + thread_local auto H = XT::Common::make_unique<MatrixType>(); + calculate_hessian(eta_ast_twoprime_vals, M_, *H); + XT::LA::cholesky(*H); + thread_local DomainType tmp_vec; + XT::LA::solve_lower_triangular(*H, tmp_vec, u); + XT::LA::solve_lower_triangular_transposed(*H, Hinv_u, tmp_vec); + } + + // J = df/dalpha is the derivative of the flux with respect to alpha. + // As F = (f_1, f_2, f_3) is matrix-valued + // (div f = \sum_{i=1}^d \partial_{x_i} f_i = \sum_{i=1}^d \partial_{x_i} < v_i m \hat{psi}(alpha) > is + // vector-valued), + // the derivative is the vector of matrices (df_1/dalpha, df_2/dalpha, ...) + // this function returns the dd-th matrix df_dd/dalpha of J + // assumes eta_ast_twoprime_values already contains the needed \eta_{\ast}^{\prime \prime} (\alpha * m) values + void calculate_J(const BasisValuesMatrixType& M, DynamicRowDerivativeRangeType& J_dd, const size_t dd) const + { + assert(dd < dimFlux); + const auto& eta_ast_twoprime_values = working_storage(); + J_dd.set_all_entries(0.); + const size_t num_quad_points = quad_points_.size(); + for (size_t ll = 0; ll < num_quad_points; ++ll) { + const auto factor_ll = eta_ast_twoprime_values[ll] * quad_points_[ll][dd] * quad_weights_[ll]; + const auto* basis_ll = &(M.get_entry_ref(ll, 0.)); + for (size_t ii = 0; ii < basis_dimRange; ++ii) { + const auto factor_ll_ii = factor_ll * basis_ll[ii]; + if (!XT::Common::is_zero(factor_ll_ii)) { + for (size_t kk = 0; kk <= ii; ++kk) + J_dd.unsafe_add_to_entry(ii, kk, basis_ll[kk] * factor_ll_ii); + } + } // ii + } // ll + // symmetric update for upper triangular part of J + for (size_t mm = 0; mm < basis_dimRange; ++mm) + for (size_t nn = mm + 1; nn < basis_dimRange; ++nn) + J_dd.set_entry(mm, nn, J_dd.get_entry(nn, mm)); + } // void calculate_J(...) + + // calculates J = J H^{-1}. H is assumed to be symmetric positive definite. + static void calculate_J_Hinv(DynamicRowDerivativeRangeType& A, MatrixType& B, bool L_calculated = false) + { + // if B = LL^T, then we have to calculate ret = A (L^T)^{-1} L^{-1} = C L^{-1} + // calculate B = LL^T first + if (!L_calculated) + XT::LA::cholesky(B); + VectorType tmp_vec; + for (size_t ii = 0; ii < basis_dimRange; ++ii) { + // calculate C = A (L^T)^{-1} and store in B + auto&& row_view = A[ii]; + XT::LA::solve_lower_triangular(B, tmp_vec, row_view); + // calculate ret = C L^{-1} + XT::LA::solve_lower_triangular_transposed(B, row_view, tmp_vec); + } // ii + } // void calculate_J_Hinv(...) + + + // ============================================================================================ + // ============================= Entropy evaluations ========================================== + // ============================================================================================ + + + // evaluates \eta_{\ast}(\alpha^T b(v_i)) for all quadrature points v_i + void evaluate_eta_ast(const DomainType& alpha, const BasisValuesMatrixType& M, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, M, ret); + apply_exponential(ret); + evaluate_eta_ast(ret); + } + + // evaluates \eta_{\ast}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already contains + // exp(alpha^T b(v_i)) + void evaluate_eta_ast(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t ll = 0; ll < ret.size(); ++ll) + ret[ll] = -std::log(1 - ret[ll]); + } + + // evaluates \eta_{\ast}^{\prime}(\alpha^T b(v_i)) for all quadrature points v_i + void evaluate_eta_ast_prime(const DomainType& alpha, const BasisValuesMatrixType& M, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, M, ret); + apply_exponential(ret); + evaluate_eta_ast_prime(ret); + } + + // evaluates \eta_{\ast}^{\prime}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already contains + // exp(alpha^T b(v_i)) + void evaluate_eta_ast_prime(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t ll = 0; ll < ret.size(); ++ll) + ret[ll] /= (1 - ret[ll]); + } + + // evaluates \eta_{\ast}^{\prime\prime}(\alpha^T b(v_i)) for all quadrature points v_i + void + evaluate_eta_ast_twoprime(const DomainType& alpha, const BasisValuesMatrixType& M, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, M, ret); + apply_exponential(ret); + evaluate_eta_ast_twoprime(ret); + } + + // evaluates \eta_{\ast}^{\prime\prime}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already + // contains exp(alpha^T b(v_i)) + void evaluate_eta_ast_twoprime(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t ll = 0; ll < ret.size(); ++ll) + ret[ll] /= std::pow(1 - ret[ll], 2); + } + + // stores evaluations of exp(alpha^T b(v_i)) for all quadrature points v_i + void store_exp_evaluations(QuadratureWeightsType& exp_evaluations, const DomainType& alpha) const + { + exp_evaluations.resize(quad_points_.size()); + this->calculate_scalar_products(alpha, M_, exp_evaluations); + this->apply_exponential(exp_evaluations); + } + + void store_eta_ast_prime_vals(const QuadratureWeightsType& exp_evaluations, QuadratureWeightsType& eta_ast_prime_vals) + { + eta_ast_prime_vals = exp_evaluations; + evaluate_eta_ast_prime(eta_ast_prime_vals); + } + + void store_eta_ast_twoprime_vals(const QuadratureWeightsType& exp_evaluations, + QuadratureWeightsType& eta_ast_twoprime_vals) + { + eta_ast_twoprime_vals = exp_evaluations; + evaluate_eta_ast_twoprime(eta_ast_twoprime_vals); + } + + // stores evaluations of a given boundary distribution psi(v) at all quadrature points v_i + void store_boundary_distribution_evaluations( + QuadratureWeightsType& boundary_distribution_evaluations, + const std::function<RangeFieldType(const FluxDomainType&)>& boundary_distribution) const + { + boundary_distribution_evaluations.resize(quad_points_.size()); + for (size_t ll = 0; ll < quad_points_.size(); ++ll) + boundary_distribution_evaluations[ll] = boundary_distribution(quad_points_[ll]); + } + + + // ============================================================================================ + // =============================== Kinetic fluxes ============================================= + // ============================================================================================ + + + // calculate \sum_{i=1}^d < v_i m \psi > n_i, where n is the unit outer normal, + // m is the basis function vector, \psi is the ansatz corresponding to u + // and x, v, t are the space, velocity and time variable, respectively + // As we are using cartesian grids, n_i == 0 in all but one dimension, so only evaluate for i == dd + DomainType + evaluate_kinetic_flux(const DomainType& u_i, const DomainType& u_j, const FluxDomainType& n_ij, const size_t dd) const + { + // calculate \sum_{i=1}^d < \omega_i m G_\alpha(u) > n_i + const auto alpha_i = get_alpha(u_i, *get_isotropic_alpha(u_i), true)->first; + const auto alpha_j = get_alpha(u_j, *get_isotropic_alpha(u_j), true)->first; + evaluate_kinetic_flux_with_alphas(alpha_i, alpha_j, n_ij, dd); + } // DomainType evaluate_kinetic_flux(...) + + DomainType evaluate_kinetic_flux_with_alphas(const DomainType& alpha_i, + const DomainType& alpha_j, + const FluxDomainType& n_ij, + const size_t dd) const + + { + thread_local FieldVector<QuadratureWeightsType, 2> eta_ast_prime_vals; + eta_ast_prime_vals[0].resize(quad_points_.size()); + eta_ast_prime_vals[1].resize(quad_points_.size()); + evaluate_eta_ast_prime(alpha_i, M_, eta_ast_prime_vals[0]); + evaluate_eta_ast_prime(alpha_j, M_, eta_ast_prime_vals[1]); + DomainType ret(0); + for (size_t ll = 0; ll < quad_points_.size(); ++ll) { + const auto position = quad_points_[ll][dd]; + RangeFieldType factor = position * n_ij[dd] > 0. ? eta_ast_prime_vals[0][ll] : eta_ast_prime_vals[1][ll]; + factor *= quad_weights_[ll] * position; + const auto* basis_ll = &(M_.get_entry_ref(ll, 0.)); + for (size_t ii = 0; ii < basis_dimRange; ++ii) + ret[ii] += basis_ll[ii] * factor; + } // ll + ret *= n_ij[dd]; + return ret; + } // DomainType evaluate_kinetic_flux_with_alphas(...) + + // Calculates left and right kinetic flux with reconstructed densities. Ansatz distribution values contains + // evaluations of the ansatz distribution at each quadrature point for a stencil of three entities. The distributions + // are reconstructed pointwise for each quadrature point and the resulting (part of) the kinetic flux is < + // psi_reconstr * b * v>_{+/-}. + template <SlopeLimiterType slope_type, class FluxesMapType> + void calculate_reconstructed_fluxes(const FieldVector<const QuadratureWeightsType*, 3>& ansatz_distribution_values, + FluxesMapType& flux_values, + const size_t dd) const + { + // get left and right reconstructed values for each quadrature point v_i + thread_local XT::Common::FieldVector<QuadratureWeightsType, 2> reconstructed_values( + QuadratureWeightsType(quad_points_.size())); + auto& vals_left = reconstructed_values[0]; + auto& vals_right = reconstructed_values[1]; + if (slope_type == SlopeLimiterType::no_slope) { + for (size_t ll = 0; ll < quad_points_.size(); ++ll) + vals_left[ll] = vals_right[ll] = (*ansatz_distribution_values[1])[ll]; + } else { + const auto slope_func = + (slope_type == SlopeLimiterType::minmod) ? XT::Common::minmod<RangeFieldType> : superbee<RangeFieldType>; + for (size_t ll = 0; ll < quad_points_.size(); ++ll) { + const auto slope = slope_func((*ansatz_distribution_values[1])[ll] - (*ansatz_distribution_values[0])[ll], + (*ansatz_distribution_values[2])[ll] - (*ansatz_distribution_values[1])[ll]); + vals_left[ll] = (*ansatz_distribution_values[1])[ll] - 0.5 * slope; + vals_right[ll] = (*ansatz_distribution_values[1])[ll] + 0.5 * slope; + } // ll + } + + BasisDomainType coord(0.5); + coord[dd] = 0; + auto& left_flux_value = flux_values[coord]; + coord[dd] = 1; + auto& right_flux_value = flux_values[coord]; + right_flux_value = left_flux_value = DomainType(0.); + + for (size_t ll = 0; ll < quad_points_.size(); ++ll) { + const auto position = quad_points_[ll][dd]; + RangeFieldType factor = position > 0. ? vals_right[ll] : vals_left[ll]; + factor *= quad_weights_[ll] * position; + auto& val = position > 0. ? right_flux_value : left_flux_value; + const auto* basis_ll = &(M_.get_entry_ref(ll, 0.)); + for (size_t ii = 0; ii < basis_dimRange; ++ii) + val[ii] += basis_ll[ii] * factor; + } // ll + } // void calculate_reconstructed_fluxes(...) + + + // ============================================================================================ + // ================================== Helper functions ======================================== + // ============================================================================================ + + + // get permutation instead of sorting directly to be able to sort two vectors the same way + // see + // https://stackoverflow.com/questions/17074324/how-can-i-sort-two-vectors-in-the-same-way-with-criteria-that-uses-only-one-of + template <class T, class Alloc, class Compare> + static std::vector<std::size_t> get_sort_permutation(const std::vector<T, Alloc>& vec, const Compare& compare) + { + std::vector<std::size_t> p(vec.size()); + std::iota(p.begin(), p.end(), 0); + std::sort(p.begin(), p.end(), [&](std::size_t i, std::size_t j) { return compare(vec[i], vec[j]); }); + return p; + } + + template <class T, class Alloc> + static void apply_permutation_in_place(std::vector<T, Alloc>& vec, const std::vector<std::size_t>& p) + { + std::vector<bool> done(vec.size()); + for (std::size_t i = 0; i < vec.size(); ++i) { + if (done[i]) { + continue; + } + done[i] = true; + std::size_t prev_j = i; + std::size_t j = p[i]; + while (i != j) { + std::swap(vec[prev_j], vec[j]); + done[j] = true; + prev_j = j; + j = p[j]; + } + } + } + + // Joins duplicate quadpoints, vectors have to be sorted! + static void join_duplicate_quadpoints(QuadraturePointsType& quad_points, QuadratureWeightsType& quad_weights) + { + // Index of first quad_point of several quad_points with the same position + size_t curr_index = 0; + std::vector<size_t> indices_to_remove; + for (size_t ll = 1; ll < quad_weights.size(); ++ll) { + if (XT::Common::FloatCmp::eq(quad_points[curr_index], quad_points[ll])) { + quad_weights[curr_index] += quad_weights[ll]; + indices_to_remove.push_back(ll); + } else { + curr_index = ll; + } + } // ll + assert(indices_to_remove.size() < std::numeric_limits<int>::max()); + // remove duplicate points, from back to front to avoid invalidating indices + for (int ll = static_cast<int>(indices_to_remove.size()) - 1; ll >= 0; --ll) { + quad_points.erase(quad_points.begin() + indices_to_remove[ll]); + quad_weights.erase(quad_weights.begin() + indices_to_remove[ll]); + } + } + + // temporary vectors to store inner products and exponentials + QuadratureWeightsType& working_storage() const + { + thread_local QuadratureWeightsType work_vec; + work_vec.resize(quad_points_.size()); + return work_vec; + } + + bool all_positive(const QuadratureWeightsType& vals) const + { + for (size_t ll = 0; ll < quad_points_.size(); ++ll) { + const auto val = vals[ll]; + if (val < 0. || std::isinf(val) || std::isnan(val)) + return false; + } + return true; + } + + void copy_transposed(const MatrixType& T_k, MatrixType& T_k_trans) const + { + for (size_t ii = 0; ii < basis_dimRange; ++ii) + for (size_t jj = 0; jj <= ii; ++jj) + T_k_trans[jj][ii] = T_k[ii][jj]; + } + + // calculates alpha^T b(v_i) for all quadrature points v_i + void calculate_scalar_products(const DomainType& beta_in, + const BasisValuesMatrixType& M, + QuadratureWeightsType& scalar_products) const + { +#if HAVE_MKL + XT::Common::Cblas::dgemv(XT::Common::Cblas::row_major(), + XT::Common::Cblas::no_trans(), + static_cast<int>(quad_points_.size()), + basis_dimRange, + 1., + M.data(), + matrix_num_cols, + &(beta_in[0]), + 1, + 0., + scalar_products.data(), + 1); +#else + const size_t num_quad_points = quad_points_.size(); + for (size_t ll = 0; ll < num_quad_points; ++ll) { + const auto* basis_ll = &(M.get_entry_ref(ll, 0.)); + scalar_products[ll] = std::inner_product(beta_in.begin(), beta_in.end(), basis_ll, 0.); + } +#endif + } + + // calculates exp(val) for all vals in values + void apply_exponential(QuadratureWeightsType& values) const + { + assert(values.size() < std::numeric_limits<int>::max()); + XT::Common::Mkl::exp(static_cast<int>(values.size()), values.data(), values.data()); + } + + const MomentBasis& basis_functions() const + { + return basis_functions_; + } + + std::unique_ptr<VectorType> get_isotropic_alpha(const RangeFieldType density) const + { + return std::make_unique<VectorType>(basis_functions_.alpha_iso(density)); + } + + std::unique_ptr<VectorType> get_isotropic_alpha(const DomainType& u) const + { + return get_isotropic_alpha(basis_functions_.density(u)); + } + +#if HAVE_CLP + template <class BasisFuncImp = MomentBasis, bool anything = true> + struct RealizabilityHelper + { + static_assert(std::is_same<BasisFuncImp, MomentBasis>::value, "BasisFuncImp has to be MomentBasis!"); + + RealizabilityHelper(const MomentBasis& basis_functions, + const QuadraturePointsType& quad_points, + const bool /*disable_realizability_check*/, + XT::Common::PerThreadValue<std::unique_ptr<ClpSimplex>>& lp) + : basis_functions_(basis_functions) + , quad_points_(quad_points) + , lp_(lp) + {} + + // The ClpSimplex structure seems to get corrupted sometimes (maybe some problems with infs/NaNs?), so we + // reinitialize it if the stopping conditions is always false + void setup_linear_program(const bool reinitialize) const + { + if (!*lp_ || reinitialize) { + // We start with creating a model with basis_dimRange rows and num_quad_points columns */ + constexpr int num_rows = static_cast<int>(basis_dimRange); + assert(quad_points_.size() < std::numeric_limits<int>::max()); + int num_cols = static_cast<int>(quad_points_.size()); /* variables are x_1, ..., x_{num_quad_points} */ + *lp_ = std::make_unique<ClpSimplex>(false); + auto& lp = **lp_; + // set number of rows + lp.resize(num_rows, 0); + + // Clp wants the row indices that are non-zero in each column. We have a dense matrix, so provide all indices + // 0..num_rows + std::array<int, num_rows> row_indices; + for (int ii = 0; ii < num_rows; ++ii) + row_indices[static_cast<size_t>(ii)] = ii; + + // set columns for quadrature points + for (int ii = 0; ii < num_cols; ++ii) { + const auto v_i = basis_functions_.evaluate(quad_points_[static_cast<size_t>(ii)]); + // First argument: number of elements in column + // Second/Third argument: indices/values of column entries + // Fourth/Fifth argument: lower/upper column bound, i.e. lower/upper bound for x_i. As all x_i should be + // positive, set to 0/inf, which is the default. + // Sixth argument: Prefactor in objective for x_i, this is 0 for all x_i, which is also the default; + lp.addColumn(num_rows, row_indices.data(), &(v_i[0])); + } + + // silence lp + lp.setLogLevel(0); + } // if (!lp_) + } + + bool is_realizable(const DomainType& u, const bool reinitialize) const + { + const auto density = basis_functions_.density(u); + if (!(density > 0.) || std::isinf(density)) + return false; + const auto phi = u / density; + setup_linear_program(reinitialize); + auto& lp = **lp_; + constexpr int num_rows = static_cast<int>(basis_dimRange); + // set rhs (equality constraints, so set both bounds equal + for (int ii = 0; ii < num_rows; ++ii) { + size_t uii = static_cast<size_t>(ii); + lp.setRowLower(ii, phi[uii]); + lp.setRowUpper(ii, phi[uii]); + } + // set maximal wall time. If this is not set, in rare cases the primal method never returns + lp.setMaximumWallSeconds(60); + // Now check solvability + lp.primal(); + return lp.primalFeasible(); + } + + const MomentBasis& basis_functions_; + const QuadraturePointsType& quad_points_; + XT::Common::PerThreadValue<std::unique_ptr<ClpSimplex>>& lp_; + }; // struct RealizabilityHelper<...> +#else // HAVE_CLP + template <class BasisFuncImp = MomentBasis, bool anything = true> + struct RealizabilityHelper + { + RealizabilityHelper(const MomentBasis& /*basis_functions*/, + const QuadraturePointsType& /*quad_points*/, + const bool disable_realizability_check) + { + if (!disable_realizability_check) + std::cerr << "Warning: You are missing Clp, realizability stopping condition will not be checked!" << std::endl; + } + + bool is_realizable(const DomainType& /*u*/, const bool /*reinitialize*/) const + { + return true; + } + }; // struct RealizabilityHelper<...> +#endif // HAVE_CLP + + // specialization for hatfunctions + template <size_t dimRange_or_refinements, bool anything> + struct RealizabilityHelper< + HatFunctionMomentBasis<DomainFieldType, dimFlux, RangeFieldType, dimRange_or_refinements, 1, dimFlux>, + anything> + { + RealizabilityHelper(const MomentBasis& /*basis_functions*/, + const std::vector<BasisDomainType>& /*quad_points*/, + const bool /*disable_realizability_check*/ +#if HAVE_CLP + , + XT::Common::PerThreadValue<std::unique_ptr<ClpSimplex>>& /*lp*/) +#else + ) +#endif + {} + + static bool is_realizable(const DomainType& u, const bool /*reinitialize*/) + { + for (const auto& u_i : u) + if (!(u_i > 0.) || std::isinf(u_i)) + return false; + return true; + } + }; // struct RealizabilityHelper<Hatfunctions, ...> + + // For each basis evaluation b, calculates T_k^{-1} b. As the basis evaluations are the rows of M, we want to + // calculate (T_k^{-1} M^T)^T = M T_k^{-T} + void apply_inverse_matrix(const MatrixType& T_k, BasisValuesMatrixType& M) const + { +#if HAVE_MKL + // Calculate the transpose here first as this is much faster than passing the matrix to dtrsm and using CblasTrans + thread_local auto T_k_trans = std::make_unique<MatrixType>(0.); + copy_transposed(T_k, *T_k_trans); + assert(quad_points_.size() < std::numeric_limits<int>::max()); + XT::Common::Cblas::dtrsm(XT::Common::Cblas::row_major(), + XT::Common::Cblas::right(), + XT::Common::Cblas::upper(), + XT::Common::Cblas::no_trans(), + XT::Common::Cblas::non_unit(), + static_cast<int>(quad_points_.size()), + basis_dimRange, + 1., + &((*T_k_trans)[0][0]), + basis_dimRange, + M.data(), + matrix_num_cols); +#else + assert(quad_points_.size() == M.rows()); + VectorType tmp_vec, tmp_vec2; + for (size_t ll = 0; ll < quad_points_.size(); ++ll) { + auto* M_row = &(M.get_entry_ref(ll, 0.)); + std::copy_n(M_row, basis_dimRange, tmp_vec.begin()); + XT::LA::solve_lower_triangular(T_k, tmp_vec2, tmp_vec); + std::copy_n(tmp_vec2.begin(), basis_dimRange, M_row); + } +#endif + } + + const MomentBasis& basis_functions_; + QuadraturePointsType quad_points_; + QuadratureWeightsType quad_weights_; + BasisValuesMatrixType M_; + const RangeFieldType tau_; + const bool disable_realizability_check_; + const RangeFieldType epsilon_gamma_; + const RangeFieldType chi_; + const RangeFieldType xi_; + const std::vector<RangeFieldType> r_sequence_; + const size_t k_0_; + const size_t k_max_; + const RangeFieldType epsilon_; + const RealizabilityHelper<> realizability_helper_; +#if HAVE_CLP + mutable XT::Common::PerThreadValue<std::unique_ptr<ClpSimplex>> lp_; +#endif +}; + +#if ENTROPY_FLUX_UNSPECIALIZED_USE_ADAPTIVE_CHANGE_OF_BASIS +/** Analytical flux \mathbf{f}(\mathbf{u}) = < \mu \mathbf{m} G_{\hat{\alpha}(\mathbf{u})} >, + * for the notation see + * Alldredge, Hauck, O'Leary, Tits, "Adaptive change of basis in entropy-based moment closures for linear kinetic + * equations" + */ +template <class MomentBasisImp> +class EntropyBasedFluxImplementation : public EntropyBasedFluxImplementationUnspecializedBase<MomentBasisImp> +{ + using BaseType = EntropyBasedFluxImplementationUnspecializedBase<MomentBasisImp>; + using ThisType = EntropyBasedFluxImplementation; + +public: + using BaseType::basis_dimRange; + using BaseType::dimFlux; + using BaseType::entropy; + using typename BaseType::AlphaReturnType; + using typename BaseType::BasisDomainType; + using typename BaseType::BasisValuesMatrixType; + using typename BaseType::DomainType; + using typename BaseType::FluxDomainType; + using typename BaseType::MatrixType; + using typename BaseType::MomentBasis; + using typename BaseType::QuadratureWeightsType; + using typename BaseType::RangeFieldType; + using typename BaseType::VectorType; + + explicit EntropyBasedFluxImplementation(const MomentBasis& basis_functions, + const RangeFieldType tau, + const bool disable_realizability_check, + const RangeFieldType epsilon_gamma, + const RangeFieldType chi, + const RangeFieldType xi, + const std::vector<RangeFieldType> r_sequence, + const size_t k_0, + const size_t k_max, + const RangeFieldType epsilon) + : BaseType( + basis_functions, tau, disable_realizability_check, epsilon_gamma, chi, xi, r_sequence, k_0, k_max, epsilon) + , T_minus_one_(std::make_unique<MatrixType>()) + { + XT::LA::eye_matrix(*T_minus_one_); + } + + using BaseType::get_alpha; + + virtual std::unique_ptr<AlphaReturnType> + get_alpha(const DomainType& u, const DomainType& alpha_in, const bool regularize) const override final + { + auto ret = std::make_unique<AlphaReturnType>(); + + // rescale u such that the density <psi> is 1 + RangeFieldType density = basis_functions_.density(u); + static const auto alpha_one = basis_functions_.alpha_one(); + if (!(density > 0.) || std::isinf(density)) + DUNE_THROW(Dune::MathError, "Negative, inf or NaN density!"); + + constexpr bool rescale = (entropy == EntropyType::MaxwellBoltzmann); + + VectorType phi = rescale ? u / density : u; + VectorType alpha_initial = rescale ? alpha_in - alpha_one * std::log(density) : alpha_in; + VectorType beta_in = alpha_initial; + VectorType v, u_eps_diff, g_k, beta_out; + RangeFieldType first_error_cond, second_error_cond, tau_prime; + + const auto u_iso = rescale ? basis_functions_.u_iso() : basis_functions_.u_iso() * density; + const RangeFieldType dim_factor = is_full_moment_basis<MomentBasis>::value ? 1. : std::sqrt(dimFlux); + tau_prime = + rescale ? std::min(tau_ / ((1 + dim_factor * phi.two_norm()) * density + dim_factor * tau_), tau_) : tau_; + + thread_local auto T_k = XT::Common::make_unique<MatrixType>(); + + const auto& r_sequence = regularize ? r_sequence_ : std::vector<RangeFieldType>{0.}; + const auto r_max = r_sequence.back(); + for (const auto& rr : r_sequence) { + // regularize u + v = phi; + if (rr > 0) { + beta_in = *get_isotropic_alpha(v); + VectorType r_times_u_iso = u_iso; + r_times_u_iso *= rr; + v *= 1 - rr; + v += r_times_u_iso; + } + *T_k = *T_minus_one_; + // calculate T_k u + VectorType v_k = v; + // calculate values of basis p = S_k m + thread_local BasisValuesMatrixType P_k(M_.backend(), false, 0., 0); + std::copy_n(M_.data(), M_.rows() * M_.cols(), P_k.data()); + // calculate f_0 + RangeFieldType f_k = get_eta_ast_integrated(beta_in, P_k); + f_k -= beta_in * v_k; + + thread_local auto H = XT::Common::make_unique<MatrixType>(0.); + + int backtracking_failed = 0; + for (size_t kk = 0; kk < k_max_; ++kk) { + // exit inner for loop to increase rr if too many iterations are used or cholesky decomposition fails + if (kk > k_0_ && rr < r_max) + break; + try { + change_basis(beta_in, v_k, P_k, *T_k, g_k, beta_out, *H); + } catch (const Dune::MathError&) { + if (rr < r_max) + break; + const std::string err_msg = + "Failed to converge for " + XT::Common::to_string(u) + " with density " + XT::Common::to_string(density) + + " and multiplier " + XT::Common::to_string(beta_in) + + " due to errors in change_basis! Last u_eps_diff = " + XT::Common::to_string(u_eps_diff) + + ", first_error_cond = " + XT::Common::to_string(first_error_cond) + ", second_error_cond = " + + XT::Common::to_string(second_error_cond) + ", tau_prime = " + XT::Common::to_string(tau_prime); + DUNE_THROW(MathError, err_msg); + } + // calculate descent direction d_k; + VectorType d_k = g_k; + d_k *= -1; + + // Calculate values for stopping criteria (in original basis). + VectorType alpha_tilde, d_alpha_tilde; + XT::LA::solve_lower_triangular_transposed(*T_k, alpha_tilde, beta_out); + XT::LA::solve_lower_triangular_transposed(*T_k, d_alpha_tilde, d_k); + VectorType u_alpha_tilde; + calculate_u(alpha_tilde, M_, u_alpha_tilde); + VectorType g_alpha_tilde = u_alpha_tilde - v; + auto density_tilde = basis_functions_.density(u_alpha_tilde); + if (!(density_tilde > 0.) || std::isinf(density_tilde)) + break; + + // if rescale == true, we ensure that the ansatz density exactly matches the density of u + const auto alpha_prime = rescale ? alpha_tilde - alpha_one * std::log(density_tilde) : alpha_tilde; + VectorType u_alpha_prime; + if (rescale) + calculate_u(alpha_prime, M_, u_alpha_prime); + else + u_alpha_prime = u_alpha_tilde; + + // calculate stopping criteria + u_eps_diff = v - u_alpha_prime * (1 - epsilon_gamma_); + first_error_cond = g_alpha_tilde.two_norm(); + second_error_cond = std::exp( + -(rescale ? d_alpha_tilde.one_norm() + std::abs(std::log(density_tilde)) : d_alpha_tilde.one_norm())); + // working_storage contains eta_ast_prime evaluations due to the calculate_u call above + const auto& eta_ast_prime_vals = working_storage(); + if (first_error_cond < tau_prime && 1 - epsilon_gamma_ < second_error_cond + && (entropy == EntropyType::MaxwellBoltzmann || all_positive(eta_ast_prime_vals)) + && (disable_realizability_check_ + || realizability_helper_.is_realizable(u_eps_diff, kk == static_cast<size_t>(0.8 * k_0_)))) { + ret->first = rescale ? alpha_prime + alpha_one * std::log(density) : alpha_prime; + ret->second = std::make_pair(rescale ? v * density : v, rr); + return ret; + } else { + RangeFieldType zeta_k = 1; + beta_in = beta_out; + // backtracking line search + while (backtracking_failed >= 2 || zeta_k > epsilon_ * beta_out.two_norm() / d_k.two_norm()) { + VectorType beta_new = d_k; + beta_new *= zeta_k; + beta_new += beta_out; + RangeFieldType f = get_eta_ast_integrated(beta_new, P_k); + f -= beta_new * v_k; + if (backtracking_failed >= 2 || XT::Common::FloatCmp::le(f, f_k + xi_ * zeta_k * (g_k * d_k))) { + beta_in = beta_new; + f_k = f; + backtracking_failed = 0; + break; + } + zeta_k = chi_ * zeta_k; + } // backtracking linesearch while + if (zeta_k <= epsilon_ * beta_out.two_norm() / d_k.two_norm()) + ++backtracking_failed; + } // else (stopping conditions) + } // k loop (Newton iterations) + } // rr loop (Regularization parameter) + const std::string err_msg = "Failed to converge for " + XT::Common::to_string(u) + " with density " + + XT::Common::to_string(density) + " and multiplier " + XT::Common::to_string(beta_in) + + " due to too many iterations! Last u_eps_diff = " + XT::Common::to_string(u_eps_diff) + + ", first_error_cond = " + XT::Common::to_string(first_error_cond) + + ", second_error_cond = " + XT::Common::to_string(second_error_cond) + + ", tau_prime = " + XT::Common::to_string(tau_prime); + DUNE_THROW(MathError, err_msg); + + return ret; + } + + using BaseType::all_positive; + using BaseType::apply_inverse_matrix; + using BaseType::calculate_hessian; + using BaseType::calculate_u; + using BaseType::get_eta_ast_integrated; + using BaseType::get_isotropic_alpha; + using BaseType::working_storage; + + void change_basis(const DomainType& beta_in, + DomainType& v_k, + BasisValuesMatrixType& P_k, + MatrixType& T_k, + DomainType& g_k, + DomainType& beta_out, + MatrixType& H) const + { + calculate_hessian(beta_in, P_k, H); + XT::LA::cholesky(H); + const auto& L = H; + thread_local std::unique_ptr<MatrixType> tmp_mat = std::make_unique<MatrixType>(); + *tmp_mat = T_k; + rightmultiply(T_k, *tmp_mat, L); + L.mtv(beta_in, beta_out); + VectorType tmp_vec; + XT::LA::solve_lower_triangular(L, tmp_vec, v_k); + v_k = tmp_vec; + apply_inverse_matrix(L, P_k); + calculate_u(beta_out, P_k, g_k, false); + g_k -= v_k; + } // void change_basis(...) + + using BaseType::basis_functions_; + using BaseType::chi_; + using BaseType::disable_realizability_check_; + using BaseType::epsilon_; + using BaseType::epsilon_gamma_; + using BaseType::k_0_; + using BaseType::k_max_; + using BaseType::M_; + using BaseType::quad_points_; + using BaseType::quad_weights_; + using BaseType::r_sequence_; + using BaseType::realizability_helper_; + using BaseType::tau_; + using BaseType::xi_; + const std::unique_ptr<MatrixType> T_minus_one_; +}; + +#else // ENTROPY_FLUX_UNSPECIALIZED_USE_ADAPTIVE_CHANGE_OF_BASIS + +/** Analytical flux \mathbf{f}(\mathbf{u}) = < \mu \mathbf{m} G_{\hat{\alpha}(\mathbf{u})} >, + * Simple backtracking Newton without change of basis + */ +template <class MomentBasisImp> +class EntropyBasedFluxImplementation : public EntropyBasedFluxImplementationUnspecializedBase<MomentBasisImp> +{ + using BaseType = EntropyBasedFluxImplementationUnspecializedBase<MomentBasisImp>; + using ThisType = EntropyBasedFluxImplementation; + +public: + using BaseType::dimFlux; + using BaseType::entropy; + using typename BaseType::AlphaReturnType; + using typename BaseType::BasisValuesMatrixType; + using typename BaseType::DomainType; + using typename BaseType::MatrixType; + using typename BaseType::MomentBasis; + using typename BaseType::RangeFieldType; + using typename BaseType::VectorType; + + explicit EntropyBasedFluxImplementation(const MomentBasis& basis_functions, + const RangeFieldType tau, + const bool disable_realizability_check, + const RangeFieldType epsilon_gamma, + const RangeFieldType chi, + const RangeFieldType xi, + const std::vector<RangeFieldType> r_sequence, + const size_t k_0, + const size_t k_max, + const RangeFieldType epsilon) + : BaseType( + basis_functions, tau, disable_realizability_check, epsilon_gamma, chi, xi, r_sequence, k_0, k_max, epsilon) + {} + + std::unique_ptr<AlphaReturnType> get_alpha(const DomainType& u) const + { + return get_alpha(u, *get_isotropic_alpha(u), true); + } + + // returns (alpha, (actual_u, r)), where r is the regularization parameter and actual_u the regularized u + virtual std::unique_ptr<AlphaReturnType> + get_alpha(const DomainType& u, const DomainType& alpha_in, const bool regularize) const override final + { + auto ret = std::make_unique<AlphaReturnType>(); + RangeFieldType density = basis_functions_.density(u); + static const auto alpha_one = basis_functions_.alpha_one(); + if (!(density > 0.) || std::isinf(density)) + DUNE_THROW(Dune::MathError, "Negative, inf or NaN density!"); + + constexpr bool rescale = (entropy == EntropyType::MaxwellBoltzmann); + + VectorType phi = rescale ? u / density : u; + VectorType alpha_initial = rescale ? alpha_in - alpha_one * std::log(density) : alpha_in; + VectorType v, g_k, d_k, tmp_vec, alpha_prime; + RangeFieldType first_error_cond, second_error_cond, tau_prime; + auto u_iso = rescale ? basis_functions_.u_iso() : basis_functions_.u_iso() * density; + const RangeFieldType dim_factor = is_full_moment_basis<MomentBasis>::value ? 1. : std::sqrt(dimFlux); + tau_prime = + rescale ? std::min(tau_ / ((1 + dim_factor * phi.two_norm()) * density + dim_factor * tau_), tau_) : tau_; + VectorType alpha_k = alpha_initial; + const auto& r_sequence = regularize ? r_sequence_ : std::vector<RangeFieldType>{0.}; + const auto r_max = r_sequence.back(); + for (const auto& rr : r_sequence) { + // regularize u + v = phi; + if (rr > 0) { + alpha_k = *get_isotropic_alpha(v); + VectorType r_times_u_iso = u_iso; + r_times_u_iso *= rr; + v *= 1 - rr; + v += r_times_u_iso; + } + // calculate T_k u + VectorType v_k = v; + // calculate f_0 + RangeFieldType f_k = get_eta_ast_integrated(alpha_k, M_); + f_k -= alpha_k * v_k; + + thread_local auto H = XT::Common::make_unique<MatrixType>(0.); + + int backtracking_failed = 0; + for (size_t kk = 0; kk < k_max_; ++kk) { + // exit inner for loop to increase rr if too many iterations are used + if (kk > k_0_ && rr < r_max) + break; + // calculate gradient g + calculate_u(alpha_k, M_, g_k); + g_k -= v_k; + // calculate Hessian H + calculate_hessian(alpha_k, M_, *H, entropy == EntropyType::MaxwellBoltzmann); + // calculate descent direction d_k; + d_k = g_k; + d_k *= -1; + try { + // if H = LL^T, then we have to calculate d_k = - L^{-T} L^{-1} g_k + // calculate H = LL^T first + XT::LA::cholesky(*H); + // calculate d_tmp = -L^{-1} g_k and store in B + XT::LA::solve_lower_triangular(*H, tmp_vec, d_k); + // calculate d_k = L^{-T} d_tmp + XT::LA::solve_lower_triangular_transposed(*H, d_k, tmp_vec); + } catch (const Dune::MathError&) { + if (rr < r_max) + break; + const std::string err_msg = + "Failed to converge for " + XT::Common::to_string(u) + " with density " + XT::Common::to_string(density); + DUNE_THROW(MathError, err_msg); + } + + const auto& alpha_tilde = alpha_k; + auto& u_alpha_tilde = tmp_vec; + u_alpha_tilde = g_k + v; + auto density_tilde = basis_functions_.density(u_alpha_tilde); + if (!(density_tilde > 0.) || std::isinf(density_tilde)) + break; + auto& u_eps_diff = tmp_vec; + alpha_prime = alpha_tilde; + if (rescale) { + alpha_prime -= alpha_one * std::log(density_tilde); + calculate_u(alpha_prime, M_, u_eps_diff); + } else { + u_eps_diff = u_alpha_tilde; + } + u_eps_diff *= -(1 - epsilon_gamma_); + u_eps_diff += v; + + first_error_cond = g_k.two_norm(); + second_error_cond = std::exp(-(rescale ? d_k.one_norm() + std::abs(std::log(density_tilde)) : d_k.one_norm())); + auto& eta_ast_prime_vals = working_storage(); + // if rescale is true, working storage already contains the eta_ast_prime evaluations due to the call to + // calculate_u above + if (!rescale) + evaluate_eta_ast_prime(alpha_prime, M_, eta_ast_prime_vals); + if (first_error_cond < tau_prime && 1 - epsilon_gamma_ < second_error_cond + && (entropy == EntropyType::MaxwellBoltzmann || all_positive(eta_ast_prime_vals)) + && (disable_realizability_check_ + || realizability_helper_.is_realizable(u_eps_diff, kk == static_cast<size_t>(0.8 * k_0_)))) { + ret->first = rescale ? alpha_prime + alpha_one * std::log(density) : alpha_prime; + ret->second = std::make_pair(rescale ? v * density : v, rr); + return ret; + } else { + RangeFieldType zeta_k = 1; + // backtracking line search + auto& alpha_new = tmp_vec; + while (backtracking_failed >= 2 || zeta_k > epsilon_ * alpha_k.two_norm() / d_k.two_norm()) { + // calculate alpha_new = alpha_k + zeta_k d_k + alpha_new = d_k; + alpha_new *= zeta_k; + alpha_new += alpha_k; + // calculate f(alpha_new) + RangeFieldType f_new = get_eta_ast_integrated(alpha_new, M_); + f_new -= alpha_new * v_k; + if (backtracking_failed >= 2 || XT::Common::FloatCmp::le(f_new, f_k + xi_ * zeta_k * (g_k * d_k))) { + alpha_k = alpha_new; + f_k = f_new; + backtracking_failed = 0; + break; + } + zeta_k = chi_ * zeta_k; + } // backtracking linesearch while + // if (zeta_k <= epsilon_ * alpha_k.two_norm() / d_k.two_norm() * 100.) + if (zeta_k <= epsilon_ * alpha_k.two_norm() / d_k.two_norm()) + ++backtracking_failed; + } // else (stopping conditions) + } // k loop (Newton iterations) + } // rr loop (Regularization parameter) + const std::string err_msg = + "Failed to converge for " + XT::Common::to_string(u) + " with density " + XT::Common::to_string(density); + DUNE_THROW(MathError, err_msg); + return ret; + } + + using BaseType::all_positive; + using BaseType::calculate_hessian; + using BaseType::calculate_u; + using BaseType::evaluate_eta_ast_prime; + using BaseType::get_eta_ast_integrated; + using BaseType::get_isotropic_alpha; + using BaseType::working_storage; + + using BaseType::basis_functions_; + using BaseType::chi_; + using BaseType::disable_realizability_check_; + using BaseType::epsilon_; + using BaseType::epsilon_gamma_; + using BaseType::k_0_; + using BaseType::k_max_; + using BaseType::M_; + using BaseType::quad_points_; + using BaseType::quad_weights_; + using BaseType::r_sequence_; + using BaseType::realizability_helper_; + using BaseType::tau_; + using BaseType::xi_; +}; +#endif + +#if ENTROPY_FLUX_USE_PARTIAL_MOMENTS_SPECIALIZATION +/** + * Specialization for DG basis + */ +template <class D, size_t d, class R, size_t dimRange_or_refinements, size_t fluxDim, EntropyType entropy> +class EntropyBasedFluxImplementation<PartialMomentBasis<D, d, R, dimRange_or_refinements, 1, fluxDim, 1, entropy>> + : public XT::Functions::FunctionInterface< + PartialMomentBasis<D, d, R, dimRange_or_refinements, 1, fluxDim, 1, entropy>::dimRange, + fluxDim, + PartialMomentBasis<D, d, R, dimRange_or_refinements, 1, fluxDim, 1, entropy>::dimRange, + R> +{ +public: + using MomentBasis = PartialMomentBasis<D, d, R, dimRange_or_refinements, 1, fluxDim, 1, entropy>; + using BaseType = + typename XT::Functions::FunctionInterface<MomentBasis::dimRange, MomentBasis::dimFlux, MomentBasis::dimRange, R>; + using ThisType = EntropyBasedFluxImplementation; + static const size_t dimFlux = MomentBasis::dimFlux; + static const size_t basis_dimRange = MomentBasis::dimRange; + using typename BaseType::DomainFieldType; + using typename BaseType::DomainType; + using typename BaseType::DynamicDerivativeRangeType; + using typename BaseType::DynamicRowDerivativeRangeType; + using typename BaseType::RangeFieldType; + using typename BaseType::RangeReturnType; + using BasisDomainType = typename MomentBasis::DomainType; + using FluxDomainType = FieldVector<DomainFieldType, dimFlux>; + static const size_t block_size = (dimFlux == 1) ? 2 : 4; + static const size_t num_blocks = basis_dimRange / block_size; + using BlockMatrixType = XT::Common::BlockedFieldMatrix<RangeFieldType, num_blocks, block_size>; + using LocalMatrixType = typename BlockMatrixType::BlockType; + using BlockVectorType = XT::Common::BlockedFieldVector<RangeFieldType, num_blocks, block_size>; + using VectorType = BlockVectorType; + using LocalVectorType = typename BlockVectorType::BlockType; + using BasisValuesMatrixType = std::vector<XT::LA::CommonDenseMatrix<RangeFieldType>>; + using QuadraturePointsType = + std::vector<std::vector<BasisDomainType, boost::alignment::aligned_allocator<BasisDomainType, 64>>>; + using BlockQuadratureWeightsType = + std::vector<RangeFieldType, boost::alignment::aligned_allocator<RangeFieldType, 64>>; + using QuadratureWeightsType = std::vector<BlockQuadratureWeightsType>; + using AlphaReturnType = std::pair<BlockVectorType, std::pair<DomainType, RangeFieldType>>; + + explicit EntropyBasedFluxImplementation(const MomentBasis& basis_functions, + const RangeFieldType tau, + const bool disable_realizability_check, + const RangeFieldType epsilon_gamma, + const RangeFieldType chi, + const RangeFieldType xi, + const std::vector<RangeFieldType> r_sequence, + const size_t k_0, + const size_t k_max, + const RangeFieldType epsilon) + : basis_functions_(basis_functions) + , quad_points_(num_blocks) + , quad_weights_(num_blocks) + , M_(num_blocks, XT::LA::CommonDenseMatrix<RangeFieldType>()) + , tau_(tau) + , disable_realizability_check_(disable_realizability_check) + , epsilon_gamma_(epsilon_gamma) + , chi_(chi) + , xi_(xi) + , r_sequence_(r_sequence) + , k_0_(k_0) + , k_max_(k_max) + , epsilon_(epsilon) + { + XT::LA::eye_matrix(T_minus_one_); + if (!disable_realizability_check_) + helper<dimFlux>::calculate_plane_coefficients(basis_functions_); + const auto& quadratures = basis_functions_.quadratures(); + assert(quadratures.size() == num_blocks); + for (size_t jj = 0; jj < num_blocks; ++jj) { + for (const auto& quad_point : quadratures[jj]) { + quad_points_[jj].emplace_back(quad_point.position()); + quad_weights_[jj].emplace_back(quad_point.weight()); + } + } // jj + for (size_t jj = 0; jj < num_blocks; ++jj) { + M_[jj] = XT::LA::CommonDenseMatrix<RangeFieldType>(quad_points_[jj].size(), block_size, 0., 0); + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) { + const auto val = basis_functions_.evaluate_on_face(quad_points_[jj][ll], jj); + for (size_t ii = 0; ii < block_size; ++ii) + M_[jj].set_entry(ll, ii, val[ii]); + } // ll + } // jj + } + + + // ============================================================================================ + // ============================= FunctionInterface methods ==================================== + // ============================================================================================ + + + int order(const XT::Common::Parameter& /*param*/) const override + { + return 1; + } + + virtual RangeReturnType evaluate(const DomainType& u, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = std::make_unique<BlockVectorType>(get_alpha(u, *get_isotropic_alpha(u), true)->first); + return evaluate_with_alpha(*alpha); + } + + virtual RangeReturnType evaluate_with_alpha(const BlockVectorType& alpha) const + { + RangeReturnType ret(0.); + auto& eta_ast_prime_vals = working_storage(); + evaluate_eta_ast_prime(alpha, M_, eta_ast_prime_vals); + for (size_t dd = 0; dd < dimFlux; ++dd) { + // calculate ret[dd] = < omega[dd] m G_\alpha(u) > + for (size_t jj = 0; jj < num_blocks; ++jj) { + const auto offset = block_size * jj; + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto factor = eta_ast_prime_vals[jj][ll] * quad_weights_[jj][ll] * quad_points_[jj][ll][dd]; + for (size_t ii = 0; ii < block_size; ++ii) + ret[dd][offset + ii] += M_[jj].get_entry(ll, ii) * factor; + } // ll + } // jj + } // dd + return ret; + } // void evaluate(...) + + virtual void jacobian(const DomainType& u, + DynamicDerivativeRangeType& result, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = std::make_unique<BlockVectorType>(get_alpha(u, *get_isotropic_alpha(u), true)->first); + jacobian_with_alpha(*alpha, result); + } + + virtual void jacobian_with_alpha(const BlockVectorType& alpha, DynamicDerivativeRangeType& result) const + { + thread_local auto H = XT::Common::make_unique<BlockMatrixType>(); + calculate_hessian(alpha, M_, *H); + for (size_t dd = 0; dd < dimFlux; ++dd) + row_jacobian(dd, M_, *H, result[dd], dd > 0); + } + + void row_jacobian(const size_t row, + const BasisValuesMatrixType& M, + BlockMatrixType& H, + DynamicRowDerivativeRangeType& ret, + bool L_calculated = false) const + { + assert(row < dimFlux); + calculate_J(M, ret, row); + calculate_J_Hinv(ret, H, L_calculated); + } // void partial_u_col(...) + + + // ============================================================================================ + // ============ Evaluations of ansatz distribution, moments, hessian etc. ===================== + // ============================================================================================ + + + std::unique_ptr<AlphaReturnType> get_alpha(const DomainType& u) const + { + return get_alpha(u, *get_isotropic_alpha(u), true); + } + + // Solves the minimum entropy optimization problem for u. + // returns (alpha, (actual_u, r)), where r is the regularization parameter and actual_u the regularized u + std::unique_ptr<AlphaReturnType> + get_alpha(const DomainType& u, const VectorType& alpha_in, const bool regularize) const + { + auto ret = std::make_unique<AlphaReturnType>(); + + constexpr bool rescale = (entropy == EntropyType::MaxwellBoltzmann); + + // rescale u such that the density <psi> is 1 + RangeFieldType density = basis_functions_.density(u); + static const auto alpha_one = std::make_unique<BlockVectorType>(basis_functions_.alpha_one()); + auto alpha_initial = std::make_unique<BlockVectorType>(*alpha_one); + if (rescale) { + *alpha_initial *= -std::log(density); + *alpha_initial += alpha_in; + } else { + *alpha_initial = alpha_in; + } + + if (!(density > 0. || !(basis_functions_.min_density(u) > 0.)) || std::isinf(density)) + DUNE_THROW(Dune::MathError, "Negative, inf or NaN density!"); + auto phi = std::make_unique<BlockVectorType>(u); + if (rescale) + *phi *= 1. / density; + + // if value has already been calculated for these values, skip computation + RangeFieldType tau_prime = rescale ? std::min(tau_ + / ((1 + std::sqrt(basis_dimRange) * phi->two_norm()) * density + + std::sqrt(basis_dimRange) * tau_), + tau_) + : tau_; + + // calculate moment vector for isotropic distribution + auto u_iso = std::make_unique<BlockVectorType>(basis_functions_.u_iso()); + if (!rescale) + *u_iso *= density; + + // define further variables + auto g_k = std::make_unique<BlockVectorType>(); + auto beta_out = std::make_unique<BlockVectorType>(); + auto v = std::make_unique<BlockVectorType>(); + thread_local auto T_k = XT::Common::make_unique<BlockMatrixType>(); + auto beta_in = std::make_unique<BlockVectorType>(*alpha_initial); + + const auto& r_sequence = regularize ? r_sequence_ : std::vector<RangeFieldType>{0.}; + const auto r_max = r_sequence.back(); + for (const auto& rr : r_sequence) { + // regularize u + *v = *phi; + if (rr > 0.) { + *beta_in = *get_isotropic_alpha(*v); + // calculate v = (1-r) u + r u_iso + // use beta_out as storage for u_iso_in * r + *v *= (1 - rr); + *beta_out = *u_iso; + *beta_out *= rr; + *v += *beta_out; + } + for (size_t jj = 0; jj < num_blocks; ++jj) + T_k->block(jj) = T_minus_one_; + // calculate T_k u + auto v_k = std::make_unique<BlockVectorType>(*v); + // calculate values of basis p = S_k m + thread_local BasisValuesMatrixType P_k(num_blocks, XT::LA::CommonDenseMatrix<RangeFieldType>(0, 0, 0., 0)); + copy_basis_matrix(M_, P_k); + // calculate f_0 + RangeFieldType f_k = get_eta_ast_integrated(*beta_in, P_k) - *beta_in * *v_k; + + thread_local auto H = XT::Common::make_unique<BlockMatrixType>(0.); + + int backtracking_failed = 0; + for (size_t kk = 0; kk < k_max_; ++kk) { + // exit inner for loop to increase r if too many iterations are used or cholesky decomposition fails + if (kk > k_0_ && rr < r_max) + break; + try { + change_basis(*beta_in, *v_k, P_k, *T_k, *g_k, *beta_out, *H); + } catch (const Dune::MathError&) { + if (rr < r_max) + break; + DUNE_THROW(Dune::MathError, "Failure to converge!"); + } + + // calculate descent direction d_k; + thread_local auto d_k = std::make_unique<BlockVectorType>(); + *d_k = *g_k; + *d_k *= -1; + + // Calculate stopping criteria (in original basis). Variables with _k are in current basis, without k in + // original basis. + thread_local auto alpha_tilde = std::make_unique<BlockVectorType>(); + thread_local auto alpha_prime = std::make_unique<BlockVectorType>(); + thread_local auto u_alpha_tilde = std::make_unique<BlockVectorType>(); + thread_local auto u_alpha_prime = std::make_unique<BlockVectorType>(); + thread_local auto d_alpha_tilde = std::make_unique<BlockVectorType>(); + thread_local auto g_alpha_tilde = std::make_unique<BlockVectorType>(); + thread_local auto u_eps_diff = std::make_unique<BlockVectorType>(); + // convert everything to original basis + for (size_t jj = 0; jj < num_blocks; ++jj) { + XT::LA::solve_lower_triangular_transposed(T_k->block(jj), alpha_tilde->block(jj), beta_out->block(jj)); + XT::LA::solve_lower_triangular_transposed(T_k->block(jj), d_alpha_tilde->block(jj), d_k->block(jj)); + } // jj + calculate_u(*alpha_tilde, M_, *u_alpha_tilde); + *g_alpha_tilde = *u_alpha_tilde; + *g_alpha_tilde -= *v; + auto density_tilde = basis_functions_.density(*u_alpha_tilde); + if (!(density_tilde > 0.) || !(basis_functions_.min_density(*u_alpha_tilde) > 0.) || std::isinf(density_tilde)) + break; + + // if rescale == true, we ensure that the ansatz density exactly matches the density of u + if (rescale) { + *alpha_prime = *alpha_one; + *alpha_prime *= -std::log(density_tilde); + *alpha_prime += *alpha_tilde; + calculate_u(*alpha_prime, M_, *u_alpha_prime); + } else { + *alpha_prime = *alpha_tilde; + *u_alpha_prime = *u_alpha_tilde; + } + + // calculate stopping criteria + *u_eps_diff = *u_alpha_prime; + *u_eps_diff *= -(1 - epsilon_gamma_); + *u_eps_diff += *v; + + // working_storage contains eta_ast_prime evaluations due to the calculate_u call above + auto& eta_ast_prime_vals = working_storage(); + if (g_alpha_tilde->two_norm() < tau_prime + && 1 - epsilon_gamma_ < std::exp(-(rescale ? d_alpha_tilde->one_norm() + std::abs(std::log(density_tilde)) + : d_alpha_tilde->one_norm())) + && (entropy == EntropyType::MaxwellBoltzmann || all_positive(eta_ast_prime_vals)) + && (disable_realizability_check_ || helper<dimFlux>::is_realizable(*u_eps_diff, basis_functions_))) { + ret->second.first = *v; + ret->second.second = rr; + if (rescale) { + ret->first = *alpha_one; + ret->first *= std::log(density); + ret->first += *alpha_prime; + ret->second.first *= density; + } else { + ret->first = *alpha_prime; + } + return ret; + } else { + RangeFieldType zeta_k = 1; + *beta_in = *beta_out; + // backtracking line search + while (backtracking_failed >= 2 || zeta_k > epsilon_ * beta_out->two_norm() / d_k->two_norm()) { + thread_local auto beta_new = std::make_unique<BlockVectorType>(); + *beta_new = *d_k; + *beta_new *= zeta_k; + *beta_new += *beta_out; + RangeFieldType f = get_eta_ast_integrated(*beta_new, P_k) - *beta_new * *v_k; + if (backtracking_failed >= 2 || f <= f_k + xi_ * zeta_k * (*g_k * *d_k)) { + *beta_in = *beta_new; + f_k = f; + backtracking_failed = 0; + break; + } + zeta_k = chi_ * zeta_k; + } // backtracking linesearch while + if (zeta_k <= epsilon_ * beta_out->two_norm() / d_k->two_norm()) + ++backtracking_failed; + } // else (stopping conditions) + } // k loop (Newton iterations) + } // rr loop (Regularization parameter) + DUNE_THROW(MathError, "Failed to converge"); + + return ret; + } + + void change_basis(const BlockVectorType& beta_in, + BlockVectorType& v_k, + BasisValuesMatrixType& P_k, + BlockMatrixType& T_k, + BlockVectorType& g_k, + BlockVectorType& beta_out, + BlockMatrixType& H) const + { + calculate_hessian(beta_in, P_k, H); + FieldVector<RangeFieldType, block_size> tmp_vec; + for (size_t jj = 0; jj < num_blocks; ++jj) + XT::LA::cholesky(H.block(jj)); + const auto& L = H; + T_k.rightmultiply(L); + L.mtv(beta_in, beta_out); + for (size_t jj = 0; jj < num_blocks; ++jj) { + XT::LA::solve_lower_triangular(L.block(jj), tmp_vec, v_k.block(jj)); + v_k.block(jj) = tmp_vec; + } // jj + apply_inverse_matrix(L, P_k); + calculate_u(beta_out, P_k, g_k); + g_k -= v_k; + } // void change_basis(...) + + // returns density rho = < eta_ast_prime(beta_in * b(v)) > + RangeFieldType get_rho(const BlockVectorType& beta_in, const BasisValuesMatrixType& M) const + { + auto& eta_ast_prime_vals = working_storage(); + evaluate_eta_ast_prime(beta_in, M, eta_ast_prime_vals); + RangeFieldType ret(0.); + for (size_t jj = 0; jj < num_blocks; ++jj) + ret += std::inner_product( + quad_weights_[jj].begin(), quad_weights_[jj].end(), eta_ast_prime_vals[jj].begin(), RangeFieldType(0.)); + return ret; + } + + // returns < eta_ast(beta_in * b(v)) > + RangeFieldType get_eta_ast_integrated(const BlockVectorType& beta_in, const BasisValuesMatrixType& M) const + { + auto& eta_ast_vals = working_storage(); + evaluate_eta_ast(beta_in, M, eta_ast_vals); + RangeFieldType ret(0.); + for (size_t jj = 0; jj < num_blocks; ++jj) + ret += std::inner_product( + quad_weights_[jj].begin(), quad_weights_[jj].end(), eta_ast_vals[jj].begin(), RangeFieldType(0.)); + return ret; + } + + // returns < b \eta_{\ast}^{\prime}(\alpha^T b(v)) > + DomainType get_u(const DomainType& alpha) const + { + BlockVectorType u_block; + calculate_u(alpha, M_, u_block); + return u_block; + } + + DomainType get_u(const QuadratureWeightsType& eta_ast_prime_vals) const + { + DomainType ret; + for (size_t jj = 0; jj < num_blocks; ++jj) { + const auto offset = block_size * jj; + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto factor = eta_ast_prime_vals[jj][ll] * quad_weights_[jj][ll]; + const auto* basis_ll = &(M_[jj].get_entry_ref(ll, 0.)); + for (size_t ii = 0; ii < block_size; ++ii) + ret[offset + ii] += basis_ll[ii] * factor; + } // ll + } // jj (intervals) + return ret; + } + + // calculate ret = \int (b eta_ast_prime(beta_in * m)) + void calculate_u(const BlockVectorType& beta_in, const BasisValuesMatrixType& M, BlockVectorType& ret) const + { + auto& eta_ast_prime_vals = working_storage(); + evaluate_eta_ast_prime(beta_in, M, eta_ast_prime_vals); + for (size_t jj = 0; jj < num_blocks; ++jj) { + auto& ret_jj = ret.block(jj); + std::fill(ret_jj.begin(), ret_jj.end(), 0.); + const size_t num_quad_points = quad_weights_[jj].size(); + for (size_t ll = 0; ll < num_quad_points; ++ll) { + const auto factor = eta_ast_prime_vals[jj][ll] * quad_weights_[jj][ll]; + const auto* basis_ll = &(M[jj].get_entry_ref(ll, 0.)); + for (size_t ii = 0; ii < block_size; ++ii) + ret_jj[ii] += basis_ll[ii] * factor; + } // ll + } // jj + } + + void calculate_hessian(const BlockVectorType& alpha, const BasisValuesMatrixType& M, BlockMatrixType& H) const + { + auto& eta_ast_twoprime_vals = working_storage(); + evaluate_eta_ast_twoprime(alpha, M, eta_ast_twoprime_vals); + calculate_hessian(eta_ast_twoprime_vals, M, H); + } // void calculate_hessian(...) + + void calculate_hessian(const QuadratureWeightsType& eta_ast_twoprime_vals, + const BasisValuesMatrixType& M, + BlockMatrixType& H) const + { + // matrix is symmetric, we only use lower triangular part + for (size_t jj = 0; jj < num_blocks; ++jj) { + std::fill(H.block(jj).begin(), H.block(jj).end(), 0.); + const size_t num_quad_points = quad_weights_[jj].size(); + for (size_t ll = 0; ll < num_quad_points; ++ll) { + auto factor_ll = eta_ast_twoprime_vals[jj][ll] * quad_weights_[jj][ll]; + const auto* basis_ll = &(M[jj].get_entry_ref(ll, 0.)); + for (size_t ii = 0; ii < block_size; ++ii) { + auto* H_row = &(H.block(jj)[ii][0]); + const auto factor_ll_ii = basis_ll[ii] * factor_ll; + for (size_t kk = 0; kk <= ii; ++kk) + H_row[kk] += basis_ll[kk] * factor_ll_ii; + } // ii + } // ll + } // jj + } // void calculate_hessian(...) + + void apply_inverse_hessian(const QuadratureWeightsType& eta_ast_twoprime_vals, + const DomainType& u, + DomainType& Hinv_u) const + { + thread_local auto H = XT::Common::make_unique<BlockMatrixType>(); + calculate_hessian(eta_ast_twoprime_vals, M_, *H); + for (size_t jj = 0; jj < num_blocks; ++jj) + XT::LA::cholesky(H->block(jj)); + FieldVector<RangeFieldType, block_size> tmp_vec; + FieldVector<RangeFieldType, block_size> block_u; + for (size_t jj = 0; jj < num_blocks; ++jj) { + // calculate C = A (L^T)^{-1} + const auto offset = block_size * jj; + for (size_t ii = 0; ii < block_size; ++ii) + block_u[ii] = u[offset + ii]; + XT::LA::solve_lower_triangular(H->block(jj), tmp_vec, block_u); + XT::LA::solve_lower_triangular_transposed(H->block(jj), block_u, tmp_vec); + for (size_t ii = 0; ii < block_size; ++ii) + Hinv_u[offset + ii] = block_u[ii]; + } // jj + } + + // J = df/dalpha is the derivative of the flux with respect to alpha. + // As F = (f_1, f_2, f_3) is matrix-valued + // (div f = \sum_{i=1}^d \partial_{x_i} f_i = \sum_{i=1}^d \partial_{x_i} < v_i m \hat{psi}(alpha) > is + // vector-valued), + // the derivative is the vector of matrices (df_1/dalpha, df_2/dalpha, ...) + // this function returns the dd-th matrix df_dd/dalpha of J + // assumes work_vecs already contains the needed eta_ast_twoprime(alpha * m) values + void calculate_J(const BasisValuesMatrixType& M, DynamicRowDerivativeRangeType& J_dd, const size_t dd) const + { + assert(dd < dimFlux); + const auto& eta_ast_twoprime_values = working_storage(); + // matrix is symmetric, we only use lower triangular part + for (size_t jj = 0; jj < num_blocks; ++jj) { + const auto offset = jj * block_size; + // set entries in this block to zero + for (size_t ii = 0; ii < block_size; ++ii) + std::fill_n(&(J_dd.get_entry_ref(offset + ii, offset)), ii + 1, 0.); + // now calculate integral + const size_t num_quad_points = quad_weights_[jj].size(); + for (size_t ll = 0; ll < num_quad_points; ++ll) { + auto factor_ll = eta_ast_twoprime_values[jj][ll] * quad_weights_[jj][ll] * quad_points_[jj][ll][dd]; + const auto* basis_ll = &(M[jj].get_entry_ref(ll, 0.)); + for (size_t ii = 0; ii < block_size; ++ii) { + auto* J_row = &(J_dd[offset + ii][offset]); + const auto factor_ll_ii = basis_ll[ii] * factor_ll; + for (size_t kk = 0; kk <= ii; ++kk) + J_row[kk] += basis_ll[kk] * factor_ll_ii; + } // ii + } // ll + } // jj + // symmetric update for upper triangular part of J + for (size_t jj = 0; jj < num_blocks; ++jj) { + const auto offset = block_size * jj; + for (size_t mm = 0; mm < block_size; ++mm) + for (size_t nn = mm + 1; nn < block_size; ++nn) + J_dd.set_entry(offset + mm, offset + nn, J_dd.get_entry(offset + nn, offset + mm)); + } + } // void calculate_J(...) + + // calculates A = A B^{-1}. B is assumed to be symmetric positive definite. + static void calculate_J_Hinv(DynamicRowDerivativeRangeType& A, BlockMatrixType& B, bool L_calculated = false) + { + // if B = LL^T, then we have to calculate ret = A (L^T)^{-1} L^{-1} = C L^{-1} + // calculate B = LL^T first + if (!L_calculated) { + for (size_t jj = 0; jj < num_blocks; ++jj) + XT::LA::cholesky(B.block(jj)); + } + FieldVector<RangeFieldType, block_size> tmp_vec; + FieldVector<RangeFieldType, block_size> tmp_A_row; + for (size_t jj = 0; jj < num_blocks; ++jj) { + // calculate C = A (L^T)^{-1} + const auto offset = block_size * jj; + for (size_t ii = 0; ii < block_size; ++ii) { + for (size_t kk = 0; kk < block_size; ++kk) + tmp_A_row[kk] = A[offset + ii][offset + kk]; + XT::LA::solve_lower_triangular(B.block(jj), tmp_vec, tmp_A_row); + // calculate ret = C L^{-1} + XT::LA::solve_lower_triangular_transposed(B.block(jj), tmp_A_row, tmp_vec); + for (size_t kk = 0; kk < block_size; ++kk) + A[offset + ii][offset + kk] = tmp_A_row[kk]; + } // ii + } // jj + } // void calculate_J_Hinv(...) + + + // ============================================================================================ + // ============================= Entropy evaluations ========================================== + // ============================================================================================ + + + // evaluates \eta_{\ast}(\alpha^T b(v_i)) for all quadrature points v_i + void evaluate_eta_ast(const DomainType& alpha, const BasisValuesMatrixType& M, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, M, ret); + apply_exponential(ret); + evaluate_eta_ast(ret); + } + + // evaluates \eta_{\ast}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already contains + // exp(alpha^T b(v_i)) + void evaluate_eta_ast(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t jj = 0; jj < num_blocks; ++jj) + for (size_t ll = 0; ll < ret[jj].size(); ++ll) + ret[jj][ll] = -std::log(1 - ret[jj][ll]); + } + + // evaluates \eta_{\ast}^{\prime}(\alpha^T b(v_i)) for all quadrature points v_i + void evaluate_eta_ast_prime(const DomainType& alpha, const BasisValuesMatrixType& M, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, M, ret); + apply_exponential(ret); + evaluate_eta_ast_prime(ret); + } + + // evaluates \eta_{\ast}^{\prime}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already contains + // exp(alpha^T b(v_i)) + void evaluate_eta_ast_prime(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t jj = 0; jj < num_blocks; ++jj) + for (size_t ll = 0; ll < ret[jj].size(); ++ll) + ret[jj][ll] /= (1 - ret[jj][ll]); + } + + // evaluates \eta_{\ast}^{\prime\prime}(\alpha^T b(v_i)) for all quadrature points v_i + void + evaluate_eta_ast_twoprime(const DomainType& alpha, const BasisValuesMatrixType& M, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, M, ret); + apply_exponential(ret); + evaluate_eta_ast_twoprime(ret); + } + + // evaluates \eta_{\ast}^{\prime\prime}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already + // contains exp(alpha^T b(v_i)) + void evaluate_eta_ast_twoprime(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t jj = 0; jj < num_blocks; ++jj) + for (size_t ll = 0; ll < ret[jj].size(); ++ll) + ret[jj][ll] /= std::pow(1 - ret[jj][ll], 2); + } + + // stores evaluations of exp(alpha^T b(v_i)) for all quadrature points v_i + void store_exp_evaluations(QuadratureWeightsType& exp_evaluations, const DomainType& alpha) const + { + this->calculate_scalar_products(alpha, M_, exp_evaluations); + this->apply_exponential(exp_evaluations); + } + + void store_eta_ast_prime_vals(const QuadratureWeightsType& exp_evaluations, QuadratureWeightsType& eta_ast_prime_vals) + { + eta_ast_prime_vals = exp_evaluations; + evaluate_eta_ast_prime(eta_ast_prime_vals); + } + + void store_eta_ast_twoprime_vals(const QuadratureWeightsType& exp_evaluations, + QuadratureWeightsType& eta_ast_twoprime_vals) + { + eta_ast_twoprime_vals = exp_evaluations; + evaluate_eta_ast_twoprime(eta_ast_twoprime_vals); + } + + // stores evaluations of a given boundary distribution psi(v) at all quadrature points v_i + void store_boundary_distribution_evaluations( + QuadratureWeightsType& boundary_distribution_evaluations, + const std::function<RangeFieldType(const FluxDomainType&)>& boundary_distribution) const + { + boundary_distribution_evaluations.resize(num_blocks); + for (size_t jj = 0; jj < num_blocks; ++jj) { + boundary_distribution_evaluations[jj].resize(quad_points_[jj].size()); + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) + boundary_distribution_evaluations[jj][ll] = boundary_distribution(quad_points_[jj][ll]); + } + } + + + // ============================================================================================ + // =============================== Kinetic fluxes ============================================= + // ============================================================================================ + + + // calculate \sum_{i=1}^d < v_i m \psi > n_i, where n is the unit outer normal, + // m is the basis function vector, \psi is the ansatz corresponding to u + // and x, v, t are the space, velocity and time variable, respectively + // As we are using cartesian grids, n_i == 0 in all but one dimension, so only evaluate for i == dd + DomainType + evaluate_kinetic_flux(const DomainType& u_i, const DomainType& u_j, const FluxDomainType& n_ij, const size_t dd) const + { + // calculate \sum_{i=1}^d < \omega_i m G_\alpha(u) > n_i + const auto alpha_i = std::make_unique<BlockVectorType>(get_alpha(u_i, *get_isotropic_alpha(u_i), true)->first); + const auto alpha_j = std::make_unique<BlockVectorType>(get_alpha(u_j, *get_isotropic_alpha(u_j), true)->first); + evaluate_kinetic_flux_with_alphas(*alpha_i, *alpha_j, n_ij, dd); + } // DomainType evaluate_kinetic_flux(...) + + DomainType evaluate_kinetic_flux_with_alphas(const BlockVectorType& alpha_i, + const BlockVectorType& alpha_j, + const FluxDomainType& n_ij, + const size_t dd) const + { + // calculate \sum_{i=1}^d < \omega_i m G_\alpha(u) > n_i + thread_local FieldVector<QuadratureWeightsType, 2> eta_ast_prime_vals{ + {QuadratureWeightsType(num_blocks), QuadratureWeightsType(num_blocks)}}; + for (size_t jj = 0; jj < num_blocks; ++jj) { + eta_ast_prime_vals[0][jj].resize(quad_points_[jj].size()); + eta_ast_prime_vals[1][jj].resize(quad_points_[jj].size()); + } + evaluate_eta_ast_prime(alpha_i, M_, eta_ast_prime_vals[0]); + evaluate_eta_ast_prime(alpha_j, M_, eta_ast_prime_vals[1]); + DomainType ret(0); + for (size_t jj = 0; jj < num_blocks; ++jj) { + const auto offset = block_size * jj; + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) { + const auto position = quad_points_[jj][ll][dd]; + RangeFieldType factor = + position * n_ij[dd] > 0. ? eta_ast_prime_vals[0][jj][ll] : eta_ast_prime_vals[1][jj][ll]; + factor *= quad_weights_[jj][ll] * position; + for (size_t ii = 0; ii < block_size; ++ii) + ret[offset + ii] += M_[jj].get_entry(ll, ii) * factor; + } // ll + } // jj + ret *= n_ij[dd]; + return ret; + } // DomainType evaluate_kinetic_flux(...) + + // Calculates left and right kinetic flux with reconstructed densities. Ansatz distribution values contains + // evaluations of the ansatz distribution at each quadrature point for a stencil of three entities. The distributions + // are reconstructed pointwise for each quadrature point and the resulting (part of) the kinetic flux is < + // psi_reconstr * b * v>_{+/-}. + template <SlopeLimiterType slope_type, class FluxesMapType> + void calculate_reconstructed_fluxes(const FieldVector<const QuadratureWeightsType*, 3>& ansatz_distribution_values, + FluxesMapType& flux_values, + const size_t dd) const + { + // get flux storage + BasisDomainType coord(0.5); + coord[dd] = 0; + auto& left_flux_value = flux_values[coord]; + coord[dd] = 1; + auto& right_flux_value = flux_values[coord]; + right_flux_value = left_flux_value = DomainType(0.); + + // evaluate exp(alpha^T b(v_i)) at all quadratures points v_i for all three alphas + thread_local XT::Common::FieldVector<BlockQuadratureWeightsType, 2> reconstructed_values( + BlockQuadratureWeightsType(quad_points_[0].size())); + + // get left and right reconstructed values for each quadrature point v_i + auto& vals_left = reconstructed_values[0]; + auto& vals_right = reconstructed_values[1]; + + const auto slope_func = + (slope_type == SlopeLimiterType::minmod) ? XT::Common::minmod<RangeFieldType> : superbee<RangeFieldType>; + for (size_t jj = 0; jj < num_blocks; ++jj) { + // reconstruct densities + if (slope_type == SlopeLimiterType::no_slope) { + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) + vals_left[ll] = vals_right[ll] = (*ansatz_distribution_values[1])[jj][ll]; + } else { + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) { + const auto slope = + slope_func((*ansatz_distribution_values[1])[jj][ll] - (*ansatz_distribution_values[0])[jj][ll], + (*ansatz_distribution_values[2])[jj][ll] - (*ansatz_distribution_values[1])[jj][ll]); + vals_left[ll] = (*ansatz_distribution_values[1])[jj][ll] - 0.5 * slope; + vals_right[ll] = (*ansatz_distribution_values[1])[jj][ll] + 0.5 * slope; + } // ll + } + // calculate fluxes + const auto offset = block_size * jj; + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) { + const auto position = quad_points_[jj][ll][dd]; + RangeFieldType factor = position > 0. ? vals_right[ll] : vals_left[ll]; + factor *= quad_weights_[jj][ll] * position; + auto& val = position > 0. ? right_flux_value : left_flux_value; + for (size_t ii = 0; ii < block_size; ++ii) + val[offset + ii] += M_[jj].get_entry(ll, ii) * factor; + } // ll + } // jj + } // void calculate_reconstructed_fluxes(...) + + + // ============================================================================================ + // ================================== Helper functions ======================================== + // ============================================================================================ + + + const MomentBasis& basis_functions() const + { + return basis_functions_; + } + + // temporary vectors to store inner products and exponentials + QuadratureWeightsType& working_storage() const + { + thread_local QuadratureWeightsType work_vecs(num_blocks); + for (size_t jj = 0; jj < num_blocks; ++jj) + work_vecs[jj].resize(quad_points_[jj].size()); + return work_vecs; + } + + bool all_positive(const QuadratureWeightsType& vals) const + { + for (size_t jj = 0; jj < num_blocks; ++jj) + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) { + const auto val = vals[jj][ll]; + if (val < 0. || std::isinf(val) || std::isnan(val)) + return false; + } + return true; + } + + std::unique_ptr<BlockVectorType> get_isotropic_alpha(const RangeFieldType density) const + { + return std::make_unique<BlockVectorType>(basis_functions_.alpha_iso(density)); + } + + std::unique_ptr<BlockVectorType> get_isotropic_alpha(const DomainType& u) const + { + return get_isotropic_alpha(basis_functions_.density(u)); + } + + void copy_basis_matrix(const BasisValuesMatrixType& source_mat, BasisValuesMatrixType& range_mat) const + { + for (size_t jj = 0; jj < num_blocks; ++jj) + range_mat[jj].backend() = source_mat[jj].backend(); + } + + void calculate_scalar_products_block(const size_t jj, + const LocalVectorType& beta_in, + const XT::LA::CommonDenseMatrix<RangeFieldType>& M, + BlockQuadratureWeightsType& scalar_products) const + { + const size_t num_quad_points = quad_points_[jj].size(); + for (size_t ll = 0; ll < num_quad_points; ++ll) { + const auto* basis_ll = &(M.get_entry_ref(ll, 0.)); + scalar_products[ll] = std::inner_product(beta_in.begin(), beta_in.end(), basis_ll, 0.); + } // ll + } + + void calculate_scalar_products(const BlockVectorType& beta_in, + const BasisValuesMatrixType& M, + QuadratureWeightsType& scalar_products) const + { + scalar_products.resize(num_blocks); + for (size_t jj = 0; jj < num_blocks; ++jj) { + scalar_products[jj].resize(quad_weights_[jj].size()); + calculate_scalar_products_block(jj, beta_in.block(jj), M[jj], scalar_products[jj]); + } + } + + void apply_exponential(BlockQuadratureWeightsType& values) const + { + assert(values.size() < std::numeric_limits<int>::max()); + XT::Common::Mkl::exp(static_cast<int>(values.size()), values.data(), values.data()); + } + + void apply_exponential(QuadratureWeightsType& values) const + { + for (size_t jj = 0; jj < num_blocks; ++jj) + apply_exponential(values[jj]); + } + + void copy_transposed(const LocalMatrixType& T_k, LocalMatrixType& T_k_trans) const + { + for (size_t ii = 0; ii < block_size; ++ii) + for (size_t kk = 0; kk <= ii; ++kk) + T_k_trans[kk][ii] = T_k[ii][kk]; + } + + void apply_inverse_matrix_block(const size_t jj, + const LocalMatrixType& T_k, + XT::LA::CommonDenseMatrix<RangeFieldType>& M) const + { + const size_t num_quad_points = quad_points_[jj].size(); + if (block_size == 2) { + const auto T_00_inv = 1 / T_k[0][0]; + const auto T_11_inv = 1 / T_k[1][1]; + for (size_t ll = 0; ll < num_quad_points; ++ll) { + auto* basis_ll = &(M.get_entry_ref(ll, 0.)); + basis_ll[0] *= T_00_inv; + basis_ll[1] = (basis_ll[1] - T_k[1][0] * basis_ll[0]) * T_11_inv; + } + } else if (block_size == 4) { + FieldVector<RangeFieldType, 4> diag_inv; + for (size_t ii = 0; ii < 4; ++ii) + diag_inv[ii] = 1. / T_k[ii][ii]; + for (size_t ll = 0; ll < num_quad_points; ++ll) { + auto* basis_ll = &(M.get_entry_ref(ll, 0.)); + basis_ll[0] *= diag_inv[0]; + basis_ll[1] = (basis_ll[1] - T_k[1][0] * basis_ll[0]) * diag_inv[1]; + basis_ll[2] = (basis_ll[2] - T_k[2][0] * basis_ll[0] - T_k[2][1] * basis_ll[1]) * diag_inv[2]; + basis_ll[3] = + (basis_ll[3] - T_k[3][0] * basis_ll[0] - T_k[3][1] * basis_ll[1] - T_k[3][2] * basis_ll[2]) * diag_inv[3]; + } + } else { +# if HAVE_MKL + thread_local LocalMatrixType T_k_trans(0.); + assert(num_quad_points < std::numeric_limits<int>::max()); + // Calculate the transpose here first as this is much faster than passing the matrix to dtrsm and using + // CblasTrans + copy_transposed(T_k, T_k_trans); + XT::Common::Cblas::dtrsm(XT::Common::Cblas::row_major(), + XT::Common::Cblas::right(), + XT::Common::Cblas::upper(), + XT::Common::Cblas::no_trans(), + XT::Common::Cblas::non_unit(), + static_cast<int>(num_quad_points), + block_size, + 1., + &(T_k_trans[0][0]), + block_size, + M.data(), + block_size); +# else + LocalVectorType tmp_vec, tmp_vec2; + for (size_t ll = 0; ll < num_quad_points; ++ll) { + auto* M_row = &(M.get_entry_ref(ll, 0.)); + std::copy_n(M_row, block_size, tmp_vec.begin()); + XT::LA::solve_lower_triangular(T_k, tmp_vec2, tmp_vec); + std::copy_n(tmp_vec2.begin(), block_size, M_row); + } +# endif + } + } + + void apply_inverse_matrix(const BlockMatrixType& T_k, BasisValuesMatrixType& M) const + { + for (size_t jj = 0; jj < num_blocks; ++jj) + apply_inverse_matrix_block(jj, T_k.block(jj), M[jj]); + } + + template <size_t domainDim = dimFlux, class anything = void> + struct helper + { +# if HAVE_QHULL + static void calculate_plane_coefficients(const MomentBasis& basis_functions) + { + if (!basis_functions.plane_coefficients()[0].size()) + basis_functions.calculate_plane_coefficients(); + } + + static bool is_realizable(const BlockVectorType& u, const MomentBasis& basis_functions) + { + for (size_t jj = 0; jj < num_blocks; ++jj) + for (const auto& coeff : basis_functions.plane_coefficients()[jj]) + if (!(u.block(jj) * coeff.first < coeff.second)) + return false; + return true; + } +# else + static void calculate_plane_coefficients(const MomentBasis& /*basis_functions*/) + { + std::cerr << "Warning: You are missing Qhull, realizability stopping condition will not be checked!" << std::endl; + } + + static bool is_realizable(const BlockVectorType& /*u*/, const MomentBasis& /*basis_functions*/) + { + return true; + } +# endif + }; // class helper<...> + + template <class anything> + struct helper<1, anything> + { + static void calculate_plane_coefficients(const MomentBasis& /*basis_functions*/) {} + + static bool is_realizable(const BlockVectorType& u, const MomentBasis& basis_functions) + { + for (size_t jj = 0; jj < num_blocks; ++jj) { + const auto& u0 = u.block(jj)[0]; + const auto& u1 = u.block(jj)[1]; + const auto& v0 = basis_functions.partitioning()[jj]; + const auto& v1 = basis_functions.partitioning()[jj + 1]; + bool ret = (u0 >= 0) && (u1 <= v1 * u0) && (v0 * u0 <= u1); + if (!ret) + return false; + } // jj + return true; + } + }; // class helper<1, ...> + + const MomentBasis& basis_functions_; + QuadraturePointsType quad_points_; + QuadratureWeightsType quad_weights_; + BasisValuesMatrixType M_; + const RangeFieldType tau_; + const bool disable_realizability_check_; + const RangeFieldType epsilon_gamma_; + const RangeFieldType chi_; + const RangeFieldType xi_; + const std::vector<RangeFieldType> r_sequence_; + const size_t k_0_; + const size_t k_max_; + const RangeFieldType epsilon_; + LocalMatrixType T_minus_one_; +}; +#endif // ENTROPY_FLUX_USE_PARTIAL_MOMENTS_SPECIALIZATION + +#if ENTROPY_FLUX_USE_3D_HATFUNCTIONS_SPECIALIZATION +/** + * Specialization of EntropyBasedFluxImplementation for 3D Hatfunctions + */ +template <class D, class R, size_t dimRange_or_refinements, size_t fluxDim, EntropyType entropy> +class EntropyBasedFluxImplementation<HatFunctionMomentBasis<D, 3, R, dimRange_or_refinements, 1, fluxDim, entropy>> + : public XT::Functions::FunctionInterface< + HatFunctionMomentBasis<D, 3, R, dimRange_or_refinements, 1, fluxDim, entropy>::dimRange, + fluxDim, + HatFunctionMomentBasis<D, 3, R, dimRange_or_refinements, 1, fluxDim, entropy>::dimRange, + R> +{ +public: + using MomentBasis = HatFunctionMomentBasis<D, 3, R, dimRange_or_refinements, 1, fluxDim, entropy>; + using BaseType = + typename XT::Functions::FunctionInterface<MomentBasis::dimRange, MomentBasis::dimFlux, MomentBasis::dimRange, R>; + using ThisType = EntropyBasedFluxImplementation; + static const size_t dimFlux = MomentBasis::dimFlux; + static const size_t basis_dimRange = MomentBasis::dimRange; + using typename BaseType::DomainFieldType; + using typename BaseType::DomainType; + using typename BaseType::DynamicDerivativeRangeType; + using typename BaseType::DynamicRowDerivativeRangeType; + using typename BaseType::RangeFieldType; + using typename BaseType::RangeReturnType; + using BasisDomainType = typename MomentBasis::DomainType; + using FluxDomainType = FieldVector<DomainFieldType, dimFlux>; + using DynamicRangeType = DynamicVector<RangeFieldType>; + using LocalVectorType = XT::Common::FieldVector<RangeFieldType, 3>; + using LocalMatrixType = XT::Common::FieldMatrix<RangeFieldType, 3, 3>; + using BasisValuesMatrixType = std::vector<std::vector<LocalVectorType>>; + using QuadraturePointsType = std::vector<std::vector<BasisDomainType>>; + using QuadratureWeightsType = std::vector<std::vector<RangeFieldType>>; +# if HAVE_EIGEN + using SparseMatrixType = typename XT::LA::Container<RangeFieldType, XT::LA::Backends::eigen_sparse>::MatrixType; + using VectorType = typename XT::LA::Container<RangeFieldType, XT::LA::Backends::eigen_sparse>::VectorType; +# else + using SparseMatrixType = typename XT::LA::Container<RangeFieldType, XT::LA::default_sparse_backend>::MatrixType; + using VectorType = typename XT::LA::Container<RangeFieldType, XT::LA::default_sparse_backend>::VectorType; +# endif + using AlphaReturnType = std::pair<VectorType, std::pair<DomainType, RangeFieldType>>; + + explicit EntropyBasedFluxImplementation(const MomentBasis& basis_functions, + const RangeFieldType tau, + const bool /*disable_realizability_check*/, + const RangeFieldType epsilon_gamma, + const RangeFieldType chi, + const RangeFieldType xi, + const std::vector<RangeFieldType> r_sequence, + const size_t k_0, + const size_t k_max, + const RangeFieldType epsilon) + : basis_functions_(basis_functions) + , quad_points_(basis_functions_.triangulation().faces().size()) + , quad_weights_(basis_functions_.triangulation().faces().size()) + , M_(basis_functions_.triangulation().faces().size()) + , tau_(tau) + , epsilon_gamma_(epsilon_gamma) + , chi_(chi) + , xi_(xi) + , r_sequence_(r_sequence) + , k_0_(k_0) + , k_max_(k_max) + , epsilon_(epsilon) + , num_faces_(basis_functions_.triangulation().faces().size()) + { + const auto& triangulation = basis_functions_.triangulation(); + const auto& faces = triangulation.faces(); + assert(triangulation.vertices().size() == basis_dimRange); + // create pattern + XT::LA::SparsityPatternDefault pattern(basis_dimRange); + for (size_t vertex_index = 0; vertex_index < basis_dimRange; ++vertex_index) { + const auto& vertex = triangulation.vertices()[vertex_index]; + const auto& adjacent_faces = triangulation.get_face_indices(vertex->position()); + for (const auto& face_index : adjacent_faces) { + const auto& face_vertices = faces[face_index]->vertices(); + assert(face_vertices.size() == 3); + for (size_t jj = 0; jj < 3; ++jj) + pattern.insert(vertex_index, face_vertices[jj]->index()); + } + } + pattern.sort(); + pattern_ = pattern; + // store basis evaluations + const auto& quadratures = basis_functions_.quadratures(); + assert(quadratures.size() == num_faces_); + for (size_t jj = 0; jj < num_faces_; ++jj) { + quad_points_[jj].resize(quadratures[jj].size()); + quad_weights_[jj].resize(quadratures[jj].size()); + for (size_t ll = 0; ll < quadratures[jj].size(); ++ll) { + const auto& quad_point = quadratures[jj][ll]; + quad_points_[jj][ll] = quad_point.position(); + quad_weights_[jj][ll] = quad_point.weight(); + } + } // jj + for (size_t jj = 0; jj < num_faces_; ++jj) { + M_[jj].resize(quad_points_[jj].size()); + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) + M_[jj][ll] = basis_functions_.evaluate_on_face(quad_points_[jj][ll], jj); + } // jj + + } // constructor + + + // ============================================================================================ + // ============================= FunctionInterface methods ==================================== + // ============================================================================================ + + + int order(const XT::Common::Parameter& /*param*/ = {}) const override + { + return 1; + } + + virtual RangeReturnType evaluate(const DomainType& u, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = get_alpha(u, *get_isotropic_alpha(u), true)->first; + return evaluate_with_alpha(alpha); + } + + RangeReturnType evaluate_with_alpha(const DomainType& alpha) const + { + const auto alpha_vec = XT::LA::convert_to<VectorType>(alpha); + return evaluate_with_alpha(alpha_vec); + } + + virtual RangeReturnType evaluate_with_alpha(const VectorType& alpha) const + { + RangeReturnType ret(0.); + LocalVectorType local_ret; + auto& eta_ast_prime_vals = working_storage(); + evaluate_eta_ast_prime(alpha, eta_ast_prime_vals); + const auto& faces = basis_functions_.triangulation().faces(); + for (size_t dd = 0; dd < dimFlux; ++dd) { + // calculate ret[dd] = < omega[dd] m G_\alpha(u) > + for (size_t jj = 0; jj < num_faces_; ++jj) { + local_ret *= 0.; + const auto& vertices = faces[jj]->vertices(); + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto& basis_ll = M_[jj][ll]; + auto factor_ll = eta_ast_prime_vals[jj][ll] * quad_points_[jj][ll][dd] * quad_weights_[jj][ll]; + for (size_t ii = 0; ii < 3; ++ii) + local_ret[ii] += basis_ll[ii] * factor_ll; + } // ll (quad points) + for (size_t ii = 0; ii < 3; ++ii) + ret[dd][vertices[ii]->index()] += local_ret[ii]; + } // jj (faces) + } // dd + return ret; + } // void evaluate(...) + + virtual void jacobian(const DomainType& u, + DynamicDerivativeRangeType& result, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = get_alpha(u, *get_isotropic_alpha(u), true)->first; + jacobian_with_alpha(alpha, result); + } + + void jacobian_with_alpha(const DomainType& alpha, DynamicDerivativeRangeType& result) const + { + const auto alpha_vec = XT::LA::convert_to<VectorType>(alpha); + jacobian_with_alpha(alpha_vec, result); + } + + void jacobian_with_alpha(const VectorType& alpha, DynamicDerivativeRangeType& result) const + { + thread_local SparseMatrixType H(basis_dimRange, basis_dimRange, pattern_, 0); + thread_local SparseMatrixType J(basis_dimRange, basis_dimRange, pattern_, 0); + calculate_hessian(alpha, M_, H); + for (size_t dd = 0; dd < dimFlux; ++dd) { + calculate_J(M_, J, dd); + calculate_J_Hinv(J, H, result[dd]); + } + } // ... jacobian(...) + + + // ============================================================================================ + // ============ Evaluations of ansatz distribution, moments, hessian etc. ===================== + // ============================================================================================ + + + std::unique_ptr<AlphaReturnType> get_alpha(const DomainType& u) const + { + return get_alpha(u, *get_isotropic_alpha(u), true); + } + + // Solves the minimum entropy optimization problem for u. + // returns (alpha, (actual_u, r)), where r is the regularization parameter and actual_u the regularized u + std::unique_ptr<AlphaReturnType> + get_alpha(const DomainType& u, const VectorType& alpha_in, const bool regularize) const + { + auto ret = std::make_unique<AlphaReturnType>(); + + RangeFieldType density = basis_functions_.density(u); + if (!(density > 0.) || std::isinf(density)) + DUNE_THROW(Dune::MathError, "Negative, inf or NaN density!"); + + constexpr bool rescale = (entropy == EntropyType::MaxwellBoltzmann); + + // rescale u such that the density <psi> is 1 if rescale is true + VectorType phi(basis_dimRange, 0., 0); + for (size_t ii = 0; ii < basis_dimRange; ++ii) + phi.set_entry(ii, rescale ? u[ii] / density : u[ii]); + VectorType alpha_one(basis_dimRange, 0., 0); + basis_functions_.alpha_one(alpha_one); + + RangeFieldType tau_prime = + rescale + ? std::min( + tau_ / ((1 + std::sqrt(basis_dimRange) * phi.l2_norm()) * density + std::sqrt(basis_dimRange) * tau_), + tau_) + : tau_; + thread_local SparseMatrixType H(basis_dimRange, basis_dimRange, pattern_, 0); +# if HAVE_EIGEN + typedef ::Eigen::SparseMatrix<RangeFieldType, ::Eigen::ColMajor> ColMajorBackendType; + typedef ::Eigen::SimplicialLDLT<ColMajorBackendType> SolverType; + thread_local SolverType solver; + ColMajorBackendType colmajor_copy(H.backend()); +# else // HAVE_EIGEN + thread_local auto solver = XT::LA::make_solver(H); +# endif // HAVE_EIGEN + + // calculate moment vector for isotropic distribution + VectorType u_iso(basis_dimRange, 0., 0); + basis_functions_.u_iso(u_iso); + if (!rescale) + u_iso *= density; + VectorType alpha_k = alpha_in; + if (rescale) + alpha_k -= alpha_one * std::log(density); + VectorType v(basis_dimRange, 0., 0), g_k(basis_dimRange, 0., 0), d_k(basis_dimRange, 0., 0), + tmp_vec(basis_dimRange, 0., 0), alpha_prime(basis_dimRange); + const auto& r_sequence = regularize ? r_sequence_ : std::vector<RangeFieldType>{0.}; + const auto r_max = r_sequence.back(); + for (const auto& rr : r_sequence_) { + // regularize u + v = phi; + if (rr > 0) { + alpha_k = *get_isotropic_alpha(v); + tmp_vec = u_iso; + tmp_vec *= rr; + v *= 1 - rr; + v += tmp_vec; + } + + // calculate f_0 + RangeFieldType f_k = calculate_f(alpha_k, v); + + int backtracking_failed = 0; + for (size_t kk = 0; kk < k_max_; ++kk) { + // exit inner for loop to increase r if too many iterations are used + if (kk > k_0_ && rr < r_max) + break; + // calculate gradient g + calculate_gradient(alpha_k, v, g_k); + // calculate Hessian H + calculate_hessian(alpha_k, M_, H, entropy == EntropyType::MaxwellBoltzmann); + // calculate descent direction d_k; + tmp_vec = g_k; + tmp_vec *= -1; + try { +# if HAVE_EIGEN + colmajor_copy = H.backend(); + solver.analyzePattern(colmajor_copy); + solver.factorize(colmajor_copy); + d_k.backend() = solver.solve(tmp_vec.backend()); +# else // HAVE_EIGEN + solver.apply(tmp_vec, d_k); +# endif // HAVE_EIGEN + } catch (const XT::LA::Exceptions::linear_solver_failed& error) { + if (rr < r_max) { + break; + } else { + DUNE_THROW(XT::LA::Exceptions::linear_solver_failed, + "Failure to converge, solver error was: " << error.what()); + } + } + + const auto& alpha_tilde = alpha_k; + auto& u_alpha_tilde = tmp_vec; + u_alpha_tilde = g_k; + u_alpha_tilde += v; + auto density_tilde = basis_functions_.density(u_alpha_tilde); + if (!(density_tilde > 0.) || std::isinf(density_tilde)) + break; + auto& u_eps_diff = tmp_vec; + if (rescale) { + alpha_prime = alpha_one; + alpha_prime *= -std::log(density_tilde); + alpha_prime += alpha_tilde; + calculate_u(alpha_prime, u_eps_diff); + } else { + alpha_prime = alpha_tilde; + u_eps_diff = u_alpha_tilde; + } + u_eps_diff *= -(1 - epsilon_gamma_); + u_eps_diff += v; + // checking realizability is cheap so we do not need the second stopping criterion + if (g_k.l2_norm() < tau_prime && is_realizable(u_eps_diff)) { + if (rescale) { + ret->first = alpha_one; + ret->first *= std::log(density); + ret->first += alpha_prime; + } else { + ret->first = alpha_prime; + } + const auto v_ret_eig = rescale ? v * density : v; + ret->second = std::make_pair(XT::LA::convert_to<DomainType>(v_ret_eig), rr); + return ret; + } else { + RangeFieldType zeta_k = 1; + // backtracking line search + auto& alpha_new = tmp_vec; + while (backtracking_failed >= 2 || zeta_k > epsilon_ * alpha_k.l2_norm() / d_k.l2_norm()) { + // calculate alpha_new = alpha_k + zeta_k d_k + alpha_new = d_k; + alpha_new *= zeta_k; + alpha_new += alpha_k; + // calculate f(alpha_new) + RangeFieldType f_new = calculate_f(alpha_new, v); + if (backtracking_failed >= 2 || XT::Common::FloatCmp::le(f_new, f_k + xi_ * zeta_k * (g_k * d_k))) { + alpha_k = alpha_new; + f_k = f_new; + backtracking_failed = 0; + break; + } + zeta_k = chi_ * zeta_k; + } // backtracking linesearch while + // if (zeta_k <= epsilon_ * alpha_k.two_norm() / d_k.two_norm() * 100.) + if (zeta_k <= epsilon_ * alpha_k.l2_norm() / d_k.l2_norm()) + ++backtracking_failed; + } // else (stopping conditions) + } // k loop (Newton iterations) + } // rr loop (Regularization parameter) + DUNE_THROW(MathError, "Failed to converge"); + return ret; + } // ... get_alpha(...) + + // returns density rho = < eta_ast_prime(alpha * b(v)) > + RangeFieldType get_rho(const DomainType& alpha) const + { + auto& eta_ast_prime_vals = working_storage(); + evaluate_eta_ast_prime(alpha, eta_ast_prime_vals); + RangeFieldType ret(0.); + for (size_t jj = 0; jj < num_faces_; ++jj) + ret += std::inner_product( + quad_weights_[jj].begin(), quad_weights_[jj].end(), eta_ast_prime_vals[jj].begin(), RangeFieldType(0.)); + return ret; + } + + // returns < eta_ast(alpha * b(v)) > + RangeFieldType get_eta_ast_integrated(const DomainType& alpha) const + { + return get_eta_ast_integrated(XT::LA::convert_to<VectorType>(alpha)); + } + + // returns < eta_ast(alpha * b(v)) > + RangeFieldType get_eta_ast_integrated(const VectorType& alpha) const + { + auto& eta_ast_vals = working_storage(); + evaluate_eta_ast(alpha, eta_ast_vals); + RangeFieldType ret(0.); + for (size_t jj = 0; jj < num_faces_; ++jj) + ret += std::inner_product( + quad_weights_[jj].begin(), quad_weights_[jj].end(), eta_ast_vals[jj].begin(), RangeFieldType(0.)); + return ret; + } + + DomainType get_u(const DomainType& alpha) const + { + VectorType u(basis_dimRange, 0., 0); + calculate_u(XT::LA::convert_to<VectorType>(alpha), u); + return XT::LA::convert_to<DomainType>(u); + } + + DomainType get_u(const QuadratureWeightsType& eta_ast_prime_vals) const + { + VectorType u(basis_dimRange, 0., 0); + calculate_u(eta_ast_prime_vals, u); + return XT::LA::convert_to<DomainType>(u); + } + + // calculate ret = < b eta_ast_prime(alpha * b) > + void calculate_u(const VectorType& alpha, VectorType& u) const + { + auto& eta_ast_prime_vals = working_storage(); + evaluate_eta_ast_prime(alpha, eta_ast_prime_vals); + calculate_u(eta_ast_prime_vals, u); + } // void calculate_u(...) + + // calculate ret = < b eta_ast_prime(alpha * b) > + void calculate_u(const QuadratureWeightsType& eta_ast_prime_vals, VectorType& u) const + { + u *= 0.; + LocalVectorType local_u; + const auto& faces = basis_functions_.triangulation().faces(); + for (size_t jj = 0; jj < num_faces_; ++jj) { + const auto& vertices = faces[jj]->vertices(); + std::fill(local_u.begin(), local_u.end(), 0.); + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto factor = eta_ast_prime_vals[jj][ll] * quad_weights_[jj][ll]; + for (size_t ii = 0; ii < 3; ++ii) + local_u[ii] += M_[jj][ll][ii] * factor; + } // ll (quad points) + for (size_t ii = 0; ii < 3; ++ii) + u.add_to_entry(vertices[ii]->index(), local_u[ii]); + } // jj (faces) + } // void calculate_u(...) + + RangeFieldType calculate_f(const VectorType& alpha, const VectorType& v) const + { + return get_eta_ast_integrated(alpha) - alpha * v; + } // void calculate_f(...) + + void calculate_gradient(const VectorType& alpha, const VectorType& v, VectorType& g_k) const + { + calculate_u(alpha, g_k); + g_k -= v; + } + + void calculate_hessian(const QuadratureWeightsType& eta_ast_twoprime_vals, + const BasisValuesMatrixType& M, + SparseMatrixType& H) const + { + H *= 0.; + LocalMatrixType H_local(0.); + const auto& faces = basis_functions_.triangulation().faces(); + for (size_t jj = 0; jj < num_faces_; ++jj) { + H_local *= 0.; + const auto& vertices = faces[jj]->vertices(); + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto& basis_ll = M[jj][ll]; + const auto factor = eta_ast_twoprime_vals[jj][ll] * quad_weights_[jj][ll]; + for (size_t ii = 0; ii < 3; ++ii) + for (size_t kk = 0; kk < 3; ++kk) + H_local[ii][kk] += basis_ll[ii] * basis_ll[kk] * factor; + } // ll (quad points) + for (size_t ii = 0; ii < 3; ++ii) + for (size_t kk = 0; kk < 3; ++kk) + H.add_to_entry(vertices[ii]->index(), vertices[kk]->index(), H_local[ii][kk]); + } // jj (faces) + } // void calculate_hessian(...) + + void calculate_hessian(const VectorType& alpha, + const BasisValuesMatrixType& M, + SparseMatrixType& H, + const bool use_working_storage = false) const + { + auto& eta_ast_twoprime_vals = working_storage(); + if (!use_working_storage) + evaluate_eta_ast_twoprime(alpha, eta_ast_twoprime_vals); + calculate_hessian(eta_ast_twoprime_vals, M, H); + } // void calculate_hessian(...) + + void apply_inverse_hessian(const QuadratureWeightsType& eta_ast_twoprime_vals, + const DomainType& u, + DomainType& Hinv_u) const + { + thread_local SparseMatrixType H(basis_dimRange, basis_dimRange, pattern_, 0); + calculate_hessian(eta_ast_twoprime_vals, M_, H); +# if HAVE_EIGEN + thread_local VectorType u_vec(basis_dimRange, 0., 0), Hinv_u_vec(basis_dimRange, 0., 0); + std::copy(u.begin(), u.end(), u_vec.begin()); + typedef ::Eigen::SparseMatrix<RangeFieldType, ::Eigen::ColMajor> ColMajorBackendType; + ColMajorBackendType colmajor_copy(H.backend()); + typedef ::Eigen::SimplicialLDLT<ColMajorBackendType> SolverType; + SolverType solver; + solver.analyzePattern(colmajor_copy); + solver.factorize(colmajor_copy); + Hinv_u_vec.backend() = solver.solve(u_vec.backend()); + std::copy(Hinv_u_vec.begin(), Hinv_u_vec.end(), Hinv_u.begin()); +# else // HAVE_EIGEN + auto solver = XT::LA::make_solver(H); + VectorType Hinv_u_la(basis_dimRange); + VectorType u_la = XT::Common::convert_to<VectorType>(u); + solver.apply(u_la, Hinv_u_la); + Hinv_u = XT::Common::convert_to<DomainType>(Hinv_u_la); +# endif + } // void apply_inverse_hessian(..) + + // J = df/dalpha is the derivative of the flux with respect to alpha. + // As F = (f_1, f_2, f_3) is matrix-valued + // (div f = \sum_{i=1}^d \partial_{x_i} f_i = \sum_{i=1}^d \partial_{x_i} < v_i m \hat{psi}(alpha) > is + // vector-valued), + // the derivative is the vector of matrices (df_1/dalpha, df_2/dalpha, ...) + // this function returns the dd-th matrix df_dd/dalpha of J + // assumes work_vecs already contains the needed \eta_{\ast}^{\prime \prime} (\alpha * b) values + void calculate_J(const BasisValuesMatrixType& M, SparseMatrixType& J_dd, const size_t dd) const + { + assert(dd < dimFlux); + J_dd *= 0.; + LocalMatrixType J_local(0.); + auto& eta_ast_twoprime_vals = working_storage(); + const auto& faces = basis_functions_.triangulation().faces(); + for (size_t jj = 0; jj < num_faces_; ++jj) { + J_local *= 0.; + const auto& vertices = faces[jj]->vertices(); + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto& basis_ll = M[jj][ll]; + const auto factor = eta_ast_twoprime_vals[jj][ll] * quad_points_[jj][ll][dd] * quad_weights_[jj][ll]; + for (size_t ii = 0; ii < 3; ++ii) + for (size_t kk = 0; kk < 3; ++kk) + J_local[ii][kk] += basis_ll[ii] * basis_ll[kk] * factor; + } // ll (quad points) + for (size_t ii = 0; ii < 3; ++ii) + for (size_t kk = 0; kk < 3; ++kk) + J_dd.add_to_entry(vertices[ii]->index(), vertices[kk]->index(), J_local[ii][kk]); + } // jj (faces) + } // void calculate_J(...) + + // calculates ret = J H^{-1}. H is assumed to be symmetric positive definite, which gives ret^T = H^{-T} J^T = + // H^{-1} J^T, so we just have to solve y = H^{-1} x for each row x of J + void calculate_J_Hinv(SparseMatrixType& J, const SparseMatrixType& H, DynamicRowDerivativeRangeType& ret) const + { + thread_local VectorType solution(basis_dimRange, 0., 0), tmp_rhs(basis_dimRange, 0., 0); +# if HAVE_EIGEN + typedef ::Eigen::SparseMatrix<RangeFieldType, ::Eigen::ColMajor> ColMajorBackendType; + ColMajorBackendType colmajor_copy(H.backend()); + typedef ::Eigen::SimplicialLDLT<ColMajorBackendType> SolverType; + SolverType solver; + solver.analyzePattern(colmajor_copy); + solver.factorize(colmajor_copy); +# else // HAVE_EIGEN + auto solver = XT::LA::make_solver(H); +# endif // HAVE_EIGEN + for (size_t ii = 0; ii < basis_dimRange; ++ii) { + // copy row to VectorType + for (size_t kk = 0; kk < basis_dimRange; ++kk) + tmp_rhs.set_entry(kk, J.get_entry(ii, kk)); + // solve +# if HAVE_EIGEN + solution.backend() = solver.solve(tmp_rhs.backend()); +# else // HAVE_EIGEN + solver.apply(tmp_rhs, solution); +# endif + // copy result to C + for (size_t kk = 0; kk < basis_dimRange; ++kk) + ret.set_entry(ii, kk, solution.get_entry(kk)); + } // ii + } // void calculate_J_Hinv(...) + + + // ============================================================================================ + // ============================= Entropy evaluations ========================================== + // ============================================================================================ + + + // evaluates \eta_{\ast}(\alpha^T b(v_i)) for all quadrature points v_i + void evaluate_eta_ast(const VectorType& alpha, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, ret); + apply_exponential(ret); + evaluate_eta_ast(ret); + } + + // evaluates \eta_{\ast}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already contains + // exp(alpha^T b(v_i)) + void evaluate_eta_ast(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t jj = 0; jj < num_faces_; ++jj) + for (size_t ll = 0; ll < ret[jj].size(); ++ll) + ret[jj][ll] = -std::log(1 - ret[jj][ll]); + } + + // evaluates \eta_{\ast}^{\prime}(\alpha^T b(v_i)) for all quadrature points v_i + void evaluate_eta_ast_prime(const VectorType& alpha, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, ret); + apply_exponential(ret); + evaluate_eta_ast_prime(ret); + } + + // evaluates \eta_{\ast}^{\prime}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already contains + // exp(alpha^T b(v_i)) + void evaluate_eta_ast_prime(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t jj = 0; jj < num_faces_; ++jj) + for (size_t ll = 0; ll < ret[jj].size(); ++ll) + ret[jj][ll] /= (1 - ret[jj][ll]); + } + + // evaluates \eta_{\ast}^{\prime\prime}(\alpha^T b(v_i)) for all quadrature points v_i + void evaluate_eta_ast_twoprime(const VectorType& alpha, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, ret); + apply_exponential(ret); + evaluate_eta_ast_twoprime(ret); + } + + // evaluates \eta_{\ast}^{\prime\prime}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already + // contains exp(alpha^T b(v_i)) + void evaluate_eta_ast_twoprime(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t jj = 0; jj < num_faces_; ++jj) + for (size_t ll = 0; ll < ret[jj].size(); ++ll) + ret[jj][ll] /= std::pow(1 - ret[jj][ll], 2); + } + + // stores evaluations of exp(alpha^T b(v_i)) for all quadrature points v_i + void store_exp_evaluations(QuadratureWeightsType& exp_evaluations, const DomainType& alpha) const + { + this->calculate_scalar_products(XT::LA::convert_to<VectorType>(alpha), exp_evaluations); + this->apply_exponential(exp_evaluations); + } + + void store_eta_ast_prime_vals(const QuadratureWeightsType& exp_evaluations, QuadratureWeightsType& eta_ast_prime_vals) + { + eta_ast_prime_vals = exp_evaluations; + evaluate_eta_ast_prime(eta_ast_prime_vals); + } + + void store_eta_ast_twoprime_vals(const QuadratureWeightsType& exp_evaluations, + QuadratureWeightsType& eta_ast_twoprime_vals) + { + eta_ast_twoprime_vals = exp_evaluations; + evaluate_eta_ast_twoprime(eta_ast_twoprime_vals); + } + + // stores evaluations of a given boundary distribution psi(v) at all quadrature points v_i + void store_boundary_distribution_evaluations( + QuadratureWeightsType& boundary_distribution_evaluations, + const std::function<RangeFieldType(const FluxDomainType&)>& boundary_distribution) const + { + boundary_distribution_evaluations.resize(num_faces_); + for (size_t jj = 0; jj < num_faces_; ++jj) { + boundary_distribution_evaluations[jj].resize(quad_points_[jj].size()); + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) + boundary_distribution_evaluations[jj][ll] = boundary_distribution(quad_points_[jj][ll]); + } + } + + + // ============================================================================================ + // =============================== Kinetic fluxes ============================================= + // ============================================================================================ + + + DomainType + evaluate_kinetic_flux(const DomainType& u_i, const DomainType& u_j, const FluxDomainType& n_ij, const size_t dd) const + { + const auto alpha_i = get_alpha(u_i, *get_isotropic_alpha(u_i), true)->first; + const auto alpha_j = get_alpha(u_j, *get_isotropic_alpha(u_j), true)->first; + return evaluate_kinetic_flux_with_alphas(alpha_i, alpha_j, n_ij, dd); + } // DomainType evaluate_kinetic_flux(...) + + DomainType evaluate_kinetic_flux_with_alphas(const DomainType& alpha_i, + const DomainType& alpha_j, + const FluxDomainType& n_ij, + const size_t dd) const + { + return evaluate_kinetic_flux_with_alphas( + XT::LA::convert_to<VectorType>(alpha_i), XT::LA::convert_to<VectorType>(alpha_j), n_ij, dd); + } + + DomainType evaluate_kinetic_flux_with_alphas(const VectorType& alpha_i, + const VectorType& alpha_j, + const FluxDomainType& n_ij, + const size_t dd) const + { + thread_local FieldVector<QuadratureWeightsType, 2> eta_ast_prime_vals; + eta_ast_prime_vals[0].resize(num_faces_); + eta_ast_prime_vals[1].resize(num_faces_); + for (size_t jj = 0; jj < num_faces_; ++jj) { + eta_ast_prime_vals[0][jj].resize(quad_points_[jj].size()); + eta_ast_prime_vals[1][jj].resize(quad_points_[jj].size()); + } + evaluate_eta_ast_prime(alpha_i, eta_ast_prime_vals[0]); + evaluate_eta_ast_prime(alpha_j, eta_ast_prime_vals[1]); + // calculate \sum_{i=1}^d < \omega_i m G_\alpha(u) > n_i + DomainType ret(0); + const auto& faces = basis_functions_.triangulation().faces(); + LocalVectorType local_ret; + for (size_t jj = 0; jj < num_faces_; ++jj) { + local_ret *= 0.; + const auto& vertices = faces[jj]->vertices(); + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto position = quad_points_[jj][ll][dd]; + RangeFieldType factor = + position * n_ij[dd] > 0. ? eta_ast_prime_vals[0][jj][ll] : eta_ast_prime_vals[1][jj][ll]; + factor *= quad_weights_[jj][ll] * position; + for (size_t ii = 0; ii < 3; ++ii) + local_ret[ii] += M_[jj][ll][ii] * factor; + } // ll (quad points) + for (size_t ii = 0; ii < 3; ++ii) + ret[vertices[ii]->index()] += local_ret[ii]; + } // jj (faces) + ret *= n_ij[dd]; + return ret; + } // DomainType evaluate_kinetic_flux(...) + + // Calculates left and right kinetic flux with reconstructed densities. Ansatz distribution values contains + // evaluations of the ansatz distribution at each quadrature point for a stencil of three entities. The distributions + // are reconstructed pointwise for each quadrature point and the resulting (part of) the kinetic flux is < + // psi_reconstr * b * v>_{+/-}. + template <SlopeLimiterType slope_type, class FluxesMapType> + void calculate_reconstructed_fluxes(const FieldVector<const QuadratureWeightsType*, 3>& ansatz_distribution_values, + FluxesMapType& flux_values, + const size_t dd) const + { + // get flux storage + BasisDomainType coord(0.5); + coord[dd] = 0; + auto& left_flux_value = flux_values[coord]; + coord[dd] = 1; + auto& right_flux_value = flux_values[coord]; + right_flux_value = left_flux_value = DomainType(0.); + thread_local XT::Common::FieldVector<std::vector<RangeFieldType>, 2> reconstructed_values( + std::vector<RangeFieldType>(quad_points_[0].size())); + const auto& faces = basis_functions_.triangulation().faces(); + const auto slope_func = + (slope_type == SlopeLimiterType::minmod) ? XT::Common::minmod<RangeFieldType> : superbee<RangeFieldType>; + auto& vals_left = reconstructed_values[0]; + auto& vals_right = reconstructed_values[1]; + for (size_t jj = 0; jj < num_faces_; ++jj) { + const auto& vertices = faces[jj]->vertices(); + // reconstruct densities + if (slope_type == SlopeLimiterType::no_slope) { + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) + vals_left[ll] = vals_right[ll] = (*ansatz_distribution_values[1])[jj][ll]; + } else { + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto slope = + slope_func((*ansatz_distribution_values[1])[jj][ll] - (*ansatz_distribution_values[0])[jj][ll], + (*ansatz_distribution_values[2])[jj][ll] - (*ansatz_distribution_values[1])[jj][ll]); + vals_left[ll] = (*ansatz_distribution_values[1])[jj][ll] - 0.5 * slope; + vals_right[ll] = (*ansatz_distribution_values[1])[jj][ll] + 0.5 * slope; + } // ll (quad points) + } + // calculate fluxes + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto& position = quad_points_[jj][ll][dd]; + RangeFieldType factor = position > 0. ? vals_right[ll] : vals_left[ll]; + factor *= quad_weights_[jj][ll] * position; + auto& val = position > 0. ? right_flux_value : left_flux_value; + const auto& basis_ll = M_[jj][ll]; + for (size_t ii = 0; ii < 3; ++ii) + val[vertices[ii]->index()] += basis_ll[ii] * factor; + } // ll (quad points) + } // jj + } // void calculate_reconstructed_fluxes(...) + + + // ============================================================================================ + // ================================== Helper functions ======================================== + // ============================================================================================ + + + std::unique_ptr<VectorType> get_isotropic_alpha(const RangeFieldType density) const + { + const auto alpha_iso_dynvector = basis_functions_.alpha_iso(density); + auto ret = std::make_unique<VectorType>(alpha_iso_dynvector.size(), 0., 0); + for (size_t ii = 0; ii < ret->size(); ++ii) + (*ret)[ii] = alpha_iso_dynvector[ii]; + return ret; + } + + std::unique_ptr<VectorType> get_isotropic_alpha(const DomainType& u) const + { + return get_isotropic_alpha(basis_functions_.density(u)); + } + + std::unique_ptr<VectorType> get_isotropic_alpha(const VectorType& u) const + { + auto u_domain = std::make_unique<DomainType>(); + for (size_t ii = 0; ii < dimFlux; ++ii) + (*u_domain)[ii] = u.get_entry(ii); + return get_isotropic_alpha(*u_domain); + } + + const MomentBasis& basis_functions() const + { + return basis_functions_; + } + + static bool is_realizable(const VectorType& u) + { + for (const auto& u_i : u) + if (!(u_i > 0.) || std::isinf(u_i)) + return false; + return true; + } + + // temporary vectors to store inner products and exponentials + std::vector<std::vector<RangeFieldType>>& working_storage() const + { + thread_local std::vector<std::vector<RangeFieldType>> work_vecs; + work_vecs.resize(num_faces_); + for (size_t jj = 0; jj < num_faces_; ++jj) + work_vecs[jj].resize(quad_points_[jj].size()); + return work_vecs; + } + + bool all_positive(const QuadratureWeightsType& vals) const + { + for (size_t jj = 0; jj < num_faces_; ++jj) + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) { + const auto val = vals[jj][ll]; + if (val < 0. || std::isinf(val) || std::isnan(val)) + return false; + } + return true; + } + + void calculate_scalar_products(const VectorType& alpha, QuadratureWeightsType& scalar_products) const + { + LocalVectorType local_alpha; + const auto& faces = basis_functions_.triangulation().faces(); + scalar_products.resize(num_faces_); + for (size_t jj = 0; jj < num_faces_; ++jj) { + scalar_products[jj].resize(quad_weights_[jj].size()); + const auto& vertices = faces[jj]->vertices(); + for (size_t ii = 0; ii < 3; ++ii) + local_alpha[ii] = alpha.get_entry(vertices[ii]->index()); + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) + scalar_products[jj][ll] = local_alpha * M_[jj][ll]; + } // jj + } + + void apply_exponential(QuadratureWeightsType& values) const + { + for (size_t jj = 0; jj < num_faces_; ++jj) { + assert(values[jj].size() < std::numeric_limits<int>::max()); + XT::Common::Mkl::exp(static_cast<int>(values[jj].size()), values[jj].data(), values[jj].data()); + } + } + + const MomentBasis& basis_functions_; + QuadraturePointsType quad_points_; + QuadratureWeightsType quad_weights_; + BasisValuesMatrixType M_; + const RangeFieldType tau_; + const RangeFieldType epsilon_gamma_; + const RangeFieldType chi_; + const RangeFieldType xi_; + const std::vector<RangeFieldType> r_sequence_; + const size_t k_0_; + const size_t k_max_; + const RangeFieldType epsilon_; + const size_t num_faces_; + XT::LA::SparsityPatternDefault pattern_; +}; +#endif // ENTROPY_FLUX_USE_3D_HATFUNCTIONS_SPECIALIZATION + +#if ENTROPY_FLUX_USE_1D_HATFUNCTIONS_SPECIALIZATION +# if ENTROPY_FLUX_1D_HATFUNCTIONS_USE_ANALYTICAL_INTEGRALS +/** + * Specialization of EntropyBasedFluxImplementation for 1D Hatfunctions with MaxwellBoltzmann entropy + * (no change of basis, analytic integrals + Taylor) + */ +template <class D, class R, size_t dimRange, EntropyType entropy> +class EntropyBasedFluxImplementation<HatFunctionMomentBasis<D, 1, R, dimRange, 1, 1, entropy>> + : public XT::Functions::FunctionInterface<dimRange, 1, dimRange, R> +{ + using BaseType = typename XT::Functions::FunctionInterface<dimRange, 1, dimRange, R>; + using ThisType = EntropyBasedFluxImplementation; + +public: + using MomentBasis = HatFunctionMomentBasis<D, 1, R, dimRange, 1, 1, entropy>; + static const size_t dimFlux = MomentBasis::dimFlux; + static const size_t basis_dimRange = dimRange; + using typename BaseType::DomainFieldType; + using typename BaseType::DomainType; + using typename BaseType::DynamicDerivativeRangeType; + using typename BaseType::DynamicRowDerivativeRangeType; + using typename BaseType::RangeFieldType; + using typename BaseType::RangeReturnType; + using BasisDomainType = typename MomentBasis::DomainType; + using FluxDomainType = FieldVector<DomainFieldType, dimFlux>; + using VectorType = XT::Common::FieldVector<RangeFieldType, basis_dimRange>; + using AlphaReturnType = std::pair<VectorType, std::pair<DomainType, RangeFieldType>>; + static_assert(entropy == EntropyType::MaxwellBoltzmann, "Not implemented for other entropies"); + + explicit EntropyBasedFluxImplementation(const MomentBasis& basis_functions, + const RangeFieldType tau, + const bool /*disable_realizability_check*/, + const RangeFieldType epsilon_gamma, + const RangeFieldType chi, + const RangeFieldType xi, + const std::vector<RangeFieldType> r_sequence, + const size_t k_0, + const size_t k_max, + const RangeFieldType epsilon, + const RangeFieldType taylor_tol = 0.1, + const size_t max_taylor_order = 200) + : basis_functions_(basis_functions) + , v_points_(basis_functions_.partitioning()) + , tau_(tau) + , epsilon_gamma_(epsilon_gamma) + , chi_(chi) + , xi_(xi) + , r_sequence_(r_sequence) + , k_0_(k_0) + , k_max_(k_max) + , epsilon_(epsilon) + , taylor_tol_(taylor_tol) + , max_taylor_order_(max_taylor_order) + {} + + + // ============================================================================================ + // ============================= FunctionInterface methods ==================================== + // ============================================================================================ + + + int order(const XT::Common::Parameter& /*param*/) const override + { + return 1; + } + + virtual RangeReturnType evaluate(const DomainType& u, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = get_alpha(u, *get_isotropic_alpha(u), true)->first; + return evaluate_with_alpha(alpha); + } + + virtual RangeReturnType evaluate_with_alpha(const VectorType& alpha) const + { + RangeReturnType ret(0.); + // calculate < \mu m G_\alpha(u) > + for (size_t nn = 0; nn < dimRange; ++nn) { + if (nn > 0) { + if (std::abs(alpha[nn] - alpha[nn - 1]) > taylor_tol_) { + ret[0][nn] += + 2. * std::pow(v_points_[nn] - v_points_[nn - 1], 2) / std::pow(alpha[nn] - alpha[nn - 1], 3) + * (std::exp(alpha[nn]) - std::exp(alpha[nn - 1])) + + (v_points_[nn] - v_points_[nn - 1]) / std::pow(alpha[nn] - alpha[nn - 1], 2) + * (v_points_[nn - 1] * (std::exp(alpha[nn]) + std::exp(alpha[nn - 1])) + - 2 * v_points_[nn] * std::exp(alpha[nn])) + + v_points_[nn] * (v_points_[nn] - v_points_[nn - 1]) / (alpha[nn] - alpha[nn - 1]) * std::exp(alpha[nn]); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha[nn] - alpha[nn - 1]; + size_t ll = 0; + auto pow_frac = 1. / 6.; + while (ll <= max_taylor_order_ - 3 && XT::Common::FloatCmp::ne(update, 0.)) { + update = pow_frac * ((ll * ll + 3 * ll + 2) * v_points_[nn] + (ll + 1) * v_points_[nn - 1]); + result += update; + ++ll; + pow_frac *= base / (ll + 3); + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + ret[0][nn] += result * (v_points_[nn] - v_points_[nn - 1]) * std::exp(alpha[nn - 1]); + } + } + if (nn < dimRange - 1) { + if (std::abs(alpha[nn + 1] - alpha[nn]) > taylor_tol_) { + ret[0][nn] += + -2. * std::pow(v_points_[nn + 1] - v_points_[nn], 2) / std::pow(alpha[nn + 1] - alpha[nn], 3) + * (std::exp(alpha[nn + 1]) - std::exp(alpha[nn])) + + (v_points_[nn + 1] - v_points_[nn]) / std::pow(alpha[nn + 1] - alpha[nn], 2) + * (v_points_[nn + 1] * (std::exp(alpha[nn + 1]) + std::exp(alpha[nn])) + - 2 * v_points_[nn] * std::exp(alpha[nn])) + - v_points_[nn] * (v_points_[nn + 1] - v_points_[nn]) / (alpha[nn + 1] - alpha[nn]) * std::exp(alpha[nn]); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha[nn + 1] - alpha[nn]; + size_t ll = 0; + auto pow_frac = 1. / 6.; + while (ll < 3 || (ll <= max_taylor_order_ - 3 && XT::Common::FloatCmp::ne(update, 0.))) { + update = pow_frac * (2 * v_points_[nn] + (ll + 1) * v_points_[nn + 1]); + result += update; + ++ll; + pow_frac *= base / (ll + 3); + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + ret[0][nn] += result * (v_points_[nn + 1] - v_points_[nn]) * std::exp(alpha[nn]); + } + } // if (nn < dimRange - 1) + } // nn + return ret; + } // void evaluate_with_alpha(...) + + virtual void jacobian(const DomainType& u, + DynamicDerivativeRangeType& result, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = get_alpha(u, *get_isotropic_alpha(u), true)->first; + jacobian_with_alpha(alpha, result); + } + + virtual void jacobian_with_alpha(const VectorType& alpha, DynamicDerivativeRangeType& result) const + { + VectorType H_diag, J_diag; + XT::Common::FieldVector<RangeFieldType, dimRange - 1> H_subdiag, J_subdiag; + calculate_hessian(alpha, H_diag, H_subdiag); + calculate_J(alpha, J_diag, J_subdiag); + calculate_J_Hinv(result[0], J_diag, J_subdiag, H_diag, H_subdiag); + } + + + // ============================================================================================ + // =============================== Kinetic fluxes ============================================= + // ============================================================================================ + + + // calculate \sum_{i=1}^d < v_i m \psi > n_i, where n is the unit outer normal, + // m is the basis function vector, \psi is the ansatz corresponding to u + // and x, v, t are the space, velocity and time variable, respectively + // As we are using cartesian grids, n_i == 0 in all but one dimension, so only evaluate for i == dd + DomainType + evaluate_kinetic_flux(const DomainType& u_i, const DomainType& u_j, const FluxDomainType& n_ij, const size_t dd) const + { + // calculate \sum_{i=1}^d < \omega_i m G_\alpha(u) > n_i + const auto alpha_i = get_alpha(u_i, *get_isotropic_alpha(u_i), true)->first; + const auto alpha_j = get_alpha(u_j, *get_isotropic_alpha(u_j), true)->first; + evaluate_kinetic_flux_with_alphas(alpha_i, alpha_j, n_ij, dd); + } // DomainType evaluate_kinetic_flux(...) + + DomainType evaluate_kinetic_flux_with_alphas(const VectorType& alpha_i, + const VectorType& alpha_j, + const FluxDomainType& n_ij, + const size_t dd) const + { + assert(dd == 0); + // calculate < \mu m G_\alpha(u) > * n_ij + DomainType ret(0); + for (size_t nn = 0; nn < dimRange; ++nn) { + if (nn > 0) { + if (dimRange % 2 || nn != dimRange / 2) { + const auto& alpha = (n_ij[0] * (v_points_[nn - 1] + v_points_[nn]) / 2. > 0.) ? alpha_i : alpha_j; + if (std::abs(alpha[nn] - alpha[nn - 1]) > taylor_tol_) { + ret[nn] += 2. * std::pow(v_points_[nn] - v_points_[nn - 1], 2) / std::pow(alpha[nn] - alpha[nn - 1], 3) + * (std::exp(alpha[nn]) - std::exp(alpha[nn - 1])) + + (v_points_[nn] - v_points_[nn - 1]) / std::pow(alpha[nn] - alpha[nn - 1], 2) + * (v_points_[nn - 1] * (std::exp(alpha[nn]) + std::exp(alpha[nn - 1])) + - 2 * v_points_[nn] * std::exp(alpha[nn])) + + v_points_[nn] * (v_points_[nn] - v_points_[nn - 1]) / (alpha[nn] - alpha[nn - 1]) + * std::exp(alpha[nn]); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha[nn - 1] - alpha[nn]; + size_t ll = 0; + auto pow_frac = 1. / 6.; + while (ll < 3 || (ll <= max_taylor_order_ - 3 && XT::Common::FloatCmp::ne(update, 0.))) { + update = pow_frac * (2 * v_points_[nn] + (ll + 1) * v_points_[nn - 1]); + result += update; + ++ll; + pow_frac *= base / (ll + 3); + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + ret[nn] += result * (v_points_[nn] - v_points_[nn - 1]) * std::exp(alpha[nn]); + } + } else { // if (dimRange % 2 || nn != dimRange/2) + const auto& alpha_pos = n_ij[0] > 0. ? alpha_i : alpha_j; + const auto& alpha_neg = n_ij[0] > 0. ? alpha_j : alpha_i; + if (std::abs(alpha_neg[nn] - alpha_neg[nn - 1]) > taylor_tol_) { + ret[nn] += -2. * std::pow(v_points_[nn], 2) + * (4. / std::pow(alpha_neg[nn - 1] - alpha_neg[nn], 3) + * (std::exp((alpha_neg[nn] + alpha_neg[nn - 1]) / 2.) - std::exp(alpha_neg[nn - 1])) + + 1. / std::pow(alpha_neg[nn - 1] - alpha_neg[nn], 2) + * (std::exp((alpha_neg[nn] + alpha_neg[nn - 1]) / 2.) + std::exp(alpha_neg[nn - 1]))); + + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha_neg[nn] - alpha_neg[nn - 1]; + size_t ll = 2; + auto pow_frac = 1. / 24.; + while (ll <= max_taylor_order_ - 1 && XT::Common::FloatCmp::ne(update, 0.)) { + update = pow_frac * (ll - 1.); + result += update; + ++ll; + pow_frac *= base / (2. * (ll + 1)); + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + ret[nn] += result * -2. * std::pow(v_points_[nn], 2) * std::exp(alpha_neg[nn - 1]); + } + if (std::abs(alpha_pos[nn] - alpha_pos[nn - 1]) > taylor_tol_) { + ret[nn] += 2. * std::pow(v_points_[nn], 2) + * (4. / std::pow(alpha_pos[nn - 1] - alpha_pos[nn], 3) + * (std::exp((alpha_pos[nn] + alpha_pos[nn - 1]) / 2.) - std::exp(alpha_pos[nn])) + + 1. / std::pow(alpha_pos[nn - 1] - alpha_pos[nn], 2) + * (std::exp((alpha_pos[nn] + alpha_pos[nn - 1]) / 2.) - 3. * std::exp(alpha_pos[nn])) + - 1. / (alpha_pos[nn - 1] - alpha_pos[nn]) * std::exp(alpha_pos[nn])); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha_pos[nn - 1] - alpha_pos[nn]; + auto pow_frac = 1. / 24.; + size_t ll = 2; + while (ll <= max_taylor_order_ - 1 && XT::Common::FloatCmp::ne(update, 0.)) { + update = pow_frac * (ll + 3); + result += update; + ++ll; + pow_frac *= base / (2. * (ll + 1)); + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + ret[nn] += result * 2. * std::pow(v_points_[nn], 2) * std::exp(alpha_pos[nn]); + } // else (alpha_n - alpha_{n-1} != 0) + } // else (dimRange % 2 || nn != dimRange/2) + } // if (nn > 0) + if (nn < dimRange - 1) { + if (dimRange % 2 || nn != dimRange / 2 - 1) { + const auto& alpha = (n_ij[0] * (v_points_[nn] + v_points_[nn + 1]) / 2. > 0.) ? alpha_i : alpha_j; + if (XT::Common::FloatCmp::ne(alpha[nn + 1], alpha[nn], 0., taylor_tol_)) { + ret[nn] += -2. * std::pow(v_points_[nn + 1] - v_points_[nn], 2) / std::pow(alpha[nn + 1] - alpha[nn], 3) + * (std::exp(alpha[nn + 1]) - std::exp(alpha[nn])) + + (v_points_[nn + 1] - v_points_[nn]) / std::pow(alpha[nn + 1] - alpha[nn], 2) + * (v_points_[nn + 1] * (std::exp(alpha[nn + 1]) + std::exp(alpha[nn])) + - 2 * v_points_[nn] * std::exp(alpha[nn])) + - v_points_[nn] * (v_points_[nn + 1] - v_points_[nn]) / (alpha[nn + 1] - alpha[nn]) + * std::exp(alpha[nn]); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha[nn + 1] - alpha[nn]; + size_t ll = 0; + auto pow_frac = 1. / 6.; + while (ll < 3 + || (ll <= max_taylor_order_ - 3 && XT::Common::FloatCmp::ne(result, result + update, 1e-16, 0.))) { + update = pow_frac * (2 * v_points_[nn] + (ll + 1) * v_points_[nn + 1]); + result += update; + ++ll; + pow_frac *= base / (ll + 3); + } // ll + ret[nn] += result * (v_points_[nn + 1] - v_points_[nn]) * std::exp(alpha[nn]); + } + } else { // if (dimRange % 2 || nn != dimRange / 2 - 1) + const auto& alpha_pos = n_ij[0] > 0. ? alpha_i : alpha_j; + const auto& alpha_neg = n_ij[0] > 0. ? alpha_j : alpha_i; + if (std::abs(alpha_neg[nn + 1] - alpha_neg[nn]) > taylor_tol_) { + ret[nn] += -2. * std::pow(v_points_[nn + 1], 2) + * (-4. / std::pow(alpha_neg[nn + 1] - alpha_neg[nn], 3) + * (std::exp(alpha_neg[nn]) - std::exp((alpha_neg[nn + 1] + alpha_neg[nn]) / 2.)) + - 1. / std::pow(alpha_neg[nn + 1] - alpha_neg[nn], 2) + * (3 * std::exp(alpha_neg[nn]) - std::exp((alpha_neg[nn + 1] + alpha_neg[nn]) / 2.)) + - 1. / (alpha_neg[nn + 1] - alpha_neg[nn]) * std::exp(alpha_neg[nn])); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha_neg[nn + 1] - alpha_neg[nn]; + auto pow_frac = 1. / 24.; + size_t ll = 2; + while (ll <= max_taylor_order_ - 1 && XT::Common::FloatCmp::ne(update, 0.)) { + update = pow_frac * (ll + 3); + result += update; + ++ll; + pow_frac *= base / (2. * (ll + 1)); + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + ret[nn] += result * -2. * std::pow(v_points_[nn + 1], 2) * std::exp(alpha_neg[nn]); + } + if (std::abs(alpha_pos[nn + 1] - alpha_pos[nn]) > taylor_tol_) { + ret[nn] += 2. * std::pow(v_points_[nn + 1], 2) + * (4. / std::pow(alpha_pos[nn + 1] - alpha_pos[nn], 3) + * (std::exp((alpha_pos[nn + 1] + alpha_pos[nn]) / 2.) - std::exp(alpha_pos[nn + 1])) + + 1. / std::pow(alpha_pos[nn + 1] - alpha_pos[nn], 2) + * (std::exp((alpha_pos[nn + 1] + alpha_pos[nn]) / 2.) + std::exp(alpha_pos[nn + 1]))); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha_pos[nn] - alpha_pos[nn + 1]; + auto pow_frac = 1. / 24.; + size_t ll = 2; + while (ll <= max_taylor_order_ - 1 && XT::Common::FloatCmp::ne(update, 0.)) { + update = pow_frac * (ll - 1.); + result += update; + ++ll; + pow_frac *= base / (2. * (ll + 1)); + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + ret[nn] += result * 2. * std::pow(v_points_[nn + 1], 2) * std::exp(alpha_pos[nn + 1]); + } // else (alpha_n - alpha_{n-1} != 0) + } // else (dimRange % 2 || nn != dimRange / 2 - 1) + } // if (nn < dimRange - 1) + } // nn + ret *= n_ij[0]; + return ret; + } // DomainType evaluate_kinetic_flux(...) + + + // ============================================================================================ + // ============ Evaluations of ansatz distribution, moments, hessian etc. ===================== + // ============================================================================================ + + + std::unique_ptr<AlphaReturnType> get_alpha(const DomainType& u) const + { + return get_alpha(u, *get_isotropic_alpha(u), true); + } + + // returns (alpha, (actual_u, r)), where r is the regularization parameter and actual_u the regularized u + std::unique_ptr<AlphaReturnType> + get_alpha(const DomainType& u, const VectorType& alpha_in, const bool regularize) const + { + auto ret = std::make_unique<AlphaReturnType>(); + // rescale u such that the density <psi> is 1 + RangeFieldType density = basis_functions_.density(u); + if (!(density > 0.) || std::isinf(density)) + DUNE_THROW(Dune::MathError, "Negative, inf or NaN density!"); + static const auto alpha_one = basis_functions_.alpha_one(); + VectorType phi = u / density; + VectorType alpha_initial = alpha_in - alpha_one * std::log(density); + RangeFieldType tau_prime = + std::min(tau_ / ((1 + std::sqrt(dimRange) * phi.two_norm()) * density + std::sqrt(dimRange) * tau_), tau_); + // The hessian H is always symmetric and tridiagonal, so we only need to store the diagonal and subdiagonal + // elements + VectorType H_diag; + FieldVector<RangeFieldType, dimRange - 1> H_subdiag; + + // calculate moment vector for isotropic distribution + VectorType u_iso = basis_functions_.u_iso(); + VectorType v; + VectorType alpha_k = alpha_initial; + const auto& r_sequence = regularize ? r_sequence_ : std::vector<RangeFieldType>{0.}; + const auto r_max = r_sequence.back(); + for (const auto& rr : r_sequence_) { + // regularize u + v = phi; + if (rr > 0) { + alpha_k = *get_isotropic_alpha(v); + VectorType r_times_u_iso(u_iso); + r_times_u_iso *= rr; + v *= 1 - rr; + v += r_times_u_iso; + } + + // calculate f_0 + RangeFieldType f_k = calculate_f(alpha_k, v); + + int backtracking_failed = 0; + for (size_t kk = 0; kk < k_max_; ++kk) { + // exit inner for loop to increase r if too many iterations are used + if (kk > k_0_ && rr < r_max) + break; + // calculate gradient g + VectorType g_k = calculate_gradient(alpha_k, v); + // calculate Hessian H + calculate_hessian(alpha_k, H_diag, H_subdiag); + // calculate descent direction d_k; + VectorType d_k(0), minus_g_k(g_k); + minus_g_k *= -1; + try { + d_k = minus_g_k; + XT::LA::solve_sym_tridiag_posdef(H_diag, H_subdiag, d_k); + } catch (const Dune::MathError&) { + if (rr < r_max) + break; + else + DUNE_THROW(Dune::MathError, "Failure to converge!"); + } + + const auto& alpha_tilde = alpha_k; + const auto u_alpha_tilde = g_k + v; + auto density_tilde = basis_functions_.density(u_alpha_tilde); + if (!(density_tilde > 0.) || std::isinf(density_tilde)) + break; + const auto alpha_prime = alpha_tilde - alpha_one * std::log(density_tilde); + const auto u_alpha_prime = calculate_u(alpha_prime); + auto u_eps_diff = v - u_alpha_prime * (1 - epsilon_gamma_); + // checking realizability is cheap so we do not need the second stopping criterion + if (g_k.two_norm() < tau_prime && is_realizable(u_eps_diff)) { + ret->first = alpha_prime + alpha_one * std::log(density); + ret->second = std::make_pair(v * density, rr); + return ret; + } else { + RangeFieldType zeta_k = 1; + // backtracking line search + while (backtracking_failed >= 2 || zeta_k > epsilon_ * alpha_k.two_norm() / d_k.two_norm()) { + // while (backtracking_failed >= 2 || zeta_k > epsilon_ * alpha_k.two_norm() / d_k.two_norm() * 100.) { + // calculate alpha_new = alpha_k + zeta_k d_k + auto alpha_new = d_k; + alpha_new *= zeta_k; + alpha_new += alpha_k; + // calculate f(alpha_new) + RangeFieldType f_new = calculate_f(alpha_new, v); + if (backtracking_failed >= 2 || XT::Common::FloatCmp::le(f_new, f_k + xi_ * zeta_k * (g_k * d_k))) { + alpha_k = alpha_new; + f_k = f_new; + backtracking_failed = 0.; + break; + } + zeta_k = chi_ * zeta_k; + } // backtracking linesearch while + // if (zeta_k <= epsilon_ * alpha_k.two_norm() / d_k.two_norm() * 100.) + if (zeta_k <= epsilon_ * alpha_k.two_norm() / d_k.two_norm()) + ++backtracking_failed; + } // else (stopping conditions) + } // k loop (Newton iterations) + } // rr loop (Regularization parameter) + DUNE_THROW(MathError, "Failed to converge"); + + return ret; + } // ... get_alpha(...) + + DomainType get_u(const DomainType& alpha) const + { + return calculate_u(alpha); + } + + VectorType calculate_u(const VectorType& alpha_k) const + { + VectorType u(0); + for (size_t nn = 0; nn < dimRange; ++nn) { + if (nn > 0) { + if (std::abs(alpha_k[nn] - alpha_k[nn - 1]) > taylor_tol_) { + u[nn] += -(v_points_[nn] - v_points_[nn - 1]) / std::pow(alpha_k[nn] - alpha_k[nn - 1], 2) + * (std::exp(alpha_k[nn]) - std::exp(alpha_k[nn - 1])) + + (v_points_[nn] - v_points_[nn - 1]) / (alpha_k[nn] - alpha_k[nn - 1]) * std::exp(alpha_k[nn]); + } else { + RangeFieldType result = 0.; + RangeFieldType base = alpha_k[nn - 1] - alpha_k[nn]; + size_t ll = 0; + RangeFieldType update = 1; + RangeFieldType pow_frac = 0.5; + while (ll <= max_taylor_order_ - 2 && XT::Common::FloatCmp::ne(update, 0.)) { + update = pow_frac; + result += update; + ++ll; + pow_frac *= base / (ll + 2); + } + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + u[nn] += result * (v_points_[nn] - v_points_[nn - 1]) * std::exp(alpha_k[nn]); + } + } // if (nn > 0) + if (nn < dimRange - 1) { + if (std::abs(alpha_k[nn + 1] - alpha_k[nn]) > taylor_tol_) { + u[nn] += (v_points_[nn + 1] - v_points_[nn]) / std::pow(alpha_k[nn + 1] - alpha_k[nn], 2) + * (std::exp(alpha_k[nn + 1]) - std::exp(alpha_k[nn])) + - (v_points_[nn + 1] - v_points_[nn]) / (alpha_k[nn + 1] - alpha_k[nn]) * std::exp(alpha_k[nn]); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + size_t ll = 0; + RangeFieldType base = alpha_k[nn + 1] - alpha_k[nn]; + auto pow_frac = 0.5; + while (ll <= max_taylor_order_ - 2 && XT::Common::FloatCmp::ne(update, 0.)) { + update = pow_frac; + result += update; + ++ll; + pow_frac *= base / (ll + 2); + } + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + u[nn] += result * (v_points_[nn + 1] - v_points_[nn]) * std::exp(alpha_k[nn]); + } + } // if (nn < dimRange-1) + } // nn + return u; + } // VectorType calculate_u(...) + + + RangeFieldType calculate_f(const VectorType& alpha_k, const VectorType& v) const + { + RangeFieldType ret(0); + for (size_t ii = 0; ii < dimRange - 1; ++ii) { + if (std::abs(alpha_k[ii + 1] - alpha_k[ii]) > taylor_tol_) { + ret += (v_points_[ii + 1] - v_points_[ii]) / (alpha_k[ii + 1] - alpha_k[ii]) + * (std::exp(alpha_k[ii + 1]) - std::exp(alpha_k[ii])); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + size_t ll = 1; + RangeFieldType base = alpha_k[ii + 1] - alpha_k[ii]; + auto pow_frac = 1.; + while (ll <= max_taylor_order_ && XT::Common::FloatCmp::ne(update, 0.)) { + update = pow_frac; + result += update; + ++ll; + pow_frac *= base / ll; + } + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + ret += result * (v_points_[ii + 1] - v_points_[ii]) * std::exp(alpha_k[ii]); + } + } // ii + ret -= alpha_k * v; + return ret; + } // .. calculate_f(...) + + VectorType calculate_gradient(const VectorType& alpha_k, const VectorType& v) const + { + return calculate_u(alpha_k) - v; + } + + void calculate_hessian(const VectorType& alpha_k, + VectorType& diag, + FieldVector<RangeFieldType, dimRange - 1>& subdiag) const + { + std::fill(diag.begin(), diag.end(), 0.); + std::fill(subdiag.begin(), subdiag.end(), 0.); + for (size_t nn = 0; nn < dimRange; ++nn) { + if (nn > 0) { + if (std::abs(alpha_k[nn] - alpha_k[nn - 1]) > taylor_tol_) { + subdiag[nn - 1] = + (v_points_[nn] - v_points_[nn - 1]) + * ((std::exp(alpha_k[nn]) + std::exp(alpha_k[nn - 1])) / std::pow(alpha_k[nn] - alpha_k[nn - 1], 2) + - 2. * (std::exp(alpha_k[nn]) - std::exp(alpha_k[nn - 1])) + / std::pow(alpha_k[nn] - alpha_k[nn - 1], 3)); + diag[nn] = (v_points_[nn] - v_points_[nn - 1]) + * ((-2. / std::pow(alpha_k[nn] - alpha_k[nn - 1], 2) + 1. / (alpha_k[nn] - alpha_k[nn - 1])) + * std::exp(alpha_k[nn]) + + 2. / std::pow(alpha_k[nn] - alpha_k[nn - 1], 3) + * (std::exp(alpha_k[nn]) - std::exp(alpha_k[nn - 1]))); + + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha_k[nn - 1] - alpha_k[nn]; + RangeFieldType factor = (v_points_[nn] - v_points_[nn - 1]) * std::exp(alpha_k[nn]); + size_t ll = 2; + auto pow_frac = 1. / 6.; + while (ll <= max_taylor_order_ - 1 && XT::Common::FloatCmp::ne(update, 0.)) { + update = pow_frac * (ll - 1.); + result += update; + ++ll; + pow_frac *= base / (ll + 1); + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + subdiag[nn - 1] += result * factor; + + result = 0.; + update = 1; + ll = 3; + pow_frac = 2. / 6.; + while (ll <= max_taylor_order_ && XT::Common::FloatCmp::ne(update, 0.)) { + update = pow_frac; + result += update; + ++ll; + pow_frac *= base / ll; + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + diag[nn] += result * factor; + } + } // if (nn > 0) + if (nn < dimRange - 1) { + if (std::abs(alpha_k[nn + 1] - alpha_k[nn]) > taylor_tol_) { + diag[nn] += (v_points_[nn + 1] - v_points_[nn]) + * ((-2. / std::pow(alpha_k[nn + 1] - alpha_k[nn], 2) - 1. / (alpha_k[nn + 1] - alpha_k[nn])) + * std::exp(alpha_k[nn]) + + 2. / std::pow(alpha_k[nn + 1] - alpha_k[nn], 3) + * (std::exp(alpha_k[nn + 1]) - std::exp(alpha_k[nn]))); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha_k[nn + 1] - alpha_k[nn]; + size_t ll = 3; + auto pow_frac = 2. / 6.; + while (ll <= max_taylor_order_ && XT::Common::FloatCmp::ne(update, 0.)) { + update = pow_frac; + result += update; + ++ll; + pow_frac *= base / ll; + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + diag[nn] += result * (v_points_[nn + 1] - v_points_[nn]) * std::exp(alpha_k[nn]); + } + } // if (nn < dimRange - 1) + } // nn + } // void calculate_hessian(...) + + void + calculate_J(const VectorType& alpha_k, VectorType& diag, FieldVector<RangeFieldType, dimRange - 1>& subdiag) const + { + std::fill(diag.begin(), diag.end(), 0.); + std::fill(subdiag.begin(), subdiag.end(), 0.); + for (size_t nn = 0; nn < dimRange; ++nn) { + if (nn > 0) { + if (std::abs(alpha_k[nn] - alpha_k[nn - 1]) > taylor_tol_) { + subdiag[nn - 1] = + (v_points_[nn] - v_points_[nn - 1]) + * ((v_points_[nn] * std::exp(alpha_k[nn]) + v_points_[nn - 1] * std::exp(alpha_k[nn - 1])) + / std::pow(alpha_k[nn - 1] - alpha_k[nn], 2) + + 2. + * ((2 * v_points_[nn] - v_points_[nn - 1]) * std::exp(alpha_k[nn]) + - (2 * v_points_[nn - 1] - v_points_[nn]) * std::exp(alpha_k[nn - 1])) + / std::pow(alpha_k[nn - 1] - alpha_k[nn], 3)) + + 6. * std::pow(v_points_[nn] - v_points_[nn - 1], 2) + * (std::exp(alpha_k[nn]) - std::exp(alpha_k[nn - 1])) / std::pow(alpha_k[nn - 1] - alpha_k[nn], 4); + diag[nn] = 6 * std::pow(v_points_[nn - 1] - v_points_[nn], 2) + * (std::exp(alpha_k[nn - 1]) - std::exp(alpha_k[nn])) + / std::pow(alpha_k[nn - 1] - alpha_k[nn], 4) + + 2. * (v_points_[nn] - v_points_[nn - 1]) + * (v_points_[nn - 1] * std::exp(alpha_k[nn - 1]) + - (3 * v_points_[nn] - 2 * v_points_[nn - 1]) * std::exp(alpha_k[nn])) + / std::pow(alpha_k[nn - 1] - alpha_k[nn], 3) + - v_points_[nn] * (v_points_[nn] - v_points_[nn - 1]) * std::exp(alpha_k[nn]) + / (alpha_k[nn - 1] - alpha_k[nn]) + - (std::pow(v_points_[nn - 1], 2) - 4 * v_points_[nn] * v_points_[nn - 1] + + 3. * std::pow(v_points_[nn], 2)) + * std::exp(alpha_k[nn]) / std::pow(alpha_k[nn - 1] - alpha_k[nn], 2); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha_k[nn - 1] - alpha_k[nn]; + RangeFieldType factor = (v_points_[nn] - v_points_[nn - 1]) * std::exp(alpha_k[nn]); + size_t ll = 0; + auto pow_frac = 1. / 24.; + while (ll < 2 || (ll <= max_taylor_order_ - 4 && XT::Common::FloatCmp::ne(update, 0.))) { + update = pow_frac * ((ll * ll + 3 * ll + 2) * v_points_[nn - 1] + (2 * ll + 2) * v_points_[nn]); + result += update; + ++ll; + pow_frac *= base / (ll + 4); + } // ll + subdiag[nn - 1] += result * factor; + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + + result = 0.; + update = 1; + ll = 0; + pow_frac = 1. / 24.; + while (ll < 4 || (ll <= max_taylor_order_ - 4 && XT::Common::FloatCmp::ne(update, 0.))) { + update = pow_frac * (6 * v_points_[nn] + (2 * ll + 2) * v_points_[nn - 1]); + result += update; + ++ll; + pow_frac *= base / (ll + 4); + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + diag[nn] += result * factor; + } + } // if (nn > 0) + if (nn < dimRange - 1) { + if (std::abs(alpha_k[nn + 1] - alpha_k[nn]) > taylor_tol_) { + diag[nn] += 6 * std::pow(v_points_[nn] - v_points_[nn + 1], 2) + * (std::exp(alpha_k[nn]) - std::exp(alpha_k[nn + 1])) + / std::pow(alpha_k[nn] - alpha_k[nn + 1], 4) + + 2. * (v_points_[nn] - v_points_[nn + 1]) + * (v_points_[nn + 1] * std::exp(alpha_k[nn + 1]) + - (3 * v_points_[nn] - 2 * v_points_[nn + 1]) * std::exp(alpha_k[nn])) + / std::pow(alpha_k[nn] - alpha_k[nn + 1], 3) + - v_points_[nn] * (v_points_[nn] - v_points_[nn + 1]) * std::exp(alpha_k[nn]) + / (alpha_k[nn] - alpha_k[nn + 1]) + + (std::pow(v_points_[nn + 1], 2) - 4 * v_points_[nn] * v_points_[nn + 1] + + 3. * std::pow(v_points_[nn], 2)) + * std::exp(alpha_k[nn]) / std::pow(alpha_k[nn] - alpha_k[nn + 1], 2); + } else { + RangeFieldType update = 1.; + RangeFieldType result = 0.; + RangeFieldType base = alpha_k[nn + 1] - alpha_k[nn]; + size_t ll = 0; + auto pow_frac = 1. / 24.; + while (ll < 4 || (ll <= max_taylor_order_ - 4 && XT::Common::FloatCmp::ne(update, 0.))) { + update = pow_frac * (6 * v_points_[nn] + (2 * ll + 2) * v_points_[nn + 1]); + result += update; + ++ll; + pow_frac *= base / (ll + 4); + } // ll + assert(!(std::isinf(pow_frac) || std::isnan(pow_frac))); + diag[nn] += result * (v_points_[nn + 1] - v_points_[nn]) * std::exp(alpha_k[nn]); + } + } // if (nn < dimRange - 1) + } // nn + } // void calculate_J(...) + + // calculates ret = J H^{-1}. Both J and H are symmetric tridiagonal, H is positive definite. + static void calculate_J_Hinv(DynamicRowDerivativeRangeType& ret, + const VectorType& J_diag, + const FieldVector<RangeFieldType, dimRange - 1>& J_subdiag, + VectorType& H_diag, + FieldVector<RangeFieldType, dimRange - 1>& H_subdiag) + { + // factorize H = LDL^T, where L is unit lower bidiagonal and D is diagonal + // H_diag is overwritten by the diagonal elements of D + // H_subdiag is overwritten by the subdiagonal elements of L + XT::LA::tridiagonal_ldlt(H_diag, H_subdiag); + + // copy J to dense matrix + ret.set_all_entries(0.); + for (size_t ii = 0; ii < dimRange - 1; ++ii) { + ret[ii][ii] = J_diag[ii]; + ret[ii + 1][ii] = J_subdiag[ii]; + ret[ii][ii + 1] = J_subdiag[ii]; + } + ret[dimRange - 1][dimRange - 1] = J_diag[dimRange - 1]; + + // Solve ret H = J which is equivalent to (as H and J are symmetric) to H ret^T = J; + XT::LA::solve_tridiagonal_ldlt_factorized(H_diag, H_subdiag, ret); + // transpose ret + RangeFieldType* ret_ptr = &(ret[0][0]); + for (size_t ii = 0; ii < dimRange; ++ii) + for (size_t jj = 0; jj < ii; ++jj) + std::swap(ret_ptr[jj * dimRange + ii], ret_ptr[ii * dimRange + jj]); + } // void calculate_J_Hinv(...) + + + // ============================================================================================ + // ================================== Helper functions ======================================== + // ============================================================================================ + + + const MomentBasis& basis_functions() const + { + return basis_functions_; + } + + static bool is_realizable(const DomainType& u) + { + for (const auto& u_i : u) + if (!(u_i > 0.) || std::isinf(u_i)) + return false; + return true; + } + + std::unique_ptr<VectorType> get_isotropic_alpha(const RangeFieldType density) const + { + return std::make_unique<VectorType>(basis_functions_.alpha_iso(density)); + } + + std::unique_ptr<VectorType> get_isotropic_alpha(const DomainType& u) const + { + return get_isotropic_alpha(basis_functions_.density(u)); + } + + const MomentBasis& basis_functions_; + const std::vector<RangeFieldType>& v_points_; + const RangeFieldType tau_; + const RangeFieldType epsilon_gamma_; + const RangeFieldType chi_; + const RangeFieldType xi_; + const std::vector<RangeFieldType> r_sequence_; + const size_t k_0_; + const size_t k_max_; + const RangeFieldType epsilon_; + const RangeFieldType taylor_tol_; + const size_t max_taylor_order_; +}; + +# else // ENTROPY_FLUX_1D_HATFUNCTIONS_USE_ANALYTICAL_INTEGRALS + +/** + * Specialization of EntropyBasedFluxImplementation for 1D Hatfunctions (no change of basis, use structure) + */ +template <class D, class R, size_t dimRange, EntropyType entropy> +class EntropyBasedFluxImplementation<HatFunctionMomentBasis<D, 1, R, dimRange, 1, 1, entropy>> + : public XT::Functions::FunctionInterface<dimRange, 1, dimRange, R> +{ + using BaseType = typename XT::Functions::FunctionInterface<dimRange, 1, dimRange, R>; + using ThisType = EntropyBasedFluxImplementation; + +public: + using MomentBasis = HatFunctionMomentBasis<D, 1, R, dimRange, 1, 1, entropy>; + static const size_t dimFlux = MomentBasis::dimFlux; + static const size_t basis_dimRange = dimRange; + using typename BaseType::DomainFieldType; + using typename BaseType::DomainType; + using typename BaseType::DynamicDerivativeRangeType; + using typename BaseType::DynamicRowDerivativeRangeType; + using typename BaseType::RangeFieldType; + using typename BaseType::RangeReturnType; + using BasisDomainType = typename MomentBasis::DomainType; + using FluxDomainType = FieldVector<DomainFieldType, dimFlux>; + using VectorType = XT::Common::FieldVector<RangeFieldType, basis_dimRange>; + using AlphaReturnType = std::pair<VectorType, std::pair<DomainType, RangeFieldType>>; + static const size_t num_intervals = dimRange - 1; + static const size_t block_size = 2; + using LocalVectorType = XT::Common::FieldVector<RangeFieldType, block_size>; + using BasisValuesMatrixType = FieldVector<std::vector<LocalVectorType>, num_intervals>; + using QuadraturePointsType = FieldVector<std::vector<RangeFieldType>, num_intervals>; + using QuadratureWeightsType = QuadraturePointsType; + + explicit EntropyBasedFluxImplementation(const MomentBasis& basis_functions, + const RangeFieldType tau, + const bool /*disable_realizability_check*/, + const RangeFieldType epsilon_gamma, + const RangeFieldType chi, + const RangeFieldType xi, + const std::vector<RangeFieldType> r_sequence, + const size_t k_0, + const size_t k_max, + const RangeFieldType epsilon) + : basis_functions_(basis_functions) + , grid_points_(basis_functions_.partitioning()) + , tau_(tau) + , epsilon_gamma_(epsilon_gamma) + , chi_(chi) + , xi_(xi) + , r_sequence_(r_sequence) + , k_0_(k_0) + , k_max_(k_max) + , epsilon_(epsilon) + { + const auto& quadratures = basis_functions_.quadratures(); + assert(quadratures.size() == grid_points_.size() - 1); + for (size_t jj = 0; jj < num_intervals; ++jj) { + for (const auto& quad_point : quadratures[jj]) { + quad_points_[jj].emplace_back(quad_point.position()[0]); + quad_weights_[jj].emplace_back(quad_point.weight()); + } + } // jj + for (size_t jj = 0; jj < num_intervals; ++jj) { + M_[jj].resize(quad_points_[jj].size()); + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) + M_[jj][ll] = basis_functions_.evaluate_on_interval(quad_points_[jj][ll], jj); + } // jj + } + + + // ============================================================================================ + // ============================= FunctionInterface methods ==================================== + // ============================================================================================ + + + int order(const XT::Common::Parameter& /*param*/) const override + { + return 1; + } + + virtual RangeReturnType evaluate(const DomainType& u, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = get_alpha(u, *get_isotropic_alpha(u), true)->first; + return evaluate_with_alpha(alpha); + } + + virtual RangeReturnType evaluate_with_alpha(const VectorType& alpha) const + { + RangeReturnType ret(0.); + // calculate ret[ii] = < omega[ii] m G_\alpha(u) > + auto& eta_ast_prime_vals = working_storage(); + evaluate_eta_ast_prime(alpha, eta_ast_prime_vals); + for (size_t jj = 0; jj < num_intervals; ++jj) { + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto& basis_ll = M_[jj][ll]; + auto factor_ll = eta_ast_prime_vals[jj][ll] * quad_points_[jj][ll] * quad_weights_[jj][ll]; + for (size_t ii = 0; ii < 2; ++ii) + ret[0][jj + ii] += basis_ll[ii] * factor_ll; + } // ll (quad points) + } // jj (intervals) + return ret; + } // void evaluate(...) + + virtual void jacobian(const DomainType& u, + DynamicDerivativeRangeType& result, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + const auto alpha = get_alpha(u, *get_isotropic_alpha(u), true)->first; + jacobian_with_alpha(alpha, result); + } + + virtual void jacobian_with_alpha(const VectorType& alpha, DynamicDerivativeRangeType& result) const + { + VectorType H_diag, J_diag; + FieldVector<RangeFieldType, dimRange - 1> H_subdiag, J_subdiag; + calculate_hessian(alpha, M_, H_diag, H_subdiag); + calculate_J(M_, J_diag, J_subdiag); + calculate_J_Hinv(result[0], J_diag, J_subdiag, H_diag, H_subdiag); + } + + + // ============================================================================================ + // ============ Evaluations of ansatz distribution, moments, hessian etc. ===================== + // ============================================================================================ + + + std::unique_ptr<AlphaReturnType> get_alpha(const DomainType& u) const + { + return get_alpha(u, *get_isotropic_alpha(u), true); + } + + // returns (alpha, (actual_u, r)), where r is the regularization parameter and actual_u the regularized u + std::unique_ptr<AlphaReturnType> + get_alpha(const DomainType& u, const VectorType& alpha_in, const bool regularize) const + { + auto ret = std::make_unique<AlphaReturnType>(); + + constexpr bool rescale = (entropy == EntropyType::MaxwellBoltzmann); + + // rescale u such that the density <psi> is 1 if rescale is true + RangeFieldType density = basis_functions_.density(u); + if (!(density > 0.) || std::isinf(density)) + DUNE_THROW(Dune::MathError, "Negative, inf or NaN density!"); + static const auto alpha_one = basis_functions_.alpha_one(); + VectorType phi = rescale ? u / density : u; + VectorType alpha_initial = alpha_in; + if (rescale) + alpha_initial -= alpha_one * std::log(density); + RangeFieldType tau_prime = + rescale + ? std::min(tau_ / ((1 + std::sqrt(dimRange) * phi.two_norm()) * density + std::sqrt(dimRange) * tau_), tau_) + : tau_; + // The hessian H is always symmetric and tridiagonal, so we only need to store the diagonal and subdiagonal + // elements + VectorType H_diag; + FieldVector<RangeFieldType, dimRange - 1> H_subdiag; + + // calculate moment vector for isotropic distribution + VectorType u_iso = basis_functions_.u_iso(); + VectorType v; + VectorType alpha_k = alpha_initial; + + const auto& r_sequence = regularize ? r_sequence_ : std::vector<RangeFieldType>{0.}; + const auto r_max = r_sequence.back(); + for (const auto& rr : r_sequence_) { + // regularize u + v = phi; + if (rr > 0) { + alpha_k = *get_isotropic_alpha(v); + VectorType r_times_u_iso(u_iso); + r_times_u_iso *= rr; + v *= 1 - rr; + v += r_times_u_iso; + } + + // calculate f_0 + RangeFieldType f_k = calculate_f(alpha_k, v); + + int backtracking_failed = 0; + VectorType g_k, d_k, minus_g_k, u_alpha_prime; + for (size_t kk = 0; kk < k_max_; ++kk) { + // exit inner for loop to increase r if too many iterations are used + if (kk > k_0_ && rr < r_max) + break; + // calculate gradient g + calculate_gradient(alpha_k, v, g_k); + // calculate Hessian H + calculate_hessian(alpha_k, M_, H_diag, H_subdiag, entropy == EntropyType::MaxwellBoltzmann); + // calculate descent direction d_k; + minus_g_k = g_k; + minus_g_k *= -1; + try { + d_k = minus_g_k; + XT::LA::solve_sym_tridiag_posdef(H_diag, H_subdiag, d_k); + } catch (const Dune::MathError&) { + if (rr < r_max) + break; + else + DUNE_THROW(Dune::MathError, "Failure to converge!"); + } + + const auto& alpha_tilde = alpha_k; + const auto u_alpha_tilde = g_k + v; + auto density_tilde = basis_functions_.density(u_alpha_tilde); + if (!(density_tilde > 0.) || std::isinf(density_tilde)) + break; + auto alpha_prime = alpha_tilde; + if (rescale) { + alpha_prime -= alpha_one * std::log(density_tilde); + calculate_u(alpha_prime, u_alpha_prime); + } else { + u_alpha_prime = u_alpha_tilde; + } + auto u_eps_diff = v - u_alpha_prime * (1 - epsilon_gamma_); + auto& eta_ast_prime_vals = working_storage(); + // if rescale is true, working storage already contains the eta_ast_prime evaluations due to the call to + // calculate_u above + if (!rescale) + evaluate_eta_ast_prime(alpha_prime, eta_ast_prime_vals); + // checking realizability is cheap so we do not need the second stopping criterion + if (g_k.two_norm() < tau_prime && is_realizable(u_eps_diff) + && (entropy == EntropyType::MaxwellBoltzmann || all_positive(eta_ast_prime_vals))) { + ret->first = rescale ? alpha_prime + alpha_one * std::log(density) : alpha_prime; + ret->second = std::make_pair(rescale ? v * density : v, rr); + return ret; + } else { + RangeFieldType zeta_k = 1; + // backtracking line search + while (backtracking_failed >= 2 || zeta_k > epsilon_ * alpha_k.two_norm() / d_k.two_norm()) { + // calculate alpha_new = alpha_k + zeta_k d_k + auto alpha_new = d_k; + alpha_new *= zeta_k; + alpha_new += alpha_k; + // calculate f(alpha_new) + RangeFieldType f_new = calculate_f(alpha_new, v); + if (backtracking_failed >= 2 || XT::Common::FloatCmp::le(f_new, f_k + xi_ * zeta_k * (g_k * d_k))) { + alpha_k = alpha_new; + f_k = f_new; + backtracking_failed = 0.; + break; + } + zeta_k = chi_ * zeta_k; + } // backtracking linesearch while + // if (zeta_k <= epsilon_ * alpha_k.two_norm() / d_k.two_norm() * 100.) + if (zeta_k <= epsilon_ * alpha_k.two_norm() / d_k.two_norm()) + ++backtracking_failed; + } // else (stopping conditions) + } // k loop (Newton iterations) + } // rr loop (Regularization parameter) + DUNE_THROW(MathError, "Failed to converge"); + return ret; + } // ... get_alpha(...) + + // returns density rho = < eta_ast_prime(alpha * b(v)) > + RangeFieldType get_rho(const DomainType& alpha) const + { + auto& eta_ast_prime_vals = working_storage(); + evaluate_eta_ast_prime(alpha, eta_ast_prime_vals); + RangeFieldType ret(0.); + for (size_t jj = 0; jj < num_intervals; ++jj) + ret += std::inner_product( + quad_weights_[jj].begin(), quad_weights_[jj].end(), eta_ast_prime_vals[jj].begin(), RangeFieldType(0.)); + return ret; + } + + // returns < eta_ast(alpha * b(v)) > + RangeFieldType get_eta_ast_integrated(const DomainType& alpha) const + { + auto& eta_ast_vals = working_storage(); + evaluate_eta_ast(alpha, eta_ast_vals); + RangeFieldType ret(0.); + for (size_t jj = 0; jj < num_intervals; ++jj) + ret += std::inner_product( + quad_weights_[jj].begin(), quad_weights_[jj].end(), eta_ast_vals[jj].begin(), RangeFieldType(0.)); + return ret; + } + + DomainType get_u(const DomainType& alpha) const + { + DomainType ret; + calculate_u(alpha, ret); + return ret; + } + + DomainType get_u(const QuadratureWeightsType& eta_ast_prime_vals) const + { + DomainType ret; + calculate_u(eta_ast_prime_vals, ret); + return ret; + } + + void calculate_u(const DomainType& alpha, DomainType& u) const + { + auto& eta_ast_prime_vals = working_storage(); + evaluate_eta_ast_prime(alpha, eta_ast_prime_vals); + calculate_u(eta_ast_prime_vals, u); + } // void calculate_u(...) + + void calculate_u(const QuadratureWeightsType& eta_ast_prime_vals, DomainType& u) const + { + std::fill(u.begin(), u.end(), 0.); + for (size_t jj = 0; jj < num_intervals; ++jj) { + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + auto factor_ll = eta_ast_prime_vals[jj][ll] * quad_weights_[jj][ll]; + for (size_t ii = 0; ii < 2; ++ii) + u[jj + ii] += M_[jj][ll][ii] * factor_ll; + } // ll (quad points) + } // jj (intervals) + } + + RangeFieldType calculate_f(const VectorType& alpha, const VectorType& v) const + { + return get_eta_ast_integrated(alpha) - alpha * v; + } // void calculate_u(...) + + void calculate_gradient(const VectorType& alpha, const VectorType& v, VectorType& g_k) const + { + calculate_u(alpha, g_k); + g_k -= v; + } + + void calculate_hessian(const QuadratureWeightsType& eta_ast_twoprime_vals, + const BasisValuesMatrixType& M, + VectorType& H_diag, + FieldVector<RangeFieldType, dimRange - 1>& H_subdiag) const + { + std::fill(H_diag.begin(), H_diag.end(), 0.); + std::fill(H_subdiag.begin(), H_subdiag.end(), 0.); + for (size_t jj = 0; jj < num_intervals; ++jj) { + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto& basis_ll = M[jj][ll]; + const auto factor = eta_ast_twoprime_vals[jj][ll] * quad_weights_[jj][ll]; + for (size_t ii = 0; ii < 2; ++ii) + H_diag[jj + ii] += std::pow(basis_ll[ii], 2) * factor; + H_subdiag[jj] += basis_ll[0] * basis_ll[1] * factor; + } // ll (quad points) + } // jj (intervals) + } // void calculate_hessian(...) + + void calculate_hessian(const DomainType& alpha, + const BasisValuesMatrixType& M, + VectorType& H_diag, + FieldVector<RangeFieldType, dimRange - 1>& H_subdiag, + const bool use_working_storage = false) const + { + auto& eta_ast_twoprime_vals = working_storage(); + if (!use_working_storage) + evaluate_eta_ast_twoprime(alpha, eta_ast_twoprime_vals); + calculate_hessian(eta_ast_twoprime_vals, M, H_diag, H_subdiag); + } // void calculate_hessian(...) + + // J = df/dalpha is the derivative of the flux with respect to alpha. + // As F = (f_1, f_2, f_3) is matrix-valued + // (div f = \sum_{i=1}^d \partial_{x_i} f_i = \sum_{i=1}^d \partial_{x_i} < v_i m \hat{psi}(alpha) > is + // vector-valued), + // the derivative is the vector of matrices (df_1/dalpha, df_2/dalpha, ...) + // this function returns the dd-th matrix df_dd/dalpha of J + // assumes work_vecs already contains the needed eta_ast_twoprime(alpha * b) values + void calculate_J(const BasisValuesMatrixType& M, + VectorType& J_diag, + FieldVector<RangeFieldType, dimRange - 1>& J_subdiag) const + { + std::fill(J_diag.begin(), J_diag.end(), 0.); + std::fill(J_subdiag.begin(), J_subdiag.end(), 0.); + const auto& eta_ast_twoprime_vals = working_storage(); + for (size_t jj = 0; jj < num_intervals; ++jj) { + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto& basis_ll = M[jj][ll]; + const auto factor = eta_ast_twoprime_vals[jj][ll] * quad_points_[jj][ll] * quad_weights_[jj][ll]; + for (size_t ii = 0; ii < 2; ++ii) + J_diag[jj + ii] += std::pow(basis_ll[ii], 2) * factor; + J_subdiag[jj] += basis_ll[0] * basis_ll[1] * factor; + } // ll (quad points) + } // jj (intervals) + } // void calculate_J(...) + + void + apply_inverse_hessian(const QuadratureWeightsType& density_evaluations, const DomainType& u, DomainType& Hinv_u) const + { + thread_local VectorType H_diag; + thread_local FieldVector<RangeFieldType, dimRange - 1> H_subdiag; + calculate_hessian(density_evaluations, M_, H_diag, H_subdiag); + // factorize H = LDL^T, where L is unit lower bidiagonal and D is diagonal + // H_diag is overwritten by the diagonal elements of D + // H_subdiag is overwritten by the subdiagonal elements of L + XT::LA::tridiagonal_ldlt(H_diag, H_subdiag); + // Solve H ret = u + Hinv_u = u; + XT::LA::solve_tridiagonal_ldlt_factorized(H_diag, H_subdiag, Hinv_u); + } + + // calculates ret = J H^{-1}. Both J and H are symmetric tridiagonal, H is positive definite. + static void calculate_J_Hinv(DynamicRowDerivativeRangeType& ret, + const VectorType& J_diag, + const FieldVector<RangeFieldType, dimRange - 1>& J_subdiag, + VectorType& H_diag, + FieldVector<RangeFieldType, dimRange - 1>& H_subdiag) + { + // factorize H = LDL^T, where L is unit lower bidiagonal and D is diagonal + // H_diag is overwritten by the diagonal elements of D + // H_subdiag is overwritten by the subdiagonal elements of L + XT::LA::tridiagonal_ldlt(H_diag, H_subdiag); + + // copy J to dense matrix + ret.set_all_entries(0.); + for (size_t ii = 0; ii < dimRange - 1; ++ii) { + ret.set_entry(ii, ii, J_diag[ii]); + ret.set_entry(ii + 1, ii, J_subdiag[ii]); + ret.set_entry(ii, ii + 1, J_subdiag[ii]); + } + ret.set_entry(dimRange - 1, dimRange - 1, J_diag[dimRange - 1]); + + // Solve ret H = J which is equivalent to (as H and J are symmetric) to H ret^T = J; + XT::LA::solve_tridiagonal_ldlt_factorized(H_diag, H_subdiag, ret); + // transpose ret + RangeFieldType* ret_ptr = &(ret[0][0]); + for (size_t ii = 0; ii < dimRange; ++ii) + for (size_t jj = 0; jj < ii; ++jj) + std::swap(ret_ptr[jj * dimRange + ii], ret_ptr[ii * dimRange + jj]); + } // void calculate_J_Hinv(...) + + + // ============================================================================================ + // ============================= Entropy evaluations ========================================== + // ============================================================================================ + + + // evaluates \eta_{\ast}(\alpha^T b(v_i)) for all quadrature points v_i + void evaluate_eta_ast(const VectorType& alpha, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, ret); + apply_exponential(ret); + evaluate_eta_ast(ret); + } + + // evaluates \eta_{\ast}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already contains + // exp(alpha^T b(v_i)) + void evaluate_eta_ast(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t jj = 0; jj < num_intervals; ++jj) + for (size_t ll = 0; ll < ret[jj].size(); ++ll) + ret[jj][ll] = -std::log(1 - ret[jj][ll]); + } + + // evaluates \eta_{\ast}^{\prime}(\alpha^T b(v_i)) for all quadrature points v_i + void evaluate_eta_ast_prime(const VectorType& alpha, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, ret); + apply_exponential(ret); + evaluate_eta_ast_prime(ret); + } + + // evaluates \eta_{\ast}^{\prime}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already contains + // exp(alpha^T b(v_i)) + void evaluate_eta_ast_prime(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t jj = 0; jj < num_intervals; ++jj) + for (size_t ll = 0; ll < ret[jj].size(); ++ll) + ret[jj][ll] /= (1 - ret[jj][ll]); + } + + // evaluates \eta_{\ast}^{\prime\prime}(\alpha^T b(v_i)) for all quadrature points v_i + void evaluate_eta_ast_twoprime(const VectorType& alpha, QuadratureWeightsType& ret) const + { + calculate_scalar_products(alpha, ret); + apply_exponential(ret); + evaluate_eta_ast_twoprime(ret); + } + + // evaluates \eta_{\ast}^{\prime\prime}(\alpha^T b(v_i)) for all quadrature points v_i, assumes that ret already + // contains exp(alpha^T b(v_i)) + void evaluate_eta_ast_twoprime(QuadratureWeightsType& ret) const + { + if (entropy == EntropyType::BoseEinstein) + for (size_t jj = 0; jj < num_intervals; ++jj) + for (size_t ll = 0; ll < ret[jj].size(); ++ll) + ret[jj][ll] /= std::pow(1 - ret[jj][ll], 2); + } + + // stores evaluations of exp(alpha^T b(v_i)) for all quadrature points v_i + void store_exp_evaluations(QuadratureWeightsType& exp_evaluations, const DomainType& alpha) const + { + this->calculate_scalar_products(XT::LA::convert_to<VectorType>(alpha), exp_evaluations); + this->apply_exponential(exp_evaluations); + } + + void store_eta_ast_prime_vals(const QuadratureWeightsType& exp_evaluations, QuadratureWeightsType& eta_ast_prime_vals) + { + eta_ast_prime_vals = exp_evaluations; + evaluate_eta_ast_prime(eta_ast_prime_vals); + } + + void store_eta_ast_twoprime_vals(const QuadratureWeightsType& exp_evaluations, + QuadratureWeightsType& eta_ast_twoprime_vals) + { + eta_ast_twoprime_vals = exp_evaluations; + evaluate_eta_ast_twoprime(eta_ast_twoprime_vals); + } + + // stores evaluations of a given boundary distribution psi(v) at all quadrature points v_i + void store_boundary_distribution_evaluations( + QuadratureWeightsType& boundary_distribution_evaluations, + const std::function<RangeFieldType(const FluxDomainType&)>& boundary_distribution) const + { + for (size_t jj = 0; jj < num_intervals; ++jj) { + boundary_distribution_evaluations[jj].resize(quad_points_[jj].size()); + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) + boundary_distribution_evaluations[jj][ll] = boundary_distribution(quad_points_[jj][ll]); + } + } + + + // ============================================================================================ + // =============================== Kinetic fluxes ============================================= + // ============================================================================================ + + + // calculate \sum_{i=1}^d < v_i m \psi > n_i, where n is the unit outer normal, + // m is the basis function vector, \psi is the ansatz corresponding to u + // and x, v, t are the space, velocity and time variable, respectively + // As we are using cartesian grids, n_i == 0 in all but one dimension, so only evaluate for i == dd + DomainType + evaluate_kinetic_flux(const DomainType& u_i, const DomainType& u_j, const FluxDomainType& n_ij, const size_t dd) const + { + const auto alpha_i = get_alpha(u_i, *get_isotropic_alpha(u_i), true)->first; + const auto alpha_j = get_alpha(u_j, *get_isotropic_alpha(u_j), true)->first; + return evaluate_kinetic_flux_with_alphas(alpha_i, alpha_j, n_ij, dd); + } // DomainType evaluate_kinetic_flux(...) + + DomainType evaluate_kinetic_flux_with_alphas(const VectorType& alpha_i, + const VectorType& alpha_j, + const FluxDomainType& n_ij, + const size_t dd) const + { + assert(dd == 0); + thread_local FieldVector<QuadratureWeightsType, 2> eta_ast_prime_vals; + for (size_t jj = 0; jj < num_intervals; ++jj) { + eta_ast_prime_vals[0][jj].resize(quad_points_[jj].size()); + eta_ast_prime_vals[1][jj].resize(quad_points_[jj].size()); + } + evaluate_eta_ast_prime(alpha_i, eta_ast_prime_vals[0]); + evaluate_eta_ast_prime(alpha_j, eta_ast_prime_vals[1]); + // calculate \sum_{i=1}^d < \omega_i m G_\alpha(u) > n_i + DomainType ret(0); + for (size_t jj = 0; jj < num_intervals; ++jj) { + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto position = quad_points_[jj][ll]; + RangeFieldType factor = + position * n_ij[dd] > 0. ? eta_ast_prime_vals[0][jj][ll] : eta_ast_prime_vals[1][jj][ll]; + factor *= quad_weights_[jj][ll] * position; + for (size_t ii = 0; ii < 2; ++ii) + ret[jj + ii] += M_[jj][ll][ii] * factor; + } // ll (quad points) + } // jj (faces) + ret *= n_ij[dd]; + return ret; + } // DomainType evaluate_kinetic_flux(...) + + // Calculates left and right kinetic flux with reconstructed densities. Ansatz distribution values contains + // evaluations of the ansatz distribution at each quadrature point for a stencil of three entities. The distributions + // are reconstructed pointwise for each quadrature point and the resulting (part of) the kinetic flux is < + // psi_reconstr * b * v>_{+/-}. + template <SlopeLimiterType slope_type, class FluxesMapType> + void calculate_reconstructed_fluxes(const FieldVector<const QuadratureWeightsType*, 3>& ansatz_distribution_values, + FluxesMapType& flux_values, + const size_t dd) const + { + assert(dd == 0); + // get flux storage + BasisDomainType coord(0.5); + coord[dd] = 0; + auto& left_flux_value = flux_values[coord]; + coord[dd] = 1; + auto& right_flux_value = flux_values[coord]; + right_flux_value = left_flux_value = DomainType(0.); + thread_local XT::Common::FieldVector<std::vector<RangeFieldType>, 2> reconstructed_values( + std::vector<RangeFieldType>(quad_points_[0].size())); + const auto slope_func = + (slope_type == SlopeLimiterType::minmod) ? XT::Common::minmod<RangeFieldType> : superbee<RangeFieldType>; + auto& vals_left = reconstructed_values[0]; + auto& vals_right = reconstructed_values[1]; + for (size_t jj = 0; jj < num_intervals; ++jj) { + // reconstruct densities + if (slope_type == SlopeLimiterType::no_slope) { + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) + vals_left[ll] = vals_right[ll] = (*ansatz_distribution_values[1])[jj][ll]; + } else { + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto slope = + slope_func((*ansatz_distribution_values[1])[jj][ll] - (*ansatz_distribution_values[0])[jj][ll], + (*ansatz_distribution_values[2])[jj][ll] - (*ansatz_distribution_values[1])[jj][ll]); + vals_left[ll] = (*ansatz_distribution_values[1])[jj][ll] - 0.5 * slope; + vals_right[ll] = (*ansatz_distribution_values[1])[jj][ll] + 0.5 * slope; + } // ll (quad points) + } + // calculate fluxes + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) { + const auto& position = quad_points_[jj][ll]; + RangeFieldType factor = position > 0. ? vals_right[ll] : vals_left[ll]; + factor *= quad_weights_[jj][ll] * position; + auto& val = position > 0. ? right_flux_value : left_flux_value; + const auto& basis_ll = M_[jj][ll]; + for (size_t ii = 0; ii < 2; ++ii) + val[jj + ii] += basis_ll[ii] * factor; + } // ll (quad points) + } // jj + } // void calculate_reconstructed_fluxes(...) + + + // ============================================================================================ + // ================================== Helper functions ======================================== + // ============================================================================================ + + + const MomentBasis& basis_functions() const + { + return basis_functions_; + } + + void calculate_scalar_products(const VectorType& alpha, QuadratureWeightsType& scalar_products) const + { + LocalVectorType local_alpha; + for (size_t jj = 0; jj < num_intervals; ++jj) { + scalar_products[jj].resize(quad_weights_[jj].size()); + for (size_t ii = 0; ii < 2; ++ii) + local_alpha[ii] = alpha[jj + ii]; + for (size_t ll = 0; ll < quad_weights_[jj].size(); ++ll) + scalar_products[jj][ll] = local_alpha * M_[jj][ll]; + } // jj + } + + void apply_exponential(QuadratureWeightsType& values) const + { + for (size_t jj = 0; jj < num_intervals; ++jj) { + assert(values[jj].size() < std::numeric_limits<int>::max()); + XT::Common::Mkl::exp(static_cast<int>(values[jj].size()), values[jj].data(), values[jj].data()); + } + } + + std::unique_ptr<VectorType> get_isotropic_alpha(const RangeFieldType density) const + { + return std::make_unique<VectorType>(basis_functions_.alpha_iso(density)); + } + + std::unique_ptr<VectorType> get_isotropic_alpha(const DomainType& u) const + { + return get_isotropic_alpha(basis_functions_.density(u)); + } + + static bool is_realizable(const DomainType& u) + { + for (const auto& u_i : u) + if (!(u_i > 0.) || std::isinf(u_i)) + return false; + return true; + } + + QuadratureWeightsType& working_storage() const + { + thread_local QuadratureWeightsType work_vec; + for (size_t jj = 0; jj < num_intervals; ++jj) + work_vec[jj].resize(quad_points_[jj].size()); + return work_vec; + } + + bool all_positive(const QuadratureWeightsType& vals) const + { + for (size_t jj = 0; jj < num_intervals; ++jj) + for (size_t ll = 0; ll < quad_points_[jj].size(); ++ll) { + const auto val = vals[jj][ll]; + if (val < 0. || std::isinf(val) || std::isnan(val)) + return false; + } + return true; + } + + const MomentBasis& basis_functions_; + QuadraturePointsType quad_points_; + QuadratureWeightsType quad_weights_; + const std::vector<RangeFieldType>& grid_points_; + BasisValuesMatrixType M_; + const RangeFieldType tau_; + const RangeFieldType epsilon_gamma_; + const RangeFieldType chi_; + const RangeFieldType xi_; + const std::vector<RangeFieldType> r_sequence_; + const size_t k_0_; + const size_t k_max_; + const RangeFieldType epsilon_; +}; +# endif // ENTROPY_FLUX_1D_HATFUNCTIONS_USE_ANALYTICAL_INTEGRALS +#endif // ENTROPY_FLUX_USE_1D_HATFUNCTIONS_SPECIALIZATION + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_MOMENTMODELS_ENTROPYFLUX_IMPLEMENTATIONS_HH diff --git a/dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh b/dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh new file mode 100644 index 0000000000000000000000000000000000000000..a948f7f7441a008b23034e43b8b487ce895eb651 --- /dev/null +++ b/dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh @@ -0,0 +1,276 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2019) + +#ifndef DUNE_GDT_LOCAL_FLUXES_ENTROPYBASED_KINETICCOORDS_HH +#define DUNE_GDT_LOCAL_FLUXES_ENTROPYBASED_KINETICCOORDS_HH + +#include <list> +#include <memory> + +#include <dune/xt/common/float_cmp.hh> +#include <dune/xt/common/vector_less.hh> + +#include <dune/xt/functions/interfaces/flux-function.hh> + +#include <dune/gdt/test/momentmodels/basisfunctions.hh> +#include <dune/gdt/test/momentmodels/entropyflux_implementations.hh> +#include <dune/gdt/test/momentmodels/entropyflux.hh> + +namespace Dune { +namespace GDT { + + +template <class GridViewImp, class MomentBasisImp, SlopeLimiterType slope> +class EntropyBasedFluxEntropyCoordsFunction + : public XT::Functions::FluxFunctionInterface<XT::Grid::extract_entity_t<GridViewImp>, + MomentBasisImp::dimRange, + MomentBasisImp::dimFlux, + MomentBasisImp::dimRange, + typename MomentBasisImp::R> +{ + using BaseType = typename XT::Functions::FluxFunctionInterface<XT::Grid::extract_entity_t<GridViewImp>, + MomentBasisImp::dimRange, + MomentBasisImp::dimFlux, + MomentBasisImp::dimRange, + typename MomentBasisImp::R>; + using ThisType = EntropyBasedFluxEntropyCoordsFunction; + +public: + using GridViewType = GridViewImp; + using MomentBasis = MomentBasisImp; + using IndexSetType = typename GridViewType::IndexSet; + static const size_t dimFlux = MomentBasis::dimFlux; + static const size_t basis_dimRange = MomentBasis::dimRange; + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::LocalFunctionType; + using typename BaseType::RangeFieldType; + using typename BaseType::StateType; + using ImplementationType = EntropyBasedFluxImplementation<MomentBasis>; + using AlphaReturnType = typename ImplementationType::AlphaReturnType; + using VectorType = typename ImplementationType::VectorType; + using I = XT::Grid::extract_intersection_t<GridViewType>; + using QuadratureWeightsType = typename ImplementationType::QuadratureWeightsType; + using BoundaryQuadratureWeightsType = + std::vector<XT::Common::FieldVector<XT::Common::FieldVector<QuadratureWeightsType, 2>, dimFlux>>; + static const EntropyType entropy = MomentBasis::entropy; + + explicit EntropyBasedFluxEntropyCoordsFunction( + const MomentBasis& basis_functions, + const bool disable_realizability_check = false, + const RangeFieldType tau = 1e-9, + const RangeFieldType epsilon_gamma = 0.01, + const RangeFieldType chi = 0.5, + const RangeFieldType xi = 1e-3, + const std::vector<RangeFieldType> r_sequence = {0, 1e-8, 1e-6, 1e-4, 1e-3, 1e-2, 5e-2, 0.1, 0.5, 1}, + const size_t k_0 = 500, + const size_t k_max = 1000, + const RangeFieldType epsilon = std::pow(2, -52)) + : implementation_(std::make_shared<ImplementationType>( + basis_functions, tau, disable_realizability_check, epsilon_gamma, chi, xi, r_sequence, k_0, k_max, epsilon)) + {} + + explicit EntropyBasedFluxEntropyCoordsFunction(EntropyBasedFluxFunction<GridViewType, MomentBasis>& other) + : implementation_(other.implementation_) + {} + + static const constexpr bool available = true; + + class Localfunction : public LocalFunctionType + { + using BaseType = LocalFunctionType; + + public: + using typename BaseType::DynamicJacobianRangeType; + using typename BaseType::E; + using typename BaseType::RangeReturnType; + + Localfunction(const ImplementationType& implementation) + : implementation_(implementation) + {} + + int order(const XT::Common::Parameter&) const override final + { + return 1.; + } + + virtual RangeReturnType evaluate(const DomainType& /*point_in_reference_element*/, + const StateType& alpha, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + return implementation_.evaluate_with_alpha(alpha); + } + + virtual void jacobian(const DomainType& /*point_in_reference_element*/, + const StateType& alpha, + DynamicJacobianRangeType& result, + const XT::Common::Parameter& /*param*/ = {}) const override final + { + implementation_.jacobian_with_alpha(alpha, result); + } // ... jacobian(...) + + private: + const ImplementationType& implementation_; + }; // class Localfunction + + bool x_dependent() const override final + { + return false; + } + + std::unique_ptr<LocalFunctionType> local_function() const override final + { + return std::make_unique<Localfunction>(*implementation_); + } + + virtual std::unique_ptr<Localfunction> derived_local_function() const + { + return std::make_unique<Localfunction>(*implementation_); + } + + StateType evaluate_kinetic_flux(const E& /*inside_entity*/, + const E& /*outside_entity*/, + const StateType& flux_i, + const StateType& flux_j, + const DomainType& n_ij, + const size_t dd) const + { + return (flux_i + flux_j) * n_ij[dd]; + } // StateType evaluate_kinetic_flux(...) + + const MomentBasis& basis_functions() const + { + return implementation_->basis_functions(); + } + + StateType get_u(const StateType& alpha) const + { + return implementation_->get_u(alpha); + } + + StateType get_u(const size_t entity_index) const + { + return implementation_->get_u((*eta_ast_prime_evaluations_)[entity_index]); + } + + StateType get_alpha(const StateType& u) const + { + const auto alpha = implementation_->get_alpha(u)->first; + StateType ret; + std::copy(alpha.begin(), alpha.end(), ret.begin()); + return ret; + } + + template <class FluxesMapType> + void calculate_reconstructed_fluxes(const FieldVector<size_t, 3>& entity_indices, + const FieldVector<bool, 3>& boundary_direction, + FluxesMapType& precomputed_fluxes, + const size_t dd) const + { + FieldVector<const QuadratureWeightsType*, 3> densities_stencil; + for (size_t ii = 0; ii < 3; ++ii) + if (entity_indices[ii] == size_t(-1)) + densities_stencil[ii] = &boundary_distribution_evaluations_[entity_indices[1]][dd][boundary_direction[ii]]; + else + densities_stencil[ii] = &(*eta_ast_prime_evaluations_)[entity_indices[ii]]; + implementation_->template calculate_reconstructed_fluxes<slope, FluxesMapType>( + densities_stencil, precomputed_fluxes, dd); + } + + void apply_inverse_hessian(const size_t entity_index, const StateType& u, StateType& Hinv_u) const + { + implementation_->apply_inverse_hessian((*eta_ast_twoprime_evaluations_)[entity_index], u, Hinv_u); + } + + void store_evaluations(const size_t entity_index, const StateType& alpha) + { + implementation_->store_exp_evaluations(exp_evaluations_[entity_index], alpha); + if (entropy != EntropyType::MaxwellBoltzmann) { + implementation_->store_eta_ast_prime_vals(exp_evaluations_[entity_index], eta_ast_prime_storage_[entity_index]); + implementation_->store_eta_ast_twoprime_vals(exp_evaluations_[entity_index], + eta_ast_twoprime_storage_[entity_index]); + } + } + + void set_eta_ast_pointers() + { + if (entropy == EntropyType::MaxwellBoltzmann) { + eta_ast_prime_evaluations_ = &exp_evaluations_; + eta_ast_twoprime_evaluations_ = &exp_evaluations_; + } else { + eta_ast_prime_evaluations_ = &eta_ast_prime_storage_; + eta_ast_twoprime_evaluations_ = &eta_ast_twoprime_storage_; + } + } + + void store_boundary_evaluations(const std::function<RangeFieldType(const DomainType&)>& boundary_distribution, + const size_t entity_index, + const size_t intersection_index) + { + implementation_->store_boundary_distribution_evaluations( + boundary_distribution_evaluations_[entity_index][intersection_index / 2][intersection_index % 2], + boundary_distribution); + } + + std::vector<QuadratureWeightsType>& exp_evaluations() + { + return exp_evaluations_; + } + + const std::vector<QuadratureWeightsType>& exp_evaluations() const + { + return exp_evaluations_; + } + + std::vector<QuadratureWeightsType>& eta_ast_prime_evaluations() + { + return *eta_ast_prime_evaluations_; + } + + const std::vector<QuadratureWeightsType>& eta_ast_prime_evaluations() const + { + return *eta_ast_prime_evaluations_; + } + + std::vector<QuadratureWeightsType>& eta_ast_twoprime_evaluations() + { + return *eta_ast_twoprime_evaluations_; + } + + const std::vector<QuadratureWeightsType>& eta_ast_twoprime_evaluations() const + { + return *eta_ast_twoprime_evaluations_; + } + + BoundaryQuadratureWeightsType& boundary_distribution_evaluations() + { + return boundary_distribution_evaluations_; + } + + const BoundaryQuadratureWeightsType& boundary_distribution_evaluations() const + { + return boundary_distribution_evaluations_; + } + + +private: + std::shared_ptr<ImplementationType> implementation_; + std::vector<QuadratureWeightsType> exp_evaluations_; + std::vector<QuadratureWeightsType> eta_ast_prime_storage_; + std::vector<QuadratureWeightsType> eta_ast_twoprime_storage_; + std::vector<QuadratureWeightsType>* eta_ast_prime_evaluations_; + std::vector<QuadratureWeightsType>* eta_ast_twoprime_evaluations_; + BoundaryQuadratureWeightsType boundary_distribution_evaluations_; +}; + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_LOCAL_FLUXES_ENTROPYBASED_KINETICCOORDS_HH diff --git a/dune/gdt/test/momentmodels/entropysolver.hh b/dune/gdt/test/momentmodels/entropysolver.hh new file mode 100644 index 0000000000000000000000000000000000000000..6540b7edc7ab81db8c8175503ea4be0a465cd407 --- /dev/null +++ b/dune/gdt/test/momentmodels/entropysolver.hh @@ -0,0 +1,190 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2018) + +#ifndef DUNE_GDT_MOMENTMODELS_ENTROPYSOLVER_HH +#define DUNE_GDT_MOMENTMODELS_ENTROPYSOLVER_HH + +#include <string> + +#include <dune/xt/grid/functors/interfaces.hh> +#include <dune/xt/common/parameter.hh> + +#include <dune/gdt/discretefunction/default.hh> +#include <dune/gdt/test/momentmodels/entropyflux.hh> +#include <dune/gdt/operators/interfaces.hh> +#include <dune/gdt/type_traits.hh> + +namespace Dune { +namespace GDT { + + +template <class SpaceType, class VectorType, class MomentBasis> +class LocalEntropySolver : public XT::Grid::ElementFunctor<typename SpaceType::GridViewType> +{ + using GridViewType = typename SpaceType::GridViewType; + using BaseType = XT::Grid::ElementFunctor<GridViewType>; + using EntityType = typename GridViewType::template Codim<0>::Entity; + using IndexSetType = typename GridViewType::IndexSet; + using EntropyFluxType = EntropyBasedFluxFunction<GridViewType, MomentBasis>; + using RangeFieldType = typename EntropyFluxType::RangeFieldType; + using LocalVectorType = typename EntropyFluxType::VectorType; + static const size_t dimFlux = EntropyFluxType::dimFlux; + static const size_t dimRange = EntropyFluxType::basis_dimRange; + using DiscreteFunctionType = DiscreteFunction<VectorType, GridViewType, dimRange, 1, RangeFieldType>; + using ConstDiscreteFunctionType = ConstDiscreteFunction<VectorType, GridViewType, dimRange, 1, RangeFieldType>; + +public: + explicit LocalEntropySolver(const SpaceType& space, + const VectorType& source_dofs, + VectorType& range_dofs, + const EntropyFluxType& analytical_flux, + const RangeFieldType min_acceptable_density, + const XT::Common::Parameter& param, + const std::string filename = "") + : space_(space) + , source_(space_, source_dofs, "source") + , local_source_(source_.local_discrete_function()) + , range_(space_, range_dofs, "range") + , local_range_(range_.local_discrete_function()) + , analytical_flux_(analytical_flux) + , local_flux_(analytical_flux_.derived_local_function()) + , min_acceptable_density_(min_acceptable_density) + , param_(param) + , filename_(filename.empty() ? "" : (filename + "_regularization.txt")) + , index_set_(space_.grid_view().indexSet()) + {} + + explicit LocalEntropySolver(LocalEntropySolver& other) + : BaseType(other) + , space_(other.space_) + , source_(space_, other.source_.dofs().vector(), "source") + , local_source_(source_.local_discrete_function()) + , range_(space_, other.range_.dofs().vector(), "range") + , local_range_(range_.local_discrete_function()) + , analytical_flux_(other.analytical_flux_) + , local_flux_(analytical_flux_.derived_local_function()) + , min_acceptable_density_(other.min_acceptable_density_) + , param_(other.param_) + , filename_(other.filename_) + , index_set_(space_.grid_view().indexSet()) + {} + + XT::Grid::ElementFunctor<GridViewType>* copy() override final + { + return new LocalEntropySolver(*this); + } + + void apply_local(const EntityType& entity) override final + { + local_source_->bind(entity); + local_range_->bind(entity); + XT::Common::FieldVector<RangeFieldType, dimRange> u; + for (size_t ii = 0; ii < dimRange; ++ii) + u[ii] = local_source_->dofs().get_entry(ii); + const auto& basis_functions = analytical_flux_.basis_functions(); + basis_functions.ensure_min_density(u, min_acceptable_density_); + local_flux_->bind(entity); + const auto alpha_ret = local_flux_->get_alpha(u, true); + const auto regularization_params = alpha_ret->second; + for (size_t ii = 0; ii < dimRange; ++ii) + local_range_->dofs().set_entry(ii, regularization_params.first[ii]); + const auto s = regularization_params.second; + if (s > 0.) { + if (!filename_.empty()) { + static std::mutex outfile_lock; + outfile_lock.lock(); + std::ofstream outfile(filename_, std::ios_base::app); + outfile << param_.get("t")[0]; + for (size_t ii = 0; ii < dimFlux; ++ii) + outfile << " " << entity.geometry().center()[ii]; + outfile << " " << s << " "; + outfile << XT::Common::to_string(u, 15) << std::endl; + outfile_lock.unlock(); + } + } + } // void apply_local(...) + +private: + const SpaceType& space_; + const ConstDiscreteFunctionType source_; + std::unique_ptr<typename ConstDiscreteFunctionType::ConstLocalDiscreteFunctionType> local_source_; + DiscreteFunctionType range_; + std::unique_ptr<typename DiscreteFunctionType::LocalDiscreteFunctionType> local_range_; + const EntropyFluxType& analytical_flux_; + std::unique_ptr<typename EntropyFluxType::Localfunction> local_flux_; + const RangeFieldType min_acceptable_density_; + const XT::Common::Parameter& param_; + const std::string filename_; + const typename SpaceType::GridViewType::IndexSet& index_set_; +}; // class LocalEntropySolver<...> + + +template <class MomentBasisImp, + class SpaceImp, + class MatrixType = typename XT::LA::Container<typename MomentBasisImp::RangeFieldType>::MatrixType> +class EntropySolver : public OperatorInterface<MatrixType, typename SpaceImp::GridViewType, MomentBasisImp::dimRange, 1> +{ + using BaseType = OperatorInterface<MatrixType, typename SpaceImp::GridViewType, MomentBasisImp::dimRange, 1>; + +public: + using typename BaseType::VectorType; + using MomentBasis = MomentBasisImp; + using SpaceType = SpaceImp; + using SourceSpaceType = SpaceImp; + using RangeSpaceType = SpaceImp; + using EntropyFluxType = EntropyBasedFluxFunction<typename SpaceType::GridViewType, MomentBasis>; + using RangeFieldType = typename MomentBasis::RangeFieldType; + using LocalVectorType = typename EntropyFluxType::VectorType; + + EntropySolver(const EntropyFluxType& analytical_flux, + const SpaceType& space, + const RangeFieldType min_acceptable_density, + const std::string filename = "") + : analytical_flux_(analytical_flux) + , space_(space) + , min_acceptable_density_(min_acceptable_density) + , filename_(filename) + {} + + bool linear() const override final + { + return false; + } + + const SourceSpaceType& source_space() const override final + { + return space_; + } + + const RangeSpaceType& range_space() const override final + { + return space_; + } + + void apply(const VectorType& source, VectorType& range, const XT::Common::Parameter& param) const override final + { + LocalEntropySolver<SpaceType, VectorType, MomentBasis> local_entropy_solver( + space_, source, range, analytical_flux_, min_acceptable_density_, param, filename_); + auto walker = XT::Grid::Walker<typename SpaceType::GridViewType>(space_.grid_view()); + walker.append(local_entropy_solver); + walker.walk(true); + } // void apply(...) + +private: + const EntropyFluxType& analytical_flux_; + const SpaceType& space_; + const RangeFieldType min_acceptable_density_; + const std::string filename_; +}; // class EntropySolver<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_MOMENTMODELS_ENTROPYSOLVER_HH diff --git a/dune/gdt/test/momentmodels/hessianinverter.hh b/dune/gdt/test/momentmodels/hessianinverter.hh new file mode 100644 index 0000000000000000000000000000000000000000..bbe655e48213bd20ffbb9d8552212852fc5c5ec3 --- /dev/null +++ b/dune/gdt/test/momentmodels/hessianinverter.hh @@ -0,0 +1,174 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2018) + +#ifndef DUNE_GDT_MOMENTMODELS_HESSIANINVERTER_HH +#define DUNE_GDT_MOMENTMODELS_HESSIANINVERTER_HH + +#include <string> + +#include <dune/xt/grid/functors/interfaces.hh> +#include <dune/xt/common/parameter.hh> + +#include <dune/gdt/discretefunction/default.hh> +#include <dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh> +#include <dune/gdt/operators/interfaces.hh> +#include <dune/gdt/type_traits.hh> + +namespace Dune { +namespace GDT { + + +template <class SpaceType, class VectorType, class MomentBasis, SlopeLimiterType slope> +class LocalEntropicHessianInverter : public XT::Grid::ElementFunctor<typename SpaceType::GridViewType> +{ + using GridViewType = typename SpaceType::GridViewType; + using BaseType = XT::Grid::ElementFunctor<GridViewType>; + using EntityType = typename GridViewType::template Codim<0>::Entity; + using IndexSetType = typename GridViewType::IndexSet; + using EntropyFluxType = EntropyBasedFluxEntropyCoordsFunction<GridViewType, MomentBasis, slope>; + using RangeFieldType = typename EntropyFluxType::RangeFieldType; + static const size_t dimFlux = EntropyFluxType::dimFlux; + static const size_t dimRange = EntropyFluxType::basis_dimRange; + using DiscreteFunctionType = DiscreteFunction<VectorType, GridViewType, dimRange, 1, RangeFieldType>; + using ConstDiscreteFunctionType = ConstDiscreteFunction<VectorType, GridViewType, dimRange, 1, RangeFieldType>; + +public: + explicit LocalEntropicHessianInverter(const SpaceType& space, + const VectorType& alpha_dofs, + const VectorType& u_update_dofs, + VectorType& alpha_range_dofs, + const EntropyFluxType& analytical_flux, + const XT::Common::Parameter& param) + : space_(space) + , alpha_(space_, alpha_dofs, "alpha") + , u_update_(space_, u_update_dofs, "u_update") + , local_alpha_(alpha_.local_discrete_function()) + , local_u_update_(u_update_.local_discrete_function()) + , range_(space_, alpha_range_dofs, "range") + , local_range_(range_.local_discrete_function()) + , analytical_flux_(analytical_flux) + , param_(param) + {} + + explicit LocalEntropicHessianInverter(LocalEntropicHessianInverter& other) + : BaseType(other) + , space_(other.space_) + , alpha_(space_, other.alpha_.dofs().vector(), "source") + , u_update_(space_, other.u_update_.dofs().vector(), "source") + , local_alpha_(alpha_.local_discrete_function()) + , local_u_update_(u_update_.local_discrete_function()) + , range_(space_, other.range_.dofs().vector(), "range") + , local_range_(range_.local_discrete_function()) + , analytical_flux_(other.analytical_flux_) + , param_(other.param_) + {} + + XT::Grid::ElementFunctor<GridViewType>* copy() override final + { + return new LocalEntropicHessianInverter(*this); + } + + void apply_local(const EntityType& entity) override final + { + local_u_update_->bind(entity); + local_range_->bind(entity); + XT::Common::FieldVector<RangeFieldType, dimRange> u, Hinv_u; + for (size_t ii = 0; ii < dimRange; ++ii) + u[ii] = local_u_update_->dofs().get_entry(ii); + analytical_flux_.apply_inverse_hessian(space_.grid_view().indexSet().index(entity), u, Hinv_u); + for (auto&& entry : Hinv_u) + if (std::isnan(entry) || std::isinf(entry)) { + // std::cout << "x: " << entity.geometry().center() << "u: " << u << ", alpha: " << alpha << ", Hinv_u: " + // << Hinv_u << std::endl; + DUNE_THROW(Dune::MathError, "Hessian"); + } + + for (size_t ii = 0; ii < dimRange; ++ii) + local_range_->dofs().set_entry(ii, Hinv_u[ii]); + } // void apply_local(...) + +private: + const SpaceType& space_; + const ConstDiscreteFunctionType alpha_; + const ConstDiscreteFunctionType u_update_; + std::unique_ptr<typename ConstDiscreteFunctionType::ConstLocalDiscreteFunctionType> local_alpha_; + std::unique_ptr<typename ConstDiscreteFunctionType::ConstLocalDiscreteFunctionType> local_u_update_; + DiscreteFunctionType range_; + std::unique_ptr<typename DiscreteFunctionType::LocalDiscreteFunctionType> local_range_; + const EntropyFluxType& analytical_flux_; + const XT::Common::Parameter& param_; +}; // class LocalEntropicHessianInverter<...> + +template <class MomentBasisImp, + class SpaceImp, + SlopeLimiterType slope, + class MatrixType = typename XT::LA::Container<typename MomentBasisImp::RangeFieldType>::MatrixType> +class EntropicHessianInverter + : public OperatorInterface<MatrixType, typename SpaceImp::GridViewType, MomentBasisImp::dimRange, 1> +{ + using BaseType = OperatorInterface<MatrixType, typename SpaceImp::GridViewType, MomentBasisImp::dimRange, 1>; + +public: + using typename BaseType::VectorType; + using MomentBasis = MomentBasisImp; + using SpaceType = SpaceImp; + using SourceSpaceType = SpaceImp; + using RangeSpaceType = SpaceImp; + using EntropyFluxType = EntropyBasedFluxEntropyCoordsFunction<typename SpaceType::GridViewType, MomentBasis, slope>; + using RangeFieldType = typename MomentBasis::RangeFieldType; + + EntropicHessianInverter(const EntropyFluxType& analytical_flux, const SpaceType& space) + : analytical_flux_(analytical_flux) + , space_(space) + {} + + bool linear() const override final + { + return false; + } + + const SourceSpaceType& source_space() const override final + { + return space_; + } + + const RangeSpaceType& range_space() const override final + { + return space_; + } + + void apply(const VectorType& /*source*/, + VectorType& /*range*/, + const XT::Common::Parameter& /*param*/) const override final + { + DUNE_THROW(Dune::NotImplemented, "Use apply_inverse_hessian!"); + } // void apply(...) + + void apply_inverse_hessian(const VectorType& alpha, + const VectorType& u_update, + VectorType& alpha_update, + const XT::Common::Parameter& param) const + { + LocalEntropicHessianInverter<SpaceType, VectorType, MomentBasis, slope> local_hessian_inverter( + space_, alpha, u_update, alpha_update, analytical_flux_, param); + auto walker = XT::Grid::Walker<typename SpaceType::GridViewType>(space_.grid_view()); + walker.append(local_hessian_inverter); + walker.walk(true); + } // void apply(...) + +private: + const EntropyFluxType& analytical_flux_; + const SpaceType& space_; +}; // class EntropicHessianInverter<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_MOMENTMODELS_HESSIANINVERTER_HH diff --git a/dune/gdt/test/momentmodels/hyperbolic__momentmodels__entropic_coords_mn.cc b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__entropic_coords_mn.cc new file mode 100644 index 0000000000000000000000000000000000000000..de05f5fd8cd5b786b94a646e17bca7894df20dd9 --- /dev/null +++ b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__entropic_coords_mn.cc @@ -0,0 +1,51 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +// This one has to come first (includes the config.h)! +#include <dune/xt/common/test/main.hxx> + +#include <dune/gdt/test/momentmodels/kinetictransport/testcases.hh> +#include <dune/gdt/test/momentmodels/entropic-coords-mn-discretization.hh> + +using Yasp1 = Dune::YaspGrid<1, Dune::EquidistantOffsetCoordinates<double, 1>>; +using Yasp2 = Dune::YaspGrid<2, Dune::EquidistantOffsetCoordinates<double, 2>>; +using Yasp3 = Dune::YaspGrid<3, Dune::EquidistantOffsetCoordinates<double, 3>>; + +using YaspGridTestCasesAll = testing::Types< + // The kinetic scheme does not work for Legendre Mn in the SourceBeam test + // Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, false, true>, + // Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 20>, true, true> + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, false, true>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, true, true>, + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, false, true>, + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, true, true>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, false, true>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, true, true>, + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, false, true>, + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, true, true>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, false, true>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, true, true> +#if !DXT_DISABLE_LARGE_TESTS + , + Dune::GDT:: + PointSourceMnTestCase<Yasp3, Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, false, true>, + Dune::GDT:: + PointSourceMnTestCase<Yasp3, Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, true, true>, + // Dune::GDT::ShadowMnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 1, 1, 3>, true, true>, + Dune::GDT::CheckerboardMnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, true, true>, + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, false, true>, + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, true, true>, + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::PartialMomentBasis<double, 3, double, 0, 1, 3>, false, true>, + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::PartialMomentBasis<double, 3, double, 0, 1, 3>, true, true> +#endif // !DXT_DISABLE_LARGE_TESTS + >; + +TYPED_TEST_CASE(HyperbolicEntropicCoordsMnTest, YaspGridTestCasesAll); +TYPED_TEST(HyperbolicEntropicCoordsMnTest, check) +{ + this->run(); +} diff --git a/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_1dhatfunctions_analytic.cc b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_1dhatfunctions_analytic.cc new file mode 100644 index 0000000000000000000000000000000000000000..a5f3b0866d9dfac012fae39b97d13ba8e5604619 --- /dev/null +++ b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_1dhatfunctions_analytic.cc @@ -0,0 +1,30 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +#define ENTROPY_FLUX_1D_HATFUNCTIONS_USE_ANALYTICAL_INTEGRALS 1 + +// This one has to come first (includes the config.h)! +#include <dune/xt/common/test/main.hxx> + +#include <dune/gdt/test/momentmodels/kinetictransport/testcases.hh> +#include <dune/gdt/test/momentmodels/mn-discretization.hh> + +using Yasp1 = Dune::YaspGrid<1, Dune::EquidistantOffsetCoordinates<double, 1>>; +using Yasp2 = Dune::YaspGrid<2, Dune::EquidistantOffsetCoordinates<double, 2>>; +using Yasp3 = Dune::YaspGrid<3, Dune::EquidistantOffsetCoordinates<double, 3>>; + +using YaspGridTestCases1dHatAnalytic = testing::Types< + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, false>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, false>, + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, true>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, true>>; + +TYPED_TEST_CASE(HyperbolicMnTest, YaspGridTestCases1dHatAnalytic); +TYPED_TEST(HyperbolicMnTest, check) +{ + this->run(1e-3); +} diff --git a/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_boseeinstein.cc b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_boseeinstein.cc new file mode 100644 index 0000000000000000000000000000000000000000..97e19ecb525e933d2cbc646857843feabb295bf6 --- /dev/null +++ b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_boseeinstein.cc @@ -0,0 +1,54 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +// This one has to come first (includes the config.h)! +#include <dune/xt/common/test/main.hxx> + +#include <dune/gdt/test/momentmodels/kinetictransport/testcases.hh> +#include <dune/gdt/test/momentmodels/mn-discretization.hh> + +using Yasp1 = Dune::YaspGrid<1, Dune::EquidistantOffsetCoordinates<double, 1>>; +using Yasp2 = Dune::YaspGrid<2, Dune::EquidistantOffsetCoordinates<double, 2>>; +using Yasp3 = Dune::YaspGrid<3, Dune::EquidistantOffsetCoordinates<double, 3>>; + +constexpr Dune::GDT::EntropyType entropy = Dune::GDT::EntropyType::BoseEinstein; + +using YaspGridTestCasesAll = testing::Types< +#if HAVE_CLP + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7, 1, entropy>, false>, + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7, 1, entropy>, true>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7, 1, entropy>, false>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7, 1, entropy>, true>, +#endif + Dune::GDT:: + SourceBeamMnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1, 1, entropy>, false>, + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1, 1, entropy>, true>, + Dune::GDT:: + SourceBeamMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1, entropy>, false>, + Dune::GDT:: + SourceBeamMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1, entropy>, true>, + Dune::GDT:: + PointSourceMnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 0, 1, 3, entropy>, false>, + Dune::GDT:: + PointSourceMnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 0, 1, 3, entropy>, true> +#if HAVE_CLP + , + Dune::GDT::PointSourceMnTestCase<Yasp3, + Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3, false, entropy>, + true> +#endif +#if HAVE_QHULL + , + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::PartialMomentBasis<double, 3, double, 0, 1, 3, 1, entropy>, true> +#endif + >; + +TYPED_TEST_CASE(HyperbolicMnTest, YaspGridTestCasesAll); +TYPED_TEST(HyperbolicMnTest, check) +{ + this->run(); +} diff --git a/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_nochangeofbasis.cc b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_nochangeofbasis.cc new file mode 100644 index 0000000000000000000000000000000000000000..07c2ef64a55f041faaf6144c3d5a26a870d452b4 --- /dev/null +++ b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_nochangeofbasis.cc @@ -0,0 +1,39 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +#define ENTROPY_FLUX_UNSPECIALIZED_USE_ADAPTIVE_CHANGE_OF_BASIS 0 + +// This one has to come first (includes the config.h)! +#include <dune/xt/common/test/main.hxx> + +#include <dune/gdt/test/momentmodels/kinetictransport/testcases.hh> +#include <dune/gdt/test/momentmodels/mn-discretization.hh> + +using Yasp1 = Dune::YaspGrid<1, Dune::EquidistantOffsetCoordinates<double, 1>>; +using Yasp3 = Dune::YaspGrid<3, Dune::EquidistantOffsetCoordinates<double, 3>>; + +using YaspGridTestCasesNoBasisChange = testing::Types< +#if HAVE_CLP + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, false>, + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, true>, +#endif + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, false>, + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, true> +#if !DXT_DISABLE_LARGE_TESTS + , +# if HAVE_CLP + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, false>, +# endif + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, false> +#endif + >; + +TYPED_TEST_CASE(HyperbolicMnTest, YaspGridTestCasesNoBasisChange); +TYPED_TEST(HyperbolicMnTest, check) +{ + this->run(); +} diff --git a/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_ord1.cc b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_ord1.cc new file mode 100644 index 0000000000000000000000000000000000000000..a7e727e77c5c0d9a3e4ec98225aaa0813860870a --- /dev/null +++ b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_ord1.cc @@ -0,0 +1,48 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +// This one has to come first (includes the config.h)! +#include <dune/xt/common/test/main.hxx> + +#define USE_LP_POSITIVITY_LIMITER 1 + +#include <dune/gdt/test/momentmodels/kinetictransport/testcases.hh> +#include <dune/gdt/test/momentmodels/mn-discretization.hh> + +using Yasp1 = Dune::YaspGrid<1, Dune::EquidistantOffsetCoordinates<double, 1>>; +using Yasp2 = Dune::YaspGrid<2, Dune::EquidistantOffsetCoordinates<double, 2>>; +using Yasp3 = Dune::YaspGrid<3, Dune::EquidistantOffsetCoordinates<double, 3>>; + +using YaspGridTestCasesOrd1 = testing::Types< +#if HAVE_CLP + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, false>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, false>, +#endif + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, false>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, false>, + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, false>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, false> +#if !DXT_DISABLE_LARGE_TESTS + , +# if HAVE_CLP + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, false>, + Dune::GDT::CheckerboardMnTestCase<Yasp3, Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, false>, + Dune::GDT::ShadowMnTestCase<Yasp3, Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, false>, +# endif + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, false> +# if HAVE_QHULL + , + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::PartialMomentBasis<double, 3, double, 0, 1, 3>, false> +# endif +#endif + >; + +TYPED_TEST_CASE(HyperbolicMnTest, YaspGridTestCasesOrd1); +TYPED_TEST(HyperbolicMnTest, check) +{ + this->run(); +} diff --git a/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_ord2.cc b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_ord2.cc new file mode 100644 index 0000000000000000000000000000000000000000..70250ddeb73672d5c53b3b92953f28b130d0d60a --- /dev/null +++ b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__mn_ord2.cc @@ -0,0 +1,50 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +// This one has to come first (includes the config.h)! +#include <dune/xt/common/test/main.hxx> + +#define USE_LP_POSITIVITY_LIMITER 1 + +#include <dune/gdt/test/momentmodels/kinetictransport/testcases.hh> +#include <dune/gdt/test/momentmodels/mn-discretization.hh> + +using Yasp1 = Dune::YaspGrid<1, Dune::EquidistantOffsetCoordinates<double, 1>>; +using Yasp2 = Dune::YaspGrid<2, Dune::EquidistantOffsetCoordinates<double, 2>>; +using Yasp3 = Dune::YaspGrid<3, Dune::EquidistantOffsetCoordinates<double, 3>>; + +using YaspGridTestCasesOrd2 = testing::Types< +#if HAVE_CLP + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, true>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, true>, +#endif + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, true>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, true>, + Dune::GDT::SourceBeamMnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, true>, + Dune::GDT::PlaneSourceMnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, true> +#if !DXT_DISABLE_LARGE_TESTS +# if HAVE_CLP + , + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, true> +# endif +// Our shifted qr eigensolver fails for this problem, needs better shifting strategy +# if HAVE_MKL || HAVE_LAPACKE || HAVE_EIGEN + , + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, true> +# endif +# if HAVE_QHULL + , + Dune::GDT::PointSourceMnTestCase<Yasp3, Dune::GDT::PartialMomentBasis<double, 3, double, 0, 1, 3>, true> +# endif +#endif + >; + +TYPED_TEST_CASE(HyperbolicMnTest, YaspGridTestCasesOrd2); +TYPED_TEST(HyperbolicMnTest, check) +{ + this->run(); +} diff --git a/dune/gdt/test/momentmodels/hyperbolic__momentmodels__pn.cc b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__pn.cc new file mode 100644 index 0000000000000000000000000000000000000000..b90d55bddc6b6c88c8f0f2c7aa8df1f7fcc4f5fb --- /dev/null +++ b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__pn.cc @@ -0,0 +1,31 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +// This one has to come first (includes the config.h)! +#include <dune/xt/common/test/main.hxx> + +#define USE_FULL_LINEAR_RECONSTRUCTION_OPERATOR 1 +#include <dune/gdt/test/momentmodels/hyperbolic_momentmodels_pn_base.hh> +#include <dune/gdt/test/momentmodels/pn-discretization.hh> + +TYPED_TEST_CASE(HyperbolicPnTest, YaspGridTestCasesWithoutReconstruction); +TYPED_TEST(HyperbolicPnTest, check) +{ + this->run(); +} + +template <class TestCaseType> +struct HyperbolicPnTestWithReconstruction : public HyperbolicPnTest<TestCaseType> +{}; + +TYPED_TEST_CASE(HyperbolicPnTestWithReconstruction, YaspGridTestCasesWithReconstruction); +TYPED_TEST(HyperbolicPnTestWithReconstruction, check_with_full_linear_reconstruction) +{ + // evaluation of reconstructed function is not thread-safe at the moment + DXTC_CONFIG["threading.max_count"] = "1"; + this->run(); +} diff --git a/dune/gdt/test/momentmodels/hyperbolic__momentmodels__pn__pointwise_reconstruction.cc b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__pn__pointwise_reconstruction.cc new file mode 100644 index 0000000000000000000000000000000000000000..0ffe18e93681efc9de772569e8b249135071bbd3 --- /dev/null +++ b/dune/gdt/test/momentmodels/hyperbolic__momentmodels__pn__pointwise_reconstruction.cc @@ -0,0 +1,19 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +// This one has to come first (includes the config.h)! +#include <dune/xt/common/test/main.hxx> + +#define USE_FULL_LINEAR_RECONSTRUCTION_OPERATOR 0 +#include <dune/gdt/test/momentmodels/hyperbolic_momentmodels_pn_base.hh> +#include <dune/gdt/test/momentmodels/pn-discretization.hh> + +TYPED_TEST_CASE(HyperbolicPnTest, YaspGridTestCasesWithReconstruction); +TYPED_TEST(HyperbolicPnTest, check_with_pointwise_linear_reconstruction) +{ + this->run(); +} diff --git a/dune/gdt/test/momentmodels/hyperbolic_momentmodels_pn_base.hh b/dune/gdt/test/momentmodels/hyperbolic_momentmodels_pn_base.hh new file mode 100644 index 0000000000000000000000000000000000000000..84ba22d199fa4353fbb22ebc89629aa1681d7786 --- /dev/null +++ b/dune/gdt/test/momentmodels/hyperbolic_momentmodels_pn_base.hh @@ -0,0 +1,53 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +#ifndef DUNE_GDT_TEST_HYPERBOLIC_MOMENTMODELS_PN_HH +#define DUNE_GDT_TEST_HYPERBOLIC_MOMENTMODELS_PN_HH + +#include <dune/xt/common/test/gtest/gtest.h> + +#include <dune/gdt/test/momentmodels/kinetictransport/testcases.hh> + +using Yasp1 = Dune::YaspGrid<1, Dune::EquidistantOffsetCoordinates<double, 1>>; +using Yasp2 = Dune::YaspGrid<2, Dune::EquidistantOffsetCoordinates<double, 2>>; +using Yasp3 = Dune::YaspGrid<3, Dune::EquidistantOffsetCoordinates<double, 3>>; + +using YaspGridTestCasesWithoutReconstruction = testing::Types< + Dune::GDT::SourceBeamPnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, false>, + Dune::GDT::PlaneSourcePnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, false>, + Dune::GDT::SourceBeamPnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, false>, + Dune::GDT::PlaneSourcePnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, false>, + Dune::GDT::SourceBeamPnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, false>, + Dune::GDT::PlaneSourcePnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, false>, + Dune::GDT::PointSourcePnTestCase<Yasp3, Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, false>, + Dune::GDT::CheckerboardPnTestCase<Yasp3, Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, false>, + Dune::GDT::ShadowPnTestCase<Yasp3, Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, false> +#if !DXT_DISABLE_LARGE_TESTS + , + Dune::GDT::PointSourcePnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, false>, + Dune::GDT::PointSourcePnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 1, 1, 3>, false>, + Dune::GDT::PointSourcePnTestCase<Yasp3, Dune::GDT::PartialMomentBasis<double, 3, double, 0, 1, 3>, false>, + Dune::GDT::PointSourcePnTestCase<Yasp3, Dune::GDT::PartialMomentBasis<double, 3, double, 1, 1, 3>, false> +#endif + >; + +using YaspGridTestCasesWithReconstruction = testing::Types< + Dune::GDT::SourceBeamPnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, true>, + Dune::GDT::PlaneSourcePnTestCase<Yasp1, Dune::GDT::LegendreMomentBasis<double, double, 7>, true>, + Dune::GDT::SourceBeamPnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, true>, + Dune::GDT::PlaneSourcePnTestCase<Yasp1, Dune::GDT::HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, true>, + Dune::GDT::SourceBeamPnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, true>, + Dune::GDT::PlaneSourcePnTestCase<Yasp1, Dune::GDT::PartialMomentBasis<double, 1, double, 8, 1, 1>, true> +#if !DXT_DISABLE_LARGE_TESTS + , + Dune::GDT::PointSourcePnTestCase<Yasp3, Dune::GDT::RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, true>, + Dune::GDT::PointSourcePnTestCase<Yasp3, Dune::GDT::HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, true>, + Dune::GDT::PointSourcePnTestCase<Yasp3, Dune::GDT::PartialMomentBasis<double, 3, double, 0, 1, 3>, true> +#endif + >; + +#endif // DUNE_GDT_TEST_HYPERBOLIC_MOMENTMODELS_PN_HH diff --git a/dune/gdt/test/momentmodels/kineticequation.hh b/dune/gdt/test/momentmodels/kineticequation.hh new file mode 100644 index 0000000000000000000000000000000000000000..d9ff3ff2fc27498b802a63f41c530e531dc8cf5c --- /dev/null +++ b/dune/gdt/test/momentmodels/kineticequation.hh @@ -0,0 +1,106 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2017 - 2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_KINETICEQUATION_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_KINETICEQUATION_HH + +#include <dune/xt/grid/gridprovider.hh> + +#include <dune/xt/functions/generic/flux-function.hh> +#include <dune/xt/functions/generic/function.hh> + +namespace Dune { +namespace GDT { + + +template <class E, class MomentBasisImp> +class KineticEquationInterface +{ + using ThisType = KineticEquationInterface; + +public: + using MomentBasis = MomentBasisImp; + using DomainFieldType = typename MomentBasis::DomainFieldType; + using RangeFieldType = typename MomentBasis::RangeFieldType; + static const size_t dimDomain = MomentBasis::dimDomain; + static const size_t dimRange = MomentBasis::dimRange; + static const size_t dimRangeCols = MomentBasis::dimRangeCols; + static const size_t dimFlux = MomentBasis::dimFlux; + using FluxType = XT::Functions::FluxFunctionInterface<E, dimRange, dimFlux, dimRange, RangeFieldType>; + using GenericFluxFunctionType = XT::Functions::GenericFluxFunction<E, dimRange, dimFlux, dimRange, RangeFieldType>; + using InitialValueType = XT::Functions::FunctionInterface<dimFlux, dimRange, 1, RangeFieldType>; + using GenericFunctionType = XT::Functions::GenericFunction<dimFlux, dimRange, 1, RangeFieldType>; + using ScalarFunctionType = XT::Functions::FunctionInterface<dimFlux, 1, 1, RangeFieldType>; + using BoundaryValueType = InitialValueType; + using MatrixType = typename Dune::DynamicMatrix<RangeFieldType>; + using DomainType = typename InitialValueType::DomainType; + using BasisDomainType = typename MomentBasis::DomainType; + using StateType = typename FluxType::StateType; + using RangeReturnType = typename InitialValueType::RangeReturnType; + using DynamicRangeType = Dune::DynamicVector<RangeFieldType>; + + KineticEquationInterface(const MomentBasis& basis_functions) + : basis_functions_(basis_functions) + {} + + virtual ~KineticEquationInterface() {} + + static XT::Common::Configuration default_grid_cfg() + { + XT::Common::Configuration grid_config; + grid_config["type"] = XT::Grid::cube_gridprovider_default_config()["type"]; + grid_config["lower_left"] = "[0.0]"; + grid_config["upper_right"] = "[1.0]"; + grid_config["num_elements"] = "[100]"; + grid_config["overlap_size"] = "[1]"; + return grid_config; + } + + static XT::Common::Configuration default_boundary_cfg() + { + XT::Common::Configuration boundary_config; + boundary_config["type"] = "dirichlet"; + return boundary_config; + } + + virtual std::unique_ptr<FluxType> flux() const = 0; + + virtual std::unique_ptr<InitialValueType> initial_values() const = 0; + + virtual std::unique_ptr<BoundaryValueType> boundary_values() const = 0; + + virtual RangeFieldType CFL() const = 0; + + virtual RangeFieldType t_end() const = 0; + + virtual std::unique_ptr<ScalarFunctionType> sigma_a() const = 0; + + virtual std::unique_ptr<ScalarFunctionType> sigma_s() const = 0; + + virtual std::unique_ptr<ScalarFunctionType> Q() const = 0; + + virtual XT::Common::Configuration grid_config() const = 0; + + virtual XT::Common::Configuration boundary_config() const = 0; + + static std::string static_id() + { + return "kineticequationinterface"; + } + +protected: + const MomentBasis& basis_functions_; +}; // class KineticEquationInterface<E, ...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_KINETICEQUATION_HH diff --git a/dune/gdt/test/momentmodels/kinetictransport.hh b/dune/gdt/test/momentmodels/kinetictransport.hh new file mode 100644 index 0000000000000000000000000000000000000000..e6569ae9b6e27ac3806f34f13a7fd26b372bc0f6 --- /dev/null +++ b/dune/gdt/test/momentmodels/kinetictransport.hh @@ -0,0 +1,21 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2017 - 2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_KINETICTRANSPORT_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_KINETICTRANSPORT_HH + +#include "kinetictransport/base.hh" +#include "kinetictransport/checkerboard.hh" +#include "kinetictransport/planesource.hh" +#include "kinetictransport/pointsource.hh" +#include "kinetictransport/shadow.hh" +#include "kinetictransport/sourcebeam.hh" + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_KINETICTRANSPORT_HH diff --git a/dune/gdt/test/momentmodels/kinetictransport/base.hh b/dune/gdt/test/momentmodels/kinetictransport/base.hh new file mode 100644 index 0000000000000000000000000000000000000000..c9705f94278d971d8877fdb332d2d2d35afe3073 --- /dev/null +++ b/dune/gdt/test/momentmodels/kinetictransport/base.hh @@ -0,0 +1,251 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_KINETICTRANSPORTEQUATION_BASE_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_KINETICTRANSPORTEQUATION_BASE_HH + +#include <dune/grid/common/partitionset.hh> + +#include <dune/xt/functions/constant.hh> + +#include <dune/xt/la/solver.hh> + +#include <dune/gdt/test/momentmodels/basisfunctions.hh> +#include <dune/gdt/test/momentmodels/entropyflux.hh> +#include <dune/gdt/test/momentmodels/kineticequation.hh> + +#include "../kineticequation.hh" + +namespace Dune { +namespace GDT { + + +template <class E, class MomentBasisImp> +class KineticTransportEquationBase : public KineticEquationInterface<E, MomentBasisImp> +{ + using ThisType = KineticTransportEquationBase; + using BaseType = KineticEquationInterface<E, MomentBasisImp>; + +public: + using BaseType::dimDomain; + using BaseType::dimFlux; + using BaseType::dimRange; + using BaseType::dimRangeCols; + using typename BaseType::BasisDomainType; + using typename BaseType::DomainFieldType; + using typename BaseType::DomainType; + using typename BaseType::GenericFluxFunctionType; + using typename BaseType::GenericFunctionType; + using typename BaseType::MatrixType; + using typename BaseType::MomentBasis; + using typename BaseType::RangeFieldType; + using typename BaseType::RangeReturnType; + using typename BaseType::StateType; + + using typename BaseType::BoundaryValueType; + using typename BaseType::FluxType; + using typename BaseType::InitialValueType; + using FluxRangeType = typename FluxType::LocalFunctionType::RangeReturnType; + using DynamicFluxRangeType = typename FluxType::LocalFunctionType::DynamicRangeType; + using FluxJacobianRangeType = typename FluxType::LocalFunctionType::JacobianRangeReturnType; + using DynamicFluxJacobianRangeType = typename FluxType::LocalFunctionType::DynamicJacobianRangeType; + using GenericScalarFunctionType = XT::Functions::GenericFunction<dimFlux, 1, 1, RangeFieldType>; + using ConstantScalarFunctionType = XT::Functions::ConstantFunction<dimFlux, 1, 1, RangeFieldType>; + using BoundaryDistributionType = + std::function<std::function<RangeFieldType(const BasisDomainType&)>(const DomainType&)>; + + using BaseType::default_boundary_cfg; + using BaseType::default_grid_cfg; + + KineticTransportEquationBase(const MomentBasis& basis_functions, + const XT::Common::Configuration& grid_cfg = default_grid_cfg(), + const XT::Common::Configuration& boundary_cfg = default_boundary_cfg(), + const RangeFieldType psi_vac = 5e-9) + : BaseType(basis_functions) + , grid_cfg_(grid_cfg) + , boundary_cfg_(boundary_cfg) + , psi_vac_(psi_vac) + {} + + template <class VectorType> + void solve(const MatrixType& mat, + VectorType& x, + const VectorType& rhs, + const MomentBasisInterface<DomainFieldType, + MomentBasis::dimDomain, + RangeFieldType, + dimRange, + dimRangeCols, + dimFlux, + MomentBasis::entropy>&) const + { + // copy to CommonDenseMatrix as the FieldMatrix copies itself on the stack during solve which may case a + // stackoverflow for large matrices + XT::LA::CommonDenseMatrix<RangeFieldType> xt_la_mat(mat); + XT::LA::CommonDenseVector<RangeFieldType> xt_la_rhs(rhs, 0); + XT::LA::CommonDenseVector<RangeFieldType> xt_la_x(rhs.size()); + XT::LA::solve(xt_la_mat, xt_la_rhs, xt_la_x); + for (size_t ii = 0; ii < xt_la_x.size(); ++ii) + x[ii] = xt_la_x[ii]; + } + + template <class VectorType, size_t refinements> + void solve(const MatrixType& mat, + VectorType& x, + const VectorType& rhs, + const PartialMomentBasis<DomainFieldType, 3, RangeFieldType, refinements, dimRangeCols, 3, 1>&) const + { + const size_t num_blocks = dimRange / 4; + const size_t block_size = 4; + XT::Common::FieldMatrix<RangeFieldType, block_size, block_size> local_mat; + XT::Common::FieldVector<RangeFieldType, block_size> local_x, local_rhs; + for (size_t jj = 0; jj < num_blocks; ++jj) { + const size_t offset = jj * block_size; + // copy to local matrix and vector + for (size_t rr = 0; rr < block_size; ++rr) { + local_rhs[rr] = rhs[offset + rr]; + for (size_t cc = 0; cc < block_size; ++cc) + local_mat[rr][cc] = mat[offset + rr][offset + cc]; + } // rr + local_mat.solve(local_x, local_rhs); + for (size_t rr = 0; rr < block_size; ++rr) + x[offset + rr] = local_x[rr]; + } // jj + } + + // flux matrix A = B M^{-1} with B_{ij} = <v h_i h_j> + std::unique_ptr<FluxType> flux() const override + { + // calculate B row-wise by solving M^{T} A^T = B^T column-wise + auto A = basis_functions_.flux_matrix(); + const auto M_T = basis_functions_.mass_matrix(); // mass matrix is symmetric + // solve + DynamicVector<RangeFieldType> tmp_row(M_T.N(), 0.); + for (size_t dd = 0; dd < dimFlux; ++dd) { + for (size_t ii = 0; ii < M_T.N(); ++ii) { + solve(M_T, tmp_row, A[dd][ii], basis_functions_); + A[dd][ii] = tmp_row; + } + } + auto order_func = [](const XT::Common::Parameter&) -> int { return 1; }; + DynamicVector<XT::LA::CommonDenseMatrix<RangeFieldType>> A_la(dimFlux); + for (size_t dd = 0; dd < dimFlux; ++dd) + A_la[dd] = A[dd]; + auto eval_func = + [A_la](const DomainType&, const StateType& u, DynamicFluxRangeType& ret, const XT::Common::Parameter&) { + for (size_t dd = 0; dd < dimFlux; ++dd) { + auto row_view = ret[dd]; + A_la[dd].mv(u, row_view); + } + }; + auto jacobian_func = + [A_la](const DomainType&, const StateType&, DynamicFluxJacobianRangeType& ret, const XT::Common::Parameter&) { + for (size_t dd = 0; dd < dimFlux; ++dd) + ret[dd] = A_la[dd]; + }; + return std::make_unique<GenericFluxFunctionType>(order_func, + GenericFluxFunctionType::default_post_bind_function(), + eval_func, + XT::Common::ParameterType{}, + "flux", + jacobian_func); + } + + // Initial value of the kinetic equation is a constant vacuum concentration psi_vac. + // Thus, the initial value of the n-th moment is basis_integrated * psi_vac. + std::unique_ptr<InitialValueType> initial_values() const override + { + RangeReturnType value = basis_functions_.integrated() * psi_vac_; + return std::make_unique<GenericFunctionType>( + [](const XT::Common::Parameter&) { return 0; }, + [value](const DomainType&, const XT::Common::Parameter&) { return value; }); + } // ... initial_values() + + // Use a constant vacuum concentration basis_integrated * psi_vac as default boundary value + std::unique_ptr<BoundaryValueType> boundary_values() const override + { + RangeReturnType value = basis_functions_.integrated() * psi_vac_; + return std::make_unique<GenericFunctionType>( + [](const XT::Common::Parameter&) { return 0; }, + [=](const DomainType&, const XT::Common::Parameter&) { return value; }); + } // ... boundary_values() + + virtual BoundaryDistributionType boundary_distribution() const + { + return [this](const DomainType&) { return [this](const BasisDomainType&) { return this->psi_vac_; }; }; + } + + RangeReturnType + kinetic_boundary_flux_from_quadrature(const DomainType& x, const RangeFieldType& n, const size_t dd) const + { + RangeReturnType ret(0.); + const auto boundary_density = boundary_distribution()(x); + const auto& quadratures = basis_functions_.quadratures(); + for (size_t jj = 0; jj < quadratures.size(); ++jj) { + for (size_t ll = 0; ll < quadratures[jj].size(); ++ll) { + const auto v = quadratures[jj][ll].position(); + const auto b = basis_functions_.evaluate(v, jj); + if (v[dd] * n < 0) { + const RangeFieldType psi = boundary_density(v); + ret += b * psi * v[dd] * quadratures[jj][ll].weight(); + } + } // ll + } // jj + return ret; + } + + virtual RangeReturnType kinetic_boundary_flux(const DomainType& x, const RangeFieldType& n, const size_t dd) const + { + return kinetic_boundary_flux_from_quadrature(x, n, dd); + } + + RangeFieldType CFL() const override + { + return 0.49; + } + + RangeFieldType t_end() const override + { + return 1.; + } + + XT::Common::Configuration grid_config() const override + { + return grid_cfg_; + } + + XT::Common::Configuration boundary_config() const override + { + return boundary_cfg_; + } + + static std::string static_id() + { + return "kinetictransportequation"; + } + + virtual const RangeFieldType psi_vac() const + { + return psi_vac_; + } + +protected: + using BaseType::basis_functions_; + const XT::Common::Configuration grid_cfg_; + const XT::Common::Configuration boundary_cfg_; + const RangeFieldType psi_vac_; + XT::Common::ParameterType parameter_type_; +}; // class KineticTransportEquation<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_KINETICTRANSPORTEQUATION_BASE_HH diff --git a/dune/gdt/test/momentmodels/kinetictransport/checkerboard.hh b/dune/gdt/test/momentmodels/kinetictransport/checkerboard.hh new file mode 100644 index 0000000000000000000000000000000000000000..3d8bbf3a7ea7b31c809ece44d4393bdaeace339c --- /dev/null +++ b/dune/gdt/test/momentmodels/kinetictransport/checkerboard.hh @@ -0,0 +1,188 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2016 - 2017) +// Rene Milk (2016 - 2018) +// Tobias Leibner (2016 - 2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_KINETICTRANSPORT_CHECKERBOARD_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_KINETICTRANSPORT_CHECKERBOARD_HH + +#include "base.hh" + +namespace Dune { +namespace GDT { + + +/** + * In 2D, this is the Testcase for the Boltzmann equation in two dimensions, + * see Section 4.2 of Brunner, Holloway, "Two-dimensional time dependent Riemann solvers for neutron transport", Journal + * of Computational Physics, Volume 210, Issue 1, 2005 + * http://dx.doi.org/10.1016/j.jcp.2005.04.011 + * The 3D version is a straightforward generalization of the setup to 3 dimensions. + * */ +template <class E, class MomentBasisImp> +class CheckerboardPn : public KineticTransportEquationBase<E, MomentBasisImp> +{ + using BaseType = KineticTransportEquationBase<E, MomentBasisImp>; + +public: + using BaseType::dimDomain; + using typename BaseType::BoundaryValueType; + using typename BaseType::DomainType; + using typename BaseType::GenericScalarFunctionType; + using typename BaseType::MomentBasis; + using typename BaseType::RangeFieldType; + using typename BaseType::ScalarFunctionType; + + using BaseType::default_boundary_cfg; + + CheckerboardPn(const MomentBasis& basis_functions, + const XT::Common::Configuration& grid_cfg = default_grid_cfg(), + const XT::Common::Configuration& boundary_cfg = default_boundary_cfg()) + : BaseType(basis_functions, grid_cfg, boundary_cfg, 1e-8 / (4 * M_PI)) + {} + + static std::string static_id() + { + size_t domainDim = dimDomain; // avoid linker error for dimDomain + return "checkerboard" + XT::Common::to_string(domainDim) + "d_pn"; + } + + static XT::Common::Configuration default_grid_cfg() + { + XT::Common::Configuration grid_config; + grid_config["type"] = XT::Grid::cube_gridprovider_default_config()["type"]; + grid_config["lower_left"] = "[0.0 0.0 0.0]"; + grid_config["upper_right"] = "[7.0 7.0 7.0]"; + grid_config["num_elements"] = "[14 14 14]"; + grid_config["overlap_size"] = "[1 1 1]"; + return grid_config; + } + + RangeFieldType t_end() const override + { + return 3.2; + } + + // Q = 0 except in the center where Q = 1. sigma_s = sigma_t = 1 in scattering regions, sigma_s = 0, sigma_t + // = 10 in absorbing regions. Center is also a scattering region. + std::unique_ptr<ScalarFunctionType> sigma_a() const override + { + return create_parameter_function(10., 0., 0.); + } + + std::unique_ptr<ScalarFunctionType> sigma_s() const override + { + return create_parameter_function(0., 1., 1.); + } + + std::unique_ptr<ScalarFunctionType> Q() const override + { + return create_parameter_function(0., 0., 1. / std::sqrt(4. * M_PI)); + } + + std::unique_ptr<ScalarFunctionType> create_parameter_function(const RangeFieldType value_on_absorbing_parts, + const RangeFieldType value_on_scattering_parts, + const RangeFieldType value_on_center) const + { + return std::make_unique<GenericScalarFunctionType>([](const XT::Common::Parameter&) { return 0; }, + [=](const DomainType& x, const XT::Common::Parameter&) { + if (is_center(x)) + return value_on_center; + else if (is_absorbing(x)) + return value_on_absorbing_parts; + else + return value_on_scattering_parts; + }); + } + +protected: + static bool is_absorbing(const FieldVector<RangeFieldType, 2>& x) + { + size_t row = XT::Common::numeric_cast<size_t>(std::floor(x[1])); + if (row == 7) + row = 6; + size_t col = XT::Common::numeric_cast<size_t>(std::floor(x[0])); + if (col == 7) + col = 6; + assert(row < 7 && col < 7); + return (row == 1 && col % 2 == 1) || ((row == 2 || row == 4) && (col == 2 || col == 4)) + || ((row == 3 || row == 5) && (col == 1 || col == 5)); + } + + static bool is_absorbing(const FieldVector<RangeFieldType, 3>& x) + { + size_t plane = XT::Common::numeric_cast<size_t>(std::floor(x[2])); + size_t col = XT::Common::numeric_cast<size_t>(std::floor(x[0])); + size_t row = XT::Common::numeric_cast<size_t>(std::floor(x[1])); + assert(plane <= 7 && row <= 7 && col <= 7); + if (plane == 0 || plane >= 6) + return false; + if (row == 0 || row >= 6) + return false; + if (col == 0 || col >= 6) + return false; + return (plane + row + col) % 2 == 1 && !is_center(x) && !(plane == 3 && row == 5 && col == 3); + } + + static bool is_center(const FieldVector<RangeFieldType, 2>& x) + { + size_t row = XT::Common::numeric_cast<size_t>(std::floor(x[1])); + size_t col = XT::Common::numeric_cast<size_t>(std::floor(x[0])); + return row == 3 && col == 3; + } + + static bool is_center(const FieldVector<RangeFieldType, 3>& x) + { + size_t plane = XT::Common::numeric_cast<size_t>(std::floor(x[2])); + size_t row = XT::Common::numeric_cast<size_t>(std::floor(x[1])); + size_t col = XT::Common::numeric_cast<size_t>(std::floor(x[0])); + return plane == 3 && row == 3 && col == 3; + } +}; // class CheckerboardPn<...> + +template <class GV, class MomentBasis> +class CheckerboardMn : public CheckerboardPn<XT::Grid::extract_entity_t<GV>, MomentBasis> +{ + using BaseType = CheckerboardPn<XT::Grid::extract_entity_t<GV>, MomentBasis>; + +public: + using typename BaseType::FluxType; + using ActualFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + + using BaseType::default_boundary_cfg; + using BaseType::default_grid_cfg; + + CheckerboardMn(const MomentBasis& basis_functions, + const GV& grid_view, + const XT::Common::Configuration& grid_cfg = default_grid_cfg(), + const XT::Common::Configuration& boundary_cfg = default_boundary_cfg()) + : BaseType(basis_functions, grid_cfg, boundary_cfg) + , grid_view_(grid_view) + {} + + static std::string static_id() + { + return "checkerboardmn"; + } + + std::unique_ptr<FluxType> flux() const override + { + return std::make_unique<ActualFluxType>(grid_view_, basis_functions_); + } + +protected: + using BaseType::basis_functions_; + const GV& grid_view_; +}; // class CheckerboardMn<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_MOMENTMODELS_KINETICTRANSPORT_CHECKERBOARD_HH diff --git a/dune/gdt/test/momentmodels/kinetictransport/planesource.hh b/dune/gdt/test/momentmodels/kinetictransport/planesource.hh new file mode 100644 index 0000000000000000000000000000000000000000..01906d8e43f53de2a98da736734bd35cc72f4377 --- /dev/null +++ b/dune/gdt/test/momentmodels/kinetictransport/planesource.hh @@ -0,0 +1,153 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_PLANESOURCE_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_PLANESOURCE_HH + +#include "base.hh" + +namespace Dune { +namespace GDT { + + +template <class E, class MomentBasisImp> +class PlaneSourcePn : public KineticTransportEquationBase<E, MomentBasisImp> +{ + using BaseType = KineticTransportEquationBase<E, MomentBasisImp>; + +public: + using BaseType::default_boundary_cfg; + using BaseType::dimDomain; + using BaseType::dimRange; + using typename BaseType::ConstantScalarFunctionType; + using typename BaseType::DomainType; + using typename BaseType::GenericFunctionType; + using typename BaseType::InitialValueType; + using typename BaseType::MomentBasis; + using typename BaseType::RangeFieldType; + using typename BaseType::RangeReturnType; + using typename BaseType::ScalarFunctionType; + + PlaneSourcePn(const MomentBasis& basis_functions, + const XT::Common::Configuration& grid_cfg = default_grid_cfg(), + const XT::Common::Configuration& boundary_cfg = default_boundary_cfg()) + : BaseType(basis_functions, grid_cfg, boundary_cfg) + {} + + static std::string static_id() + { + return "planesourcepn"; + } + + static XT::Common::Configuration default_grid_cfg() + { + XT::Common::Configuration grid_config; + grid_config["type"] = XT::Grid::cube_gridprovider_default_config()["type"]; + grid_config["lower_left"] = "[-1.2]"; + grid_config["upper_right"] = "[1.2]"; + grid_config["num_elements"] = "[240]"; + grid_config["overlap_size"] = "[1]"; + return grid_config; + } + + // Initial value of the kinetic equation is psi_vac + delta(x). + // Thus the initial value for the n-th moment is base_integrated_n * (psi_vac + delta(x)) + std::unique_ptr<InitialValueType> initial_values() const override + { + const DomainType lower_left = XT::Common::from_string<DomainType>(grid_cfg_["lower_left"]); + const DomainType upper_right = XT::Common::from_string<DomainType>(grid_cfg_["upper_right"]); + const size_t num_elements = XT::Common::from_string<std::vector<size_t>>(grid_cfg_["num_elements"])[0]; + const RangeFieldType len_domain = upper_right[0] - lower_left[0]; + const RangeFieldType vol_entity = len_domain / num_elements; + RangeReturnType basis_integrated = basis_functions_.integrated(); + const RangeFieldType domain_center = lower_left[0] + len_domain / 2; + + // approximate delta function by constant value of 1/(2*vol_entity) on cells on both side of 0. + const auto eval_func = [=](const DomainType& x, const XT::Common::Parameter&) { + auto ret = basis_integrated; + if (XT::Common::FloatCmp::ge(x[0], domain_center - vol_entity) + && XT::Common::FloatCmp::le(x[0], domain_center + vol_entity)) + ret *= psi_vac_ + 1. / (2. * vol_entity); + else + ret *= psi_vac_; + return ret; + }; + return std::make_unique<GenericFunctionType>(0, eval_func); + } // ... initial_values() + + RangeFieldType t_end() const override + { + return 1.0; + } + + std::unique_ptr<ScalarFunctionType> sigma_a() const override + { + return std::make_unique<ConstantScalarFunctionType>(0.); + } + + std::unique_ptr<ScalarFunctionType> sigma_s() const override + { + return std::make_unique<ConstantScalarFunctionType>(1.); + } + + std::unique_ptr<ScalarFunctionType> Q() const override + { + return std::make_unique<ConstantScalarFunctionType>(0.); + } + +protected: + using BaseType::basis_functions_; + using BaseType::grid_cfg_; + using BaseType::psi_vac_; +}; // class PlaneSourcePn<...> + + +template <class GV, class MomentBasis> +class PlaneSourceMn : public PlaneSourcePn<XT::Grid::extract_entity_t<GV>, MomentBasis> +{ + using BaseType = PlaneSourcePn<XT::Grid::extract_entity_t<GV>, MomentBasis>; + using ThisType = PlaneSourceMn; + +public: + using typename BaseType::FluxType; + using typename BaseType::RangeReturnType; + using ActualFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + + using BaseType::default_boundary_cfg; + using BaseType::default_grid_cfg; + + PlaneSourceMn(const MomentBasis& basis_functions, + const GV& grid_view, + const XT::Common::Configuration& grid_cfg = default_grid_cfg(), + const XT::Common::Configuration& boundary_cfg = default_boundary_cfg()) + : BaseType(basis_functions, grid_cfg, boundary_cfg) + , grid_view_(grid_view) + {} + + static std::string static_id() + { + return "planesourcemn"; + } + + std::unique_ptr<FluxType> flux() const override + { + return std::make_unique<ActualFluxType>(grid_view_, basis_functions_); + } + +protected: + using BaseType::basis_functions_; + const GV& grid_view_; +}; // class PlaneSourceMn<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_PLANESOURCE_HH diff --git a/dune/gdt/test/momentmodels/kinetictransport/pointsource.hh b/dune/gdt/test/momentmodels/kinetictransport/pointsource.hh new file mode 100644 index 0000000000000000000000000000000000000000..132bf1f7600c1b909124a82f206ca6b7204437e8 --- /dev/null +++ b/dune/gdt/test/momentmodels/kinetictransport/pointsource.hh @@ -0,0 +1,142 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2017) +// Rene Milk (2017 - 2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_POINTSOURCE_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_POINTSOURCE_HH + +#include "base.hh" + +namespace Dune { +namespace GDT { + + +template <class E, class MomentBasisImp> +class PointSourcePn : public KineticTransportEquationBase<E, MomentBasisImp> +{ + using BaseType = KineticTransportEquationBase<E, MomentBasisImp>; + +public: + using BaseType::dimDomain; + using typename BaseType::ConstantScalarFunctionType; + using typename BaseType::DomainType; + using typename BaseType::GenericFunctionType; + using typename BaseType::InitialValueType; + using typename BaseType::MomentBasis; + using typename BaseType::RangeFieldType; + using typename BaseType::RangeReturnType; + using typename BaseType::ScalarFunctionType; + + using BaseType::default_boundary_cfg; + + PointSourcePn(const MomentBasis& basis_functions, + const XT::Common::Configuration& grid_cfg = default_grid_cfg(), + const XT::Common::Configuration& boundary_cfg = default_boundary_cfg()) + : BaseType(basis_functions, grid_cfg, boundary_cfg, 1e-8 / (4 * M_PI)) + {} + + static std::string static_id() + { + return "pointsourcepn"; + } + + static XT::Common::Configuration default_grid_cfg() + { + XT::Common::Configuration grid_config; + grid_config["type"] = XT::Grid::cube_gridprovider_default_config()["type"]; + grid_config["lower_left"] = "[-1 -1 -1]"; + grid_config["upper_right"] = "[1 1 1]"; + grid_config["num_elements"] = "[10 10 10]"; + grid_config["overlap_size"] = "[1 1 1]"; + return grid_config; + } + + // Initial value of the kinetic equation is psi_vac + 1/(4 pi^4 sigma^3) * exp(-||x||^2/(pi*sigma^2)). + std::unique_ptr<InitialValueType> initial_values() const override + { + RangeReturnType basis_integrated = basis_functions_.integrated(); + const auto psi_vac = psi_vac_; + const auto eval_func = [basis_integrated, psi_vac](const DomainType& x, const XT::Common::Parameter&) { + static const auto sigma = 0.03; + static const auto first_factor = 1. / (4 * M_PI * std::pow(M_PI * sigma, 3)); + static const auto second_factor = 1. / (M_PI * std::pow(sigma, 2)); + return basis_integrated * std::max(first_factor * std::exp(-x.two_norm2() * second_factor), psi_vac); + }; + return std::make_unique<GenericFunctionType>(21, eval_func); + } // ... initial_values() + + RangeFieldType t_end() const override + { + return 0.75; + } + + // sigma_a = 0, sigma_s = 1, Q = 0 + std::unique_ptr<ScalarFunctionType> sigma_a() const override + { + return std::make_unique<ConstantScalarFunctionType>(0.); + } + + std::unique_ptr<ScalarFunctionType> sigma_s() const override + { + return std::make_unique<ConstantScalarFunctionType>(1.); + } + + std::unique_ptr<ScalarFunctionType> Q() const override + { + return std::make_unique<ConstantScalarFunctionType>(0.); + } + +protected: + using BaseType::basis_functions_; + using BaseType::grid_cfg_; + using BaseType::psi_vac_; +}; // class PointSourcePn<...> + +template <class GV, class MomentBasis> +class PointSourceMn : public PointSourcePn<XT::Grid::extract_entity_t<GV>, MomentBasis> +{ + using BaseType = PointSourcePn<XT::Grid::extract_entity_t<GV>, MomentBasis>; + using ThisType = PointSourceMn; + +public: + using typename BaseType::FluxType; + using ActualFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + + using BaseType::default_boundary_cfg; + using BaseType::default_grid_cfg; + + PointSourceMn(const MomentBasis& basis_functions, + const GV& grid_view, + const XT::Common::Configuration& grid_cfg = default_grid_cfg(), + const XT::Common::Configuration& boundary_cfg = default_boundary_cfg()) + : BaseType(basis_functions, grid_cfg, boundary_cfg) + , grid_view_(grid_view) + {} + + static std::string static_id() + { + return "pointsourcemn"; + } + + std::unique_ptr<FluxType> flux() const override final + { + return std::make_unique<ActualFluxType>(grid_view_, basis_functions_); + } + +protected: + using BaseType::basis_functions_; + const GV& grid_view_; +}; // class PointSourceMn<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_POINTSOURCE_HH diff --git a/dune/gdt/test/momentmodels/kinetictransport/shadow.hh b/dune/gdt/test/momentmodels/kinetictransport/shadow.hh new file mode 100644 index 0000000000000000000000000000000000000000..a1d0301a08f2faf32b9489d8004562a6eace9bfe --- /dev/null +++ b/dune/gdt/test/momentmodels/kinetictransport/shadow.hh @@ -0,0 +1,150 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Felix Schindler (2016) +// Tobias Leibner (2016) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_SHADOW_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_SHADOW_HH + +#include "base.hh" + +namespace Dune { +namespace GDT { + + +template <class E, class MomentBasisImp> +class ShadowPn : public KineticTransportEquationBase<E, MomentBasisImp> +{ + using BaseType = KineticTransportEquationBase<E, MomentBasisImp>; + +public: + using typename BaseType::BoundaryValueType; + using typename BaseType::ConstantScalarFunctionType; + using typename BaseType::DomainType; + using typename BaseType::GenericFunctionType; + using typename BaseType::GenericScalarFunctionType; + using typename BaseType::MomentBasis; + using typename BaseType::RangeFieldType; + using typename BaseType::ScalarFunctionType; + + using BaseType::default_boundary_cfg; + + ShadowPn(const MomentBasis& basis_functions, + const XT::Common::Configuration& grid_cfg = default_grid_cfg(), + const XT::Common::Configuration& boundary_cfg = default_boundary_cfg()) + : BaseType(basis_functions, grid_cfg, boundary_cfg, 1e-8 / (4 * M_PI)) + {} + + static std::string static_id() + { + return "Shadowpn"; + } + + static XT::Common::Configuration default_grid_cfg() + { + XT::Common::Configuration grid_config; + grid_config["type"] = XT::Grid::cube_gridprovider_default_config()["type"]; + grid_config["lower_left"] = "[0 0 0]"; + grid_config["upper_right"] = "[12 4 3]"; + grid_config["num_elements"] = "[4 4 4]"; + grid_config["overlap_size"] = "[1 1 1]"; + return grid_config; + } + + RangeFieldType t_end() const override + { + return 20; + } + + // sigma_a = 50 on [2,3]x[1,3]x[0,2], sigma_s = 0, Q = 0 + std::unique_ptr<ScalarFunctionType> sigma_a() const override + { + return std::make_unique<GenericScalarFunctionType>(0, [=](const DomainType& x, const XT::Common::Parameter&) { + return (x[0] < 2 || x[0] > 3 || x[1] < 1 || x[1] > 3 || x[2] < 0 || x[2] > 2) ? 0. : 50.; + }); + } + + std::unique_ptr<ScalarFunctionType> sigma_s() const override + { + return std::make_unique<ConstantScalarFunctionType>(0.); + } + + std::unique_ptr<ScalarFunctionType> Q() const override + { + return std::make_unique<ConstantScalarFunctionType>(0.); + } + +#define USE_DIRAC_BOUNDARY 0 + // Boundary value of kinetic equation is either \dirac(v - (1, 0, 0)) or an isotropic beam with density 2, + // i.e. 2/(4 pi), at x = 0 and psi_vac else + std::unique_ptr<BoundaryValueType> boundary_values() const override final + { + auto basis_integrated = basis_functions_.integrated(); + const auto psi_vac = psi_vac_; + return std::make_unique<GenericFunctionType>( + 0, [basis_integrated, psi_vac](const DomainType& x, const XT::Common::Parameter&) { + auto ret = basis_integrated; + ret *= psi_vac; + // left boundary + if (XT::Common::FloatCmp::eq(x[0], 0.)) { +#if USE_DIRAC_BOUNDARY + auto dirac_integrated = basis_functions_.integrate_dirac_at(DomainType{1, 0, 0}); + ret += dirac_integrated; +#else // USE_DIRAC_BOUNDARY + ret += basis_integrated * 2. / (4 * M_PI); +#endif // USE_DIRAC_BOUNDARY + } + return ret; + }); + } // ... boundary_values() + +protected: + using BaseType::basis_functions_; + using BaseType::grid_cfg_; + using BaseType::psi_vac_; +}; // class ShadowPn<...> + +template <class GV, class MomentBasis> +class ShadowMn : public ShadowPn<XT::Grid::extract_entity_t<GV>, MomentBasis> +{ + using BaseType = ShadowPn<XT::Grid::extract_entity_t<GV>, MomentBasis>; + using ThisType = ShadowMn; + +public: + using typename BaseType::FluxType; + using ActualFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + + using BaseType::default_boundary_cfg; + using BaseType::default_grid_cfg; + + ShadowMn(const MomentBasis& basis_functions, + const GV& grid_view, + const XT::Common::Configuration& grid_cfg = default_grid_cfg(), + const XT::Common::Configuration& boundary_cfg = default_boundary_cfg()) + : BaseType(basis_functions, grid_cfg, boundary_cfg) + , grid_view_(grid_view) + {} + + static std::string static_id() + { + return "Shadowmn"; + } + + std::unique_ptr<FluxType> flux() const override + { + return std::make_unique<ActualFluxType>(grid_view_, basis_functions_); + } + +protected: + using BaseType::basis_functions_; + const GV& grid_view_; +}; // class ShadowMn<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_SHADOW_HH diff --git a/dune/gdt/test/momentmodels/kinetictransport/sourcebeam.hh b/dune/gdt/test/momentmodels/kinetictransport/sourcebeam.hh new file mode 100644 index 0000000000000000000000000000000000000000..184277d80b73614dd4d51d233de4eaa14abc2ee4 --- /dev/null +++ b/dune/gdt/test/momentmodels/kinetictransport/sourcebeam.hh @@ -0,0 +1,407 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2016 - 2017) +// Rene Milk (2016 - 2018) +// Tobias Leibner (2016 - 2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_SOURCEBEAM_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_SOURCEBEAM_HH + +#include <cmath> +#include <memory> +#include <vector> +#include <string> + +#include <dune/xt/common/string.hh> +#include <dune/xt/common/math.hh> + +#include <dune/xt/la/eigen-solver.hh> + +#include "base.hh" + +namespace Dune { +namespace GDT { + + +template <class E, class MomentBasisImp> +class SourceBeamPn : public KineticTransportEquationBase<E, MomentBasisImp> +{ + using BaseType = KineticTransportEquationBase<E, MomentBasisImp>; + using ThisType = SourceBeamPn; + +public: + using BaseType::dimDomain; + using BaseType::dimRange; + using typename BaseType::BoundaryDistributionType; + using typename BaseType::BoundaryValueType; + using typename BaseType::DomainFieldType; + using typename BaseType::DomainType; + using typename BaseType::DynamicRangeType; + using typename BaseType::FluxType; + using typename BaseType::GenericFunctionType; + using typename BaseType::GenericScalarFunctionType; + using typename BaseType::MomentBasis; + using typename BaseType::RangeFieldType; + using typename BaseType::RangeReturnType; + using typename BaseType::ScalarFunctionType; + + using BaseType::default_boundary_cfg; + + SourceBeamPn(const MomentBasis& basis_functions, + const XT::Common::Configuration& grid_cfg = default_grid_cfg(), + const XT::Common::Configuration& boundary_cfg = default_boundary_cfg(), + const bool is_mn_model = false) + : BaseType(basis_functions, grid_cfg, boundary_cfg) + , is_mn_model_(is_mn_model) + {} + + static std::string static_id() + { + return "sourcebeampn"; + } + + static XT::Common::Configuration default_grid_cfg() + { + XT::Common::Configuration grid_config; + grid_config["type"] = XT::Grid::cube_gridprovider_default_config()["type"]; + grid_config["lower_left"] = "[0.0]"; + grid_config["upper_right"] = "[3.0]"; + grid_config["num_elements"] = "[300]"; + grid_config["overlap_size"] = "[2]"; + return grid_config; + } + + // Boundary value of kinetic equation is \frac{g}{<g>} at x = 0 and + // \psi_{vac} = 0.5*10^(-8) at x = 3, with g(v) = exp(-10^5(v-1)^2), so n-th component of boundary value has to be + // \frac{<base_n(v)*g(v)>}{<g>} at x = 0 and \psi_{vac}*base_integrated_n + // at x = 3. + std::unique_ptr<BoundaryValueType> boundary_values() const override final + { + return std::make_unique<GenericFunctionType>(1, [&](const DomainType& x, const XT::Common::Parameter&) { + if (x[0] < 1.5) { + static auto ret = helper<MomentBasis>::get_left_boundary_values(basis_functions_, psi_vac_, is_mn_model_); + return ret; + } else { + auto ret = basis_functions_.integrated(); + ret *= psi_vac_; + return ret; + } + }); + } // ... boundary_values() + + BoundaryDistributionType boundary_distribution() const override final + { + return [this](const DomainType& x) -> std::function<RangeFieldType(const DomainType&)> { + if (x[0] > 1.5) + return [this](const DomainType& /*v*/) { return this->psi_vac_; }; + else + return [this](const DomainType& v) { + const RangeFieldType val = std::exp(-1e5 * std::pow(v[0] - 1., 2)); + return (val > this->psi_vac_) ? val : this->psi_vac_; + }; + }; + } + + virtual RangeReturnType + kinetic_boundary_flux(const DomainType& x, const RangeFieldType& n, const size_t dd) const override final + { + return helper<MomentBasis>::get_kinetic_boundary_flux(basis_functions_, psi_vac_, is_mn_model_, x, n, dd, *this); + } + + RangeReturnType left_boundary_value() const + { + return helper<MomentBasis>::get_left_boundary_values(basis_functions_, psi_vac_, is_mn_model_); + } + + RangeFieldType t_end() const override + { + return 2.5; + } + + // sigma_a = 1 if x <= 2, 0 else + std::unique_ptr<ScalarFunctionType> sigma_a() const override + { + return std::make_unique<GenericScalarFunctionType>( + 0, [](const DomainType& x, const XT::Common::Parameter&) { return x[0] > 2 ? 0. : 1.; }); + } + + // sigma_s = 0 if x <= 1, 2 if 1 < x <= 2, 10 else + std::unique_ptr<ScalarFunctionType> sigma_s() const override + { + return std::make_unique<GenericScalarFunctionType>(0, [](const DomainType& x, const XT::Common::Parameter&) { + if (x[0] > 2) + return 10.; + else if (x[0] > 1) + return 2.; + else + return 0.; + }); + } + + // Q = 0.5 if 1 <= x <= 1.5, 0 else + std::unique_ptr<ScalarFunctionType> Q() const override + { + return std::make_unique<GenericScalarFunctionType>( + 0, [](const DomainType& x, const XT::Common::Parameter&) { return x[0] < 1 || x[0] > 1.5 ? 0. : 0.5; }); + } + +protected: + struct helper_base + { + // returns the numerator g of the left boundary value (see create_boundary_values) + static RangeFieldType g(const RangeFieldType v) + { + return std::exp(-1e5 * (v - 1) * (v - 1)); + } + + static RangeFieldType dg(const RangeFieldType v) + { + return -2e5 * (v - 1) * g(v); + } + + // returns the denominator <g> of the left boundary value (see create_boundary_values) + static RangeFieldType denominator() + { + static RangeFieldType ret = 1 / 200. * std::sqrt(M_PI / 10) * std::erf(200 * std::sqrt(10)); + return ret; + } + + // calculates integral from v_l to v_u of numerator g + static RangeFieldType integral_1(RangeFieldType v_l, RangeFieldType v_u) + { + return 1 / 200. * std::sqrt(M_PI / 10) + * (std::erf(100 * std::sqrt(10) * (v_u - 1)) - std::erf(100 * std::sqrt(10) * (v_l - 1))); + } + + // calculates integral from v_l to v_u of v*g + static RangeFieldType integral_2(RangeFieldType v_l, RangeFieldType v_u) + { + return integral_1(v_l, v_u) - 1. / 2e5 * (g(v_u) - g(v_l)); + } + + // calculates integral from v_l to v_u of v^2*g + static RangeFieldType integral_3(RangeFieldType v_l, RangeFieldType v_u) + { + return 0.25e-10 * (dg(v_u) - dg(v_l)) + 2. * integral_2(v_l, v_u) + (0.5e-5 - 1.) * integral_1(v_l, v_u); + } + }; + + + template <class B, class anything = void> + struct helper : public helper_base + { + using helper_base::denominator; + using helper_base::g; + + static DynamicRangeType get_left_boundary_values(const MomentBasisImp& basis_functions, + const RangeFieldType& psi_vac, + const bool is_mn_model) + { + DynamicRangeType ret(dimRange, 0); + // For the MN-Models, we have to use the quadrature also used in the optimization problem to guarantee + // realizability of the boundary_values. + // For the PN-Models, we do not have these issues and just use a very fine quadrature (which is not a performance + // problem as the integration is only done once). + const auto& quadratures = + is_mn_model ? basis_functions.quadratures() : MomentBasisImp::gauss_lobatto_quadratures(100, 31); + for (size_t ii = 0; ii < quadratures.size(); ++ii) { + const auto& quadrature = quadratures[ii]; + for (const auto& quad_point : quadrature) { + const auto& v = quad_point.position()[0]; + auto summand = basis_functions.evaluate(v, ii); + summand *= g(v) * quad_point.weight(); + ret += summand; + } + } + ret /= denominator(); + // add small vacuum concentration to move away from realizable boundary + ret += basis_functions.integrated() * psi_vac; + return ret; + } + + static DynamicRangeType get_kinetic_boundary_flux(const MomentBasisImp& /*basis_functions*/, + const RangeFieldType& /*psi_vac*/, + const bool /*is_mn_model*/, + const DomainType& x, + const RangeFieldType& n, + const size_t dd, + const ThisType& problem) + { + return problem.kinetic_boundary_flux_from_quadrature(x, n, dd); + } + }; + + template <class anything, EntropyType entropy> + struct helper<HatFunctionMomentBasis<DomainFieldType, dimDomain, RangeFieldType, dimRange, 1, 1, entropy>, anything> + : public helper_base + { + using helper_base::denominator; + using helper_base::g; + using helper_base::integral_1; + using helper_base::integral_2; + using helper_base::integral_3; + + static DynamicRangeType get_left_boundary_values(const MomentBasisImp& basis_functions, + const RangeFieldType psi_vac, + const bool /*is_mn_model*/) + { + DynamicRangeType ret(dimRange, 0); + for (size_t nn = 0; nn < dimRange; ++nn) { + const auto& partitioning = basis_functions.partitioning(); + const auto vn = partitioning[nn]; + if (nn < dimRange - 1) { + const auto vnp = partitioning[nn + 1]; + ret[nn] += 1. / ((vn - vnp) * denominator()) * (integral_2(vn, vnp) - vnp * integral_1(vn, vnp)); + } + if (nn > 0) { + const auto vnm = partitioning[nn - 1]; + ret[nn] += 1. / ((vn - vnm) * denominator()) * (integral_2(vnm, vn) - vnm * integral_1(vnm, vn)); + } + } + // add small vacuum concentration to move away from realizable boundary + ret += basis_functions.integrated() * psi_vac; + return ret; + } // ... get_left_boundary_values(...) + + static DynamicRangeType get_kinetic_boundary_flux(const MomentBasisImp& basis_functions, + const RangeFieldType& /*psi_vac*/, + const bool is_mn_model, + const DomainType& x, + const RangeFieldType& n, + const size_t dd, + const ThisType& problem) + { + if (!is_mn_model) + DUNE_THROW(Dune::NotImplemented, "Only implemented for mn"); + if (x < 1.5) { + DynamicRangeType ret(dimRange, 0.); + const auto& partitioning = basis_functions.partitioning(); + for (size_t nn = 0; nn < dimRange; ++nn) { + const auto vn = partitioning[nn]; + if (nn < dimRange - 1) { + const auto vnp = partitioning[nn + 1]; + if (vnp > 0.) { + const auto left_limit = vn > 0. ? vn : 0.; + ret[nn] += + 1. / ((vn - vnp) * denominator()) * (integral_3(left_limit, vnp) - vnp * integral_2(left_limit, vnp)); + } // if (vnp > 0.) + } // if (nn < dimRange -1) + if (vn > 0.) { + if (nn > 0) { + const auto vnm = partitioning[nn - 1]; + const auto left_limit = vnm > 0. ? vnm : 0.; + ret[nn] += + 1. / ((vn - vnm) * denominator()) * (integral_2(left_limit, vn) - vnm * integral_1(left_limit, vn)); + } // if (nn > 0) + } // if (vn > 0.) + } // nn + return ret; + } else { + return problem.kinetic_boundary_flux_from_quadrature(x, n, dd); + } + } // ... get_kinetic_boundary_flux(...) + }; + + template <class anything, EntropyType entropy> + struct helper<PartialMomentBasis<DomainFieldType, dimDomain, RangeFieldType, dimRange, 1, 1, 1, entropy>, anything> + : public helper_base + { + using helper_base::denominator; + using helper_base::integral_1; + using helper_base::integral_2; + using helper_base::integral_3; + + static DynamicRangeType get_left_boundary_values(const MomentBasisImp& basis_functions, + const RangeFieldType psi_vac, + const bool /*is_mn_model*/) + { + const auto& partitioning = basis_functions.partitioning(); + DynamicRangeType ret(dimRange, 0); + for (size_t ii = 0; ii < dimRange / 2; ++ii) { + ret[2 * ii] = integral_1(partitioning[ii], partitioning[ii + 1]) / denominator(); + ret[2 * ii + 1] = integral_2(partitioning[ii], partitioning[ii + 1]) / denominator(); + } + // add small vacuum concentration to move away from realizable boundary + ret += basis_functions.integrated() * psi_vac; + return ret; + } + + static DynamicRangeType get_kinetic_boundary_flux(const MomentBasisImp& basis_functions, + const RangeFieldType& /*psi_vac*/, + const bool is_mn_model, + const DomainType& x, + const RangeFieldType& n, + const size_t dd, + const ThisType& problem) + { + if (!is_mn_model) + DUNE_THROW(Dune::NotImplemented, "Only implemented for mn"); + if (x < 1.5) { + const auto& partitioning = basis_functions.partitioning(); + DynamicRangeType ret(dimRange, 0.); + for (size_t ii = 0; ii < dimRange / 2; ++ii) { + if (partitioning[ii + 1] > 0.) { + const auto left_limit = partitioning[ii] > 0. ? partitioning[ii] : 0.; + ret[2 * ii] = integral_2(left_limit, partitioning[ii + 1]) / denominator(); + ret[2 * ii + 1] = integral_3(left_limit, partitioning[ii + 1]) / denominator(); + } + } // ii + return ret; + } else { + return problem.kinetic_boundary_flux_from_quadrature(x, n, dd); + } + } // ... get_kinetic_boundary_flux(...) + }; + + using BaseType::basis_functions_; + using BaseType::psi_vac_; + const bool is_mn_model_; +}; // class SourceBeamPn<...> + +template <class GV, class MomentBasis> +class SourceBeamMn : public SourceBeamPn<XT::Grid::extract_entity_t<GV>, MomentBasis> +{ + using BaseType = SourceBeamPn<XT::Grid::extract_entity_t<GV>, MomentBasis>; + using ThisType = SourceBeamMn; + +public: + using typename BaseType::FluxType; + using typename BaseType::RangeReturnType; + using ActualFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + + using BaseType::default_boundary_cfg; + using BaseType::default_grid_cfg; + + SourceBeamMn(const MomentBasis& basis_functions, + const GV& grid_view, + const XT::Common::Configuration& grid_cfg = default_grid_cfg(), + const XT::Common::Configuration& boundary_cfg = default_boundary_cfg()) + : BaseType(basis_functions, grid_cfg, boundary_cfg, true) + , grid_view_(grid_view) + {} + + static std::string static_id() + { + return "sourcebeammn"; + } + + std::unique_ptr<FluxType> flux() const override + { + return std::make_unique<ActualFluxType>(grid_view_, basis_functions_); + } + +protected: + using BaseType::basis_functions_; + const GV& grid_view_; +}; // class SourceBeamMn<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_SOURCEBEAM_HH diff --git a/dune/gdt/test/momentmodels/kinetictransport/testcases.hh b/dune/gdt/test/momentmodels/kinetictransport/testcases.hh new file mode 100644 index 0000000000000000000000000000000000000000..f16229a02abd021ac0eda054f83b60b15e16b604 --- /dev/null +++ b/dune/gdt/test/momentmodels/kinetictransport/testcases.hh @@ -0,0 +1,882 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_HYPERBOLIC_PROBLEMS_KINETICTRANSPORT_TESTCASES_HH +#define DUNE_GDT_HYPERBOLIC_PROBLEMS_KINETICTRANSPORT_TESTCASES_HH + +#include <dune/grid/yaspgrid.hh> + +#include <dune/gdt/test/momentmodels/basisfunctions.hh> +#include <dune/gdt/spaces/l2/finite-volume.hh> +#include <dune/gdt/spaces/l2/discontinuous-lagrange.hh> +#include <dune/gdt/tools/timestepper/interface.hh> +#include <dune/gdt/operators/reconstruction/slopes.hh> + +#include "checkerboard.hh" +#include "planesource.hh" +#include "pointsource.hh" +#include "shadow.hh" +#include "sourcebeam.hh" + +namespace Dune { +namespace GDT { + + +// choose Quadrature suitable for MomentBasisImp +template <class MomentBasisImp> +struct QuadratureChooser; + +template <size_t order, EntropyType entropy> +struct QuadratureChooser<LegendreMomentBasis<double, double, order, 1, entropy>> +{ + static constexpr size_t quad_order = 54; + static constexpr size_t quad_refinements = 1; +}; + +template <size_t dimRange, EntropyType entropy> +struct QuadratureChooser<HatFunctionMomentBasis<double, 1, double, dimRange, 1, 1, entropy>> +{ + static constexpr size_t quad_order = 15; + static constexpr size_t quad_refinements = 0; +}; + +template <size_t dimRange, EntropyType entropy> +struct QuadratureChooser<PartialMomentBasis<double, 1, double, dimRange, 1, 1, 1, entropy>> +{ + static constexpr size_t quad_order = 15; + static constexpr size_t quad_refinements = 0; +}; + +template <size_t order, EntropyType entropy> +struct QuadratureChooser<RealSphericalHarmonicsMomentBasis<double, double, order, 3, false, entropy>> +{ + static constexpr size_t quad_order = 2 * order + 8; + static constexpr size_t quad_refinements = 0; +}; + +template <size_t refinements, EntropyType entropy> +struct QuadratureChooser<HatFunctionMomentBasis<double, 3, double, refinements, 1, 3, entropy>> +{ + static constexpr size_t quad_order = refinements == 0 ? 18 /*fekete rule number 7*/ : 9 /*fekete rule number 3*/; + static constexpr size_t quad_refinements = 0; +}; + +template <size_t refinements, EntropyType entropy> +struct QuadratureChooser<PartialMomentBasis<double, 3, double, refinements, 1, 3, 1, entropy>> +{ + static constexpr size_t quad_order = refinements == 0 ? 18 /*fekete rule number 7*/ : 9 /*fekete rule number 3*/; + static constexpr size_t quad_refinements = 0; +}; + + +// choose RealizabilityLimiter suitable for MomentBasisImp +template <class GV, class MomentBasisImp, class AnalyticalFluxType, class DiscreteFunctionType> +struct RealizabilityLimiterChooser; + +#if HAVE_CLP +template <class GV, size_t order, class AnalyticalFluxType, class DiscreteFunctionType, EntropyType entropy> +struct RealizabilityLimiterChooser<GV, + LegendreMomentBasis<double, double, order, 1, entropy>, + AnalyticalFluxType, + DiscreteFunctionType> +{ + using MomentBasis = LegendreMomentBasis<double, double, order, 1, entropy>; + using EntropyFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + + template <class EigenVectorWrapperType> + static std::unique_ptr<LpConvexhullRealizabilityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>> + make_slope(const EntropyFluxType& entropy_flux, const MomentBasis& basis_functions, const double epsilon) + { + using SlopeType = LpConvexhullRealizabilityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>; + return std::make_unique<SlopeType>(entropy_flux, basis_functions, epsilon); + } +}; +#endif + +#ifndef USE_LP_POSITIVITY_LIMITER +# define USE_LP_POSITIVITY_LIMITER 0 +#endif // USE_LP_POSITIVITY_LIMITER +template <class GV, size_t dimRange, class AnalyticalFluxType, class DiscreteFunctionType, EntropyType entropy> +struct RealizabilityLimiterChooser<GV, + HatFunctionMomentBasis<double, 1, double, dimRange, 1, 1, entropy>, + AnalyticalFluxType, + DiscreteFunctionType> +{ + using MomentBasis = HatFunctionMomentBasis<double, 1, double, dimRange, 1, 1, entropy>; + using EntropyFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + +#if HAVE_CLP && USE_LP_POSITIVITY_LIMITER + template <class EigenVectorWrapperType> + static std::unique_ptr<LpPositivityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>> + make_slope(const EntropyFluxType& entropy_flux, const MomentBasis& /*basis_functions*/, const double epsilon) + { + using SlopeType = LpPositivityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>; + return std::make_unique<SlopeType>(entropy_flux, epsilon); + } +#else // HAVE_CLP + template <class EigenVectorWrapperType> + static std::unique_ptr<PositivityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>> + make_slope(const EntropyFluxType& entropy_flux, const MomentBasis& /*basis_functions*/, const double epsilon) + { + using SlopeType = PositivityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>; + return std::make_unique<SlopeType>(entropy_flux, epsilon); + } +#endif // HAVE_CLP +}; + +template <class GV, size_t dimRange, class AnalyticalFluxType, class DiscreteFunctionType, EntropyType entropy> +struct RealizabilityLimiterChooser<GV, + PartialMomentBasis<double, 1, double, dimRange, 1, 1, 1, entropy>, + AnalyticalFluxType, + DiscreteFunctionType> +{ + using MomentBasis = PartialMomentBasis<double, 1, double, dimRange, 1, 1, 1, entropy>; + using EntropyFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + + template <class EigenVectorWrapperType> + static std::unique_ptr<Dg1dRealizabilityLimitedSlope<GV, double, dimRange, EigenVectorWrapperType, entropy>> + make_slope(const EntropyFluxType& entropy_flux, const MomentBasis& basis_functions, const double epsilon) + { + using SlopeType = Dg1dRealizabilityLimitedSlope<GV, double, dimRange, EigenVectorWrapperType, entropy>; + return std::make_unique<SlopeType>(entropy_flux, basis_functions, epsilon); + } +}; + +#if HAVE_CLP +template <class GV, size_t order, class AnalyticalFluxType, class DiscreteFunctionType, EntropyType entropy> +struct RealizabilityLimiterChooser<GV, + RealSphericalHarmonicsMomentBasis<double, double, order, 3, false, entropy>, + AnalyticalFluxType, + DiscreteFunctionType> +{ + using MomentBasis = RealSphericalHarmonicsMomentBasis<double, double, order, 3, false, entropy>; + using EntropyFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + + template <class EigenVectorWrapperType> + static std::unique_ptr<LpConvexhullRealizabilityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>> + make_slope(const EntropyFluxType& entropy_flux, const MomentBasis& basis_functions, const double epsilon) + { + using SlopeType = LpConvexhullRealizabilityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>; + return std::make_unique<SlopeType>(entropy_flux, basis_functions, epsilon); + } +}; +#endif + +template <class GV, size_t refinements, class AnalyticalFluxType, class DiscreteFunctionType, EntropyType entropy> +struct RealizabilityLimiterChooser<GV, + HatFunctionMomentBasis<double, 3, double, refinements, 1, 3, entropy>, + AnalyticalFluxType, + DiscreteFunctionType> +{ + using MomentBasis = HatFunctionMomentBasis<double, 3, double, refinements, 1, 3, entropy>; + using EntropyFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + +#if HAVE_CLP && USE_LP_POSITIVITY_LIMITER + template <class EigenVectorWrapperType> + static std::unique_ptr<LpPositivityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>> + make_slope(const EntropyFluxType& entropy_flux, const MomentBasis& /*basis_functions*/, const double epsilon) + { + using SlopeType = LpPositivityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>; + return std::make_unique<SlopeType>(entropy_flux, epsilon); + } +#else // HAVE_CLP + template <class EigenVectorWrapperType> + static std::unique_ptr<PositivityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>> + make_slope(const EntropyFluxType& entropy_flux, const MomentBasis& /*basis_functions*/, const double epsilon) + { + using SlopeType = PositivityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>; + return std::make_unique<SlopeType>(entropy_flux, epsilon); + } +#endif // HAVE_CLP +}; + +#if HAVE_QHULL +template <class GV, size_t refinements, class AnalyticalFluxType, class DiscreteFunctionType, EntropyType entropy> +struct RealizabilityLimiterChooser<GV, + PartialMomentBasis<double, 3, double, refinements, 1, 3, 1, entropy>, + AnalyticalFluxType, + DiscreteFunctionType> +{ + using MomentBasis = PartialMomentBasis<double, 3, double, refinements, 1, 3, 1, entropy>; + using EntropyFluxType = EntropyBasedFluxFunction<GV, MomentBasis>; + + template <class EigenVectorWrapperType> + static std::unique_ptr<DgConvexHullRealizabilityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>> + make_slope(const EntropyFluxType& entropy_flux, const MomentBasis& basis_functions, const double epsilon) + { + using SlopeType = DgConvexHullRealizabilityLimitedSlope<GV, MomentBasis, EigenVectorWrapperType>; + return std::make_unique<SlopeType>(entropy_flux, basis_functions, epsilon); + } +}; +#endif // HAVE_QHULL + +// SourceBeam Pn +template <class MomentBasisImp, bool reconstruct> +struct SourceBeamPnExpectedResults; + +template <bool reconstruct> +struct SourceBeamPnExpectedResults<LegendreMomentBasis<double, double, 7>, reconstruct> +{ + static constexpr double l1norm = reconstruct ? 0.33066818456325309 : 0.33107004463414219; + static constexpr double l2norm = reconstruct ? 0.46157514055648202 : 0.44609169128864046; + static constexpr double linfnorm = reconstruct ? 1.1553979882432905 : 1.0882801946666183; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct SourceBeamPnExpectedResults<HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, reconstruct> +{ + static constexpr double l1norm = reconstruct ? 0.33146057542497681 : 0.33146794280840425; + static constexpr double l2norm = reconstruct ? 0.46411980559363358 : 0.44913032300780292; + static constexpr double linfnorm = reconstruct ? 0.98904667015384473 : 0.98709215129457029; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct SourceBeamPnExpectedResults<PartialMomentBasis<double, 1, double, 8, 1, 1>, reconstruct> +{ + static constexpr double l1norm = reconstruct ? 0.33140398337610927 : 0.33140398337603194; + static constexpr double l2norm = reconstruct ? 0.47294828933204164 : 0.45667075585121392; + static constexpr double linfnorm = reconstruct ? 1.0490804598503625 : 0.99004736850989217; + static constexpr double tol = 1e-9; +}; + +template <class GridImp, class MomentBasisImp, bool reconstruct> +struct SourceBeamPnTestCase +{ + using MomentBasis = MomentBasisImp; + static constexpr size_t dimDomain = MomentBasis::dimDomain; + static constexpr size_t dimRange = MomentBasis::dimRange; + using DomainFieldType = typename MomentBasis::DomainFieldType; + using RangeFieldType = typename MomentBasis::RangeFieldType; + using GridType = GridImp; + using GridViewType = typename GridType::LeafGridView; + using E = XT::Grid::extract_entity_t<GridViewType>; + using SpaceType = FiniteVolumeSpace<GridViewType, dimRange, 1, RangeFieldType>; + using AdvectionSourceSpaceType = + std::conditional_t<reconstruct, DiscontinuousLagrangeSpace<GridViewType, dimRange, RangeFieldType>, SpaceType>; + using VectorType = typename Dune::XT::LA::Container<RangeFieldType, Dune::XT::LA::default_backend>::VectorType; + using DiscreteFunctionType = DiscreteFunction<VectorType, GridViewType, dimRange, 1, RangeFieldType>; + using ProblemType = SourceBeamPn<E, MomentBasis>; + static constexpr RangeFieldType t_end = 0.25; + static constexpr bool reconstruction = reconstruct; + using ExpectedResultsType = SourceBeamPnExpectedResults<MomentBasisImp, reconstruction>; +}; + + +// SourceBeam Mn +template <class MomentBasisImp, bool reconstruct, bool kinetic_scheme = false> +struct SourceBeamMnExpectedResults +{ + static constexpr double l1norm = 0.; + static constexpr double l2norm = 0.; + static constexpr double linfnorm = 0.; + static constexpr double tol = 1e-15; +}; + +template <bool reconstruct, bool kinetic_scheme> +struct SourceBeamMnExpectedResults<LegendreMomentBasis<double, double, 7>, reconstruct, kinetic_scheme> +{ + static constexpr double l1norm = reconstruct ? 0.28535354296013105 : 0.28535354295945792; + static constexpr double l2norm = reconstruct ? 0.37115145999473981 : 0.36265752973701221; + static constexpr double linfnorm = reconstruct ? 0.78506610334488358 : 0.78315544039143314; + static constexpr double tol = 1e-5; +}; + +template <bool reconstruct, bool kinetic_scheme> +struct SourceBeamMnExpectedResults<LegendreMomentBasis<double, double, 7, 1, EntropyType::BoseEinstein>, + reconstruct, + kinetic_scheme> +{ + static constexpr double l1norm = reconstruct ? 0.28535354297901544 : 0.28535354297288812; + static constexpr double l2norm = reconstruct ? 0.37115153411073604 : 0.362657577171562; + static constexpr double linfnorm = reconstruct ? 0.78506610330723181 : 0.78315544052307973; + static constexpr double tol = 1e-5; +}; + +template <bool reconstruct> +struct SourceBeamMnExpectedResults<HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, reconstruct, false> +{ + static constexpr double l1norm = reconstruct ? 0.33140398330545301 : 0.33140398330533227; + static constexpr double l2norm = reconstruct ? 0.45584140597017353 : 0.44485191601010715; + static constexpr double linfnorm = reconstruct ? 0.99172197084890834 : 0.98930925210045084; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct SourceBeamMnExpectedResults<HatFunctionMomentBasis<double, 1, double, 8, 1, 1, EntropyType::BoseEinstein>, + reconstruct, + false> +{ + static constexpr double l1norm = reconstruct ? 0.33140398337940113 : 0.33140398338096477; + static constexpr double l2norm = reconstruct ? 0.45580284843165519 : 0.44483205570831974; + static constexpr double linfnorm = reconstruct ? 0.99172119511603896 : 0.98930804287194951; + static constexpr double tol = 1e-9; +}; + + +template <bool reconstruct> +struct SourceBeamMnExpectedResults<HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, reconstruct, true> +{ + static constexpr double l1norm = reconstruct ? 371.54588397717055 : 367.97988291905477; + static constexpr double l2norm = reconstruct ? 236.4476851910448 : 235.54814675091959; + static constexpr double linfnorm = reconstruct ? 210.63369526083264 : 208.81107020771216; + static constexpr double tol = 1e-5; +}; + +template <bool reconstruct> +struct SourceBeamMnExpectedResults<PartialMomentBasis<double, 1, double, 8, 1, 1>, reconstruct, false> +{ + static constexpr double l1norm = reconstruct ? 0.33140398337368543 : 0.3314039833756291; + static constexpr double l2norm = reconstruct ? 0.45583354074069732 : 0.44484887610818585; + static constexpr double linfnorm = reconstruct ? 0.99172184304625632 : 0.98930905293056492; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct SourceBeamMnExpectedResults<PartialMomentBasis<double, 1, double, 8, 1, 1, 1, EntropyType::BoseEinstein>, + reconstruct, + false> +{ + static constexpr double l1norm = reconstruct ? 0.33140398337969496 : 0.33140398335992233; + static constexpr double l2norm = reconstruct ? 0.45580154156528901 : 0.44483189012485808; + static constexpr double linfnorm = reconstruct ? 0.99172111701075782 : 0.98930792103242149; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct SourceBeamMnExpectedResults<PartialMomentBasis<double, 1, double, 8, 1, 1>, reconstruct, true> +{ + static constexpr double l1norm = reconstruct ? 254.20216502516391 : 270.74268779687191; + static constexpr double l2norm = reconstruct ? 187.86036790841933 : 202.76054800096165; + static constexpr double linfnorm = reconstruct ? 265.10790627160509 : 260.82089045524185; + static constexpr double tol = 1e-5; +}; + +template <class GridImp, class MomentBasisImp, bool reconstruct, bool kinetic_scheme = false> +struct SourceBeamMnTestCase : public SourceBeamPnTestCase<GridImp, MomentBasisImp, reconstruct> +{ + using BaseType = SourceBeamPnTestCase<GridImp, MomentBasisImp, reconstruct>; + using typename BaseType::DiscreteFunctionType; + using typename BaseType::GridViewType; + using ProblemType = SourceBeamMn<GridViewType, MomentBasisImp>; + using ExpectedResultsType = SourceBeamMnExpectedResults<MomentBasisImp, reconstruct, kinetic_scheme>; + using QuadratureChooserType = QuadratureChooser<MomentBasisImp>; + static constexpr size_t quad_order = QuadratureChooserType::quad_order; + static constexpr size_t quad_refinements = QuadratureChooserType::quad_refinements; + using RealizabilityLimiterChooserType = + RealizabilityLimiterChooser<GridViewType, MomentBasisImp, typename ProblemType::FluxType, DiscreteFunctionType>; +}; + +// PlaneSource Pn +template <class MomentBasisImp, bool reconstruct> +struct PlaneSourcePnExpectedResults; + +template <bool reconstruct> +struct PlaneSourcePnExpectedResults<LegendreMomentBasis<double, double, 7>, reconstruct> +{ + static constexpr double l1norm = reconstruct ? 2.0000000240000007 : 2.0000000240000029; + static constexpr double l2norm = reconstruct ? 2.9616518419466558 : 2.7792352623482848; + static constexpr double linfnorm = reconstruct ? 7.5355813391308644 : 5.9472849007944166; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct PlaneSourcePnExpectedResults<HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, reconstruct> +{ + static constexpr double l1norm = 2.0000000240000149; + static constexpr double l2norm = reconstruct ? 2.8915349919892397 : 2.7676677008555917; + static constexpr double linfnorm = reconstruct ? 6.9950740716997668 : 5.8904604670932663; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct PlaneSourcePnExpectedResults<PartialMomentBasis<double, 1, double, 8, 1, 1>, reconstruct> +{ + static constexpr double l1norm = reconstruct ? 2.0000000239999896 : 2.0000000239999918; + static constexpr double l2norm = reconstruct ? 2.8799152602279068 : 2.771228836660768; + static constexpr double linfnorm = reconstruct ? 6.9320887958307775 : 6.0090382693364512; + static constexpr double tol = 1e-9; +}; + +template <class GridImp, class MomentBasisImp, bool reconstruct> +struct PlaneSourcePnTestCase : SourceBeamPnTestCase<GridImp, MomentBasisImp, reconstruct> +{ + using BaseType = SourceBeamPnTestCase<GridImp, MomentBasisImp, reconstruct>; + using RangeFieldType = typename BaseType::RangeFieldType; + using typename BaseType::E; + using ProblemType = PlaneSourcePn<E, MomentBasisImp>; + static constexpr RangeFieldType t_end = 0.25; + static constexpr bool reconstruction = reconstruct; + using ExpectedResultsType = PlaneSourcePnExpectedResults<MomentBasisImp, reconstruction>; +}; + + +// PlaneSource Mn +template <class MomentBasisImp, bool reconstruct, bool kinetic_scheme = false> +struct PlaneSourceMnExpectedResults +{ + static constexpr double l1norm = 0.; + static constexpr double l2norm = 0.; + static constexpr double linfnorm = 0.; + static constexpr double tol = 0.; +}; + +template <bool reconstruct> +struct PlaneSourceMnExpectedResults<LegendreMomentBasis<double, double, 7>, reconstruct, false> +{ + static constexpr double l1norm = reconstruct ? 2.0000000240000007 : 2.0000000240000029; + static constexpr double l2norm = reconstruct ? 2.785411193059216 : 2.746101358507282; + static constexpr double linfnorm = reconstruct ? 4.9069101475812698 : 5.327698357914608; + static constexpr double tol = 1e-7; +}; + +template <bool reconstruct> +struct PlaneSourceMnExpectedResults<LegendreMomentBasis<double, double, 7, 1, EntropyType::BoseEinstein>, + reconstruct, + false> +{ + static constexpr double l1norm = reconstruct ? 2.000000024000002 : 2.0000000239999993; + static constexpr double l2norm = reconstruct ? 2.8065243992927944 : 2.7602055903929905; + static constexpr double linfnorm = reconstruct ? 6.4715719275169796 : 6.5649315387146858; + // Results are not really stable here, even very small numerical errors (e.g. due to the parallel quadrature in the + // Legendre integrated() initializer) can lead to quite large errors in the result, so we use a high tolerance here. + static constexpr double tol = 1e-2; +}; + +template <bool reconstruct> +struct PlaneSourceMnExpectedResults<LegendreMomentBasis<double, double, 7>, reconstruct, true> +{ + static constexpr double l1norm = reconstruct ? 33.830651291425575 : 31.119878976551046; + static constexpr double l2norm = reconstruct ? 24.726893737746675 : 23.385570207485049; + static constexpr double linfnorm = reconstruct ? 19.113827924512311 : 19.113827924512311; + static constexpr double tol = 1e-5; +}; + +template <bool reconstruct> +struct PlaneSourceMnExpectedResults<HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, reconstruct, false> +{ + static constexpr double l1norm = 2.0000000239315696; + static constexpr double l2norm = reconstruct ? 2.7966600752714887 : 2.7457411547488615; + static constexpr double linfnorm = reconstruct ? 5.2425259627991894 : 4.9923971272638816; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct PlaneSourceMnExpectedResults<HatFunctionMomentBasis<double, 1, double, 8, 1, 1>, reconstruct, true> +{ + static constexpr double l1norm = reconstruct ? 268.42768559247429 : 246.7429359648828; + static constexpr double l2norm = reconstruct ? 197.1506094198385 : 186.09403264481648; + static constexpr double linfnorm = reconstruct ? 152.91062339609854 : 152.91062339609854; + static constexpr double tol = 1e-5; +}; + +template <bool reconstruct> +struct PlaneSourceMnExpectedResults<PartialMomentBasis<double, 1, double, 8, 1, 1>, reconstruct, false> +{ + static constexpr double l1norm = reconstruct ? 2.0000000239999913 : 2.0000000239999904; + static constexpr double l2norm = reconstruct ? 2.8215879031834015 : 2.7633864171098814; + static constexpr double linfnorm = reconstruct ? 6.0674052799351612 : 6.2607864745531092; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct PlaneSourceMnExpectedResults<PartialMomentBasis<double, 1, double, 8, 1, 1>, reconstruct, true> +{ + static constexpr double l1norm = reconstruct ? 144.19157186249112 : 135.86834797834712; + static constexpr double l2norm = reconstruct ? 104.28938402311856 : 100.2359224660796; + static constexpr double linfnorm = reconstruct ? 100.43185554232102 : 97.933985765677008; + static constexpr double tol = 1e-5; +}; + + +template <class GridImp, class MomentBasisImp, bool reconstruct, bool kinetic_scheme = false> +struct PlaneSourceMnTestCase : SourceBeamMnTestCase<GridImp, MomentBasisImp, reconstruct> +{ + using BaseType = SourceBeamMnTestCase<GridImp, MomentBasisImp, reconstruct>; + using typename BaseType::DiscreteFunctionType; + using RangeFieldType = typename BaseType::RangeFieldType; + using typename BaseType::GridViewType; + using ProblemType = PlaneSourceMn<GridViewType, MomentBasisImp>; + static constexpr RangeFieldType t_end = 0.25; + static constexpr bool reconstruction = reconstruct; + using ExpectedResultsType = PlaneSourceMnExpectedResults<MomentBasisImp, reconstruction, kinetic_scheme>; + using QuadratureChooserType = QuadratureChooser<MomentBasisImp>; + static constexpr size_t quad_order = QuadratureChooserType::quad_order; + static constexpr size_t quad_refinements = QuadratureChooserType::quad_refinements; + using RealizabilityLimiterChooserType = + RealizabilityLimiterChooser<GridViewType, MomentBasisImp, typename ProblemType::FluxType, DiscreteFunctionType>; +}; + + +// PointSourcePn +template <class MomentBasisImp, bool reconstruct> +struct PointSourcePnExpectedResults +{ + static constexpr double l1norm = 0.; + static constexpr double l2norm = 0.; + static constexpr double linfnorm = 0.; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct PointSourcePnExpectedResults<RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, reconstruct> +{ + static constexpr double l1norm = reconstruct ? 1.0000013830443908 : 1.000001383044226; + static constexpr double l2norm = reconstruct ? 2.6933361115324854 : 2.6827446884685; + static constexpr double linfnorm = reconstruct ? 10.361584898132795 : 10.368534349621724; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct PointSourcePnExpectedResults<HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, reconstruct> +{ + static constexpr double l1norm = reconstruct ? 1.000000489200628 : 1.0000004892004557; + static constexpr double l2norm = reconstruct ? 2.7000542373965715 : 2.6889777333363365; + static constexpr double linfnorm = reconstruct ? 10.393925182562946 : 10.395628177780834; + // The matrices in this test case all have eigenvalues [+-0.808311035811965, 0, 0, 0, 0]. + // Thus, the eigenvectors are not unique, and the eigensolvers are extremely sensitive + // to numerical errors. A difference of 1e-16 in the jacobians entries suffices to + // result in completely different eigenvectors. In all cases, the eigenvectors are + // valid eigenvectors to the correct eigenvalues. However, this difference in the + // eigendecomposition leads to differences in the results with linear reconstruction + // that are larger than would be expected by pure numerical errors. + static constexpr double tol = reconstruct ? 1e-5 : 1e-9; +}; + +template <bool reconstruct> +struct PointSourcePnExpectedResults<HatFunctionMomentBasis<double, 3, double, 1, 1, 3>, reconstruct> +{ + // Results with reconstruction not available yet + static constexpr double l1norm = 0.9999999937547992; + static constexpr double l2norm = 2.6881086659719111; + static constexpr double linfnorm = 10.393501289579167; + // see above + static constexpr double tol = reconstruct ? 1e-5 : 1e-9; +}; + +template <bool reconstruct> +struct PointSourcePnExpectedResults<PartialMomentBasis<double, 3, double, 0, 1, 3>, reconstruct> +{ + static constexpr double l1norm = reconstruct ? 1.000000489200628 : 1.0000004892004604; + static constexpr double l2norm = reconstruct ? 2.6985809847834017 : 2.6881899717088591; + static constexpr double linfnorm = reconstruct ? 10.391256326798887 : 10.394092510258828; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct PointSourcePnExpectedResults<PartialMomentBasis<double, 3, double, 1, 1, 3>, reconstruct> +{ + static_assert(!reconstruct, "Results with reconstruction not available yet!"); + static constexpr double l1norm = 0.99999999375479631; + static constexpr double l2norm = 2.6881891561264872; + static constexpr double linfnorm = 10.394089431581479; + static constexpr double tol = 1e-9; +}; + + +template <class GridImp, class MomentBasisImp, bool reconstruct> +struct PointSourcePnTestCase : SourceBeamPnTestCase<GridImp, MomentBasisImp, reconstruct> +{ + using BaseType = SourceBeamPnTestCase<GridImp, MomentBasisImp, reconstruct>; + using RangeFieldType = typename BaseType::RangeFieldType; + using typename BaseType::E; + using ProblemType = PointSourcePn<E, MomentBasisImp>; + static constexpr RangeFieldType t_end = 0.1; + static constexpr bool reconstruction = reconstruct; + using ExpectedResultsType = PointSourcePnExpectedResults<MomentBasisImp, reconstruction>; +}; + +// CheckerboardPn +template <class MomentBasisImp, bool reconstruct> +struct CheckerboardPnExpectedResults +{ + static constexpr double l1norm = 0.; + static constexpr double l2norm = 0.; + static constexpr double linfnorm = 0; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct CheckerboardPnExpectedResults<RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, reconstruct> +{ + static constexpr double l1norm = 0.35405006483527851; + static constexpr double l2norm = 0.32921416691428851; + static constexpr double linfnorm = 0.32895256210981677; + static constexpr double tol = 1e-9; +}; + +template <class GridImp, class MomentBasisImp, bool reconstruct> +struct CheckerboardPnTestCase : SourceBeamPnTestCase<GridImp, MomentBasisImp, reconstruct> +{ + using BaseType = SourceBeamPnTestCase<GridImp, MomentBasisImp, reconstruct>; + using RangeFieldType = typename BaseType::RangeFieldType; + using typename BaseType::E; + using ProblemType = CheckerboardPn<E, MomentBasisImp>; + static constexpr RangeFieldType t_end = 0.1; + static constexpr bool reconstruction = reconstruct; + using ExpectedResultsType = CheckerboardPnExpectedResults<MomentBasisImp, reconstruction>; +}; + +// ShadowPn +template <class MomentBasisImp, bool reconstruct> +struct ShadowPnExpectedResults +{ + static constexpr double l1norm = 0.; + static constexpr double l2norm = 0.; + static constexpr double linfnorm = 0; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct ShadowPnExpectedResults<RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, reconstruct> +{ + static constexpr double l1norm = 0.59263334787808175; + static constexpr double l2norm = 0.097679818213367978; + static constexpr double linfnorm = 0.016484487060897713; + static constexpr double tol = 1e-9; +}; + +template <class GridImp, class MomentBasisImp, bool reconstruct> +struct ShadowPnTestCase : SourceBeamPnTestCase<GridImp, MomentBasisImp, reconstruct> +{ + using BaseType = SourceBeamPnTestCase<GridImp, MomentBasisImp, reconstruct>; + using RangeFieldType = typename BaseType::RangeFieldType; + using typename BaseType::E; + using ProblemType = ShadowPn<E, MomentBasisImp>; + static constexpr RangeFieldType t_end = 0.1; + static constexpr bool reconstruction = reconstruct; + using ExpectedResultsType = ShadowPnExpectedResults<MomentBasisImp, reconstruction>; +}; + + +// PointSourceMn +template <class MomentBasisImp, bool reconstruct, bool kinetic_scheme = false> +struct PointSourceMnExpectedResults +{ + static constexpr double l1norm = 0.; + static constexpr double l2norm = 0.; + static constexpr double linfnorm = 0.; + static constexpr double tol = 0.; +}; + +template <bool reconstruct> +struct PointSourceMnExpectedResults<RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, reconstruct, false> +{ + static constexpr double l1norm = reconstruct ? 1.0000013830443908 : 1.0000013830442143; + static constexpr double l2norm = reconstruct ? 2.6901467570598112 : 2.684314243798307; + static constexpr double linfnorm = reconstruct ? 10.371048798431969 : 10.377307670780343; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct PointSourceMnExpectedResults< + RealSphericalHarmonicsMomentBasis<double, double, 2, 3, false, EntropyType::BoseEinstein>, + reconstruct, + false> +{ + static constexpr double l1norm = reconstruct ? 1.0000013830443903 : 0.; + static constexpr double l2norm = reconstruct ? 2.6909504479323516 : 0.; + static constexpr double linfnorm = reconstruct ? 10.375951173911345 : 0.; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct PointSourceMnExpectedResults<RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, reconstruct, true> +{ + static constexpr double l1norm = reconstruct ? 1674.9008041695579 : 1585.7044225325101; + static constexpr double l2norm = reconstruct ? 619.41343145125302 : 589.93299566257235; + static constexpr double linfnorm = reconstruct ? 264.16080528868997 : 266.5453598444696; + static constexpr double tol = 1e-5; +}; + +template <bool reconstruct> +struct PointSourceMnExpectedResults<HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, reconstruct, false> +{ + static constexpr double l1norm = reconstruct ? 1.0000000829624791 : 1.0000000829622864; + static constexpr double l2norm = reconstruct ? 2.694751941188763 : 2.6892684619955305; + static constexpr double linfnorm = reconstruct ? 10.379060444346454 : 10.395305896397684; + // The matrices in this test case all have eigenvalues [+-0.808311035811965, 0, 0, 0, 0]. + // Thus, the eigenvectors are not unique, and the eigensolvers are extremely sensitive + // to numerical errors. A difference of 1e-16 in the jacobians entries suffices to + // result in completely different eigenvectors. In all cases, the eigenvectors are + // valid eigenvectors to the correct eigenvalues. However, this difference in the + // eigendecomposition leads to differences in the results with linear reconstruction + // that are larger than would be expected by pure numerical errors. + static constexpr double tol = reconstruct ? 1e-5 : 1e-9; +}; + +template <bool reconstruct> +struct PointSourceMnExpectedResults<HatFunctionMomentBasis<double, 3, double, 0, 1, 3, EntropyType::BoseEinstein>, + reconstruct, + false> +{ + static constexpr double l1norm = reconstruct ? 1.0000000829624884 : 1.0000000829622837; + static constexpr double l2norm = reconstruct ? 2.694161596061091 : 2.6895958084783342; + static constexpr double linfnorm = reconstruct ? 10.377805677445533 : 10.396217979398697; + static constexpr double tol = reconstruct ? 1e-5 : 1e-9; +}; + +template <bool reconstruct> +struct PointSourceMnExpectedResults<HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, reconstruct, true> +{ + static constexpr double l1norm = reconstruct ? 818.73622981959204 : 781.1965079003387; + static constexpr double l2norm = reconstruct ? 301.48148670872598 : 289.21738528985526; + static constexpr double linfnorm = reconstruct ? 125.7102296804655 : 125.71014355518233; + static constexpr double tol = 1e-5; +}; + +template <bool reconstruct> +struct PointSourceMnExpectedResults<PartialMomentBasis<double, 3, double, 0, 1, 3, 1>, reconstruct, false> +{ + static constexpr double l1norm = reconstruct ? 1.0000000829624787 : 1.0000000829623072; + static constexpr double l2norm = reconstruct ? 2.6983516853120966 : 2.6881937835020211; + static constexpr double linfnorm = reconstruct ? 10.391142640527102 : 10.394108065213185; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct PointSourceMnExpectedResults<PartialMomentBasis<double, 3, double, 0, 1, 3, 1, EntropyType::BoseEinstein>, + reconstruct, + false> +{ + static constexpr double l1norm = reconstruct ? 1.0000000829624796 : 0.; + static constexpr double l2norm = reconstruct ? 2.6983603000374528 : 0.; + static constexpr double linfnorm = reconstruct ? 10.391283146511036 : 0.; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct PointSourceMnExpectedResults<PartialMomentBasis<double, 3, double, 0, 1, 3, 1>, reconstruct, true> +{ + static constexpr double l1norm = reconstruct ? 1167.5985275432627 : 1126.5174600848904; + static constexpr double l2norm = reconstruct ? 428.15220455351266 : 415.19451310103005; + static constexpr double linfnorm = reconstruct ? 188.26590907577059 : 191.48910050886076; + static constexpr double tol = 1e-5; +}; + +template <class GridImp, class MomentBasisImp, bool reconstruct, bool kinetic_scheme = false> +struct PointSourceMnTestCase : SourceBeamMnTestCase<GridImp, MomentBasisImp, reconstruct, kinetic_scheme> +{ + using BaseType = SourceBeamMnTestCase<GridImp, MomentBasisImp, reconstruct, kinetic_scheme>; + using typename BaseType::GridViewType; + using ProblemType = PointSourceMn<GridViewType, MomentBasisImp>; + using typename BaseType::RangeFieldType; + static constexpr RangeFieldType t_end = 0.1; + static constexpr bool reconstruction = reconstruct; + using ExpectedResultsType = PointSourceMnExpectedResults<MomentBasisImp, reconstruction, kinetic_scheme>; + using QuadratureChooserType = QuadratureChooser<MomentBasisImp>; + static constexpr size_t quad_order = QuadratureChooserType::quad_order; + static constexpr size_t quad_refinements = QuadratureChooserType::quad_refinements; + using RealizabilityLimiterChooserType = RealizabilityLimiterChooser<GridViewType, + MomentBasisImp, + typename ProblemType::FluxType, + typename BaseType::DiscreteFunctionType>; +}; + + +// CheckerboardMn +template <class MomentBasisImp, bool reconstruct, bool kinetic_scheme = false> +struct CheckerboardMnExpectedResults; + +template <bool reconstruct> +struct CheckerboardMnExpectedResults<RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, reconstruct, false> +{ + static constexpr double l1norm = reconstruct ? 0. : 0.35404509573284748; + static constexpr double l2norm = reconstruct ? 0. : 0.32922954029850499; + static constexpr double linfnorm = reconstruct ? 0. : 0.32896894056609421; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct CheckerboardMnExpectedResults<RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, reconstruct, true> +{ + static constexpr double l1norm = reconstruct ? 0. : 0.; + static constexpr double l2norm = reconstruct ? 0. : 0.; + static constexpr double linfnorm = reconstruct ? 0. : 0.; + static constexpr double tol = 1e-5; +}; + +template <bool reconstruct> +struct CheckerboardMnExpectedResults<HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, reconstruct, false> +{ + static constexpr double l1norm = reconstruct ? 0. : 0.; + static constexpr double l2norm = reconstruct ? 0. : 0.; + static constexpr double linfnorm = reconstruct ? 0. : 0.; + static constexpr double tol = 1e-9; +}; + +template <bool reconstruct> +struct CheckerboardMnExpectedResults<HatFunctionMomentBasis<double, 3, double, 0, 1, 3>, reconstruct, true> +{ + static constexpr double l1norm = reconstruct ? 42799.981949017187 : 0.; + static constexpr double l2norm = reconstruct ? 2318.887531040597 : 0.; + static constexpr double linfnorm = reconstruct ? 131.24293776745421 : 0.; + static constexpr double tol = 1e-5; +}; + +template <class GridImp, class MomentBasisImp, bool reconstruct, bool kinetic_scheme = false> +struct CheckerboardMnTestCase : SourceBeamMnTestCase<GridImp, MomentBasisImp, reconstruct, kinetic_scheme> +{ + using BaseType = SourceBeamMnTestCase<GridImp, MomentBasisImp, reconstruct, kinetic_scheme>; + using typename BaseType::GridViewType; + using ProblemType = CheckerboardMn<GridViewType, MomentBasisImp>; + using typename BaseType::RangeFieldType; + static constexpr RangeFieldType t_end = 0.1; + static constexpr bool reconstruction = reconstruct; + using ExpectedResultsType = CheckerboardMnExpectedResults<MomentBasisImp, reconstruction, kinetic_scheme>; + using QuadratureChooserType = QuadratureChooser<MomentBasisImp>; + static constexpr size_t quad_order = QuadratureChooserType::quad_order; + static constexpr size_t quad_refinements = QuadratureChooserType::quad_refinements; + using RealizabilityLimiterChooserType = RealizabilityLimiterChooser<GridViewType, + MomentBasisImp, + typename ProblemType::FluxType, + typename BaseType::DiscreteFunctionType>; +}; + + +// ShadowMn +template <class MomentBasisImp, bool reconstruct> +struct ShadowMnExpectedResults; + +template <bool reconstruct> +struct ShadowMnExpectedResults<RealSphericalHarmonicsMomentBasis<double, double, 2, 3>, reconstruct> +{ + static constexpr double l1norm = reconstruct ? 0. : 0.59248402251960053; + static constexpr double l2norm = reconstruct ? 0. : 0.097644561106262767; + static constexpr double linfnorm = reconstruct ? 0. : 0.016480889201743513; + static constexpr double tol = 1e-9; +}; + + +template <class GridImp, class MomentBasisImp, bool reconstruct> +struct ShadowMnTestCase : SourceBeamMnTestCase<GridImp, MomentBasisImp, reconstruct> +{ + using BaseType = SourceBeamMnTestCase<GridImp, MomentBasisImp, reconstruct>; + using typename BaseType::GridViewType; + using ProblemType = ShadowMn<GridViewType, MomentBasisImp>; + using typename BaseType::RangeFieldType; + static constexpr RangeFieldType t_end = 0.1; + static constexpr bool reconstruction = reconstruct; + using ExpectedResultsType = ShadowMnExpectedResults<MomentBasisImp, reconstruction>; + using QuadratureChooserType = QuadratureChooser<MomentBasisImp>; + static constexpr size_t quad_order = QuadratureChooserType::quad_order; + static constexpr size_t quad_refinements = QuadratureChooserType::quad_refinements; + using RealizabilityLimiterChooserType = RealizabilityLimiterChooser<GridViewType, + MomentBasisImp, + typename ProblemType::FluxType, + typename BaseType::DiscreteFunctionType>; +}; + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_HYPERBOLIC_PROBLEMS_KINETICTRANSPORT_TESTCASES_HH diff --git a/dune/gdt/test/momentmodels/mn-discretization.hh b/dune/gdt/test/momentmodels/mn-discretization.hh new file mode 100644 index 0000000000000000000000000000000000000000..2458bd8f449ec51076802e604de7fa36333859ed --- /dev/null +++ b/dune/gdt/test/momentmodels/mn-discretization.hh @@ -0,0 +1,265 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +#ifndef DUNE_GDT_TEST_HYPERBOLIC_MN_DISCRETIZATION_HH +#define DUNE_GDT_TEST_HYPERBOLIC_MN_DISCRETIZATION_HH + +#include <chrono> + +#include <dune/xt/common/parallel/threadmanager.hh> +#include <dune/xt/common/string.hh> +#include <dune/xt/common/test/gtest/gtest.h> + +#include <dune/xt/grid/information.hh> +#include <dune/xt/grid/gridprovider.hh> + +#include <dune/xt/la/container.hh> + +#include <dune/gdt/discretefunction/default.hh> +#include <dune/gdt/operators/advection-fv-entropybased.hh> +#include <dune/gdt/operators/advection-fv.hh> +#include <dune/gdt/interpolations/default.hh> +#include <dune/gdt/test/momentmodels/entropysolver.hh> +#include <dune/gdt/local/numerical-fluxes/kinetic.hh> +#include <dune/gdt/local/operators/advection-fv.hh> +#include <dune/gdt/spaces/l2/finite-volume.hh> +#include <dune/gdt/tools/timestepper/fractional-step.hh> +#include <dune/gdt/tools/timestepper/explicit-rungekutta.hh> +#include <dune/gdt/tools/timestepper/matrix-exponential-kinetic-isotropic.hh> + +#include <dune/gdt/test/momentmodels/kineticequation.hh> + +#include "pn-discretization.hh" + +template <class TestCaseType> +struct HyperbolicMnDiscretization +{ + // returns: (l1norm, l2norm, linfnorm, MPI rank) + static std::pair<Dune::FieldVector<double, 3>, int> run(size_t num_save_steps = 1, + size_t num_output_steps = 0, + size_t quad_order = size_t(-1), + size_t quad_refinements = size_t(-1), + std::string grid_size = "", + size_t overlap_size = 2, + double t_end = 0., + std::string filename = "", + bool disable_thread_cache = false) + { + using namespace Dune; + using namespace Dune::GDT; + + //******************* get typedefs and constants from ProblemType **********************// + using MomentBasis = typename TestCaseType::MomentBasis; + using DiscreteFunctionType = typename TestCaseType::DiscreteFunctionType; + using GridType = typename TestCaseType::GridType; + using SpaceType = typename TestCaseType::SpaceType; + using AdvectionSourceSpaceType = typename TestCaseType::AdvectionSourceSpaceType; + using GV = typename TestCaseType::GridViewType; + using I = XT::Grid::extract_intersection_t<GV>; + using ProblemType = typename TestCaseType::ProblemType; + using RangeFieldType = typename MomentBasis::RangeFieldType; + using BoundaryValueType = typename ProblemType::BoundaryValueType; + static constexpr size_t dimDomain = MomentBasis::dimDomain; + static constexpr size_t dimRange = MomentBasis::dimRange; + using MatrixType = typename XT::LA::Container<RangeFieldType>::MatrixType; + using VectorType = typename XT::LA::Container<RangeFieldType>::VectorType; + + //******************* create grid and FV space *************************************** + auto grid_config = ProblemType::default_grid_cfg(); + if (!grid_size.empty()) + grid_config["num_elements"] = grid_size; + grid_config["overlap_size"] = XT::Common::to_string(overlap_size); + const auto grid_ptr = + Dune::XT::Grid::CubeGridProviderFactory<GridType>::create(grid_config, MPIHelper::getCommunicator()).grid_ptr(); + assert(grid_ptr->comm().size() == 1 || grid_ptr->overlapSize(0) > 0); + const GV grid_view(grid_ptr->leafGridView()); + const SpaceType fv_space(grid_view); + const AdvectionSourceSpaceType advection_source_space(grid_view); + + //******************* create EquationType object *************************************** + std::shared_ptr<const MomentBasis> basis_functions = std::make_shared<const MomentBasis>( + quad_order == size_t(-1) ? MomentBasis::default_quad_order() : quad_order, + quad_refinements == size_t(-1) ? MomentBasis::default_quad_refinements() : quad_refinements); + const std::unique_ptr<ProblemType> problem_ptr = + XT::Common::make_unique<ProblemType>(*basis_functions, grid_view, grid_config); + const auto& problem = *problem_ptr; + const auto initial_values = problem.initial_values(); + const auto boundary_values = problem.boundary_values(); + using AnalyticalFluxType = typename ProblemType::FluxType; + using EntropyFluxType = typename ProblemType::ActualFluxType; + auto analytical_flux = problem.flux(); + // for Legendre polynomials and real spherical harmonics, the results are sensitive to the initial guess in the + // Newton algorithm. If the thread cache is enabled, the guess is different dependent on how many threads we are + // using, so for the tests we disable this cache to get reproducible results. + if (disable_thread_cache) + dynamic_cast<EntropyFluxType*>(analytical_flux.get())->disable_thread_cache(); + const RangeFieldType CFL = problem.CFL(); + + // ***************** project initial values to discrete function ********************* + // create a discrete function for the solution + DiscreteFunctionType u(fv_space, "solution"); + // project initial values + default_interpolation(*initial_values, u, grid_view); + + // ******************** choose flux and rhs operator and timestepper ****************************************** + + using AdvectionOperatorType = AdvectionFvOperator<MatrixType, GV, dimRange>; + using EigenvectorWrapperType = typename EigenvectorWrapperChooser<MomentBasis, AnalyticalFluxType>::type; + using EntropySolverType = EntropySolver<MomentBasis, SpaceType>; + // using ReconstructionOperatorType = + // LinearReconstructionOperator<AnalyticalFluxType, BoundaryValueType, GV, MatrixType, + // EigenvectorWrapperType>; + using ReconstructionOperatorType = PointwiseLinearReconstructionOperator<AnalyticalFluxType, + BoundaryValueType, + GV, + VectorType, + EigenvectorWrapperType>; + using ReconstructionAdvectionOperatorType = + AdvectionWithPointwiseReconstructionOperator<AdvectionOperatorType, ReconstructionOperatorType>; + using FvOperatorType = EntropyBasedMomentFvOperator< + std::conditional_t<TestCaseType::reconstruction, ReconstructionAdvectionOperatorType, AdvectionOperatorType>, + EntropySolverType>; + using OperatorTimeStepperType = + ExplicitRungeKuttaTimeStepper<FvOperatorType, + DiscreteFunctionType, + TimeStepperMethods::explicit_rungekutta_second_order_ssp>; + using RhsTimeStepperType = KineticIsotropicTimeStepper<DiscreteFunctionType, MomentBasis>; + using TimeStepperType = StrangSplittingTimeStepper<RhsTimeStepperType, OperatorTimeStepperType>; + + // *************** Calculate dx and initial dt ************************************** + Dune::XT::Grid::Dimensions<GV> dimensions(grid_view); + RangeFieldType dx = dimensions.entity_width.max(); + if (dimDomain == 2) + dx /= std::sqrt(2); + if (dimDomain == 3) + dx /= std::sqrt(3); + RangeFieldType dt = CFL * dx; + + // *********************** create operators and timesteppers ************************************ + NumericalKineticFlux<GV, MomentBasis> numerical_flux(*analytical_flux, *basis_functions); + AdvectionOperatorType advection_operator(grid_view, numerical_flux, advection_source_space, fv_space); + + // boundary treatment + using BoundaryOperator = + LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator<I, VectorType, GV, dimRange>; + using LambdaType = typename BoundaryOperator::LambdaType; + using StateType = typename BoundaryOperator::StateType; + LambdaType boundary_lambda = + [&boundary_values](const I& intersection, + const FieldVector<RangeFieldType, dimDomain - 1>& xx_in_reference_intersection_coordinates, + const AnalyticalFluxType& /*flux*/, + const StateType& /*u*/, + const XT::Common::Parameter& /*param*/) { + return boundary_values->evaluate(intersection.geometry().global(xx_in_reference_intersection_coordinates)); + }; + XT::Grid::ApplyOn::NonPeriodicBoundaryIntersections<GV> filter; + advection_operator.append(boundary_lambda, {}, filter); + + constexpr double epsilon = 1e-11; + auto slope = TestCaseType::RealizabilityLimiterChooserType::template make_slope<EigenvectorWrapperType>( + *dynamic_cast<EntropyFluxType*>(analytical_flux.get()), *basis_functions, epsilon); + ReconstructionOperatorType reconstruction_operator(*analytical_flux, *boundary_values, fv_space, *slope, false); + ReconstructionAdvectionOperatorType reconstruction_advection_operator(advection_operator, reconstruction_operator); + + if (XT::Common::is_zero(t_end)) + t_end = problem.t_end(); + + if (!filename.empty()) + filename += "_"; + filename += ProblemType::static_id(); + filename += "_grid_" + grid_config["num_elements"]; + filename += "_tend_" + XT::Common::to_string(t_end); + filename += "_quad_" + XT::Common::to_string(quad_order); + filename += MomentBasis::entropy == EntropyType::MaxwellBoltzmann ? "_MaxwellBoltzmann_" : "_BoseEinstein_"; + filename += TestCaseType::reconstruction ? "_ord2" : "_ord1"; + filename += "_" + basis_functions->mn_name(); + + EntropySolverType entropy_solver(*(dynamic_cast<EntropyFluxType*>(analytical_flux.get())), + fv_space, + problem.psi_vac() * basis_functions->unit_ball_volume() / 10, + filename); + FvOperatorType fv_operator( + FvOperatorChooser<TestCaseType::reconstruction>::choose(advection_operator, reconstruction_advection_operator), + entropy_solver); + + // ******************************** do the time steps *********************************************************** + const auto sigma_a = problem.sigma_a(); + const auto sigma_s = problem.sigma_s(); + const auto Q = problem.Q(); + OperatorTimeStepperType timestepper_op(fv_operator, u, -1.0); + RhsTimeStepperType timestepper_rhs(*basis_functions, u, *sigma_a, *sigma_s, *Q); + TimeStepperType timestepper(timestepper_rhs, timestepper_op); + + auto begin_time = std::chrono::steady_clock::now(); + timestepper.solve(t_end, + dt, + num_save_steps, + num_output_steps, + false, + true, + true, + false, + filename, + *basis_functions->visualizer(), + basis_functions->stringifier()); + auto end_time = std::chrono::steady_clock::now(); + std::chrono::duration<double> time_diff = end_time - begin_time; + if (grid_view.comm().rank() == 0) + std::cout << "Solving took: " << XT::Common::to_string(time_diff.count(), 15) << " s" << std::endl; + + auto ret = std::make_pair(FieldVector<double, 3>(0.), int(0)); + double& l1norm = ret.first[0]; + double& l2norm = ret.first[1]; + double& linfnorm = ret.first[2]; + ret.second = grid_view.comm().rank(); + const auto& current_sol = timestepper.current_solution(); + const auto local_sol = current_sol.local_function(); + for (const auto& entity : elements(grid_view, Dune::Partitions::interior)) { + local_sol->bind(entity); + const auto val = local_sol->evaluate(entity.geometry().local(entity.geometry().center())); + RangeFieldType psi = basis_functions->density(val); + l1norm += std::abs(psi) * entity.geometry().volume(); + l2norm += std::pow(psi, 2) * entity.geometry().volume(); + linfnorm = std::max(std::abs(psi), linfnorm); + } + l1norm = grid_view.comm().sum(l1norm); + l2norm = grid_view.comm().sum(l2norm); + linfnorm = grid_view.comm().max(linfnorm); + l2norm = std::sqrt(l2norm); + return ret; + } +}; + +template <class TestCaseType> +struct HyperbolicMnTest + : public HyperbolicMnDiscretization<TestCaseType> + , public ::testing::Test +{ + void run(const double tol = TestCaseType::ExpectedResultsType::tol) + { + auto norms = HyperbolicMnDiscretization<TestCaseType>::run( + 1, + 0, + TestCaseType::quad_order, + TestCaseType::quad_refinements, + "", + 2, + TestCaseType::t_end, + "test", + Dune::GDT::is_full_moment_basis<typename TestCaseType::MomentBasis>::value) + .first; + const double l1norm = norms[0]; + const double l2norm = norms[1]; + const double linfnorm = norms[2]; + using ResultsType = typename TestCaseType::ExpectedResultsType; + EXPECT_NEAR(ResultsType::l1norm, l1norm, ResultsType::l1norm * tol); + EXPECT_NEAR(ResultsType::l2norm, l2norm, ResultsType::l2norm * tol); + EXPECT_NEAR(ResultsType::linfnorm, linfnorm, ResultsType::linfnorm * tol); + } +}; + +#endif // DUNE_GDT_TEST_HYPERBOLIC_MN_DISCRETIZATION_HH diff --git a/dune/gdt/test/momentmodels/pn-discretization.hh b/dune/gdt/test/momentmodels/pn-discretization.hh new file mode 100644 index 0000000000000000000000000000000000000000..f446d49e371c054aa440a8a2c41f020747765a09 --- /dev/null +++ b/dune/gdt/test/momentmodels/pn-discretization.hh @@ -0,0 +1,390 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved. +// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// Authors: +// Tobias Leibner (2016) + +#ifndef DUNE_GDT_TEST_HYPERBOLIC_PN_DISCRETIZATION_HH +#define DUNE_GDT_TEST_HYPERBOLIC_PN_DISCRETIZATION_HH + +#include <dune/common/exceptions.hh> + +#include <dune/xt/common/parallel/threadmanager.hh> +#include <dune/xt/common/string.hh> +#include <dune/xt/common/test/gtest/gtest.h> + +#include <dune/xt/grid/information.hh> +#include <dune/xt/grid/gridprovider.hh> + +#include <dune/xt/la/container.hh> + +#include <dune/xt/functions/checkerboard.hh> + +#include <dune/gdt/discretefunction/default.hh> +#include <dune/gdt/operators/advection-fv.hh> +#include <dune/gdt/operators/advection-with-reconstruction.hh> +#include <dune/gdt/operators/reconstruction/linear.hh> +#include <dune/gdt/interpolations/default.hh> +#include <dune/gdt/local/numerical-fluxes/kinetic.hh> +#include <dune/gdt/local/numerical-fluxes/lax-friedrichs.hh> +#include <dune/gdt/local/operators/advection-fv.hh> +#include <dune/gdt/tools/timestepper/fractional-step.hh> +#include <dune/gdt/tools/timestepper/explicit-rungekutta.hh> +#include <dune/gdt/tools/timestepper/matrix-exponential-kinetic-isotropic.hh> + +#include <dune/gdt/test/momentmodels/kineticequation.hh> + +void parse_momentmodel_arguments(int argc, + char** argv, + size_t& num_threads, + size_t& threading_partition_factor, + size_t& num_save_steps, + size_t& num_output_steps, + size_t& quad_order, + size_t& quad_refinements, + std::string& grid_size, + size_t& overlap_size, + double& t_end, + std::string& filename) +{ + using namespace Dune; + using namespace Dune::GDT; + MPIHelper::instance(argc, argv); + + // default values + num_threads = 1; + threading_partition_factor = 1; + num_save_steps = 10; + num_output_steps = num_save_steps; + quad_order = -1; + quad_refinements = -1; + grid_size = ""; + overlap_size = 2; + t_end = 0.; + filename = ""; + + for (int i = 1; i < argc; ++i) { + if (std::string(argv[i]) == "--num_threads") { + if (i + 1 < argc) + num_threads = XT::Common::from_string<size_t>(argv[++i]); + else + DUNE_THROW(Dune::IOError, "--num_threads option requires one argument."); + } else if (std::string(argv[i]) == "--threading_partition_factor") { + if (i + 1 < argc) + threading_partition_factor = XT::Common::from_string<size_t>(argv[++i]); + else + DUNE_THROW(Dune::IOError, "--threading_partition_factor option requires one argument."); + } else if (std::string(argv[i]) == "--filename") { + if (i + 1 < argc) + filename = std::string(argv[++i]); + else + DUNE_THROW(Dune::IOError, "--filename option requires one argument."); + } else if (std::string(argv[i]) == "--quad_order") { + if (i + 1 < argc) + quad_order = XT::Common::from_string<size_t>(argv[++i]); + else + DUNE_THROW(Dune::IOError, "--quad_order option requires one argument."); + } else if (std::string(argv[i]) == "--quad_refinements") { + if (i + 1 < argc) + quad_refinements = XT::Common::from_string<size_t>(argv[++i]); + else + DUNE_THROW(Dune::IOError, "--quad_refinements option requires one argument."); + } else if (std::string(argv[i]) == "--num_save_steps") { + if (i + 1 < argc) + num_save_steps = XT::Common::from_string<size_t>(argv[++i]); + else + DUNE_THROW(Dune::IOError, "--num_save_steps option requires one argument."); + } else if (std::string(argv[i]) == "--num_output_steps") { + if (i + 1 < argc) + num_output_steps = XT::Common::from_string<size_t>(argv[++i]); + else + DUNE_THROW(Dune::IOError, "--num_output_steps option requires one argument."); + } else if (std::string(argv[i]) == "--grid_size") { + if (i + 1 < argc) + grid_size = argv[++i]; + else + DUNE_THROW(Dune::IOError, "--grid_size option requires one argument."); + } else if (std::string(argv[i]) == "--overlap_size") { + if (i + 1 < argc) + overlap_size = XT::Common::from_string<size_t>(argv[++i]); + else + DUNE_THROW(Dune::IOError, "--overlap_size option requires one argument."); + } else if (std::string(argv[i]) == "--t_end") { + if (i + 1 < argc) + t_end = XT::Common::from_string<double>(argv[++i]); + else + DUNE_THROW(Dune::IOError, "--t_end option requires one argument."); + } else { + DUNE_THROW(Dune::IOError, "Unknown option " + std::string(argv[i])); + } + } + + DXTC_CONFIG.set("threading.partition_factor", threading_partition_factor, true); + XT::Common::threadManager().set_max_threads(num_threads); +} + + +template <class MomentBasis, class AnalyticalFluxType> +struct EigenvectorWrapperChooser +{ + using type = Dune::GDT::internal::EigenvectorWrapper<AnalyticalFluxType>; +}; + +template <class AnalyticalFluxType, + class DomainFieldType, + size_t dimDomain, + class RangeFieldType, + size_t dimRange_or_refinements, + Dune::GDT::EntropyType entropy> +struct EigenvectorWrapperChooser<Dune::GDT::PartialMomentBasis<DomainFieldType, + dimDomain, + RangeFieldType, + dimRange_or_refinements, + 1, + dimDomain, + 1, + entropy>, + AnalyticalFluxType> +{ + using type = Dune::GDT::internal::BlockedEigenvectorWrapper<AnalyticalFluxType>; +}; + +template <bool reconstruction> +struct FvOperatorChooser +{ + template <class AdvectionOperatorType, class ReconstructionOperatorType> + static ReconstructionOperatorType& choose(AdvectionOperatorType& /*advection_operator*/, + ReconstructionOperatorType& reconstruction_operator) + { + return reconstruction_operator; + } +}; + +template <> +struct FvOperatorChooser<false> +{ + template <class AdvectionOperatorType, class ReconstructionOperatorType> + static AdvectionOperatorType& choose(AdvectionOperatorType& advection_operator, + ReconstructionOperatorType& /*reconstruction_operator*/) + { + return advection_operator; + } +}; + +#ifndef USE_FULL_LINEAR_RECONSTRUCTION_OPERATOR +# define USE_FULL_LINEAR_RECONSTRUCTION_OPERATOR 0 +#endif + +template <class TestCaseType> +struct HyperbolicPnDiscretization +{ + + Dune::FieldVector<double, 3> run(size_t num_save_steps = 1, + size_t num_output_steps = 0, + size_t quad_order = size_t(-1), + size_t quad_refinements = size_t(-1), + std::string grid_size = "", + size_t overlap_size = 2, + double t_end = 0., + std::string filename = "") + { + using namespace Dune; + using namespace Dune::GDT; + + //******************* get typedefs and constants from ProblemType **********************// + using MomentBasis = typename TestCaseType::MomentBasis; + using DiscreteFunctionType = typename TestCaseType::DiscreteFunctionType; + using GridType = typename TestCaseType::GridType; + using SpaceType = typename TestCaseType::SpaceType; + using AdvectionSourceSpaceType = typename TestCaseType::AdvectionSourceSpaceType; + using GV = typename TestCaseType::GridViewType; + using I = XT::Grid::extract_intersection_t<GV>; + using E = XT::Grid::extract_entity_t<GV>; + using ProblemType = typename TestCaseType::ProblemType; + using RangeFieldType = typename ProblemType::RangeFieldType; + using BoundaryValueType = typename ProblemType::BoundaryValueType; + static constexpr size_t dimDomain = MomentBasis::dimDomain; + static constexpr size_t dimRange = MomentBasis::dimRange; + using MatrixType = typename XT::LA::Container<RangeFieldType>::MatrixType; + using VectorType = typename XT::LA::Container<RangeFieldType>::VectorType; + + //******************* create grid and FV space *************************************** + auto grid_config = ProblemType::default_grid_cfg(); + if (!grid_size.empty()) + grid_config["num_elements"] = grid_size; + grid_config["overlap_size"] = XT::Common::to_string(overlap_size); + const auto grid_ptr = + Dune::XT::Grid::CubeGridProviderFactory<GridType>::create(grid_config, MPIHelper::getCommunicator()).grid_ptr(); + assert(grid_ptr->comm().size() == 1 || grid_ptr->overlapSize(0) > 0); + const GV grid_view(grid_ptr->leafGridView()); + const SpaceType fv_space(grid_view); + const AdvectionSourceSpaceType advection_source_space(grid_view); + + //******************* create EquationType object *************************************** + std::shared_ptr<const MomentBasis> basis_functions = std::make_shared<const MomentBasis>( + quad_order == size_t(-1) ? MomentBasis::default_quad_order() : quad_order, + quad_refinements == size_t(-1) ? MomentBasis::default_quad_refinements() : quad_refinements); + const std::unique_ptr<ProblemType> problem_ptr = + XT::Common::make_unique<ProblemType>(*basis_functions, grid_config); + const auto& problem = *problem_ptr; + const auto initial_values = problem.initial_values(); + const auto boundary_values = problem.boundary_values(); + const RangeFieldType CFL = problem.CFL(); + + // ***************** project initial values to discrete function ********************* + // create a discrete function for the solution + const size_t vec_size = fv_space.mapper().size(); + // we do very few whole-container operations with this vec, so using that many mutexes improves performance as it + // avoids locking + const size_t num_mutexes = XT::Common::threadManager().max_threads() * 100; + typename DiscreteFunctionType::VectorType vec(vec_size, 0., num_mutexes); + DiscreteFunctionType u(fv_space, vec, "solution"); + // project initial values + default_interpolation(*initial_values, u, grid_view); + + // ************************* create analytical flux object *************************************** + using AnalyticalFluxType = typename ProblemType::FluxType; + const auto analytical_flux = problem.flux(); + + // ******************** choose flux and rhs operator and timestepper ****************************************** + using AdvectionOperatorType = AdvectionFvOperator<MatrixType, GV, dimRange>; + using EigenvectorWrapperType = typename EigenvectorWrapperChooser<MomentBasis, AnalyticalFluxType>::type; + using ReconstructionOperatorType = +#if USE_FULL_LINEAR_RECONSTRUCTION_OPERATOR + LinearReconstructionOperator<AnalyticalFluxType, BoundaryValueType, GV, MatrixType, EigenvectorWrapperType>; +#else + PointwiseLinearReconstructionOperator<AnalyticalFluxType, + BoundaryValueType, + GV, + VectorType, + EigenvectorWrapperType>; +#endif + + using ReconstructionFvOperatorType = +#if USE_FULL_LINEAR_RECONSTRUCTION_OPERATOR + AdvectionWithReconstructionOperator<AdvectionOperatorType, ReconstructionOperatorType>; +#else + AdvectionWithPointwiseReconstructionOperator<AdvectionOperatorType, ReconstructionOperatorType>; +#endif + using FvOperatorType = + std::conditional_t<TestCaseType::reconstruction, ReconstructionFvOperatorType, AdvectionOperatorType>; + using OperatorTimeStepperType = + ExplicitRungeKuttaTimeStepper<FvOperatorType, + DiscreteFunctionType, + TimeStepperMethods::explicit_rungekutta_second_order_ssp>; + using RhsTimeStepperType = KineticIsotropicTimeStepper<DiscreteFunctionType, MomentBasis>; + using TimeStepperType = StrangSplittingTimeStepper<RhsTimeStepperType, OperatorTimeStepperType>; + + // *************** choose t_end and initial dt ************************************** + // calculate dx and choose initial dt + Dune::XT::Grid::Dimensions<GV> dimensions(grid_view); + RangeFieldType dx = dimensions.entity_width.max(); + if (dimDomain == 2) + dx /= std::sqrt(2); + if (dimDomain == 3) + dx /= std::sqrt(3); + RangeFieldType dt = CFL * dx; + + // *********************** create operators and timesteppers ************************************ + NumericalKineticFlux<GV, MomentBasis> numerical_flux(*analytical_flux, *basis_functions); + // NumericalLaxFriedrichsFlux<I, dimDomain, dimRange, RangeFieldType> numerical_flux(*analytical_flux, 1.); + AdvectionOperatorType advection_operator(grid_view, numerical_flux, advection_source_space, fv_space); + // boundary treatment + using BoundaryOperator = + LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator<I, VectorType, GV, dimRange>; + using LambdaType = typename BoundaryOperator::LambdaType; + using StateType = typename BoundaryOperator::StateType; + LambdaType boundary_lambda = + [&boundary_values](const I& intersection, + const FieldVector<RangeFieldType, dimDomain - 1>& xx_in_reference_intersection_coordinates, + const AnalyticalFluxType& /*flux*/, + const StateType& /*u*/, + const XT::Common::Parameter& /*param*/) { + return boundary_values->evaluate(intersection.geometry().global(xx_in_reference_intersection_coordinates)); + }; + XT::Grid::ApplyOn::NonPeriodicBoundaryIntersections<GV> filter; + advection_operator.append(boundary_lambda, {}, filter); + + MinmodSlope<E, EigenvectorWrapperType> slope; + ReconstructionOperatorType reconstruction_operator(*analytical_flux, *boundary_values, fv_space, slope, true); + + ReconstructionFvOperatorType reconstruction_fv_operator(advection_operator, reconstruction_operator); + FvOperatorType& fv_operator = + FvOperatorChooser<TestCaseType::reconstruction>::choose(advection_operator, reconstruction_fv_operator); + + if (!filename.empty()) + filename += "_"; + filename += ProblemType::static_id(); + filename += "_grid_" + grid_config["num_elements"]; + filename += "_tend_" + XT::Common::to_string(t_end); + filename += TestCaseType::reconstruction ? "_ord2" : "_ord1"; + filename += "_" + basis_functions->pn_name(); + + // ******************************** do the time steps *********************************************************** + const auto sigma_a = problem.sigma_a(); + const auto sigma_s = problem.sigma_s(); + const auto Q = problem.Q(); + OperatorTimeStepperType timestepper_op(fv_operator, u, -1.0); + RhsTimeStepperType timestepper_rhs(*basis_functions, u, *sigma_a, *sigma_s, *Q); + TimeStepperType timestepper(timestepper_rhs, timestepper_op); + + auto begin_time = std::chrono::steady_clock::now(); + timestepper.solve(t_end, + dt, + num_save_steps, + num_output_steps, + false, + true, + true, + false, + filename, + *basis_functions->visualizer(), + basis_functions->stringifier()); + auto end_time = std::chrono::steady_clock::now(); + std::chrono::duration<double> time_diff = end_time - begin_time; + if (grid_view.comm().rank() == 0) + std::cout << "Solving took: " << XT::Common::to_string(time_diff.count(), 15) << " s" << std::endl; + + FieldVector<double, 3> ret(0); + double& l1norm = ret[0]; + double& l2norm = ret[1]; + double& linfnorm = ret[2]; + const auto& current_sol = timestepper.current_solution(); + const auto local_sol = current_sol.local_function(); + for (const auto& entity : elements(grid_view, Dune::Partitions::interior)) { + local_sol->bind(entity); + const auto val = local_sol->evaluate(entity.geometry().local(entity.geometry().center())); + RangeFieldType psi = basis_functions->density(val); + l1norm += std::abs(psi) * entity.geometry().volume(); + l2norm += std::pow(psi, 2) * entity.geometry().volume(); + linfnorm = std::max(std::abs(psi), linfnorm); + } + l1norm = grid_view.comm().sum(l1norm); + l2norm = grid_view.comm().sum(l2norm); + linfnorm = grid_view.comm().max(linfnorm); + l2norm = std::sqrt(l2norm); + return ret; + } +}; + +template <class TestCaseType> +struct HyperbolicPnTest + : public HyperbolicPnDiscretization<TestCaseType> + , public ::testing::Test +{ + void run() + { + auto norms = + HyperbolicPnDiscretization<TestCaseType>::run(1, 0, size_t(-1), size_t(-1), "", 2, TestCaseType::t_end, "test"); + const double l1norm = norms[0]; + const double l2norm = norms[1]; + const double linfnorm = norms[2]; + using ResultsType = typename TestCaseType::ExpectedResultsType; + EXPECT_NEAR(ResultsType::l1norm, l1norm, ResultsType::l1norm * ResultsType::tol); + EXPECT_NEAR(ResultsType::l2norm, l2norm, ResultsType::l2norm * ResultsType::tol); + EXPECT_NEAR(ResultsType::linfnorm, linfnorm, ResultsType::linfnorm * ResultsType::tol); + } +}; + +#endif // DUNE_GDT_TEST_HYPERBOLIC_PN_DISCRETIZATION_HH diff --git a/dune/gdt/test/momentmodels/triangulation.hh b/dune/gdt/test/momentmodels/triangulation.hh new file mode 100644 index 0000000000000000000000000000000000000000..d70891f9cda028b8aaea981a138a19a57a015497 --- /dev/null +++ b/dune/gdt/test/momentmodels/triangulation.hh @@ -0,0 +1,477 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2017) +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_MOMENTMODELS_TRIANGULATION_HH +#define DUNE_GDT_MOMENTMODELS_TRIANGULATION_HH + +#include <memory> +#include <vector> +#include <string> +#include <mutex> + +#include <dune/common/typetraits.hh> + +#include <dune/geometry/quadraturerules.hh> + +#include <dune/xt/common/fvector.hh> + +namespace Dune { +namespace GDT { + + +template <class FieldType, size_t dimDomain> +class Vertex +{ +public: + using DomainType = XT::Common::FieldVector<FieldType, dimDomain>; + + Vertex() = default; + + Vertex(const DomainType& pos, const size_t index) + : position_(pos) + , index_(index) + {} + + const DomainType& position() const + { + return position_; + } + + DomainType& position() + { + return position_; + } + + size_t index() const + { + return index_; + } + + void set_child_with(const std::shared_ptr<Vertex>& parent, std::shared_ptr<Vertex>& child) + { + children_.insert({parent->index(), child}); + } + + bool has_child_with(const std::shared_ptr<Vertex>& parent) + { + return children_.count(parent->index()); + } + + const std::shared_ptr<Vertex>& child(const std::shared_ptr<Vertex>& parent) + { + return children_[parent->index()]; + } + +private: + DomainType position_; + size_t index_; + std::map<size_t, std::shared_ptr<Vertex>> children_; +}; // class Vertex + +template <class RangeFieldImp = double> +class SphericalTriangle +{ + using ThisType = SphericalTriangle; + +public: + using RangeFieldType = RangeFieldImp; + using VertexType = Vertex<RangeFieldType, 3>; + using DomainType = typename VertexType::DomainType; + using TriangulationVerticesVectorType = typename std::vector<std::shared_ptr<VertexType>>; + using VertexVectorType = typename XT::Common::FieldVector<std::shared_ptr<VertexType>, 3>; + using SubtrianglesVectorType = typename XT::Common::FieldVector<std::shared_ptr<ThisType>, 4>; + using QuadraturePointType = QuadraturePoint<RangeFieldType, 3>; + using QuadratureRuleType = QuadratureRule<RangeFieldType, 3>; + using FieldVectorType = XT::Common::FieldVector<RangeFieldType, 3>; + + SphericalTriangle() = default; + SphericalTriangle(ThisType&& other) = default; + ThisType& operator=(ThisType&& other) = default; + + SphericalTriangle(TriangulationVerticesVectorType& triangulation_vertices, + const VertexVectorType& vertices, + std::shared_ptr<size_t> current_vertex_index, + std::shared_ptr<std::mutex> triangulation_vertices_mutex) + : triangulation_vertices_(triangulation_vertices) + , vertices_(vertices) + , current_vertex_index_(current_vertex_index) + , triangulation_vertices_mutex_(triangulation_vertices_mutex) + {} + + SphericalTriangle(TriangulationVerticesVectorType& triangulation_vertices, + const std::shared_ptr<VertexType> vertex_1, + const std::shared_ptr<VertexType> vertex_2, + const std::shared_ptr<VertexType> vertex_3, + std::shared_ptr<size_t> current_vertex_index, + std::shared_ptr<std::mutex> triangulation_vertices_mutex) + : triangulation_vertices_(triangulation_vertices) + , vertices_{vertex_1, vertex_2, vertex_3} + , current_vertex_index_(current_vertex_index) + , triangulation_vertices_mutex_(triangulation_vertices_mutex) + {} + + const SubtrianglesVectorType& subtriangles() const + { + return subtriangles_; + } + + SubtrianglesVectorType& subtriangles() + { + return subtriangles_; + } + + const VertexVectorType& vertices() + { + return vertices_; + } + + DomainType center() const + { + DomainType center = (vertices_[0]->position() + vertices_[1]->position() + vertices_[2]->position()) / 3.; + center /= center.two_norm(); + return center; + } + + QuadratureRuleType quadrature_rule(const QuadratureRule<RangeFieldType, 2>& reference_quadrature_rule) const + { + QuadratureRuleType quadrature_rule; + quadrature_rule.reserve(reference_quadrature_rule.size()); + const FieldVectorType vertices_1_minus_0 = vertices_[1]->position() - vertices_[0]->position(); + const FieldVectorType vertices_2_minus_0 = vertices_[2]->position() - vertices_[0]->position(); + FieldVectorType ff, partial_s_gg, partial_t_gg; + for (const auto& quad_point : reference_quadrature_rule) { + const auto& ref_pos = quad_point.position(); + const auto& ref_weight = quad_point.weight(); + // map point to spherical triangle + ff = vertices_[0]->position() + ref_pos[0] * vertices_1_minus_0 + ref_pos[1] * vertices_2_minus_0; + const RangeFieldType norm_ff = ff.two_norm(); + const RangeFieldType norm_ff_3 = std::pow(norm_ff, 3); + partial_s_gg = vertices_2_minus_0 / norm_ff - ff * ((ff * vertices_2_minus_0) / norm_ff_3); + partial_t_gg = vertices_1_minus_0 / norm_ff - ff * ((ff * vertices_1_minus_0) / norm_ff_3); + const RangeFieldType weight = XT::Common::cross_product(partial_s_gg, partial_t_gg).two_norm() * ref_weight; + quadrature_rule.emplace_back(ff / norm_ff, weight); + } + return quadrature_rule; + } + + void initialize_subtriangles() + { + if (!(subtriangles_[0])) { + std::lock_guard<std::mutex> vertices_lock(*triangulation_vertices_mutex_); + VertexVectorType midpoints; + for (size_t ii = 0; ii < 3; ++ii) { + auto& vertex1 = vertices_[ii]; + auto& vertex2 = vertices_[(1 + ii) % 3]; + DomainType midpoint_position = vertex1->position() + vertex2->position(); + midpoint_position /= midpoint_position.two_norm(); + if (vertex1->has_child_with(vertex2)) { + midpoints[ii] = vertex1->child(vertex2); + } else { + triangulation_vertices_.emplace_back( + std::make_shared<VertexType>(midpoint_position, (*current_vertex_index_)++)); + vertex1->set_child_with(vertex2, triangulation_vertices_.back()); + vertex2->set_child_with(vertex1, triangulation_vertices_.back()); + midpoints[ii] = triangulation_vertices_.back(); + } + } // ii + subtriangles_[0] = std::make_shared<ThisType>(triangulation_vertices_, + vertices_[0], + midpoints[0], + midpoints[2], + current_vertex_index_, + triangulation_vertices_mutex_); + subtriangles_[1] = std::make_shared<ThisType>(triangulation_vertices_, + vertices_[1], + midpoints[1], + midpoints[0], + current_vertex_index_, + triangulation_vertices_mutex_); + subtriangles_[2] = std::make_shared<ThisType>(triangulation_vertices_, + vertices_[2], + midpoints[2], + midpoints[1], + current_vertex_index_, + triangulation_vertices_mutex_); + subtriangles_[3] = std::make_shared<ThisType>(triangulation_vertices_, + midpoints[0], + midpoints[1], + midpoints[2], + current_vertex_index_, + triangulation_vertices_mutex_); + } + } // initialize_subtriangles() + +private: + TriangulationVerticesVectorType& triangulation_vertices_; + const VertexVectorType vertices_; + SubtrianglesVectorType subtriangles_; + std::shared_ptr<size_t> current_vertex_index_; + std::shared_ptr<std::mutex> triangulation_vertices_mutex_; +}; // class SphericalTriangle<...> + +template <class RangeFieldImp = double> +class SphericalTriangulation +{ +public: + using TriangleType = SphericalTriangle<RangeFieldImp>; + using TriangleVectorType = std::vector<std::shared_ptr<TriangleType>>; + using VertexVectorType = typename TriangleType::TriangulationVerticesVectorType; + using VertexType = typename TriangleType::VertexType; + using DomainType = typename VertexType::DomainType; + + static QuadratureRule<RangeFieldImp, 2> barycentre_rule() + { + QuadratureRule<RangeFieldImp, 2> ret; + ret.push_back(QuadraturePoint<RangeFieldImp, 2>({1. / 3., 1. / 3.}, 0.5)); + return ret; + } + + SphericalTriangulation() {} + + SphericalTriangulation(size_t num_refinements, + const std::vector<DomainType>& initial_points = + {{1., 0., 0.}, {-1., 0., 0.}, {0., 1., 0.}, {0., -1., 0.}, {0., 0., 1.}, {0., 0., -1.}}) + : current_vertex_index_(std::make_shared<size_t>(0)) + , all_vertices_mutex_(std::make_shared<std::mutex>()) + { + calculate_faces(initial_points); + refine(num_refinements); + } + + // Do not allow copying as the triangles hold references to the vectors in this class. + SphericalTriangulation(const SphericalTriangulation& other) = delete; + SphericalTriangulation(SphericalTriangulation&& other) = delete; + SphericalTriangulation& operator=(const SphericalTriangulation& other) = delete; + SphericalTriangulation& operator=(SphericalTriangulation&& other) = delete; + + const TriangleVectorType& faces() const + { + return faces_; + } + + TriangleVectorType& faces() + { + return faces_; + } + + const VertexVectorType& vertices() const + { + return vertices_; + } + + VertexVectorType& vertices() + { + return vertices_; + } + + // get indices of all faces that contain point + std::vector<size_t> get_face_indices(const DomainType& v) const + { + std::vector<size_t> face_indices; + assert(XT::Common::FloatCmp::eq(v * v, 1.)); + FieldMatrix<RangeFieldImp, 3, 3> vertices_matrix; + FieldMatrix<RangeFieldImp, 3, 3> determinant_matrix; + for (size_t kk = 0; kk < faces().size(); ++kk) { + const auto& face = faces_[kk]; + bool v_in_this_face = false; + bool second_check = true; + const auto& vertices = face->vertices(); + for (size_t ii = 0; ii < 3; ++ii) { + // if v is not on the same octant of the sphere as the vertices, return false + // assumes the triangulation is fine enough that vertices[ii]*vertices[jj] >= 0 for all triangles + const auto scalar_prod = v * vertices[ii]->position(); + if (XT::Common::FloatCmp::lt(scalar_prod, 0.)) { + second_check = false; + break; + } else if (XT::Common::FloatCmp::eq(scalar_prod, 1.)) { + v_in_this_face = true; + second_check = false; + break; + } + vertices_matrix[ii] = vertices[ii]->position(); + } // ii + + if (second_check) { + // Vertices are ordered counterclockwise, so if the point is inside the spherical triangle, + // the coordinate system formed by two adjacent vertices and v is always right-handed, i.e. + // the triple product is positive. + // The triple products that need to be positive are the determinants of the matrices (v1, v2, v), (v2, v3, v), + // (v3, v1, v), where vi is the ith vertex. Swapping two columns changes the sign of det, the matrices used + // below all have an even number of column swaps. + // The determinant is 0 iff v is on the same plane as the two vertices. Then, to be on the edge of the + // current face, v has be in between the two vertices, i.e. v = x * v1 + y * v2 with x, y >= 0. This is + // equivalent to v * v1 >= (v*v2)v2 * v1 && v * v2 >= (v*v1)v1 * v2 (the projection of v to v1 has to be + // greater than the projection of its v2-projection to v1). + v_in_this_face = true; + for (size_t ii = 0; ii < 3; ++ii) { + determinant_matrix = vertices_matrix; + determinant_matrix[ii] = v; + auto det = determinant_matrix.determinant(); + if (XT::Common::FloatCmp::eq(det, 0.)) { + const auto& v1 = vertices_matrix[(ii + 1) % 3]; + const auto& v2 = vertices_matrix[(ii + 2) % 3]; + v_in_this_face = v * v1 > (v * v2) * (v2 * v1) && v * v2 > (v * v1) * (v1 * v2) ? true : false; + break; + } else if (det < 0.) { + v_in_this_face = false; + break; + } + } // ii + } // if (second_check) + if (v_in_this_face) + face_indices.push_back(kk); + } // faces + assert(face_indices.size()); + return face_indices; + } + + std::vector<QuadratureRule<RangeFieldImp, 3>> + quadrature_rules(size_t refinements = 0, + const QuadratureRule<RangeFieldImp, 2>& reference_quadrature_rule = barycentre_rule()) const + { + std::vector<TriangleVectorType> quadrature_faces = get_subtriangles(refinements); + std::vector<QuadratureRule<RangeFieldImp, 3>> ret(faces_.size()); + for (size_t jj = 0; jj < faces_.size(); ++jj) { + for (size_t ii = 0; ii < quadrature_faces[jj].size(); ++ii) { + const auto quad_rule = quadrature_faces[jj][ii]->quadrature_rule(reference_quadrature_rule); + ret[jj].insert(ret[jj].end(), quad_rule.begin(), quad_rule.end()); + } + } + return ret; + } + + // This returns a vector, which contains for each face kk a FieldVector<size_t, 3> of the + // indices of the faces that correspond to face kk when it is reflected in direction ii, + // i.e. reflected_face_indices()[kk][0] is the index of the face which is the result of + // reflecting face kk through the y-z Plane. + const std::vector<XT::Common::FieldVector<size_t, 3>>& reflected_face_indices() const + { + return reflected_face_indices_; + } + +private: + void refine(size_t times = 1) + { + set_faces_to_subtriangles(times); + vertices_ = all_vertices_; + calculate_reflected_faces(); + } // void refine(...) + + std::vector<TriangleVectorType> get_subtriangles(const size_t refinements = 1) const + { + std::vector<TriangleVectorType> ret(faces_.size()); + for (size_t jj = 0; jj < faces_.size(); ++jj) { + TriangleVectorType subtriangles(1, faces_[jj]); + size_t refs = refinements; + while (refs-- > 0) + get_subtriangles(subtriangles); + ret[jj] = subtriangles; + } // jj + return ret; + } // ... get_subtriangles(...) + + void get_subtriangles(TriangleVectorType& subtriangles) const + { + const size_t old_size = subtriangles.size(); + subtriangles.resize(4. * old_size); + for (size_t ii = 0; ii < old_size; ++ii) { + subtriangles[ii]->initialize_subtriangles(); + const auto& local_subtriangles = subtriangles[ii]->subtriangles(); + for (size_t jj = 0; jj < 4; ++jj) + subtriangles[(3 - jj) * old_size + ii] = local_subtriangles[jj]; + } + } + + void set_faces_to_subtriangles(size_t refinements = 1) + { + while (refinements-- > 0) + get_subtriangles(faces_); + } + + void calculate_faces(const std::vector<DomainType>& points0) + { + for (const auto& point : points0) + all_vertices_.emplace_back(std::make_shared<VertexType>(point, (*current_vertex_index_)++)); + vertices_ = all_vertices_; + const auto all_vertices = all_vertices_; + auto vertices0 = all_vertices_; + while (vertices0.size() > 0) { + const auto v0 = vertices0.back(); + vertices0.pop_back(); + auto vertices1 = vertices0; + while (vertices1.size() > 0) { + const auto v1 = vertices1.back(); + vertices1.pop_back(); + for (const auto& v2 : vertices1) { + // calculate plane equation defined by three points + const DomainType v0v1 = v1->position() - v0->position(); + const DomainType v0v2 = v2->position() - v0->position(); + const DomainType normal = XT::Common::cross_product(v0v1, v0v2); + if (XT::Common::FloatCmp::ne(normal.two_norm2(), 0.)) { + bool is_face = true; + double max_value = std::numeric_limits<double>::lowest(); + double min_value = std::numeric_limits<double>::max(); + for (const auto& v3 : all_vertices) { + const auto v0v3 = v3->position() - v0->position(); + const auto value = normal * v0v3; + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + if (XT::Common::FloatCmp::lt(min_value * max_value, 0.)) { + is_face = false; + break; + } + } // p3 + if (is_face) { + // if max_value is <= 0, all values are less or equal zero, + // i.e the normal points outwards and thus p0, p1, p2 are oriented counterclockwise, which is what we want + if (XT::Common::FloatCmp::le(max_value, 0.)) + faces_.emplace_back(std::make_shared<TriangleType>( + all_vertices_, v0, v1, v2, current_vertex_index_, all_vertices_mutex_)); + else + faces_.emplace_back(std::make_shared<TriangleType>( + all_vertices_, v0, v2, v1, current_vertex_index_, all_vertices_mutex_)); + } // if (is_face) + } // check if points define a plane + } // p2 + } // p1 + } // p0 + calculate_reflected_faces(); + } // void calculate_faces(...) + + void calculate_reflected_faces() + { + reflected_face_indices_.resize(faces_.size()); + for (size_t kk = 0; kk < faces_.size(); ++kk) { + const auto midpoint_rule = faces_[kk]->quadrature_rule(barycentre_rule()); + assert(midpoint_rule.size() == 1); + for (size_t ii = 0; ii < 3; ++ii) { + auto midpoint_reflected_in_dir_ii = midpoint_rule[0].position(); + midpoint_reflected_in_dir_ii[ii] = -midpoint_reflected_in_dir_ii[ii]; + auto reflected_index = get_face_indices(midpoint_reflected_in_dir_ii); + assert(reflected_index.size() == 1); + reflected_face_indices_[kk][ii] = reflected_index[0]; + } + } + } + + TriangleVectorType faces_; + VertexVectorType vertices_; + VertexVectorType all_vertices_; + std::shared_ptr<size_t> current_vertex_index_; + std::vector<XT::Common::FieldVector<size_t, 3>> reflected_face_indices_; + std::shared_ptr<std::mutex> all_vertices_mutex_; +}; // class SphericalTriangulation<...> + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_MOMENTMODELS_TRIANGULATION_HH diff --git a/dune/gdt/test/operators/oswald-interpolation.hh b/dune/gdt/test/operators/oswald-interpolation.hh index 19ba54d87673b9162148bb057387636f231312d1..b8845f82625022a890c7af15a701caa9585075c9 100644 --- a/dune/gdt/test/operators/oswald-interpolation.hh +++ b/dune/gdt/test/operators/oswald-interpolation.hh @@ -33,7 +33,7 @@ #include <dune/gdt/local/bilinear-forms/integrals.hh> #include <dune/gdt/local/functionals/integrals.hh> #include <dune/gdt/local/integrands/abs.hh> -#include <dune/gdt/local/integrands/elliptic.hh> +#include <dune/gdt/local/integrands/laplace.hh> #include <dune/gdt/local/integrands/product.hh> #include <dune/gdt/operators/localizable-operator.hh> #include <dune/gdt/operators/oswald-interpolation.hh> @@ -253,7 +253,7 @@ struct OswaldInterpolationOperatorOnLeafViewTest : public ::testing::Test auto local_difference = difference.local_function(); local_difference->bind(element); auto local_indicator = h1_element_indicators.local_discrete_function(element); - local_indicator->dofs()[0] += LocalElementIntegralBilinearForm<E>(LocalEllipticIntegrand<E>(1.)) + local_indicator->dofs()[0] += LocalElementIntegralBilinearForm<E>(LocalLaplaceIntegrand<E>(1.)) .apply2(*local_difference, *local_difference)[0][0]; }, []() {}); @@ -376,6 +376,8 @@ template <class G> struct OswaldInterpolationOperatorOnCubicLeafViewTest : public OswaldInterpolationOperatorOnLeafViewTest<G> { using BaseType = OswaldInterpolationOperatorOnLeafViewTest<G>; + using BaseType::d; + using typename BaseType::D; using typename BaseType::E; using typename BaseType::GV; using typename BaseType::M; @@ -385,8 +387,6 @@ struct OswaldInterpolationOperatorOnCubicLeafViewTest : public OswaldInterpolati std::shared_ptr<XT::Grid::GridProvider<G>> make_grid() override final { - using D = typename G::ctype; - static const constexpr size_t d = G::dimension; FieldVector<D, d> lower_left(0.); auto upper_right = XT::Common::from_string<FieldVector<double, d>>("[3 1 1 1]"); std::array<unsigned int, d> num_elements; diff --git a/dune/gdt/test/spaces/base.hh b/dune/gdt/test/spaces/base.hh index fbbefbba18cac2212a184179987882ec33c2107f..30ad635280e53d1614499679a9459637b39a4aff 100644 --- a/dune/gdt/test/spaces/base.hh +++ b/dune/gdt/test/spaces/base.hh @@ -49,6 +49,7 @@ struct SpaceTestBase : public ::testing::Test using R = typename SpaceType::R; static const constexpr size_t r = SpaceType::r; static const constexpr size_t rC = SpaceType::rC; + static constexpr double default_tolerance = p > 2 ? (d > 3 ? 1e-7 : (d == 3 ? 1e-10 : 1e-13)) : 1e-15; using GlobalBasisType = typename SpaceType::GlobalBasisType; using MapperType = typename SpaceType::MapperType; @@ -98,7 +99,7 @@ struct SpaceTestBase : public ::testing::Test space->finite_elements().get(geometry_type, p).lagrange_points().size()); } - void basis_is_lagrange_basis(const double& tolerance = 1e-15) + void basis_is_lagrange_basis(const double tolerance = default_tolerance) { ASSERT_NE(grid_view, nullptr); ASSERT_NE(space, nullptr); @@ -226,7 +227,7 @@ struct SpaceTestBase : public ::testing::Test EXPECT_EQ(1, map_to_global.count(global_index)); } // ... mapper_of_discontinuous_space_maps_correctly(...) - void local_interpolation_seems_to_be_correct() + void local_interpolation_seems_to_be_correct(const double tolerance = default_tolerance) { ASSERT_NE(grid_view, nullptr); ASSERT_NE(space, nullptr); @@ -240,7 +241,7 @@ struct SpaceTestBase : public ::testing::Test [&](const auto& x) { return shape_functions.evaluate(x)[ii]; }, shape_functions.order()); ASSERT_GE(dofs.size(), shape_functions.size()); for (size_t jj = 0; jj < shape_functions.size(); ++jj) - EXPECT_TRUE(XT::Common::FloatCmp::eq(ii == jj ? 1. : 0., dofs[jj])) + EXPECT_TRUE(XT::Common::FloatCmp::eq(ii == jj ? 1. : 0., dofs[jj], tolerance, tolerance)) << "\nii == jj ? 1. : 0. = " << (ii == jj ? 1. : 0.) << "\ndofs[jj] = " << dofs[jj]; } } diff --git a/dune/gdt/test/spaces/h1_continuous_lagrange.hh b/dune/gdt/test/spaces/h1_continuous_lagrange.hh index ba11ed9169842d3fa4d62f2776fd01849705c6fb..e2fa806d0b764cae11c371aa19e42bc508d57872 100644 --- a/dune/gdt/test/spaces/h1_continuous_lagrange.hh +++ b/dune/gdt/test/spaces/h1_continuous_lagrange.hh @@ -70,7 +70,7 @@ struct ContinuousLagrangeSpaceTest std::set<size_t> global_DoF_indices; for (const auto& entry : global_lagrange_point_to_global_indices_map) { const auto global_DoF_indices_per_point = entry.second; - EXPECT_EQ(global_DoF_indices_per_point.size(), 1); + EXPECT_EQ(1, global_DoF_indices_per_point.size()); global_DoF_indices.insert(*(global_DoF_indices_per_point.begin())); } EXPECT_EQ(global_lagrange_point_to_global_indices_map.size(), global_DoF_indices.size()); diff --git a/dune/gdt/test/spaces/spaces_h1_continuous_lagrange__cubic_grids.cc b/dune/gdt/test/spaces/spaces_h1_continuous_lagrange__cubic_grids.cc index b75e6053b6a99b99d54c21ef80895107c2456447..9e523211dbb1ff9301918d798ce69ce785b40c13 100644 --- a/dune/gdt/test/spaces/spaces_h1_continuous_lagrange__cubic_grids.cc +++ b/dune/gdt/test/spaces/spaces_h1_continuous_lagrange__cubic_grids.cc @@ -60,3 +60,48 @@ TYPED_TEST(Order2CubicContinuousLagrangeSpace, local_interpolation_seems_to_be_c { this->local_interpolation_seems_to_be_correct(); } + + +template <class G> +using Order3CubicContinuousLagrangeSpace = ContinuousLagrangeSpaceOnCubicLeafViewTest<G, 1, double, 3>; +TYPED_TEST_CASE(Order3CubicContinuousLagrangeSpace, CubicGrids); +TYPED_TEST(Order3CubicContinuousLagrangeSpace, gives_correct_identification) +{ + this->gives_correct_identification(); +} +TYPED_TEST(Order3CubicContinuousLagrangeSpace, basis_exists_on_each_element_with_correct_size) +{ + this->basis_of_lagrange_space_exists_on_each_element_with_correct_size(); +} +TYPED_TEST(Order3CubicContinuousLagrangeSpace, basis_exists_on_each_element_with_correct_order) +{ + this->basis_of_lagrange_space_exists_on_each_element_with_correct_order(); +} +TYPED_TEST(Order3CubicContinuousLagrangeSpace, mapper_reports_correct_num_DoFs_on_each_element) +{ + this->mapper_reports_correct_num_DoFs_of_lagrange_space_on_each_element(); +} +TYPED_TEST(Order3CubicContinuousLagrangeSpace, mapper_reports_correct_max_num_DoFs) +{ + this->mapper_reports_correct_max_num_DoFs(); +} +TYPED_TEST(Order3CubicContinuousLagrangeSpace, mapper_maps_correctly) +{ + this->mapper_maps_correctly(); +} +TYPED_TEST(Order3CubicContinuousLagrangeSpace, lagrange_points_exist_on_each_element_with_correct_size) +{ + this->lagrange_points_exist_on_each_element_with_correct_size(); +} +TYPED_TEST(Order3CubicContinuousLagrangeSpace, basis_is_lagrange_basis) +{ + this->basis_is_lagrange_basis(); +} +TYPED_TEST(Order3CubicContinuousLagrangeSpace, basis_jacobians_seem_to_be_correct) +{ + this->template basis_jacobians_of_lagrange_space_seem_to_be_correct<>(); +} +TYPED_TEST(Order3CubicContinuousLagrangeSpace, local_interpolation_seems_to_be_correct) +{ + this->local_interpolation_seems_to_be_correct(); +} diff --git a/dune/gdt/test/spaces/spaces_hdiv_raviart_thomas.cc b/dune/gdt/test/spaces/spaces_hdiv_raviart_thomas.cc index 8036a88d95ef9e8b62a10a9bacaf16f36fb4c4a3..64fbca0d078829ebfb099a2aa3cc72f7c4e54c3f 100644 --- a/dune/gdt/test/spaces/spaces_hdiv_raviart_thomas.cc +++ b/dune/gdt/test/spaces/spaces_hdiv_raviart_thomas.cc @@ -398,14 +398,15 @@ struct RtSpaceOnCubicLeafView : public RtSpace<typename Dune::XT::Grid::GridProv { using GridProviderType = Dune::XT::Grid::GridProvider<G>; using LeafGridViewType = typename GridProviderType::LeafGridViewType; + using BaseType = RtSpace<typename Dune::XT::Grid::GridProvider<G>::LeafGridViewType, p>; + using BaseType::d; + using typename BaseType::D; std::shared_ptr<GridProviderType> grid_provider; std::shared_ptr<LeafGridViewType> leaf_view; RtSpaceOnCubicLeafView() { - using D = typename G::ctype; - static const constexpr size_t d = G::dimension; Dune::FieldVector<D, d> lower_left(-1.5); // (i) negative coordinates and not the same as the reference element Dune::FieldVector<D, d> upper_right(-1.); std::array<unsigned int, d> num_elements; // (ii) at least 3 elements to have fully inner ones @@ -495,14 +496,15 @@ struct RtSpaceOnMixedLeafView : public RtSpace<typename Dune::XT::Grid::GridProv { using GridProviderType = Dune::XT::Grid::GridProvider<G>; using LeafGridViewType = typename GridProviderType::LeafGridViewType; + using BaseType = RtSpace<typename Dune::XT::Grid::GridProvider<G>::LeafGridViewType, p>; + using BaseType::d; + using typename BaseType::D; std::shared_ptr<GridProviderType> grid_provider; std::shared_ptr<LeafGridViewType> leaf_view; RtSpaceOnMixedLeafView() { - using D = typename G::ctype; - static const constexpr size_t d = G::dimension; switch (d) { case 1: { // cannot use ASSERT_... in a ctor diff --git a/dune/gdt/test/spaces/spaces_l2_finite_volume.cc b/dune/gdt/test/spaces/spaces_l2_finite_volume.cc index 1f3a6cfeb1b12593e0922f5d0aa09ac2d92e9ad3..8caf7032fd254bb10174132933657881a2a66c87 100644 --- a/dune/gdt/test/spaces/spaces_l2_finite_volume.cc +++ b/dune/gdt/test/spaces/spaces_l2_finite_volume.cc @@ -254,14 +254,15 @@ struct FiniteVolumeSpaceOnCubicLeafView { using GridProviderType = Dune::XT::Grid::GridProvider<G>; using LeafGridViewType = typename GridProviderType::LeafGridViewType; + using BaseType = FiniteVolumeSpace<typename Dune::XT::Grid::GridProvider<G>::LeafGridViewType, r>; + using BaseType::d; + using typename BaseType::D; std::shared_ptr<GridProviderType> grid_provider; std::shared_ptr<LeafGridViewType> leaf_view; FiniteVolumeSpaceOnCubicLeafView() { - using D = typename G::ctype; - static const constexpr size_t d = G::dimension; Dune::FieldVector<D, d> lower_left(-1.5); // (i) negative coordinates and not the same as the reference element Dune::FieldVector<D, d> upper_right(-1.); std::array<unsigned int, d> num_elements; // (ii) at least 3 elements to have fully inner ones @@ -345,14 +346,15 @@ struct FiniteVolumeSpaceOnPrismLeafView { using GridProviderType = Dune::XT::Grid::GridProvider<G>; using LeafGridViewType = typename GridProviderType::LeafGridViewType; + using BaseType = FiniteVolumeSpace<typename Dune::XT::Grid::GridProvider<G>::LeafGridViewType, r>; + using BaseType::d; + using typename BaseType::D; std::shared_ptr<GridProviderType> grid_provider; std::shared_ptr<LeafGridViewType> leaf_view; FiniteVolumeSpaceOnPrismLeafView() { - using D = typename G::ctype; - static const constexpr size_t d = G::dimension; if (d == 3) { Dune::GridFactory<G> factory; for (auto&& vertex : {Dune::XT::Common::FieldVector<D, d>({-1., -1.5, -1.5}), @@ -435,14 +437,15 @@ struct FiniteVolumeSpaceOnPyramidLeafView { using GridProviderType = Dune::XT::Grid::GridProvider<G>; using LeafGridViewType = typename GridProviderType::LeafGridViewType; + using BaseType = FiniteVolumeSpace<typename Dune::XT::Grid::GridProvider<G>::LeafGridViewType, r>; + using BaseType::d; + using typename BaseType::D; std::shared_ptr<GridProviderType> grid_provider; std::shared_ptr<LeafGridViewType> leaf_view; FiniteVolumeSpaceOnPyramidLeafView() { - using D = typename G::ctype; - static const constexpr size_t d = G::dimension; if (d == 3) { Dune::GridFactory<G> factory; for (auto&& vertex : {Dune::XT::Common::FieldVector<D, d>({0, 0, 0}), @@ -524,14 +527,15 @@ struct FiniteVolumeSpaceOnMixedLeafView { using GridProviderType = Dune::XT::Grid::GridProvider<G>; using LeafGridViewType = typename GridProviderType::LeafGridViewType; + using BaseType = FiniteVolumeSpace<typename Dune::XT::Grid::GridProvider<G>::LeafGridViewType, r>; + using BaseType::d; + using typename BaseType::D; std::shared_ptr<GridProviderType> grid_provider; std::shared_ptr<LeafGridViewType> leaf_view; FiniteVolumeSpaceOnMixedLeafView() { - using D = typename G::ctype; - static const constexpr size_t d = G::dimension; switch (d) { case 1: { // cannot use ASSERT_... in a ctor diff --git a/dune/gdt/test/stationary-eocstudies/base.hh b/dune/gdt/test/stationary-eocstudies/base.hh index 86295d83fb9f443adfb8ea9b693ee1c848043db7..dbb19d99e4039f5d8ede975dc1f24d82fa69c19b 100644 --- a/dune/gdt/test/stationary-eocstudies/base.hh +++ b/dune/gdt/test/stationary-eocstudies/base.hh @@ -36,7 +36,7 @@ #include <dune/gdt/local/bilinear-forms/integrals.hh> #include <dune/gdt/local/functionals/integrals.hh> #include <dune/gdt/local/integrands/abs.hh> -#include <dune/gdt/local/integrands/elliptic.hh> +#include <dune/gdt/local/integrands/laplace.hh> #include <dune/gdt/local/integrands/identity.hh> #include <dune/gdt/local/integrands/product.hh> #include <dune/gdt/operators/constant.hh> @@ -101,33 +101,33 @@ public: , reference_solution_on_reference_grid_(nullptr) {} - virtual size_t num_refinements() const override + size_t num_refinements() const override { return num_refinements_; } - virtual std::vector<std::string> targets() const override + std::vector<std::string> targets() const override { return {"h"}; } - virtual std::vector<std::string> norms() const override + std::vector<std::string> norms() const override { // We currently support the following norms: L_1, L_2, H_1_semi return {"L_2", "H_1_semi"}; } - virtual std::vector<std::pair<std::string, std::string>> estimates() const override + std::vector<std::pair<std::string, std::string>> estimates() const override { return {}; } - virtual std::vector<std::string> quantities() const override + std::vector<std::string> quantities() const override { return {"time to solution (s)"}; } - virtual std::string discretization_info_title() const override + std::string discretization_info_title() const override { return " |grid| | #DoFs"; } @@ -138,7 +138,7 @@ protected: virtual std::unique_ptr<S> make_space(const GP& current_grid) = 0; public: - virtual std::string discretization_info(const size_t refinement_level) override + std::string discretization_info(const size_t refinement_level) override { if (current_refinement_ != refinement_level) { // clear the current state @@ -266,7 +266,7 @@ public: spatial_norm = [&](const DF& func) { auto localizable_product = make_localizable_bilinear_form(reference_space.grid_view(), func, func); localizable_product.append(LocalElementIntegralBilinearForm<E, m>( - LocalEllipticIntegrand<E, m>(), DXTC_TEST_CONFIG_GET("setup.over_integrate", 3))); + LocalLaplaceIntegrand<E, m>(), DXTC_TEST_CONFIG_GET("setup.over_integrate", 3))); localizable_product.assemble(DXTC_TEST_CONFIG_GET("setup.use_tbb", true)); return std::sqrt(localizable_product.result()); }; diff --git a/dune/gdt/test/stationary-eocstudies/diffusion-ipdg.hh b/dune/gdt/test/stationary-eocstudies/diffusion-ipdg.hh index 3625a2f6ee3c7b5fbca25283658c5465f925139f..6ac3c8bf29639fbe2c55ba0dd4cb6a273402d5f4 100644 --- a/dune/gdt/test/stationary-eocstudies/diffusion-ipdg.hh +++ b/dune/gdt/test/stationary-eocstudies/diffusion-ipdg.hh @@ -27,8 +27,9 @@ #include <dune/gdt/functionals/vector-based.hh> #include <dune/gdt/local/functionals/integrals.hh> #include <dune/gdt/local/bilinear-forms/integrals.hh> -#include <dune/gdt/local/integrands/elliptic-ipdg.hh> -#include <dune/gdt/local/integrands/elliptic.hh> +#include <dune/gdt/local/integrands/laplace.hh> +#include <dune/gdt/local/integrands/laplace-ipdg.hh> +#include <dune/gdt/local/integrands/ipdg.hh> #include <dune/gdt/local/integrands/product.hh> #include <dune/gdt/local/integrands/conversion.hh> #include <dune/gdt/norms.hh> @@ -81,6 +82,7 @@ public: StationaryDiffusionIpdgEocStudy() : BaseType() , space_type_("") + , one_(1.) {} protected: @@ -89,13 +91,11 @@ protected: virtual const XT::Grid::BoundaryInfo<I>& boundary_info() const = 0; - virtual const FF& diffusion_factor() const = 0; - - virtual const FT& diffusion_tensor() const = 0; + virtual const FT& diffusion() const = 0; virtual const FF& force() const = 0; - virtual std::vector<std::string> norms() const override + std::vector<std::string> norms() const override { auto nrms = BaseType::norms(); nrms.push_back("eta_NC"); @@ -125,15 +125,15 @@ protected: if (DXTC_TEST_CONFIG_GET("setup.visualize", false)) { const std::string prefix = XT::Common::Test::get_unique_test_name() + "_problem_"; const std::string postfix = "_ref_" + XT::Common::to_string(refinement_level); - self.diffusion_factor().visualize(current_space.grid_view(), prefix + "diffusion_factor" + postfix); - self.diffusion_tensor().visualize(current_space.grid_view(), prefix + "diffusion_tensor" + postfix); + // self.diffusion_factor().visualize(current_space.grid_view(), prefix + "diffusion_factor" + postfix); + self.diffusion().visualize(current_space.grid_view(), prefix + "diffusion" + postfix); self.force().visualize(current_space.grid_view(), prefix + "force" + postfix); // self.dirichlet().visualize(current_space.grid_view(), prefix + "dirichlet" + postfix); // self.neumann().visualize(current_space.grid_view(), prefix + "neumann" + postfix); } Timer timer; const auto solution = make_discrete_function(current_space, self.solve(current_space)); - const auto diffusion = diffusion_factor() * diffusion_tensor(); + const auto& one = one_.template as_grid_function<E>(); // only set time if this did not happen in solve() if (self.current_data_["quantity"].count("time to solution (s)") == 0) self.current_data_["quantity"]["time to solution (s)"] = timer.elapsed(); @@ -146,21 +146,21 @@ protected: current_space.grid_view(), current_space, current_space, boundary_info()); oswald_interpolation_operator.assemble(/*parallel=*/true); const auto h1_interpolation = oswald_interpolation_operator.apply(solution); - self.current_data_["norm"][norm_id] = elliptic_norm( - current_space.grid_view(), diffusion_factor(), diffusion_tensor(), solution - h1_interpolation); + self.current_data_["norm"][norm_id] = + elliptic_norm(current_space.grid_view(), diffusion(), solution - h1_interpolation); } else if (norm_id == "eta_R") { norm_it = remaining_norms.erase(norm_it); // ... or here ... // compute estimate auto rt_space = make_raviart_thomas_space(current_space.grid_view(), current_space.max_polorder() - 1); auto reconstruction_op = make_ipdg_flux_reconstruction_operator<M, ipdg_method>( - current_space.grid_view(), current_space, rt_space, diffusion_factor(), diffusion_tensor()); + current_space.grid_view(), current_space, rt_space, one, diffusion()); auto flux_reconstruction = reconstruction_op.apply(solution); double eta_R_2 = 0.; std::mutex eta_R_2_mutex; auto walker = XT::Grid::make_walker(current_space.grid_view()); walker.append([]() {}, [&](const auto& element) { - auto local_df = diffusion.local_function(); + auto local_df = this->diffusion().local_function(); local_df->bind(element); auto local_force = this->force().local_function(); local_force->bind(element); @@ -201,40 +201,36 @@ protected: // compute estimate auto rt_space = make_raviart_thomas_space(current_space.grid_view(), current_space.max_polorder() - 1); auto reconstruction_op = make_ipdg_flux_reconstruction_operator<M, ipdg_method>( - current_space.grid_view(), current_space, rt_space, diffusion_factor(), diffusion_tensor()); + current_space.grid_view(), current_space, rt_space, one, diffusion()); auto flux_reconstruction = reconstruction_op.apply(solution); double eta_DF_2 = 0.; std::mutex eta_DF_2_mutex; auto walker = XT::Grid::make_walker(current_space.grid_view()); - walker.append([]() {}, - [&](const auto& element) { - auto local_df = this->diffusion_factor().local_function(); - local_df->bind(element); - auto local_dt = this->diffusion_tensor().local_function(); - local_dt->bind(element); - auto local_solution = solution.local_function(); - local_solution->bind(element); - auto local_reconstruction = flux_reconstruction.local_function(); - local_reconstruction->bind(element); - auto result = XT::Grid::element_integral( - element, - [&](const auto& xx) { - const auto df = local_df->evaluate(xx); - const auto dt = local_dt->evaluate(xx); - const auto diff = dt * df; - const auto diff_inv = XT::LA::invert_matrix(diff); - const auto solution_grad = local_solution->jacobian(xx)[0]; - const auto flux_rec = local_reconstruction->evaluate(xx); - auto difference = diff * solution_grad + flux_rec; - return (diff_inv * difference) * difference; - }, - std::max(local_df->order() + local_dt->order() + std::max(local_solution->order() - 1, 0), - local_reconstruction->order()) - + /*over_integrate=*/3); - std::lock_guard<std::mutex> lock(eta_DF_2_mutex); - eta_DF_2 += result; - }, - []() {}); + walker.append( + []() {}, + [&](const auto& element) { + auto local_df = this->diffusion().local_function(); + local_df->bind(element); + auto local_solution = solution.local_function(); + local_solution->bind(element); + auto local_reconstruction = flux_reconstruction.local_function(); + local_reconstruction->bind(element); + auto result = XT::Grid::element_integral( + element, + [&](const auto& xx) { + const auto diff = local_df->evaluate(xx); + const auto diff_inv = XT::LA::invert_matrix(diff); + const auto solution_grad = local_solution->jacobian(xx)[0]; + const auto flux_rec = local_reconstruction->evaluate(xx); + auto difference = diff * solution_grad + flux_rec; + return (diff_inv * difference) * difference; + }, + std::max(local_df->order() + std::max(local_solution->order() - 1, 0), local_reconstruction->order()) + + /*over_integrate=*/3); + std::lock_guard<std::mutex> lock(eta_DF_2_mutex); + eta_DF_2 += result; + }, + []() {}); walker.walk(/*parallel=*/true); self.current_data_["norm"][norm_id] = std::sqrt(eta_DF_2); } else @@ -244,7 +240,7 @@ protected: return BaseType::compute(refinement_level, remaining_norms, remaining_estimates, remaining_quantities); } // ... compute(...) - virtual std::unique_ptr<S> make_space(const GP& current_grid) override + std::unique_ptr<S> make_space(const GP& current_grid) override { if (space_type_ == "fv") return std::make_unique<FiniteVolumeSpace<GV>>(current_grid.leaf_view()); @@ -260,23 +256,35 @@ protected: } } // ... make_space(...) - virtual std::unique_ptr<O> make_residual_operator(const S& space) override + std::unique_ptr<O> make_residual_operator(const S& space) override { + const auto& one = one_.template as_grid_function<E>(); // define lhs operator (has to be a pointer to allow the residual operator to manage the memory in the end) auto lhs_op = std::make_unique<MatrixOperator<M, GV>>(make_matrix_operator<M>( space, (space_type_.size() >= 2 && space_type_.substr(0, 2) == "cg") ? Stencil::element : Stencil::element_and_intersection)); - lhs_op->append(LocalElementIntegralBilinearForm<E>( - LocalEllipticIntegrand<E>(this->diffusion_factor(), this->diffusion_tensor()))); - lhs_op->append(LocalIntersectionIntegralBilinearForm<I>(LocalEllipticIpdgIntegrands::Inner<I, double, ipdg_method>( - this->diffusion_factor(), this->diffusion_tensor())), + // - volume term + lhs_op->append(LocalElementIntegralBilinearForm<E>(LocalLaplaceIntegrand<E>(this->diffusion()))); + // - inner faces + lhs_op->append(LocalIntersectionIntegralBilinearForm<I>( + LocalLaplaceIPDGIntegrands::InnerCoupling<I>(1., this->diffusion(), this->diffusion())), {}, XT::Grid::ApplyOn::InnerIntersectionsOnce<GV>()); + lhs_op->append( + LocalIntersectionIntegralBilinearForm<I>(LocalIPDGIntegrands::InnerPenalty<I>( + 8, this->diffusion(), [](const auto& intersection) { return intersection.geometry().volume(); })), + {}, + XT::Grid::ApplyOn::InnerIntersectionsOnce<GV>()); + // - Dirichlet faces lhs_op->append( LocalIntersectionIntegralBilinearForm<I>( - LocalEllipticIpdgIntegrands::DirichletBoundaryLhs<I, double, ipdg_method>(this->diffusion_factor(), - this->diffusion_tensor())), + LocalLaplaceIPDGIntegrands::DirichletCoupling<I>(1., this->diffusion())), + {}, + XT::Grid::ApplyOn::CustomBoundaryIntersections<GV>(this->boundary_info(), new XT::Grid::DirichletBoundary())); + lhs_op->append( + LocalIntersectionIntegralBilinearForm<I>(LocalIPDGIntegrands::BoundaryPenalty<I>( + 14, this->diffusion(), [](const auto& intersection) { return intersection.geometry().volume(); })), {}, XT::Grid::ApplyOn::CustomBoundaryIntersections<GV>(this->boundary_info(), new XT::Grid::DirichletBoundary())); // define rhs functional @@ -297,6 +305,7 @@ protected: } // ... make_residual_operator(...) std::string space_type_; + XT::Functions::ConstantFunction<d> one_; }; // class StationaryDiffusionIpdgEocStudy diff --git a/dune/gdt/test/stationary-heat-equation/ESV2007.hh b/dune/gdt/test/stationary-heat-equation/ESV2007.hh index f3872f39ddf9f18fb3d25a974fd57c0f4e0fe1ac..390c8451f26ea47c824d7442acde6ad62bb81c88 100644 --- a/dune/gdt/test/stationary-heat-equation/ESV2007.hh +++ b/dune/gdt/test/stationary-heat-equation/ESV2007.hh @@ -48,8 +48,7 @@ struct ESV2007DiffusionProblem // We can only reproduce the results from ESV2007 by using a quadrature of order 3, which we obtain with a p1 DG space // and a force of order 2. ESV2007DiffusionProblem(int force_order = 2) - : diffusion_factor(1) - , diffusion_tensor(XT::LA::eye_matrix<XT::Common::FieldMatrix<double, d, d>>(d, d)) + : diffusion(XT::LA::eye_matrix<XT::Common::FieldMatrix<double, d, d>>(d, d)) , dirichlet(0) , neumann(0) , force(force_order) @@ -75,8 +74,7 @@ struct ESV2007DiffusionProblem EXPECT_TRUE(false) << "Please add a specialization for '" << XT::Common::Typename<G>::value << "'!"; } // ... make_initial_grid(...) - const XT::Functions::ConstantFunction<d> diffusion_factor; - const XT::Functions::ConstantFunction<d, d, d> diffusion_tensor; + const XT::Functions::ConstantFunction<d, d, d> diffusion; const XT::Functions::ConstantFunction<d> dirichlet; const XT::Functions::ConstantFunction<d> neumann; const XT::Functions::ESV2007::Testcase1Force<d, 1> force; @@ -144,14 +142,9 @@ protected: return problem.boundary_info; } - const FF& diffusion_factor() const override final + const FT& diffusion() const override final { - return problem.diffusion_factor.template as_grid_function<E>(); - } - - const FT& diffusion_tensor() const override final - { - return problem.diffusion_tensor.template as_grid_function<E>(); + return problem.diffusion.template as_grid_function<E>(); } const FF& force() const override final diff --git a/dune/gdt/test/stationary-heat-equation/stationary_heat_equation__ESV2007__table_1.cc b/dune/gdt/test/stationary-heat-equation/stationary_heat_equation__ESV2007__table_1.cc index a228d8e0412e5e1a03cea7efe1ad1a67d39c5cf6..440bbc40afed167af65e7601e85efdafefea933f 100644 --- a/dune/gdt/test/stationary-heat-equation/stationary_heat_equation__ESV2007__table_1.cc +++ b/dune/gdt/test/stationary-heat-equation/stationary_heat_equation__ESV2007__table_1.cc @@ -22,7 +22,9 @@ using namespace Dune; using namespace Dune::GDT::Test; -using ESV2007Table1Test = ESV2007DiffusionTest<ALU_2D_SIMPLEX_CONFORMING>; +#if SIMPLEXGRID_2D_AVAILABLE + +using ESV2007Table1Test = ESV2007DiffusionTest<SIMPLEXGRID_2D>; TEST_F(ESV2007Table1Test, columns_1_to_5) { this->space_type_ = "dg_p1"; @@ -30,3 +32,15 @@ TEST_F(ESV2007Table1Test, columns_1_to_5) const auto expected_results = DXTC_TEST_CONFIG_SUB("results"); XT::Test::check_eoc_study_for_success(expected_results, actual_results); } + +#endif // SIMPLEXGRID_2D_AVAILABLE + + +using NearlyESV2007Table1ButWithCubicGridTest = ESV2007DiffusionTest<CUBEGRID_2D>; +TEST_F(NearlyESV2007Table1ButWithCubicGridTest, columns_1_to_5) +{ + this->space_type_ = "dg_p1"; + const auto actual_results = this->run(); + const auto expected_results = DXTC_TEST_CONFIG_SUB("results"); + XT::Test::check_eoc_study_for_success(expected_results, actual_results); +} diff --git a/dune/gdt/test/stationary-heat-equation/stationary_heat_equation__ESV2007__table_1.mini b/dune/gdt/test/stationary-heat-equation/stationary_heat_equation__ESV2007__table_1.mini index 6f6bd6a3990e670c59147dda8ff618854b077fe5..74a38f7bb7f3c4ab755f4aedd8ab8c136e866b42 100644 --- a/dune/gdt/test/stationary-heat-equation/stationary_heat_equation__ESV2007__table_1.mini +++ b/dune/gdt/test/stationary-heat-equation/stationary_heat_equation__ESV2007__table_1.mini @@ -19,3 +19,18 @@ norm.eta_R = [7.23e-02 1.82e-02 4.54e-03] # 1.14e-03] # norm.eta_DF = [3.38e-01 1.69e-01 8.39e-02 4.18e-02] norm.eta_DF = [3.55e-01 1.76e-01 8.73e-02] # 4.35e-02] + +[NearlyESV2007Table1ButWithCubicGridTest.columns_1_to_5.setup] +force_order = 4 +over_integrate = 0 +num_refinements = 2 +num_additional_refinements_for_reference = 0 +reference_solution_order = 4 +use_tbb = false + +[NearlyESV2007Table1ButWithCubicGridTest.columns_1_to_5.results] +target.h = [3.54e-01 1.77e-01 8.84e-02] +norm.H_1_semi = [2.52e-01 1.26e-01 6.30e-02] +norm.eta_NC = [1.58e-02 4.40e-03 1.15e-03] +norm.eta_R = [8.85e-02 2.22e-02 5.56e-03] +norm.eta_DF = [3.51e-01 1.77e-01 8.90e-02] diff --git a/dune/gdt/test/stokes/stokes-taylorhood.hh b/dune/gdt/test/stokes/stokes-taylorhood.hh index dc471cb0902bc4a7606e16fb8cd6ab2342b29b69..d6bb86047e689ef79345586332e1769e030c03a4 100644 --- a/dune/gdt/test/stokes/stokes-taylorhood.hh +++ b/dune/gdt/test/stokes/stokes-taylorhood.hh @@ -31,7 +31,7 @@ #include <dune/gdt/local/bilinear-forms/integrals.hh> #include <dune/gdt/local/integrands/conversion.hh> #include <dune/gdt/local/integrands/div.hh> -#include <dune/gdt/local/integrands/elliptic.hh> +#include <dune/gdt/local/integrands/laplace.hh> #include <dune/gdt/local/integrands/product.hh> #include <dune/gdt/local/functionals/integrals.hh> #include <dune/gdt/norms.hh> @@ -60,16 +60,15 @@ struct StokesDirichletProblem using ScalarGridFunction = XT::Functions::GridFunctionInterface<E, 1, 1>; using VectorGridFunction = XT::Functions::GridFunctionInterface<E, d, 1>; using DomainType = typename ScalarGridFunction::LocalFunctionType::DomainType; + using DiffusionTensor = XT::Functions::GridFunctionInterface<E, d, d, RangeField>; - StokesDirichletProblem(std::shared_ptr<const ScalarGridFunction> diffusion_factor_in = default_diffusion_factor(), + StokesDirichletProblem(std::shared_ptr<const DiffusionTensor> diffusion_in = default_diffusion, std::shared_ptr<const VectorGridFunction> rhs_f_in = default_rhs_f(), std::shared_ptr<const VectorGridFunction> rhs_g_in = default_rhs_g(), std::shared_ptr<const VectorGridFunction> dirichlet_in = default_dirichlet_values(), std::shared_ptr<const VectorGridFunction> reference_sol_u = nullptr, std::shared_ptr<const ScalarGridFunction> reference_sol_p = nullptr) - : diffusion_factor_(diffusion_factor_in) - , diffusion_tensor_(std::make_shared<const XT::Functions::ConstantGridFunction<E, d, d>>( - XT::LA::eye_matrix<FieldMatrix<double, d, d>>(d, d))) + : diffusion_(diffusion_in) , rhs_f_(rhs_f_in) , rhs_g_(rhs_g_in) , dirichlet_(dirichlet_in) @@ -80,9 +79,10 @@ struct StokesDirichletProblem , grid_view_(grid_.leaf_view()) {} - static std::shared_ptr<const ScalarGridFunction> default_diffusion_factor() + static std::shared_ptr<const DiffusionTensor> default_diffusion() { - return std::make_shared<const XT::Functions::ConstantGridFunction<E, 1, 1>>(1., "default diffusion factor"); + return std::make_shared<const XT::Functions::ConstantGridFunction<E, d, d>>( + XT::LA::eye_matrix<FieldMatrix<double, d, d>>(d, d), "isotropic_diffusion"); } static std::shared_ptr<const VectorGridFunction> default_rhs_f() @@ -105,14 +105,9 @@ struct StokesDirichletProblem return grid_view_; } // ... make_initial_grid(...) - const ScalarGridFunction& diffusion_factor() + const XT::Functions::GridFunctionInterface<E, d, d>& diffusion() { - return *diffusion_factor_; - } // ... make_initial_grid(...) - - const XT::Functions::GridFunctionInterface<E, d, d>& diffusion_tensor() - { - return *diffusion_tensor_; + return *diffusion_; } // ... make_initial_grid(...) const VectorGridFunction& rhs_f() @@ -147,8 +142,7 @@ struct StokesDirichletProblem return boundary_info_; } // ... make_initial_grid(...) - std::shared_ptr<const ScalarGridFunction> diffusion_factor_; - std::shared_ptr<const XT::Functions::GridFunctionInterface<E, d, d, RangeField>> diffusion_tensor_; + std::shared_ptr<const DiffusionTensor> diffusion_; std::shared_ptr<const VectorGridFunction> rhs_f_; std::shared_ptr<const VectorGridFunction> rhs_g_; std::shared_ptr<const VectorGridFunction> dirichlet_; @@ -206,7 +200,7 @@ public: } } - void run() + void run(const int velocity_order, const double expected_error_u, const double expected_error_p) { const auto& grid_view = problem_.grid_view(); // Setup spaces and matrices and vectors @@ -215,8 +209,8 @@ public: // \int (div u) q = \int gg q // System is [A B; B^T C] [u; p] = [f; g] // Dimensions are: A: n x n, B: n x m, C: m x m, u: n, f: n, p: m, g: m - const VelocitySpace velocity_space(grid_view, 2); - const PressureSpace pressure_space(grid_view, 1); + const VelocitySpace velocity_space(grid_view, velocity_order); + const PressureSpace pressure_space(grid_view, velocity_order - 1); const size_t m = velocity_space.mapper().size(); const size_t n = pressure_space.mapper().size(); auto pattern_A = make_element_sparsity_pattern(velocity_space, velocity_space, grid_view); @@ -227,9 +221,8 @@ public: MatrixOperator<Matrix, GV, d> A_operator(grid_view, velocity_space, velocity_space, A); MatrixOperator<Matrix, GV, 1, 1, d> B_operator(grid_view, pressure_space, velocity_space, B); // calculate A_{ij} as \int \nabla v_i \nabla v_j - A_operator.append(LocalElementIntegralBilinearForm<E, d>( - LocalEllipticIntegrand<E, d>(problem_.diffusion_factor(), problem_.diffusion_tensor()))); - // calculate B_{ij} as \int \nabla p_i div(v_j) + A_operator.append(LocalElementIntegralBilinearForm<E, d>(LocalLaplaceIntegrand<E, d>(problem_.diffusion()))); + // calculate B_{ij} as \int -\nabla p_i div(v_j) B_operator.append(LocalElementIntegralBilinearForm<E, d, 1, RangeField, RangeField, 1>( LocalElementAnsatzValueTestDivProductIntegrand<E>(-1.))); // calculate rhs f as \int ff v and the integrated pressure space basis \int q_i @@ -283,7 +276,7 @@ public: C.set_entry(dof_index, dof_index, 1.); // now solve the system - XT::LA::SaddlePointSolver<double> solver(A, B, B, C); + XT::LA::SaddlePointSolver<Vector, Matrix> solver(A, B, B, C); Vector solution_u(m), solution_p(n); // solve both by direct solver and by schurcomplement (where the schur complement is inverted by CG and the inner // solves with A are using a direct method) @@ -294,31 +287,39 @@ public: const auto actual_u_vector = solution_u + dirichlet_vector; // ensure int_\Omega p = 0 auto p_integral = p_basis_integrated_vector * solution_p; + auto p_ref_integral = p_basis_integrated_vector * reference_solution_p_vector; auto p_correction = p_basis_integrated_vector; auto p_correction_func = make_discrete_function(pressure_space, p_correction); - auto vol_domain = 4.; + auto p_ref_correction = reference_solution_p_vector; + auto p_ref_correction_func = make_discrete_function(pressure_space, p_ref_correction); + const auto vol_domain = 4.; XT::Functions::ConstantGridFunction<E> const_p_integral_func(p_integral / vol_domain); + XT::Functions::ConstantGridFunction<E> const_p_ref_integral_func(p_ref_integral / vol_domain); default_interpolation(const_p_integral_func, p_correction_func); + default_interpolation(const_p_ref_integral_func, p_ref_correction_func); const auto actual_p_vector = solution_p - p_correction; + const auto actual_p_ref_vector = reference_solution_p_vector - p_ref_correction; // calculate difference to reference solution const auto u_diff_vector = actual_u_vector - reference_solution_u_vector; - const auto p_diff_vector = actual_p_vector - reference_solution_p_vector; + const auto p_diff_vector = actual_p_vector - actual_p_ref_vector; auto sol_u_func = make_discrete_function(velocity_space, actual_u_vector); auto sol_p_func = make_discrete_function(pressure_space, actual_p_vector); auto p_diff = make_discrete_function(pressure_space, p_diff_vector); auto u_diff = make_discrete_function(velocity_space, u_diff_vector); - bool visualize = false; + auto actual_p_ref = make_discrete_function(pressure_space, actual_p_ref_vector); + bool visualize = true; + std::string grid_name = XT::Common::Typename<G>::value(); if (visualize) { - sol_u_func.visualize("solution_u_" + type); - sol_p_func.visualize("solution_p_" + type); - reference_solution_u.visualize("u_ref"); - reference_solution_p.visualize("p_ref"); - u_diff.visualize("u_error_" + type); - p_diff.visualize("p_error_" + type); + sol_u_func.visualize("solution_u_" + type + "_" + grid_name); + sol_p_func.visualize("solution_p_" + type + "_" + grid_name); + reference_solution_u.visualize("u_ref_" + grid_name); + actual_p_ref.visualize("p_ref_" + grid_name); + u_diff.visualize("u_error_" + type + "_" + grid_name); + p_diff.visualize("p_error_" + type + "_" + grid_name); } - DXTC_EXPECT_FLOAT_LE(l2_norm(problem_.grid_view(), u_diff), 2.29e-06); - DXTC_EXPECT_FLOAT_LE(l2_norm(problem_.grid_view(), p_diff), 2.22e-05); + DXTC_EXPECT_FLOAT_LE(l2_norm(problem_.grid_view(), u_diff), expected_error_u); + DXTC_EXPECT_FLOAT_LE(l2_norm(problem_.grid_view(), p_diff), expected_error_p); } } // run @@ -338,7 +339,7 @@ class StokesTestcase1 : public StokesDirichletTest<G> public: StokesTestcase1() - : BaseType(ProblemType(ProblemType::default_diffusion_factor(), + : BaseType(ProblemType(ProblemType::default_diffusion(), ProblemType::default_rhs_f(), ProblemType::default_rhs_g(), dirichlet(), diff --git a/dune/gdt/test/stokes/stokes.cc b/dune/gdt/test/stokes/stokes.cc new file mode 100644 index 0000000000000000000000000000000000000000..90066d4d2877b65a60bda3157f4a4395cedcb241 --- /dev/null +++ b/dune/gdt/test/stokes/stokes.cc @@ -0,0 +1,83 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Tobias Leibner (2019) + +#define DUNE_XT_COMMON_TEST_MAIN_ENABLE_TIMED_LOGGING 1 +#define DUNE_XT_COMMON_TEST_MAIN_ENABLE_INFO_LOGGING 1 + +#define DUNE_XT_COMMON_TEST_MAIN_CATCH_EXCEPTIONS 1 + +#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)! + +#include <dune/xt/grid/grids.hh> + +#include <dune/gdt/test/stokes/stokes-taylorhood.hh> + +#if HAVE_DUNE_ISTL + +using namespace Dune; +using namespace Dune::GDT::Test; + +using SimplexGrids2D = ::testing::Types< +# if HAVE_DUNE_ALUGRID + ALU_2D_SIMPLEX_CONFORMING, + ALU_2D_SIMPLEX_NONCONFORMING +# endif +# if HAVE_DUNE_UGGRID || HAVE_UG +# if HAVE_DUNE_ALUGRID + , +# endif + UG_2D +# endif + >; + +using CubeGrids2D = ::testing::Types<YASP_2D_EQUIDISTANT_OFFSET +# if HAVE_DUNE_ALUGRID + , + ALU_2D_CUBE +# endif + >; + +DUNE_XT_COMMON_TYPENAME(YASP_2D_EQUIDISTANT_OFFSET) +# if HAVE_DUNE_ALUGRID +DUNE_XT_COMMON_TYPENAME(ALU_2D_SIMPLEX_CONFORMING) +DUNE_XT_COMMON_TYPENAME(ALU_2D_SIMPLEX_NONCONFORMING) +DUNE_XT_COMMON_TYPENAME(ALU_2D_CUBE) +# endif +# if HAVE_DUNE_UGGRID || HAVE_UG +DUNE_XT_COMMON_TYPENAME(UG_2D) +# endif +# if HAVE_ALBERTA +DUNE_XT_COMMON_TYPENAME(ALBERTA_2D) +# endif + + +template <class G> +using StokesTestSimplex = StokesTestcase1<G>; +TYPED_TEST_CASE(StokesTestSimplex, SimplexGrids2D); + +TYPED_TEST(StokesTestSimplex, order2) +{ + this->run(2, 2e-5, 3e-3); +} + +template <class G> +using StokesTestCube = StokesTestcase1<G>; +TYPED_TEST_CASE(StokesTestCube, CubeGrids2D); + +TYPED_TEST(StokesTestCube, order2) +{ + this->run(2, 3e-6, 3e-5); +} + +TYPED_TEST(StokesTestCube, order3) +{ + this->run(3, 4e-7, 7e-6); +} + +#endif // HAVE_DUNE_ISTL diff --git a/dune/gdt/test/stokes/stokes_testcase1.mini b/dune/gdt/test/stokes/stokes_testcase1.mini deleted file mode 100644 index cd684836bc81eb30fe0fc67b62124340bc24168e..0000000000000000000000000000000000000000 --- a/dune/gdt/test/stokes/stokes_testcase1.mini +++ /dev/null @@ -1,13 +0,0 @@ -__name = ESV2007Table1Test_column_1 - -[ESV2007Table1Test.column_1.setup] -force_order = 4 -over_integrate = 0 -num_refinements = 3 -num_additional_refinements_for_reference = 0 -reference_solution_order = 4 -use_tbb = false - -[ESV2007Table1Test.column_1.results] -target.h = [3.54e-01 1.77e-01 8.84e-02 4.42e-02] -norm.H_1_semi = [3.28e-01 1.62e-01 8.04e-02 4.01e-02] diff --git a/dune/gdt/tools/adaptation-helper.hh b/dune/gdt/tools/adaptation-helper.hh index 318b1072d3048d79e36bcf6ab4843958ae7f50f3..c1ec256ca9da804894c05849d647a24326bbc8b2 100644 --- a/dune/gdt/tools/adaptation-helper.hh +++ b/dune/gdt/tools/adaptation-helper.hh @@ -35,7 +35,7 @@ namespace GDT { template <class V, class GV, size_t r = 1, size_t rC = 1, class RF = double> class AdaptationHelper { - using ThisType = AdaptationHelper<V, GV, r, rC, RF>; + using ThisType = AdaptationHelper; public: using DiscreteFunctionType = DiscreteFunction<V, GV, r, rC, RF>; @@ -50,11 +50,11 @@ public: ThisType& append(SpaceType& space, DiscreteFunctionType& discrete_function) { - data_->emplace_back(space, - discrete_function, + data_->emplace_back(XT::Common::StorageProvider<SpaceType>(space), + XT::Common::StorageProvider<DiscreteFunctionType>(discrete_function), PersistentContainer<G, std::pair<DynamicVector<RF>, DynamicVector<RF>>>( grid_, 0, std::make_pair(DynamicVector<RF>(), DynamicVector<RF>())), - discrete_function.local_discrete_function()); + std::move(discrete_function.local_discrete_function())); return *this; } diff --git a/dune/gdt/tools/dirichlet-constraints.hh b/dune/gdt/tools/dirichlet-constraints.hh index 11ff5c2945da836baa814bb345e77be727e1efe8..262d38975d8302dc68e73c66ccfc849f6838c0a6 100644 --- a/dune/gdt/tools/dirichlet-constraints.hh +++ b/dune/gdt/tools/dirichlet-constraints.hh @@ -51,7 +51,7 @@ class DirichletConstraints std::set<size_t>, internal::setUnion<size_t>> { - using ThisType = DirichletConstraints<IntersectionType, SpaceType>; + using ThisType = DirichletConstraints; using BaseType = XT::Grid::ElementFunctor<typename SpaceType::GridViewType>; using Propagator = XT::Common::ThreadResultPropagator<ThisType, std::set<size_t>, internal::setUnion<size_t>>; friend Propagator; @@ -64,21 +64,22 @@ public: static const constexpr size_t r = SpaceType::r; static const constexpr size_t rC = SpaceType::rC; using R = typename SpaceType::R; + using SpaceInterfaceType = SpaceInterface<GridView, r, rC, R>; DirichletConstraints(const BoundaryInfoType& bnd_info, const SpaceType& space) : BaseType() , Propagator(this) , boundary_info_(bnd_info) - , space_(space) - , basis_(space_.basis().localize()) + , space_(space.copy()) + , basis_(space_->basis().localize()) {} DirichletConstraints(const ThisType& other) : BaseType(other) , Propagator(this) , boundary_info_(other.boundary_info_) - , space_(other.space_) - , basis_(space_.basis().localize()) + , space_(other.space_->copy()) + , basis_(space_->basis().localize()) {} void apply_local(const ElementType& element) override final @@ -87,8 +88,8 @@ public: basis_->bind(element); const auto& reference_element = ReferenceElements<double, d>::general(element.geometry().type()); const auto local_key_indices = basis_->finite_element().coefficients().local_key_indices(); - const auto intersection_it_end = space_.grid_view().iend(element); - for (auto intersection_it = space_.grid_view().ibegin(element); intersection_it != intersection_it_end; + const auto intersection_it_end = space_->grid_view().iend(element); + for (auto intersection_it = space_->grid_view().ibegin(element); intersection_it != intersection_it_end; ++intersection_it) { const auto& intersection = *intersection_it; // actual dirichlet intersections + process boundaries for parallel runs @@ -107,7 +108,7 @@ public: } } for (const auto& local_DoF : local_DoFs) { - dirichlet_DoFs_.insert(space_.mapper().global_index(element, local_DoF)); + dirichlet_DoFs_.insert(space_->mapper().global_index(element, local_DoF)); } } // ... apply_local(...) @@ -207,8 +208,8 @@ public: private: const BoundaryInfoType& boundary_info_; - const SpaceType& space_; - mutable std::unique_ptr<typename SpaceType::GlobalBasisType::LocalizedType> basis_; + std::unique_ptr<const SpaceInterfaceType> space_; + mutable std::unique_ptr<typename SpaceInterfaceType::GlobalBasisType::LocalizedType> basis_; std::set<size_t> dirichlet_DoFs_; }; // class DirichletConstraints diff --git a/dune/gdt/tools/discretevalued-grid-function.hh b/dune/gdt/tools/discretevalued-grid-function.hh new file mode 100644 index 0000000000000000000000000000000000000000..614c2de20e2b1174b0f99a51931f6d9d17b83477 --- /dev/null +++ b/dune/gdt/tools/discretevalued-grid-function.hh @@ -0,0 +1,127 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_TOOLS_DISCRETEVALUED_GRID_FUNCTION_HH +#define DUNE_GDT_TOOLS_DISCRETEVALUED_GRID_FUNCTION_HH + +#include <memory> + +#include <dune/xt/common/fvector.hh> +#include <dune/xt/common/string.hh> +#include <dune/xt/common/vector_less.hh> + +#include <dune/xt/functions/interfaces/grid-function.hh> + +namespace Dune { +namespace GDT { + + +/** + * \brief Wrapper for the map of reconstructed values that fulfills the XT::Functions::LocalizableFunctionInterface + */ +template <class GV, size_t rangeDim, size_t rangeDimCols, class RangeField> +class DiscreteValuedGridFunction + : public XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GV>, rangeDim, rangeDimCols, RangeField> +{ + using BaseType = + XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GV>, rangeDim, rangeDimCols, RangeField>; + using ThisType = DiscreteValuedGridFunction; + +public: + using BaseType::d; + using BaseType::r; + using BaseType::rC; + + using IndexSetType = typename GV::IndexSet; + using E = XT::Grid::extract_entity_t<GV>; + using typename BaseType::LocalFunctionType; + using typename BaseType::R; + +private: + class DiscreteValuedLocalFunction : public LocalFunctionType + { + using BaseType = LocalFunctionType; + + public: + using typename BaseType::DomainType; + using typename BaseType::E; + using typename BaseType::RangeReturnType; + using LocalFunctionValuesType = std::map<DomainType, RangeReturnType, XT::Common::FieldVectorLess>; + + DiscreteValuedLocalFunction(std::vector<LocalFunctionValuesType>& values, const IndexSetType& index_set) + : values_(values) + , index_set_(index_set) + {} + + int order(const XT::Common::Parameter& /*mu*/ = {}) const override + { + DUNE_THROW(Dune::InvalidStateException, "This function can't be integrated!"); + return 2; + } + + using BaseType::element; + + void post_bind(const E& elem) override final + { + local_values_ = &(values_[index_set_.index(elem)]); + } + + RangeReturnType evaluate(const DomainType& xx, const XT::Common::Parameter& /*param*/) const override + { + try { + return local_values_->at(xx); + } catch (const std::out_of_range& /*e*/) { + DUNE_THROW(Dune::RangeError, + "There are no values for local coord " + << XT::Common::to_string(xx) << " (global coord " + << XT::Common::to_string(element().geometry().global(xx)) << ") on entity " + << XT::Common::to_string(element().geometry().center()) << " in this function!"); + } + return RangeReturnType{}; + } + + private: + std::vector<LocalFunctionValuesType>& values_; + const IndexSetType& index_set_; + LocalFunctionValuesType* local_values_; + }; + +public: + using LocalFunctionValuesType = typename DiscreteValuedLocalFunction::LocalFunctionValuesType; + + static const bool available = true; + + DiscreteValuedGridFunction(const GV& grid_view, std::vector<LocalFunctionValuesType>& values) + : index_set_(grid_view.indexSet()) + , values_(values) + { + assert(grid_view.size(0) >= 0); + } + + std::unique_ptr<LocalFunctionType> local_function() const override final + { + return std::make_unique<DiscreteValuedLocalFunction>(values_, index_set_); + } + + LocalFunctionValuesType& local_values(const E& elem) + { + return values_[index_set_.index(elem)]; + } + +private: + const IndexSetType& index_set_; + std::vector<LocalFunctionValuesType>& values_; +}; // class DiscreteValuedGridFunction + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_TOOLS_DISCRETEVALUED_GRID_FUNCTION_HH diff --git a/dune/gdt/tools/grid-quality-estimates.hh b/dune/gdt/tools/grid-quality-estimates.hh new file mode 100644 index 0000000000000000000000000000000000000000..baecd3fc444a02dbb270d4f9c45ee38fdce73d77 --- /dev/null +++ b/dune/gdt/tools/grid-quality-estimates.hh @@ -0,0 +1,134 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2019) + +#ifndef DUNE_GDT_TOOLS_GRID_QUALITY_ESTIMATES_HH +#define DUNE_GDT_TOOLS_GRID_QUALITY_ESTIMATES_HH + +#include <limits> +#include <vector> + +#include <dune/grid/common/rangegenerators.hh> + +#include <dune/xt/common/exceptions.hh> +#include <dune/xt/la/container/common.hh> +#include <dune/xt/la/container/conversion.hh> +#include <dune/xt/la/generalized-eigen-solver.hh> +#include <dune/xt/grid/entity.hh> +#include <dune/xt/grid/intersection.hh> +#include <dune/xt/grid/type_traits.hh> + +#include <dune/gdt/local/bilinear-forms/integrals.hh> +#include <dune/gdt/local/integrands/laplace.hh> +#include <dune/gdt/local/integrands/product.hh> +#include <dune/gdt/spaces/interface.hh> + +namespace Dune { +namespace GDT { + + +template <class GV, size_t r> +double estimate_inverse_inequality_constant(const SpaceInterface<GV, r>& space) +{ + DUNE_THROW_IF(!XT::Common::Lapacke::available(), XT::Common::Exceptions::dependency_missing, "lapacke"); + using E = XT::Grid::extract_entity_t<GV>; + double result = std::numeric_limits<double>::min(); + auto basis = space.basis().localize(); + for (auto&& element : elements(space.grid_view())) { + basis->bind(element); + const double h = XT::Grid::diameter(element); + auto H1_product_matrix = XT::LA::convert_to<XT::LA::CommonDenseMatrix<double>>( + LocalElementIntegralBilinearForm<E, r>(LocalLaplaceIntegrand<E, r>()).apply2(*basis, *basis)); + auto L2_product_matrix = XT::LA::convert_to<XT::LA::CommonDenseMatrix<double>>( + LocalElementIntegralBilinearForm<E, r>(LocalElementProductIntegrand<E, r>()).apply2(*basis, *basis)); + auto evs = + XT::LA::make_generalized_eigen_solver(H1_product_matrix, + L2_product_matrix, + {{"type", XT::LA::generalized_eigen_solver_types(H1_product_matrix)[0]}, + {"compute_eigenvectors", "false"}, + {"assert_real_eigenvalues", "1e-15"}}) + .real_eigenvalues(); + double min_ev = std::numeric_limits<double>::max(); + for (auto&& ev : evs) + if (std::abs(ev) > 1e-7) // TODO: find a better tolerance here! + min_ev = std::min(min_ev, ev); + // the smalles nonzero eigenvalue is (C_I / h)^2 + result = std::max(result, h * std::sqrt(min_ev)); + } + return result; +} // ... estimate_inverse_inequality_constant(...) + + +template <class GV, size_t r> +double estimate_combined_inverse_trace_inequality_constant(const SpaceInterface<GV, r>& space) +{ + DUNE_THROW_IF(!XT::Common::Lapacke::available(), XT::Common::Exceptions::dependency_missing, "lapacke"); + using E = XT::Grid::extract_entity_t<GV>; + using I = XT::Grid::extract_intersection_t<GV>; + double result = std::numeric_limits<double>::min(); + auto basis = space.basis().localize(); + for (auto&& element : elements(space.grid_view())) { + basis->bind(element); + const double h = XT::Grid::diameter(element); + XT::LA::CommonDenseMatrix<double> L2_face_product_matrix(basis->size(), basis->size(), 0.); + DynamicMatrix<double> tmp_L2_face_product_matrix(basis->size(), basis->size(), 0.); + for (auto&& intersection : intersections(space.grid_view(), element)) { + LocalIntersectionIntegralBilinearForm<I, r>(LocalIntersectionProductIntegrand<I, r>(1.)) + .apply2(intersection, *basis, *basis, tmp_L2_face_product_matrix); + for (size_t ii = 0; ii < basis->size(); ++ii) + for (size_t jj = 0; jj < basis->size(); ++jj) + L2_face_product_matrix.add_to_entry(ii, jj, tmp_L2_face_product_matrix[ii][jj]); + } + auto L2_element_product_matrix = XT::LA::convert_to<XT::LA::CommonDenseMatrix<double>>( + LocalElementIntegralBilinearForm<E, r>(LocalElementProductIntegrand<E, r>(1.)).apply2(*basis, *basis)); + auto evs = XT::LA::make_generalized_eigen_solver( + L2_face_product_matrix, + L2_element_product_matrix, + {{"type", XT::LA::generalized_eigen_solver_types(L2_face_product_matrix)[0]}, + {"compute_eigenvectors", "false"}, + {"assert_real_eigenvalues", "1e-15"}}) + .real_eigenvalues(); + double min_ev = std::numeric_limits<double>::max(); + for (auto&& ev : evs) + if (std::abs(ev) > 1e-7) // TODO: find a better tolerance here! + min_ev = std::min(min_ev, ev); + // the smalles nonzero eigenvalue is (C_M (1 + C_I)) / h + result = std::max(result, h * min_ev); + } + return result; +} // ... estimate_combined_inverse_trace_inequality_constant(...) + + +template <class GV> +double estimate_element_to_intersection_equivalence_constant( + const GridView<GV>& grid_view, + const std::function<double(const XT::Grid::extract_intersection_t<GridView<GV>>&)>& intersection_diameter = + [](const auto& intersection) { + if (GridView<GV>::dimension == 1) { + if (intersection.neighbor()) + return 0.5 * (XT::Grid::diameter(intersection.inside()) + XT::Grid::diameter(intersection.outside())); + else + return XT::Grid::diameter(intersection.inside()); + } else + return XT::Grid::diameter(intersection); + }) +{ + auto result = std::numeric_limits<double>::min(); + for (auto&& element : elements(grid_view)) { + const double h = XT::Grid::diameter(element); + for (auto&& intersection : intersections(grid_view, element)) + result = std::max(result, intersection_diameter(intersection) / h); + } + return result; +} // ... estimate_element_to_intersection_equivalence_constant(...) + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_TOOLS_GRID_QUALITY_ESTIMATES_HH diff --git a/dune/gdt/tools/local-mass-matrix.hh b/dune/gdt/tools/local-mass-matrix.hh index 3aa5f4ea1f19c16660a211bdcc17820230aa455f..67f404f94908bbca8ae2fc59a06e4786dacdb3e4 100644 --- a/dune/gdt/tools/local-mass-matrix.hh +++ b/dune/gdt/tools/local-mass-matrix.hh @@ -41,7 +41,7 @@ class LocalMassMatrixProvider { static_assert(XT::Grid::is_view<AGV>::value, ""); - using ThisType = LocalMassMatrixProvider<GV, r, rC, F>; + using ThisType = LocalMassMatrixProvider; using BaseType = XT::Grid::ElementFunctor<GV>; using Propagator = XT::Common::ThreadResultPropagator< LocalMassMatrixProvider<GV, r, rC, F>, @@ -60,20 +60,20 @@ public: : BaseType() , Propagator(this) , grid_view_(grid_view) - , space_(space) + , space_(space.copy()) , element_mapper_(grid_view_) , instance_counter_(0) - , local_basis_(space_.basis().localize()) + , local_basis_(space_->basis().localize()) {} LocalMassMatrixProvider(const ThisType& other) : BaseType(other) , Propagator(this) , grid_view_(other.grid_view_) - , space_(other.space_) + , space_(other.space_->copy()) , element_mapper_(grid_view_) , instance_counter_(other.instance_counter_ + 1) - , local_basis_(space_.basis().localize()) + , local_basis_(space_->basis().localize()) {} void apply_local(const ElementType& element) override @@ -131,8 +131,8 @@ public: } private: - const AssemblyGridView& grid_view_; - const SpaceType& space_; + const AssemblyGridView grid_view_; + std::unique_ptr<const SpaceType> space_; const FiniteVolumeMapper<GV> element_mapper_; size_t instance_counter_; std::unique_ptr<typename SpaceType::GlobalBasisType::LocalizedType> local_basis_; diff --git a/dune/gdt/tools/timestepper/adaptive-rungekutta.hh b/dune/gdt/tools/timestepper/adaptive-rungekutta.hh new file mode 100644 index 0000000000000000000000000000000000000000..00a1d84ee60e42b1950bbab5ced0810401979178 --- /dev/null +++ b/dune/gdt/tools/timestepper/adaptive-rungekutta.hh @@ -0,0 +1,414 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2016 - 2017) +// Rene Milk (2016 - 2018) +// Tobias Leibner (2016 - 2017) + +#ifndef DUNE_GDT_TIMESTEPPER_ADAPTIVE_RUNGEKUTTA_HH +#define DUNE_GDT_TIMESTEPPER_ADAPTIVE_RUNGEKUTTA_HH + +#include <utility> + +#include <dune/gdt/operators/interfaces.hh> + +#include <dune/xt/common/memory.hh> +#include <dune/xt/common/string.hh> + +#include "interface.hh" + + +namespace Dune { +namespace GDT { + + +namespace internal { + + +// unspecialized +template <class RangeFieldType, TimeStepperMethods method> +struct AdaptiveButcherArrayProvider +{ + static_assert(AlwaysFalse<RangeFieldType>::value, + "You cannot use AdaptiveRungeKuttaTimeStepper with this value of TimeStepperMethods!"); +}; + +// user-provided Butcher array +template <class RangeFieldType> +struct AdaptiveButcherArrayProvider<RangeFieldType, TimeStepperMethods::adaptive_rungekutta_other> +{ + static Dune::DynamicMatrix<RangeFieldType> A() + { + DUNE_THROW(Dune::NotImplemented, + "You have to provide a Butcher array in AdaptiveRungeKuttaTimeStepper's constructor for this method!"); + return Dune::DynamicMatrix<RangeFieldType>(); + } + + static Dune::DynamicVector<RangeFieldType> b_1() + { + DUNE_THROW(Dune::NotImplemented, + "You have to provide a Butcher array in AdaptiveRungeKuttaTimeStepper's constructor for this method!"); + return Dune::DynamicVector<RangeFieldType>(); + } + + static Dune::DynamicVector<RangeFieldType> b_2() + { + DUNE_THROW(Dune::NotImplemented, + "You have to provide a Butcher array in AdaptiveRungeKuttaTimeStepper's constructor for this method!"); + return Dune::DynamicVector<RangeFieldType>(); + } + + static Dune::DynamicVector<RangeFieldType> c() + { + DUNE_THROW(Dune::NotImplemented, + "You have to provide a Butcher array in AdaptiveRungeKuttaTimeStepper's constructor for this method!"); + return Dune::DynamicVector<RangeFieldType>(); + } +}; + +// Bogacki-Shampine (adaptive RK23) +template <class RangeFieldType> +class AdaptiveButcherArrayProvider<RangeFieldType, TimeStepperMethods::bogacki_shampine> +{ +public: + static Dune::DynamicMatrix<RangeFieldType> A() + { + return Dune::XT::Common::from_string<Dune::DynamicMatrix<RangeFieldType>>( + "[0 0 0 0; 0.5 0 0 0; 0 0.75 0 0; " + Dune::XT::Common::to_string(2.0 / 9.0, 15) + " " + + Dune::XT::Common::to_string(1.0 / 3.0, 15) + " " + Dune::XT::Common::to_string(4.0 / 9.0, 15) + " 0]"); + } + + static Dune::DynamicVector<RangeFieldType> b_1() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>( + "[" + Dune::XT::Common::to_string(2.0 / 9.0, 15) + " " + Dune::XT::Common::to_string(1.0 / 3.0, 15) + " " + + Dune::XT::Common::to_string(4.0 / 9.0, 15) + " 0]"); + } + + static Dune::DynamicVector<RangeFieldType> b_2() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>( + "[" + Dune::XT::Common::to_string(7.0 / 24.0, 15) + " " + Dune::XT::Common::to_string(1.0 / 4.0, 15) + " " + + Dune::XT::Common::to_string(1.0 / 3.0, 15) + " " + Dune::XT::Common::to_string(1.0 / 8.0, 15) + " 0]"); + } + + static Dune::DynamicVector<RangeFieldType> c() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>("[0.5 0.75 1 0]"); + } +}; + +// Dormand-Prince (adaptive RK45) +template <class RangeFieldType> +class AdaptiveButcherArrayProvider<RangeFieldType, TimeStepperMethods::dormand_prince> +{ +public: + static Dune::DynamicMatrix<RangeFieldType> A() + { + return Dune::XT::Common::from_string<Dune::DynamicMatrix<RangeFieldType>>( + std::string("[0 0 0 0 0 0 0;") + " 0.2 0 0 0 0 0 0;" + " 0.075 0.225 0 0 0 0 0;" + " " + + Dune::XT::Common::to_string(44.0 / 45.0, 15) + " " + Dune::XT::Common::to_string(-56.0 / 15.0, 15) + " " + + Dune::XT::Common::to_string(32.0 / 9.0, 15) + " 0 0 0 0;" + " " + + Dune::XT::Common::to_string(19372.0 / 6561.0, 15) + " " + Dune::XT::Common::to_string(-25360.0 / 2187.0, 15) + + " " + Dune::XT::Common::to_string(64448.0 / 6561.0, 15) + " " + + Dune::XT::Common::to_string(-212.0 / 729.0, 15) + " 0 0 0;" + " " + + Dune::XT::Common::to_string(9017.0 / 3168.0, 15) + " " + Dune::XT::Common::to_string(-355.0 / 33.0, 15) + " " + + Dune::XT::Common::to_string(46732.0 / 5247.0, 15) + " " + Dune::XT::Common::to_string(49.0 / 176.0, 15) + " " + + Dune::XT::Common::to_string(-5103.0 / 18656.0, 15) + " 0 0;" + " " + + Dune::XT::Common::to_string(35.0 / 384.0, 15) + " 0 " + Dune::XT::Common::to_string(500.0 / 1113.0, 15) + " " + + Dune::XT::Common::to_string(125.0 / 192.0, 15) + " " + Dune::XT::Common::to_string(-2187.0 / 6784.0, 15) + " " + + Dune::XT::Common::to_string(11.0 / 84.0, 15) + " 0]"); + } + + static Dune::DynamicVector<RangeFieldType> b_1() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>( + "[" + Dune::XT::Common::to_string(35.0 / 384.0, 15) + " 0 " + Dune::XT::Common::to_string(500.0 / 1113.0, 15) + + " " + Dune::XT::Common::to_string(125.0 / 192.0, 15) + " " + Dune::XT::Common::to_string(-2187.0 / 6784.0, 15) + + " " + Dune::XT::Common::to_string(11.0 / 84.0, 15) + " 0]"); + } + + static Dune::DynamicVector<RangeFieldType> b_2() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>( + "[" + Dune::XT::Common::to_string(5179.0 / 57600.0, 15) + " 0 " + + Dune::XT::Common::to_string(7571.0 / 16695.0, 15) + " " + Dune::XT::Common::to_string(393.0 / 640.0, 15) + " " + + Dune::XT::Common::to_string(-92097.0 / 339200.0, 15) + " " + Dune::XT::Common::to_string(187.0 / 2100.0, 15) + + " " + Dune::XT::Common::to_string(1.0 / 40.0, 15) + "]"); + } + + static Dune::DynamicVector<RangeFieldType> c() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>( + "[0 0.2 0.3 0.8 " + Dune::XT::Common::to_string(8.0 / 9.0, 15) + " 1 1]"); + } +}; // Dormand-Prince (RK45) + + +} // namespace internal + + +/** \brief Time stepper using adaptive Runge Kutta methods + * + * Timestepper using adaptive Runge Kutta methods to solve equations of the form u_t = r * L(u, t) where u is a + * discrete function, L an operator acting on u and \alpha a scalar factor (e.g. -1). + * The specific Runge Kutta method can be chosen as the third template argument. If your desired Runge Kutta method is + * not contained in AdaptiveRungeKuttaMethods, choose AdaptiveRungeKuttaMethods::other and + * supply a DynamicMatrix< RangeFieldType > A and vectors b_1, b_2 (DynamicVector< RangeFieldType >) and c + * (DynamicVector< RangeFieldType >) in the constructor. Here, A, b_1, b_2 and c form the butcher tableau (see + * https://en.wikipedia.org/wiki/List_of_Runge%E2%80%93Kutta_methods#Embedded_methods, A is composed of the coefficients + * a_{ij}, b_1 of b_j, b_2 of b_j^* and c of c_j). The default is the Dormand-Prince RK45 method. + * In each time step, the error is estimated using the difference between the two solutions obtained using either b_1 or + * b_2. If the estimated error is higher than a specified tolerance tol, the calculation is repeated with a smaller + * time step. The tolerance tol and the error estimate are also used to estimate the optimal time step length for the + * next time step via dt_new = dt_old*min(max(0.9*(tol/error)^(1/5), scale_factor_min), scale_factor_max_); + * + * Notation: For an s-stage method, + * \mathbf{u}^{n+1} = \mathbf{u}^n + dt \sum_{i=0}^{s-1} b_i \mathbf{k}_i + * \mathbf{k}_i = L(\mathbf{u}_i, t^n + dt c_i) + * \mathbf{u}_i = \mathbf{u}^n + dt \sum_{j=0}^{i-1} a_{ij} \mathbf{k}_j, + * + * \tparam OperatorImp Type of operator L + * \tparam DiscreteFunctionImp Type of initial values and solution at a fixed time + * \tparam method Adaptive Runge-Kutta method that is used (default is AdaptiveRungeKuttaMethods::dormand_prince) + */ +template <class OperatorImp, class DiscreteFunctionImp, TimeStepperMethods method = TimeStepperMethods::dormand_prince> +class AdaptiveRungeKuttaTimeStepper : public TimeStepperInterface<DiscreteFunctionImp> +{ + typedef TimeStepperInterface<DiscreteFunctionImp> BaseType; + typedef typename internal::AdaptiveButcherArrayProvider<typename BaseType::RangeFieldType, method> + ButcherArrayProviderType; + +public: + typedef OperatorImp OperatorType; + typedef DiscreteFunctionImp DiscreteFunctionType; + + typedef typename DiscreteFunctionType::DomainFieldType DomainFieldType; + typedef typename DiscreteFunctionType::RangeFieldType RangeFieldType; + typedef typename Dune::DynamicMatrix<RangeFieldType> MatrixType; + typedef typename Dune::DynamicVector<RangeFieldType> VectorType; + typedef typename std::vector<std::pair<RangeFieldType, DiscreteFunctionType>> SolutionType; + + /** + * \brief Constructor for AdaptiveRungeKuttaTimeStepper time stepper + * \param op Operator L + * \param initial_values Discrete function containing initial values for u at time t_0. + * \param r Scalar factor (see above, default is 1) + * \param t_0 Initial time (default is 0) + * \param tol Error tolerance for the adaptive scheme (default is 1e-4) + * \param scale_factor_min Minimum allowed factor for time step scaling (default is 0.2). + * \param scale_factor_max Maximum allowed factor for time step scaling (default is 5). + * \param A Coefficient matrix (only provide if you use AdaptiveRungeKuttaMethods::other) + * \param b_1 First set of coefficients (only provide if you use AdaptiveRungeKuttaMethods::other) + * \param b_2 Second set of coefficients (only provide if you use AdaptiveRungeKuttaMethods::other) + * \param c Coefficients for time steps (only provide if you use AdaptiveRungeKuttaMethods::other) + */ + AdaptiveRungeKuttaTimeStepper(const OperatorType& op, + DiscreteFunctionType& initial_values, + const RangeFieldType r = 1.0, + const double t_0 = 0.0, + const RangeFieldType tol = 1e-4, + const RangeFieldType scale_factor_min = 0.2, + const RangeFieldType scale_factor_max = 5, + const MatrixType& A = ButcherArrayProviderType::A(), + const VectorType& b_1 = ButcherArrayProviderType::b_1(), + const VectorType& b_2 = ButcherArrayProviderType::b_2(), + const VectorType& c = ButcherArrayProviderType::c()) + : BaseType(t_0, initial_values) + , op_(op) + , r_(r) + , tol_(tol) + , scale_factor_min_(scale_factor_min) + , scale_factor_max_(scale_factor_max) + , u_tmp_(BaseType::current_solution()) + , A_(A) + , b_1_(b_1) + , b_2_(b_2) + , c_(c) + , b_diff_(b_2_ - b_1_) + , num_stages_(A_.rows()) + { + assert(Dune::XT::Common::FloatCmp::gt(tol_, 0.0)); + assert(Dune::XT::Common::FloatCmp::le(scale_factor_min_, 1.0)); + assert(Dune::XT::Common::FloatCmp::ge(scale_factor_max_, 1.0)); + assert(A_.rows() == A_.cols() && "A has to be a square matrix"); + assert(b_1_.size() == A_.rows()); + assert(b_2_.size() == A_.rows()); + assert(c_.size() == A_.rows()); +#ifndef NDEBUG + for (size_t ii = 0; ii < A_.rows(); ++ii) { + for (size_t jj = ii; jj < A_.cols(); ++jj) { + assert(Dune::XT::Common::FloatCmp::eq(A_[ii][jj], 0.0) + && "A has to be a lower triangular matrix with 0 on the main diagonal"); + } + } +#endif // NDEBUG + // store as many discrete functions as needed for intermediate stages + for (size_t ii = 0; ii < num_stages_; ++ii) { + stages_k_.emplace_back(current_solution()); + } + } // constructor AdaptiveRungeKuttaTimeStepper + + using BaseType::current_solution; + using BaseType::current_time; + using BaseType::solve; + + virtual RangeFieldType solve(const RangeFieldType t_end, + const RangeFieldType initial_dt, + const size_t num_save_steps, + const size_t num_output_steps, + const bool save_solution, + const bool visualize, + const bool write_discrete, + const bool write_exact, + const std::string prefix, + typename BaseType::DiscreteSolutionType& sol, + const typename BaseType::VisualizerType& visualizer, + const typename BaseType::StringifierType& stringifier, + const typename BaseType::GridFunctionType& exact_solution) override final + { + const auto ret = BaseType::solve(t_end, + initial_dt, + num_save_steps, + num_output_steps, + save_solution, + visualize, + write_discrete, + write_exact, + prefix, + sol, + visualizer, + stringifier, + exact_solution); + // in a fractional step scheme, we cannot use last_stage_of_previous_step + last_stage_of_previous_step_ = nullptr; + return ret; + } + + RangeFieldType step(const RangeFieldType dt, const RangeFieldType max_dt) override final + { + RangeFieldType actual_dt = std::min(dt, max_dt); + RangeFieldType mixed_error = std::numeric_limits<RangeFieldType>::max(); + RangeFieldType time_step_scale_factor = 1.0; + + auto& t = current_time(); + auto& u_n = current_solution(); + + while (Dune::XT::Common::FloatCmp::gt(mixed_error, tol_)) { + bool skip_error_computation = false; + actual_dt *= time_step_scale_factor; + size_t first_stage_to_compute = 0; + if (last_stage_of_previous_step_) { + stages_k_[0].dofs().vector() = last_stage_of_previous_step_->dofs().vector(); + first_stage_to_compute = 1; + } + + for (size_t ii = first_stage_to_compute; ii < num_stages_; ++ii) { + std::fill(stages_k_[ii].dofs().vector().begin(), stages_k_[ii].dofs().vector().end(), RangeFieldType(0.)); + u_tmp_.dofs().vector() = u_n.dofs().vector(); + for (size_t jj = 0; jj < ii; ++jj) + u_tmp_.dofs().vector() += stages_k_[jj].dofs().vector() * (actual_dt * r_ * (A_[ii][jj])); + try { + op_.apply(u_tmp_.dofs().vector(), stages_k_[ii].dofs().vector(), t + actual_dt * c_[ii]); + } catch (const Dune::MathError& e) { + mixed_error = 1e10; + skip_error_computation = true; + time_step_scale_factor = 0.5; + break; +#if HAVE_TBB + } catch (const tbb::captured_exception& e) { + mixed_error = 1e10; + skip_error_computation = true; + time_step_scale_factor = 0.5; + break; +#endif + } + } + + if (!skip_error_computation) { + // compute error vector + u_tmp_.dofs().vector() = stages_k_[0].dofs().vector() * b_diff_[0]; + for (size_t ii = 1; ii < num_stages_; ++ii) + u_tmp_.dofs().vector() += stages_k_[ii].dofs().vector() * b_diff_[ii]; + u_tmp_.dofs().vector() *= actual_dt * r_; + + // calculate u at timestep n+1 + for (size_t ii = 0; ii < num_stages_; ++ii) + u_n.dofs().vector() += stages_k_[ii].dofs().vector() * (actual_dt * r_ * b_1_[ii]); + + // scale error, use absolute error if norm is less than 0.01 and relative error else + auto& diff_vector = u_tmp_.dofs().vector(); + for (size_t ii = 0; ii < diff_vector.size(); ++ii) { + if (std::abs(u_n.dofs().vector()[ii]) > 0.01) + diff_vector[ii] /= std::abs(u_n.dofs().vector()[ii]); + } + mixed_error = diff_vector.sup_norm(); + // scale dt to get the estimated optimal time step length, TODO: adapt formula + time_step_scale_factor = + std::min(std::max(0.9 * std::pow(tol_ / mixed_error, 1.0 / 5.0), scale_factor_min_), scale_factor_max_); + + if (mixed_error > tol_) { // go back from u at timestep n+1 to timestep n + for (size_t ii = 0; ii < num_stages_; ++ii) + u_n.dofs().vector() += stages_k_[ii].dofs().vector() * (-1.0 * r_ * actual_dt * b_1_[ii]); + } + } + } // while (mixed_error > tol_) + if (!last_stage_of_previous_step_) + last_stage_of_previous_step_ = Dune::XT::Common::make_unique<DiscreteFunctionType>(u_n); + last_stage_of_previous_step_->dofs().vector() = stages_k_[num_stages_ - 1].dofs().vector(); + +#if 0 + const auto u_local_func = u_n.local_discrete_function(); + for (auto&& element : Dune::elements(u_n.space().grid_view())) { + u_local_func->bind(element); + for (size_t ii = 0; ii < BaseType::dimRange; ++ii) { +// constexpr double min_val = -100.; + constexpr double max_val = 1000.; + const auto entry_ii = u_local_func->dofs().get_entry(ii); + if (std::abs(entry_ii) > max_val) { +// std::cout << "limited from " << u_local_func->dofs().get_entry(ii) << " to " << min_val << " in entity " << element.geometry().center() << std::endl; +// std::cout << "Entries are: "; +// for (size_t jj = 0; jj < BaseType::dimRange; ++jj) { +// std::cout << u_local_func->dofs().get_entry(jj) << " "; +// } +// std::cout << std::endl; + last_stage_of_previous_step_ = nullptr; +// u_local_func->dofs().set_entry(ii, min_val); + std::cout << "Replacing " << entry_ii << " by " << std::copysign(max_val, entry_ii) << std::endl; + u_local_func->dofs().set_entry(ii, std::copysign(max_val, entry_ii)); + } + } // ii + } // elements +#endif + + t += actual_dt; + + return actual_dt * time_step_scale_factor; + } // ... step(...) + +private: + const OperatorType& op_; + const RangeFieldType r_; + const RangeFieldType tol_; + const RangeFieldType scale_factor_min_; + const RangeFieldType scale_factor_max_; + DiscreteFunctionType u_tmp_; + const MatrixType A_; + const VectorType b_1_; + const VectorType b_2_; + const VectorType c_; + const VectorType b_diff_; + std::vector<DiscreteFunctionType> stages_k_; + const size_t num_stages_; + std::unique_ptr<DiscreteFunctionType> last_stage_of_previous_step_; +}; // class AdaptiveRungeKuttaTimeStepper + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_TIMESTEPPER_ADAPTIVE_RUNGEKUTTA_HH diff --git a/dune/gdt/tools/timestepper/enums.hh b/dune/gdt/tools/timestepper/enums.hh new file mode 100644 index 0000000000000000000000000000000000000000..60dd1f7fc2768581eaad9eacfbc42718db2dd658 --- /dev/null +++ b/dune/gdt/tools/timestepper/enums.hh @@ -0,0 +1,45 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_TIMESTEPPER_ENUMS_HH +#define DUNE_GDT_TIMESTEPPER_ENUMS_HH + +namespace Dune { +namespace GDT { + + +enum class TimeStepperMethods +{ + bogacki_shampine, + dormand_prince, + adaptive_rungekutta_other, + explicit_euler, + explicit_rungekutta_second_order_ssp, + explicit_rungekutta_third_order_ssp, + explicit_rungekutta_classic_fourth_order, + explicit_rungekutta_other, + implicit_euler, + implicit_midpoint, + trapezoidal_rule, + diagonally_implicit_other, + matrix_exponential +}; + +enum class TimeStepperSplittingMethods +{ + fractional_step, + strang +}; + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_TIMESTEPPER_ENUMS_HH diff --git a/dune/gdt/tools/timestepper/explicit-rungekutta.hh b/dune/gdt/tools/timestepper/explicit-rungekutta.hh new file mode 100644 index 0000000000000000000000000000000000000000..b1804fe385807f62b475c7beb7adb005d3f57421 --- /dev/null +++ b/dune/gdt/tools/timestepper/explicit-rungekutta.hh @@ -0,0 +1,337 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2016 - 2017) +// Rene Milk (2016 - 2018) +// Tobias Leibner (2016 - 2017) + +#ifndef DUNE_GDT_TIMESTEPPER_EXPLICIT_RUNGEKUTTA_HH +#define DUNE_GDT_TIMESTEPPER_EXPLICIT_RUNGEKUTTA_HH + +#include <utility> + +#include "enums.hh" +#include "interface.hh" + + +namespace Dune { +namespace GDT { + + +namespace internal { + + +// unspecialized +template <class RangeFieldType, TimeStepperMethods method> +struct ButcherArrayProvider +{ + static_assert(AlwaysFalse<RangeFieldType>::value, + "You cannot use ExplicitRungeKuttaTimeStepper with this value of TimeStepperMethods!"); +}; + +// user-provided Butcher array +template <class RangeFieldType> +struct ButcherArrayProvider<RangeFieldType, TimeStepperMethods::explicit_rungekutta_other> +{ + static Dune::DynamicMatrix<RangeFieldType> A() + { + DUNE_THROW(Dune::NotImplemented, + "You have to provide a Butcher array in ExplicitRungeKuttaTimeStepper's constructor for this method!"); + return Dune::DynamicMatrix<RangeFieldType>(); + } + + static Dune::DynamicVector<RangeFieldType> b() + { + DUNE_THROW(Dune::NotImplemented, + "You have to provide a Butcher array in ExplicitRungeKuttaTimeStepper's constructor for this method!"); + return Dune::DynamicVector<RangeFieldType>(); + } + + static Dune::DynamicVector<RangeFieldType> c() + { + DUNE_THROW(Dune::NotImplemented, + "You have to provide a Butcher array in ExplicitRungeKuttaTimeStepper's constructor for this method!"); + return Dune::DynamicVector<RangeFieldType>(); + } +}; + +// Euler +template <class RangeFieldType> +struct ButcherArrayProvider<RangeFieldType, TimeStepperMethods::explicit_euler> +{ + static Dune::DynamicMatrix<RangeFieldType> A() + { + return Dune::XT::Common::from_string<Dune::DynamicMatrix<RangeFieldType>>("[0]"); + } + + static Dune::DynamicVector<RangeFieldType> b() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>("[1]"); + } + + static Dune::DynamicVector<RangeFieldType> c() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>("[0]"); + } +}; + +// Second order SSP +template <class RangeFieldType> +struct ButcherArrayProvider<RangeFieldType, TimeStepperMethods::explicit_rungekutta_second_order_ssp> +{ + static Dune::DynamicMatrix<RangeFieldType> A() + { + return Dune::XT::Common::from_string<Dune::DynamicMatrix<RangeFieldType>>("[0 0; 1 0]"); + } + + static Dune::DynamicVector<RangeFieldType> b() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>("[0.5 0.5]"); + } + + static Dune::DynamicVector<RangeFieldType> c() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>("[0 1]"); + } +}; + +// Third order SSP +template <class RangeFieldType> +struct ButcherArrayProvider<RangeFieldType, TimeStepperMethods::explicit_rungekutta_third_order_ssp> +{ + static Dune::DynamicMatrix<RangeFieldType> A() + { + return Dune::XT::Common::from_string<Dune::DynamicMatrix<RangeFieldType>>("[0 0 0; 1 0 0; 0.25 0.25 0]"); + } + + static Dune::DynamicVector<RangeFieldType> b() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>( + "[" + Dune::XT::Common::to_string(1.0 / 6.0, 15) + " " + Dune::XT::Common::to_string(1.0 / 6.0, 15) + " " + + Dune::XT::Common::to_string(2.0 / 3.0, 15) + "]"); + } + + static Dune::DynamicVector<RangeFieldType> c() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>("[0 1 0.5]"); + } +}; + +// Classic fourth order RK +template <class RangeFieldType> +struct ButcherArrayProvider<RangeFieldType, TimeStepperMethods::explicit_rungekutta_classic_fourth_order> +{ + static Dune::DynamicMatrix<RangeFieldType> A() + { + return Dune::XT::Common::from_string<Dune::DynamicMatrix<RangeFieldType>>( + "[0 0 0 0; 0.5 0 0 0; 0 0.5 0 0; 0 0 1 0]"); + } + + static Dune::DynamicVector<RangeFieldType> b() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>( + "[" + Dune::XT::Common::to_string(1.0 / 6.0, 15) + " " + Dune::XT::Common::to_string(1.0 / 3.0, 15) + " " + + Dune::XT::Common::to_string(1.0 / 3.0, 15) + " " + Dune::XT::Common::to_string(1.0 / 6.0, 15) + "]"); + } + + static Dune::DynamicVector<RangeFieldType> c() + { + return Dune::XT::Common::from_string<Dune::DynamicVector<RangeFieldType>>("[0 0.5 0.5 1]"); + } +}; + + +} // namespace internal + + +/** \brief Time stepper using Runge Kutta methods + * + * Timestepper using explicit Runge Kutta methods to solve equations of the form u_t = r * L(u, t) where u is a + * discrete function, L an operator acting on u and r a scalar factor (e.g. -1). + * The specific Runge Kutta method can be chosen as the third template argument. If your desired Runge Kutta method is + * not contained in ExplicitRungeKuttaMethods, choose ExplicitRungeKuttaMethods::other and supply a + * DynamicMatrix< RangeFieldType > A and vectors (DynamicVector< RangeFieldType >) b and c in the constructor. Here, A, + * b and c form the butcher tableau (see https://en.wikipedia.org/wiki/List_of_Runge%E2%80%93Kutta_methods, A is + * composed of the coefficients a_{ij}, b of b_j and c of c_j). The default is a forward euler method. + * + * Notation: For an s-stage method, + * \mathbf{u}^{n+1} = \mathbf{u}^n + dt \sum_{i=0}^{s-1} b_i \mathbf{k}_i + * \mathbf{k}_i = L(\mathbf{u}_i, t^n + dt c_i) + * \mathbf{u}_i = \mathbf{u}^n + dt \sum_{j=0}^{i-1} a_{ij} \mathbf{k}_j, + * + * \tparam OperatorImp Type of operator L + * \tparam DiscreteFunctionImp Type of initial values + */ +template <class OperatorImp, class DiscreteFunctionImp, TimeStepperMethods method = TimeStepperMethods::explicit_euler> +class ExplicitRungeKuttaTimeStepper : public TimeStepperInterface<DiscreteFunctionImp> +{ + using BaseType = TimeStepperInterface<DiscreteFunctionImp>; + using ButcherArrayProviderType = typename internal::ButcherArrayProvider<typename BaseType::RangeFieldType, method>; + +public: + using typename BaseType::DataHandleType; + using typename BaseType::DiscreteFunctionType; + using typename BaseType::DiscreteSolutionType; + using typename BaseType::DomainFieldType; + using typename BaseType::RangeFieldType; + + using OperatorType = OperatorImp; + using MatrixType = Dune::DynamicMatrix<RangeFieldType>; + using VectorType = Dune::DynamicVector<RangeFieldType>; + + using BaseType::current_solution; + using BaseType::current_time; + + /** + * \brief Constructor for RungeKutta time stepper + * \param op Operator L + * \param initial_values Discrete function containing initial values for u at time t_0. + * \param r Scalar factor (see above, default is 1) + * \param t_0 Initial time (default is 0) + * \param A Coefficient matrix (only provide if you use ExplicitRungeKuttaMethods::other) + * \param b Coefficient vector (only provide if you use ExplicitRungeKuttaMethods::other) + * \param c Coefficients for time steps (only provide if you use ExplicitRungeKuttaMethods::other) + */ + ExplicitRungeKuttaTimeStepper(const OperatorType& op, + DiscreteFunctionType& initial_values, + const RangeFieldType r = 1.0, + const double t_0 = 0.0, + const MatrixType& A = ButcherArrayProviderType::A(), + const VectorType& b = ButcherArrayProviderType::b(), + const VectorType& c = ButcherArrayProviderType::c()) + : BaseType(t_0, initial_values) + , op_(op) + , r_(r) + , u_i_(BaseType::current_solution()) + , A_(A) + , b_(b) + , c_(c) + , num_stages_(A_.rows()) + { + assert(A_.rows() == A_.cols() && "A has to be a square matrix"); + assert(b_.size() == A_.rows()); + assert(c_.size() == A_.rows()); +#ifndef NDEBUG + for (size_t ii = 0; ii < A_.rows(); ++ii) { + for (size_t jj = ii; jj < A_.cols(); ++jj) { + assert(Dune::XT::Common::FloatCmp::eq(A_[ii][jj], 0.0) + && "A has to be a lower triangular matrix with 0 on the main diagonal"); + } + } +#endif // NDEBUG + // store as many discrete functions as needed for the stages k + for (size_t ii = 0; ii < num_stages_; ++ii) { + stages_k_.emplace_back(current_solution()); + } + } // constructor + + /** + * \brief Constructor ignoring the tol argument for compatibility with AdaptiveRungeKuttaTimeStepper + */ + ExplicitRungeKuttaTimeStepper(const OperatorType& op, + const DiscreteFunctionType& initial_values, + const RangeFieldType r, + const double t_0, + const RangeFieldType /*tol*/) + : ExplicitRungeKuttaTimeStepper(op, initial_values, r, t_0) + {} + + RangeFieldType step(const RangeFieldType dt, const RangeFieldType max_dt) override final + { + const RangeFieldType actual_dt = std::min(dt, max_dt); + auto& t = current_time(); + auto& u_n = current_solution(); + // calculate stages + for (size_t ii = 0; ii < num_stages_; ++ii) { + u_i_.dofs().vector() = u_n.dofs().vector(); + for (size_t jj = 0; jj < ii; ++jj) + u_i_.dofs().vector() += stages_k_[jj].dofs().vector() * (actual_dt * r_ * (A_[ii][jj])); + // TODO: provide actual_dt to op_. This leads to spurious oscillations in the Lax-Friedrichs flux + // because actual_dt/dx may become very small. + op_.apply(u_i_.dofs().vector(), + stages_k_[ii].dofs().vector(), + XT::Common::Parameter({{"t", {t + actual_dt * c_[ii]}}, {"dt", {dt}}})); + DataHandleType stages_k_ii_handle(stages_k_[ii]); + stages_k_[ii].space().grid_view().template communicate<DataHandleType>( + stages_k_ii_handle, Dune::InteriorBorder_All_Interface, Dune::ForwardCommunication); + } + + // calculate value of u at next time step + for (size_t ii = 0; ii < num_stages_; ++ii) + u_n.dofs().vector() += stages_k_[ii].dofs().vector() * (r_ * actual_dt * b_[ii]); + + // augment time + t += actual_dt; + + return dt; + } // ... step(...) + + const std::pair<bool, RangeFieldType> + find_suitable_dt(const RangeFieldType initial_dt, + const RangeFieldType dt_refinement_factor = 2, + const RangeFieldType treshold = 0.9 * std::numeric_limits<RangeFieldType>::max(), + const size_t max_steps_per_dt = 20, + const size_t max_refinements = 20) + { + auto& t = current_time(); + auto& u_n = current_solution(); + assert(treshold > 0); + // save current state + DiscreteFunctionType initial_u_n = u_n; + RangeFieldType initial_t = t; + // start with initial dt + RangeFieldType current_dt = initial_dt; + size_t num_refinements = 0; + while (num_refinements < max_refinements) { + std::cout << "Trying time step length dt = " << current_dt << "... " << std::flush; + bool unlikely_value_occured = false; + size_t num_steps = 0; + // do max_steps_per_dt time steps... + while (!unlikely_value_occured) { + step(current_dt); + ++num_steps; + // ... unless there is a value above threshold + for (size_t kk = 0; kk < u_n.dofs().vector().size(); ++kk) { + if (std::abs(u_n.dofs().vector()[kk]) > treshold) { + unlikely_value_occured = true; + std::cout << "failed" << std::endl; + break; + } + } + // if we are able to do max_steps_per_dt time steps with this dt, we accept this dt + if (num_steps == max_steps_per_dt) { + std::cout << "looks fine" << std::endl; + u_n.dofs().vector() = initial_u_n.dofs().vector(); + t = initial_t; + return std::make_pair(bool(true), current_dt); + } + } + // if there was a value above threshold start over with smaller dt + u_n.dofs().vector() = initial_u_n.dofs().vector(); + t = initial_t; + current_dt /= dt_refinement_factor; + ++num_refinements; + } + return std::make_pair(bool(false), current_dt); + } + +private: + const OperatorType& op_; + const RangeFieldType r_; + DiscreteFunctionType u_i_; + const MatrixType A_; + const VectorType b_; + const VectorType c_; + std::vector<DiscreteFunctionType> stages_k_; + const size_t num_stages_; +}; + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_TIMESTEPPER_EXPLICIT_RUNGEKUTTA_HH diff --git a/dune/gdt/tools/timestepper/fractional-step.hh b/dune/gdt/tools/timestepper/fractional-step.hh new file mode 100644 index 0000000000000000000000000000000000000000..902ef00effda3b764c8fbaa1cf4224123c3407fa --- /dev/null +++ b/dune/gdt/tools/timestepper/fractional-step.hh @@ -0,0 +1,136 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2016 - 2017) +// Rene Milk (2016 - 2018) +// Tobias Leibner (2016 - 2017) + +#ifndef DUNE_GDT_TIMESTEPPER_FRACTIONAL_STEP_HH +#define DUNE_GDT_TIMESTEPPER_FRACTIONAL_STEP_HH + +#include <utility> + +#include <dune/gdt/operators/interfaces.hh> + +#include <dune/xt/common/memory.hh> +#include <dune/xt/common/string.hh> +#include <dune/xt/la/container.hh> + +#include "interface.hh" + + +namespace Dune { +namespace GDT { + + +/** + * Takes two time steppers and performs a simple fractional step scheme (see e.g. LeVeque, "Finite Volume Methods for + * Hyperbolic Problems", 2002, Section 17.1). In each time step t, the first stepper is applied up to time t+dt and the + * result is taken as input for the second time stepper, which is also applied up to time t+dt. Initial values and time + * are taken from the first time stepper. + */ +template <class FirstStepperImp, class SecondStepperImp> +class FractionalTimeStepper : public TimeStepperInterface<typename FirstStepperImp::DiscreteFunctionType> +{ + using BaseType = TimeStepperInterface<typename FirstStepperImp::DiscreteFunctionType>; + +public: + using typename BaseType::DiscreteFunctionType; + using typename BaseType::DomainFieldType; + using typename BaseType::RangeFieldType; + + using FirstStepperType = FirstStepperImp; + using SecondStepperType = SecondStepperImp; + + using BaseType::current_solution; + using BaseType::current_time; + using BaseType::solution; + + FractionalTimeStepper(FirstStepperType& first_stepper, SecondStepperType& second_stepper) + : BaseType(first_stepper.current_time(), first_stepper.current_solution()) + , first_stepper_(first_stepper) + , second_stepper_(second_stepper) + { + first_stepper_.set_current_solution_pointer(current_solution()); + first_stepper_.set_solution_pointer(solution()); + second_stepper_.set_current_solution_pointer(current_solution()); + second_stepper_.set_solution_pointer(solution()); + } // constructor + + RangeFieldType step(const RangeFieldType dt, const RangeFieldType max_dt) override final + { + auto& t = current_time(); + const RangeFieldType actual_dt = std::min(dt, max_dt); + const auto dt_1 = first_stepper_.solve(t + actual_dt, dt, -1, 0, false); + const auto dt_2 = second_stepper_.solve(t + actual_dt, dt_1, -1, 0, false); + t += actual_dt; + return dt_2; + } // ... step(...) + +private: + FirstStepperType& first_stepper_; + SecondStepperType& second_stepper_; +}; // class FractionalTimeStepper + +/** + * Takes two time steppers and performs a strang splitting fractional step scheme (see e.g. LeVeque, "Finite Volume + * Methods for + * Hyperbolic Problems", 2002, Section 17.1). In each time step t, the first stepper is applied up to time t+dt/2, then + * the + * second time stepper is applied up to time t+dt, then the first stepper is applied again up to time t+dt. Initial + * values and time + * are taken from the first time stepper. + */ +template <class FirstStepperImp, class SecondStepperImp> +class StrangSplittingTimeStepper : public TimeStepperInterface<typename FirstStepperImp::DiscreteFunctionType> +{ + using BaseType = TimeStepperInterface<typename FirstStepperImp::DiscreteFunctionType>; + +public: + using typename BaseType::DiscreteFunctionType; + using typename BaseType::DomainFieldType; + using typename BaseType::RangeFieldType; + + using FirstStepperType = FirstStepperImp; + using SecondStepperType = SecondStepperImp; + + using BaseType::current_solution; + using BaseType::current_time; + using BaseType::solution; + + StrangSplittingTimeStepper(FirstStepperType& first_stepper, SecondStepperType& second_stepper) + : BaseType(first_stepper.current_time(), first_stepper.current_solution()) + , first_stepper_(first_stepper) + , second_stepper_(second_stepper) + { + first_stepper_.set_current_solution_pointer(current_solution()); + first_stepper_.set_solution_pointer(solution()); + second_stepper_.set_current_solution_pointer(current_solution()); + second_stepper_.set_solution_pointer(solution()); + } // constructor + + RangeFieldType step(const RangeFieldType dt, const RangeFieldType max_dt) override final + { + auto& t = current_time(); + const RangeFieldType actual_dt = std::min(dt, max_dt); + first_stepper_.solve(t + actual_dt / 2, actual_dt / 2, static_cast<size_t>(-1), 0, false); + second_stepper_.solve(t + actual_dt, actual_dt, static_cast<size_t>(-1), 0, false); + first_stepper_.solve(t + actual_dt, actual_dt / 2, static_cast<size_t>(-1), 0, false); + t += actual_dt; + return dt; + } // ... step(...) + +private: + FirstStepperType& first_stepper_; + SecondStepperType& second_stepper_; +}; // class StrangSplittingTimeStepper + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_TIMESTEPPER_FRACTIONAL_STEP_HH diff --git a/dune/gdt/tools/timestepper/interface.hh b/dune/gdt/tools/timestepper/interface.hh new file mode 100644 index 0000000000000000000000000000000000000000..08b88370ecc5167f793962a1a11fde80c25e25db --- /dev/null +++ b/dune/gdt/tools/timestepper/interface.hh @@ -0,0 +1,470 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2016 - 2017) +// Rene Milk (2016 - 2018) +// Tobias Leibner (2016 - 2017) + +#ifndef DUNE_GDT_TIMESTEPPER_INTERFACE_HH +#define DUNE_GDT_TIMESTEPPER_INTERFACE_HH + +#include <cstdio> +#include <utility> + +#include <dune/xt/common/memory.hh> +#include <dune/xt/common/string.hh> +#include <dune/xt/common/tuple.hh> + +#include <dune/xt/la/container.hh> + +#include <dune/xt/functions/interfaces/function.hh> +#include <dune/xt/functions/interfaces/grid-function.hh> +#include <dune/xt/functions/generic/grid-function.hh> + +#include <dune/gdt/operators/interfaces.hh> +#include <dune/gdt/discretefunction/default.hh> + +#include "enums.hh" + +namespace Dune { +namespace GDT { +namespace internal { + + +struct FloatCmpLt +{ + template <class A, class B> + bool operator()(const A& a, const B& b) const + { + return Dune::XT::Common::FloatCmp::lt(a, b); + } +}; + + +} // namespace internal + + +template <class DiscreteFunctionImp> +class TimeStepperInterface + : Dune::XT::Common::StorageProvider<DiscreteFunctionImp> + , Dune::XT::Common::StorageProvider< + std::map<typename DiscreteFunctionImp::RangeFieldType, DiscreteFunctionImp, typename internal::FloatCmpLt>> +{ +public: + using DiscreteFunctionType = DiscreteFunctionImp; + using GridViewType = typename DiscreteFunctionType::SpaceType::GridViewType; + using EntityType = typename GridViewType::template Codim<0>::Entity; + using DomainFieldType = typename DiscreteFunctionType::DomainFieldType; + using RangeFieldType = typename DiscreteFunctionType::RangeFieldType; + static const size_t dimDomain = DiscreteFunctionType::d; + static const size_t dimRange = DiscreteFunctionType::r; + static const size_t dimRangeCols = DiscreteFunctionType::rC; + using DomainType = typename DiscreteFunctionType::LocalFunctionType::DomainType; + using RangeType = typename DiscreteFunctionType::LocalFunctionType::RangeType; + using DiscreteSolutionType = typename std::map<RangeFieldType, DiscreteFunctionType, typename internal::FloatCmpLt>; + using GridFunctionType = XT::Functions::GridFunctionInterface<EntityType, dimRange, dimRangeCols, RangeFieldType>; + using DataHandleType = DiscreteFunctionDataHandle<DiscreteFunctionType>; + using VisualizerType = XT::Functions::VisualizerInterface<dimRange, dimRangeCols, RangeFieldType>; + using StringifierType = std::function<std::string(const RangeType&)>; + using ThisType = TimeStepperInterface; + +private: + using CurrentSolutionStorageProviderType = typename Dune::XT::Common::StorageProvider<DiscreteFunctionImp>; + using SolutionStorageProviderType = typename Dune::XT::Common::StorageProvider< + std::map<RangeFieldType, DiscreteFunctionImp, typename internal::FloatCmpLt>>; + +protected: + TimeStepperInterface(const RangeFieldType t_0, DiscreteFunctionType& initial_values) + : CurrentSolutionStorageProviderType(initial_values) + , SolutionStorageProviderType(new DiscreteSolutionType()) + , t_(t_0) + , u_n_(&CurrentSolutionStorageProviderType::access()) + , solution_(&SolutionStorageProviderType::access()) + {} + +public: + TimeStepperInterface(const ThisType& other) = delete; + TimeStepperInterface(ThisType&& source) = delete; + ThisType& operator=(const ThisType& other) = delete; + ThisType& operator=(ThisType&& source) = delete; + + virtual ~TimeStepperInterface() = default; + + /** + * \brief Perform one time step and return the estimated optimal time step length for the next time step. + * \param dt Time step length. + * \param max_dt Maximal allowed time step length in this time step. + * \return Estimated optimal time step length for the next time step. + * \note For adaptive methods or if max_dt < dt, dt is just the initial time step length, the actual time step taken + * may be shorter. To get the actual time step length you need to compare current_time() before and after calling + * step(). + * \note This method has to increase the current time by the actual time step length taken, otherwise + * solve will never finish execution (if current_time is not increased) or give wrong results (if current time is + * increased by a wrong dt). + */ + virtual RangeFieldType step(const RangeFieldType dt, const RangeFieldType max_dt) = 0; + + const RangeFieldType& current_time() const + { + return t_; + } + + RangeFieldType& current_time() + { + return t_; + } + + const DiscreteFunctionType& current_solution() const + { + return *u_n_; + } + + DiscreteFunctionType& current_solution() + { + return *u_n_; + } + + void set_current_solution_pointer(DiscreteFunctionType& discrete_function) + { + u_n_ = &discrete_function; + } + + const DiscreteSolutionType& solution() const + { + return *solution_; + } + + DiscreteSolutionType& solution() + { + return *solution_; + } + + void set_solution_pointer(DiscreteSolutionType& solution_ref) + { + solution_ = &solution_ref; + } + + static const GridFunctionType& dummy_solution() + { + static auto dummy_sol = XT::Functions::GenericGridFunction<EntityType, dimRange, dimRangeCols, RangeFieldType>(0); + return dummy_sol; + } + + /** + * \brief solve Applies time stepping scheme up to time t_end + * \param t_end Final time. + * \param initial_dt Initial time step length. Non-adaptive schemes will use this dt for all time steps. Adaptive + * schemes will use initial_dt as a first guess for the time step length. + * \param num_save_steps Number of time points that will be stored/visualized/written Default is size_t(-1), which + * will store all time steps. + * \param num_output_steps Number of time points where current time and current time step length will be written to + * std::cout. Default is size_t(-1), which will output all time steps. Set to 0 to suppress output. + * \param save_solution If true, the discrete solution at num_save_steps equidistant time points will be stored in + * solution. + * \param visualize If true, solution will be written to .vtp/.vtu files at num_save_steps equidistant time points + * \param write_discrete If true, discrete solution will be written to .txt files at num_save_steps equidistant time + * points + * \param write_exact If true, exact solution will be written to .txt files at num_save_steps equidistant time points + * \param prefix Filename prefix of .vtp/.vtu/.txt files that are written + * \param sol The discrete solution + * \param visualizer Function object that determines how the discrete solution is visualized. + * \param stringifier Function object that determines how RangeType is converted to string before writing to .txt + * files. + * \param exact_solution Exact solution function. + * \return estimated optimal time step length for next step + * \note If num_save_steps is specified (i.e. if it is not size_t(-1), the solution will be stored/visualized at + * exactly num_save_steps + 1 equidistant time points (including the initial time and t_end), even if the time step + * length has to be reduced to hit these time points. + */ + virtual RangeFieldType solve(const RangeFieldType t_end, + const RangeFieldType initial_dt, + const size_t num_save_steps, + const size_t num_output_steps, + const bool save_solution, + const bool visualize, + const bool write_discrete, + const bool write_exact, + const std::string prefix, + DiscreteSolutionType& sol, + const VisualizerType& visualizer, + const StringifierType& stringifier, + const GridFunctionType& exact_solution) + { + RangeFieldType dt = initial_dt; + RangeFieldType t = current_time(); + assert(Dune::XT::Common::FloatCmp::ge(t_end, t)); + size_t time_step_counter = 0; + + const RangeFieldType save_interval = (t_end - t) / num_save_steps; + const RangeFieldType output_interval = + (num_output_steps == 0 ? std::numeric_limits<RangeFieldType>::max() : (t_end - t) / num_output_steps); + RangeFieldType next_save_time = t + save_interval > t_end ? t_end : t + save_interval; + RangeFieldType next_output_time = t + output_interval > t_end ? t_end : t + output_interval; + size_t save_step_counter = 1; + + // save/visualize initial solution + if (save_solution) + sol.insert(std::make_pair(t, current_solution())); + write_files(visualize, + write_discrete, + write_exact, + current_solution(), + exact_solution, + prefix, + 0, + t, + stringifier, + visualizer); + + while (Dune::XT::Common::FloatCmp::lt(t, t_end)) { + RangeFieldType max_dt = dt; + // match saving times and t_end exactly + if (Dune::XT::Common::FloatCmp::gt(t + dt, t_end)) + max_dt = t_end - t; + if (Dune::XT::Common::FloatCmp::gt(t + dt, next_save_time) && num_save_steps != size_t(-1)) + max_dt = std::min(next_save_time - t, max_dt); + + // do a timestep + dt = step(dt, max_dt); + t = current_time(); + + // augment time step counter + ++time_step_counter; + + // check if data should be written in this timestep (and write) + if (Dune::XT::Common::FloatCmp::ge(t, next_save_time) || num_save_steps == size_t(-1)) { + if (save_solution) + sol.insert(sol.end(), std::make_pair(t, current_solution())); + write_files(visualize, + write_discrete, + write_exact, + current_solution(), + exact_solution, + prefix, + save_step_counter, + t, + stringifier, + visualizer); + next_save_time += save_interval; + ++save_step_counter; + } + if (num_output_steps && (Dune::XT::Common::FloatCmp::ge(t, next_output_time) || num_output_steps == size_t(-1))) { + if (current_solution().space().grid_view().comm().rank() == 0) + std::cout << "time step " << time_step_counter << " done, time =" << t << ", current dt= " << dt << std::endl; + next_output_time += output_interval; + } + } // while (t < t_end) + + return dt; + } // ... solve(...) + + // default solve, use internal solution + virtual RangeFieldType solve(const RangeFieldType t_end, + const RangeFieldType initial_dt, + const size_t num_save_steps = size_t(-1), + const size_t num_output_steps = size_t(-1), + const bool save_solution = false, + const bool visualize = false, + const bool write_discrete = false, + const bool write_exact = false, + const std::string prefix = "solution", + const VisualizerType& visualizer = default_visualizer(), + const StringifierType& stringifier = vector_stringifier(), + const GridFunctionType& exact_solution = dummy_solution()) + { + return solve(t_end, + initial_dt, + num_save_steps, + num_output_steps, + save_solution, + visualize, + write_discrete, + write_exact, + prefix, + *solution_, + visualizer, + stringifier, + exact_solution); + } + + // solve and store in sol, no (file) output + virtual RangeFieldType solve(const RangeFieldType t_end, + const RangeFieldType initial_dt, + const size_t num_save_steps, + DiscreteSolutionType& sol) + { + return solve(t_end, + initial_dt, + num_save_steps, + 0, + true, + false, + false, + false, + "", + sol, + default_visualizer(), + vector_stringifier(), + dummy_solution()); + } + + /** + * \brief Find discrete solution for time point that is closest to t. + * + * The timestepper only stores the solution at discrete time points. This function returns the discrete solution + * for + * the stored time point that is closest to the query time t. + * + * \param t Time + * \return std::pair with pair.second the discrete solution at time pair.first + */ + virtual const typename DiscreteSolutionType::value_type& solution_closest_to_time(const RangeFieldType t) const + { + if (solution().empty()) + DUNE_THROW(Dune::InvalidStateException, "Solution is empty!"); + return solution().upper_bound(t)->first - t > t - solution().lower_bound(t)->first ? *solution().lower_bound(t) + : *solution().upper_bound(t); + } + + virtual const DiscreteFunctionType& solution_at_time(const RangeFieldType t) const + { + const auto it = solution().find(t); + if (it == solution().end()) + DUNE_THROW(Dune::InvalidStateException, + "There is no solution for time " + Dune::XT::Common::to_string(t) + " stored in this object!"); + return it->second; + } + + virtual void visualize_solution(const std::string prefix = "", + const VisualizerType& visualizer = default_visualizer()) const + { + size_t counter = 0; + for (const auto& pair : solution()) { + pair.second.visualize(pair.second.space().grid_view(), + prefix + "_" + Dune::XT::Common::to_string(counter), + false, + VTK::appendedraw, + {}, + visualizer); + ++counter; + } + } + + static const VisualizerType& default_visualizer() + { + static auto default_vis = + std::make_unique<XT::Functions::DefaultVisualizer<dimRange, dimRangeCols, RangeFieldType>>(); + return *default_vis; + } + + static StringifierType vector_stringifier() + { + return [](const RangeType& val) { + std::string ret = XT::Common::to_string(val[0], 15); + for (size_t ii = 1; ii < val.size(); ++ii) + ret += " " + XT::Common::to_string(val[ii], 15); + return ret; + }; + } // ... vector_stringifier() + + static std::string rankfile_name(const std::string& prefix, const int rank, const size_t step) + { + return prefix + "_rank_" + XT::Common::to_string(rank) + "_" + XT::Common::to_string(step) + ".txt"; + } + + static void write_to_textfile(const GridFunctionType& u_n, + const GridViewType& grid_view, + const std::string& prefix, + const size_t step, + const RangeFieldType t, + const StringifierType& stringifier, + const bool intersection_wise = false) + { + // write one file per MPI rank + std::ofstream rankfile(rankfile_name(prefix, grid_view.comm().rank(), step)); + const auto local_func = u_n.local_function(); + for (const auto& entity : elements(grid_view, Dune::Partitions::interiorBorder)) { + local_func->bind(entity); + const auto entity_center = entity.geometry().center(); + if (intersection_wise) { + for (const auto& intersection : Dune::intersections(grid_view, entity)) { + auto position = intersection.geometry().center(); + assert(position.size() == dimDomain); + // avoid ambiguity at interface + for (size_t ii = 0; ii < dimDomain; ++ii) + if (position[ii] < entity_center[ii]) + position[ii] += 1e-6 * (entity_center[ii] - position[ii]); + const auto val = local_func->evaluate(entity.geometry().local(position), {"t", t}); + for (size_t ii = 0; ii < dimDomain; ++ii) + rankfile << XT::Common::to_string(position[ii], 15) << " "; + rankfile << stringifier(val) << std::endl; + } // intersections + } else { + auto position = entity_center; + assert(position.size() == dimDomain); + // avoid ambiguity at interface + const auto val = local_func->evaluate(entity.geometry().local(position), {"t", t}); + for (size_t ii = 0; ii < dimDomain; ++ii) + rankfile << XT::Common::to_string(position[ii], 15) << " "; + rankfile << stringifier(val) << std::endl; + } + } + rankfile.close(); + // Wait till files on all ranks are written + grid_view.comm().barrier(); + // Merge files + if (grid_view.comm().rank() == 0) { + const std::string mergedfile_name = prefix + "_" + XT::Common::to_string(step) + ".txt"; + std::remove(mergedfile_name.c_str()); + std::ofstream merged_file(mergedfile_name, std::ios_base::binary | std::ios_base::app); + for (int ii = 0; ii < grid_view.comm().size(); ++ii) { + const std::string rankfile_to_merge_name = rankfile_name(prefix, ii, step); + std::ifstream rankfile_to_merge(rankfile_to_merge_name, std::ios_base::binary); + merged_file << rankfile_to_merge.rdbuf(); + rankfile_to_merge.close(); + std::remove(rankfile_to_merge_name.c_str()); + } // ii + merged_file.close(); + } // if (rank == 0) + } // void write_to_textfile() + + static void write_files(const bool visualize, + const bool write_discrete, + const bool write_exact, + const DiscreteFunctionType& discrete_sol, + const GridFunctionType& exact_sol, + const std::string& prefix, + const size_t step, + const RangeFieldType t, + const StringifierType& stringifier, + const VisualizerType& visualizer) + { + const auto& grid_view = discrete_sol.space().grid_view(); + if (visualize) + discrete_sol.visualize(discrete_sol.space().grid_view(), + prefix + "_" + XT::Common::to_string(step), + false, + VTK::appendedraw, + {}, + visualizer); + if (write_discrete) + write_to_textfile(discrete_sol, grid_view, prefix, step, t, stringifier); + if (write_exact) + write_to_textfile(exact_sol, grid_view, prefix + "_exact", step, t, stringifier); + } + +private: + RangeFieldType t_; + DiscreteFunctionType* u_n_; + DiscreteSolutionType* solution_; +}; // class TimeStepperInterface + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_TIMESTEPPER_INTERFACE_HH diff --git a/dune/gdt/tools/timestepper/matrix-exponential-kinetic-isotropic.hh b/dune/gdt/tools/timestepper/matrix-exponential-kinetic-isotropic.hh new file mode 100644 index 0000000000000000000000000000000000000000..b7a1a4aa6effdfc648cfce857de5aad40a0c657c --- /dev/null +++ b/dune/gdt/tools/timestepper/matrix-exponential-kinetic-isotropic.hh @@ -0,0 +1,173 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Rene Milk (2018) +// Tobias Leibner (2017) + +#ifndef DUNE_GDT_TIMESTEPPER_KINETIC_ISOTROPIC_HH +#define DUNE_GDT_TIMESTEPPER_KINETIC_ISOTROPIC_HH + +#include <dune/xt/grid/functors/interfaces.hh> +#include <dune/xt/grid/walker.hh> + +#include <dune/xt/functions/interfaces/function.hh> + +#include "interface.hh" + +namespace Dune { +namespace GDT { + + +template <class DiscreteFunctionType, class MomentBasis> +class KineticIsotropicLocalFunctor + : public XT::Grid::ElementFunctor<typename DiscreteFunctionType::SpaceType::GridViewType> +{ + using GridViewType = typename DiscreteFunctionType::SpaceType::GridViewType; + using BaseType = typename XT::Grid::ElementFunctor<GridViewType>; + using RangeType = typename DiscreteFunctionType::LocalFunctionType::RangeReturnType; + using ScalarFunctionType = + XT::Functions::FunctionInterface<MomentBasis::dimDomain, 1, 1, typename MomentBasis::RangeFieldType>; + static constexpr size_t dimRange = DiscreteFunctionType::r; + +public: + using typename BaseType::E; + + KineticIsotropicLocalFunctor(const MomentBasis& basis_functions, + DiscreteFunctionType& solution, + const double dt, + const ScalarFunctionType& sigma_a, + const ScalarFunctionType& sigma_s, + const ScalarFunctionType& Q) + + : basis_functions_(basis_functions) + , solution_(solution) + , local_solution_(solution_.local_discrete_function()) + , dt_(dt) + , sigma_a_(sigma_a) + , sigma_s_(sigma_s) + , Q_(Q) + , basis_integrated_(basis_functions_.integrated()) + , u_iso_(basis_functions_.u_iso()) + {} + + KineticIsotropicLocalFunctor(const KineticIsotropicLocalFunctor& other) + : BaseType(other) + , basis_functions_(other.basis_functions_) + , solution_(other.solution_) + , local_solution_(solution_.local_discrete_function()) + , dt_(other.dt_) + , sigma_a_(other.sigma_a_) + , sigma_s_(other.sigma_s_) + , Q_(other.Q_) + , basis_integrated_(other.basis_integrated_) + , u_iso_(other.u_iso_) + {} + + XT::Grid::ElementFunctor<GridViewType>* copy() override final + { + return new KineticIsotropicLocalFunctor(*this); + } + + void apply_local(const E& entity) override final + { + local_solution_->bind(entity); + + // get u + const auto center = entity.geometry().center(); + const auto center_local = entity.geometry().local(center); + const auto u0 = local_solution_->evaluate(center_local); + const auto sigma_a = sigma_a_.evaluate(center)[0]; + const auto sigma_s = sigma_s_.evaluate(center)[0]; + const auto Q = Q_.evaluate(center)[0]; + const auto exp_sigma_a = std::exp(-sigma_a * dt_); + const auto exp_sigma_s = std::exp(-sigma_s * dt_); + const auto u_iso = u_iso_ * basis_functions_.density(u0); + + auto u = exp_sigma_a * (u0 * exp_sigma_s + u_iso * (1 - exp_sigma_s)); + if (!XT::Common::is_zero(sigma_a)) + u += basis_integrated_ * (1 - exp_sigma_a) / sigma_a * Q; + else + u += basis_integrated_ * dt_ * Q; + + // write to return vector + auto& local_vector = local_solution_->dofs(); + for (size_t ii = 0; ii < dimRange; ++ii) + local_vector.set_entry(ii, u[ii]); + } + +private: + const MomentBasis& basis_functions_; + DiscreteFunctionType& solution_; + std::unique_ptr<typename DiscreteFunctionType::LocalDiscreteFunctionType> local_solution_; + const double dt_; + const ScalarFunctionType& sigma_a_; + const ScalarFunctionType& sigma_s_; + const ScalarFunctionType& Q_; + const RangeType basis_integrated_; + const RangeType u_iso_; +}; + + +/** \brief Time stepper solving linear equation d_t u = Au + b by matrix exponential + */ +template <class DiscreteFunctionImp, class MomentBasis> +class KineticIsotropicTimeStepper : public TimeStepperInterface<DiscreteFunctionImp> +{ + typedef KineticIsotropicTimeStepper ThisType; + typedef TimeStepperInterface<DiscreteFunctionImp> BaseType; + +public: + using typename BaseType::DiscreteFunctionType; + using typename BaseType::DomainFieldType; + using typename BaseType::EntityType; + using typename BaseType::RangeFieldType; + static const size_t dimDomain = DiscreteFunctionType::d; + static const size_t dimRange = DiscreteFunctionType::r; + using ScalarFunctionType = XT::Functions::FunctionInterface<dimDomain, 1, 1, RangeFieldType>; + + using BaseType::current_solution; + using BaseType::current_time; + + KineticIsotropicTimeStepper(const MomentBasis& basis_functions, + DiscreteFunctionType& initial_values, + const ScalarFunctionType& sigma_a, + const ScalarFunctionType& sigma_s, + const ScalarFunctionType& Q, + const RangeFieldType t_0 = 0.0) + : BaseType(t_0, initial_values) + , basis_functions_(basis_functions) + , sigma_a_(sigma_a) + , sigma_s_(sigma_s) + , Q_(Q) + {} + + RangeFieldType step(const RangeFieldType dt, const RangeFieldType max_dt) override final + { + const RangeFieldType actual_dt = std::min(dt, max_dt); + auto& t = current_time(); + auto& u_n = current_solution(); + KineticIsotropicLocalFunctor<DiscreteFunctionType, MomentBasis> functor( + basis_functions_, u_n, actual_dt, sigma_a_, sigma_s_, Q_); + auto walker = XT::Grid::Walker<typename DiscreteFunctionType::SpaceType::GridViewType>(u_n.space().grid_view()); + walker.append(functor); + walker.walk(true); + t += actual_dt; + return dt; + } // ... step(...) + +private: + const MomentBasis& basis_functions_; + const ScalarFunctionType& sigma_a_; + const ScalarFunctionType& sigma_s_; + const ScalarFunctionType& Q_; +}; + + +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_TIMESTEPPER_KINETIC_ISOTROPIC_HH diff --git a/dune/gdt/type_traits.hh b/dune/gdt/type_traits.hh index 64c8ff932fe5699ef704a8d4b8372c25eb197fe0..031738a28c319c7ba64ebc94c86725bfc3f21367 100644 --- a/dune/gdt/type_traits.hh +++ b/dune/gdt/type_traits.hh @@ -23,6 +23,7 @@ namespace GDT { enum class SpaceType { + continuous_flattop, continuous_lagrange, discontinuous_lagrange, finite_volume, @@ -34,6 +35,8 @@ std::ostream& operator<<(std::ostream& out, const SpaceType& space_type) { if (space_type == SpaceType::continuous_lagrange) out << "continuous_lagrange"; + else if (space_type == SpaceType::continuous_flattop) + out << "continuous_flattop"; else if (space_type == SpaceType::discontinuous_lagrange) out << "discontinuous_lagrange"; else if (space_type == SpaceType::finite_volume) @@ -80,6 +83,47 @@ class LocalFiniteElementFamilyInterface; template <class GV, size_t r, size_t rC, class R> class SpaceInterface; +// from #include <dune/gdt/test/momentmodels/basisfunctions.hh> +enum class EntropyType; + +template <class DomainFieldType, + size_t dimDomain, + class RangeFieldType, + size_t dimRange, + size_t dimRangeCols, + size_t dimFlux, + EntropyType entropy> +class HatFunctionMomentBasis; + +template <class DomainFieldType, class RangeFieldType, size_t order, size_t dimRangeCols, EntropyType entropy> +class LegendreMomentBasis; + +template <class DomainFieldType, + size_t dimDomain, + class RangeFieldType, + size_t dimRange, + size_t dimRangeCols, + size_t dimFlux, + size_t order, + EntropyType entropy> +class PartialMomentBasis; + +template <class DomainFieldType, + class RangeFieldType, + size_t order, + size_t fluxDim, + bool only_positive, + EntropyType entropy> +class SphericalHarmonicsMomentBasis; + +template <class DomainFieldType, + class RangeFieldType, + size_t order, + size_t fluxDim, + bool only_even, + EntropyType entropy> +class RealSphericalHarmonicsMomentBasis; + namespace internal { @@ -132,6 +176,126 @@ struct is_space<S, true> : public std::is_base_of<SpaceInterface<typename S::GV, {}; +// from #include <dune/gdt/test/momentmodels/basisfunctions.hh> +template <class T> +struct is_hatfunction_basis : public std::false_type +{}; + +template <class DomainFieldType, + size_t dimDomain, + class RangeFieldType, + size_t dimRange_or_refinements, + size_t dimRangeCols, + size_t dimFlux, + EntropyType entropy> +struct is_hatfunction_basis<HatFunctionMomentBasis<DomainFieldType, + dimDomain, + RangeFieldType, + dimRange_or_refinements, + dimRangeCols, + dimFlux, + entropy>> : public std::true_type +{}; + +template <class T> +struct is_legendre_basis : public std::false_type +{}; + +template <class DomainFieldType, class RangeFieldType, size_t order, size_t dimRangeCols, EntropyType entropy> +struct is_legendre_basis<LegendreMomentBasis<DomainFieldType, RangeFieldType, order, dimRangeCols, entropy>> + : public std::true_type +{}; + +template <class T> +struct is_partial_moment_basis : public std::false_type +{}; + +template <class DomainFieldType, + size_t dimDomain, + class RangeFieldType, + size_t dimRange_or_refinements, + size_t dimRangeCols, + size_t dimFlux, + size_t order, + EntropyType entropy> +struct is_partial_moment_basis<PartialMomentBasis<DomainFieldType, + dimDomain, + RangeFieldType, + dimRange_or_refinements, + dimRangeCols, + dimFlux, + order, + entropy>> : public std::true_type +{}; + +template <class T> +struct is_1d_partial_moment_basis : public std::false_type +{}; + +template <class DomainFieldType, + class RangeFieldType, + size_t dimRange_or_refinements, + size_t dimRangeCols, + size_t order, + EntropyType entropy> +struct is_1d_partial_moment_basis< + PartialMomentBasis<DomainFieldType, 1, RangeFieldType, dimRange_or_refinements, dimRangeCols, 1, order, entropy>> + : public std::true_type +{}; + +template <class T> +struct is_3d_partial_moment_basis : public std::false_type +{}; + +template <class DomainFieldType, + class RangeFieldType, + size_t dimRange_or_refinements, + size_t dimRangeCols, + size_t order, + EntropyType entropy> +struct is_3d_partial_moment_basis< + PartialMomentBasis<DomainFieldType, 3, RangeFieldType, dimRange_or_refinements, dimRangeCols, 3, order, entropy>> + : public std::true_type +{}; + +template <class T> +struct is_spherical_harmonics_basis : public std::false_type +{}; + +template <class DomainFieldType, + class RangeFieldType, + size_t order, + size_t fluxDim, + bool only_positive, + EntropyType entropy> +struct is_spherical_harmonics_basis< + SphericalHarmonicsMomentBasis<DomainFieldType, RangeFieldType, order, fluxDim, only_positive, entropy>> + : public std::true_type +{}; + +template <class T> +struct is_real_spherical_harmonics_basis : public std::false_type +{}; + +template <class DomainFieldType, + class RangeFieldType, + size_t order, + size_t fluxDim, + bool only_even, + EntropyType entropy> +struct is_real_spherical_harmonics_basis< + RealSphericalHarmonicsMomentBasis<DomainFieldType, RangeFieldType, order, fluxDim, only_even, entropy>> + : public std::true_type +{}; + +template <class T> +struct is_full_moment_basis +{ + static constexpr bool value = is_legendre_basis<T>::value || is_spherical_harmonics_basis<T>::value + || is_real_spherical_harmonics_basis<T>::value; +}; + + #if 0 // from #include <dune/gdt/playground/spaces/restricted.hh> template <class S, bool candidate = internal::is_restricted_space_helper<S>::is_candidate> diff --git a/examples/adaptive_elliptic_swipdg.cc b/examples/adaptive_elliptic_swipdg.cc index 1e9e995d8e423c0ddb75a2e0de163c04332767c7..bc5a88a1f2df56e322ee63cdd7df85333ac3209e 100644 --- a/examples/adaptive_elliptic_swipdg.cc +++ b/examples/adaptive_elliptic_swipdg.cc @@ -198,8 +198,9 @@ int main(int argc, char* argv[]) // problem const Test::ESV2007DiffusionProblem<GV> problem; - const auto& df = problem.diffusion_factor.as_grid_function<E>(); - const auto& dt = problem.diffusion_tensor.as_grid_function<E>(); + const XT::Functions::ConstantFunction<d> diff_factor(1.); + const auto& df = diff_factor.as_grid_function<E>(); + const auto& dt = problem.diffusion.as_grid_function<E>(); const auto& f = problem.force.as_grid_function<E>(); const auto& boundary_info = problem.boundary_info; diff --git a/examples/mpi_2019_02_talk_on_hyperbolic_equations.cc b/examples/mpi_2019_02_talk_on_hyperbolic_equations.cc index 46163ce1827e51c21d1af25257a39abc9c14651b..80225f445c5543dccf79cc80dd5d0445cbacaf2a 100644 --- a/examples/mpi_2019_02_talk_on_hyperbolic_equations.cc +++ b/examples/mpi_2019_02_talk_on_hyperbolic_equations.cc @@ -29,7 +29,7 @@ #include <dune/gdt/local/numerical-fluxes/generic.hh> #include <dune/gdt/local/numerical-fluxes/upwind.hh> #include <dune/gdt/local/numerical-fluxes/vijayasundaram.hh> -#include <dune/gdt/local/integrands/elliptic.hh> +#include <dune/gdt/local/integrands/laplace.hh> #include <dune/gdt/local/integrands/product.hh> #include <dune/gdt/interpolations.hh> #include <dune/gdt/operators/advection-fv.hh> @@ -188,7 +188,6 @@ XT::LA::ListVectorArray<V> implicit_euler(const DiscreteFunction<V, GV, m>& init GTEST_TEST(MPI201902TalkExamples, instationary_heat_equation) { using G = ONED_1D; - static const size_t d = G::dimension; auto grid = XT::Grid::make_cube_grid<G>(0., 1., 1024); auto grid_view = grid.leaf_view(); using GV = decltype(grid_view); @@ -199,7 +198,7 @@ GTEST_TEST(MPI201902TalkExamples, instationary_heat_equation) auto cg_space = make_continuous_lagrange_space(grid_view, 1); auto dirichlet_constraints = make_dirichlet_constraints(cg_space, boundary_info); auto spatial_op = make_matrix_operator<M>(cg_space, Stencil::element); - spatial_op.append(LocalElementIntegralBilinearForm<E>(LocalEllipticIntegrand<E>(1.))); + spatial_op.append(LocalElementIntegralBilinearForm<E>(LocalLaplaceIntegrand<E>(1.))); spatial_op.append(dirichlet_constraints); auto l2_op = make_matrix_operator<M>(cg_space, Stencil::element); l2_op.append(LocalElementIntegralBilinearForm<E>(LocalElementProductIntegrand<E>(1.))); @@ -212,14 +211,14 @@ GTEST_TEST(MPI201902TalkExamples, instationary_heat_equation) auto time_loop = [&](const double& T_end, const double& dt) { XT::LA::ListVectorArray<V> solution(cg_space.mapper().size(), /*length=*/0, /*reserve=*/std::ceil(T_end / (dt))); // initial values - solution.append(interpolate<V>(0, - [](const auto& xx, const auto& /*param*/) { - if (0.25 <= xx[0] && xx[0] <= 0.5) - return 1.; - else - return 0.; - }, - cg_space) + solution.append(default_interpolation<V>(0, + [](const auto& xx, const auto& /*param*/) { + if (0.25 <= xx[0] && xx[0] <= 0.5) + return 1.; + else + return 0.; + }, + cg_space) .dofs() .vector(), {"_t", 0.}); @@ -239,7 +238,7 @@ GTEST_TEST(MPI201902TalkExamples, instationary_heat_equation) const BochnerSpace<GV> bochner_space(cg_space, time_points_from_vector_array(solution)); const auto timdomain_solution = make_discrete_bochner_function(bochner_space, solution); for (size_t ii = 0; ii < 100; ++ii) { - const double time = ii * (T_end / 100); + time = ii * (T_end / 100); timdomain_solution.evaluate(time).visualize(XT::Common::Test::get_unique_test_name() + "__dt" + XT::Common::to_string(dt) + "_solution_" + XT::Common::to_string(ii)); @@ -259,7 +258,6 @@ GTEST_TEST(MPI201902TalkExamples, linear_transport) auto grid = XT::Grid::make_cube_grid<G>(0., 1., 1024); auto grid_view = XT::Grid::make_periodic_grid_view(grid.leaf_view()); using GV = decltype(grid_view); - using E = XT::Grid::extract_entity_t<GV>; using I = XT::Grid::extract_intersection_t<GV>; auto V_h_0 = make_finite_volume_space(grid_view); @@ -269,17 +267,17 @@ GTEST_TEST(MPI201902TalkExamples, linear_transport) "transport_to_the_right", {}, [&](const auto& /*w*/, const auto& /*param*/) { return 1.; }); - const NumericalUpwindFlux<d, 1> g(f); + const NumericalUpwindFlux<I, d, 1> g(f); auto L_h = make_advection_fv_operator<M>(grid_view, g, V_h_0, V_h_0); - auto w_0 = interpolate<V>(0, - [](const auto& xx, const auto& /*param*/) { - if (0.25 <= xx[0] && xx[0] <= 0.5) - return 1.; - else - return 0.; - }, - V_h_0); + auto w_0 = default_interpolation<V>(0, + [](const auto& xx, const auto& /*param*/) { + if (0.25 <= xx[0] && xx[0] <= 0.5) + return 1.; + else + return 0.; + }, + V_h_0); // explicit, the right choice const double T_end = 1.; @@ -304,7 +302,6 @@ GTEST_TEST(MPI201902TalkExamples, burgers) auto grid = XT::Grid::make_cube_grid<G>(0., 1., 1024); auto grid_view = XT::Grid::make_periodic_grid_view(grid.leaf_view()); using GV = decltype(grid_view); - using E = XT::Grid::extract_entity_t<GV>; using I = XT::Grid::extract_intersection_t<GV>; auto V_h_0 = make_finite_volume_space(grid_view); @@ -314,14 +311,14 @@ GTEST_TEST(MPI201902TalkExamples, burgers) "burgers", {}, [&](const auto& w, const auto& /*param*/) { return w; }); - const NumericalUpwindFlux<d, 1> g(f); + const NumericalUpwindFlux<I, d, 1> g(f); auto L_h = make_advection_fv_operator<M>(grid_view, g, V_h_0, V_h_0); - auto w_0 = interpolate<V>(3, - [&](const auto& xx, const auto& /*mu*/) { - return std::exp(-std::pow(xx[0] - 0.33, 2) / (2 * std::pow(0.075, 2))); - }, - V_h_0); + auto w_0 = default_interpolation<V>(3, + [&](const auto& xx, const auto& /*mu*/) { + return std::exp(-std::pow(xx[0] - 0.33, 2) / (2 * std::pow(0.075, 2))); + }, + V_h_0); // explicit const double T_end = 1.; @@ -342,7 +339,6 @@ GTEST_TEST(MPI201902TalkExamples, linear_transport__central_differences) auto grid = XT::Grid::make_cube_grid<G>(0., 1., 16); auto grid_view = XT::Grid::make_periodic_grid_view(grid.leaf_view()); using GV = decltype(grid_view); - using E = XT::Grid::extract_entity_t<GV>; using I = XT::Grid::extract_intersection_t<GV>; auto V_h_0 = make_finite_volume_space(grid_view); @@ -352,20 +348,20 @@ GTEST_TEST(MPI201902TalkExamples, linear_transport__central_differences) "transport_to_the_right", {}, [&](const auto& /*w*/, const auto& /*param*/) { return 1.; }); - const GenericNumericalFlux<d, 1> g( - f, [&](const auto& w_minus, const auto& w_plus, const auto& n, const auto& /*param*/) { + const GenericNumericalFlux<I, d, 1> g( + f, [&](const auto&, const auto&, const auto& w_minus, const auto& w_plus, const auto& n, const auto& /*param*/) { return 0.5 * (f.evaluate(w_minus) + f.evaluate(w_plus)) * n; }); auto L_h = make_advection_fv_operator<M>(grid_view, g, V_h_0, V_h_0); - auto w_0 = interpolate<V>(0, - [](const auto& xx, const auto& /*param*/) { - if (0.25 <= xx[0] && xx[0] <= 0.5) - return 1.; - else - return 0.; - }, - V_h_0); + auto w_0 = default_interpolation<V>(0, + [](const auto& xx, const auto& /*param*/) { + if (0.25 <= xx[0] && xx[0] <= 0.5) + return 1.; + else + return 0.; + }, + V_h_0); // explicit, the right choice const double T_end = 1.; @@ -392,10 +388,11 @@ GTEST_TEST(MPI201902TalkExamples, 2d_euler) auto grid = XT::Grid::make_cube_grid<G>(-1., 1., 128); auto grid_view = XT::Grid::make_periodic_grid_view(grid.leaf_view()); using GV = decltype(grid_view); + using I = XT::Grid::extract_intersection_t<GV>; auto V_h_0 = make_finite_volume_space<m>(grid_view); - const NumericalVijayasundaramFlux<d, m> g( + const NumericalVijayasundaramFlux<I, d, m> g( f, /*flux_eigen_decomposition=*/[&](const auto& /*f*/, const auto& w, const auto& n, const auto& /*param*/) { @@ -405,15 +402,15 @@ GTEST_TEST(MPI201902TalkExamples, 2d_euler) }); auto L_h = make_advection_fv_operator<M>(grid_view, g, V_h_0, V_h_0); - auto w_0 = interpolate<V>(0, - [&](const auto& xx, const auto& /*mu*/) { - if (XT::Common::FloatCmp::ge(xx, DomainType(-0.5)) - && XT::Common::FloatCmp::le(xx, DomainType(0))) - return euler_tools.conservative(/*density=*/4., /*velocity=*/0., /*pressure=*/1.6); - else - return euler_tools.conservative(/*density=*/1., /*velocity=*/0., /*pressure=*/0.4); - }, - V_h_0); + auto w_0 = default_interpolation<V>( + 0, + [&](const auto& xx, const auto& /*mu*/) { + if (XT::Common::FloatCmp::ge(xx, DomainType(-0.5)) && XT::Common::FloatCmp::le(xx, DomainType(0))) + return euler_tools.conservative(/*density=*/4., /*velocity=*/0., /*pressure=*/1.6); + else + return euler_tools.conservative(/*density=*/1., /*velocity=*/0., /*pressure=*/0.4); + }, + V_h_0); const double T_end = 1.; const double dt = estimate_dt_for_hyperbolic_system(grid_view, w_0, f); @@ -437,6 +434,7 @@ GTEST_TEST(MPI201902TalkExamples, burgers_p1_unstable) auto grid = XT::Grid::make_cube_grid<G>(0., 1., 128); auto grid_view = XT::Grid::make_periodic_grid_view(grid.leaf_view()); using GV = decltype(grid_view); + using I = XT::Grid::extract_intersection_t<GV>; const DiscontinuousLagrangeSpace<GV> V_h_1(grid_view, 1); @@ -445,15 +443,15 @@ GTEST_TEST(MPI201902TalkExamples, burgers_p1_unstable) "burgers", {}, [&](const auto& w, const auto& /*param*/) { return w; }); - const NumericalUpwindFlux<d, 1> g(f); + const NumericalUpwindFlux<I, d, 1> g(f); // unstable DG operator const AdvectionDgOperator<M, GV> L_h(grid_view, g, V_h_1, V_h_1, XT::Grid::ApplyOn::NoIntersections<GV>(), 0., 0.); - auto w_0 = interpolate<V>(3, - [&](const auto& xx, const auto& /*mu*/) { - return std::exp(-std::pow(xx[0] - 0.33, 2) / (2 * std::pow(0.075, 2))); - }, - V_h_1); + auto w_0 = default_interpolation<V>(3, + [&](const auto& xx, const auto& /*mu*/) { + return std::exp(-std::pow(xx[0] - 0.33, 2) / (2 * std::pow(0.075, 2))); + }, + V_h_1); const double T_end = 1.; const double fv_dt = estimate_dt_for_hyperbolic_system(grid_view, w_0, f); @@ -469,13 +467,14 @@ GTEST_TEST(MPI201902TalkExamples, burgers_shock_capturing) auto grid = XT::Grid::make_cube_grid<G>(0., 1., 16u); auto grid_view = XT::Grid::make_periodic_grid_view(grid.leaf_view()); using GV = decltype(grid_view); + using I = XT::Grid::extract_intersection_t<GV>; const XT::Functions::GenericFunction<1, d, 1> f(2, [&](const auto& w, const auto& /*param*/) { return 0.5 * w * w; }, "burgers", {}, [&](const auto& w, const auto& /*param*/) { return w; }); - const NumericalEngquistOsherFlux<d, 1> g(f); + const NumericalEngquistOsherFlux<I, d, 1> g(f); auto perform_simulation = [&](const int p, const std::string& prefix, const double& CFL_factor = 0.99) { const DiscontinuousLagrangeSpace<GV> V_h_p(grid_view, p); @@ -483,11 +482,11 @@ GTEST_TEST(MPI201902TalkExamples, burgers_shock_capturing) // stabilized DG operator const AdvectionDgOperator<M, GV> L_h(grid_view, g, V_h_p, V_h_p); - auto w_0 = interpolate<V>(3, - [&](const auto& xx, const auto& /*mu*/) { - return std::exp(-std::pow(xx[0] - 0.33, 2) / (2 * std::pow(0.075, 2))); - }, - V_h_p); + auto w_0 = default_interpolation<V>(3, + [&](const auto& xx, const auto& /*mu*/) { + return std::exp(-std::pow(xx[0] - 0.33, 2) / (2 * std::pow(0.075, 2))); + }, + V_h_p); const double T_end = 1.; const double fv_dt = estimate_dt_for_hyperbolic_system(grid_view, w_0, f); diff --git a/examples/stationary-heat-equation.cc b/examples/stationary-heat-equation.cc index f56e7fc57009da611ac4b25aebe24f8f3f318310..463db173b50049b0fe30194cc76e64506e842c57 100644 --- a/examples/stationary-heat-equation.cc +++ b/examples/stationary-heat-equation.cc @@ -32,7 +32,7 @@ #include <dune/gdt/local/bilinear-forms/integrals.hh> #include <dune/gdt/local/functionals/integrals.hh> #include <dune/gdt/local/integrands/conversion.hh> -#include <dune/gdt/local/integrands/elliptic.hh> +#include <dune/gdt/local/integrands/laplace.hh> #include <dune/gdt/local/integrands/product.hh> #include <dune/gdt/operators/localizable-bilinear-form.hh> #include <dune/gdt/operators/matrix-based.hh> @@ -63,7 +63,6 @@ int main(int argc, char* argv[]) XT::Common::TimedLogger().create(DXTC_CONFIG_GET("logger.info", 1), DXTC_CONFIG_GET("logger.debug", -1)); auto logger = XT::Common::TimedLogger().get("main"); - const XT::Functions::ConstantFunction<d> lambda(1); const XT::Functions::ConstantFunction<d, d, d> kappa( XT::Common::from_string<FieldMatrix<double, d, d>>("[1 0 0; 0 1 0; 0 0 1]")); const XT::Functions::GenericFunction<d> force(3, [](const auto& x, const auto& /*param*/) { @@ -93,8 +92,7 @@ int main(int argc, char* argv[]) auto space = make_continuous_lagrange_space(grid_view, /*polorder=*/1); auto lhs_op = make_matrix_operator<M>(space, Stencil::element); - lhs_op.append(LocalElementIntegralBilinearForm<E>( - LocalEllipticIntegrand<E>(lambda.as_grid_function<E>(), kappa.as_grid_function<E>()))); + lhs_op.append(LocalElementIntegralBilinearForm<E>(LocalLaplaceIntegrand<E>(kappa.as_grid_function<E>()))); auto rhs_func = make_vector_functional<V>(space); rhs_func.append(LocalElementIntegralFunctional<E>( @@ -117,8 +115,7 @@ int main(int argc, char* argv[]) const auto error = solution - exact_solution.as_grid_function<E>(); auto h1_prod = make_localizable_bilinear_form(grid_view, error, error); - h1_prod.append(LocalElementIntegralBilinearForm<E>( - LocalEllipticIntegrand<E>(lambda.as_grid_function<E>(), kappa.as_grid_function<E>()))); + h1_prod.append(LocalElementIntegralBilinearForm<E>(LocalLaplaceIntegrand<E>(kappa.as_grid_function<E>()))); auto l2_prod = make_localizable_bilinear_form(grid_view, error, error); l2_prod.append(LocalElementIntegralBilinearForm<E>(LocalElementProductIntegrand<E>())); diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index d6c2495801cc689b95bc77bbe8d24a1dc6b2cea3..621f4703b6c18aed7895e6b518d8dfefb2bc4934 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -9,5 +9,5 @@ # René Fritze (2018) # ~~~ -add_subdirectory(dune/gdt) +add_subdirectory(dune) dxt_add_python_tests() diff --git a/python/dune/CMakeLists.txt b/python/dune/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..1cb4768f2890209df79dd24a2ec741b8af2444b0 --- /dev/null +++ b/python/dune/CMakeLists.txt @@ -0,0 +1,12 @@ +# ~~~ +# This file is part of the dune-gdt project: +# https://github.com/dune-community/dune-gdt +# Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +# License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +# or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +# with "runtime exception" (http://www.dune-project.org/license.html) +# Authors: +# René Fritze (2018) +# ~~~ + +add_subdirectory(gdt) diff --git a/python/dune/gdt/CMakeLists.txt b/python/dune/gdt/CMakeLists.txt index ce08e9c3b9bfc0d715d9fc392f0fbe6569e8274c..bc0b3d9b0afcd025b4068cf631d8c6534e23f9e3 100644 --- a/python/dune/gdt/CMakeLists.txt +++ b/python/dune/gdt/CMakeLists.txt @@ -18,3 +18,5 @@ dune_pybindxi_add_module(gamm_2019_talk_on_conservative_rb EXCLUDE_FROM_ALL ${header} gamm-2019-talk-on-conservative-rb.cc) + +add_subdirectory(discretefunction) diff --git a/python/dune/gdt/__init__.py b/python/dune/gdt/__init__.py index 490eb3d68cb8d4359a60cccc8adc148fbbeffa1d..dd488b5818436f31e623e01f9d34a37fdc13c6a7 100644 --- a/python/dune/gdt/__init__.py +++ b/python/dune/gdt/__init__.py @@ -9,94 +9,3 @@ # Felix Schindler (2017 - 2018) # René Fritze (2016, 2018) # ~~~ - -from importlib import import_module - -import numpy as np - -import dune.xt.common - -_init_logger_methods = list() -_test_logger_methods = list() -_init_mpi_methods = list() -_other_modules = ('xt.common', 'xt.grid', 'xt.functions', 'xt.la') - -_gdt_modules = () -# 'spaces_block', -# 'local_diffusive_flux_estimation_operator', -# 'local_elliptic_ipdg_operators', -# 'assembler', -# 'discretefunction', -# 'projections', -# 'functionals_elliptic_ipdg', -# 'functionals_l2', -# 'operators_elliptic', -# 'operators_elliptic_ipdg', -# 'operators_fluxreconstruction', -# 'operators_oswaldinterpolation', -# 'operators_ESV2007', -# 'operators_OS2015', -# 'operators_RS2017', -# 'operators_l2', -# 'operators_weighted_l2'] - -for module_name in _gdt_modules: - mod = import_module('.__{}'.format(module_name), 'dune.gdt') - to_import = [name for name in mod.__dict__ if not name.startswith('_')] - globals().update({name: mod.__dict__[name] for name in to_import}) - _init_logger_methods.append(mod.__dict__['_init_logger']) - _test_logger_methods.append(mod.__dict__['_test_logger']) - _init_mpi_methods.append(mod.__dict__['_init_mpi']) - -del _gdt_modules - - -def init_logger(max_info_level=999, - max_debug_level=999, - enable_warnings=True, - enable_colors=True, - info_color='blue', - debug_color='darkgray', - warning_color='red'): - init_logger_methods = _init_logger_methods.copy() - for module_name in _other_modules: - try: - mm = import_module('dune.{}'.format(module_name)) - for init_logger_method in mm._init_logger_methods: - init_logger_methods.append(init_logger_method) - except ModuleNotFoundError: - pass - for init_logger_method in init_logger_methods: - init_logger_method(max_info_level, max_debug_level, enable_warnings, enable_colors, info_color, debug_color, - warning_color) - - -def test_logger(info=True, debug=True, warning=True): - test_logger_methods = _test_logger_methods.copy() - for module_name in _other_modules: - try: - mm = import_module('dune.{}'.format(module_name)) - for test_logger_method in mm._test_logger_methods: - test_logger_methods.append(test_logger_method) - except ModuleNotFoundError: - pass - for test_logger_method in test_logger_methods: - test_logger_method(info, debug, warning) - - -def init_mpi(args=list()): - if DEBUG: - init_mpi_methods = [ - _init_mpi_methods[0], - ] - else: - init_mpi_methods = _init_mpi_methods.copy() - for module_name in _other_modules: - try: - mm = import_module('dune.{}'.format(module_name)) - for init_mpi_method in mm._init_mpi_methods: - init_mpi_methods.append(init_mpi_method) - except ModuleNotFoundError: - pass - for init_mpi_method in init_mpi_methods: - init_mpi_method(args) diff --git a/python/dune/gdt/assembler/system.cc b/python/dune/gdt/assembler/system.cc deleted file mode 100644 index 355bf905df55a86ad54d6698d2d90e1d9fb24048..0000000000000000000000000000000000000000 --- a/python/dune/gdt/assembler/system.cc +++ /dev/null @@ -1,54 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> - -# include <python/dune/gdt/assembler/system.hh> -# include <python/dune/gdt/spaces/constraints.hh> - - -PYBIND11_MODULE(__assembler, m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - py::module::import("dune.gdt.__local_elliptic_ipdg_operators"); - - py::class_<Dune::GDT::bindings::ResultStorage> ResultStorage(m, "ResultStorage", "dune-gdt: ResultStorage"); - ResultStorage.def(pybind11::init<>()); - ResultStorage.def_property( - "result", - [](const Dune::GDT::bindings::ResultStorage& self) { return self.result(); }, - [](Dune::GDT::bindings::ResultStorage& self, const double& value) { self.result() = value; }); - - DUNE_GDT_SPACES_CONSTRAINTS_BIND(m); - DUNE_GDT_ASSEMBLER_SYSTEM_BIND(m); - - add_initialization(m, "dune.gdt.assembler"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/assembler/system.hh b/python/dune/gdt/assembler/system.hh deleted file mode 100644 index db14a2f5c3fc3808bce918e7907cb75c2420f9e1..0000000000000000000000000000000000000000 --- a/python/dune/gdt/assembler/system.hh +++ /dev/null @@ -1,394 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_ASSEMBLER_SYSTEM_BINDINGS_HH -#define PYTHON_DUNE_GDT_ASSEMBLER_SYSTEM_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/common/memory.hh> -# include <dune/xt/la/container.hh> -# include <dune/xt/grid/grids.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <python/dune/xt/grid/layers.bindings.hh> -# include <dune/xt/grid/walker.hh> - -# include <python/dune/gdt/spaces/bindings.hh> -# include <python/dune/gdt/spaces/constraints.hh> -# include <dune/gdt/type_traits.hh> - -# include <dune/gdt/assembler/system.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -class ResultStorage -{ -public: - ResultStorage() - : result_(0.) - { - } - - ResultStorage(const ResultStorage& other) = delete; - ResultStorage(ResultStorage&& source) = delete; - - ResultStorage& operator=(const ResultStorage& other) = delete; - ResultStorage& operator=(ResultStorage&& source) = delete; - - double& result() - { - return result_; - } - - const double& result() const - { - return result_; - } - -private: - double result_; -}; // class ResultStorage - - -template <class TP, XT::Grid::Layers grid_layer, XT::Grid::Backends grid_backend> -class SystemAssembler -{ - typedef typename TP::type T; - static_assert(is_space<T>::value, ""); - typedef XT::Grid::extract_grid_t<typename T::GridLayerType> G; - typedef typename XT::Grid::Layer<G, grid_layer, grid_backend, XT::Grid::DD::SubdomainGrid<G>>::type GL; - typedef XT::Grid::extract_entity_t<GL> E; - typedef typename G::ctype D; - static const constexpr size_t d = G::dimension; - -public: - typedef GDT::SystemAssembler<T, GL> type; - typedef pybind11::class_<type, XT::Grid::Walker<GL>> bound_type; - -private: - typedef typename type::TestSpaceType TestSpaceType; - typedef typename type::GridLayerType GridLayerType; - typedef typename type::AnsatzSpaceType AnsatzSpaceType; - - template <bool do_bind = (std::is_same<TestSpaceType, AnsatzSpaceType>::value - && std::is_same<GridLayerType, typename TestSpaceType::GridLayerType>::value), - bool anything = true> - struct addbind_ctor_single - { - void operator()(bound_type& c) - { - namespace py = pybind11; - using namespace pybind11::literals; - c.def(py::init<T>(), - "space"_a, - "Uses given space as test and ansatz space, and the grid layer of the given space as grid layer.", - py::keep_alive<1, 2>()); - } - }; // struct addbind_ctor_single - - template <bool anything> - struct addbind_ctor_single<false, anything> - { - void operator()(bound_type& /*c*/) - { - } - }; // struct addbind_ctor_single - - template <bool same = std::is_same<GL, typename T::GridLayerType>::value, bool anything = true> - struct space_and_layer_name - { - static std::string value() - { - return space_name<TP>::value(); - } - }; - - template <bool anything> - struct space_and_layer_name<false, anything> - { - static std::string value() - { - return space_name<TP>::value() + "_" + XT::Grid::bindings::layer_name<grid_layer>::value() + "_" - + XT::Grid::bindings::backend_name<grid_backend>::value(); - } - }; - - template <bool same = std::is_same<GL, typename T::GridLayerType>::value, bool anything = true> - struct addbind_factory_methods - { - void operator()(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - m.def("make_system_assembler", - [](const TestSpaceType& space) { return new type(space); }, - "space"_a, - py::keep_alive<0, 1>()); - } - }; - - template <bool anything> - struct addbind_factory_methods<false, anything> - { - void operator()(pybind11::module& /*m*/) - { - } - }; - - template <XT::LA::Backends la> - static void addaddbind_matrixatrix(bound_type& c) - { - namespace py = pybind11; - using namespace pybind11::literals; - - typedef typename XT::LA::Container<typename T::RangeFieldType, la>::MatrixType M; - - c.def("append", - [](type& self, - const GDT::LocalBoundaryTwoFormInterface<typename T::BaseFunctionSetType, - XT::Grid::extract_intersection_t<GL>>& local_boundary_two_form, - M& matrix, - const XT::Grid::ApplyOn::WhichIntersection<GL>& which_intersections) { - self.append(local_boundary_two_form, matrix, which_intersections.copy()); - }, - "local_boundary_two_form"_a, - "matrix"_a, - "which_intersections"_a = XT::Grid::ApplyOn::AllIntersections<GL>(), - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>()); - c.def("append", - [](type& self, - const GDT::LocalCouplingTwoFormInterface<typename T::BaseFunctionSetType, - XT::Grid::extract_intersection_t<GL>>& local_coupling_two_form, - M& matrix, - const XT::Grid::ApplyOn::WhichIntersection<GL>& which_intersections) { - self.append(local_coupling_two_form, matrix, which_intersections.copy()); - }, - "local_coupling_two_form"_a, - "matrix"_a, - "which_intersections"_a = XT::Grid::ApplyOn::AllIntersections<GL>(), - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>()); - c.def("append", - [](type& self, - const GDT::LocalCouplingTwoFormInterface<typename T::BaseFunctionSetType, - XT::Grid::extract_intersection_t<GL>>& local_coupling_two_form, - M& matrix_in_in, - M& matrix_out_out, - M& matrix_in_out, - M& matrix_out_in, - const XT::Grid::ApplyOn::WhichIntersection<GL>& which_intersections) { - self.append(local_coupling_two_form, - matrix_in_in, - matrix_out_out, - matrix_in_out, - matrix_out_in, - which_intersections.copy()); - }, - "local_coupling_two_form"_a, - "matrix_in_in"_a, - "matrix_out_out"_a, - "matrix_in_out"_a, - "matrix_out_in"_a, - "which_intersections"_a = XT::Grid::ApplyOn::AllIntersections<GL>(), - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>(), - py::keep_alive<0, 4>(), - py::keep_alive<0, 5>()); - } // ... addaddbind_matrixatrix(...) - -public: - static bound_type bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto ClassName = - XT::Common::to_camel_case(std::string("system_assembler_") + space_and_layer_name<>::value()); - - bound_type c(m, ClassName.c_str(), ClassName.c_str()); - addbind_ctor_single<>()(c); - - c.def("append", - [](type& self, type& other, const XT::Grid::ApplyOn::WhichIntersection<GL>& which_intersections) { - self.append(other, which_intersections.copy()); - }, - "system_assembler"_a, - "which_intersections"_a = XT::Grid::ApplyOn::AllIntersections<GL>(), - py::keep_alive<1, 2>()); - c.def("append", - [](type& self, - XT::Grid::Walker<GridLayerType>& other, - const XT::Grid::ApplyOn::WhichIntersection<GL>& which_intersections) { - self.append(other, which_intersections.copy()); - }, - "grid_walker"_a, - "which_intersections"_a = XT::Grid::ApplyOn::AllIntersections<GL>(), - py::keep_alive<1, 2>()); - c.def("assemble", - [](type& self, const bool use_tbb) { - py::gil_scoped_release DUNE_UNUSED(release); - self.assemble(use_tbb); - }, - "use_tbb"_a = false); - - bindings::DirichletConstraints<XT::Grid::extract_intersection_t<typename type::GridLayerType>, - XT::Grid::extract_grid_t<typename type::GridLayerType>>::addbind(c); - -# if HAVE_DUNE_ISTL - addaddbind_matrixatrix<XT::LA::Backends::istl_sparse>(c); -# endif - - c.def("append", - [](type& self, - const GDT::LocalVolumeTwoFormInterface<XT::Functions::LocalfunctionInterface<E, D, d, double, 1>, - XT::Functions::LocalfunctionInterface<E, D, d, double, 1>, - double>& local_volume_two_form, - const XT::Functions::GridFunctionInterface<E, D, d, double, 1>& test_function, - const XT::Functions::GridFunctionInterface<E, D, d, double, 1>& ansatz_function, - ResultStorage& result /*, - const XT::Grid::ApplyOn::WhichEntity<GL>& where*/) { - self.append(local_volume_two_form, test_function, ansatz_function, result.result() /*, where.copy()*/); - }, - "local_volume_two_form"_a, - "test_function"_a, - "ansatz_function"_a, - "result"_a /*, - "where"_a = XT::Grid::ApplyOn::AllEntities<GL>()*/, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>()); - - addbind_factory_methods<>()(m); - - return c; - } // ... bind(...) -}; // class SystemAssembler - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - - -// begin: this is what we need for the lib - -# define _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB( \ - _pre, _G, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) \ - _pre class Dune::GDT::bindings::SystemAssembler<Dune::GDT::SpaceProvider<_G, \ - Dune::XT::Grid::Layers::_s_grid_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - _r, \ - _rC>, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::XT::Grid::Backends::_g_backend> - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_ALU_SPACE( \ - _pre, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB( \ - _pre, ALU_2D_SIMPLEX_CONFORMING, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) -# else -# define _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_ALU_SPACE( \ - _pre, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) -# endif - -# define _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_YASP_SPACE( \ - _pre, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB( \ - _pre, YASP_1D_EQUIDISTANT_OFFSET, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB( \ - _pre, YASP_2D_EQUIDISTANT_OFFSET, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) - -# define _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_ALU(_pre, _s_type, _p, _r, _rC) \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_ALU_SPACE(_pre, leaf, view, _s_type, gdt, leaf, _p, 1, 1); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_ALU_SPACE(_pre, level, view, _s_type, gdt, level, _p, 1, 1) - -# define _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_YASP(_pre, _s_type, _p, _r, _rC) \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_YASP_SPACE(_pre, leaf, view, _s_type, gdt, leaf, _p, 1, 1); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_YASP_SPACE(_pre, level, view, _s_type, gdt, level, _p, 1, 1) - -# define DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_ALU(_pre) \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_ALU(_pre, fv, 0, 1, 1); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_ALU(_pre, cg, 1, 1, 1) - -# define DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_YASP(_pre) \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_YASP(_pre, fv, 0, 1, 1); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_YASP(_pre, cg, 1, 1, 1) - -# define DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB(_pre) \ - DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_ALU(_pre); \ - DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_YASP(_pre) - -DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB(extern template); - -// end: this is what we need for the lib -// begin: this is what we need for the .so - - -# define _DUNE_GDT_ASSEMBLER_SYSTEM_BIND( \ - _m, _G, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) \ - Dune::GDT::bindings::SystemAssembler<Dune::GDT::SpaceProvider<_G, \ - Dune::XT::Grid::Layers::_s_grid_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - _r, \ - _rC>, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::XT::Grid::Backends::_g_backend>::bind(_m) - -# define _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_YASP( \ - _m, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND( \ - _m, YASP_1D_EQUIDISTANT_OFFSET, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND( \ - _m, YASP_2D_EQUIDISTANT_OFFSET, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_ALU( \ - _m, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND( \ - _m, ALU_2D_SIMPLEX_CONFORMING, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) -# else -# define _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_ALU( \ - _m, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) -# endif - -# define _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_ALL_GRIDS( \ - _m, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_YASP(_m, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_ALU(_m, _g_layer, _g_backend, _s_type, _s_backend, _s_grid_layer, _p, _r, _rC) - - -# define DUNE_GDT_ASSEMBLER_SYSTEM_BIND(_m) \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_ALL_GRIDS(_m, dd_subdomain_boundary, view, dg, gdt, dd_subdomain, 1, 1, 1); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_ALL_GRIDS(_m, dd_subdomain_coupling, view, dg, gdt, dd_subdomain, 1, 1, 1); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_ALL_GRIDS(_m, leaf, view, cg, gdt, leaf, 1, 1, 1); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_ALL_GRIDS(_m, level, view, cg, gdt, level, 1, 1, 1); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_ALL_GRIDS(_m, leaf, view, fv, gdt, leaf, 0, 1, 1); \ - _DUNE_GDT_ASSEMBLER_SYSTEM_BIND_ALL_GRIDS(_m, level, view, fv, gdt, level, 0, 1, 1) -// end: this is what we need for the .so - - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_ASSEMBLER_SYSTEM_BINDINGS_HH diff --git a/python/dune/gdt/assembler/system/alu.cc b/python/dune/gdt/assembler/system/alu.cc deleted file mode 100644 index 68a3a27f8910bab9a5b4dc09705cd39bfe3acdf1..0000000000000000000000000000000000000000 --- a/python/dune/gdt/assembler/system/alu.cc +++ /dev/null @@ -1,30 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI && HAVE_DUNE_ALUGRID - -# include "../system.hh" - - -namespace Dune { -namespace GDT { -namespace bindings { - - -DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_ALU(template); - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI && HAVE_DUNE_ALUGRID diff --git a/python/dune/gdt/assembler/system/yasp.cc b/python/dune/gdt/assembler/system/yasp.cc deleted file mode 100644 index 0b1360bfbc0770a963157e1ccd05953a97e5af37..0000000000000000000000000000000000000000 --- a/python/dune/gdt/assembler/system/yasp.cc +++ /dev/null @@ -1,30 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include "../system.hh" - - -namespace Dune { -namespace GDT { -namespace bindings { - - -DUNE_GDT_ASSEMBLER_SYSTEM_BIND_LIB_YASP(template); - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/discretefunction/CMakeLists.txt b/python/dune/gdt/discretefunction/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..41c2d4c1724a55a3b58e79d73d751bcce82957c3 --- /dev/null +++ b/python/dune/gdt/discretefunction/CMakeLists.txt @@ -0,0 +1,16 @@ +# ~~~ +# This file is part of the dune-gdt project: +# https://github.com/dune-community/dune-gdt +# Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +# License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +# or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +# with "runtime exception" (http://www.dune-project.org/license.html) +# Authors: +# Felix Schindler (2018) +# René Fritze (2018) +# Tobias Leibner (2018) +# ~~~ + +dune_pybindxi_add_module(_discretefunction_1d EXCLUDE_FROM_ALL ${header} discretefunction_1d.cc) +dune_pybindxi_add_module(_discretefunction_2d EXCLUDE_FROM_ALL ${header} discretefunction_2d.cc) +dune_pybindxi_add_module(_discretefunction_3d EXCLUDE_FROM_ALL ${header} discretefunction_3d.cc) diff --git a/python/dune/gdt/discretefunction/__init__.py b/python/dune/gdt/discretefunction/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c2b7cd23b3dfd3bdaf597501c2a446b978a24d73 --- /dev/null +++ b/python/dune/gdt/discretefunction/__init__.py @@ -0,0 +1,26 @@ +# ~~~ +# This file is part of the dune-xt-grid project: +# https://github.com/dune-community/dune-xt-grid +# Copyright 2009-2018 dune-xt-grid developers and contributors. All rights reserved. +# License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +# or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +# with "runtime exception" (http://www.dune-project.org/license.html) +# Authors: +# Felix Schindler (2017) +# René Fritze (2018) +# ~~~ + +from dune.xt import guarded_import + +from ._discretefunction_1d import * +from ._discretefunction_2d import * +from ._discretefunction_3d import * + + +def make_discrete_function(space, vector, name="dune.gdt.discretefunction"): + for factory in [globals()[s] for s in globals().keys() if s.startswith('make_discrete_function_')]: + try: + return factory(space, vector, name) + except: + continue + raise TypeError('no matching factory for space \'{}\''.format(space)) diff --git a/python/dune/gdt/discretefunction/bindings.cc b/python/dune/gdt/discretefunction/bindings.cc deleted file mode 100644 index bfd4e85733ed5b6e3a7e2d643c7a2ca5485a9e58..0000000000000000000000000000000000000000 --- a/python/dune/gdt/discretefunction/bindings.cc +++ /dev/null @@ -1,44 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> - -# include <python/dune/gdt/discretefunction/bindings.hh> -# include <python/dune/gdt/shared.hh> - -PYBIND11_MODULE(__discretefunction, m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - py::module::import("dune.gdt.__spaces_block"); - - DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND(m); - - add_initialization(m, "dune.gdt.discretefunction"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/discretefunction/bindings.hh b/python/dune/gdt/discretefunction/bindings.hh deleted file mode 100644 index 9bf2d74d03bad7014c8d43996d9297a9935a418d..0000000000000000000000000000000000000000 --- a/python/dune/gdt/discretefunction/bindings.hh +++ /dev/null @@ -1,330 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BINDINGS_HH -#define PYTHON_DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <python/dune/xt/common/bindings.hh> -# include <dune/xt/grid/dd/subdomains/grid.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <dune/xt/grid/layers.hh> -# include <dune/xt/la/type_traits.hh> -# include <python/dune/xt/la/container.bindings.hh> - -# include <dune/gdt/spaces/bindings.hh> -# include <dune/gdt/playground/spaces/block.hh> -# include <dune/gdt/playground/spaces/restricted.hh> -# include <dune/gdt/type_traits.hh> - -# include <dune/gdt/discretefunction/default.hh> - -namespace Dune { -namespace GDT { -namespace bindings { -namespace internal { - - -template <class S, class V> -class ConstDiscreteFunction -{ - static_assert(is_space<S>::value, ""); - static_assert(XT::LA::is_vector<V>::value, ""); - typedef XT::Grid::extract_grid_t<typename S::GridLayerType> G; - -public: - typedef GDT::ConstDiscreteFunction<S, V> type; - -private: - typedef XT::Functions::GridFunctionInterface<typename S::EntityType, - typename S::DomainFieldType, - S::dimDomain, - typename S::RangeFieldType, - S::dimRange, - S::dimRangeCols> - BaseType; - -public: - typedef pybind11::class_<type, BaseType> bound_type; - - static bound_type bind(pybind11::module& m, const std::string& space_name) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto ClassName = XT::Common::to_camel_case("const_discrete_function_" + space_name + "_" - + XT::LA::bindings::container_name<V>::value()); - - bound_type c(m, ClassName.c_str(), ClassName.c_str()); - c.def(py::init<const S&, V&, const std::string>(), - "space"_a, - "vector"_a, - "name"_a = "gdt.constdiscretefunction", - py::keep_alive<1, 2>(), - py::keep_alive<1, 3>()); - c.def("space", [](type& self) { return self.space(); }); - c.def("vector_copy", [](type& self) { return self.vector(); }); - c.def("visualize", - [](type& self, const std::string filename, const bool subsampling) { - return self.visualize(filename, subsampling); - }, - "filename"_a, - "subsampling"_a = (S::polOrder > 1)); - // these two are copied from <dune/xt/functions/interfaces.pbh>, would be nicer to inherit them - c.def("visualize", - [](const type& self, - const XT::Grid::GridProvider<G>& grid_provider, - const std::string& layer, - const ssize_t lvl, - const std::string& path, - const bool subsampling) { - const auto level = XT::Common::numeric_cast<int>(lvl); - if (layer == "leaf") - self.visualize(grid_provider.leaf_view(), path, subsampling); - else if (layer == "level") - self.visualize(grid_provider.template layer<XT::Grid::Layers::level, XT::Grid::Backends::view>(level), - path, - subsampling); - else - DUNE_THROW(XT::Common::Exceptions::wrong_input_given, - "Given layer has to be one of ('leaf', 'level'), is '" << layer << "'!"); - }, - "grid_provider"_a, - "layer"_a = "leaf", - "level"_a = -1, - "path"_a, - "subsampling"_a = true); - c.def("visualize", - [](const type& self, - const XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const std::string& layer, - const ssize_t lvl_or_sbdmn, - const std::string& path, - const bool subsampling) { - const auto level_or_subdomain = XT::Common::numeric_cast<int>(lvl_or_sbdmn); - if (layer == "leaf") - self.visualize(dd_grid_provider.leaf_view(), path, subsampling); - else if (layer == "level") - self.visualize(dd_grid_provider.template layer<XT::Grid::Layers::level, XT::Grid::Backends::view>( - level_or_subdomain), - path, - subsampling); - else if (layer == "dd_subdomain") - self.visualize(dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain, XT::Grid::Backends::view>( - level_or_subdomain), - path, - subsampling); - else if (layer == "dd_subdomain_oversampled") - self.visualize( - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain_oversampled, XT::Grid::Backends::view>( - level_or_subdomain), - path, - subsampling); - else - DUNE_THROW( - XT::Common::Exceptions::wrong_input_given, - "Given layer has to be one of ('leaf', 'level', 'dd_subdomain', 'dd_subdomain_oversampled'), is '" - << layer - << "'!"); - }, - "dd_grid_provider"_a, - "layer"_a = "leaf", - "level_or_subdomain"_a = -1, - "path"_a, - "subsampling"_a = true); - return c; - } // ... bind(...) -}; // class ConstDiscreteFunction - - -template <class S, class V> -class DiscreteFunction -{ - static_assert(is_space<S>::value, ""); - static_assert(XT::LA::is_vector<V>::value, ""); - - typedef GDT::ConstDiscreteFunction<S, V> BaseType; - -public: - typedef GDT::DiscreteFunction<S, V> type; - typedef pybind11::class_<type, BaseType> bound_type; - - static bound_type bind(pybind11::module& m, const std::string& space_name) - { - namespace py = pybind11; - using namespace pybind11::literals; - - bindings::internal::ConstDiscreteFunction<S, V>::bind(m, space_name); - - const auto ClassName = XT::Common::to_camel_case("discrete_function_" + space_name + "_" - + XT::LA::bindings::container_name<V>::value()); - - bound_type c(m, ClassName.c_str(), ClassName.c_str()); - c.def(py::init<const S&, V&, const std::string>(), - "space"_a, - "vector"_a, - "name"_a = "gdt.discretefunction", - py::keep_alive<1, 2>(), - py::keep_alive<1, 3>()); - c.def( - py::init<const S&, const std::string>(), "space"_a, "name"_a = "gdt.discretefunction", py::keep_alive<1, 2>()); - - m.def( - std::string("make_discrete_function").c_str(), - [](const S& space, V& vector, const std::string& name) { return make_discrete_function(space, vector, name); }, - "space"_a, - "vector"_a, - "name"_a = "gdt.discretefunction", - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>()); - m.def(std::string("make_discrete_function").c_str(), - [](const S& space, const std::string& name) { return make_discrete_function<V>(space, name); }, - "space"_a, - "name"_a = "gdt.discretefunction", - py::keep_alive<0, 1>()); - - return c; - } // ... bind(...) - -}; // class DiscreteFunction - - -} // namespace internal - - -template <class SP, class V> -class DiscreteFunction -{ - typedef typename SP::type S; - static_assert(is_space<S>::value, ""); - static_assert(XT::LA::is_vector<V>::value, ""); - typedef GDT::ConstDiscreteFunction<S, V> BaseType; - -public: - typedef GDT::DiscreteFunction<S, V> type; - typedef pybind11::class_<type, BaseType> bound_type; - - template <XT::Grid::Backends backend, XT::Grid::Layers layer> - static void addbind_restricted(pybind11::module& m, const std::string sp_name) - { - try { // we might not be the first to add this - internal::DiscreteFunction<GDT::RestrictedSpace<S, - typename XT::Grid:: - Layer<XT::Grid::extract_grid_t<typename S::GridLayerType>, - layer, - backend>::type>, - V>::bind(m, - sp_name + "_restricted_to_" + XT::Grid::bindings::layer_name<layer>::value() - + "_" - + XT::Grid::bindings::backend_name<backend>::value()); - } catch (std::runtime_error&) { - } - } // ... addbind_restricted(...) - - static bound_type bind(pybind11::module& m) - { - const auto sp_name = space_name<SP>::value(); - auto c = internal::DiscreteFunction<S, V>::bind(m, sp_name); - - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::dd_subdomain>(m, sp_name); - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::dd_subdomain_boundary>(m, sp_name); - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::dd_subdomain_coupling>(m, sp_name); - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::dd_subdomain_oversampled>(m, sp_name); - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::leaf>(m, sp_name); - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::level>(m, sp_name); - - return c; - } -}; // class DiscreteFunction - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - - -// begin: this is what we need for the .so - - -# define _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC, _la) \ - Dune::GDT::bindings::DiscreteFunction< \ - Dune::GDT::SpaceProvider<_G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - _r, \ - _rC>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>::bind(_m) - -# define _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_COMMON(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC) \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC, common_dense) - -# if HAVE_EIGEN -# define _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_EIGEN(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC) \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC, eigen_dense) -# else -# define _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_EIGEN(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC) -# endif - -# if HAVE_DUNE_ISTL -# define _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ISTL(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC) \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC, istl_dense) -# else -# define _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ISTL(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC) -# endif - -# define _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_LA(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC) \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_COMMON(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_EIGEN(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ISTL(_m, _G, _g_layer, _s_type, _s_backend, _p, _r, _rC) - -# define _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_YASP(_m, _g_layer, _s_type, _s_backend, _p, _r, _rC) \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_LA( \ - _m, YASP_1D_EQUIDISTANT_OFFSET, _g_layer, _s_type, _s_backend, _p, _r, _rC); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_LA( \ - _m, YASP_2D_EQUIDISTANT_OFFSET, _g_layer, _s_type, _s_backend, _p, _r, _rC) - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALU(_m, _g_layer, _s_type, _s_backend, _p, _r, _rC) \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_LA( \ - _m, ALU_2D_SIMPLEX_CONFORMING, _g_layer, _s_type, _s_backend, _p, _r, _rC) -# else -# define _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALU(_m, _g_layer, _s_type, _s_backend, _p, _r, _rC) -# endif - -# define _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_GRIDS(_m, _g_layer, _s_type, _s_backend, _p, _r, _rC) \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_YASP(_m, _g_layer, _s_type, _s_backend, _p, _r, _rC); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALU(_m, _g_layer, _s_type, _s_backend, _p, _r, _rC) - -# define DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND(_m) \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_GRIDS(_m, leaf, dg, gdt, 1, 1, 1); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_GRIDS(_m, level, dg, gdt, 1, 1, 1); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_GRIDS(_m, leaf, fv, gdt, 0, 1, 1); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_GRIDS(_m, level, fv, gdt, 0, 1, 1); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_GRIDS(_m, leaf, cg, gdt, 1, 1, 1); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_GRIDS(_m, level, cg, gdt, 1, 1, 1); - -# define DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_DD(_m) \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_GRIDS(_m, dd_subdomain, dg, gdt, 1, 1, 1); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_GRIDS(_m, dd_subdomain, block_dg, gdt, 1, 1, 1); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_GRIDS(_m, dd_subdomain, cg, gdt, 1, 1, 1); \ - _DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BIND_ALL_GRIDS(_m, dd_subdomain, block_cg, gdt, 1, 1, 1); - -// end: this is what we need for the .so - - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BINDINGS_HH diff --git a/python/dune/gdt/discretefunction/discretefunction.hh b/python/dune/gdt/discretefunction/discretefunction.hh new file mode 100644 index 0000000000000000000000000000000000000000..76542869ce333cfdeeb31cb5542415cec2a136fd --- /dev/null +++ b/python/dune/gdt/discretefunction/discretefunction.hh @@ -0,0 +1,165 @@ +// This file is part of the dune-gdt project: +// https://github.com/dune-community/dune-gdt +// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. +// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) +// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) +// with "runtime exception" (http://www.dune-project.org/license.html) +// Authors: +// Felix Schindler (2017 - 2018) +// René Fritze (2018) +// Tobias Leibner (2018) + +#ifndef PYTHON_DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BINDINGS_HH +#define PYTHON_DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BINDINGS_HH + +#if HAVE_DUNE_PYBINDXI + +# include <dune/pybindxi/pybind11.h> + +# include <python/dune/xt/common/exceptions.bindings.hh> +# include <python/dune/xt/la/container.bindings.hh> +# include <python/dune/xt/grid/grids.bindings.hh> +# include <python/dune/xt/functions/gridfunction-interface.hh> + +# include <dune/xt/common/python.hh> +# include <dune/xt/common/string.hh> +# include <dune/xt/la/container.hh> +# include <dune/xt/grid/grids.hh> +# include <dune/xt/grid/type_traits.hh> +# include <dune/xt/functions/interfaces/grid-function.hh> + +# include <dune/gdt/discretefunction/default.hh> + +namespace Dune { +namespace GDT { +namespace bindings { + + +template <class V, class GV, size_t r = 1, size_t rC = 1, class R = double> +class DiscreteFunction +{ +public: + using type = GDT::DiscreteFunction<V, GV, r, rC, R>; + using base_type = XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<GV>, r, rC, R>; + using bound_type = pybind11::class_<type, base_type>; + + static bound_type bind(pybind11::module& m) + { + namespace py = pybind11; + using namespace pybind11::literals; + using G = typename GV::Grid; + using S = typename type::SpaceType; + + // base_type + const auto grid_name = XT::Grid::bindings::grid_name<G>::value(); + if (std::is_same<R, double>::value) + XT::Common::bindings::guarded_bind( + [&]() { XT::Functions::bindings::bind_GridFunctionInterface<G, r, rC>(m, grid_name); }); + + // type + std::string class_name = "discrete_function_" + grid_name; + if (r > 1) + class_name += "_to" + XT::Common::to_string(r); + if (rC > 1) + class_name += "x" + XT::Common::to_string(rC); + class_name += "_" + XT::LA::bindings::container_name<V>::value(); + class_name = XT::Common::to_camel_case(class_name); + const std::string default_name = "dune.gdt.discretefunction"; + bound_type c(m, XT::Common::to_camel_case(class_name).c_str(), XT::Common::to_camel_case(class_name).c_str()); + c.def(py::init<const S&, V&, const std::string&>(), + "space"_a, + "vector"_a, + "name"_a = default_name, + py::keep_alive<1, 2>(), + py::keep_alive<1, 3>()); + c.def(py::init<const S&, const std::string&>(), "space"_a, "name"_a = default_name, py::keep_alive<1, 2>()); + c.def_property_readonly("space", &type::space); + c.def_property("dof_vector", + [](const type& self) { return self.dofs().vector(); }, + [](type& self, const V& vec) { + DUNE_THROW_IF(vec.size() != self.dofs().vector().size(), + Exceptions::discrete_function_error, + "vec.size() = " << vec.size() << "\n self.dofs().vector().size() = " + << self.dofs().vector().size()); + self.dofs().vector() = vec; + }, + py::return_value_policy::reference_internal); + c.def_property_readonly("name", &type::name); + c.def("visualize", + [](type& self, const std::string& filename) { return self.visualize(filename, VTK::appendedraw); }, + "filename"_a); + + // factory + const std::string factory_name = "make_" + class_name; + m.def( + factory_name.c_str(), + [](const S& space, V& vector, const std::string& name) { return make_discrete_function(space, vector, name); }, + "space"_a, + "vector"_a, + "name"_a = default_name, + py::keep_alive<0, 1>(), + py::keep_alive<0, 2>()); + m.def(factory_name.c_str(), + [](const S& space, const std::string& name) { return make_discrete_function<V>(space, name); }, + "space"_a, + "name"_a = default_name, + py::keep_alive<0, 1>()); + + return c; + } // ... bind(...) +}; // class DiscreteFunction + + +template <class V, class GridTypes = Dune::XT::Grid::AvailableGridTypes> +struct DiscreteFunction_for_all_grids +{ + using G = typename GridTypes::head_type; + using GV = typename G::LeafGridView; + static const constexpr size_t d = G::dimension; + + static void bind(pybind11::module& m) + { + Dune::GDT::bindings::DiscreteFunction<V, GV>::bind(m); + if (d > 1) + Dune::GDT::bindings::DiscreteFunction<V, GV, d>::bind(m); + // add your extra dimensions here + // ... + DiscreteFunction_for_all_grids<V, typename GridTypes::tail_type>::bind(m); + } +}; + +template <class V> +struct DiscreteFunction_for_all_grids<V, boost::tuples::null_type> +{ + static void bind(pybind11::module& /*m*/) {} +}; + + +template <class VectorTypes = Dune::XT::LA::AvailableVectorTypes<double>, + class GridTypes = Dune::XT::Grid::AvailableGridTypes> +struct DiscreteFunction_for_all_vectors_and_grids + +{ + static void bind(pybind11::module& m) + { + using V = typename VectorTypes::head_type; + DiscreteFunction_for_all_grids<V, GridTypes>::bind(m); + DiscreteFunction_for_all_vectors_and_grids<typename VectorTypes::tail_type, GridTypes>::bind(m); + } +}; + +template <class GridTypes> +struct DiscreteFunction_for_all_vectors_and_grids<boost::tuples::null_type, GridTypes> +{ + static void bind(pybind11::module&) {} +}; + + +} // namespace bindings +} // namespace GDT +} // namespace Dune + + +#endif // HAVE_DUNE_PYBINDXI + +#endif // PYTHON_DUNE_GDT_DISCRETEFUNCTION_DEFAULT_BINDINGS_HH diff --git a/python/dune/gdt/playground/spaces/block.cc b/python/dune/gdt/discretefunction/discretefunction_1d.cc similarity index 56% rename from python/dune/gdt/playground/spaces/block.cc rename to python/dune/gdt/discretefunction/discretefunction_1d.cc index bc8c22ea76a6b05e4acec36e53bef9d86d1c5e40..5e309a5bea0d0b6d9a4f97faa8e534a0e97a70f3 100644 --- a/python/dune/gdt/playground/spaces/block.cc +++ b/python/dune/gdt/discretefunction/discretefunction_1d.cc @@ -5,40 +5,30 @@ // or GPL-2.0+ (http://opensource.org/licenses/gpl-license) // with "runtime exception" (http://www.dune-project.org/license.html) // Authors: -// Felix Schindler (2017) -// René Fritze (2018) +// Felix Schindler (2019) #include "config.h" #if HAVE_DUNE_PYBINDXI -# include <dune/common/parallel/mpihelper.hh> +# include "discretefunction.hh" -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> - -# include "block.hh" - - -PYBIND11_MODULE(__spaces_block, m) +PYBIND11_MODULE(_discretefunction_1d, m) { namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); + using namespace Dune; + using namespace Dune::XT; + using namespace Dune::GDT; py::module::import("dune.xt.common"); + py::module::import("dune.xt.la"); py::module::import("dune.xt.grid"); py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - DUNE_GDT_SPACES_BLOCK_BIND(m); - - add_initialization(m, "dune.gdt.spaces.block"); + bindings::DiscreteFunction_for_all_vectors_and_grids<LA::AvailableVectorTypes<double>, + XT::Grid::Available1dGridTypes>::bind(m); } + #endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/spaces/bindings.cc b/python/dune/gdt/discretefunction/discretefunction_2d.cc similarity index 54% rename from python/dune/gdt/spaces/bindings.cc rename to python/dune/gdt/discretefunction/discretefunction_2d.cc index dcf57a1db6e1a68fd3931aed913013ee0e9d7f61..ba3c7d6539811db974a33492d8101d79ca1d14c8 100644 --- a/python/dune/gdt/spaces/bindings.cc +++ b/python/dune/gdt/discretefunction/discretefunction_2d.cc @@ -5,42 +5,30 @@ // or GPL-2.0+ (http://opensource.org/licenses/gpl-license) // with "runtime exception" (http://www.dune-project.org/license.html) // Authors: -// Felix Schindler (2017) -// René Fritze (2018) +// Felix Schindler (2019) #include "config.h" #if HAVE_DUNE_PYBINDXI -# include <dune/common/parallel/mpihelper.hh> +# include "discretefunction.hh" -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> - -# include "bindings.hh" - - -PYBIND11_MODULE(__spaces, m) +PYBIND11_MODULE(_discretefunction_2d, m) { namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); + using namespace Dune; + using namespace Dune::XT; + using namespace Dune::GDT; py::module::import("dune.xt.common"); + py::module::import("dune.xt.la"); py::module::import("dune.xt.grid"); py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - DUNE_GDT_SPACES_CG_BIND(m); - DUNE_GDT_SPACES_DG_BIND(m); - DUNE_GDT_SPACES_FV_BIND(m); - DUNE_GDT_SPACES_RT_BIND(m); - - add_initialization(m, "dune.gdt.spaces"); + bindings::DiscreteFunction_for_all_vectors_and_grids<LA::AvailableVectorTypes<double>, + XT::Grid::Available2dGridTypes>::bind(m); } + #endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/local/diffusive-flux-estimation-operator.cc b/python/dune/gdt/discretefunction/discretefunction_3d.cc similarity index 54% rename from python/dune/gdt/local/diffusive-flux-estimation-operator.cc rename to python/dune/gdt/discretefunction/discretefunction_3d.cc index 2b3d7312fc3563ceb04ea8a75357ebc8aabb85fb..449d8b298f5734d092439faa4e41f6ca01b0f3ab 100644 --- a/python/dune/gdt/local/diffusive-flux-estimation-operator.cc +++ b/python/dune/gdt/discretefunction/discretefunction_3d.cc @@ -5,39 +5,30 @@ // or GPL-2.0+ (http://opensource.org/licenses/gpl-license) // with "runtime exception" (http://www.dune-project.org/license.html) // Authors: -// Felix Schindler (2017) -// René Fritze (2018) +// Felix Schindler (2019) #include "config.h" #if HAVE_DUNE_PYBINDXI -# include <dune/common/parallel/mpihelper.hh> +# include "discretefunction.hh" -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> - -# include "diffusive-flux-estimation-operator.hh" - - -PYBIND11_MODULE(__local_diffusive_flux_estimation_operator, m) +PYBIND11_MODULE(_discretefunction_3d, m) { namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); + using namespace Dune; + using namespace Dune::XT; + using namespace Dune::GDT; py::module::import("dune.xt.common"); + py::module::import("dune.xt.la"); py::module::import("dune.xt.grid"); py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - DUNE_GDT_LOCAL_DIFFUSIVE_FLUX_ESTIMATION_OPERATOR_BIND(m); - - add_initialization(m, "dune.gdt.assembler"); + bindings::DiscreteFunction_for_all_vectors_and_grids<LA::AvailableVectorTypes<double>, + XT::Grid::Available3dGridTypes>::bind(m); } + #endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/functionals/base.hh b/python/dune/gdt/functionals/base.hh deleted file mode 100644 index c527d78461394917deee63b9cfce0b16ed3bfd90..0000000000000000000000000000000000000000 --- a/python/dune/gdt/functionals/base.hh +++ /dev/null @@ -1,64 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_FUNCTIONALS_BASE_BINDINGS_H -#define PYTHON_DUNE_GDT_FUNCTIONALS_BASE_BINDINGS_H - -// Todo: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/la/container.hh> - -# include <dune/gdt/assembler/system.hh> -# include <dune/gdt/discretefunction/default.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class FunctionalType> -class VectorFunctionalBase -{ -public: - typedef FunctionalType type; - typedef GDT::SystemAssembler<typename FunctionalType::SpaceType, typename FunctionalType::GridLayerType> BaseType; - typedef pybind11::class_<type, BaseType> bound_type; - - static bound_type bind(pybind11::module& m, const std::string& class_id) - { - namespace py = pybind11; - using namespace pybind11::literals; - - typedef typename type::SpaceType S; - typedef typename type::VectorType V; - - bound_type c(m, std::string(class_id).c_str(), std::string(class_id).c_str()); - - c.def("vector", [](type& self) { return self.vector(); }); - c.def("space", [](type& self) { return self.space(); }); - c.def("apply", [](type& self, const V& source) { return self.apply(source); }, "source"_a); - c.def( - "apply", [](type& self, const ConstDiscreteFunction<S, V>& source) { return self.apply(source); }, "source"_a); - - return c; - } // ... bind(...) -}; // class VectorFunctionalBase - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_FUNCTIONALS_BASE_BINDINGS_H diff --git a/python/dune/gdt/functionals/elliptic-ipdg/alu_istl.cc b/python/dune/gdt/functionals/elliptic-ipdg/alu_istl.cc deleted file mode 100644 index 5e99d2925c569095819bd4a9edbb27978ac83a9e..0000000000000000000000000000000000000000 --- a/python/dune/gdt/functionals/elliptic-ipdg/alu_istl.cc +++ /dev/null @@ -1,25 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <python/dune/gdt/functionals/elliptic-ipdg/bindings.hh> - - -# if HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL -DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_ALU(template, leaf, view, dg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_ALU(template, level, view, dg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_ALU(template, dd_subdomain, view, dg, gdt, 1, istl_sparse); -# endif - - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/functionals/elliptic-ipdg/bindings.cc b/python/dune/gdt/functionals/elliptic-ipdg/bindings.cc deleted file mode 100644 index 4dd5054ee945dd7b9fd08e3e8041c32f55ad042f..0000000000000000000000000000000000000000 --- a/python/dune/gdt/functionals/elliptic-ipdg/bindings.cc +++ /dev/null @@ -1,56 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> - -# include <python/dune/gdt/functionals/elliptic-ipdg/bindings.hh> - - -PYBIND11_MODULE(__functionals_elliptic_ipdg, m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - -// alu_istl.cc -# if HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL - DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_ALU(m, leaf, view, dg, gdt, 1, istl_dense); - DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_ALU(m, level, view, dg, gdt, 1, istl_dense); - DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_ALU(m, dd_subdomain, view, dg, gdt, 1, istl_dense); -# endif - -// yasp_istl.cc -# if HAVE_DUNE_ISTL - DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_YASP(m, leaf, view, dg, gdt, 1, istl_dense); - DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_YASP(m, level, view, dg, gdt, 1, istl_dense); - DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_YASP(m, dd_subdomain, view, dg, gdt, 1, istl_dense); -# endif - - add_initialization(m, "dune.gdt.functionals.elliptic-ipdg"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/functionals/elliptic-ipdg/bindings.hh b/python/dune/gdt/functionals/elliptic-ipdg/bindings.hh deleted file mode 100644 index bc329aa457d6e9497aebcdc5926c448c732f9090..0000000000000000000000000000000000000000 --- a/python/dune/gdt/functionals/elliptic-ipdg/bindings.hh +++ /dev/null @@ -1,728 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BINDINGS_HH -#define PYTHON_DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/grid/type_traits.hh> -# include <python/dune/xt/la/container.bindings.hh> - -# include <dune/gdt/spaces/bindings.hh> -# include <dune/gdt/type_traits.hh> - -# include <dune/gdt/functionals/elliptic-ipdg.hh> -# include <python/dune/gdt/functionals/base.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class DI, - class DF, - typename DT, // may be void - class SP, - LocalEllipticIpdgIntegrands::Method method, - class V /* = typename XT::LA::Container<typename R::RangeFieldType>::VectorType, - class GL = typename RP::type::GridLayerType, - class F = typename RP::type::RangeFieldType*/> -class EllipticIpdgDirichletVectorFunctional -{ - typedef typename SP::type S; - static_assert(is_space<S>::value, ""); - -public: - typedef GDT::EllipticIpdgDirichletVectorFunctional<DI, DF, DT, S, method, V /*, GL, F*/> type; - typedef pybind11::class_<type> bound_type; - -private: - template <bool single_diffusion = std::is_same<DT, void>::value, - bool scalar = (DF::dimRange == 1 && DF::dimRangeCols == 1), - bool anything = false> - struct diffusion_switch - { - static std::string suffix() - { - return "diffusion_factor_and_tensor"; - } - - template <class C> - static void addbind_factory_methods(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto method_name = - "make_elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() + "_dirichlet_vector_functional"; - - m.def( - std::string(method_name + "_" + XT::LA::bindings::container_name<V>::value()).c_str(), - [](const DI& dirichlet, - const DF& diffusion_factor, - const DT& diffusion_tensor, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<typename S::GridLayerType>>& boundary_info, - const S& space, - const size_t over_integrate) { - return make_elliptic_ipdg_dirichlet_vector_functional<V, method>( - dirichlet, diffusion_factor, diffusion_tensor, boundary_info, space, over_integrate) - .release(); // <- b.c. EllipticIpdgDirichletVectorFunctional is not movable, returning the raw pointer - }, // lets pybind11 correctly manage the memory - "dirichlet"_a, - "diffusion_factor"_a, - "diffusion_tensor"_a, - "boundary_info"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>(), - py::keep_alive<0, 4>(), - py::keep_alive<0, 5>()); - - m.def( - method_name.c_str(), - [](const DI& dirichlet, - const DF& diffusion_factor, - const DT& diffusion_tensor, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<typename S::GridLayerType>>& boundary_info, - V& vector, - const S& space, - const size_t over_integrate) { - return make_elliptic_ipdg_dirichlet_vector_functional<method>( - dirichlet, diffusion_factor, diffusion_tensor, boundary_info, vector, space, over_integrate) - .release(); // <- s.a. for release() - }, - "dirichlet"_a, - "diffusion_factor"_a, - "diffusion_tensor"_a, - "boundary_info"_a, - "vector"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>(), - py::keep_alive<0, 4>(), - py::keep_alive<0, 5>(), - py::keep_alive<0, 6>()); - } // ... addbind_factory_methods(...) - }; // struct diffusion_switch - - struct diffusion_switch_scalar_base - { - template <class C> - static void addbind_factory_methods(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto method_name = - "make_elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() + "_dirichlet_vector_functional"; - - m.def( - std::string(method_name + "_" + XT::LA::bindings::container_name<V>::value()).c_str(), - [](const DI& dirichlet, - const DF& diffusion, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<typename S::GridLayerType>>& boundary_info, - const S& space, - const size_t over_integrate) { - return make_elliptic_ipdg_dirichlet_vector_functional<V, method>( - dirichlet, diffusion, boundary_info, space, over_integrate) - .release(); // <- b.c. EllipticIpdgDirichletVectorFunctional is not movable, returning the raw pointer - }, // lets pybind11 correctly manage the memory - "dirichlet"_a, - "diffusion"_a, - "boundary_info"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>(), - py::keep_alive<0, 4>()); - - m.def( - method_name.c_str(), - [](const DI& dirichlet, - const DF& diffusion, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<typename S::GridLayerType>>& boundary_info, - V& vector, - const S& space, - const size_t over_integrate) { - return make_elliptic_ipdg_dirichlet_vector_functional<method>( - dirichlet, diffusion, boundary_info, vector, space, over_integrate) - .release(); // <- s.a. for release() - }, - "dirichlet"_a, - "diffusion"_a, - "boundary_info"_a, - "vector"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>(), - py::keep_alive<0, 4>(), - py::keep_alive<0, 5>()); - } // ... addbind_factory_methods(...) - }; // struct diffusion_switch_scalar_base - - template <bool anything> - struct diffusion_switch<true, true, anything> : public diffusion_switch_scalar_base - { - static std::string suffix() - { - return "single_diffusion_factor"; - } - }; - - template <bool anything> - struct diffusion_switch<true, false, anything> : public diffusion_switch_scalar_base - { - static std::string suffix() - { - return "single_diffusion_tensor"; - } - }; - -public: - static bound_type bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto ClassName = XT::Common::to_camel_case( - "elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() + "_dirichlet_vector_functional_" - + space_name<SP>::value() - + "_" - + XT::LA::bindings::container_name<V>::value() - + "_" - + diffusion_switch<>::suffix()); - - auto c = VectorFunctionalBase<type>::bind(m, ClassName.c_str()); - - diffusion_switch<>::template addbind_factory_methods<type>(m); - - return c; - } // ... bind(...) -}; // class EllipticIpdgDirichletVectorFunctional - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - - -// begin: this is what we need for the lib - -# define _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, _method) \ - _prefix class Dune::GDT::bindings::EllipticIpdgDirichletVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>; \ - _prefix class Dune::GDT::bindings::EllipticIpdgDirichletVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType> - -# define _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, _method) \ - _prefix class Dune::GDT::bindings::EllipticIpdgDirichletVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>; \ - _prefix class Dune::GDT::bindings::EllipticIpdgDirichletVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>; \ - _prefix class Dune::GDT::bindings::EllipticIpdgDirichletVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType> - -# define _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_METHODS_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, sipdg); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_factor); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_tensor) - -# define _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_METHODS_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, sipdg); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_factor); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_tensor) - -/* -#if HAVE_ALBERTA -#define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_ALBERTA(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_METHODS_D( \ - _prefix, 2, ALBERTA_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_ALBERTA(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# if HAVE_DUNE_ALUGRID -# define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_ALU(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_METHODS_D( \ - _prefix, 2, ALU_2D_SIMPLEX_CONFORMING, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# else -# define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_ALU(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# endif - -/* -#if HAVE_DUNE_UGGRID || HAVE_UG -#define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_UG(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_METHODS_D( \ - _prefix, 2, UG_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_UG(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_YASP(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_METHODS_1D( \ - _prefix, YASP_1D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_METHODS_D( \ - _prefix, 2, YASP_2D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la) - -// alu_istl.cc -# if HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL -DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_ALU(extern template, leaf, view, cg, gdt, 1, istl_dense); -DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_ALU(extern template, level, view, cg, gdt, 1, istl_dense); -// DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_ALU(extern template, dd_subdomain, part, cg, gdt, 1, istl_dense); -# endif - -// yasp_istl.cc -# if HAVE_DUNE_ISTL -DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_YASP(extern template, leaf, view, cg, gdt, 1, istl_dense); -DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_YASP(extern template, level, view, cg, gdt, 1, istl_dense); -// DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_YASP(extern template, dd_subdomain, part, cg, gdt, 1, istl_dense); -# endif - -// end: this is what we need for the lib - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_1D( \ - _m, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, _method) \ - Dune::GDT::bindings::EllipticIpdgDirichletVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>::bind(_m); \ - Dune::GDT::bindings::EllipticIpdgDirichletVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>::bind(_m) - -# define _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, _method) \ - Dune::GDT::bindings::EllipticIpdgDirichletVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>::bind(_m); \ - Dune::GDT::bindings::EllipticIpdgDirichletVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>::bind(_m); \ - Dune::GDT::bindings::EllipticIpdgDirichletVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>::bind(_m) - -# define _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_METHODS_1D( \ - _m, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_1D(_m, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, sipdg); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_1D(_m, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_1D( \ - _m, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_factor); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_1D( \ - _m, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_tensor) - -# define _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_METHODS_D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, sipdg); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_factor); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_tensor) - -/* -#if HAVE_ALBERTA -#define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_ALBERTA(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_METHODS_D(_m, 2, ALBERTA_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_ALBERTA(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# if HAVE_DUNE_ALUGRID -# define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_ALU(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_METHODS_D( \ - _m, 2, ALU_2D_SIMPLEX_CONFORMING, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# else -# define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_ALU(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# endif - -/* -#if HAVE_DUNE_UGGRID || HAVE_UG -#define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_UG(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_METHODS_D(_m, 2, UG_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_UG(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# define DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_YASP(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_METHODS_1D( \ - _m, YASP_1D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_METHODS_D( \ - _m, 2, YASP_2D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la) - - -// end: this is what we need for the .so - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BINDINGS_HH diff --git a/python/dune/gdt/functionals/elliptic-ipdg/yasp_istl.cc b/python/dune/gdt/functionals/elliptic-ipdg/yasp_istl.cc deleted file mode 100644 index b74e62fecbb2f2f71a62cda544fc345b0248e232..0000000000000000000000000000000000000000 --- a/python/dune/gdt/functionals/elliptic-ipdg/yasp_istl.cc +++ /dev/null @@ -1,25 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <python/dune/gdt/functionals/elliptic-ipdg/bindings.hh> - - -# if HAVE_DUNE_ISTL -DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_YASP(template, leaf, view, dg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_YASP(template, level, view, dg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_ELLIPTIC_IPDG_BIND_LIB_YASP(template, dd_subdomain, view, dg, gdt, 1, istl_sparse); -# endif - - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/functionals/l2/alu_istl.cc b/python/dune/gdt/functionals/l2/alu_istl.cc deleted file mode 100644 index f0df4d822b0319bf9247e88e18427af63ffc1263..0000000000000000000000000000000000000000 --- a/python/dune/gdt/functionals/l2/alu_istl.cc +++ /dev/null @@ -1,24 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <python/dune/gdt/functionals/l2/bindings.hh> - - -# if HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_ALU(template, leaf, view, cg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_ALU(template, level, view, cg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_ALU(template, dd_subdomain, view, cg, gdt, 1, istl_sparse); -# endif - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/functionals/l2/bindings.cc b/python/dune/gdt/functionals/l2/bindings.cc deleted file mode 100644 index de92c3fc68ed72c2a30bb3ba3a8e102b5a99b1f2..0000000000000000000000000000000000000000 --- a/python/dune/gdt/functionals/l2/bindings.cc +++ /dev/null @@ -1,62 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> - -# include <python/dune/gdt/functionals/l2/bindings.hh> - - -PYBIND11_MODULE(__functionals_l2, m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - - // alu_istl.cc - DUNE_GDT_FUNCTIONALS_L2_BIND_ALU(m, leaf, view, dg, gdt, 1, istl_sparse); - DUNE_GDT_FUNCTIONALS_L2_BIND_ALU(m, level, view, dg, gdt, 1, istl_sparse); - DUNE_GDT_FUNCTIONALS_L2_BIND_ALU(m, dd_subdomain, view, dg, gdt, 1, istl_sparse); -# if HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL - DUNE_GDT_FUNCTIONALS_L2_BIND_ALU(m, leaf, view, cg, gdt, 1, istl_sparse); - DUNE_GDT_FUNCTIONALS_L2_BIND_ALU(m, level, view, cg, gdt, 1, istl_sparse); - DUNE_GDT_FUNCTIONALS_L2_BIND_ALU(m, dd_subdomain, view, cg, gdt, 1, istl_sparse); -# endif - -// yasp_istl.cc -# if HAVE_DUNE_ISTL - DUNE_GDT_FUNCTIONALS_L2_BIND_YASP(m, leaf, view, dg, gdt, 1, istl_sparse); - DUNE_GDT_FUNCTIONALS_L2_BIND_YASP(m, level, view, dg, gdt, 1, istl_sparse); - DUNE_GDT_FUNCTIONALS_L2_BIND_YASP(m, dd_subdomain, view, dg, gdt, 1, istl_sparse); - DUNE_GDT_FUNCTIONALS_L2_BIND_YASP(m, leaf, view, cg, gdt, 1, istl_sparse); - DUNE_GDT_FUNCTIONALS_L2_BIND_YASP(m, level, view, cg, gdt, 1, istl_sparse); - DUNE_GDT_FUNCTIONALS_L2_BIND_YASP(m, dd_subdomain, view, cg, gdt, 1, istl_sparse); -# endif - - add_initialization(m, "dune.gdt.functionals.l2"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/functionals/l2/bindings.hh b/python/dune/gdt/functionals/l2/bindings.hh deleted file mode 100644 index fb1da6478dbe1ba784d5e7ef1073ba4d84a51eb5..0000000000000000000000000000000000000000 --- a/python/dune/gdt/functionals/l2/bindings.hh +++ /dev/null @@ -1,316 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_FUNCTIONALS_L2_BINDINGS_HH -#define PYTHON_DUNE_GDT_FUNCTIONALS_L2_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <python/dune/xt/grid/grids.bindings.hh> -# include <python/dune/xt/la/container.bindings.hh> - -# include <dune/gdt/spaces/bindings.hh> -# include <dune/gdt/type_traits.hh> - -# include <dune/gdt/functionals/l2.hh> -# include <python/dune/gdt/functionals/base.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class F, class SP, class V /*= typename XT::LA::Container<typename SP::type::RangeFieldType>::VectorType, - class GridView = typename Space::GridLayerType, - class Field = typename Space::RangeFieldType*/> -class L2VolumeVectorFunctional -{ - typedef typename SP::type S; - static_assert(is_space<S>::value, ""); - -public: - typedef GDT::L2VolumeVectorFunctional<F, S, V> type; - typedef pybind11::class_<type> bound_type; - - static bound_type bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto ClassName = XT::Common::to_camel_case("l2_volume_vector_functional_" + space_name<SP>::value() + "_" - + XT::LA::bindings::container_name<V>::value()); - - auto c = VectorFunctionalBase<type>::bind(m, ClassName); - - m.def(std::string("make_l2_volume_vector_functional_" + XT::LA::bindings::container_name<V>::value()).c_str(), - [](const F& function, const S& space, const size_t over_integrate) { - return make_l2_volume_vector_functional<V>(function, space, over_integrate).release(); // <- b.c. - }, // L2VolumeVectorFunctional is not movable, returning the raw pointer lets pybind11 correctly manage the - "function"_a, // memory - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>()); - - m.def("make_l2_volume_vector_functional", - [](const F& function, V& vector, const S& space, const size_t over_integrate) { - return make_l2_volume_vector_functional(function, vector, space, over_integrate).release(); // <- s.a. - }, - "function"_a, - "vector"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>()); - - return c; - } // ... bind(...) -}; // class L2VolumeVectorFunctional - - -template <class F, - class SP, - class V /*= typename XT::LA::Container<typename SP::type::RangeFieldType>::VectorType*/, - class GL /*= typename SP::type::GridLayerType, - class Field = typename SP::type::RangeFieldType*/> -class L2FaceVectorFunctional -{ - typedef typename SP::type S; - static_assert(is_space<S>::value, ""); - -public: - typedef GDT::L2FaceVectorFunctional<F, S, V> type; - typedef pybind11::class_<type> bound_type; - - static bound_type bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const std::string class_name = "l2_face_vector_functional"; - const auto ClassName = XT::Common::to_camel_case(class_name + "_" + space_name<SP>::value() + "_" - + XT::LA::bindings::container_name<V>::value()); - - auto c = VectorFunctionalBase<type>::bind(m, ClassName); - - m.def(std::string("make_" + class_name + "_" + XT::LA::bindings::container_name<V>::value()).c_str(), - [](const F& function, const S& space, const size_t over_integrate) { - return make_l2_face_vector_functional<V>(function, space, over_integrate).release(); // <- b.c. - }, // L2FaceVectorFunctional is not movable, returning the raw pointer lets pybind11 correctly manage the - "function"_a, // memory - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>()); - m.def(std::string("make_" + class_name + "_" + XT::LA::bindings::container_name<V>::value()).c_str(), - [](const F& function, - const S& space, - const XT::Grid::ApplyOn::WhichIntersection<GL>& which_intersections, - const size_t over_integrate) { - return make_l2_face_vector_functional<V>(function, space, over_integrate, which_intersections.copy()) - .release(); // <- s.a. - }, - "function"_a, - "space"_a, - "which_intersections"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>()); - - m.def(std::string("make_" + class_name).c_str(), - [](const F& function, V& vector, const S& space, const size_t over_integrate) { - return make_l2_face_vector_functional(function, vector, space, over_integrate).release(); // <- s.a. - }, - "function"_a, - "vector"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>()); - m.def(std::string("make_" + class_name).c_str(), - [](const F& function, - V& vector, - const S& space, - const XT::Grid::ApplyOn::WhichIntersection<GL>& which_intersections, - const size_t over_integrate) { - return make_l2_face_vector_functional(function, vector, space, over_integrate, which_intersections.copy()) - .release(); // <- s.a. - }, - "function"_a, - "vector"_a, - "space"_a, - "which_intersections"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>()); - - return c; - } // ... bind(...) -}; // XT::LA::bindings::container_name<V>::value() - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - - -// begin: this is what we need for the lib - -# define _DUNE_GDT_FUNCTIONALS_L2_BIND_LIB(_prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _prefix class Dune::GDT::bindings::L2VolumeVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>; \ - _prefix class Dune::GDT::bindings::L2FaceVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType, \ - typename Dune::XT::Grid::Layer<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type> - - -# if HAVE_DUNE_ALUGRID -# define DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_ALU(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_L2_BIND_LIB( \ - _prefix, 2, ALU_2D_SIMPLEX_CONFORMING, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# else -# define DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_ALU(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# endif - -# define DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_YASP(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_L2_BIND_LIB( \ - _prefix, 1, YASP_1D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_FUNCTIONALS_L2_BIND_LIB( \ - _prefix, 2, YASP_2D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la) - -// alu_istl.cc -# if HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_ALU(extern template, leaf, view, cg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_ALU(extern template, level, view, cg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_ALU(extern template, dd_subdomain, view, cg, gdt, 1, istl_sparse); -# endif - -// yasp_istl.cc -# if HAVE_DUNE_ISTL -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_YASP(extern template, leaf, view, cg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_YASP(extern template, level, view, cg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_YASP(extern template, dd_subdomain, view, cg, gdt, 1, istl_sparse); -# endif - -// end: this is what we need for the lib - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_FUNCTIONALS_L2_BIND(_m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - Dune::GDT::bindings::L2VolumeVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>::bind(_m); \ - Dune::GDT::bindings::L2FaceVectorFunctional< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType, \ - typename Dune::XT::Grid::Layer<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>::bind(_m) - - -# if HAVE_DUNE_ALUGRID -# define DUNE_GDT_FUNCTIONALS_L2_BIND_ALU(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_L2_BIND(_m, 2, ALU_2D_SIMPLEX_CONFORMING, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# else -# define DUNE_GDT_FUNCTIONALS_L2_BIND_ALU(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# endif - -# define DUNE_GDT_FUNCTIONALS_L2_BIND_YASP(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_FUNCTIONALS_L2_BIND( \ - _m, 1, YASP_1D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_FUNCTIONALS_L2_BIND(_m, 2, YASP_2D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la) - - -// end: this is what we need for the .so - - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_FUNCTIONALS_L2_BINDINGS_HH diff --git a/python/dune/gdt/functionals/l2/yasp_istl.cc b/python/dune/gdt/functionals/l2/yasp_istl.cc deleted file mode 100644 index 2229c17e6fcba3af5099952d0dab89f55798da96..0000000000000000000000000000000000000000 --- a/python/dune/gdt/functionals/l2/yasp_istl.cc +++ /dev/null @@ -1,25 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <python/dune/gdt/functionals/l2/bindings.hh> - - -# if HAVE_DUNE_ISTL -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_YASP(template, leaf, view, cg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_YASP(template, level, view, cg, gdt, 1, istl_sparse); -DUNE_GDT_FUNCTIONALS_L2_BIND_LIB_YASP(template, dd_subdomain, view, cg, gdt, 1, istl_sparse); -# endif - - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/gamm-2019-talk-on-conservative-rb.cc b/python/dune/gdt/gamm-2019-talk-on-conservative-rb.cc index ef4028b4b6d9e9ae81d05e433d149618e63d1b3c..88142231942fe60208b7e3cbb449f835a165eb3d 100644 --- a/python/dune/gdt/gamm-2019-talk-on-conservative-rb.cc +++ b/python/dune/gdt/gamm-2019-talk-on-conservative-rb.cc @@ -48,7 +48,15 @@ using namespace Dune; using namespace Dune::GDT; +#if HAVE_DUNE_ALUGRID using G = ALU_2D_SIMPLEX_CONFORMING; +#elif HAVE_DUNE_UGGRID || HAVE_UG +using G = UG_2D; +#else +# warning Falling back to cubic grid, results will not be reproduced but similar! +using G = YASP_2D_EQUIDISTANT_OFFSET; +#endif + using GP = XT::Grid::GridProvider<G>; using GV = typename G::LeafGridView; using E = XT::Grid::extract_entity_t<GV>; @@ -301,49 +309,7 @@ PYBIND11_MODULE(gamm_2019_talk_on_conservative_rb, m) py::module::import("dune.xt.la"); py::module::import("dune.xt.grid"); py::module::import("dune.xt.functions"); - - Dune::XT::Common::bindings::addbind_exceptions(m); - Dune::XT::Common::bindings::add_initialization(m, "dune.gdt"); - - py::class_<XT::Functions::Spe10::Model1Function<E, d, d, double>, - XT::Functions::GridFunctionInterface<E, d, d, double>> - spe10_function(m, "Spe10Model1Function", "Spe10Model1Function"); - spe10_function.def(py::init([](const FieldVector<double, d>& lower_left, const FieldVector<double, d>& upper_right) { - return new XT::Functions::Spe10::Model1Function<E, d, d, double>( - XT::Data::spe10_model1_filename(), lower_left, upper_right); - }), - "lower_left"_a, - "upper_right"_a); - - py::class_<XT::Functions::FunctionAsGridFunctionWrapper<E, 1, 1, double>, - XT::Functions::GridFunctionInterface<E, 1, 1, double>> - scalar_wrapper(m, "ScalarFunctionAsGridFunctionWrapper", "ScalarFunctionAsGridFunctionWrapper"); - scalar_wrapper.def(py::init([](const XT::Functions::FunctionInterface<d>& func) { - return new XT::Functions::FunctionAsGridFunctionWrapper<E, 1, 1, double>(func); - }), - py::keep_alive<1, 2>(), - "scalar_function"_a); - py::class_<XT::Functions::FunctionAsGridFunctionWrapper<E, d, d, double>, - XT::Functions::GridFunctionInterface<E, d, d, double>> - matrix_wrapper(m, "MatrixFunctionAsGridFunctionWrapper", "MatrixFunctionAsGridFunctionWrapper"); - matrix_wrapper.def(py::init([](const XT::Functions::FunctionInterface<d, d, d>& func) { - return new XT::Functions::FunctionAsGridFunctionWrapper<E, d, d, double>(func); - }), - py::keep_alive<1, 2>(), - "matrix_function"_a); - - m.def("function_to_grid_function", - [](XT::Functions::FunctionInterface<d>& func) { - return std::make_unique<XT::Functions::FunctionAsGridFunctionWrapper<E, 1, 1, double>>(func); - }, - py::keep_alive<0, 1>(), - "scalar_function"_a); - m.def("function_to_grid_function", - [](XT::Functions::FunctionInterface<d, d, d>& func) { - return std::make_unique<XT::Functions::FunctionAsGridFunctionWrapper<E, d, d, double>>(func); - }, - py::keep_alive<0, 1>(), - "matrix_function"_a); + py::module::import("dune.gdt.discretefunction"); m.def("visualize", [](GP& grid, XT::Functions::FunctionInterface<d>& func, const std::string& filename) { @@ -404,24 +370,6 @@ PYBIND11_MODULE(gamm_2019_talk_on_conservative_rb, m) rtn_space.def_property_readonly("dimDomain", [](RTN& /*self*/) { return d; }); rtn_space.def_property_readonly("num_DoFs", [](RTN& self) { return self.mapper().size(); }); - py::class_<ScalarDF> scalar_discrete_function(m, "ScalarDiscreteFunction", "ScalarDiscreteFunction"); - scalar_discrete_function.def( - py::init([](DG& space, V& vec, const std::string& name) { return new ScalarDF(space, vec, name); }), - "dg_space"_a, - "DoF_vector"_a, - "name"_a); - scalar_discrete_function.def( - "visualize", [](ScalarDF& self, const std::string filename) { self.visualize(filename); }, "filename"_a); - - py::class_<VectorDF> vector_discrete_function(m, "VectorDiscreteFunction", "VectorDiscreteFunction"); - vector_discrete_function.def( - py::init([](RTN& space, V& vec, const std::string& name) { return new VectorDF(space, vec, name); }), - "rtn_space"_a, - "DoF_vector"_a, - "name"_a); - vector_discrete_function.def( - "visualize", [](VectorDF& self, const std::string filename) { self.visualize(filename); }, "filename"_a); - m.def("make_discrete_function", [](DG& dg_space, V& vec, const std::string& name) { return ScalarDF(dg_space, vec, name); }, "dg_space"_a, diff --git a/python/dune/gdt/local/diffusive-flux-estimation-operator.hh b/python/dune/gdt/local/diffusive-flux-estimation-operator.hh deleted file mode 100644 index 3ab96574de33c14ccaafc3c97a70284fd56fecc6..0000000000000000000000000000000000000000 --- a/python/dune/gdt/local/diffusive-flux-estimation-operator.hh +++ /dev/null @@ -1,118 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_LOCAL_DIFFUSIVE_FLUX_ESTIMATION_OPERATOR_BINDINGS_HH -#define PYTHON_DUNE_GDT_LOCAL_DIFFUSIVE_FLUX_ESTIMATION_OPERATOR_BINDINGS_HH -// Todo: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/functions/interfaces/grid-function.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <dune/xt/grid/type_traits.hh> - -# include <dune/gdt/local/integrands/ESV2007.hh> -# include <dune/gdt/local/operators/integrals.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class G> -class LocalDiffusiveFluxEstimationOperator -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef typename G::template Codim<0>::Entity E; - typedef typename G::ctype D; - static const constexpr size_t d = G::dimension; - typedef double R; - - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunction; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d> VectorFunction; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> TensorFunction; - typedef typename ScalarFunction::LocalfunctionType ScalarLocalFunctionType; - typedef GDT::LocalVolumeTwoFormInterface<ScalarLocalFunctionType> InterfaceType; - -public: - typedef LocalVolumeIntegralOperator<LocalDiffusiveFluxEstimateESV2007Integrand<ScalarFunction, - VectorFunction, - TensorFunction>, - ScalarLocalFunctionType> - type; - typedef pybind11::class_<type, InterfaceType> bound_type; - - static bound_type bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - using XT::Common::to_string; - - // bind interface, guard since we might not be the first to do so for this combination - try { - const auto InterfaceName = XT::Common::to_camel_case( - "local_volume_two_form_interface_" + XT::Grid::bindings::grid_name<G>::value() + "_to_1x1"); - py::class_<InterfaceType>(m, InterfaceName.c_str(), "LocalVolumeTwoFormInterface"); - } catch (std::runtime_error&) { - } - - const std::string class_name = "local_diffusive_flux_estimation_esv2007_operator"; - const auto ClassName = - XT::Common::to_camel_case(class_name + "_" + XT::Grid::bindings::grid_name<G>::value() + "_to_1x1"); - - bound_type c(m, ClassName.c_str(), "LocalVolumeIntegralOperator<LocalDiffusiveFluxEstimateESV2007Integrand<...>>"); - - m.def(("make_" + class_name + "_to_1x1").c_str(), - [](const ScalarFunction& diffusion_factor, - const TensorFunction& diffusion_tensor, - const VectorFunction& diffusive_flux, - const size_t over_integrate) { - return type(over_integrate, diffusion_factor, diffusion_tensor, diffusive_flux); - }, - "diffusion_factor"_a, - "diffusion_tensor"_a, - "diffusive_flux"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>()); - - return c; - } // ... bind(...) -}; // class LocalDiffusiveFluxEstimationOperator - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - - -// begin: this is what we need for the .so - - -# define _DUNE_GDT_LOCAL_DIFFUSIVE_FLUX_ESTIMATION_OPERATOR_BIND(_G, _m) \ - Dune::GDT::bindings::LocalDiffusiveFluxEstimationOperator<_G>::bind(_m) - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_LOCAL_DIFFUSIVE_FLUX_ESTIMATION_OPERATOR_BIND_ALU(_m) \ - _DUNE_GDT_LOCAL_DIFFUSIVE_FLUX_ESTIMATION_OPERATOR_BIND(ALU_2D_SIMPLEX_CONFORMING, _m) -# else -# define _DUNE_GDT_LOCAL_DIFFUSIVE_FLUX_ESTIMATION_OPERATOR_BIND_ALU(_m) -# endif - -# define DUNE_GDT_LOCAL_DIFFUSIVE_FLUX_ESTIMATION_OPERATOR_BIND(_m) \ - _DUNE_GDT_LOCAL_DIFFUSIVE_FLUX_ESTIMATION_OPERATOR_BIND_ALU(_m) - -// end: this is what we need for the .so - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_LOCAL_DIFFUSIVE_FLUX_ESTIMATION_OPERATOR_BINDINGS_HH diff --git a/python/dune/gdt/local/elliptic-ipdg-operators.cc b/python/dune/gdt/local/elliptic-ipdg-operators.cc deleted file mode 100644 index 55888904eb8f67b79b3c221359628142c6c96ec3..0000000000000000000000000000000000000000 --- a/python/dune/gdt/local/elliptic-ipdg-operators.cc +++ /dev/null @@ -1,44 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> - -# include "elliptic-ipdg-operators.hh" - - -PYBIND11_MODULE(__local_elliptic_ipdg_operators, m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - - DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND(m); - - add_initialization(m, "dune.gdt.assembler"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/local/elliptic-ipdg-operators.hh b/python/dune/gdt/local/elliptic-ipdg-operators.hh deleted file mode 100644 index 7ea84327e67010ad9908b29b8b30ecad19cb73cb..0000000000000000000000000000000000000000 --- a/python/dune/gdt/local/elliptic-ipdg-operators.hh +++ /dev/null @@ -1,686 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BINDINGS_HH -#define PYTHON_DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/la/container.hh> -# include <dune/xt/functions/interfaces.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <python/dune/xt/grid/layers.bindings.hh> -# include <dune/xt/grid/dd/subdomains/grid.hh> - -# include <dune/gdt/spaces.hh> -# include <dune/gdt/spaces/bindings.hh> -# include <dune/gdt/type_traits.hh> - -# include <dune/gdt/local/integrands/elliptic-ipdg.hh> -# include <dune/gdt/local/operators/integrals.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class DF, typename DT, class SP, XT::Grid::Layers layer, LocalEllipticIpdgIntegrands::Method method> -class LocalEllipticIpdgInnerIntegralOperator -{ - static_assert(XT::Functions::is_localizable_function<DF>::value, ""); - static_assert(XT::Functions::is_localizable_function<DT>::value || std::is_same<DT, void>::value, ""); - typedef typename SP::type S; - static_assert(is_space<S>::value, ""); - typedef XT::Grid::extract_grid_t<typename S::GridLayerType> G; - typedef typename S::BaseFunctionSetType B; - typedef XT::Grid::extract_intersection_t< - typename XT::Grid::Layer<G, layer, S::layer_backend, XT::Grid::DD::SubdomainGrid<G>>::type> - I; - -public: - typedef GDT::LocalCouplingTwoFormInterface<B, I> InterfaceType; - typedef LocalCouplingIntegralOperator<LocalEllipticIpdgIntegrands::Inner<DF, DT, method>, B, I> type; - typedef pybind11::class_<type, InterfaceType> bound_type; - -private: - template <bool intersection_matches_layer = (layer == SP::grid_layer), bool anything = false> - struct intersection_postfix - { - static std::string value() - { - return ""; - } - }; - - template <bool anything> - struct intersection_postfix<false, anything> - { - static std::string value() - { - return "_" + XT::Grid::bindings::layer_name<layer>::value() + "_intersection"; - } - }; - - template <bool single_diffusion = std::is_same<DT, void>::value, - bool scalar = (DF::dimRange == 1 && DF::dimRangeCols == 1), - bool anything = false> - struct diffusion_switch - { - static std::string suffix() - { - return "diffusion_factor_and_tensor"; - } - - static void addbind_factory_methods(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - using XT::Common::to_string; - - const std::string method_name = - "make_local_elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() - + "_inner_integral_operator_" + to_string(size_t(S::dimRange)) + "x" + to_string(size_t(S::dimRangeCols)) - + "_p" + to_string(int(S::polOrder)) + "_" + space_type_name<SP::space_type>::value() + "_" - + backend_name<SP::space_backend>::value() + "_space" + intersection_postfix<>::value(); - - m.def(method_name.c_str(), - [](const DF& diffusion_factor, const DT& diffusion_tensor, const size_t over_integrate) { - return type(over_integrate, diffusion_factor, diffusion_tensor); - }, - "diffusion_factor"_a, - "diffusion_tensor"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>()); - } // ... addbind_factory_methods(...) - }; // struct diffusion_switch - - struct diffusion_switch_scalar_base - { - static void addbind_factory_methods(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - using XT::Common::to_string; - - const std::string method_name = - "make_local_elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() - + "_inner_integral_operator_" + to_string(size_t(S::dimRange)) + "x" + to_string(size_t(S::dimRangeCols)) - + "_p" + to_string(int(S::polOrder)) + "_" + space_type_name<SP::space_type>::value() + "_" - + backend_name<SP::space_backend>::value() + "_space" + intersection_postfix<>::value(); - - m.def(method_name.c_str(), - [](const DF& diffusion, const size_t over_integrate) { return type(over_integrate, diffusion); }, - "diffusion"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>()); - } // ... addbind_factory_methods(...) - }; // struct diffusion_switch_scalar_base - - template <bool anything> - struct diffusion_switch<true, true, anything> : public diffusion_switch_scalar_base - { - - static std::string suffix() - { - return "single_diffusion_factor"; - } - }; - - template <bool anything> - struct diffusion_switch<true, false, anything> : public diffusion_switch_scalar_base - { - - static std::string suffix() - { - return "single_diffusion_tensor"; - } - }; - -public: - static bound_type bind(pybind11::module& m, const std::string& layer_name) - { - namespace py = pybind11; - using namespace pybind11::literals; - using XT::Common::to_string; - - // bind interface, guard since we might not be the first to do so for this intersection - try { - const auto InterfaceName = XT::Common::to_camel_case( - "local_coupling_two_form_interface_" + XT::Grid::bindings::grid_name<G>::value() + layer_name + "_to_" - + to_string(size_t(S::dimRange)) - + "x" - + to_string(size_t(S::dimRangeCols)) - + "_p" - + to_string(int(S::polOrder)) - + "_" - + space_type_name<SP::space_type>::value() - + "_" - + backend_name<SP::space_backend>::value() - + "_space" - + intersection_postfix<>::value()); - py::class_<InterfaceType>(m, InterfaceName.c_str(), InterfaceName.c_str()); - } catch (std::runtime_error&) { - } - - const auto ClassName = - XT::Common::to_camel_case("local_elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() + "_" - + diffusion_switch<>::suffix() - + "_inner_integral_operator_" - + XT::Grid::bindings::grid_name<G>::value() - + layer_name - + "_to_" - + to_string(size_t(S::dimRange)) - + "x" - + to_string(size_t(S::dimRangeCols)) - + "_p" - + to_string(int(S::polOrder)) - + "_" - + space_type_name<SP::space_type>::value() - + "_" - + backend_name<SP::space_backend>::value() - + "_space" - + intersection_postfix<>::value()); - - bound_type c(m, ClassName.c_str()); - - diffusion_switch<>::addbind_factory_methods(m); - - return c; - } // ... bind(...) -}; // class LocalEllipticIpdgInnerIntegralOperator - - -template <class DF, typename DT, class SP, XT::Grid::Layers layer, LocalEllipticIpdgIntegrands::Method method> -class LocalEllipticIpdgBoundaryIntegralOperator -{ - static_assert(XT::Functions::is_localizable_function<DF>::value, ""); - static_assert(XT::Functions::is_localizable_function<DT>::value || std::is_same<DT, void>::value, ""); - typedef typename SP::type S; - static_assert(is_space<S>::value, ""); - typedef XT::Grid::extract_grid_t<typename S::GridLayerType> G; - typedef typename S::BaseFunctionSetType B; - typedef XT::Grid::extract_intersection_t< - typename XT::Grid::Layer<G, layer, S::layer_backend, XT::Grid::DD::SubdomainGrid<G>>::type> - I; - -public: - typedef GDT::LocalBoundaryTwoFormInterface<B, I> InterfaceType; - typedef LocalBoundaryIntegralOperator<LocalEllipticIpdgIntegrands::BoundaryLHS<DF, DT, method>, B, I> type; - typedef pybind11::class_<type, InterfaceType> bound_type; - -private: - template <bool intersection_matches_layer = (layer == SP::grid_layer), bool anything = false> - struct intersection_postfix - { - static std::string value() - { - return ""; - } - }; - - template <bool anything> - struct intersection_postfix<false, anything> - { - static std::string value() - { - return "_" + XT::Grid::bindings::layer_name<layer>::value() + "_intersection"; - } - }; - - template <bool single_diffusion = std::is_same<DT, void>::value, - bool scalar = (DF::dimRange == 1 && DF::dimRangeCols == 1), - bool anything = false> - struct diffusion_switch - { - static std::string suffix() - { - return "diffusion_factor_and_tensor"; - } - - static void addbind_factory_methods(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - using XT::Common::to_string; - - const std::string method_name = - "make_local_elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() - + "_boundary_integral_operator_" + to_string(size_t(S::dimRange)) + "x" + to_string(size_t(S::dimRangeCols)) - + "_p" + to_string(int(S::polOrder)) + "_" + space_type_name<SP::space_type>::value() + "_" - + backend_name<SP::space_backend>::value() + "_space" + intersection_postfix<>::value(); - - m.def(method_name.c_str(), - [](const DF& diffusion_factor, const DT& diffusion_tensor, const size_t over_integrate) { - return type(over_integrate, diffusion_factor, diffusion_tensor); - }, - "diffusion_factor"_a, - "diffusion_tensor"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>()); - } // ... addbind_factory_methods(...) - }; // struct diffusion_switch - - struct diffusion_switch_scalar_base - { - static void addbind_factory_methods(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - using XT::Common::to_string; - - const std::string method_name = - "make_local_elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() - + "_boundary_integral_operator_" + to_string(size_t(S::dimRange)) + "x" + to_string(size_t(S::dimRangeCols)) - + "_p" + to_string(int(S::polOrder)) + "_" + space_type_name<SP::space_type>::value() + "_" - + backend_name<SP::space_backend>::value() + "_space" + intersection_postfix<>::value(); - - m.def(method_name.c_str(), - [](const DF& diffusion, const size_t over_integrate) { return type(over_integrate, diffusion); }, - "diffusion"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>()); - } // ... addbind_factory_methods(...) - }; // struct diffusion_switch_scalar_base - - template <bool anything> - struct diffusion_switch<true, true, anything> : public diffusion_switch_scalar_base - { - - static std::string suffix() - { - return "single_diffusion_factor"; - } - }; - - template <bool anything> - struct diffusion_switch<true, false, anything> : public diffusion_switch_scalar_base - { - - static std::string suffix() - { - return "single_diffusion_tensor"; - } - }; - -public: - static bound_type bind(pybind11::module& m, const std::string& layer_name) - { - namespace py = pybind11; - using namespace pybind11::literals; - using XT::Common::to_string; - - // bind interface, guard since we might not be the first to do so for this intersection - try { - const auto InterfaceName = XT::Common::to_camel_case( - "local_boundary_two_form_interface_" + XT::Grid::bindings::grid_name<G>::value() + layer_name + "_to_" - + to_string(size_t(S::dimRange)) - + "x" - + to_string(size_t(S::dimRangeCols)) - + "_p" - + to_string(int(S::polOrder)) - + "_" - + space_type_name<SP::space_type>::value() - + "_" - + backend_name<SP::space_backend>::value() - + "_space" - + intersection_postfix<>::value()); - py::class_<InterfaceType>(m, InterfaceName.c_str(), InterfaceName.c_str()); - } catch (std::runtime_error&) { - } - - const auto ClassName = - XT::Common::to_camel_case("local_elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() + "_" - + diffusion_switch<>::suffix() - + "_boundary_integral_operator_" - + XT::Grid::bindings::grid_name<G>::value() - + layer_name - + "_to_" - + to_string(size_t(S::dimRange)) - + "x" - + to_string(size_t(S::dimRangeCols)) - + "_p" - + to_string(int(S::polOrder)) - + "_" - + space_type_name<SP::space_type>::value() - + "_" - + backend_name<SP::space_backend>::value() - + "_space" - + intersection_postfix<>::value()); - - bound_type c(m, ClassName.c_str()); - - diffusion_switch<>::addbind_factory_methods(m); - - return c; - } // ... bind(...) -}; // class LocalEllipticIpdgBoundaryIntegralOperator - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_1D( \ - _m, _G, _d, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name, _method) \ - Dune::GDT::bindings::LocalEllipticIpdgInnerIntegralOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_G>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_G>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - Dune::GDT::SpaceProvider<_G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - _R, \ - _r, \ - _rC>, \ - Dune::XT::Grid::Layers::_i_layer_type, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method>::bind(_m, _layer_name); \ - Dune::GDT::bindings::LocalEllipticIpdgInnerIntegralOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_G>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - void, \ - Dune::GDT::SpaceProvider<_G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - _R, \ - _r, \ - _rC>, \ - Dune::XT::Grid::Layers::_i_layer_type, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method>::bind(_m, _layer_name); \ - Dune::GDT::bindings::LocalEllipticIpdgBoundaryIntegralOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_G>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_G>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - Dune::GDT::SpaceProvider<_G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - _R, \ - _r, \ - _rC>, \ - Dune::XT::Grid::Layers::_i_layer_type, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method>::bind(_m, _layer_name); \ - Dune::GDT::bindings::LocalEllipticIpdgBoundaryIntegralOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_G>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - void, \ - Dune::GDT::SpaceProvider<_G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - _R, \ - _r, \ - _rC>, \ - Dune::XT::Grid::Layers::_i_layer_type, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method>::bind(_m, _layer_name) - -# define _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_DD( \ - _m, _G, _d, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name, _method) \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_1D( \ - _m, _G, _d, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name, _method); \ - Dune::GDT::bindings::LocalEllipticIpdgInnerIntegralOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_G>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - void, \ - Dune::GDT::SpaceProvider<_G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - _R, \ - _r, \ - _rC>, \ - Dune::XT::Grid::Layers::_i_layer_type, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method>::bind(_m, _layer_name); \ - Dune::GDT::bindings::LocalEllipticIpdgBoundaryIntegralOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_G>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - void, \ - Dune::GDT::SpaceProvider<_G, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - _R, \ - _r, \ - _rC>, \ - Dune::XT::Grid::Layers::_i_layer_type, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method>::bind(_m, _layer_name) - -# define _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_METHODS_1D( \ - _m, _G, _d, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name) \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_1D( \ - _m, _G, _d, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name, sipdg); \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_1D( \ - _m, _G, _d, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name, swipdg); \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_1D(_m, \ - _G, \ - _d, \ - _g_layer, \ - _g_backend, \ - _s_type, \ - _s_backend, \ - _i_layer_type, \ - _p, \ - _R, \ - _r, \ - _rC, \ - _layer_name, \ - swipdg_affine_factor); \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_1D(_m, \ - _G, \ - _d, \ - _g_layer, \ - _g_backend, \ - _s_type, \ - _s_backend, \ - _i_layer_type, \ - _p, \ - _R, \ - _r, \ - _rC, \ - _layer_name, \ - swipdg_affine_tensor) - -# define _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_METHODS_DD( \ - _m, _G, _d, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name) \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_DD( \ - _m, _G, _d, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name, sipdg); \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_DD( \ - _m, _G, _d, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name, swipdg); \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_DD(_m, \ - _G, \ - _d, \ - _g_layer, \ - _g_backend, \ - _s_type, \ - _s_backend, \ - _i_layer_type, \ - _p, \ - _R, \ - _r, \ - _rC, \ - _layer_name, \ - swipdg_affine_factor); \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_DD(_m, \ - _G, \ - _d, \ - _g_layer, \ - _g_backend, \ - _s_type, \ - _s_backend, \ - _i_layer_type, \ - _p, \ - _R, \ - _r, \ - _rC, \ - _layer_name, \ - swipdg_affine_tensor) - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_ALU( \ - _m, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name) \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_METHODS_DD(_m, \ - ALU_2D_SIMPLEX_CONFORMING, \ - 2, \ - _g_layer, \ - _g_backend, \ - _s_type, \ - _s_backend, \ - _i_layer_type, \ - _p, \ - _R, \ - _r, \ - _rC, \ - _layer_name) -# else -# define _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_ALU( \ - _m, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name) -# endif - -# define _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_YASP( \ - _m, _g_layer, _g_backend, _s_type, _s_backend, _i_layer_type, _p, _R, _r, _rC, _layer_name) \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_METHODS_1D(_m, \ - YASP_1D_EQUIDISTANT_OFFSET, \ - 1, \ - _g_layer, \ - _g_backend, \ - _s_type, \ - _s_backend, \ - _i_layer_type, \ - _p, \ - _R, \ - _r, \ - _rC, \ - _layer_name); \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_METHODS_DD(_m, \ - YASP_2D_EQUIDISTANT_OFFSET, \ - 2, \ - _g_layer, \ - _g_backend, \ - _s_type, \ - _s_backend, \ - _i_layer_type, \ - _p, \ - _R, \ - _r, \ - _rC, \ - _layer_name); \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_METHODS_DD(_m, \ - YASP_3D_EQUIDISTANT_OFFSET, \ - 3, \ - _g_layer, \ - _g_backend, \ - _s_type, \ - _s_backend, \ - _i_layer_type, \ - _p, \ - _R, \ - _r, \ - _rC, \ - _layer_name) - - /* -_DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_ALU( \ - _m, leaf, part, _s_type, _s_backend, leaf, _p, _R, _r, _rC, "_leaf_"); \ -_DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_ALU( \ - _m, level, part, _s_type, _s_backend, level, _p, _R, _r, _rC, "_level_"); \ -_DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_YASP(_m, leaf, part, _s_type, _s_backend, leaf, _p, _R, _r, _rC, ""); \ -_DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_YASP( \ - _m, dd_subdomain, part, _s_type, _s_backend, dd_subdomain_coupling, _p, _R, _r, _rC, "_dd_subdomain_") -*/ - -# define DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND(_m) \ - _DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BIND_ALU( \ - _m, dd_subdomain, view, dg, gdt, dd_subdomain_coupling, 1, double, 1, 1, "_dd_subdomain_") - -// end: this is what we need for the .so - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_LOCAL_ELLIPTIC_IPDG_OPERATORS_BINDINGS_HH diff --git a/python/dune/gdt/operators/base.hh b/python/dune/gdt/operators/base.hh deleted file mode 100644 index b5b1c448bb9dca770acfa37dd140dad4ed7894ee..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/base.hh +++ /dev/null @@ -1,196 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_OPERATORS_BASE_BINDINGS_HH -#define PYTHON_DUNE_GDT_OPERATORS_BASE_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/la/container.hh> - -# include <dune/gdt/type_traits.hh> - -# include <dune/gdt/operators/base.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class OperatorType> -class MatrixOperatorBase -{ - static_assert(is_matrix_operator<OperatorType>::value, ""); - -public: - typedef OperatorType type; - typedef GDT::SystemAssembler<typename OperatorType::RangeSpaceType, - typename OperatorType::GridLayerType, - typename OperatorType::SourceSpaceType> - BaseType; - typedef pybind11::class_<type, BaseType> bound_type; - -private: - typedef typename type::RangeSpaceType R; - typedef typename type::SourceSpaceType S; - typedef typename XT::LA::Container<typename type::FieldType, type::MatrixType::vector_type>::VectorType V; - -public: - template <bool same_spaces = - std::is_same<typename OperatorType::RangeSpaceType, typename OperatorType::SourceSpaceType>::value, - bool anything = true> - struct induced_norm - { - static void addbind(bound_type& c) - { - namespace py = pybind11; - using namespace pybind11::literals; - - c.def("induced_norm", - [](type& self, const V& range) { - py::gil_scoped_release DUNE_UNUSED(release); - return self.induced_norm(range); - }, - "range"_a); - c.def("induced_norm", - [](type& self, const GDT::ConstDiscreteFunction<R, V>& range) { - py::gil_scoped_release DUNE_UNUSED(release); - return self.induced_norm(range); - }, - "range"_a); - } - }; // struct induced_norm - - template <bool anything> - struct induced_norm<false, anything> - { - static void addbind(bound_type& /*c*/) - { - } - }; - - static bound_type bind(pybind11::module& m, const std::string& class_id) - { - namespace py = pybind11; - using namespace pybind11::literals; - - bound_type c(m, std::string(class_id).c_str(), std::string(class_id).c_str()); - - // Does not work if the grid layer of the operator is not the same as the one from the space: - // c.def_static("pattern", [](const R& space) { return type::pattern(space); }); - - // from MatrixOperatorBase - c.def("pattern", - [](type& self) { return self.pattern(self.range_space(), self.source_space(), self.grid_layer()); }); - c.def("matrix", [](type& self) { return self.matrix(); }); - c.def("source_space", [](type& self) { return self.source_space(); }); - c.def("range_space", [](type& self) { return self.range_space(); }); - c.def("apply", - [](type& self, const V& source, V& range) { - py::gil_scoped_release DUNE_UNUSED(release); - self.apply(source, range); - }, - "source"_a, - "range"_a); - c.def("apply", - [](type& self, const GDT::ConstDiscreteFunction<S, V>& source, GDT::DiscreteFunction<R, V>& range) { - py::gil_scoped_release DUNE_UNUSED(release); - self.apply(source, range); - }, - "source"_a, - "range"_a); - c.def("apply2", - [](type& self, const V& range, const V& source) { - py::gil_scoped_release DUNE_UNUSED(release); - return self.apply2(range, source); - }, - "range"_a, - "source"_a); - c.def( - "apply2", - [](type& self, const GDT::ConstDiscreteFunction<R, V>& range, const GDT::ConstDiscreteFunction<S, V>& source) { - py::gil_scoped_release DUNE_UNUSED(release); - return self.apply2(range, source); - }, - "range"_a, - "source"_a); - c.def("apply_inverse", - [](type& self, const V& range, V& source, const XT::Common::Configuration& opts) { - py::gil_scoped_release DUNE_UNUSED(release); - self.apply_inverse(range, source, opts); - }, - "range"_a, - "source"_a, - "opts"_a); - c.def("apply_inverse", - [](type& self, - const GDT::ConstDiscreteFunction<R, V>& range, - GDT::ConstDiscreteFunction<S, V>& source, - const XT::Common::Configuration& opts) { - py::gil_scoped_release DUNE_UNUSED(release); - self.apply_inverse(range, source, opts); - }, - "range"_a, - "source"_a, - "opts"_a); - c.def("invert_options", [](type& self) { return self.invert_options(); }); - c.def("invert_options", [](type& self, const std::string& type) { return self.invert_options(type); }, "type"_a); - - // from OperatorInterface - c.def("apply_inverse", - [](type& self, const V& range, V& source, const std::string& type) { - py::gil_scoped_release DUNE_UNUSED(release); - self.apply_inverse(range, source, type); - }, - "range"_a, - "source"_a, - "type"_a); - c.def("apply_inverse", - [](type& self, - const GDT::ConstDiscreteFunction<R, V>& range, - GDT::ConstDiscreteFunction<S, V>& source, - const std::string& type) { - py::gil_scoped_release DUNE_UNUSED(release); - self.apply_inverse(range, source, type); - }, - "range"_a, - "source"_a, - "type"_a); - c.def("apply_inverse", - [](type& self, const V& range, V& source) { - py::gil_scoped_release DUNE_UNUSED(release); - self.apply_inverse(range, source); - }, - "range"_a, - "source"_a); - c.def("apply_inverse", - [](type& self, const GDT::ConstDiscreteFunction<R, V>& range, GDT::ConstDiscreteFunction<S, V>& source) { - py::gil_scoped_release DUNE_UNUSED(release); - self.apply_inverse(range, source); - }, - "range"_a, - "source"_a); - - induced_norm<>::addbind(c); - - return c; - } // ... bind(...) -}; // class MatrixOperatorBase - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_OPERATORS_BASE_BINDINGS_HH diff --git a/python/dune/gdt/operators/elliptic-ipdg/alu_istl.cc b/python/dune/gdt/operators/elliptic-ipdg/alu_istl.cc deleted file mode 100644 index 6e37864063fbbb514e4715b542729a89835bedaf..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/elliptic-ipdg/alu_istl.cc +++ /dev/null @@ -1,25 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <python/dune/gdt/operators/elliptic-ipdg/bindings.hh> - - -# if HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL -DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_ALU(template, leaf, view, dg, gdt, 1, istl_sparse); -DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_ALU(template, level, view, dg, gdt, 1, istl_sparse); -DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_ALU(template, dd_subdomain, view, dg, gdt, 1, istl_sparse); -# endif - - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/operators/elliptic-ipdg/bindings.cc b/python/dune/gdt/operators/elliptic-ipdg/bindings.cc deleted file mode 100644 index 79069357a31408935d64761a0ce4f40f2565c95c..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/elliptic-ipdg/bindings.cc +++ /dev/null @@ -1,57 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> - -# include <python/dune/gdt/operators/elliptic-ipdg/bindings.hh> - - -PYBIND11_MODULE(__operators_elliptic_ipdg, m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - py::module::import("dune.gdt.__discretefunction"); - -// alu_istl.cc -# if HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL - DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_ALU(m, leaf, view, dg, gdt, 1, istl_sparse); - DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_ALU(m, level, view, dg, gdt, 1, istl_sparse); - DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_ALU(m, dd_subdomain, view, dg, gdt, 1, istl_sparse); -# endif - -// yasp_istl.cc -# if HAVE_DUNE_ISTL - DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_YASP(m, leaf, view, dg, gdt, 1, istl_sparse); - DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_YASP(m, level, view, dg, gdt, 1, istl_sparse); - DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_YASP(m, dd_subdomain, view, dg, gdt, 1, istl_sparse); -# endif - - add_initialization(m, "dune.gdt.operators.elliptic.ipdg"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/operators/elliptic-ipdg/bindings.hh b/python/dune/gdt/operators/elliptic-ipdg/bindings.hh deleted file mode 100644 index 1ed981e6070f455846a3fd3cdcdb1558a76066fe..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/elliptic-ipdg/bindings.hh +++ /dev/null @@ -1,565 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BINDINGS_HH -#define PYTHON_DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/common/string.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <dune/xt/grid/type_traits.hh> -# include <python/dune/xt/la/container.bindings.hh> - -# include <python/dune/gdt/spaces/bindings.hh> -# include <dune/gdt/type_traits.hh> - -# include <dune/gdt/operators/elliptic-ipdg.hh> -# include <python/dune/gdt/operators/base.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class DF, - typename DT, // may be void - class RP, - LocalEllipticIpdgIntegrands::Method method, - class M /* = typename XT::LA::Container<typename R::RangeFieldType>::MatrixType, - class GL = typename RP::type::GridLayerType, - class SP = RP, - class F = typename RP::type::RangeFieldType*/> -class EllipticIpdgMatrixOperator -{ - typedef typename RP::type R; - static_assert(is_space<R>::value, ""); - -public: - typedef GDT::EllipticIpdgMatrixOperator<DF, DT, R, method, M /*, GL, S, F*/> type; - typedef pybind11::class_<type> bound_type; - -private: - template <bool single_diffusion = std::is_same<DT, void>::value, - bool scalar = (DF::dimRange == 1 && DF::dimRangeCols == 1), - bool anything = false> - struct diffusion_switch - { - static std::string suffix() - { - return "diffusion_factor_and_tensor"; - } - - template <class C> - static void addbind_factory_methods(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto method_name = - "make_elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() + "_matrix_operator"; - - m.def( - std::string(method_name + "_" + XT::LA::bindings::container_name<M>::value()).c_str(), - [](const DF& diffusion_factor, - const DT& diffusion_tensor, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<typename R::GridLayerType>>& boundary_info, - const R& space, - const size_t over_integrate) { - return make_elliptic_ipdg_matrix_operator<M, method>( - diffusion_factor, diffusion_tensor, boundary_info, space, over_integrate) - .release(); // <- b.c. EllipticIpdgMatrixOperator is not movable, returning the raw pointer lets - }, // pybind11 correctly manage the memory - "diffusion_factor"_a, - "diffusion_tensor"_a, - "boundary_info"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>(), - py::keep_alive<0, 4>()); - - m.def( - method_name.c_str(), - [](const DF& diffusion_factor, - const DT& diffusion_tensor, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<typename R::GridLayerType>>& boundary_info, - M& matrix, - const R& space, - const size_t over_integrate) { - return make_elliptic_ipdg_matrix_operator<method>( - diffusion_factor, diffusion_tensor, boundary_info, matrix, space, over_integrate) - .release(); // <- s.a. for release() - }, - "diffusion_factor"_a, - "diffusion_tensor"_a, - "boundary_info"_a, - "matrix"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>(), - py::keep_alive<0, 4>(), - py::keep_alive<0, 5>()); - } // ... addbind_factory_methods(...) - - }; // struct diffusion_switch - - struct diffusion_switch_scalar_base - { - template <class C> - static void addbind_factory_methods(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto method_name = - "make_elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() + "_matrix_operator"; - - m.def( - std::string(method_name + "_" + XT::LA::bindings::container_name<M>::value()).c_str(), - [](const DF& diffusion, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<typename R::GridLayerType>>& boundary_info, - const R& space, - const size_t over_integrate) { - return make_elliptic_ipdg_matrix_operator<M, method>(diffusion, boundary_info, space, over_integrate) - .release(); // <- s.a. for release() - }, - "diffusion"_a, - "boundary_info"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>()); - - m.def( - method_name.c_str(), - [](const DF& diffusion, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<typename R::GridLayerType>>& boundary_info, - M& matrix, - const R& space, - const size_t over_integrate) { - return make_elliptic_ipdg_matrix_operator<method>(diffusion, boundary_info, matrix, space, over_integrate) - .release(); // <- s.a. for release() - }, - "diffusion"_a, - "boundary_info"_a, - "matrix"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>(), - py::keep_alive<0, 4>()); - } // ... addbind_factory_methods(...) - }; // struct diffusion_switch<..., void> - - template <bool anything> - struct diffusion_switch<true, true, anything> : public diffusion_switch_scalar_base - { - static std::string suffix() - { - return "single_diffusion_factor"; - } - }; - - template <bool anything> - struct diffusion_switch<true, false, anything> : public diffusion_switch_scalar_base - { - static std::string suffix() - { - return "single_diffusion_tensor"; - } - }; - -public: - static bound_type bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto ClassName = XT::Common::to_camel_case( - "elliptic_" + LocalEllipticIpdgIntegrands::method_name<method>::value() + "_matrix_operator_" - + space_name<RP>::value() - + "_" - + XT::LA::bindings::container_name<M>::value() - + "_" - + diffusion_switch<>::suffix()); - - auto c = MatrixOperatorBase<type>::bind(m, ClassName.c_str()); - - diffusion_switch<>::template addbind_factory_methods<type>(m); - - return c; - } // ... bind(...) -}; // EllipticIpdgMatrixOperator - - -} // naemspace bindings -} // namespace GDT -} // namespace Dune - - -// begin: this is what we need for the lib - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, _method) \ - _prefix class Dune::GDT::bindings::EllipticIpdgMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType>; \ - _prefix class Dune::GDT::bindings::EllipticIpdgMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - 1, \ - double, \ - 1, \ - 1>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType> - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, _method) \ - _prefix class Dune::GDT::bindings::EllipticIpdgMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType>; \ - _prefix class Dune::GDT::bindings::EllipticIpdgMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType>; \ - _prefix class Dune::GDT::bindings::EllipticIpdgMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType> - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_METHODS_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, sipdg); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_factor); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_1D( \ - _prefix, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_tensor) - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_METHODS_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, sipdg); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_factor); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_tensor) - -/* -#if HAVE_ALBERTA -#define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_ALBERTA(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_METHODS_D( \ - _prefix, 2, ALBERTA_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_ALBERTA(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# if HAVE_DUNE_ALUGRID -# define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_ALU(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_METHODS_D( \ - _prefix, 2, ALU_2D_SIMPLEX_CONFORMING, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# else -# define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_ALU(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# endif - -/* -#if HAVE_DUNE_UGGRID || HAVE_UG -#define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_UG(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_METHODS_D( \ - _prefix, 2, UG_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_UG(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_YASP(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_METHODS_1D( \ - _prefix, YASP_1D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_METHODS_D( \ - _prefix, 2, YASP_2D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la) - -// alu_istl.cc -# if HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL -DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_ALU(extern template, leaf, view, cg, gdt, 1, istl_sparse); -DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_ALU(extern template, level, view, cg, gdt, 1, istl_sparse); -// DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_ALU(extern template, dd_subdomain, view, cg, gdt, 1, istl_sparse); -# endif - -// yasp_istl.cc -# if HAVE_DUNE_ISTL -DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_YASP(extern template, leaf, view, cg, gdt, 1, istl_sparse); -DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_YASP(extern template, level, view, cg, gdt, 1, istl_sparse); -// DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_YASP(extern template, dd_subdomain, view, cg, gdt, 1, istl_sparse); -# endif - -// end: this is what we need for the lib - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_1D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, _method) \ - Dune::GDT::bindings::EllipticIpdgMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType>::bind(_m); \ - Dune::GDT::bindings::EllipticIpdgMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType>::bind(_m) - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, _method) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_1D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, _method); \ - Dune::GDT::bindings::EllipticIpdgMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - Dune::GDT::LocalEllipticIpdgIntegrands::Method::_method, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType>::bind(_m) - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_METHODS_1D( \ - _m, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_1D(_m, 1, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, sipdg); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_1D(_m, 1, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_1D( \ - _m, 1, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_factor); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_1D( \ - _m, 1, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_tensor) - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_METHODS_D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_D(_m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, sipdg); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_D(_m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_factor); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_D( \ - _m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la, swipdg_affine_tensor) - -/* -#if HAVE_ALBERTA -#define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_ALBERTA(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_METHODS_D(_m, 2, ALBERTA_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_ALBERTA(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# if HAVE_DUNE_ALUGRID -# define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_ALU(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_METHODS_D( \ - _m, 2, ALU_2D_SIMPLEX_CONFORMING, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# else -# define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_ALU(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# endif - -/* -#if HAVE_DUNE_UGGRID || HAVE_UG -#define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_UG(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_METHODS_D(_m, 2, UG_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_UG(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# define DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_YASP(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_METHODS_1D( \ - _m, YASP_1D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_METHODS_D( \ - _m, 2, YASP_2D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la) - - -// end: this is what we need for the .so - - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BINDINGS_HH diff --git a/python/dune/gdt/operators/elliptic-ipdg/yasp_istl.cc b/python/dune/gdt/operators/elliptic-ipdg/yasp_istl.cc deleted file mode 100644 index 22199e07861a5157001fee84413445ee2899dfda..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/elliptic-ipdg/yasp_istl.cc +++ /dev/null @@ -1,25 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <python/dune/gdt/operators/elliptic-ipdg/bindings.hh> - - -# if HAVE_DUNE_ISTL -DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_YASP(template, leaf, view, dg, gdt, 1, istl_sparse); -DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_YASP(template, level, view, dg, gdt, 1, istl_sparse); -DUNE_GDT_OPERATORS_ELLIPTIC_IPDG_BIND_LIB_YASP(template, dd_subdomain, view, dg, gdt, 1, istl_sparse); -# endif - - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/operators/elliptic/bindings.cc b/python/dune/gdt/operators/elliptic/bindings.cc deleted file mode 100644 index 30a17de5d33bea4bba60f698167dc5a50550fb50..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/elliptic/bindings.cc +++ /dev/null @@ -1,45 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> - -# include <python/dune/gdt/operators/elliptic/bindings.hh> - - -PYBIND11_MODULE(__operators_elliptic, m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - py::module::import("dune.gdt.__discretefunction"); - - DUNE_GDT_OPERATORS_ELLIPTIC_BIND_ISTL(m); - - add_initialization(m, "dune.gdt.operators.elliptic"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/operators/elliptic/bindings.hh b/python/dune/gdt/operators/elliptic/bindings.hh deleted file mode 100644 index 4f130da92fd291f47b4c54ab65f3fff8a324b106..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/elliptic/bindings.hh +++ /dev/null @@ -1,465 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_OPERATORS_ELLIPTIC_BINDINGS_HH -#define PYTHON_DUNE_GDT_OPERATORS_ELLIPTIC_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <python/dune/xt/grid/grids.bindings.hh> -# include <dune/xt/grid/type_traits.hh> -# include <python/dune/xt/la/container.bindings.hh> - -# include <python/dune/gdt/spaces/bindings.hh> -# include <dune/gdt/type_traits.hh> - -# include <python/dune/gdt/operators/base.hh> -# include <dune/gdt/operators/elliptic.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class DF, - typename DT, // may be void - class RP, - class M /* = typename XT::LA::Container<typename R::RangeFieldType>::MatrixType, - class GL = typename R::GridLayerType, - class S = R, - class F = typename R::RangeFieldType*/> -class EllipticMatrixOperator -{ - typedef typename RP::type R; - static_assert(is_space<R>::value, ""); - -public: - typedef GDT::EllipticMatrixOperator<DF, DT, R, M /*, GL, S, F*/> type; - typedef pybind11::class_<type> bound_type; - -private: - template <bool single_diffusion = std::is_same<DT, void>::value, - bool scalar = (DF::dimRange == 1 && DF::dimRangeCols == 1), - bool anything = false> - struct diffusion_switch - { - static std::string suffix() - { - return "diffusion_factor_and_tensor"; - } - - template <class C> - static void addbind_factory_methods(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const std::string method_name = "make_elliptic_matrix_operator_" + XT::LA::bindings::container_name<M>::value(); - - m.def( - method_name.c_str(), - [](const DF& diffusion_factor, const DT& diffusion_tensor, const R& space, const size_t over_integrate) { - return make_elliptic_matrix_operator<M>(diffusion_factor, diffusion_tensor, space, over_integrate) - .release(); // <- b.c. EllipticMatrixOperator is not movable, returning the raw pointer lets pybind11 - }, // correctly manage the memory - "diffusion_factor"_a, - "diffusion_tensor"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>()); - - m.def( - std::string(method_name).c_str(), - [](const DF& diffusion_factor, - const DT& diffusion_tensor, - M& matrix, - const R& space, - const size_t over_integrate) { - return make_elliptic_matrix_operator(diffusion_factor, diffusion_tensor, matrix, space, over_integrate) - .release(); // <- s.a. for release() - }, - "diffusion_factor"_a, - "diffusion_tensor"_a, - "matrix"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>()); - } // ... addbind_factory_methods(...) - }; // struct diffusion_switch - - struct diffusion_switch_scalar_base - { - template <class C> - static void addbind_factory_methods(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const std::string method_name = "make_elliptic_matrix_operator_" + XT::LA::bindings::container_name<M>::value(); - - m.def(method_name.c_str(), - [](const DF& diffusion, const R& space, const size_t over_integrate) { - return make_elliptic_matrix_operator<M>(diffusion, space, over_integrate).release(); // <- s.a. - }, - "diffusion"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>()); - - m.def(std::string(method_name).c_str(), - [](const DF& diffusion, M& matrix, const R& space, const size_t over_integrate) { - return make_elliptic_matrix_operator(diffusion, matrix, space, over_integrate).release(); // <- s.a. - }, - "diffusion"_a, - "matrix"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>()); - } // ... addbind_factory_methods(...) - }; // struct diffusion_switch<..., void> - - template <bool anything> - struct diffusion_switch<true, true, anything> : public diffusion_switch_scalar_base - { - - static std::string suffix() - { - return "single_diffusion_factor"; - } - }; - - template <bool anything> - struct diffusion_switch<true, false, anything> : public diffusion_switch_scalar_base - { - - static std::string suffix() - { - return "single_diffusion_tensor"; - } - }; - -public: - static bound_type bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto ClassName = XT::Common::to_camel_case( - "elliptic_matrix_operator_" + space_name<RP>::value() + "_" + XT::LA::bindings::container_name<M>::value() + "_" - + diffusion_switch<>::suffix()); - - auto c = MatrixOperatorBase<type>::bind(m, ClassName); - - diffusion_switch<>::template addbind_factory_methods<type>(m); - - return c; - } // ... bind(...) -}; // class EllipticMatrixOperator - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - - -// begin: this is what we need for the lib - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_1D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _prefix class Dune::GDT::bindings::EllipticMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType>; \ - _prefix class Dune::GDT::bindings::EllipticMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType> - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_D( \ - _prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_1D(_prefix, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _prefix class Dune::GDT::bindings::EllipticMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType> - -/* -#if HAVE_ALBERTA -#define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_ALBERTA(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_D(_prefix, 2, ALBERTA_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_ALBERTA(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_ALU(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_D( \ - _prefix, 2, ALU_2D_SIMPLEX_CONFORMING, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# else -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_ALU(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# endif - -/* -#if HAVE_DUNE_UGGRID || HAVE_UG -#define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_UG(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_D(_prefix, 2, UG_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_UG(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_YASP(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_1D( \ - _prefix, 1, YASP_1D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_D( \ - _prefix, 2, YASP_2D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la) - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_GRIDS(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_ALBERTA(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_ALU(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_UG(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_YASP(_prefix, _layer, _g_backend, _s_type, _s_backend, _p, _la) - - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB(_prefix, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_GRIDS(_prefix, leaf, view, dg, gdt, 1, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_GRIDS(_prefix, level, view, dg, gdt, 1, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_GRIDS(_prefix, dd_subdomain, view, dg, gdt, 1, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_GRIDS(_prefix, dd_subdomain, view, cg, gdt, 1, _la) - -# if HAVE_DUNE_ISTL -# define DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_ISTL(_prefix) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB(_prefix, istl_sparse) -# else -# define DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_ISTL(_prefix) -# endif - -// istl.cc -DUNE_GDT_OPERATORS_ELLIPTIC_BIND_LIB_ISTL(extern template); - -// end: this is what we need for the lib - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_1D(_m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - Dune::GDT::bindings::EllipticMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType>::bind(_m); \ - Dune::GDT::bindings::EllipticMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - 1, \ - 1>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType>::bind(_m) - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_D(_m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_1D(_m, _d, _GRID, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - Dune::GDT::bindings::EllipticMatrixOperator< \ - Dune::XT::Functions::GridFunctionInterface<Dune::XT::Grid::extract_entity_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_g_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - double, \ - _d, \ - double, \ - _d, \ - _d>, \ - void, \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::MatrixType>::bind(_m) - -/* -#if HAVE_ALBERTA -#define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_ALBERTA(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_D(_m, 2, ALBERTA_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_ALBERTA(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_ALU(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_D( \ - _m, 2, ALU_2D_SIMPLEX_CONFORMING, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# else -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_ALU(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) -# endif - -/* -#if HAVE_DUNE_UGGRID || HAVE_UG -#define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_UG(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_D(_m, 2, UG_2D, _layer, _g_backend, _s_type, _s_backend, _p, _la) -#else -*/ -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_UG(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) -//#endif - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_YASP(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_1D( \ - _m, 1, YASP_1D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_D( \ - _m, 2, YASP_2D_EQUIDISTANT_OFFSET, _layer, _g_backend, _s_type, _s_backend, _p, _la) - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_GRIDS(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_ALBERTA(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_ALU(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_UG(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_YASP(_m, _layer, _g_backend, _s_type, _s_backend, _p, _la) - -# define _DUNE_GDT_OPERATORS_ELLIPTIC_BIND(_m, _la) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_GRIDS(_m, leaf, view, cg, gdt, 1, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_GRIDS(_m, level, view, cg, gdt, 1, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_GRIDS(_m, leaf, view, dg, gdt, 1, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_GRIDS(_m, level, view, dg, gdt, 1, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_GRIDS(_m, dd_subdomain, view, dg, gdt, 1, _la); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND_GRIDS(_m, dd_subdomain, view, dg, gdt, 1, _la) -# define DUNE_GDT_OPERATORS_ELLIPTIC_BIND_COMMON(_m) -//_DUNE_GDT_OPERATORS_ELLIPTIC_BIND(_m, common_dense) - /* -#if HAVE_EIGEN -#define DUNE_GDT_OPERATORS_ELLIPTIC_BIND_EIGEN(_m) \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND(_m, eigen_dense); \ - _DUNE_GDT_OPERATORS_ELLIPTIC_BIND(_m, eigen_sparse) -#else -*/ -# define DUNE_GDT_OPERATORS_ELLIPTIC_BIND_EIGEN(_m) -//#endif -# if HAVE_DUNE_ISTL -# define DUNE_GDT_OPERATORS_ELLIPTIC_BIND_ISTL(_m) _DUNE_GDT_OPERATORS_ELLIPTIC_BIND(_m, istl_sparse) -# else -# define DUNE_GDT_OPERATORS_ELLIPTIC_BIND_ISTL(_m) -# endif - -// end: this is what we need for the .so - - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_OPERATORS_ELLIPTIC_BINDINGS_HH diff --git a/python/dune/gdt/operators/fluxreconstruction.cc b/python/dune/gdt/operators/fluxreconstruction.cc deleted file mode 100644 index 5fee70ab9259928d023896eda91eaff42a4777d2..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/fluxreconstruction.cc +++ /dev/null @@ -1,57 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <python/dune/gdt/shared.hh> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <dune/xt/grid/dd/subdomains/grid.hh> -# include <dune/xt/grid/grids.hh> - -# include <dune/gdt/spaces.hh> -# include <python/dune/gdt/operators/fluxreconstruction.hh> - - -PYBIND11_MODULE(__operators_fluxreconstruction, m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - py::module::import("dune.gdt.__discretefunction"); - -# if HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL - Dune::GDT::bindings::DiffusiveFluxReconstructionOperator<ALU_2D_SIMPLEX_CONFORMING, - Dune::GDT::SpaceType::rt, - Dune::GDT::Backends::gdt, - Dune::XT::Grid::Layers::leaf, - 0, - double, - 2, - Dune::XT::LA::Backends::istl_dense>::bind(m); -# endif // HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL - - add_initialization(m, "dune.gdt.operators.elliptic"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/operators/fluxreconstruction.hh b/python/dune/gdt/operators/fluxreconstruction.hh deleted file mode 100644 index 030948aefcf084670f3e147ea18bb7a0f524a8c3..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/fluxreconstruction.hh +++ /dev/null @@ -1,99 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_OPERATORS_FLUXRECONSTRUCTION_BINDINGS_HH -#define PYTHON_DUNE_GDT_OPERATORS_FLUXRECONSTRUCTION_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/la/container.hh> - -# include <dune/gdt/spaces.hh> - -# include <dune/gdt/operators/fluxreconstruction.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class G, - SpaceType space_type, - Backends space_backend, - XT::Grid::Layers space_layer_type, - int p, - class R, - size_t r, - XT::LA::Backends la_backend /*, - XT::Grid::Layers layer_type = space_layer_type, - XT::Grid::Backends layer_backend = - SpaceProvider<G, space_layer_type, space_type, space_backend, p, R, r>::layer_backend*/> -class DiffusiveFluxReconstructionOperator -{ - typedef typename SpaceProvider<G, space_layer_type, space_type, space_backend, p, R, r>::type S; - typedef typename S::GridLayerType GL; - typedef typename XT::LA::Container<R, la_backend>::VectorType V; - typedef typename S::EntityType E; - typedef typename S::DomainFieldType D; - static const size_t d = S::dimDomain; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunctionType; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> TensorFunctionType; - -public: - static void bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - // m.def("apply_diffusive_flux_reconstruction_operator", - // [](const ScalarFunctionType& diffusion_factor, - // const ScalarFunctionType& source, - // DiscreteFunction<S, V>& range) { - // py::gil_scoped_release DUNE_UNUSED(release); - // GDT::DiffusiveFluxReconstructionOperator<GL, - // ScalarFunctionType, - // void, - // LocalEllipticIpdgIntegrands::Method::swipdg_affine_factor>( - // range.space().grid_layer(), diffusion_factor) - // .apply(source, range); - // }, - // "diffusion_tensor"_a, - // "source"_a, - // "range"_a); - m.def("apply_diffusive_flux_reconstruction_operator", - [](const ScalarFunctionType& diffusion_factor, - const TensorFunctionType& diffusion_tensor, - const ScalarFunctionType& source, - DiscreteFunction<S, V>& range) { - py::gil_scoped_release DUNE_UNUSED(release); - GDT::DiffusiveFluxReconstructionOperator<GL, - ScalarFunctionType, - TensorFunctionType, - LocalEllipticIpdgIntegrands::Method::swipdg_affine_factor>( - range.space().grid_layer(), diffusion_factor, diffusion_tensor) - .apply(source, range); - }, - "diffusion_factor"_a, - "diffusion_tensor"_a, - "source"_a, - "range"_a); - } -}; // class DiffusiveFluxReconstructionOperator - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_OPERATORS_FLUXRECONSTRUCTION_BINDINGS_HH diff --git a/python/dune/gdt/operators/l2.cc b/python/dune/gdt/operators/l2.cc deleted file mode 100644 index 7acf814ebf2a3d0720acd3f90f53ff40847a132e..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/l2.cc +++ /dev/null @@ -1,108 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <dune/xt/grid/layers.hh> - -# include <python/dune/gdt/operators/l2.hh> -# include <dune/gdt/playground/spaces/restricted.hh> - -using namespace Dune; -namespace py = pybind11; -using namespace pybind11::literals; -using Dune::XT::Grid::Layers; -using namespace Dune::XT; -using Dune::GDT::SpaceType; - - -template <class G, - XT::Grid::Layers layer_type, - XT::Grid::Backends layer_backend, - size_t range_r = 1, - size_t range_rC = 1, - size_t source_r = range_r, - size_t source_rC = range_rC> -void bind_l2_localizable_product(py::module& m) -{ - try { - GDT::bindings::L2LocalizableProduct<G, layer_type, layer_backend, range_r, range_rC, source_r, source_rC>::bind(m); - } catch (std::runtime_error&) { - } -} - - -PYBIND11_MODULE(__operators_l2, m) -{ - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - py::module::import("dune.gdt.__discretefunction"); - -# if HAVE_DUNE_ALUGRID - bind_l2_localizable_product<ALU_2D_SIMPLEX_CONFORMING, Layers::dd_subdomain, XT::Grid::Backends::view>(m); - - Dune::GDT::bindings::L2MatrixOperator<ALU_2D_SIMPLEX_CONFORMING, - Layers::dd_subdomain, - SpaceType::dg, - GDT::Backends::gdt, - 1, - 1, - LA::Backends::istl_sparse>::bind(m); - Dune::GDT::bindings::L2MatrixOperator<ALU_2D_SIMPLEX_CONFORMING, - Layers::leaf, - SpaceType::dg, - GDT::Backends::gdt, - 1, - 1, - LA::Backends::istl_sparse>::bind(m); - Dune::GDT::bindings::L2MatrixOperator<ALU_2D_SIMPLEX_CONFORMING, - Layers::level, - SpaceType::dg, - GDT::Backends::gdt, - 1, - 1, - LA::Backends::istl_sparse>::bind(m); - Dune::GDT::bindings::internal::L2MatrixOperator< - GDT::RestrictedSpace<typename GDT::SpaceProvider<ALU_2D_SIMPLEX_CONFORMING, - Layers::leaf, - GDT::SpaceType::rt, - GDT::Backends::gdt, - 0, - double, - 2>::type, - typename XT::Grid::Layer<ALU_2D_SIMPLEX_CONFORMING, - Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<ALU_2D_SIMPLEX_CONFORMING>>::type>, - XT::LA::IstlRowMajorSparseMatrix<double>>::bind(m, - "RtAlu2dSimplexLeafRestrictedSubdomainPartSpace", - "istl_row_major_sparse_matrix_double"); - -# endif // HAVE_DUNE_ALUGRID - - add_initialization(m, "dune.gdt.operators.elliptic"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/operators/l2.hh b/python/dune/gdt/operators/l2.hh deleted file mode 100644 index efcd95ea05fc0a3da48841ae81f9f92cff62ce95..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/l2.hh +++ /dev/null @@ -1,245 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_OPERATORS_L2_BINDINGS_HH -#define PYTHON_DUNE_GDT_OPERATORS_L2_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <python/dune/xt/grid/grids.bindings.hh> -# include <dune/xt/grid/type_traits.hh> -# include <python/dune/xt/la/container.bindings.hh> - -# include <dune/gdt/spaces.hh> -# include <dune/gdt/spaces/bindings.hh> -# include <dune/gdt/type_traits.hh> - -# include <python/dune/gdt/operators/base.hh> -# include <dune/gdt/operators/l2.hh> - -namespace Dune { -namespace GDT { -namespace bindings { -namespace internal { - - -template <class R, class M> -class L2MatrixOperator -{ -public: - typedef GDT::L2MatrixOperator<R, M> type; - typedef pybind11::class_<type, XT::Grid::Walker<typename R::GridLayerType>> bound_type; - -public: - static bound_type bind(pybind11::module& m, const std::string& space_name, const std::string& container_name) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const std::string class_name = "l2_matrix_operator"; - const auto ClassName = XT::Common::to_camel_case(class_name + "_" + space_name + "_" + container_name); - - bound_type c(m, ClassName.c_str()); - c.def("assemble", [](type& self) { self.assemble(); }); - c.def("matrix", [](type& self) { return self.matrix(); }); - - m.def(std::string("make_" + class_name + "_" + container_name).c_str(), - [](const R& space, const size_t over_integrate) { - return make_l2_matrix_operator<M>(space, over_integrate).release(); - }, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>()); - - m.def(std::string("make_" + class_name).c_str(), - [](M& matrix, const R& space, const size_t over_integrate) { - return make_l2_matrix_operator(matrix, space, over_integrate).release(); - }, - "matrix"_a, - "space"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>()); - - return c; - } // ... bind(...) -}; // class L2MatrixOperator - - -} // namespace internal - - -template <class G, - XT::Grid::Layers layer_type, - GDT::SpaceType space_type, - GDT::Backends space_backend, - int p, - size_t r, - XT::LA::Backends la_backend> -class L2MatrixOperator -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef GDT::SpaceProvider<G, layer_type, space_type, space_backend, p, double, r, 1> RP; - typedef typename RP::type R; - typedef typename XT::LA::Container<double, la_backend>::MatrixType M; - - typedef internal::L2MatrixOperator<R, M> binder; - -public: - typedef typename binder::type type; - typedef typename binder::bound_type bound_type; - -public: - static bound_type bind(pybind11::module& m) - { - return binder::bind(m, space_name<RP>::value(), XT::LA::bindings::container_name<M>::value()); - } -}; // class L2MatrixOperator - - -template <class G, - XT::Grid::Layers layer_type, - XT::Grid::Backends layer_backend, - size_t range_r = 1, - size_t range_rC = 1, - size_t source_r = range_r, - size_t source_rC = range_rC> -class L2LocalizableProduct -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - - template <bool is_dd = layer_type == XT::Grid::Layers::dd_subdomain - || layer_type == XT::Grid::Layers::dd_subdomain_boundary - || layer_type == XT::Grid::Layers::dd_subdomain_coupling - || layer_type == XT::Grid::Layers::dd_subdomain_oversampled, - bool anything = true> - struct GridLayer - { - typedef typename XT::Grid::Layer<G, layer_type, layer_backend, XT::Grid::DD::SubdomainGrid<G>>::type type; - }; - - template <bool anything> - struct GridLayer<false, anything> - { - typedef typename XT::Grid::Layer<G, layer_type, layer_backend>::type type; - }; - - typedef typename GridLayer<>::type GL; - typedef XT::Grid::extract_entity_t<GL> E; - typedef typename G::ctype D; - static const size_t d = G::dimension; - typedef XT::Functions::GridFunctionInterface<E, D, d, double, range_r, range_rC> R; - typedef XT::Functions::GridFunctionInterface<E, D, d, double, source_r, source_rC> S; - -public: - typedef GDT::L2LocalizableProduct<GL, R, S> type; - typedef pybind11::class_<type, XT::Grid::Walker<GL>> bound_type; - -private: - static std::string class_name() - { - return "l2_localizable_product_on_" + XT::Grid::bindings::layer_name<layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<layer_backend>::value() + "_for_" + XT::Common::to_string(range_r) + "x" - + XT::Common::to_string(range_rC) + "_range_times_" + XT::Common::to_string(source_r) + "x" - + XT::Common::to_string(source_rC) + "_source"; - } - - template <bool is_dd = layer_type == XT::Grid::Layers::dd_subdomain - || layer_type == XT::Grid::Layers::dd_subdomain_boundary - || layer_type == XT::Grid::Layers::dd_subdomain_coupling - || layer_type == XT::Grid::Layers::dd_subdomain_oversampled, - bool anything = true> - struct FactoryMethods - { - static void addbind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name()).c_str(), - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& grid_provider, - const int level_or_subdomain, - const R& range, - const S& source, - const size_t over_integrate) { - return make_l2_localizable_product( - grid_provider.template layer<layer_type, layer_backend>(level_or_subdomain), - range, - source, - over_integrate) - .release(); - }, - "grid_provider"_a, - "level_or_subdomain"_a, - "range"_a, - "source"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 3>(), - py::keep_alive<0, 4>()); - } - }; // struct FactoryMethods<true, ...> - - template <bool anything> - struct FactoryMethods<false, anything> - { - static void addbind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name()).c_str(), - [](XT::Grid::GridProvider<G>& grid_provider, - const int level, - const R& range, - const S& source, - const size_t over_integrate) { - return make_l2_localizable_product( - grid_provider.template layer<layer_type, layer_backend>(level), range, source, over_integrate) - .release(); - }, - "grid_provider"_a, - "level"_a, - "range"_a, - "source"_a, - "over_integrate"_a = 0, - py::keep_alive<0, 3>(), - py::keep_alive<0, 4>()); - - FactoryMethods<true>::addbind(m); - } - }; // struct FactoryMethods<false, ...> - -public: - static bound_type bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - FactoryMethods<>::addbind(m); // needs to come first, as the code below may fail - - const std::string cn = class_name(); - bound_type c(m, XT::Common::to_camel_case(cn).c_str()); - c.def("apply2", [](type& self) { return self.apply2(); }); - c.def("result", [](type& self) { return self.result(); }); - - return c; - } // ... bind(...) -}; // class L2LocalizableProduct - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_OPERATORS_L2_BINDINGS_HH diff --git a/python/dune/gdt/operators/oswaldinterpolation.cc b/python/dune/gdt/operators/oswaldinterpolation.cc deleted file mode 100644 index 354ae3c409255dcce4423a6f63937e59bf9e149f..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/oswaldinterpolation.cc +++ /dev/null @@ -1,58 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> -# include <dune/xt/grid/dd/subdomains/grid.hh> -# include <dune/xt/grid/grids.hh> - -# include <dune/gdt/spaces.hh> -# include <python/dune/gdt/operators/oswaldinterpolation.hh> - - -PYBIND11_MODULE(__operators_oswaldinterpolation, m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - py::module::import("dune.gdt.__discretefunction"); - -# if HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL - Dune::GDT::bindings::OswaldInterpolationOperator<ALU_2D_SIMPLEX_CONFORMING, - Dune::GDT::SpaceType::block_dg, - Dune::GDT::Backends::gdt, - Dune::XT::Grid::Layers::dd_subdomain, - 1, - double, - 1, - Dune::XT::LA::Backends::istl_dense, - Dune::XT::Grid::Layers::dd_subdomain_oversampled>::bind(m); -# endif // HAVE_DUNE_ALUGRID && HAVE_DUNE_ISTL - - add_initialization(m, "dune.gdt.operators.elliptic"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/operators/oswaldinterpolation.hh b/python/dune/gdt/operators/oswaldinterpolation.hh deleted file mode 100644 index 8f0bac8fff72c8d2902821214a10a12cd709e3f5..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/oswaldinterpolation.hh +++ /dev/null @@ -1,84 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017) -// René Fritze (2018) -// Tobias Leibner (2017 - 2018) - -#ifndef PYTHON_DUNE_GDT_OPERATORS_OSWALDINTERPOLATION_BINDINGS_HH -#define PYTHON_DUNE_GDT_OPERATORS_OSWALDINTERPOLATION_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/la/container.hh> -# include <dune/xt/grid/gridprovider/provider.hh> - -# include <dune/gdt/spaces.hh> - -# include <dune/gdt/operators/oswaldinterpolation.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class G, - SpaceType space_type, - Backends space_backend, - XT::Grid::Layers space_layer_type, - int p, - class R, - size_t r, - XT::LA::Backends la_backend, - XT::Grid::Layers interpolation_layer_type = space_layer_type, - XT::Grid::Backends interpolation_layer_backend = - SpaceProvider<G, space_layer_type, space_type, space_backend, p, R, r>::layer_backend> -class OswaldInterpolationOperator -{ - typedef typename SpaceProvider<G, space_layer_type, space_type, space_backend, p, R, r>::type S; - typedef typename S::GridLayerType GL; - typedef typename XT::LA::Container<R, la_backend>::VectorType V; - typedef typename XT::Grid:: - Layer<G, interpolation_layer_type, interpolation_layer_backend, XT::Grid::DD::SubdomainGrid<G>>::type - InterpolationLayerType; - -public: - static void bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - m.def("apply_oswald_interpolation_operator", - [](const XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t layer_level_or_subdomain, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<InterpolationLayerType>>& boundary_info, - const GDT::ConstDiscreteFunction<S, V>& source, - GDT::DiscreteFunction<S, V>& range) { - GDT::OswaldInterpolationOperator<InterpolationLayerType, R>( - dd_grid_provider.template layer<interpolation_layer_type, interpolation_layer_backend>( - layer_level_or_subdomain), - boundary_info) - .apply(source, range); - }, - "dd_grid_provider"_a, - "layer_level_or_subdomain"_a = -1, - "boundary_info"_a = - XT::Grid::AllDirichletBoundaryInfo<XT::Grid::extract_intersection_t<InterpolationLayerType>>(), - "source"_a, - "range"_a); - } -}; // class OswaldInterpolationOperator - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_OPERATORS_OSWALDINTERPOLATION_BINDINGS_HH diff --git a/python/dune/gdt/operators/weighted-l2.cc b/python/dune/gdt/operators/weighted-l2.cc deleted file mode 100644 index d53fbf214fdbfa950c146f05c2dce4caf0ea5a31..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/weighted-l2.cc +++ /dev/null @@ -1,55 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2017) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <dune/xt/grid/layers.hh> - -# include <python/dune/gdt/operators/weighted-l2.hh> - - -PYBIND11_MODULE(__operators_weighted_l2, m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - using Dune::XT::Grid::Backends; - using Dune::XT::Grid::Layers; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - py::module::import("dune.gdt.__discretefunction"); - -# if HAVE_DUNE_ALUGRID - Dune::GDT::bindings::WeightedL2LocalizableProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::leaf, Backends::view>::bind(m); - Dune::GDT::bindings::WeightedL2LocalizableProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::level, Backends::view>::bind(m); - Dune::GDT::bindings::WeightedL2LocalizableProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::dd_subdomain, Backends::view>:: - bind(m); -# endif // HAVE_DUNE_ALUGRID - - add_initialization(m, "dune.gdt.operators.elliptic"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/operators/weighted-l2.hh b/python/dune/gdt/operators/weighted-l2.hh deleted file mode 100644 index 2da773f33cf64bd8367671780032e1a967a77082..0000000000000000000000000000000000000000 --- a/python/dune/gdt/operators/weighted-l2.hh +++ /dev/null @@ -1,143 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_OPERATORS_WEIGHTED_L2_BINDINGS_HH -#define PYTHON_DUNE_GDT_OPERATORS_WEIGHTED_L2_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/grid/dd/subdomains/grid.hh> -# include <dune/xt/grid/gridprovider/provider.hh> -# include <python/dune/xt/grid/layers.bindings.hh> -# include <dune/xt/functions/interfaces/grid-function.hh> - -# include <dune/gdt/spaces/interface.hh> - -# include <dune/gdt/operators/weighted-l2.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class G, XT::Grid::Layers layer_type, XT::Grid::Backends layer_backend> -class WeightedL2LocalizableProduct -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef typename XT::Grid::Layer<G, layer_type, layer_backend, XT::Grid::DD::SubdomainGrid<G>>::type GL; - - typedef XT::Grid::extract_entity_t<GL> E; - typedef typename G::ctype D; - static const size_t d = G::dimension; - typedef XT::Functions::GridFunctionInterface<E, D, d, double, 1, 1> F; - - template <bool is_dd_subdomain = (layer_type == XT::Grid::Layers::dd_subdomain) - || (layer_type == XT::Grid::Layers::dd_subdomain_boundary) - || (layer_type == XT::Grid::Layers::dd_subdomain_coupling), - bool anything = true> - struct helper - { - static void bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - m.def(std::string("apply_weighted_l2_product_" + XT::Grid::bindings::layer_name<layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<layer_backend>::value()) - .c_str(), - [](const F& weight, - const F& range, - const F& source, - const XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& grid, - const int level_or_subdomain, - const size_t over_integrate) { - return GDT::WeightedL2LocalizableProduct<F, GL, F, F>( - over_integrate, - weight, - grid.template layer<layer_type, layer_backend>(level_or_subdomain), - range, - source) - .apply2(); - }, - "weight"_a, - "range"_a, - "source"_a, - "grid"_a, - "level_or_subdomain"_a = -1, - "over_integrate"_a = 0); - } // ... bind(...) - }; // struct helper<true, ...> - - template <bool anything> - struct helper<false, anything> - { - static void bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - m.def(std::string("apply_weighted_l2_product_" + XT::Grid::bindings::layer_name<layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<layer_backend>::value()) - .c_str(), - [](const F& weight, - const F& range, - const F& source, - const XT::Grid::GridProvider<G>& grid, - const int level, - const size_t over_integrate) { - return GDT::WeightedL2LocalizableProduct<F, GL, F, F>( - over_integrate, weight, grid.template layer<layer_type, layer_backend>(level), range, source) - .apply2(); - }, - "weight"_a, - "range"_a, - "source"_a, - "grid"_a, - "level"_a = -1, - "over_integrate"_a = 0); - m.def(std::string("apply_weighted_l2_product_" + XT::Grid::bindings::layer_name<layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<layer_backend>::value()) - .c_str(), - [](const F& weight, - const F& range, - const F& source, - const XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& grid, - const int layer, - const size_t over_integrate) { - return GDT::WeightedL2LocalizableProduct<F, GL, F, F>( - over_integrate, weight, grid.template layer<layer_type, layer_backend>(layer), range, source) - .apply2(); - }, - "weight"_a, - "range"_a, - "source"_a, - "grid"_a, - "layer"_a = -1, - "over_integrate"_a = 0); - } // ... bind(...) - }; // struct helper<false, ...> - -public: - static void bind(pybind11::module& m) - { - helper<>::bind(m); - } -}; // class WeightedL2LocalizableProduct - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_OPERATORS_WEIGHTED_L2_BINDINGS_HH diff --git a/python/dune/gdt/playground/operators/ESV2007.cc b/python/dune/gdt/playground/operators/ESV2007.cc deleted file mode 100644 index 95caa37d448b3c92a737679d4e18e8460fccfcaa..0000000000000000000000000000000000000000 --- a/python/dune/gdt/playground/operators/ESV2007.cc +++ /dev/null @@ -1,525 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <memory> - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> -# include <dune/xt/common/numeric_cast.hh> -# include <dune/xt/grid/dd/subdomains/grid.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <python/dune/xt/grid/layers.bindings.hh> -# include <dune/xt/grid/gridprovider/provider.hh> -# include <dune/xt/grid/walker.hh> -# include <dune/xt/grid/type_traits.hh> - -# include <python/dune/gdt/playground/operators/ESV2007.hh> - -using namespace Dune; -using XT::Grid::Backends; -using XT::Grid::Layers; -namespace py = pybind11; - - -template <class G, Layers layer_type, Backends layer_backend, Layers interpolation_layer_type = layer_type> -struct NonconformityProduct -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef typename XT::Grid::Layer<G, layer_type, layer_backend, XT::Grid::DD::SubdomainGrid<G>>::type GL; - typedef - typename XT::Grid::Layer<G, interpolation_layer_type, Backends::view, XT::Grid::DD::SubdomainGrid<G>>::type IGL; - - typedef GDT::ESV2007::NonconformityProduct<GL, IGL> type; - typedef py::class_<type, XT::Grid::Walker<GL>> bound_type; - - template <bool is_same = (interpolation_layer_type == layer_type) && (layer_backend == Backends::view), - bool anything = true> - struct interpolation_layer_suffix - { - static std::string value() - { - return ""; - } - }; // struct interpolation_layer_suffix<true, ...> - - template <bool anything> - struct interpolation_layer_suffix<false, anything> - { - static std::string value() - { - return "_" + XT::Grid::bindings::layer_name<interpolation_layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<Backends::view>::value(); - } - }; // struct interpolation_layer_suffix<false, ...> - - static std::string class_name() - { - return "ESV2007_nonconformity_product"; - } - - static std::string layer_suffix() - { - return XT::Grid::bindings::layer_name<layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<layer_backend>::value() + interpolation_layer_suffix<>::value(); - } - - template <bool is_dd = (layer_type == Layers::dd_subdomain) || (layer_type == Layers::dd_subdomain_boundary) - || (layer_type == Layers::dd_subdomain_coupling) - || (layer_type == Layers::dd_subdomain_oversampled) - || (interpolation_layer_type == Layers::dd_subdomain) - || (interpolation_layer_type == Layers::dd_subdomain_boundary) - || (interpolation_layer_type == Layers::dd_subdomain_coupling) - || (interpolation_layer_type == Layers::dd_subdomain_oversampled), - bool anything = true> - struct factory_method - { - static void addbind(py::module& m) - { - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name() + "_" + layer_suffix()).c_str(), - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t layer_level_or_subdomain, - const ssize_t interpolation_layer_level_or_subdomain, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<IGL>>& interpolation_boundary_info, - const typename type::ScalarFunctionType& lambda, - const typename type::TensorFunctionType& kappa, - const typename type::ScalarFunctionType& u, - const typename type::ScalarFunctionType& v, - const ssize_t over_integrate) { - return new type(dd_grid_provider.template layer<layer_type, layer_backend>( - XT::Common::numeric_cast<int>(layer_level_or_subdomain)), - dd_grid_provider.template layer<interpolation_layer_type, Backends::view>( - XT::Common::numeric_cast<int>(interpolation_layer_level_or_subdomain)), - interpolation_boundary_info, - lambda, - kappa, - u, - v, - XT::Common::numeric_cast<size_t>(over_integrate)); - }, - "dd_grid_provider"_a, - "layer_level_or_subdomain"_a = -1, - "interpolation_layer_level_or_subdomain"_a = -1, - "interpolation_boundary_info"_a, - "lambda"_a, - "kappa"_a, - "u"_a, - "v"_a, - "over_integrate"_a = 2); - } - }; // struct factory_method<true, ...> - - template <bool anything> - struct factory_method<false, anything> - { - static void addbind(py::module& m) - { - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name() + "_" + layer_suffix()).c_str(), - [](XT::Grid::GridProvider<G>& grid_provider, - const ssize_t layer_level, - const ssize_t interpolation_layer_level, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<IGL>>& interpolation_boundary_info, - const typename type::ScalarFunctionType& lambda, - const typename type::TensorFunctionType& kappa, - const typename type::ScalarFunctionType& u, - const typename type::ScalarFunctionType& v, - const ssize_t over_integrate) { - return new type( - grid_provider.template layer<layer_type, layer_backend>(XT::Common::numeric_cast<int>(layer_level)), - grid_provider.template layer<interpolation_layer_type, Backends::view>( - XT::Common::numeric_cast<int>(interpolation_layer_level)), - interpolation_boundary_info, - lambda, - kappa, - u, - v, - XT::Common::numeric_cast<size_t>(over_integrate)); - }, - "grid_provider"_a, - "layer_level"_a = -1, - "interpolation_layer_level"_a = -1, - "interpolation_boundary_info"_a, - "lambda"_a, - "kappa"_a, - "u"_a, - "v"_a, - "over_integrate"_a = 2); - - factory_method<true>::addbind(m); - } - }; // struct factory_method<false, ...> - - static void bind(py::module& m) - { - using namespace pybind11::literals; - - try { // we might not be the first ones to add this type - bound_type c(m, - XT::Common::to_camel_case(class_name() + "_" + XT::Grid::bindings::grid_name<G>::value() + "_" - + layer_suffix()) - .c_str(), - "ESV2007::NonconformityProduct"); - c.def("apply2", [](type& self) { return self.apply2(); }); - c.def("result", [](type& self) { return self.apply2(); }); - } catch (std::runtime_error& ee) { - } - - factory_method<>::addbind(m); - } // ... bind(...) -}; // struct NonconformityProduct - - -template <class G, Layers layer_type, Backends layer_backend, Layers reconstruction_layer_type = layer_type> -struct ResidualProduct -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef typename XT::Grid::Layer<G, layer_type, layer_backend, XT::Grid::DD::SubdomainGrid<G>>::type GL; - typedef - typename XT::Grid::Layer<G, reconstruction_layer_type, Backends::view, XT::Grid::DD::SubdomainGrid<G>>::type RGL; - - typedef GDT::ESV2007::ResidualProduct<GL, RGL> type; - typedef py::class_<type, XT::Grid::Walker<GL>> bound_type; - - template <bool is_same = (reconstruction_layer_type == layer_type) && (layer_backend == Backends::view), - bool anything = true> - struct reconstruction_layer_suffix - { - static std::string value() - { - return ""; - } - }; // struct reconstruction_layer_suffix<true, ...> - - template <bool anything> - struct reconstruction_layer_suffix<false, anything> - { - static std::string value() - { - return "_" + XT::Grid::bindings::layer_name<reconstruction_layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<Backends::view>::value(); - } - }; // struct reconstruction_layer_suffix<false, ...> - - static std::string class_name() - { - return "ESV2007_residual_product"; - } - - static std::string layer_suffix() - { - return XT::Grid::bindings::layer_name<layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<layer_backend>::value() + reconstruction_layer_suffix<>::value(); - } - - template <bool is_dd = (layer_type == Layers::dd_subdomain) || (layer_type == Layers::dd_subdomain_boundary) - || (layer_type == Layers::dd_subdomain_coupling) - || (layer_type == Layers::dd_subdomain_oversampled) - || (reconstruction_layer_type == Layers::dd_subdomain) - || (reconstruction_layer_type == Layers::dd_subdomain_boundary) - || (reconstruction_layer_type == Layers::dd_subdomain_coupling) - || (reconstruction_layer_type == Layers::dd_subdomain_oversampled), - bool anything = true> - struct factory_method - { - static void addbind(py::module& m) - { - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name() + "_" + layer_suffix()).c_str(), - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t layer_level_or_subdomain, - const ssize_t reconstruction_layer_level_or_subdomain, - const typename type::ScalarFunctionType& lambda, - const typename type::TensorFunctionType& kappa, - const typename type::ScalarFunctionType& f, - const typename type::ScalarFunctionType& u, - const typename type::ScalarFunctionType& v, - const ssize_t over_integrate, - const double& poincare_constant) { - return new type(dd_grid_provider.template layer<layer_type, layer_backend>( - XT::Common::numeric_cast<int>(layer_level_or_subdomain)), - dd_grid_provider.template layer<reconstruction_layer_type, Backends::view>( - XT::Common::numeric_cast<int>(reconstruction_layer_level_or_subdomain)), - lambda, - kappa, - f, - u, - v, - poincare_constant, - XT::Common::numeric_cast<size_t>(over_integrate)); - }, - "dd_grid_provider"_a, - "layer_level"_a = -1, - "reconstruction_layer_level"_a = -1, - "lambda"_a, - "kappa"_a, - "f"_a, - "u"_a, - "v"_a, - "over_integrate"_a = 2, - "poincare_constant"_a = 1.0 / (M_PIl * M_PIl)); - } - }; // struct factory_method<true, ...> - - template <bool anything> - struct factory_method<false, anything> - { - static void addbind(py::module& m) - { - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name() + "_" + layer_suffix()).c_str(), - [](XT::Grid::GridProvider<G>& grid_provider, - const ssize_t layer_level, - const ssize_t reconstruction_layer_level, - const typename type::ScalarFunctionType& lambda, - const typename type::TensorFunctionType& kappa, - const typename type::ScalarFunctionType& f, - const typename type::ScalarFunctionType& u, - const typename type::ScalarFunctionType& v, - const ssize_t over_integrate, - const double& poincare_constant) { - return new type( - grid_provider.template layer<layer_type, layer_backend>(XT::Common::numeric_cast<int>(layer_level)), - grid_provider.template layer<reconstruction_layer_type, Backends::view>( - XT::Common::numeric_cast<int>(reconstruction_layer_level)), - lambda, - kappa, - f, - u, - v, - poincare_constant, - XT::Common::numeric_cast<size_t>(over_integrate)); - }, - "grid_provider"_a, - "layer_level"_a = -1, - "reconstruction_layer_level"_a = -1, - "lambda"_a, - "kappa"_a, - "f"_a, - "u"_a, - "v"_a, - "over_integrate"_a = 2, - "poincare_constant"_a = 1.0 / (M_PIl * M_PIl)); - - factory_method<true>::addbind(m); - } - }; // struct factory_method<false, ...> - - static void bind(py::module& m) - { - using namespace pybind11::literals; - - try { // we might not be the first ones to add this type - bound_type c(m, - XT::Common::to_camel_case(class_name() + "_" + XT::Grid::bindings::grid_name<G>::value() + "_" - + layer_suffix()) - .c_str(), - "ESV2007::ResidualProduct"); - c.def("apply2", [](type& self) { return self.apply2(); }); - c.def("result", [](type& self) { return self.apply2(); }); - } catch (std::runtime_error& ee) { - } - - factory_method<>::addbind(m); - } // ... bind(...) -}; // struct ResidualProduct - - -template <class G, Layers layer_type, Backends layer_backend, Layers reconstruction_layer_type = layer_type> -struct DiffusiveFluxProduct -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef typename XT::Grid::Layer<G, layer_type, layer_backend, XT::Grid::DD::SubdomainGrid<G>>::type GL; - typedef - typename XT::Grid::Layer<G, reconstruction_layer_type, Backends::view, XT::Grid::DD::SubdomainGrid<G>>::type RGL; - - typedef GDT::ESV2007::DiffusiveFluxProduct<GL, RGL> type; - typedef py::class_<type, XT::Grid::Walker<GL>> bound_type; - - template <bool is_same = (reconstruction_layer_type == layer_type) && (layer_backend == Backends::view), - bool anything = true> - struct reconstruction_layer_suffix - { - static std::string value() - { - return ""; - } - }; // struct reconstruction_layer_suffix<true, ...> - - template <bool anything> - struct reconstruction_layer_suffix<false, anything> - { - static std::string value() - { - return "_" + XT::Grid::bindings::layer_name<reconstruction_layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<Backends::view>::value(); - } - }; // struct reconstruction_layer_suffix<false, ...> - - static std::string class_name() - { - return "ESV2007_diffusive_flux_product"; - } - - static std::string layer_suffix() - { - return XT::Grid::bindings::layer_name<layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<layer_backend>::value() + reconstruction_layer_suffix<>::value(); - } - - template <bool is_dd = (layer_type == Layers::dd_subdomain) || (layer_type == Layers::dd_subdomain_boundary) - || (layer_type == Layers::dd_subdomain_coupling) - || (layer_type == Layers::dd_subdomain_oversampled) - || (reconstruction_layer_type == Layers::dd_subdomain) - || (reconstruction_layer_type == Layers::dd_subdomain_boundary) - || (reconstruction_layer_type == Layers::dd_subdomain_coupling) - || (reconstruction_layer_type == Layers::dd_subdomain_oversampled), - bool anything = true> - struct factory_method - { - static void addbind(py::module& m) - { - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name() + "_" + layer_suffix()).c_str(), - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t layer_level_or_subdomain, - const ssize_t reconstruction_layer_level_or_subdomain, - const typename type::ScalarFunctionType& lambda, - const typename type::TensorFunctionType& kappa, - const typename type::ScalarFunctionType& u, - const typename type::ScalarFunctionType& v, - const ssize_t over_integrate) { - return new type(dd_grid_provider.template layer<layer_type, layer_backend>( - XT::Common::numeric_cast<int>(layer_level_or_subdomain)), - dd_grid_provider.template layer<reconstruction_layer_type, Backends::view>( - XT::Common::numeric_cast<int>(reconstruction_layer_level_or_subdomain)), - lambda, - kappa, - u, - v, - XT::Common::numeric_cast<size_t>(over_integrate)); - }, - "dd_grid_provider"_a, - "layer_level"_a = -1, - "reconstruction_layer_level"_a = -1, - "lambda"_a, - "kappa"_a, - "u"_a, - "v"_a, - "over_integrate"_a = 2); - } - }; // struct factory_method<true, ...> - - template <bool anything> - struct factory_method<false, anything> - { - static void addbind(py::module& m) - { - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name() + "_" + layer_suffix()).c_str(), - [](XT::Grid::GridProvider<G>& grid_provider, - const ssize_t layer_level, - const ssize_t reconstruction_layer_level, - const typename type::ScalarFunctionType& lambda, - const typename type::TensorFunctionType& kappa, - const typename type::ScalarFunctionType& u, - const typename type::ScalarFunctionType& v, - const ssize_t over_integrate) { - return new type( - grid_provider.template layer<layer_type, layer_backend>(XT::Common::numeric_cast<int>(layer_level)), - grid_provider.template layer<reconstruction_layer_type, Backends::view>( - XT::Common::numeric_cast<int>(reconstruction_layer_level)), - lambda, - kappa, - u, - v, - XT::Common::numeric_cast<size_t>(over_integrate)); - }, - "grid_provider"_a, - "layer_level"_a = -1, - "reconstruction_layer_level"_a = -1, - "lambda"_a, - "kappa"_a, - "u"_a, - "v"_a, - "over_integrate"_a = 2); - - factory_method<true>::addbind(m); - } - }; // struct factory_method<false, ...> - - static void bind(py::module& m) - { - using namespace pybind11::literals; - - try { // we might not be the first ones to add this type - bound_type c(m, - XT::Common::to_camel_case(class_name() + "_" + XT::Grid::bindings::grid_name<G>::value() + "_" - + layer_suffix()) - .c_str(), - "ESV2007::DiffusiveFluxProduct"); - c.def("apply2", [](type& self) { return self.apply2(); }); - c.def("result", [](type& self) { return self.apply2(); }); - } catch (std::runtime_error& ee) { - } - - factory_method<>::addbind(m); - } // ... bind(...) -}; // struct DiffusiveFluxProduct - - -PYBIND11_MODULE(__operators_ESV2007, m) -{ - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - -# if HAVE_DUNE_ALUGRID - NonconformityProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::leaf, Backends::view>::bind(m); - NonconformityProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::dd_subdomain, Backends::view>::bind(m); - NonconformityProduct<ALU_2D_SIMPLEX_CONFORMING, - Layers::dd_subdomain, - Backends::view, - Layers::dd_subdomain_oversampled>::bind(m); - ResidualProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::leaf, Backends::view>::bind(m); - ResidualProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::leaf, Backends::view>::bind(m); - // on a dd_subdomain_oversampled grid view is broken, if based on - // a 2d simplex alugrid. - ResidualProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::dd_subdomain, Backends::view, Layers::leaf>::bind(m); - DiffusiveFluxProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::leaf, Backends::view>::bind(m); - DiffusiveFluxProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::leaf, Backends::view>::bind(m); - // s.a. - DiffusiveFluxProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::dd_subdomain, Backends::view, Layers::leaf>::bind(m); -# endif - - add_initialization(m, "dune.gdt.operators.elliptic"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/playground/operators/ESV2007.hh b/python/dune/gdt/playground/operators/ESV2007.hh deleted file mode 100644 index cc6ed6446d873e3983ce688fa294f19146c00b29..0000000000000000000000000000000000000000 --- a/python/dune/gdt/playground/operators/ESV2007.hh +++ /dev/null @@ -1,389 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef DUNE_GDT_PLAYGROUND_OPERATORS_RS2017_HH -#define DUNE_GDT_PLAYGROUND_OPERATORS_RS2017_HH - -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/common/typetraits.hh> - -# include <dune/xt/common/fmatrix.hh> -# include <dune/xt/la/eigen-solver.hh> -# include <dune/xt/grid/boundaryinfo/interfaces.hh> -# include <dune/xt/grid/entity.hh> -# include <dune/xt/grid/type_traits.hh> -# include <dune/xt/functions/derived.hh> -# include <dune/xt/functions/interfaces/grid-function.hh> - -# include <dune/gdt/discretefunction/default.hh> -# include <dune/gdt/local/operators/integrals.hh> -# include <dune/gdt/local/integrands/lambda.hh> -# include <dune/gdt/operators/base.hh> -# include <dune/gdt/operators/fluxreconstruction.hh> -# include <dune/gdt/operators/oswaldinterpolation.hh> -# include <dune/gdt/spaces/dg/default.hh> -# include <dune/gdt/spaces/rt/default.hh> - -namespace Dune { -namespace GDT { -namespace ESV2007 { - - -template <class ProductGridLayer, class InterpolationGridLayerType> -class NonconformityProduct - : public LocalizableProductBase<ProductGridLayer, - XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<ProductGridLayer>, - typename ProductGridLayer::ctype, - ProductGridLayer::dimension, - double, - 1>> -{ - static_assert(XT::Grid::is_layer<ProductGridLayer>::value, ""); - static_assert(XT::Grid::is_layer<InterpolationGridLayerType>::value, ""); - typedef XT::Grid::extract_entity_t<ProductGridLayer> E; - static_assert(std::is_same<XT::Grid::extract_entity_t<InterpolationGridLayerType>, E>::value, ""); - typedef typename ProductGridLayer::ctype D; - static const constexpr size_t d = ProductGridLayer::dimension; - typedef double R; - -public: - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunctionType; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> TensorFunctionType; - -private: - typedef LocalizableProductBase<ProductGridLayer, ScalarFunctionType> BaseType; - typedef NonconformityProduct<ProductGridLayer, InterpolationGridLayerType> ThisType; - typedef LocalVolumeIntegralOperator<LocalLambdaBinaryVolumeIntegrand<E>, - typename ScalarFunctionType::LocalfunctionType> - LocalProductType; - typedef DiscontinuousLagrangeSpace<InterpolationGridLayerType, 1, R> DgSpaceType; - typedef DiscreteFunction<DgSpaceType> DiscreteFunctionType; - -public: - using typename BaseType::GridLayerType; - - NonconformityProduct(GridLayerType product_grid_layer, - InterpolationGridLayerType interpolation_grid_layer, - const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<InterpolationGridLayerType>>& - interpolation_boundary_info, - const ScalarFunctionType& lambda, - const TensorFunctionType& kappa, - const ScalarFunctionType& u, - const ScalarFunctionType& v, - const size_t over_integrate = 2) - : BaseType(product_grid_layer, u, v) - , interpolation_grid_layer_(interpolation_grid_layer) - , lambda_(lambda) - , kappa_(kappa) - , dg_space_(interpolation_grid_layer_) - , interpolated_u_(dg_space_) - , interpolated_v_(dg_space_) - , over_integrate_(over_integrate) - , local_product_( - // the order lambda - [&](const auto& local_u, const auto& local_v) { - const auto& entity = local_u.entity(); - const auto local_lambda = lambda_.local_function(entity); - const auto local_kappa = kappa_.local_function(entity); - return local_lambda->order() + local_kappa->order() - + size_t(std::max(ssize_t(local_u.order()) - 1, ssize_t(0)) - + std::max(ssize_t(local_v.order()) - 1, ssize_t(0))) - + over_integrate_; - }, - // the evaluate lambda - [&](const auto& local_u, const auto& local_v, const auto& local_point, auto& ret) { - const auto& entity = local_u.entity(); - XT::Common::FieldMatrix<R, d, d> diffusion = kappa_.local_function(entity)->evaluate(local_point); - diffusion *= lambda_.local_function(entity)->evaluate(local_point); - const auto grad_u = local_u.jacobian(local_point).at(0)[0]; - const auto grad_interpolated_u = interpolated_u_.local_function(entity)->jacobian(local_point)[0]; - const auto grad_v = local_v.jacobian(local_point).at(0)[0]; - const auto grad_interpolated_v = interpolated_v_.local_function(entity)->jacobian(local_point)[0]; - ret[0][0] = (diffusion * (grad_u - grad_interpolated_u)) * (grad_v - grad_interpolated_v); - }) - { - OswaldInterpolationOperator<InterpolationGridLayerType> oswald_interpolation(interpolation_grid_layer_, - interpolation_boundary_info); - oswald_interpolation.apply(this->range(), interpolated_u_); - oswald_interpolation.apply(this->source(), interpolated_v_); - this->append(local_product_); - } - - NonconformityProduct(const ThisType&) = delete; - NonconformityProduct(ThisType&&) = delete; - -private: - const InterpolationGridLayerType interpolation_grid_layer_; - const ScalarFunctionType& lambda_; - const TensorFunctionType& kappa_; - const DgSpaceType dg_space_; - DiscreteFunctionType interpolated_u_; - DiscreteFunctionType interpolated_v_; - const size_t over_integrate_; - const LocalProductType local_product_; -}; // class NonconformityProduct - - -namespace internal { - - -template <class ProductGridLayer, class ReconstructionGridLayer> -class ResidualProductBase -{ - static_assert(XT::Grid::is_layer<ProductGridLayer>::value, ""); - static_assert(XT::Grid::is_layer<ReconstructionGridLayer>::value, ""); - -protected: - typedef XT::Grid::extract_entity_t<ProductGridLayer> E; - typedef typename ProductGridLayer::ctype D; - static const constexpr size_t d = ProductGridLayer::dimension; - typedef double R; - -private: - static_assert(std::is_same<XT::Grid::extract_entity_t<ReconstructionGridLayer>, E>::value, ""); - typedef ResidualProductBase<ProductGridLayer, ReconstructionGridLayer> ThisType; - -public: - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunctionType; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> TensorFunctionType; - -private: - typedef RaviartThomasSpace<ReconstructionGridLayer, 0, R> RtSpaceType; - typedef DiscreteFunction<RtSpaceType> FluxReconstructionType; - typedef XT::Functions::DivergenceFunction<FluxReconstructionType> DivergenceOfFluxReconstructionType; - typedef typename ScalarFunctionType::DifferenceType DifferenceType; - -public: - ResidualProductBase(ReconstructionGridLayer reconstruction_grid_layer, - const ScalarFunctionType& lambda, - const TensorFunctionType& kappa, - const ScalarFunctionType& f, - const ScalarFunctionType& u, - const ScalarFunctionType& v) - : f_(f) - , rt_space_(reconstruction_grid_layer) - , reconstructed_u_(rt_space_) - , reconstructed_v_(rt_space_) - , divergence_of_reconstructed_u_(reconstructed_u_) - , divergence_of_reconstructed_v_(reconstructed_v_) - , f_minus_divergence_of_reconstructed_u_(f_ - divergence_of_reconstructed_u_) - , f_minus_divergence_of_reconstructed_v_(f_ - divergence_of_reconstructed_v_) - { - DiffusiveFluxReconstructionOperator<ReconstructionGridLayer, ScalarFunctionType, TensorFunctionType> - flux_reconstruction(reconstruction_grid_layer, lambda, kappa); - flux_reconstruction.apply(u, reconstructed_u_); - flux_reconstruction.apply(v, reconstructed_v_); - } - - ResidualProductBase(const ThisType&) = delete; - ResidualProductBase(ThisType&&) = delete; - -protected: - const ScalarFunctionType& f_; - const RtSpaceType rt_space_; - FluxReconstructionType reconstructed_u_; - FluxReconstructionType reconstructed_v_; - const DivergenceOfFluxReconstructionType divergence_of_reconstructed_u_; - const DivergenceOfFluxReconstructionType divergence_of_reconstructed_v_; - const DifferenceType f_minus_divergence_of_reconstructed_u_; - const DifferenceType f_minus_divergence_of_reconstructed_v_; -}; // class ResidualProductBase - - -} // namespace internal - - -template <class ProductGridLayer, class ReconstructionGridLayer> -class ResidualProduct - : internal::ResidualProductBase<ProductGridLayer, ReconstructionGridLayer>, - public LocalizableProductBase<ProductGridLayer, - XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<ProductGridLayer>, - typename ProductGridLayer::ctype, - ProductGridLayer::dimension, - double, - 1>> -{ - typedef internal::ResidualProductBase<ProductGridLayer, ReconstructionGridLayer> ResidualProductBaseType; - typedef LocalizableProductBase<ProductGridLayer, - XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<ProductGridLayer>, - typename ProductGridLayer::ctype, - ProductGridLayer::dimension, - double, - 1>> - LocalizableProductBaseType; - -public: - using typename ResidualProductBaseType::ScalarFunctionType; - using typename ResidualProductBaseType::TensorFunctionType; - -private: - using typename ResidualProductBaseType::E; - using typename ResidualProductBaseType::R; - typedef LocalVolumeIntegralOperator<LocalLambdaBinaryVolumeIntegrand<E>, - typename ScalarFunctionType::LocalfunctionType> - LocalProductType; - -public: - ResidualProduct(ProductGridLayer product_grid_layer, - ReconstructionGridLayer reconstruction_grid_layer, - const ScalarFunctionType& lambda, - const TensorFunctionType& kappa, - const ScalarFunctionType& f, - const ScalarFunctionType& u, - const ScalarFunctionType& v, - const double& poincare_constant = 1.0 / (M_PIl * M_PIl), - const size_t over_integrate = 2) - : ResidualProductBaseType(reconstruction_grid_layer, lambda, kappa, f, u, v) - , LocalizableProductBaseType(product_grid_layer, - this->f_minus_divergence_of_reconstructed_u_, - this->f_minus_divergence_of_reconstructed_v_) - , lambda_(lambda) - , kappa_(kappa) - , poincare_constant_(poincare_constant) - , over_integrate_(over_integrate) - , local_product_( - // the order lambda - [&](const auto& local_f_minus_divergence_of_reconstructed_u, - const auto& local_f_minus_divergence_of_reconstructed_v) { - return local_f_minus_divergence_of_reconstructed_u.order() - + local_f_minus_divergence_of_reconstructed_v.order() + over_integrate_; - }, - // the evaluate lambda - [&](const auto& local_f_minus_divergence_of_reconstructed_u, - const auto& local_f_minus_divergence_of_reconstructed_v, - const auto& local_point, - auto& ret) { - const auto& entity = local_f_minus_divergence_of_reconstructed_u.entity(); - // we need the min_ev for this entity, so we just evaluate in one point - const auto center = entity.geometry().local(entity.geometry().center()); - auto diffusion = kappa_.local_function(entity)->evaluate(center); - diffusion *= lambda_.local_function(entity)->evaluate(center); - const auto min_ev = XT::LA::make_eigen_solver( - diffusion, XT::Common::Configuration{{"assert_positive_eigenvalues"}, {1e-15}}) - .min_eigenvalues(1) - .at(0); - const auto h = XT::Grid::entity_diameter(entity); - ret[0][0] = (poincare_constant_ / min_ev) * h * h - * local_f_minus_divergence_of_reconstructed_u.evaluate(local_point).at(0)[0] - * local_f_minus_divergence_of_reconstructed_v.evaluate(local_point).at(0)[0]; - }) - { - this->append(local_product_); - } - -private: - const ScalarFunctionType& lambda_; - const TensorFunctionType& kappa_; - const double poincare_constant_; - const size_t over_integrate_; - const LocalProductType local_product_; -}; // class ResidualProduct - - -template <class ProductGridLayer, class ReconstructionGridLayer> -class DiffusiveFluxProduct - : public LocalizableProductBase<ProductGridLayer, - XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<ProductGridLayer>, - typename ProductGridLayer::ctype, - ProductGridLayer::dimension, - double, - 1>> -{ - static_assert(XT::Grid::is_layer<ProductGridLayer>::value, ""); - static_assert(XT::Grid::is_layer<ReconstructionGridLayer>::value, ""); - typedef XT::Grid::extract_entity_t<ProductGridLayer> E; - static_assert(std::is_same<XT::Grid::extract_entity_t<ReconstructionGridLayer>, E>::value, ""); - typedef typename ProductGridLayer::ctype D; - static const constexpr size_t d = ProductGridLayer::dimension; - typedef double R; - typedef DiffusiveFluxProduct<ProductGridLayer, ReconstructionGridLayer> ThisType; - -public: - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunctionType; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> TensorFunctionType; - -private: - typedef RaviartThomasSpace<ReconstructionGridLayer, 0, R> RtSpaceType; - typedef DiscreteFunction<RtSpaceType> FluxReconstructionType; - typedef LocalizableProductBase<ProductGridLayer, XT::Functions::GridFunctionInterface<E, D, d, R, 1>> BaseType; - typedef LocalVolumeIntegralOperator<LocalLambdaBinaryVolumeIntegrand<E>, - typename ScalarFunctionType::LocalfunctionType> - LocalProductType; - -public: - DiffusiveFluxProduct(ProductGridLayer product_grid_layer, - ReconstructionGridLayer reconstruction_grid_layer, - const ScalarFunctionType& lambda, - const TensorFunctionType& kappa, - const ScalarFunctionType& u, - const ScalarFunctionType& v, - const size_t over_integrate = 2) - : BaseType(product_grid_layer, u, v) - , lambda_(lambda) - , kappa_(kappa) - , rt_space_(reconstruction_grid_layer) - , reconstructed_u_(rt_space_) - , reconstructed_v_(rt_space_) - , over_integrate_(over_integrate) - , local_product_( - // the order lambda - [&](const auto& local_u, const auto& local_v) { - const auto& entity = local_u.entity(); - const size_t diffusion_order = - lambda_.local_function(entity)->order() + kappa_.local_function(entity)->order(); - return 3 * diffusion_order + size_t(std::max(ssize_t(local_u.order()) - 1, ssize_t(0))) - + size_t(std::max(ssize_t(local_v.order()) - 1, ssize_t(0))) + over_integrate_; - }, - // the evaluate lambda - [&](const auto& local_u, const auto& local_v, const auto& local_point, auto& ret) { - const auto& entity = local_u.entity(); - XT::Common::FieldMatrix<R, d, d> diffusion = kappa_.local_function(entity)->evaluate(local_point); - diffusion *= lambda_.local_function(entity)->evaluate(local_point); - XT::Common::FieldMatrix<R, d, d> one_over_diffusion = diffusion; - one_over_diffusion.invert(); // there is no documented way to assert that the inversion was successfull - const auto grad_u = local_u.jacobian(local_point).at(0)[0]; - const auto grad_v = local_v.jacobian(local_point).at(0)[0]; - const auto val_reconstructed_u = reconstructed_u_.local_function(entity)->evaluate(local_point); - const auto val_reconstructed_v = reconstructed_v_.local_function(entity)->evaluate(local_point); - ret[0][0] = (one_over_diffusion * ((diffusion * grad_u) + val_reconstructed_u)) // clang-format off - * ((diffusion * grad_v) + val_reconstructed_v); // clang-format on - }) - { - DiffusiveFluxReconstructionOperator<ReconstructionGridLayer, ScalarFunctionType, TensorFunctionType> - flux_reconstruction(reconstruction_grid_layer, lambda, kappa); - flux_reconstruction.apply(u, reconstructed_u_); - flux_reconstruction.apply(v, reconstructed_v_); - this->append(local_product_); - } - - DiffusiveFluxProduct(const ThisType&) = delete; - DiffusiveFluxProduct(ThisType&&) = delete; - -private: - const ScalarFunctionType& lambda_; - const TensorFunctionType& kappa_; - const RtSpaceType rt_space_; - FluxReconstructionType reconstructed_u_; - FluxReconstructionType reconstructed_v_; - const size_t over_integrate_; - const LocalProductType local_product_; -}; // class DiffusiveFluxProduct - - -} // namespace ESV2007 -} // namespace GDT -} // namespace Dune - -#endif // 0 - -#endif // DUNE_GDT_PLAYGROUND_OPERATORS_RS2017_HH diff --git a/python/dune/gdt/playground/operators/OS2015.cc b/python/dune/gdt/playground/operators/OS2015.cc deleted file mode 100644 index 4f2be0ec68f68c9918466b51e0c916cae0056d39..0000000000000000000000000000000000000000 --- a/python/dune/gdt/playground/operators/OS2015.cc +++ /dev/null @@ -1,379 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <memory> - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> -# include <dune/xt/common/numeric_cast.hh> -# include <dune/xt/grid/dd/subdomains/grid.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <python/dune/xt/grid/layers.bindings.hh> -# include <dune/xt/grid/gridprovider/provider.hh> -# include <dune/xt/grid/walker.hh> -# include <dune/xt/grid/type_traits.hh> - -# include <python/dune/gdt/playground/operators/OS2015.hh> - -using namespace Dune; -using XT::Grid::Backends; -using XT::Grid::Layers; -namespace py = pybind11; - - -template <class G, Layers layer_type, Backends layer_backend, Layers reconstruction_layer_type = layer_type> -struct ResidualProduct -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef typename XT::Grid::Layer<G, layer_type, layer_backend, XT::Grid::DD::SubdomainGrid<G>>::type GL; - typedef - typename XT::Grid::Layer<G, reconstruction_layer_type, Backends::view, XT::Grid::DD::SubdomainGrid<G>>::type RGL; - - typedef GDT::OS2015::ResidualProduct<GL, RGL> type; - typedef py::class_<type, XT::Grid::Walker<GL>> bound_type; - - template <bool is_same = (reconstruction_layer_type == layer_type) && (layer_backend == Backends::view), - bool anything = true> - struct reconstruction_layer_suffix - { - static std::string value() - { - return ""; - } - }; // struct reconstruction_layer_suffix<true, ...> - - template <bool anything> - struct reconstruction_layer_suffix<false, anything> - { - static std::string value() - { - return "_" + XT::Grid::bindings::layer_name<reconstruction_layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<Backends::view>::value(); - } - }; // struct reconstruction_layer_suffix<false, ...> - - static std::string class_name() - { - return "OS2015_residual_product"; - } - - static std::string layer_suffix() - { - return XT::Grid::bindings::layer_name<layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<layer_backend>::value() + reconstruction_layer_suffix<>::value(); - } - - template <bool is_dd = (layer_type == Layers::dd_subdomain) || (layer_type == Layers::dd_subdomain_boundary) - || (layer_type == Layers::dd_subdomain_coupling) - || (layer_type == Layers::dd_subdomain_oversampled) - || (reconstruction_layer_type == Layers::dd_subdomain) - || (reconstruction_layer_type == Layers::dd_subdomain_boundary) - || (reconstruction_layer_type == Layers::dd_subdomain_coupling) - || (reconstruction_layer_type == Layers::dd_subdomain_oversampled), - bool anything = true> - struct factory_method - { - static void addbind(py::module& m) - { - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name() + "_" + layer_suffix()).c_str(), - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t layer_level_or_subdomain, - const ssize_t reconstruction_layer_level_or_subdomain, - const typename type::ScalarFunctionType& lambda, - const typename type::ScalarFunctionType& lambda_hat, - const typename type::TensorFunctionType& kappa, - const typename type::ScalarFunctionType& f, - const typename type::ScalarFunctionType& u, - const typename type::ScalarFunctionType& v, - const ssize_t over_integrate, - const double& poincare_constant) { - return new type(dd_grid_provider.template layer<layer_type, layer_backend>( - XT::Common::numeric_cast<int>(layer_level_or_subdomain)), - dd_grid_provider.template layer<reconstruction_layer_type, Backends::view>( - XT::Common::numeric_cast<int>(reconstruction_layer_level_or_subdomain)), - lambda, - lambda_hat, - kappa, - f, - u, - v, - poincare_constant, - XT::Common::numeric_cast<size_t>(over_integrate)); - }, - "dd_grid_provider"_a, - "layer_level"_a = -1, - "reconstruction_layer_level"_a = -1, - "lambda"_a, - "lambda_hat"_a, - "kappa"_a, - "f"_a, - "u"_a, - "v"_a, - "over_integrate"_a = 2, - "poincare_constant"_a = 1.0 / (M_PIl * M_PIl)); - } - }; // struct factory_method<true, ...> - - template <bool anything> - struct factory_method<false, anything> - { - static void addbind(py::module& m) - { - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name() + "_" + layer_suffix()).c_str(), - [](XT::Grid::GridProvider<G>& grid_provider, - const ssize_t layer_level, - const ssize_t reconstruction_layer_level, - const typename type::ScalarFunctionType& lambda, - const typename type::ScalarFunctionType& lambda_hat, - const typename type::TensorFunctionType& kappa, - const typename type::ScalarFunctionType& f, - const typename type::ScalarFunctionType& u, - const typename type::ScalarFunctionType& v, - const ssize_t over_integrate, - const double& poincare_constant) { - return new type( - grid_provider.template layer<layer_type, layer_backend>(XT::Common::numeric_cast<int>(layer_level)), - grid_provider.template layer<reconstruction_layer_type, Backends::view>( - XT::Common::numeric_cast<int>(reconstruction_layer_level)), - lambda, - lambda_hat, - kappa, - f, - u, - v, - poincare_constant, - XT::Common::numeric_cast<size_t>(over_integrate)); - }, - "grid_provider"_a, - "layer_level"_a = -1, - "reconstruction_layer_level"_a = -1, - "lambda"_a, - "lambda_hat"_a, - "kappa"_a, - "f"_a, - "u"_a, - "v"_a, - "over_integrate"_a = 2, - "poincare_constant"_a = 1.0 / (M_PIl * M_PIl)); - - factory_method<true>::addbind(m); - } - }; // struct factory_method<false, ...> - - static void bind(py::module& m) - { - using namespace pybind11::literals; - - try { // we might not be the first ones to add this type - bound_type c(m, - XT::Common::to_camel_case(class_name() + "_" + XT::Grid::bindings::grid_name<G>::value() + "_" - + layer_suffix()) - .c_str(), - "OS2015::ResidualProduct"); - c.def("apply2", [](type& self) { return self.apply2(); }); - c.def("result", [](type& self) { return self.apply2(); }); - } catch (std::runtime_error& ee) { - } - - factory_method<>::addbind(m); - } // ... bind(...) -}; // struct ResidualProduct - - -template <class G, Layers layer_type, Backends layer_backend, Layers reconstruction_layer_type = layer_type> -struct DiffusiveFluxProduct -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef typename XT::Grid::Layer<G, layer_type, layer_backend, XT::Grid::DD::SubdomainGrid<G>>::type GL; - typedef - typename XT::Grid::Layer<G, reconstruction_layer_type, Backends::view, XT::Grid::DD::SubdomainGrid<G>>::type RGL; - - typedef GDT::OS2015::DiffusiveFluxProduct<GL, RGL> type; - typedef py::class_<type, XT::Grid::Walker<GL>> bound_type; - - template <bool is_same = (reconstruction_layer_type == layer_type) && (layer_backend == Backends::view), - bool anything = true> - struct reconstruction_layer_suffix - { - static std::string value() - { - return ""; - } - }; // struct reconstruction_layer_suffix<true, ...> - - template <bool anything> - struct reconstruction_layer_suffix<false, anything> - { - static std::string value() - { - return "_" + XT::Grid::bindings::layer_name<reconstruction_layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<Backends::view>::value(); - } - }; // struct reconstruction_layer_suffix<false, ...> - - static std::string class_name() - { - return "OS2015_diffusive_flux_product"; - } - - static std::string layer_suffix() - { - return XT::Grid::bindings::layer_name<layer_type>::value() + "_" - + XT::Grid::bindings::backend_name<layer_backend>::value() + reconstruction_layer_suffix<>::value(); - } - - template <bool is_dd = (layer_type == Layers::dd_subdomain) || (layer_type == Layers::dd_subdomain_boundary) - || (layer_type == Layers::dd_subdomain_coupling) - || (layer_type == Layers::dd_subdomain_oversampled) - || (reconstruction_layer_type == Layers::dd_subdomain) - || (reconstruction_layer_type == Layers::dd_subdomain_boundary) - || (reconstruction_layer_type == Layers::dd_subdomain_coupling) - || (reconstruction_layer_type == Layers::dd_subdomain_oversampled), - bool anything = true> - struct factory_method - { - static void addbind(py::module& m) - { - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name() + "_" + layer_suffix()).c_str(), - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t layer_level_or_subdomain, - const ssize_t reconstruction_layer_level_or_subdomain, - const typename type::ScalarFunctionType& lambda, - const typename type::ScalarFunctionType& lambda_hat, - const typename type::TensorFunctionType& kappa, - const typename type::ScalarFunctionType& u, - const typename type::ScalarFunctionType& v, - const ssize_t over_integrate) { - return new type(dd_grid_provider.template layer<layer_type, layer_backend>( - XT::Common::numeric_cast<int>(layer_level_or_subdomain)), - dd_grid_provider.template layer<reconstruction_layer_type, Backends::view>( - XT::Common::numeric_cast<int>(reconstruction_layer_level_or_subdomain)), - lambda, - lambda_hat, - kappa, - u, - v, - XT::Common::numeric_cast<size_t>(over_integrate)); - }, - "dd_grid_provider"_a, - "layer_level"_a = -1, - "reconstruction_layer_level"_a = -1, - "lambda"_a, - "lambda_hat"_a, - "kappa"_a, - "u"_a, - "v"_a, - "over_integrate"_a = 2); - } - }; // struct factory_method<true, ...> - - template <bool anything> - struct factory_method<false, anything> - { - static void addbind(py::module& m) - { - using namespace pybind11::literals; - - m.def(std::string("make_" + class_name() + "_" + layer_suffix()).c_str(), - [](XT::Grid::GridProvider<G>& grid_provider, - const ssize_t layer_level, - const ssize_t reconstruction_layer_level, - const typename type::ScalarFunctionType& lambda, - const typename type::ScalarFunctionType& lambda_hat, - const typename type::TensorFunctionType& kappa, - const typename type::ScalarFunctionType& u, - const typename type::ScalarFunctionType& v, - const ssize_t over_integrate) { - return new type( - grid_provider.template layer<layer_type, layer_backend>(XT::Common::numeric_cast<int>(layer_level)), - grid_provider.template layer<reconstruction_layer_type, Backends::view>( - XT::Common::numeric_cast<int>(reconstruction_layer_level)), - lambda, - lambda_hat, - kappa, - u, - v, - XT::Common::numeric_cast<size_t>(over_integrate)); - }, - "grid_provider"_a, - "layer_level"_a = -1, - "reconstruction_layer_level"_a = -1, - "lambda"_a, - "lambda_hat"_a, - "kappa"_a, - "u"_a, - "v"_a, - "over_integrate"_a = 2); - - factory_method<true>::addbind(m); - } - }; // struct factory_method<false, ...> - - static void bind(py::module& m) - { - using namespace pybind11::literals; - - try { // we might not be the first ones to add this type - bound_type c(m, - XT::Common::to_camel_case(class_name() + "_" + XT::Grid::bindings::grid_name<G>::value() + "_" - + layer_suffix()) - .c_str(), - "OS2015::DiffusiveFluxProduct"); - c.def("apply2", [](type& self) { return self.apply2(); }); - c.def("result", [](type& self) { return self.apply2(); }); - } catch (std::runtime_error& ee) { - } - - factory_method<>::addbind(m); - } // ... bind(...) -}; // struct DiffusiveFluxProduct - - -PYBIND11_MODULE(__operators_OS2015, m) -{ - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - -# if HAVE_DUNE_ALUGRID - // This is not efficient: we reconstruct on the whole leaf instead of only the neighborhood, but the rt space - // on a dd_subdomain_oversampled grid view (which is a wrapped part) is broken, if based on - // a 2d simplex alugrid. - ResidualProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::dd_subdomain, Backends::view, Layers::leaf>::bind(m); - DiffusiveFluxProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::leaf, Backends::view>::bind(m); - DiffusiveFluxProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::leaf, Backends::view>::bind(m); - // s.a. - DiffusiveFluxProduct<ALU_2D_SIMPLEX_CONFORMING, Layers::dd_subdomain, Backends::view, Layers::leaf>::bind(m); -# endif - - add_initialization(m, "dune.gdt.operators.elliptic"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/playground/operators/OS2015.hh b/python/dune/gdt/playground/operators/OS2015.hh deleted file mode 100644 index b9b368337af7c5fdac5c897d7bbe1f48dfe2e93a..0000000000000000000000000000000000000000 --- a/python/dune/gdt/playground/operators/OS2015.hh +++ /dev/null @@ -1,351 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef DUNE_GDT_PLAYGROUND_OPERATORS_OS2015_HH -#define DUNE_GDT_PLAYGROUND_OPERATORS_OS2015_HH - -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/common/typetraits.hh> - -# include <dune/geometry/quadraturerules.hh> -# include <dune/geometry/referenceelements.hh> - -# include <dune/xt/common/fmatrix.hh> -# include <dune/xt/la/container/eigen.hh> -# include <dune/xt/la/eigen-solver.hh> -# include <dune/xt/grid/boundaryinfo/interfaces.hh> -# include <dune/xt/grid/entity.hh> -# include <dune/xt/grid/type_traits.hh> -# include <dune/xt/functions/derived.hh> -# include <dune/xt/functions/interfaces/grid-function.hh> - -# include <dune/gdt/discretefunction/default.hh> -# include <dune/gdt/local/operators/integrals.hh> -# include <dune/gdt/local/integrands/lambda.hh> -# include <dune/gdt/operators/base.hh> -# include <dune/gdt/operators/fluxreconstruction.hh> -# include <dune/gdt/spaces/rt/default.hh> - -namespace Dune { -namespace GDT { -namespace OS2015 { -namespace internal { - - -template <class ProductGridLayer, class ReconstructionGridLayer> -class ResidualProductBase -{ - static_assert(XT::Grid::is_layer<ProductGridLayer>::value, ""); - static_assert(XT::Grid::is_layer<ReconstructionGridLayer>::value, ""); - -protected: - typedef XT::Grid::extract_entity_t<ProductGridLayer> E; - typedef typename ProductGridLayer::ctype D; - static const constexpr size_t d = ProductGridLayer::dimension; - typedef double R; - -private: - static_assert(std::is_same<XT::Grid::extract_entity_t<ReconstructionGridLayer>, E>::value, ""); - typedef ResidualProductBase<ProductGridLayer, ReconstructionGridLayer> ThisType; - -public: - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunctionType; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> TensorFunctionType; - -private: - typedef RaviartThomasSpace<ReconstructionGridLayer, 0, R> RtSpaceType; - typedef DiscreteFunction<RtSpaceType> FluxReconstructionType; - typedef XT::Functions::DivergenceFunction<FluxReconstructionType> DivergenceOfFluxReconstructionType; - typedef typename ScalarFunctionType::DifferenceType DifferenceType; - -public: - ResidualProductBase(ReconstructionGridLayer reconstruction_grid_layer, - const ScalarFunctionType& lambda, - const TensorFunctionType& kappa, - const ScalarFunctionType& f, - const ScalarFunctionType& u, - const ScalarFunctionType& v) - : f_(f) - , rt_space_(reconstruction_grid_layer) - , reconstructed_u_(rt_space_) - , reconstructed_v_(rt_space_) - , divergence_of_reconstructed_u_(reconstructed_u_) - , divergence_of_reconstructed_v_(reconstructed_v_) - , f_minus_divergence_of_reconstructed_u_(f_ - divergence_of_reconstructed_u_) - , f_minus_divergence_of_reconstructed_v_(f_ - divergence_of_reconstructed_v_) - { - DiffusiveFluxReconstructionOperator<ReconstructionGridLayer, - ScalarFunctionType, - TensorFunctionType, - LocalEllipticIpdgIntegrands::Method::swipdg_affine_factor> - flux_reconstruction(reconstruction_grid_layer, lambda, kappa); - flux_reconstruction.apply(u, reconstructed_u_); - flux_reconstruction.apply(v, reconstructed_v_); - } - - ResidualProductBase(const ThisType&) = delete; - ResidualProductBase(ThisType&&) = delete; - -protected: - const ScalarFunctionType& f_; - const RtSpaceType rt_space_; - FluxReconstructionType reconstructed_u_; - FluxReconstructionType reconstructed_v_; - const DivergenceOfFluxReconstructionType divergence_of_reconstructed_u_; - const DivergenceOfFluxReconstructionType divergence_of_reconstructed_v_; - const DifferenceType f_minus_divergence_of_reconstructed_u_; - const DifferenceType f_minus_divergence_of_reconstructed_v_; -}; // class ResidualProductBase - - -} // namespace internal - - -template <class ProductGridLayer, class ReconstructionGridLayer> -class ResidualProduct - : internal::ResidualProductBase<ProductGridLayer, ReconstructionGridLayer>, - public LocalizableProductBase<ProductGridLayer, - XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<ProductGridLayer>, - typename ProductGridLayer::ctype, - ProductGridLayer::dimension, - double, - 1>> -{ - typedef internal::ResidualProductBase<ProductGridLayer, ReconstructionGridLayer> ResidualProductBaseType; - typedef LocalizableProductBase<ProductGridLayer, - XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<ProductGridLayer>, - typename ProductGridLayer::ctype, - ProductGridLayer::dimension, - double, - 1>> - LocalizableProductBaseType; - -public: - using typename ResidualProductBaseType::ScalarFunctionType; - using typename ResidualProductBaseType::TensorFunctionType; - -private: - using typename ResidualProductBaseType::E; - using typename ResidualProductBaseType::D; - using ResidualProductBaseType::d; - using typename ResidualProductBaseType::R; - typedef LocalVolumeIntegralOperator<LocalLambdaBinaryVolumeIntegrand<E>, - typename ScalarFunctionType::LocalfunctionType> - LocalProductType; - -public: - ResidualProduct(ProductGridLayer product_grid_layer, - ReconstructionGridLayer reconstruction_grid_layer, - const ScalarFunctionType& lambda, - const ScalarFunctionType& lambda_hat, - const TensorFunctionType& kappa, - const ScalarFunctionType& f, - const ScalarFunctionType& u, - const ScalarFunctionType& v, - const double& poincare_constant = 1.0 / (M_PIl * M_PIl), - const size_t over_integrate = 2) - : ResidualProductBaseType(reconstruction_grid_layer, lambda, kappa, f, u, v) - , LocalizableProductBaseType(product_grid_layer, - this->f_minus_divergence_of_reconstructed_u_, - this->f_minus_divergence_of_reconstructed_v_) - , lambda_(lambda_hat) - , kappa_(kappa) - , poincare_constant_(poincare_constant) - , over_integrate_(over_integrate) - , local_product_( - // the order lambda - [&](const auto& local_f_minus_divergence_of_reconstructed_u, - const auto& local_f_minus_divergence_of_reconstructed_v) { - return local_f_minus_divergence_of_reconstructed_u.order() - + local_f_minus_divergence_of_reconstructed_v.order() + over_integrate_; - }, - // the evaluate lambda - [&](const auto& local_f_minus_divergence_of_reconstructed_u, - const auto& local_f_minus_divergence_of_reconstructed_v, - const auto& local_point, - auto& ret) { - ret[0][0] = local_f_minus_divergence_of_reconstructed_u.evaluate(local_point).at(0)[0] - * local_f_minus_divergence_of_reconstructed_v.evaluate(local_point).at(0)[0]; - }) - , min_diffusion_ev_(std::numeric_limits<R>::max()) - , subdomain_vertices_() - , finalized_(false) - { - this->append(local_product_); - - // the functor to collect all grid vertices - this->append([&](const E& entity) { - for (size_t cc = 0; cc < entity.subEntities(d); ++cc) - subdomain_vertices_.emplace_back(entity.template subEntity<d>(cc).geometry().center()); - }); - - // the functor to compute the min eigenvalue of the diffusion - this->append([&](const E& entity) { - const auto local_lambda = lambda_.local_function(entity); - const auto local_kappa = kappa_.local_function(entity); - // To find the minimum of a function we evaluate it - // * in all quadrature points of a quadrature which would integrate such a function exactly - for (const auto& quadrature_point : - QuadratureRules<D, d>::rule(entity.type(), local_lambda->order() + local_kappa->order() + over_integrate_)) { - const auto xx = quadrature_point.position(); - auto diffusion = local_kappa->evaluate(xx); - diffusion *= local_lambda->evaluate(xx); - min_diffusion_ev_ = std::min( - min_diffusion_ev_, - XT::LA::make_eigen_solver(diffusion, XT::Common::Configuration{{"assert_positive_eigenvalues"}, {1e-15}}) - .min_eigenvalues(1) - .at(0)); - } - // * and in the corners of the gigen entity. - const auto& reference_element = ReferenceElements<D, d>::general(entity.type()); - for (int ii = 0; ii < reference_element.size(d); ++ii) { - const auto xx = reference_element.position(ii, d); - auto diffusion = local_kappa->evaluate(xx); - diffusion *= local_lambda->evaluate(xx); - min_diffusion_ev_ = std::min( - min_diffusion_ev_, - XT::LA::make_eigen_solver(diffusion, XT::Common::Configuration{{"assert_positive_eigenvalues"}, {1e-15}}) - .min_eigenvalues(1) - .at(0)); - } - }); - } // ResidualProduct(...) - - R apply2() - { - if (!finalized_) { - this->walk(); - R subdomain_h = std::numeric_limits<R>::min(); - for (size_t ii = 0; ii < subdomain_vertices_.size(); ++ii) - for (size_t jj = ii + 1; jj < subdomain_vertices_.size(); ++jj) - subdomain_h = std::max(subdomain_h, (subdomain_vertices_[ii] - subdomain_vertices_[jj]).two_norm()); - this->result_ *= (poincare_constant_ / min_diffusion_ev_) * subdomain_h * subdomain_h; - } - return this->result_; - } - -private: - const ScalarFunctionType& lambda_; - const TensorFunctionType& kappa_; - const double poincare_constant_; - const size_t over_integrate_; - const LocalProductType local_product_; - R min_diffusion_ev_; - std::vector<FieldVector<D, d>> subdomain_vertices_; - bool finalized_; -}; // class ResidualProduct - - -template <class ProductGridLayer, class ReconstructionGridLayer> -class DiffusiveFluxProduct - : public LocalizableProductBase<ProductGridLayer, - XT::Functions::GridFunctionInterface<XT::Grid::extract_entity_t<ProductGridLayer>, - typename ProductGridLayer::ctype, - ProductGridLayer::dimension, - double, - 1>> -{ - static_assert(XT::Grid::is_layer<ProductGridLayer>::value, ""); - static_assert(XT::Grid::is_layer<ReconstructionGridLayer>::value, ""); - typedef XT::Grid::extract_entity_t<ProductGridLayer> E; - static_assert(std::is_same<XT::Grid::extract_entity_t<ReconstructionGridLayer>, E>::value, ""); - typedef typename ProductGridLayer::ctype D; - static const constexpr size_t d = ProductGridLayer::dimension; - typedef double R; - typedef DiffusiveFluxProduct<ProductGridLayer, ReconstructionGridLayer> ThisType; - -public: - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunctionType; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> TensorFunctionType; - -private: - typedef RaviartThomasSpace<ReconstructionGridLayer, 0, R> RtSpaceType; - typedef DiscreteFunction<RtSpaceType> FluxReconstructionType; - typedef LocalizableProductBase<ProductGridLayer, XT::Functions::GridFunctionInterface<E, D, d, R, 1>> BaseType; - typedef LocalVolumeIntegralOperator<LocalLambdaBinaryVolumeIntegrand<E>, - typename ScalarFunctionType::LocalfunctionType> - LocalProductType; - -public: - DiffusiveFluxProduct(ProductGridLayer product_grid_layer, - ReconstructionGridLayer reconstruction_grid_layer, - const ScalarFunctionType& lambda, - const ScalarFunctionType& lambda_hat, - const TensorFunctionType& kappa, - const ScalarFunctionType& u, - const ScalarFunctionType& v, - const size_t over_integrate = 2) - : BaseType(product_grid_layer, u, v) - , lambda_(lambda) - , lambda_hat_(lambda_hat) - , kappa_(kappa) - , rt_space_(reconstruction_grid_layer) - , reconstructed_u_(rt_space_) - , reconstructed_v_(rt_space_) - , over_integrate_(over_integrate) - , local_product_( - // the order lambda - [&](const auto& local_u, const auto& local_v) { - const auto& entity = local_u.entity(); - const size_t diffusion_order = - lambda_.local_function(entity)->order() + kappa_.local_function(entity)->order(); - return 3 * diffusion_order + size_t(std::max(ssize_t(local_u.order()) - 1, ssize_t(0))) - + size_t(std::max(ssize_t(local_v.order()) - 1, ssize_t(0))) + over_integrate_; - }, - // the evaluate lambda - [&](const auto& local_u, const auto& local_v, const auto& local_point, auto& ret) { - const auto& entity = local_u.entity(); - XT::Common::FieldMatrix<R, d, d> diffusion = kappa_.local_function(entity)->evaluate(local_point); - XT::Common::FieldMatrix<R, d, d> one_over_diffusion_hat = diffusion; - diffusion *= lambda_.local_function(entity)->evaluate(local_point); - one_over_diffusion_hat *= lambda_hat_.local_function(entity)->evaluate(local_point); - one_over_diffusion_hat.invert(); // there is no documented way to assert that the inversion was successfull - const auto grad_u = local_u.jacobian(local_point).at(0)[0]; - const auto grad_v = local_v.jacobian(local_point).at(0)[0]; - const auto val_reconstructed_u = reconstructed_u_.local_function(entity)->evaluate(local_point); - const auto val_reconstructed_v = reconstructed_v_.local_function(entity)->evaluate(local_point); - ret[0][0] = (one_over_diffusion_hat * ((diffusion * grad_u) + val_reconstructed_u)) // clang-format off - * ((diffusion * grad_v) + val_reconstructed_v); // clang-format on - }) - { - DiffusiveFluxReconstructionOperator<ReconstructionGridLayer, - ScalarFunctionType, - TensorFunctionType, - LocalEllipticIpdgIntegrands::Method::swipdg_affine_factor> - flux_reconstruction(reconstruction_grid_layer, lambda, kappa); - flux_reconstruction.apply(u, reconstructed_u_); - flux_reconstruction.apply(v, reconstructed_v_); - this->append(local_product_); - } - - DiffusiveFluxProduct(const ThisType&) = delete; - DiffusiveFluxProduct(ThisType&&) = delete; - -private: - const ScalarFunctionType& lambda_; - const ScalarFunctionType& lambda_hat_; - const TensorFunctionType& kappa_; - const RtSpaceType rt_space_; - FluxReconstructionType reconstructed_u_; - FluxReconstructionType reconstructed_v_; - const size_t over_integrate_; - const LocalProductType local_product_; -}; // class DiffusiveFluxProduct - - -} // namespace OS2015 -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI -#endif // DUNE_GDT_PLAYGROUND_OPERATORS_OS2015_HH diff --git a/python/dune/gdt/playground/operators/RS2017.cc b/python/dune/gdt/playground/operators/RS2017.cc deleted file mode 100644 index 64074df779c3c94401309505e2c4d913b77469e7..0000000000000000000000000000000000000000 --- a/python/dune/gdt/playground/operators/RS2017.cc +++ /dev/null @@ -1,204 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_ALUGRID && HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> - -# include <dune/xt/la/eigen-solver.hh> - -# include <dune/gdt/operators/elliptic.hh> - -# include <python/dune/gdt/playground/operators/RS2017.hh> - -using namespace Dune; -using namespace Dune::GDT::RS2017; -using XT::Grid::Backends; -using XT::Grid::Layers; -namespace py = pybind11; - - -PYBIND11_MODULE(__operators_RS2017, m) -{ - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - - SwipdgPenaltySubdomainProduct<ALU_2D_SIMPLEX_CONFORMING>::bind(m); - HdivSemiProduct<ALU_2D_SIMPLEX_CONFORMING>::bind(m); - DiffusiveFluxAaProduct<ALU_2D_SIMPLEX_CONFORMING>::bind(m); - DiffusiveFluxAbProduct<ALU_2D_SIMPLEX_CONFORMING>::bind(m); - DiffusiveFluxBbProduct<ALU_2D_SIMPLEX_CONFORMING>::bind(m); - ResidualPartFunctional<ALU_2D_SIMPLEX_CONFORMING>::bind(m); - - bind_neighborhood_reconstruction<ALU_2D_SIMPLEX_CONFORMING>(m); - bind_neighborhood_discretization<ALU_2D_SIMPLEX_CONFORMING>(m); - - typedef typename ALU_2D_SIMPLEX_CONFORMING::template Codim<0>::Entity E; - typedef double D; - static const constexpr size_t d = 2; - typedef double R; - - typedef XT::LA::IstlDenseVector<R> V; - typedef XT::LA::IstlRowMajorSparseMatrix<R> M; - - m.def("RS2017_residual_indicator_min_diffusion_eigenvalue", - [](XT::Grid::GridProvider<ALU_2D_SIMPLEX_CONFORMING, XT::Grid::DD::SubdomainGrid<ALU_2D_SIMPLEX_CONFORMING>>& - dd_grid_provider, - const ssize_t subdomain, - const XT::Functions::GridFunctionInterface<E, D, d, R, 1>& lambda, - const XT::Functions::GridFunctionInterface<E, D, d, R, d, d>& kappa, - const ssize_t over_int) { - py::gil_scoped_release DUNE_UNUSED(release); - const auto over_integrate = XT::Common::numeric_cast<size_t>(over_int); - auto subdomain_layer = dd_grid_provider.template layer<Layers::dd_subdomain, Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain)); - typedef decltype(subdomain_layer) GL; - XT::Grid::Walker<GL> walker(subdomain_layer); - double min_ev = std::numeric_limits<double>::max(); - walker.append([&](const E& entity) { - const auto local_lambda = lambda.local_function(entity); - const auto local_kappa = kappa.local_function(entity); - // To find the minimum of a function we evaluate it - // * in all quadrature points of a quadrature which would integrate such a function exactly - for (const auto& quadrature_point : QuadratureRules<D, d>::rule( - entity.type(), local_lambda->order() + local_kappa->order() + over_integrate)) { - const auto xx = quadrature_point.position(); - auto diffusion = local_kappa->evaluate(xx); - diffusion *= local_lambda->evaluate(xx); - min_ev = std::min(min_ev, - XT::LA::make_eigen_solver( - diffusion, XT::Common::Configuration{{"assert_positive_eigenvalues"}, {1e-15}}) - .min_eigenvalues(1) - .at(0)); - } - // * and in the corners of the gigen entity. - const auto& reference_element = ReferenceElements<D, d>::general(entity.type()); - for (int ii = 0; ii < reference_element.size(d); ++ii) { - const auto xx = reference_element.position(ii, d); - auto diffusion = local_kappa->evaluate(xx); - diffusion *= local_lambda->evaluate(xx); - min_ev = std::min(min_ev, - XT::LA::make_eigen_solver( - diffusion, XT::Common::Configuration{{"assert_positive_eigenvalues"}, {1e-15}}) - .min_eigenvalues(1) - .at(0)); - } - }); - walker.walk(); - return min_ev; - }, - "dd_grid_provider"_a, - "subdomain"_a, - "lambda"_a, - "kappa"_a, - "over_integrate"_a = 2); - m.def("RS2017_residual_indicator_subdomain_diameter", - [](XT::Grid::GridProvider<ALU_2D_SIMPLEX_CONFORMING, XT::Grid::DD::SubdomainGrid<ALU_2D_SIMPLEX_CONFORMING>>& - dd_grid_provider, - const ssize_t subdomain) { - py::gil_scoped_release DUNE_UNUSED(release); - auto subdomain_layer = dd_grid_provider.template layer<Layers::dd_subdomain, Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain)); - typedef decltype(subdomain_layer) GL; - XT::Grid::Walker<GL> walker(subdomain_layer); - std::vector<FieldVector<D, d>> subdomain_vertices; - walker.append([&](const E& entity) { - for (size_t cc = 0; cc < entity.subEntities(d); ++cc) - subdomain_vertices.emplace_back(entity.template subEntity<d>(cc).geometry().center()); - }); - walker.walk(); - R subdomain_h = std::numeric_limits<R>::min(); - for (size_t ii = 0; ii < subdomain_vertices.size(); ++ii) - for (size_t jj = ii + 1; jj < subdomain_vertices.size(); ++jj) - subdomain_h = std::max(subdomain_h, (subdomain_vertices[ii] - subdomain_vertices[jj]).two_norm()); - return subdomain_h; - }, - "dd_grid_provider"_a, - "subdomain"_a); - m.def("RS2017_apply_l2_product", - [](XT::Grid::GridProvider<ALU_2D_SIMPLEX_CONFORMING, XT::Grid::DD::SubdomainGrid<ALU_2D_SIMPLEX_CONFORMING>>& - dd_grid_provider, - const ssize_t subdomain, - const XT::Functions::GridFunctionInterface<E, D, d, R, 1>& u, - const XT::Functions::GridFunctionInterface<E, D, d, R, 1>& v, - const ssize_t over_integrate) { - py::gil_scoped_release DUNE_UNUSED(release); - return GDT::make_l2_operator(dd_grid_provider.template layer<Layers::dd_subdomain, Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain)), - XT::Common::numeric_cast<size_t>(over_integrate)) - ->apply2(u, v); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "u"_a, - "v"_a, - "over_integrate"_a = 2); - - typedef GDT::EllipticMatrixOperator< - XT::Functions::GridFunctionInterface<E, D, d, R, 1>, - XT::Functions::GridFunctionInterface<E, D, d, R, d, d>, - typename GDT::SpaceProvider<ALU_2D_SIMPLEX_CONFORMING, - Layers::dd_subdomain, - GDT::SpaceType::dg, - GDT::Backends::gdt, - 1, - double, - 1>::type, - XT::LA::IstlRowMajorSparseMatrix<double>, - typename XT::Grid::Layer<ALU_2D_SIMPLEX_CONFORMING, Layers::dd_subdomain, Backends::view>::type> - EllipticMatrixOperatorType; - try { // we might not be the first to add this - py::class_<EllipticMatrixOperatorType, - GDT::SystemAssembler<typename EllipticMatrixOperatorType::SourceSpaceType, - typename EllipticMatrixOperatorType::GridLayerType>> - elliptic_matrix_operator(m, "EllipticMatrixOperatorNeighborhood"); - elliptic_matrix_operator.def("matrix", [](EllipticMatrixOperatorType& self) { return self.matrix(); }); - } catch (std::runtime_error&) { - } - m.def("RS2017_make_elliptic_matrix_operator_on_subdomain", - [](XT::Grid::GridProvider<ALU_2D_SIMPLEX_CONFORMING, XT::Grid::DD::SubdomainGrid<ALU_2D_SIMPLEX_CONFORMING>>& - dd_grid_provider, - const ssize_t subdomain, - const typename EllipticMatrixOperatorType::SourceSpaceType& space, - const XT::Functions::GridFunctionInterface<E, D, d, R, 1>& lambda, - const XT::Functions::GridFunctionInterface<E, D, d, R, d, d>& kappa, - const ssize_t over_integrate) { - return new EllipticMatrixOperatorType(XT::Common::numeric_cast<ssize_t>(over_integrate), - lambda, - kappa, - space, - dd_grid_provider.template layer<Layers::dd_subdomain, Backends::view>( - XT::Common::numeric_cast<int>(subdomain))); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "space"_a, - "lambda"_a, - "kappa"_a, - "over_integrate"_a = 2); - - add_initialization(m, "dune.gdt.operators.elliptic"); -} - -#endif // HAVE_DUNE_ALUGRID && HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/playground/operators/RS2017.hh b/python/dune/gdt/playground/operators/RS2017.hh deleted file mode 100644 index 3992a5e2bd7c7d3ef46212f113d19295869becf2..0000000000000000000000000000000000000000 --- a/python/dune/gdt/playground/operators/RS2017.hh +++ /dev/null @@ -1,1311 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef DUNE_GDT_PLAYGROUND_OPERATORS_RS2017_HH -#define DUNE_GDT_PLAYGROUND_OPERATORS_RS2017_HH - -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI -# include <type_traits> - -# include <dune/common/typetraits.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <dune/xt/common/numeric_cast.hh> -# include <dune/xt/la/container/istl.hh> -# include <dune/xt/grid/dd/subdomains/grid.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <dune/xt/grid/layers.hh> -# include <dune/xt/grid/type_traits.hh> -# include <dune/xt/functions/interfaces/grid-function.hh> - -# include <python/dune/gdt/assembler/system.hh> -# include <dune/gdt/functionals/elliptic-ipdg.hh> -# include <dune/gdt/functionals/l2.hh> -# include <dune/gdt/local/integrands/elliptic.hh> -# include <dune/gdt/local/integrands/elliptic-ipdg.hh> -# include <dune/gdt/local/integrands/lambda.hh> -# include <dune/gdt/local/operators/integrals.hh> -# include <dune/gdt/operators/base.hh> -# include <python/dune/gdt/operators/base.hh> -# include <dune/gdt/operators/elliptic-ipdg.hh> -# include <dune/gdt/operators/fluxreconstruction.hh> -# include <dune/gdt/operators/l2.hh> -# include <dune/gdt/spaces.hh> - -namespace Dune { -namespace GDT { -namespace RS2017 { - -# if HAVE_DUNE_ISTL - - -template <class G> -class DiffusiveFluxAaProduct - : public GDT::MatrixOperatorBase<XT::LA::IstlRowMajorSparseMatrix<double>, - typename GDT::SpaceProvider<G, - XT::Grid::Layers::dd_subdomain, - GDT::SpaceType::dg, - GDT::Backends::gdt, - 1, - double, - 1>::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type> -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef typename GDT:: - SpaceProvider<G, XT::Grid::Layers::dd_subdomain, GDT::SpaceType::dg, GDT::Backends::gdt, 1, double, 1> - SP; - typedef GDT::MatrixOperatorBase<XT::LA::IstlRowMajorSparseMatrix<double>, - typename SP::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type> - BaseType; - typedef DiffusiveFluxAaProduct<G> ThisType; - -public: - using typename BaseType::GridLayerType; - using typename BaseType::RangeSpaceType; - - typedef XT::Grid::extract_entity_t<GridLayerType> E; - typedef XT::Grid::extract_intersection_t<GridLayerType> I; - typedef typename G::ctype D; - static const constexpr size_t d = G::dimension; - typedef double R; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunctionType; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> TensorFunctionType; - typedef typename RangeSpaceType::BaseFunctionSetType BasisType; - - static void bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - GDT::bindings::MatrixOperatorBase<ThisType>::bind( - m, - XT::Common::to_camel_case("RS2017_diffusive_flux_aa_product_matrix_operator_subdomain_" - + XT::Grid::bindings::grid_name<G>::value()) - .c_str()); - - m.def("RS2017_make_diffusive_flux_aa_product_matrix_operator_on_subdomain", - [](const XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - const RangeSpaceType& space, - const ScalarFunctionType& lambda_hat, - const ScalarFunctionType& lambda_u, - const ScalarFunctionType& lambda_v, - const TensorFunctionType& kappa, - const size_t over_integrate) { - return new ThisType( - space, - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain)), - lambda_hat, - lambda_u, - lambda_v, - kappa, - over_integrate); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "space"_a, - "lambda_hat"_a, - "lambda_u"_a, - "lambda_v"_a, - "kappa"_a, - "over_integrate"_a = 2); - } // ... bind(...) - - DiffusiveFluxAaProduct(RangeSpaceType space, - GridLayerType grd_lyr, - const ScalarFunctionType& lambda_hat, - const ScalarFunctionType& lambda_u, - const ScalarFunctionType& lambda_v, - const TensorFunctionType& kappa, - const size_t over_integrate = 2) - : BaseType(space, grd_lyr) - , unit_matrix_(XT::Common::from_string<XT::Common::FieldMatrix<D, d, d>>("[1 0 0; 0 1 0; 0 0 1]")) - , over_integrate_(over_integrate) - , local_operator_( - [&](const auto& test_base, const auto& ansatz_base) { - const auto& entity = test_base.entity(); - const auto local_lambda_hat = lambda_hat.local_function(entity); - const auto local_lambda_u = lambda_u.local_function(entity); - const auto local_lambda_v = lambda_v.local_function(entity); - const auto local_kappa = kappa.local_function(entity); - const auto integrand_order = local_lambda_hat->order() + local_lambda_u->order() + local_lambda_v->order() - + 3 * local_kappa->order() - + size_t(std::max(ssize_t(test_base.order()) - 1, ssize_t(0))) - + size_t(std::max(ssize_t(ansatz_base.order()) - 1, ssize_t(0))); - return integrand_order + over_integrate_; - }, - [&](const auto& test_base, const auto& ansatz_base, const auto& local_point, auto& ret) { - const auto& entity = test_base.entity(); - const auto local_lambda_hat = lambda_hat.local_function(entity); - const auto local_lambda_u = lambda_u.local_function(entity); - const auto local_lambda_v = lambda_v.local_function(entity); - const auto local_kappa = kappa.local_function(entity); - XT::Common::FieldMatrix<D, d, d> diffusion_hat_inverse = local_kappa->evaluate(local_point); - XT::Common::FieldMatrix<D, d, d> diffusion_u = diffusion_hat_inverse; - XT::Common::FieldMatrix<D, d, d> diffusion_v = diffusion_hat_inverse; - diffusion_hat_inverse *= local_lambda_hat->evaluate(local_point); -# ifndef NDEBUG - const auto diffusion_hat = diffusion_hat_inverse; -# endif - diffusion_hat_inverse.invert(); -# ifndef NDEBUG - // there is no documented way to tell if the inversion was successfull - if (XT::Common::FloatCmp::ne(diffusion_hat_inverse * diffusion_hat, unit_matrix_)) - DUNE_THROW(XT::Common::Exceptions::internal_error, - "Local inversion of lambda_hat*kappa failed!\n\nx = " - << local_point - << "\nlocal_lambda_hat(x) = " - << local_lambda_hat->evaluate(local_point) - << "\nlocal_kappa(x) = " - << local_kappa->evaluate(local_point) - << "\ninverse = " - << diffusion_hat_inverse - << "\ninverse * (local_lambda_hat(x)*local_kappa(x))) = " - << diffusion_hat_inverse * diffusion_hat); -# endif - diffusion_u *= local_lambda_u->evaluate(local_point); - diffusion_v *= local_lambda_v->evaluate(local_point); - const auto test_grads = test_base.jacobian(local_point); - const auto ansatz_grads = ansatz_base.jacobian(local_point); - ret *= 0.; - for (size_t ii = 0; ii < test_base.size(); ++ii) - for (size_t jj = 0; jj < ansatz_base.size(); ++jj) - ret[ii][jj] = - ((diffusion_hat_inverse * (diffusion_u * ansatz_grads[jj][0])) * (diffusion_v * test_grads[ii][0])); - }) - { - this->append(local_operator_); - } - - DiffusiveFluxAaProduct(const ThisType&) = delete; - DiffusiveFluxAaProduct(ThisType&&) = delete; - -private: - const XT::Common::FieldMatrix<D, d, d> unit_matrix_; - const size_t over_integrate_; - const GDT::LocalVolumeIntegralOperator<GDT::LocalLambdaBinaryVolumeIntegrand<E, R, 1>, BasisType> local_operator_; -}; // class DiffusiveFluxAaProduct - - -template <class G> -class DiffusiveFluxAbProduct - : public GDT:: - MatrixOperatorBase<XT::LA::IstlRowMajorSparseMatrix<double>, - typename GDT::SpaceProvider<G, - XT::Grid::Layers::dd_subdomain, - GDT::SpaceType::dg, - GDT::Backends::gdt, - 1, - double, - 1>::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type, - GDT::RestrictedSpace<typename GDT::SpaceProvider<G, - XT::Grid::Layers::leaf, - GDT::SpaceType::rt, - GDT::Backends::gdt, - 0, - double, - G::dimension>::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type>> -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef GDT::MatrixOperatorBase<XT::LA::IstlRowMajorSparseMatrix<double>, - typename GDT::SpaceProvider<G, - XT::Grid::Layers::dd_subdomain, - GDT::SpaceType::dg, - GDT::Backends::gdt, - 1, - double, - 1>::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type, - GDT::RestrictedSpace<typename GDT::SpaceProvider<G, - XT::Grid::Layers::leaf, - GDT::SpaceType::rt, - GDT::Backends::gdt, - 0, - double, - G::dimension>::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type>> - BaseType; - typedef DiffusiveFluxAbProduct<G> ThisType; - -public: - using typename BaseType::GridLayerType; - using typename BaseType::RangeSpaceType; - using typename BaseType::RangeBaseType; - using typename BaseType::SourceSpaceType; - using typename BaseType::SourceBaseType; - - typedef XT::Grid::extract_entity_t<GridLayerType> E; - typedef XT::Grid::extract_intersection_t<GridLayerType> I; - typedef typename G::ctype D; - static const constexpr size_t d = G::dimension; - typedef double R; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunctionType; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> TensorFunctionType; - - static void bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - py::class_<ThisType, XT::Grid::Walker<GridLayerType>> c( - m, - XT::Common::to_camel_case("RS2017_diffusive_flux_ab_product_matrix_operator_subdomain_" - + XT::Grid::bindings::grid_name<G>::value()) - .c_str()); - c.def("assemble", [](ThisType& self) { self.assemble(); }); - c.def("matrix", [](ThisType& self) { return self.matrix(); }); - - m.def("RS2017_make_diffusive_flux_ab_product_matrix_operator_on_subdomain", - [](const XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - const RangeSpaceType& range_space, - const SourceSpaceType& source_space, - const ScalarFunctionType& lambda_hat, - const ScalarFunctionType& lambda_range, - const TensorFunctionType& kappa, - const size_t over_integrate) { - return new ThisType( - range_space, - source_space, - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain)), - lambda_hat, - lambda_range, - kappa, - over_integrate); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "range_space"_a, - "source_space"_a, - "lambda_hat"_a, - "lambda_range"_a, - "kappa"_a, - "over_integrate"_a = 2); - } // ... bind(...) - - DiffusiveFluxAbProduct(RangeSpaceType range_space, - SourceSpaceType source_space, - GridLayerType grd_lyr, - const ScalarFunctionType& lambda_hat, - const ScalarFunctionType& lambda_range, - const TensorFunctionType& kappa, - const size_t over_integrate = 2) - : BaseType(range_space, source_space, grd_lyr) - , unit_matrix_(XT::Common::from_string<XT::Common::FieldMatrix<D, d, d>>("[1 0 0; 0 1 0; 0 0 1]")) - , over_integrate_(over_integrate) - , local_operator_( - [&](const auto& test_base, const auto& ansatz_base) { - const auto& entity = test_base.entity(); - const auto local_lambda_hat = lambda_hat.local_function(entity); - const auto local_lambda_range = lambda_range.local_function(entity); - const auto local_kappa = kappa.local_function(entity); - const auto integrand_order = - local_lambda_hat->order() + local_lambda_range->order() + 2 * local_kappa->order() - + size_t(std::max(ssize_t(test_base.order()) - 1, ssize_t(0))) + ansatz_base.order(); - return integrand_order + over_integrate_; - }, - [&](const auto& test_base, const auto& ansatz_base, const auto& local_point, auto& ret) { - const auto& entity = test_base.entity(); - const auto local_lambda_hat = lambda_hat.local_function(entity); - const auto local_lambda_range = lambda_range.local_function(entity); - const auto local_kappa = kappa.local_function(entity); - XT::Common::FieldMatrix<D, d, d> diffusion_hat_inverse = local_kappa->evaluate(local_point); - XT::Common::FieldMatrix<D, d, d> diffusion_range = diffusion_hat_inverse; - diffusion_hat_inverse *= local_lambda_hat->evaluate(local_point); -# ifndef NDEBUG - const auto diffusion_hat = diffusion_hat_inverse; -# endif - diffusion_hat_inverse.invert(); -# ifndef NDEBUG - // there is no documented way to tell if the inversion was successfull - if (XT::Common::FloatCmp::ne(diffusion_hat_inverse * diffusion_hat, unit_matrix_)) - DUNE_THROW(XT::Common::Exceptions::internal_error, - "Local inversion of lambda_hat*kappa failed!\n\nx = " - << local_point - << "\nlocal_lambda_hat(x) = " - << local_lambda_hat->evaluate(local_point) - << "\nlocal_kappa(x) = " - << local_kappa->evaluate(local_point) - << "\ninverse = " - << diffusion_hat_inverse - << "\ninverse * (local_lambda_hat(x)*local_kappa(x))) = " - << diffusion_hat_inverse * diffusion_hat); -# endif - diffusion_range *= local_lambda_range->evaluate(local_point); - const auto test_grads = test_base.jacobian(local_point); - const auto ansatz_values = ansatz_base.evaluate(local_point); - ret *= 0.; - for (size_t ii = 0; ii < test_base.size(); ++ii) - for (size_t jj = 0; jj < ansatz_base.size(); ++jj) - ret[ii][jj] = ((diffusion_hat_inverse * (diffusion_range * test_grads[ii][0])) * (ansatz_values[jj])); - }) - { - this->append(local_operator_); - } - - DiffusiveFluxAbProduct(const ThisType&) = delete; - DiffusiveFluxAbProduct(ThisType&&) = delete; - -private: - const XT::Common::FieldMatrix<D, d, d> unit_matrix_; - const size_t over_integrate_; - const GDT::LocalVolumeIntegralOperator<GDT::LocalLambdaBinaryVolumeIntegrand<E, R, 1, 1, d, 1>, - RangeBaseType, - SourceBaseType> - local_operator_; -}; // class DiffusiveFluxAbProduct - - -template <class G> -class DiffusiveFluxBbProduct - : public GDT:: - MatrixOperatorBase<XT::LA::IstlRowMajorSparseMatrix<double>, - GDT::RestrictedSpace<typename GDT::SpaceProvider<G, - XT::Grid::Layers::leaf, - GDT::SpaceType::rt, - GDT::Backends::gdt, - 0, - double, - G::dimension>::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type>, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type> -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef GDT::MatrixOperatorBase<XT::LA::IstlRowMajorSparseMatrix<double>, - GDT::RestrictedSpace<typename GDT::SpaceProvider<G, - XT::Grid::Layers::leaf, - GDT::SpaceType::rt, - GDT::Backends::gdt, - 0, - double, - G::dimension>::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type>, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type> - BaseType; - typedef DiffusiveFluxBbProduct<G> ThisType; - -public: - using typename BaseType::GridLayerType; - using typename BaseType::RangeSpaceType; - using typename BaseType::RangeBaseType; - - typedef XT::Grid::extract_entity_t<GridLayerType> E; - typedef XT::Grid::extract_intersection_t<GridLayerType> I; - typedef typename G::ctype D; - static const constexpr size_t d = G::dimension; - typedef double R; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunctionType; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> TensorFunctionType; - - static void bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - py::class_<ThisType, XT::Grid::Walker<GridLayerType>> c( - m, - XT::Common::to_camel_case("RS2017_diffusive_flux_bb_product_matrix_operator_subdomain_" - + XT::Grid::bindings::grid_name<G>::value()) - .c_str()); - c.def("assemble", [](ThisType& self) { self.assemble(); }); - c.def("matrix", [](ThisType& self) { return self.matrix(); }); - - m.def("RS2017_make_diffusive_flux_bb_product_matrix_operator_on_subdomain", - [](const XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - const RangeSpaceType& space, - const ScalarFunctionType& lambda_hat, - const TensorFunctionType& kappa, - const size_t over_integrate) { - return new ThisType( - space, - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain)), - lambda_hat, - kappa, - over_integrate); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "space"_a, - "lambda_hat"_a, - "kappa"_a, - "over_integrate"_a = 2); - } // ... bind(...) - - DiffusiveFluxBbProduct(RangeSpaceType space, - GridLayerType grd_lyr, - const ScalarFunctionType& lambda_hat, - const TensorFunctionType& kappa, - const size_t over_integrate = 2) - : BaseType(space, grd_lyr) - , unit_matrix_(XT::Common::from_string<XT::Common::FieldMatrix<D, d, d>>("[1 0 0; 0 1 0; 0 0 1]")) - , over_integrate_(over_integrate) - , local_operator_( - [&](const auto& test_base, const auto& ansatz_base) { - const auto& entity = test_base.entity(); - const auto local_lambda_hat = lambda_hat.local_function(entity); - const auto local_kappa = kappa.local_function(entity); - const auto integrand_order = - local_lambda_hat->order() + local_kappa->order() + test_base.order() + ansatz_base.order(); - return integrand_order + over_integrate_; - }, - [&](const auto& test_base, const auto& ansatz_base, const auto& local_point, auto& ret) { - const auto& entity = test_base.entity(); - const auto local_lambda_hat = lambda_hat.local_function(entity); - const auto local_kappa = kappa.local_function(entity); - XT::Common::FieldMatrix<D, d, d> diffusion_hat_inverse = local_kappa->evaluate(local_point); - diffusion_hat_inverse *= local_lambda_hat->evaluate(local_point); -# ifndef NDEBUG - const auto diffusion_hat = diffusion_hat_inverse; -# endif - diffusion_hat_inverse.invert(); -# ifndef NDEBUG - // there is no documented way to tell if the inversion was successfull - if (XT::Common::FloatCmp::ne(diffusion_hat_inverse * diffusion_hat, unit_matrix_)) - DUNE_THROW(XT::Common::Exceptions::internal_error, - "Local inversion of lambda_hat*kappa failed!\n\nx = " - << local_point - << "\nlocal_lambda_hat(x) = " - << local_lambda_hat->evaluate(local_point) - << "\nlocal_kappa(x) = " - << local_kappa->evaluate(local_point) - << "\ninverse = " - << diffusion_hat_inverse - << "\ninverse * (local_lambda_hat(x)*local_kappa(x))) = " - << diffusion_hat_inverse * diffusion_hat); -# endif - const auto test_values = test_base.evaluate(local_point); - const auto ansatz_values = ansatz_base.evaluate(local_point); - ret *= 0.; - for (size_t ii = 0; ii < test_base.size(); ++ii) - for (size_t jj = 0; jj < ansatz_base.size(); ++jj) - ret[ii][jj] = ((diffusion_hat_inverse * test_values[ii]) * ansatz_values[jj]); - }) - { - this->append(local_operator_); - } - - DiffusiveFluxBbProduct(const ThisType&) = delete; - DiffusiveFluxBbProduct(ThisType&&) = delete; - -private: - const XT::Common::FieldMatrix<D, d, d> unit_matrix_; - const size_t over_integrate_; - const GDT::LocalVolumeIntegralOperator<GDT::LocalLambdaBinaryVolumeIntegrand<E, R, d, 1>, RangeBaseType> - local_operator_; -}; // class DiffusiveFluxBbProduct - - -template <class G> -class SwipdgPenaltySubdomainProduct - : public GDT::MatrixOperatorBase<XT::LA::IstlRowMajorSparseMatrix<double>, - typename GDT::SpaceProvider<G, - XT::Grid::Layers::dd_subdomain, - GDT::SpaceType::dg, - GDT::Backends::gdt, - 1, - double, - 1>::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type> -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef GDT::SpaceProvider<G, XT::Grid::Layers::dd_subdomain, GDT::SpaceType::dg, GDT::Backends::gdt, 1, double, 1> - SP; - typedef GDT::MatrixOperatorBase<XT::LA::IstlRowMajorSparseMatrix<double>, - typename SP::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type> - BaseType; - typedef SwipdgPenaltySubdomainProduct<G> ThisType; - -public: - using typename BaseType::GridLayerType; - using typename BaseType::RangeSpaceType; - - typedef XT::Grid::extract_entity_t<GridLayerType> E; - typedef XT::Grid::extract_intersection_t<GridLayerType> I; - typedef typename G::ctype D; - static const constexpr size_t d = G::dimension; - typedef double R; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunctionType; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> TensorFunctionType; - typedef typename RangeSpaceType::BaseFunctionSetType BasisType; - - static void bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - GDT::bindings::MatrixOperatorBase<ThisType>::bind( - m, - XT::Common::to_camel_case("RS2017_penalty_product_matrix_operator_subdomain_" - + XT::Grid::bindings::grid_name<G>::value()) - .c_str()); - - m.def("RS2017_make_penalty_product_matrix_operator_on_subdomain", - [](const XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - const XT::Grid::BoundaryInfo<I>& boundary_info, - const RangeSpaceType& space, - const ScalarFunctionType& lambda, - const TensorFunctionType& kappa, - const size_t over_integrate) { - return new ThisType( - space, - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain)), - boundary_info, - lambda, - kappa, - over_integrate); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "boundary_info"_a, - "space"_a, - "lambda_bar"_a, - "kappa"_a, - "over_integrate"_a = 2); - } // ... bind(...) - - SwipdgPenaltySubdomainProduct(RangeSpaceType space, - GridLayerType grd_lyr, - const XT::Grid::BoundaryInfo<I>& boundary_info, - const ScalarFunctionType& lambda, - const TensorFunctionType& kappa, - const size_t over_integrate = 2) - : BaseType(space, grd_lyr) - , lambda_(lambda) - , kappa_(kappa) - , over_integrate_(over_integrate) - , local_coupling_operator_( - // the order lambda - [&](const auto& test_base_en, - const auto& ansatz_base_en, - const auto& test_base_ne, - const auto& ansatz_base_ne) { - const auto& entity = test_base_en.entity(); - const auto& neighbor = test_base_ne.entity(); - const auto local_lambda_en = lambda_.local_function(entity); - const auto local_lambda_ne = lambda_.local_function(neighbor); - const auto local_kappa_en = kappa_.local_function(entity); - const auto local_kappa_ne = kappa_.local_function(neighbor); - const auto integrand_order = std::max(local_lambda_en->order(), local_lambda_ne->order()) - + std::max(local_kappa_en->order(), local_kappa_ne->order()) - + std::max(test_base_en.order(), test_base_ne.order()) - + std::max(ansatz_base_en.order(), ansatz_base_ne.order()); - return integrand_order + over_integrate_; - }, - // The evaluate lambda, this is the penalty part of LocalEllipticIpdgIntegrands::Inner from - // dune/gdt/local/integrands/elliptic-ipdg.hh, swipdg_affine_factor variant. - [&](const auto& test_base_en, - const auto& ansatz_base_en, - const auto& test_base_ne, - const auto& ansatz_base_ne, - const auto& intersection, - const auto& local_point, - auto& ret_en_en, - auto& ret_ne_ne, - auto& ret_en_ne, - auto& ret_ne_en) { - // clear ret - ret_en_en *= 0.0; - ret_ne_ne *= 0.0; - ret_en_ne *= 0.0; - ret_ne_en *= 0.0; - // convert local point (which is in intersection coordinates) to entity/neighbor coordinates - const auto local_point_en = intersection.geometryInInside().global(local_point); - const auto local_point_ne = intersection.geometryInOutside().global(local_point); - const auto normal = intersection.unitOuterNormal(local_point); - // evaluate local function - const auto& entity = test_base_en.entity(); - const auto& neighbor = test_base_ne.entity(); - const auto lambda_val_en = lambda_.local_function(entity)->evaluate(local_point_en); - const auto lambda_val_ne = lambda_.local_function(neighbor)->evaluate(local_point_ne); - const XT::Common::FieldMatrix<D, d, d> kappa_val_en = - kappa_.local_function(entity)->evaluate(local_point_en); - const XT::Common::FieldMatrix<D, d, d> kappa_val_ne = - kappa_.local_function(neighbor)->evaluate(local_point_ne); - // compute penalty - const size_t max_polorder = - std::max(test_base_en.order(), - std::max(ansatz_base_en.order(), std::max(test_base_ne.order(), ansatz_base_ne.order()))); - const R sigma = GDT::LocalEllipticIpdgIntegrands::internal::inner_sigma(max_polorder); - const R delta_plus = normal * (kappa_val_ne * normal); - const R delta_minus = normal * (kappa_val_en * normal); - const R gamma = (delta_plus * delta_minus) / (delta_plus + delta_minus); - const auto h = intersection.geometry().volume(); - const auto beta = GDT::LocalEllipticIpdgIntegrands::internal::default_beta(d); - const R penalty = (0.5 * (lambda_val_en + lambda_val_ne) * sigma * gamma) / std::pow(h, beta); - // evaluate bases - const size_t rows_en = test_base_en.size(); - const size_t cols_en = ansatz_base_en.size(); - const size_t rows_ne = test_base_ne.size(); - const size_t cols_ne = ansatz_base_ne.size(); - const auto test_values_en = test_base_en.evaluate(local_point_en); - const auto ansatz_values_en = ansatz_base_en.evaluate(local_point_en); - const auto test_values_ne = test_base_ne.evaluate(local_point_ne); - const auto ansatz_values_ne = ansatz_base_ne.evaluate(local_point_ne); - // compute integrals, loop over all combinations of basis functions - assert(ret_en_en.rows() >= rows_en && ret_en_en.cols() >= cols_en); - assert(ret_en_ne.rows() >= rows_en && ret_en_ne.cols() >= cols_ne); - assert(ret_ne_en.rows() >= rows_ne && ret_ne_en.cols() >= cols_en); - assert(ret_ne_ne.rows() >= rows_ne && ret_ne_ne.cols() >= cols_ne); - for (size_t ii = 0; ii < rows_en; ++ii) { - for (size_t jj = 0; jj < cols_en; ++jj) - ret_en_en[ii][jj] += penalty * ansatz_values_en[jj] * test_values_en[ii]; - for (size_t jj = 0; jj < cols_ne; ++jj) - ret_en_ne[ii][jj] += -1.0 * penalty * ansatz_values_ne[jj] * test_values_en[ii]; - } - for (size_t ii = 0; ii < rows_ne; ++ii) { - for (size_t jj = 0; jj < cols_en; ++jj) - ret_ne_en[ii][jj] += -1.0 * penalty * ansatz_values_en[jj] * test_values_ne[ii]; - for (size_t jj = 0; jj < cols_ne; ++jj) - ret_ne_ne[ii][jj] += penalty * ansatz_values_ne[jj] * test_values_ne[ii]; - } - }) - , local_boundary_operator_( - // the order lambda - [&](const auto& test_base, const auto& ansatz_base) { - const auto& entity = test_base.entity(); - const auto local_lambda = lambda_.local_function(entity); - const auto local_kappa = kappa_.local_function(entity); - const auto integrand_order = - local_lambda->order() + local_kappa->order() + test_base.order() + ansatz_base.order(); - return integrand_order + over_integrate_; - }, - // The evaluate lambda, this is the penalty part of LocalEllipticIpdgIntegrands::BoundaryLHS from - // dune/gdt/local/integrands/elliptic-ipdg.hh, swipdg_affine_factor variant. - [&](const auto& test_base, - const auto& ansatz_base, - const auto& intersection, - const auto& local_point, - auto& ret) { - // clear ret - ret *= 0.0; - // get local point (which is in intersection coordinates) in entity coordinates - const auto local_point_entity = intersection.geometryInInside().global(local_point); - const auto normal = intersection.unitOuterNormal(local_point); - // evaluate local functions - const auto& entity = test_base.entity(); - XT::Common::FieldMatrix<D, d, d> diffusion = kappa_.local_function(entity)->evaluate(local_point_entity); - diffusion *= lambda_.local_function(entity)->evaluate(local_point_entity); - // compute penalty - const size_t max_polorder = std::max(test_base.order(), ansatz_base.order()); - const R sigma = GDT::LocalEllipticIpdgIntegrands::internal::boundary_sigma(max_polorder); - const R gamma = normal * (diffusion * normal); - const auto h = intersection.geometry().volume(); - const auto beta = GDT::LocalEllipticIpdgIntegrands::internal::default_beta(d); - const R penalty = (sigma * gamma) / std::pow(h, beta); - // evaluate bases - const size_t rows = test_base.size(); - const size_t cols = ansatz_base.size(); - const auto test_values = test_base.evaluate(local_point_entity); - const auto ansatz_values = ansatz_base.evaluate(local_point_entity); - // compute integrals, loop over all combinations of basis functions - assert(ret.rows() >= rows && ret.cols() >= cols); - for (size_t ii = 0; ii < rows; ++ii) - for (size_t jj = 0; jj < cols; ++jj) - ret[ii][jj] += penalty * ansatz_values[jj] * test_values[ii]; - }) - { - this->append(local_coupling_operator_, new XT::Grid::ApplyOn::InnerIntersectionsPrimally<GridLayerType>()); - this->append(local_boundary_operator_, new XT::Grid::ApplyOn::DirichletIntersections<GridLayerType>(boundary_info)); - } - - SwipdgPenaltySubdomainProduct(const ThisType&) = delete; - SwipdgPenaltySubdomainProduct(ThisType&&) = delete; - -private: - const ScalarFunctionType& lambda_; - const TensorFunctionType& kappa_; - const size_t over_integrate_; - const GDT::LocalCouplingIntegralOperator<GDT::LocalLambdaQuaternaryFaceIntegrand<E, I>, BasisType, I> - local_coupling_operator_; - const GDT::LocalBoundaryIntegralOperator<GDT::LocalLambdaBinaryFaceIntegrand<E, I>, BasisType, I> - local_boundary_operator_; -}; // class SwipdgPenaltySubdomainProduct - - -template <class G> -void bind_neighborhood_discretization(pybind11::module& m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - typedef typename G::template Codim<0>::Entity E; - typedef double D; - static const constexpr size_t d = 2; - typedef double R; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> DF; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, d, d> DT; - - typedef typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain_oversampled, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type NGL; - typedef GDT:: - SpaceProvider<G, XT::Grid::Layers::dd_subdomain, GDT::SpaceType::block_dg, GDT::Backends::gdt, 1, double, 1> - SP; - typedef typename SP::type S; - typedef XT::LA::IstlDenseVector<R> V; - typedef XT::LA::IstlRowMajorSparseMatrix<R> M; - - try { // we might not be the first to add this SystemAssembler - GDT::bindings::SystemAssembler<SP, XT::Grid::Layers::dd_subdomain_oversampled, XT::Grid::Backends::view>::bind(m); - } catch (std::runtime_error&) { - } - - m.def("RS2017_make_neighborhood_system_assembler", - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - const S& neighborhood_space) { - return new GDT::SystemAssembler<S, NGL>( - neighborhood_space, - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain_oversampled, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain))); - }); - - typedef GDT:: - EllipticIpdgMatrixOperator<DF, DT, S, GDT::LocalEllipticIpdgIntegrands::Method::swipdg_affine_factor, M, NGL> - DgMatrixOperator; - py::class_<DgMatrixOperator, GDT::SystemAssembler<S, NGL>> dg_matrix_operator( - m, "EllipticIpdgMatrixOperatorNeighborhood"); - dg_matrix_operator.def("matrix", [](DgMatrixOperator& self) { return self.matrix(); }); - - m.def("RS2017_make_elliptic_swipdg_matrix_operator_on_neighborhood", - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<NGL>>& boundary_info, - const S& neighborhood_space, - const DF& lambda, - const DT& kappa, - const ssize_t over_integrate) { - return new DgMatrixOperator( - over_integrate, - boundary_info, - lambda, - kappa, - neighborhood_space, - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain_oversampled, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain))); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "boundary_info"_a, - "neighborhood_space"_a, - "lambda"_a, - "kappa"_a, - "over_integrate"_a = 2); - - typedef GDT::EllipticIpdgDirichletVectorFunctional<DF, - DF, - DT, - S, - GDT::LocalEllipticIpdgIntegrands::Method::swipdg_affine_factor, - V, - NGL> - DgVectorFunctional; - py::class_<DgVectorFunctional, GDT::SystemAssembler<S, NGL>> dg_vector_functional( - m, "EllipticSwipdgVectorFunctionalNeighborhood"); - dg_vector_functional.def("vector", [](DgVectorFunctional& self) { return self.vector(); }); - - m.def("RS2017_make_elliptic_swipdg_vector_functional_on_neighborhood", - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<NGL>>& boundary_info, - const S& neighborhood_space, - const DF& g_D, - const DF& lambda, - const DT& kappa, - const ssize_t over_integrate) { - return new DgVectorFunctional( - over_integrate, - boundary_info, - g_D, - lambda, - kappa, - neighborhood_space, - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain_oversampled, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain))); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "boundary_info"_a, - "neighborhood_space"_a, - "g_D"_a, - "lambda"_a, - "kappa"_a, - "over_integrate"_a = 2); - - typedef GDT::L2VolumeVectorFunctional<DF, S, V, NGL> L2VolumeFunctional; - py::class_<L2VolumeFunctional, GDT::SystemAssembler<S, NGL>> l2_volume_vector_functional( - m, "L2VolumeVectorFunctionalNeighborhood"); - l2_volume_vector_functional.def("vector", [](L2VolumeFunctional& self) { return self.vector(); }); - - m.def("RS2017_make_l2_vector_functional_on_neighborhood", - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - const S& neighborhood_space, - const DF& f, - const ssize_t over_integrate) { - return new L2VolumeFunctional( - over_integrate, - f, - neighborhood_space, - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain_oversampled, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain))); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "neighborhood_space"_a, - "f"_a, - "over_integrate"_a = 2); -} // ... bind_neighborhood_discretization(...) - - -template <class G> -class HdivSemiProduct - : public GDT:: - MatrixOperatorBase<XT::LA::IstlRowMajorSparseMatrix<double>, - GDT::RestrictedSpace<typename GDT::SpaceProvider<G, - XT::Grid::Layers::leaf, - GDT::SpaceType::rt, - GDT::Backends::gdt, - 0, - double, - G::dimension>::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type>, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type> -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef GDT::MatrixOperatorBase<XT::LA::IstlRowMajorSparseMatrix<double>, - GDT::RestrictedSpace<typename GDT::SpaceProvider<G, - XT::Grid::Layers::leaf, - GDT::SpaceType::rt, - GDT::Backends::gdt, - 0, - double, - G::dimension>::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type>, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type> - BaseType; - typedef HdivSemiProduct<G> ThisType; - -public: - using typename BaseType::GridLayerType; - using typename BaseType::RangeSpaceType; - - typedef XT::Grid::extract_entity_t<GridLayerType> E; - typedef XT::Grid::extract_intersection_t<GridLayerType> I; - typedef typename G::ctype D; - static const constexpr size_t d = G::dimension; - typedef double R; - typedef typename RangeSpaceType::BaseFunctionSetType BasisType; - - static void bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - py::class_<ThisType, XT::Grid::Walker<GridLayerType>> c( - m, - XT::Common::to_camel_case("RS2017_Hdiv_semi_product_matrix_operator_subdomain_" - + XT::Grid::bindings::grid_name<G>::value()) - .c_str()); - c.def("assemble", [](ThisType& self) { self.assemble(); }); - c.def("matrix", [](ThisType& self) { return self.matrix(); }); - - m.def("RS2017_make_Hdiv_semi_product_matrix_operator_on_subdomain", - [](const XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - const RangeSpaceType& space, - const size_t over_integrate) { - return new ThisType( - space, - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain)), - over_integrate); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "space"_a, - "over_integrate"_a = 2); - } // ... bind(...) - - HdivSemiProduct(RangeSpaceType space, GridLayerType grd_lyr, const size_t over_integrate = 2) - : BaseType(space, grd_lyr) - , over_integrate_(over_integrate) - , local_operator_( - [&](const auto& test_base, const auto& ansatz_base) { - const auto integrand_order = std::max(ssize_t(test_base.order()) - 1, ssize_t(0)) - + std::max(ssize_t(ansatz_base.order()) - 1, ssize_t(0)); - return size_t(integrand_order) + over_integrate_; - }, - [&](const auto& test_base, const auto& ansatz_base, const auto& local_point, auto& ret) { - const auto test_gradient = test_base.jacobian(local_point); - const auto ansatz_gradient = ansatz_base.jacobian(local_point); - for (size_t ii = 0; ii < test_base.size(); ++ii) - for (size_t jj = 0; jj < ansatz_base.size(); ++jj) { - R test_divergence = 0.; - R ansatz_divergence = 0.; - for (size_t dd = 0; dd < d; ++dd) { - test_divergence += test_gradient[ii][dd][dd]; - ansatz_divergence += ansatz_gradient[jj][dd][dd]; - } - ret[ii][jj] = test_divergence * ansatz_divergence; - } - }) - { - this->append(local_operator_); - } - - HdivSemiProduct(const ThisType&) = delete; - HdivSemiProduct(ThisType&&) = delete; - -private: - const size_t over_integrate_; - const GDT::LocalVolumeIntegralOperator<GDT::LocalLambdaBinaryVolumeIntegrand<E, R, d>, BasisType> local_operator_; -}; // class HdivSemiProduct - - -template <class G> -class ResidualPartFunctional - : public GDT:: - VectorFunctionalBase<XT::LA::IstlDenseVector<double>, - GDT::RestrictedSpace<typename GDT::SpaceProvider<G, - XT::Grid::Layers::leaf, - GDT::SpaceType::rt, - GDT::Backends::gdt, - 0, - double, - G::dimension>::type, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type>, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type> -{ - static_assert(XT::Grid::is_grid<G>::value, ""); - typedef GDT::RestrictedSpace< - typename GDT:: - SpaceProvider<G, XT::Grid::Layers::leaf, GDT::SpaceType::rt, GDT::Backends::gdt, 0, double, G::dimension>:: - type, - typename XT::Grid:: - Layer<G, XT::Grid::Layers::dd_subdomain, XT::Grid::Backends::view, XT::Grid::DD::SubdomainGrid<G>>::type> - RtSpaceType; - typedef GDT::VectorFunctionalBase<XT::LA::IstlDenseVector<double>, - RtSpaceType, - typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type> - BaseType; - typedef ResidualPartFunctional<G> ThisType; - -public: - using typename BaseType::GridLayerType; - using typename BaseType::SpaceType; - - typedef XT::Grid::extract_entity_t<GridLayerType> E; - typedef XT::Grid::extract_intersection_t<GridLayerType> I; - typedef typename G::ctype D; - static const constexpr size_t d = G::dimension; - typedef double R; - typedef XT::Functions::GridFunctionInterface<E, D, d, R, 1> ScalarFunctionType; - typedef typename SpaceType::BaseFunctionSetType BasisType; - - static void bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - py::class_<ThisType, XT::Grid::Walker<GridLayerType>> c( - m, - XT::Common::to_camel_case("RS2017_residual_part_vector_functional_subdomain_" - + XT::Grid::bindings::grid_name<G>::value()) - .c_str()); - c.def("assemble", [](ThisType& self) { self.assemble(); }); - c.def("vector", [](ThisType& self) { return self.vector(); }); - - m.def("RS2017_make_residual_part_vector_functional_on_subdomain", - [](const XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - const SpaceType& space, - const ScalarFunctionType& f, - const size_t over_integrate) { - return new ThisType( - space, - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain)), - f, - over_integrate); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "space"_a, - "f"_a, - "over_integrate"_a = 2); - } // ... bind(...) - - ResidualPartFunctional(SpaceType space, - GridLayerType grd_lyr, - const ScalarFunctionType& f, - const size_t over_integrate = 0) - : BaseType(space, grd_lyr) - , f_(f) - , over_integrate_(over_integrate) - , local_functional_( - [&](const auto& test_base) { - const auto integrand_order = ssize_t(f_.local_function(test_base.entity())->order()) - + std::max(ssize_t(test_base.order()) - 1, ssize_t(0)); - return size_t(integrand_order) + over_integrate_; - }, - [&](const auto& test_base, const auto& local_point, auto& ret) { - const auto local_f = f_.local_function(test_base.entity()); - ret *= 0.; - // f \times \divergence test - const auto test_jacobians = test_base.jacobian(local_point); - for (size_t ii = 0; ii < test_base.size(); ++ii) - for (size_t dd = 0; dd < d; ++dd) - ret[ii] += test_jacobians[ii][dd][dd]; - ret *= local_f->evaluate(local_point); - }) - { - this->append(local_functional_); - } - - ResidualPartFunctional(const ThisType&) = delete; - ResidualPartFunctional(ThisType&&) = delete; - -private: - const ScalarFunctionType& f_; - const size_t over_integrate_; - const GDT::LocalVolumeIntegralFunctional<GDT::LocalLambdaUnaryVolumeIntegrand<E, R, d, 1>, BasisType> - local_functional_; -}; // class ResidualPartFunctional - - -template <class G> -void bind_neighborhood_reconstruction(pybind11::module& m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - typedef typename G::template Codim<0>::Entity E; - typedef double D; - static const constexpr size_t d = 2; - typedef double R; - typedef typename XT::Grid::Layer<G, XT::Grid::Layers::leaf, XT::Grid::Backends::view>::type LeafViewType; - typedef GDT::RaviartThomasSpace<LeafViewType, 0> RtSpaceType; - typedef typename XT::Grid::Layer<G, - XT::Grid::Layers::dd_subdomain_oversampled, - XT::Grid::Backends::view, - XT::Grid::DD::SubdomainGrid<G>>::type NeighborHoodGridLayer; - typedef GDT::RestrictedSpace<RtSpaceType, NeighborHoodGridLayer> NeighborhoodRtSpaceType; - typedef XT::LA::IstlDenseVector<R> VectorType; - typedef GDT:: - LocalizableDiffusiveFluxReconstructionOperator<NeighborHoodGridLayer, - XT::Functions::GridFunctionInterface<E, D, d, R, 1>, - GDT::DiscreteFunction<NeighborhoodRtSpaceType, VectorType>, - GDT::LocalEllipticIpdgIntegrands::Method::swipdg_affine_factor> - LocalizableDiffusiveFluxReconstructionOperatorForRestrictedSpaceType; - - m.def("RS2017_apply_diffusive_flux_reconstruction_in_neighborhood", - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - const XT::Functions::GridFunctionInterface<E, D, d, R, 1>& lambda, - const XT::Functions::GridFunctionInterface<E, D, d, R, d, d>& kappa, - const XT::Functions::GridFunctionInterface<E, D, d, R, 1>& u, - typename LocalizableDiffusiveFluxReconstructionOperatorForRestrictedSpaceType::RangeType& reconstructed_u, - const ssize_t over_integrate) { - py::gil_scoped_release DUNE_UNUSED(release); - LocalizableDiffusiveFluxReconstructionOperatorForRestrictedSpaceType( - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain_oversampled, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain)), - lambda, - kappa, - u, - reconstructed_u, - over_integrate) - .apply(); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "lambda_hat"_a, - "kappa"_a, - "u"_a, - "reconstructed_u"_a, - "over_integrate"_a = 2); - - typedef GDT:: - LocalizableDiffusiveFluxReconstructionOperator<NeighborHoodGridLayer, - XT::Functions::GridFunctionInterface<E, D, d, R, 1>, - GDT::DiscreteFunction<RtSpaceType, VectorType>, - GDT::LocalEllipticIpdgIntegrands::Method::swipdg_affine_factor> - LocalizableDiffusiveFluxReconstructionOperatorForLeafSpaceType; - - m.def("RS2017_apply_diffusive_flux_reconstruction_in_neighborhood", - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider, - const ssize_t subdomain, - const XT::Functions::GridFunctionInterface<E, D, d, R, 1>& lambda, - const XT::Functions::GridFunctionInterface<E, D, d, R, d, d>& kappa, - const XT::Functions::GridFunctionInterface<E, D, d, R, 1>& u, - typename LocalizableDiffusiveFluxReconstructionOperatorForLeafSpaceType::RangeType& reconstructed_u, - const ssize_t over_integrate) { - py::gil_scoped_release DUNE_UNUSED(release); - LocalizableDiffusiveFluxReconstructionOperatorForLeafSpaceType( - dd_grid_provider.template layer<XT::Grid::Layers::dd_subdomain_oversampled, XT::Grid::Backends::view>( - XT::Common::numeric_cast<size_t>(subdomain)), - lambda, - kappa, - u, - reconstructed_u, - over_integrate) - .apply(); - }, - "dd_grid_provider"_a, - "subdomain"_a, - "lambda_hat"_a, - "kappa"_a, - "u"_a, - "reconstructed_u"_a, - "over_integrate"_a = 2); -} // ... bind_neighborhood_reconstruction(...) - - -# else // HAVE_DUNE_ISTL - - -template <class G> -class DiffusiveFluxAaProduct -{ - static_assert(AlwaysFalse<G>::value, "You are missing dune-istl!"); -}; - - -template <class G> -class DiffusiveFluxAbProduct -{ - static_assert(AlwaysFalse<G>::value, "You are missing dune-istl!"); -}; - - -template <class G> -class DiffusiveFluxBbProduct -{ - static_assert(AlwaysFalse<G>::value, "You are missing dune-istl!"); -}; - - -template <class G> -class SwipdgPenaltySubdomainProduct -{ - static_assert(AlwaysFalse<G>::value, "You are missing dune-istl!"); -}; - - -template <class G> -void bind_neighborhood_discretization(pybind11::module& /*m*/) -{ - static_assert(AlwaysFalse<G>::value, "You are missing dune-istl!"); -} - - -template <class G> -class HdivSemiProduct -{ - static_assert(AlwaysFalse<G>::value, "You are missing dune-istl!"); -}; - - -template <class G> -class ResidualPartFunctional -{ - static_assert(AlwaysFalse<G>::value, "You are missing dune-istl!"); -}; - - -template <class G> -void bind_neighborhood_reconstruction(pybind11::module& /*m*/) -{ - static_assert(AlwaysFalse<G>::value, "You are missing dune-istl!"); -} - - -# endif // HAVE_DUNE_ISTL - -} // namespace RS2017 -} // namespace GDT -} // namespace Dune - -#endif // 0 -#endif // DUNE_GDT_PLAYGROUND_OPERATORS_RS2017_HH diff --git a/python/dune/gdt/playground/spaces/block.hh b/python/dune/gdt/playground/spaces/block.hh deleted file mode 100644 index 7cbadcd95ff233850b9ee8a0c96614200a18abd0..0000000000000000000000000000000000000000 --- a/python/dune/gdt/playground/spaces/block.hh +++ /dev/null @@ -1,453 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_PLAYGROUND_SPACES_BLOCK_BINDINGS_HH -#define PYTHON_DUNE_GDT_PLAYGROUND_SPACES_BLOCK_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/grid/common/rangegenerators.hh> - -# include <dune/xt/common/numeric_cast.hh> -# include <dune/xt/common/string.hh> -# include <dune/xt/la/container.hh> -# include <dune/xt/grid/gridprovider/provider.hh> -# include <dune/xt/grid/dd/subdomains/grid.hh> -# include <python/dune/xt/grid/grids.bindings.hh> - -# include <dune/gdt/assembler/system.hh> -# include <dune/gdt/discretefunction/default.hh> -# include <dune/gdt/projections.hh> -# include <dune/gdt/spaces/bindings.hh> -# include <dune/gdt/type_traits.hh> - -# include <dune/gdt/playground/spaces/block.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class SP> -class BlockMapper -{ - typedef typename SP::type S; - static_assert(is_space<S>::value, ""); - using G = XT::Grid::extract_grid_t<typename S::GridLayerType>; - -public: - typedef GDT::BlockMapper<S> type; - typedef pybind11::class_<type> bound_type; - - template <XT::LA::Backends la> - static void addbind_matrix(bound_type& c) - { - namespace py = pybind11; - using namespace pybind11::literals; - - typedef typename XT::LA::Container<double, la>::MatrixType M; - - c.def("copy_local_to_global", - [](const type& self, - const M& local_matrix, - const XT::LA::SparsityPatternDefault& local_pattern, - const ssize_t block, - M& global_matrix) { - auto bb = XT::Common::numeric_cast<size_t>(block); - for (size_t local_ii = 0; local_ii < local_pattern.size(); ++local_ii) { - const size_t global_ii = self.mapToGlobal(bb, local_ii); - for (const size_t& local_jj : local_pattern.inner(local_ii)) { - const size_t global_jj = self.mapToGlobal(bb, local_jj); - global_matrix.add_to_entry(global_ii, global_jj, local_matrix.get_entry(local_ii, local_jj)); - } - } - }, - "local_matrix"_a, - "local_sparsity_pattern"_a, - "block"_a, - "global_matrix"_a); - c.def("copy_local_to_global", - [](const type& self, - const M& local_matrix, - const XT::LA::SparsityPatternDefault& local_pattern, - const ssize_t test_block, - const ssize_t ansatz_block, - M& global_matrix) { - auto tt = XT::Common::numeric_cast<size_t>(test_block); - auto aa = XT::Common::numeric_cast<size_t>(ansatz_block); - for (size_t local_ii = 0; local_ii < local_pattern.size(); ++local_ii) { - const size_t global_ii = self.mapToGlobal(tt, local_ii); - for (const size_t& local_jj : local_pattern.inner(local_ii)) { - const size_t global_jj = self.mapToGlobal(aa, local_jj); - global_matrix.add_to_entry(global_ii, global_jj, local_matrix.get_entry(local_ii, local_jj)); - } - } - }, - "local_matrix"_a, - "local_sparsity_pattern"_a, - "test_block"_a, - "ansatz_block"_a, - "global_matrix"_a); - } // ... addbind_matrix(...) - - template <XT::LA::Backends la> - static void addbind_vector(bound_type& c) - { - namespace py = pybind11; - using namespace pybind11::literals; - - typedef typename XT::LA::Container<double, la>::VectorType V; - - c.def("copy_local_to_global", - [](const type& self, const V& local_vector, const ssize_t block, V& global_vector) { - auto bb = XT::Common::numeric_cast<size_t>(block); - for (size_t local_ii = 0; local_ii < local_vector.size(); ++local_ii) { - const size_t global_ii = self.mapToGlobal(bb, local_ii); - global_vector.add_to_entry(global_ii, local_vector.get_entry(local_ii)); - } - }, - "local_vector"_a, - "block"_a, - "global_vector"_a); - } // ... addbind_vector(...) - - static bound_type bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto ClassName = XT::Common::to_camel_case("block_" + space_name<SP>::value() + "_mappe"); - - bound_type c(m, ClassName.c_str()); - - c.def_property_readonly("size", [](const type& self) { return self.size(); }); - - // sparsity patterns - c.def("copy_local_to_global", - [](const type& self, - const XT::LA::SparsityPatternDefault& local_pattern, - const ssize_t block, - XT::LA::SparsityPatternDefault& global_pattern) { - auto bb = XT::Common::numeric_cast<size_t>(block); - for (size_t local_ii = 0; local_ii < local_pattern.size(); ++local_ii) { - const size_t global_ii = self.mapToGlobal(bb, local_ii); - const auto& local_rows = local_pattern.inner(local_ii); - for (const auto& local_jj : local_rows) { - const size_t global_jj = self.mapToGlobal(bb, local_jj); - global_pattern.insert(global_ii, global_jj); - } - } - }, - "local_sparsity_pattern"_a, - "block"_a, - "global_sparsity_pattern"_a); - c.def("copy_local_to_global", - [](const type& self, - const XT::LA::SparsityPatternDefault& local_pattern, - const ssize_t test_block, - const ssize_t ansatz_block, - XT::LA::SparsityPatternDefault& global_pattern) { - auto tt = XT::Common::numeric_cast<size_t>(test_block); - auto aa = XT::Common::numeric_cast<size_t>(ansatz_block); - for (size_t local_ii = 0; local_ii < local_pattern.size(); ++local_ii) { - const size_t global_ii = self.mapToGlobal(tt, local_ii); - const auto& local_rows = local_pattern.inner(local_ii); - for (const auto& local_jj : local_rows) { - const size_t global_jj = self.mapToGlobal(aa, local_jj); - global_pattern.insert(global_ii, global_jj); - } - } - }, - "local_sparsity_pattern"_a, - "test_block"_a, - "ansatz_block"_a, - "global_sparsity_pattern"_a); - - // matrices - addbind_matrix<XT::LA::Backends::common_dense>(c); - addbind_matrix<XT::LA::Backends::common_sparse>(c); -# if HAVE_EIGEN - addbind_matrix<XT::LA::Backends::eigen_dense>(c); - addbind_matrix<XT::LA::Backends::eigen_sparse>(c); -# endif -# if HAVE_DUNE_ISTL - addbind_matrix<XT::LA::Backends::istl_sparse>(c); -# endif - - // vectors - addbind_vector<XT::LA::Backends::common_dense>(c); -# if HAVE_EIGEN - addbind_vector<XT::LA::Backends::eigen_dense>(c); -# endif -# if HAVE_DUNE_ISTL - addbind_vector<XT::LA::Backends::istl_dense>(c); -# endif - - return c; - } // ... bind(...) -}; // class BlockMapper - - -template <class SP> -class BlockSpace -{ - typedef typename SP::type S; - static_assert(is_space<S>::value, ""); - using G = XT::Grid::extract_grid_t<typename S::GridLayerType>; - -public: - typedef GDT::BlockSpace<S> type; - typedef pybind11::class_<type> bound_type; - -private: - template <bool is_dg = (SP::space_type == SpaceType::dg), bool anything = false> - struct projector - { - template <class V> - static V project(const type& self, const std::vector<V>& local_vectors, const std::vector<size_t>& subdomains) - { - V neighborhood_vector(self.mapper().size(), 0.); - assert(local_vectors.size() == subdomains.size() && "This should not happen, blame the caller!"); - for (size_t ii = 0; ii < local_vectors.size(); ++ii) { - const auto subdomain = subdomains[ii]; - const auto& local_vector = local_vectors[ii]; - for (size_t jj = 0; jj < local_vector.size(); ++jj) - neighborhood_vector[self.mapper().mapToGlobal(subdomain, jj)] = local_vector[jj]; - } - return neighborhood_vector; - } - }; // struct projector<true, ...> - - template <bool anything> - struct projector<false, anything> - { - template <class V> - static V project(const type&, const std::vector<V>&, const std::vector<size_t>&) - { - static_assert(AlwaysFalse<V>::value, "Not implemented for non DG spaces"); - } - }; - - template <XT::LA::Backends la> - static void addbind_vector(bound_type& c) - { - namespace py = pybind11; - using namespace pybind11::literals; - - typedef typename XT::LA::Container<double, la>::VectorType V; - - c.def("project_onto_neighborhood", - [](const type& self, const std::vector<V>& local_vectors, const std::vector<ssize_t>& neighborhood) { - if (local_vectors.size() != neighborhood.size()) - DUNE_THROW(XT::Common::Exceptions::shapes_do_not_match, - "local_vectors.size(): " << local_vectors.size() << "\n neighborhood.size(): " - << neighborhood.size()); - std::vector<size_t> subdomains(neighborhood.size()); - for (size_t ii = 0; ii < neighborhood.size(); ++ii) - subdomains[ii] = XT::Common::numeric_cast<size_t>(neighborhood[ii]); - std::vector<std::shared_ptr<const S>> neighborhood_spaces(self.dd_grid().size(), nullptr); - for (const auto& subdomain : subdomains) { - if (self.backend()[subdomain] == nullptr) - DUNE_THROW(XT::Common::Exceptions::you_are_using_this_wrong, - "This BlockSpace (restricted to a neighborhood) does not have a local space for subdomain " - << subdomain - << "!"); - neighborhood_spaces[subdomain] = self.backend()[subdomain]; - } - const type neighborhood_space(self.dd_grid(), neighborhood_spaces); - return projector<>::project(neighborhood_space, local_vectors, subdomains); - }, - "local_vectors"_a, - "neighborhood"_a); - } // ... addbind_vector(...) - -public: - static bound_type bind(pybind11::module& m) - { - BlockMapper<SP>::bind(m); - - namespace py = pybind11; - using namespace pybind11::literals; - - const auto ClassName = XT::Common::to_camel_case("block_" + space_name<SP>::value()); - - bound_type c(m, ClassName.c_str(), ClassName.c_str()); // metaclass required for static properties - - c.def("__init__", - [](type& self, XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider) { - const auto& dd_grid = dd_grid_provider.dd_grid(); - std::vector<std::shared_ptr<const S>> local_spaces(dd_grid.size()); - for (size_t ss = 0; ss < dd_grid.size(); ++ss) - local_spaces[ss] = std::make_shared<S>(SP::create(dd_grid_provider, boost::numeric_cast<int>(ss))); - try { - new (&self) type(dd_grid, local_spaces); - } catch (...) { - self.~type(); - throw; - } - }, - "dd_grid"_a, - py::keep_alive<1, 2>()); - c.def_property_readonly("dimDomain", [](const type& /*self*/) { return S::dimDomain; }); - c.def_property_readonly("dimRange", [](const type& /*self*/) { return S::dimRange; }); - c.def_property_readonly("dimRangeCols", [](const type& /*self*/) { return S::dimRangeCols; }); - c.def_property_readonly("polOrder", [](const type& /*self*/) { return S::polOrder; }); - c.def_property_readonly("num_blocks", [](const type& self) { return self.num_blocks(); }); - c.def_property_readonly("mapper", - [](const type& self) { - // we get a segfault without the explicit copy - return std::decay_t<decltype(self.mapper())>(self.mapper()); - }, - py::keep_alive<0, 1>()); - // these need to be defined *after* their non static counterparts - c.def_property_readonly_static("dimDomain", [](const type& /*self*/) { return S::dimDomain; }); - c.def_property_readonly_static("dimRange", [](const type& /*self*/) { return S::dimRange; }); - c.def_property_readonly_static("dimRangeCols", [](const type& /*self*/) { return S::dimRangeCols; }); - c.def_property_readonly_static("polOrder", [](const type& /*self*/) { return S::polOrder; }); - c.def("local_space", - [](const type& self, ssize_t block) { return self.local_space(XT::Common::numeric_cast<size_t>(block)); }, - "block"_a); - c.def("compute_boundary_pattern", - [](const type& self, const ssize_t block, const std::string tp) { - auto bb = XT::Common::numeric_cast<size_t>(block); - if (tp == "volume") - return self.local_space(bb).compute_volume_pattern(self.dd_grid().boundary_grid_view(bb)); - else if (tp == "face") - return self.local_space(bb).compute_face_pattern(self.dd_grid().boundary_grid_view(bb)); - else if (tp == "face_and_volume") - return self.local_space(bb).compute_face_and_volume_pattern(self.dd_grid().boundary_grid_view(bb)); - else - DUNE_THROW(XT::Common::Exceptions::wrong_input_given, - " type has to be one of ('volume', 'face', 'face_and_volume'), is '" << tp << "'!"); - // we will never get here - return XT::LA::SparsityPatternDefault(); - }, - "block"_a, - "type"_a); - c.def("compute_coupling_pattern", - [](const type& self, const ssize_t subdomain, const ssize_t neighbor, const std::string tp) { - auto ss = XT::Common::numeric_cast<size_t>(subdomain); - auto nn = XT::Common::numeric_cast<size_t>(neighbor); - if (tp == "volume") - return self.local_space(ss).compute_volume_pattern(self.dd_grid().coupling_grid_view(ss, nn), - self.local_space(nn)); - else if (tp == "face") - return self.local_space(ss).compute_face_pattern(self.dd_grid().coupling_grid_view(ss, nn), - self.local_space(nn)); - else if (tp == "face_and_volume") - return self.local_space(ss).compute_face_and_volume_pattern(self.dd_grid().coupling_grid_view(ss, nn), - self.local_space(nn)); - else - DUNE_THROW(XT::Common::Exceptions::wrong_input_given, - " type has to be one of ('volume', 'face', 'face_and_volume'), is '" << tp << "'!"); - // we will never get here - return XT::LA::SparsityPatternDefault(); - }, - "block_subdomain"_a, - "neighboring_subdomain"_a, - "type"_a); - c.def("boundary_assembler", - [](const type& self, const ssize_t subdomain) { - auto ss = XT::Common::numeric_cast<size_t>(subdomain); - auto boundary_grid_part = self.dd_grid().boundary_grid_view(ss); - return new GDT::SystemAssembler<S, decltype(boundary_grid_part), S>(self.local_space(ss), // see below for - boundary_grid_part); // the 'new' - }, - "subdomain"_a); - c.def("coupling_assembler", - [](const type& self, const ssize_t subdomain, const ssize_t neighbor) { - auto ss = XT::Common::numeric_cast<size_t>(subdomain); - auto nn = XT::Common::numeric_cast<size_t>(neighbor); - auto coupling_grid_part = self.dd_grid().coupling_grid_view(ss, nn); - return new GDT::SystemAssembler<S, decltype(coupling_grid_part), S>(coupling_grid_part, // SystemAssembler - self.local_space(ss), // is not copyable - self.local_space(ss), // or movable, - self.local_space(nn), // thus the raw - self.local_space(nn)); // pointer - }, - "subdomain"_a, - "neighbor"_a); - c.def("restricted_to_neighborhood", - [](const type& self, const std::vector<ssize_t>& neighborhood) { - std::vector<std::shared_ptr<const S>> neighborhood_spaces(self.dd_grid().size(), nullptr); - for (const auto& subdomain : neighborhood) - neighborhood_spaces[subdomain] = self.backend()[XT::Common::numeric_cast<size_t>(subdomain)]; - return type(self.dd_grid(), neighborhood_spaces); - }, - "neighborhood"_a); - - addbind_vector<XT::LA::Backends::common_dense>(c); -# if HAVE_EIGEN - addbind_vector<XT::LA::Backends::eigen_dense>(c); -# endif -# if HAVE_DUNE_ISTL - addbind_vector<XT::LA::Backends::istl_dense>(c); -# endif - - const std::string factory_method_name = "make_block_" + space_name<SP>::value_wo_grid(); - m.def(factory_method_name.c_str(), - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& dd_grid_provider) { - const auto& dd_grid = dd_grid_provider.dd_grid(); - std::vector<std::shared_ptr<const S>> local_spaces(dd_grid.size()); - for (size_t ss = 0; ss < dd_grid.size(); ++ss) - local_spaces[ss] = std::make_shared<S>(SP::create(dd_grid_provider, boost::numeric_cast<int>(ss))); - return type(dd_grid, local_spaces); - }, - "dd_grid_provider"_a); - - return c; - } // ... bind(...) -}; // class BlockSpace - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_SPACES_BLOCK_BIND(_m, _GRID, _s_type, _s_backend, _p) \ - Dune::GDT::bindings::BlockSpace<Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::dd_subdomain, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>>::bind(_m) - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_SPACES_BLOCK_BIND_ALU(_m, _s_type, _s_backend, _p) \ - _DUNE_GDT_SPACES_BLOCK_BIND(_m, ALU_2D_SIMPLEX_CONFORMING, _s_type, _s_backend, _p) -# else -# define _DUNE_GDT_SPACES_BLOCK_BIND_ALU(_m, _s_type, _s_backend, _p) -# endif - -# define _DUNE_GDT_SPACES_BLOCK_BIND_YASP(_m, _s_type, _s_backend, _p) \ - _DUNE_GDT_SPACES_BLOCK_BIND(_m, YASP_1D_EQUIDISTANT_OFFSET, _s_type, _s_backend, _p); \ - _DUNE_GDT_SPACES_BLOCK_BIND(_m, YASP_2D_EQUIDISTANT_OFFSET, _s_type, _s_backend, _p) - -# define _DUNE_GDT_SPACES_BLOCK_BIND_ALL_GRIDS(_m, _s_type, _s_backend, _p) \ - _DUNE_GDT_SPACES_BLOCK_BIND_ALU(_m, _s_type, _s_backend, _p); \ - _DUNE_GDT_SPACES_BLOCK_BIND_YASP(_m, _s_type, _s_backend, _p) - - -# define DUNE_GDT_SPACES_BLOCK_BIND(_m) _DUNE_GDT_SPACES_BLOCK_BIND_ALL_GRIDS(_m, dg, gdt, 1) -# define _DUNE_GDT_SPACES_BLOCK_BIND_FEM(_m) _DUNE_GDT_SPACES_BLOCK_BIND_ALL_GRIDS(_m, dg, gdt, 1) - -// end: this is what we need for the .so - - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_PLAYGROUND_SPACES_BLOCK_BINDINGS_HH diff --git a/python/dune/gdt/projections/bindings.cc b/python/dune/gdt/projections/bindings.cc deleted file mode 100644 index 93fcf43079acac3c27f171673526cfeda60ca0ba..0000000000000000000000000000000000000000 --- a/python/dune/gdt/projections/bindings.cc +++ /dev/null @@ -1,46 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017) -// René Fritze (2018) - -#include "config.h" - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <python/dune/gdt/shared.hh> - -# include <dune/gdt/projections/bindings.hh> -# include <python/dune/gdt/projections/dirichlet.hh> - - -PYBIND11_MODULE(__projections, m) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - Dune::XT::Common::bindings::addbind_exceptions(m); - - py::module::import("dune.xt.common"); - py::module::import("dune.xt.grid"); - py::module::import("dune.xt.functions"); - py::module::import("dune.xt.la"); - py::module::import("dune.gdt.__spaces"); - - DUNE_GDT_PROJECTIONS_BIND(m); - DUNE_GDT_PROJECTIONS_DIRICHLET_BIND(m); - - add_initialization(m, "dune.gdt.projections"); -} - -#endif // HAVE_DUNE_PYBINDXI diff --git a/python/dune/gdt/projections/bindings.hh b/python/dune/gdt/projections/bindings.hh deleted file mode 100644 index 90f8401e30ed493ba3f66e13d9ea595efd44ba26..0000000000000000000000000000000000000000 --- a/python/dune/gdt/projections/bindings.hh +++ /dev/null @@ -1,150 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_PROJECTIONS_BINDINGS_HH -#define PYTHON_DUNE_GDT_PROJECTIONS_BINDINGS_HH - -// Todo: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <python/dune/xt/grid/grids.bindings.hh> -# include <python/dune/xt/la/container.bindings.hh> - -# include <dune/gdt/spaces/bindings.hh> -# include <dune/gdt/type_traits.hh> - -# include <dune/gdt/projections.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class SP, class V> -class project -{ - typedef typename SP::type SpaceType; - static_assert(is_space<SpaceType>::value, ""); - static_assert(XT::LA::is_vector<V>::value, ""); - typedef typename XT::Functions::GridFunctionInterface<typename SpaceType::EntityType, - typename SpaceType::DomainFieldType, - SpaceType::dimDomain, - typename SpaceType::RangeFieldType, - SpaceType::dimRange, - SpaceType::dimRangeCols> - SourceType; - typedef DiscreteFunction<SpaceType, V> RangeType; - -public: - static void bind(pybind11::module& m) - { - using namespace pybind11::literals; - - m.def("project", - [](const SourceType& source, RangeType& range, const size_t over_integrate) { - GDT::project(source, range, over_integrate); - }, - "source"_a, - "range"_a, - "over_integrate"_a = 0); - } // ... bind(...) -}; // class project - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_PROJECTIONS_BIND(_m, _GRID, _g_layer, _s_backend, _s_type, _p, _la) \ - Dune::GDT::bindings::project< \ - Dune::GDT::SpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_g_layer, \ - Dune::GDT::SpaceType::_s_type, \ - Dune::GDT::Backends::_s_backend, \ - _p, \ - double, \ - 1, \ - 1>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>::bind(_m) - -// for each grid - -//#if HAVE_ALBERTA -// ... -//#else -# define _DUNE_GDT_PROJECTIONS_BIND_ALBERTA(_m, _g_layer, _s_backend, _s_type, _p, _la) -//#endif - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_PROJECTIONS_BIND_ALU(_m, _g_layer, _s_backend, _s_type, _p, _la) \ - _DUNE_GDT_PROJECTIONS_BIND(_m, ALU_2D_SIMPLEX_CONFORMING, _g_layer, _s_backend, _s_type, _p, _la) -# else -# define _DUNE_GDT_PROJECTIONS_BIND_ALU(_m, _g_layer, _s_backend, _s_type, _p, _la) -# endif - -//#if HAVE_DUNE_UGGRID || HAVE_UG -// ... -//#else -# define _DUNE_GDT_PROJECTIONS_BIND_UG(_m, _g_layer, _s_backend, _s_type, _p, _la) -//#endif - -# define _DUNE_GDT_PROJECTIONS_BIND_YASP(_m, _g_layer, _s_backend, _s_type, _p, _la) \ - _DUNE_GDT_PROJECTIONS_BIND(_m, YASP_1D_EQUIDISTANT_OFFSET, _g_layer, _s_backend, _s_type, _p, _la); \ - _DUNE_GDT_PROJECTIONS_BIND(_m, YASP_2D_EQUIDISTANT_OFFSET, _g_layer, _s_backend, _s_type, _p, _la) - -# define _DUNE_GDT_PROJECTIONS_BIND_ALL_GRIDS(_m, _g_layer, _s_backend, _s_type, _p, _la) \ - _DUNE_GDT_PROJECTIONS_BIND_ALBERTA(_m, _g_layer, _s_backend, _s_type, _p, _la); \ - _DUNE_GDT_PROJECTIONS_BIND_ALU(_m, _g_layer, _s_backend, _s_type, _p, _la); \ - _DUNE_GDT_PROJECTIONS_BIND_UG(_m, _g_layer, _s_backend, _s_type, _p, _la); \ - _DUNE_GDT_PROJECTIONS_BIND_YASP(_m, _g_layer, _s_backend, _s_type, _p, _la) - -// for each space backend - -# define _DUNE_GDT_PROJECTIONS_BIND_DEFAULT(_m, _la) \ - _DUNE_GDT_PROJECTIONS_BIND_ALL_GRIDS(_m, leaf, gdt, fv, 0, _la); \ - _DUNE_GDT_PROJECTIONS_BIND_ALL_GRIDS(_m, dd_subdomain, gdt, cg, 1, _la); \ - _DUNE_GDT_PROJECTIONS_BIND_ALL_GRIDS(_m, level, gdt, fv, 0, _la); \ - _DUNE_GDT_PROJECTIONS_BIND_ALL_GRIDS(_m, dd_subdomain, gdt, dg, 1, _la) - - -# define _DUNE_GDT_PROJECTIONS_BIND_ALL_SPACES(_m, _la) _DUNE_GDT_PROJECTIONS_BIND_DEFAULT(_m, _la); - -// for each la backend - -//#define _DUNE_GDT_PROJECTIONS_BIND_COMMON(_m) _DUNE_GDT_PROJECTIONS_BIND_ALL_SPACES(_m, common_dense) -# define _DUNE_GDT_PROJECTIONS_BIND_COMMON(_m) - -//#if HAVE_EIGEN -//#define _DUNE_GDT_PROJECTIONS_BIND_EIGEN(_m) _DUNE_GDT_PROJECTIONS_BIND_ALL_SPACES(_m, eigen_dense) -//#else -# define _DUNE_GDT_PROJECTIONS_BIND_EIGEN(_m) -//#endif - -# if HAVE_DUNE_ISTL -# define _DUNE_GDT_PROJECTIONS_BIND_ISTL(_m) _DUNE_GDT_PROJECTIONS_BIND_ALL_SPACES(_m, istl_dense) -# else -# define _DUNE_GDT_PROJECTIONS_BIND_ISTL(_m) -# endif - -# define DUNE_GDT_PROJECTIONS_BIND(_m) \ - _DUNE_GDT_PROJECTIONS_BIND_COMMON(_m); \ - _DUNE_GDT_PROJECTIONS_BIND_EIGEN(_m); \ - _DUNE_GDT_PROJECTIONS_BIND_ISTL(_m) - -// end: this is what we need for the .so - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_PROJECTIONS_BINDINGS_HH diff --git a/python/dune/gdt/projections/dirichlet.hh b/python/dune/gdt/projections/dirichlet.hh deleted file mode 100644 index 50038a1b68ec8134db849d5f4af8e6302bfbcece..0000000000000000000000000000000000000000 --- a/python/dune/gdt/projections/dirichlet.hh +++ /dev/null @@ -1,160 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_PROJECTIONS_DIRICHLET_BINDINGS_HH -#define PYTHON_DUNE_GDT_PROJECTIONS_DIRICHLET_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <python/dune/xt/grid/grids.bindings.hh> -# include <python/dune/xt/la/container.bindings.hh> - -# include <dune/gdt/spaces/bindings.hh> -# include <dune/gdt/type_traits.hh> - -# include <dune/gdt/projections/dirichlet.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class SP, class V> -class DirichletProjectionLocalizableOperator -{ - typedef typename SP::type SpaceType; - static_assert(is_space<SpaceType>::value, ""); - static_assert(XT::LA::is_vector<V>::value, ""); - typedef typename SpaceType::GridLayerType GridLayerType; - typedef typename XT::Functions::GridFunctionInterface<typename SpaceType::EntityType, - typename SpaceType::DomainFieldType, - SpaceType::dimDomain, - typename SpaceType::RangeFieldType, - SpaceType::dimRange, - SpaceType::dimRangeCols> - SourceType; - typedef DiscreteFunction<SpaceType, V> RangeType; - typedef XT::Grid::Walker<GridLayerType> BaseType; - -public: - typedef GDT::DirichletProjectionLocalizableOperator<GridLayerType, SourceType, RangeType, double> type; - typedef pybind11::class_<type, BaseType> bound_type; - - static bound_type bind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto ClassName = - XT::Common::to_camel_case("dirichlet_projection_localizable_operator_" + space_name<SP>::value() + "_" - + XT::LA::bindings::container_name<V>::value()); - - bound_type c(m, ClassName.c_str()); - c.def("apply", [](type& self) { self.apply(); }); - - m.def(std::string("make_localizable_dirichlet_projection_operator").c_str(), - [](const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<GridLayerType>>& boundary_info, - const SourceType& source, - RangeType& range) { - return make_localizable_dirichlet_projection_operator( - range.space().grid_layer(), boundary_info, source, range) - .release(); - }, - "boundary_info"_a, - "source"_a, - "range"_a, - py::keep_alive<0, 1>(), - py::keep_alive<0, 2>(), - py::keep_alive<0, 3>()); - - return c; - } // ... bind(...) -}; // class DirichletProjectionLocalizableOperator - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND(_m, _GRID, _layer, _backend, _r, _rC, _la) \ - Dune::GDT::bindings::DirichletProjectionLocalizableOperator< \ - Dune::GDT:: \ - CgSpaceProvider<_GRID, Dune::XT::Grid::Layers::_layer, Dune::GDT::Backends::_backend, 1, double, _r, _rC>, \ - typename Dune::XT::LA::Container<double, Dune::XT::LA::Backends::_la>::VectorType>::bind(_m) - -/* -#if HAVE_ALBERTA -#define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_ALBERTA(_m, _layer, _backend, _la) \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND(_m, ALBERTA_2D, _layer, _backend, 1, 1, _la) -#else -*/ -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_ALBERTA(_m, _layer, _backend, _la) -//#endif - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_ALU(_m, _layer, _backend, _la) \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND(_m, ALU_2D_SIMPLEX_CONFORMING, _layer, _backend, 1, 1, _la) -# else -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_ALU(_m, _layer, _backend, _la) -# endif - -/* -#if HAVE_DUNE_UGGRID || HAVE_UG -#define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_UG(_m, _layer, _backend, _la) \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND(_m, UG_2D, _layer, _backend, 1, 1, _la) -#else -*/ -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_UG(_m, _layer, _backend, _la) -//#endif - -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_YASP(_m, _layer, _backend, _la) \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND(_m, YASP_1D_EQUIDISTANT_OFFSET, _layer, _backend, 1, 1, _la); \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND(_m, YASP_2D_EQUIDISTANT_OFFSET, _layer, _backend, 1, 1, _la) - -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_GDT(_m, _la) \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_ALBERTA(_m, leaf, gdt, _la); \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_ALU(_m, leaf, gdt, _la); \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_UG(_m, leaf, gdt, _la); \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_YASP(_m, leaf, gdt, _la) - - -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_BACKENDS(_m, _la) _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_GDT(_m, _la); - -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_COMMON(_m) -//_DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_BACKENDS(_m, common_dense) - -//#if HAVE_EIGEN -//#define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_EIGEN(_m) _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_BACKENDS(_m, eigen_dense) -//#else -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_EIGEN(_m) -//#endif - -# if HAVE_DUNE_ISTL -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_ISTL(_m) _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_BACKENDS(_m, istl_dense) -# else -# define _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_ISTL(_m) -# endif - - -# define DUNE_GDT_PROJECTIONS_DIRICHLET_BIND(_m) \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_COMMON(_m); \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_EIGEN(_m); \ - _DUNE_GDT_PROJECTIONS_DIRICHLET_BIND_ISTL(_m) - -// end: this is what we need for the .so - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_PROJECTIONS_DIRICHLET_BINDINGS_HH diff --git a/python/dune/gdt/shared.hh b/python/dune/gdt/shared.hh deleted file mode 100644 index bd622d28ab1f7918c5afb5b8a3eda5279aebed75..0000000000000000000000000000000000000000 --- a/python/dune/gdt/shared.hh +++ /dev/null @@ -1,76 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017) -// René Fritze (2018) -// -// Created by r_milk01 on 2/7/18. - -#ifndef PYTHON_DUNE_GDT_SHARED_HH -#define PYTHON_DUNE_GDT_SHARED_HH - -#if HAVE_DUNE_PYBINDXI - -# include <dune/common/parallel/mpihelper.hh> - -# include <dune/pybindxi/pybind11.h> -# include <dune/pybindxi/stl.h> - -# include <python/dune/xt/common/bindings.hh> -# include <dune/xt/common/numeric_cast.hh> -# include <dune/xt/common/timedlogging.hh> - -void add_initialization(pybind11::module& m, std::string logger_name) -{ - namespace py = pybind11; - using namespace pybind11::literals; - - m.def("_init_mpi", - [](const std::vector<std::string>& args) { - int argc = Dune::XT::Common::numeric_cast<int>(args.size()); - char** argv = Dune::XT::Common::vector_to_main_args(args); - Dune::MPIHelper::instance(argc, argv); - }, - "args"_a = std::vector<std::string>()); - - m.def("_init_logger", - [](const ssize_t max_info_level, - const ssize_t max_debug_level, - const bool enable_warnings, - const bool enable_colors, - const std::string& info_color, - const std::string& debug_color, - const std::string& warning_color) { - Dune::XT::Common::TimedLogger().create( - max_info_level, max_debug_level, enable_warnings, enable_colors, info_color, debug_color, warning_color); - }, - "max_info_level"_a = std::numeric_limits<ssize_t>::max(), - "max_debug_level"_a = std::numeric_limits<ssize_t>::max(), - "enable_warnings"_a = true, - "enable_colors"_a = true, - "info_color"_a = "blue", - "debug_color"_a = "darkgray", - "warning_color"_a = "red"); - - m.def("_test_logger", - [=](const bool info, const bool debug, const bool warning) { - auto logger = Dune::XT::Common::TimedLogger().get(logger_name); - if (info) - logger.info() << "info logging works!" << std::endl; - if (debug) - logger.debug() << "debug logging works!" << std::endl; - if (warning) - logger.warn() << "warning logging works!" << std::endl; - }, - "info"_a = true, - "debug"_a = true, - "warning"_a = true); -} - -#endif // HAVE_DUNE_PYBINDXI - -#endif // PYTHON_DUNE_GDT_SHARED_HH diff --git a/python/dune/gdt/spaces/bindings.hh b/python/dune/gdt/spaces/bindings.hh deleted file mode 100644 index fed318daa80532403034da6168c748afe2be4e35..0000000000000000000000000000000000000000 --- a/python/dune/gdt/spaces/bindings.hh +++ /dev/null @@ -1,26 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_SPACES_BINDINGS_HH -#define PYTHON_DUNE_GDT_SPACES_BINDINGS_HH - -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/gdt/spaces.hh> -# include <python/dune/gdt/spaces/interface.hh> -# include <python/dune/gdt/spaces/cg.hh> -# include <python/dune/gdt/spaces/dg.hh> -# include <python/dune/gdt/spaces/fv.hh> -# include <python/dune/gdt/spaces/rt.hh> - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_SPACES_BINDINGS_HH diff --git a/python/dune/gdt/spaces/cg.hh b/python/dune/gdt/spaces/cg.hh deleted file mode 100644 index 56104c9d5c3f35c97ab59f743e08abd028c1def9..0000000000000000000000000000000000000000 --- a/python/dune/gdt/spaces/cg.hh +++ /dev/null @@ -1,86 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_SPACES_CG_BINDINGS_HH -#define PYTHON_DUNE_GDT_SPACES_CG_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <python/dune/xt/grid/grids.bindings.hh> - -# include <dune/gdt/spaces/cg.hh> -# include <python/dune/gdt/spaces/interface.hh> - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_SPACES_CG_BIND(_m, _GRID, _layer, _r, _rC) \ - Dune::GDT::bindings::SpaceInterface< \ - Dune::GDT:: \ - CgSpaceProvider<_GRID, Dune::XT::Grid::Layers::_layer, Dune::GDT::Backends::gdt, 1, double, _r, _rC>>:: \ - bind(_m) - -/* -#if HAVE_ALBERTA -#define _DUNE_GDT_SPACES_CG_BIND_ALBERTA_LAYER(_m, _layer) \ - _DUNE_GDT_SPACES_CG_BIND(_m, ALBERTA_2D, _layer, 1, 1) -#define _DUNE_GDT_SPACES_CG_BIND_ALBERTA(_m) \ - _DUNE_GDT_SPACES_CG_BIND_ALBERTA_LAYER(_m, dd_subdomain); \ - _DUNE_GDT_SPACES_CG_BIND_ALBERTA_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_CG_BIND_ALBERTA_LAYER(_m, level) -#else -*/ -# define _DUNE_GDT_SPACES_CG_BIND_ALBERTA(_m) -//#endif - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_SPACES_CG_BIND_ALU_LAYER(_m, _layer) \ - _DUNE_GDT_SPACES_CG_BIND(_m, ALU_2D_SIMPLEX_CONFORMING, _layer, 1, 1) -# define _DUNE_GDT_SPACES_CG_BIND_ALU(_m) \ - _DUNE_GDT_SPACES_CG_BIND_ALU_LAYER(_m, dd_subdomain); \ - _DUNE_GDT_SPACES_CG_BIND_ALU_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_CG_BIND_ALU_LAYER(_m, level) -# else -# define _DUNE_GDT_SPACES_CG_BIND_ALU(_m) -# endif - -/* -#if HAVE_DUNE_UGGRID || HAVE_UG -#define _DUNE_GDT_SPACES_CG_BIND_UG_LAYER(_m, _layer) _DUNE_GDT_SPACES_CG_BIND(_m, UG_2D, _layer, 1, 1) -#define _DUNE_GDT_SPACES_CG_BIND_UG(_m) \ - _DUNE_GDT_SPACES_CG_BIND_UG_LAYER(_m, dd_subdomain); \ - _DUNE_GDT_SPACES_CG_BIND_UG_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_CG_BIND_UG_LAYER(_m, level) -#else -*/ -# define _DUNE_GDT_SPACES_CG_BIND_UG(_m) -//#endif - -# define _DUNE_GDT_SPACES_CG_BIND_YASP_LAYER(_m, _layer) \ - _DUNE_GDT_SPACES_CG_BIND(_m, YASP_1D_EQUIDISTANT_OFFSET, _layer, 1, 1); \ - _DUNE_GDT_SPACES_CG_BIND(_m, YASP_2D_EQUIDISTANT_OFFSET, _layer, 1, 1) -# define _DUNE_GDT_SPACES_CG_BIND_YASP(_m) \ - _DUNE_GDT_SPACES_CG_BIND_YASP_LAYER(_m, dd_subdomain); \ - _DUNE_GDT_SPACES_CG_BIND_YASP_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_CG_BIND_YASP_LAYER(_m, level) - -# define DUNE_GDT_SPACES_CG_BIND(_m) \ - _DUNE_GDT_SPACES_CG_BIND_ALBERTA(_m); \ - _DUNE_GDT_SPACES_CG_BIND_ALU(_m); \ - _DUNE_GDT_SPACES_CG_BIND_UG(_m); \ - _DUNE_GDT_SPACES_CG_BIND_YASP(_m) - - -// end: this is what we need for the .so - - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_SPACES_CG_BINDINGS_HH diff --git a/python/dune/gdt/spaces/constraints.hh b/python/dune/gdt/spaces/constraints.hh deleted file mode 100644 index 99bff702b6c3faca69c15f184659770c4232cafe..0000000000000000000000000000000000000000 --- a/python/dune/gdt/spaces/constraints.hh +++ /dev/null @@ -1,245 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_SPACES_CONSTRAINTS_BINDINGS_HH -#define PYTHON_DUNE_GDT_SPACES_CONSTRAINTS_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <boost/numeric/conversion/cast.hpp> - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/common/exceptions.hh> -# include <dune/xt/common/type_traits.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <dune/xt/grid/type_traits.hh> -# include <dune/xt/la/container.hh> -# include <python/dune/xt/la/container.bindings.hh> - -# include <dune/gdt/assembler/system.hh> -# include <dune/gdt/spaces/cg/interface.hh> -# include <dune/gdt/spaces/cg.hh> - -# include <dune/gdt/spaces/constraints.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <class I, class G> -class DirichletConstraints -{ -public: - typedef GDT::DirichletConstraints<I> type; - typedef pybind11::class_<type> bound_type; - - static bound_type bind(pybind11::module& m, const std::string& layer_name) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto grid_name = XT::Grid::bindings::grid_name<G>::value(); - const auto ClassName = XT::Common::to_camel_case("DirichletConstraints_" + layer_name + "_" + grid_name); - - bound_type c(m, ClassName.c_str(), ClassName.c_str()); - c.def("__init__", - [](type& self, const XT::Grid::BoundaryInfo<I>& boundary_info, const ssize_t size, const bool set) { - try { - new (&self) type(boundary_info, boost::numeric_cast<size_t>(size), set); - } catch (boost::bad_numeric_cast& ee) { - DUNE_THROW(XT::Common::Exceptions::wrong_input_given, - "Given size has to be positive!\n\n The error in boost while converting '" - << size - << "' to '" - << XT::Common::Typename<size_t>::value() - << "' was: " - << ee.what()); - } - }, - "boundary_info"_a, - "size"_a, - "set_diagonal_entries"_a = true, - py::keep_alive<1, 2>()); - c.def("boundary_info", &type::boundary_info); - c.def("size", &type::size); - - m.def(std::string("make_dirichlet_constraints").c_str(), - [](const XT::Grid::BoundaryInfo<I>& boundary_info, const ssize_t size, const bool set) { - size_t size__as_size_t = 0; - try { - size__as_size_t = boost::numeric_cast<size_t>(size); - } catch (boost::bad_numeric_cast& ee) { - DUNE_THROW(XT::Common::Exceptions::wrong_input_given, - "Given size has to be positive!\n\n The error in boost while converting '" - << size - << "' to '" - << XT::Common::Typename<size_t>::value() - << "' was: " - << ee.what()); - } - return type(boundary_info, size__as_size_t, set); - }, - "boundary_info"_a, - "size"_a, - "set_diagonal_entries"_a, - py::keep_alive<0, 1>()); - - return c; - } // ... bind(...) - - template <XT::LA::Backends la_backend, class R = double> - static void addbind(bound_type& c) - { - typedef typename XT::LA::Container<R, la_backend>::MatrixType M; - typedef typename XT::LA::Container<R, la_backend>::VectorType V; - using namespace pybind11::literals; - - c.def("apply", [](const type& self, M& matrix) { self.apply(matrix); }, "matrix"_a); - c.def("apply", [](const type& self, V& vector) { self.apply(vector); }, "vector"_a); - c.def("apply", [](const type& self, M& matrix, V& vector) { self.apply(matrix, vector); }, "matrix"_a, "vector"_a); - } // ... addbind(...) - -private: - template <class T, bool is_cg = is_cg_space<T>::value> - struct addbind_assembler - { - template <class GL, class A> - void operator()(pybind11::class_<GDT::SystemAssembler<T, GL, A>, XT::Grid::Walker<GL>>& bound_system_assembler) - { - using namespace pybind11::literals; - - bound_system_assembler.def("append", - [](GDT::SystemAssembler<T, GL, A>& self, - GDT::DirichletConstraints<XT::Grid::extract_intersection_t<GL>>& constraints) { - self.append(constraints); - }, - "dirichlet_constraints"_a); - } // ... addbind(...) - }; // struct addbind_assembler - - template <class T> - struct addbind_assembler<T, false> - { - template <class GL, class A> - void operator()(pybind11::class_<GDT::SystemAssembler<T, GL, A>, XT::Grid::Walker<GL>>& /*bound_system_assembler*/) - { - } - }; - -public: - template <class T, class GL, class A> - static void addbind(pybind11::class_<GDT::SystemAssembler<T, GL, A>, XT::Grid::Walker<GL>>& bound_system_assembler) - { - addbind_assembler<T>()(bound_system_assembler); - } -}; // class DirichletConstraints - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA(_c, _GRID, _layer, _backend, _la) \ - Dune::GDT::bindings::DirichletConstraints<Dune::XT::Grid::extract_intersection_t<typename Dune::XT::Grid::Layer< \ - _GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - _GRID>::addbind<Dune::XT::LA::Backends::_la>(_c) - -# define _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA_COMMON(_c, _GRID, _layer, _backend) -// _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA(_c, _GRID, _layer, _backend, common_dense) - -/* -#if HAVE_EIGEN -#define _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA_EIGEN(_c, _GRID, _layer, _backend) \ - _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA(_c, _GRID, _layer, _backend, eigen_sparse) -#else -*/ -# define _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA_EIGEN(_c, _GRID, _layer, _backend) -//#endif - -# if HAVE_DUNE_ISTL -# define _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA_ISTL(_c, _GRID, _layer, _backend) \ - _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA(_c, _GRID, _layer, _backend, istl_sparse) -# else -# define _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA_ISTL(_c, _GRID, _layer, _backend) -# endif - -# define _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA_ALL(_c, _GRID, _layer, _backend) \ - _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA_COMMON(_c, _GRID, _layer, _backend); \ - _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA_EIGEN(_c, _GRID, _layer, _backend); \ - _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA_ISTL(_c, _GRID, _layer, _backend) - -# define _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, _GRID, _layer, _backend, _layer_name) \ - auto dirichlet_constraints_##_GRID##_##_layer##_##_backend = Dune::GDT::bindings::DirichletConstraints< \ - Dune::XT::Grid::extract_intersection_t< \ - typename Dune::XT::Grid::Layer<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::XT::Grid::Backends::_backend, \ - Dune::XT::Grid::DD::SubdomainGrid<_GRID>>::type>, \ - _GRID>::bind(_m, _layer_name); \ - _DUNE_GDT_SPACES_CONSTRAINTS_ADDBIND_LA_ALL( \ - dirichlet_constraints_##_GRID##_##_layer##_##_backend, _GRID, _layer, _backend) - - -/* -#if HAVE_ALBERTA -#define _DUNE_GDT_SPACES_CONSTRAINTS_BIND_ALBERTA(_m) \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, ALBERTA_2D, leaf, view, ""); \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, ALBERTA_2D, dd_subdomain, part, "dd_subdomain") -#else -*/ -# define _DUNE_GDT_SPACES_CONSTRAINTS_BIND_ALBERTA(_m) -//#endif - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_SPACES_CONSTRAINTS_BIND_ALU(_m) \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, ALU_2D_SIMPLEX_CONFORMING, leaf, view, "leaf"); \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, ALU_2D_SIMPLEX_CONFORMING, level, view, "level"); \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, ALU_2D_SIMPLEX_CONFORMING, dd_subdomain, view, "dd_subdomain") -# else -# define _DUNE_GDT_SPACES_CONSTRAINTS_BIND_ALU(_m) -# endif - -/* -#if HAVE_DUNE_UGGRID -#define _DUNE_GDT_SPACES_CONSTRAINTS_BIND_UG(_m) \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, UG_2D, leaf, view, "leaf"); \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, UG_2D, level, view, "level"); \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, UG_2D, dd_subdomain, part, "dd_subdomain") -#else -*/ -# define _DUNE_GDT_SPACES_CONSTRAINTS_BIND_UG(_m) -//#endif - -# define _DUNE_GDT_SPACES_CONSTRAINTS_BIND_YASP(_m) \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, YASP_1D_EQUIDISTANT_OFFSET, leaf, view, ""); \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, YASP_1D_EQUIDISTANT_OFFSET, dd_subdomain, view, "dd_subdomain"); \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, YASP_2D_EQUIDISTANT_OFFSET, leaf, view, ""); \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m, YASP_2D_EQUIDISTANT_OFFSET, dd_subdomain, view, "dd_subdomain") - -# define DUNE_GDT_SPACES_CONSTRAINTS_BIND(_m) \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND_ALBERTA(_m); \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND_ALU(_m); \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND_UG(_m); \ - _DUNE_GDT_SPACES_CONSTRAINTS_BIND_YASP(_m) - -// end: this is what we need for the .so - - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_SPACES_CONSTRAINTS_BINDINGS_HH diff --git a/python/dune/gdt/spaces/dg.hh b/python/dune/gdt/spaces/dg.hh deleted file mode 100644 index 6db34ad25b577243861de4f0ca3c58a54935c711..0000000000000000000000000000000000000000 --- a/python/dune/gdt/spaces/dg.hh +++ /dev/null @@ -1,83 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_SPACES_DG_BINDINGS_HH -#define PYTHON_DUNE_GDT_SPACES_DG_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <python/dune/xt/grid/grids.bindings.hh> - -# include <dune/gdt/spaces/dg.hh> -# include <python/dune/gdt/spaces/interface.hh> - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_SPACES_DG_BIND(_m, _GRID, _layer, _r, _rC) \ - Dune::GDT::bindings::SpaceInterface< \ - Dune::GDT:: \ - DgSpaceProvider<_GRID, Dune::XT::Grid::Layers::_layer, Dune::GDT::Backends::gdt, 1, double, _r, _rC>>:: \ - bind(_m) - -/* -#if HAVE_ALBERTA -#define _DUNE_GDT_SPACES_DG_BIND_ALBERTA_LAYER(_m, _layer) \ - _DUNE_GDT_SPACES_DG_BIND(_m, ALBERTA_2D, _layer, 1, 1) -#define _DUNE_GDT_SPACES_DG_BIND_ALBERTA(_m) \ - _DUNE_GDT_SPACES_DG_BIND_ALBERTA_LAYER(_m, dd_subdomain); \ - _DUNE_GDT_SPACES_DG_BIND_ALBERTA_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_DG_BIND_ALBERTA_LAYER(_m, level) -#else -*/ -# define _DUNE_GDT_SPACES_DG_BIND_ALBERTA(_m) -//#endif - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_SPACES_DG_BIND_ALU_LAYER(_m, _layer) \ - _DUNE_GDT_SPACES_DG_BIND(_m, ALU_2D_SIMPLEX_CONFORMING, _layer, 1, 1) -# define _DUNE_GDT_SPACES_DG_BIND_ALU(_m) \ - _DUNE_GDT_SPACES_DG_BIND_ALU_LAYER(_m, dd_subdomain); \ - _DUNE_GDT_SPACES_DG_BIND_ALU_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_DG_BIND_ALU_LAYER(_m, level) -# else -# define _DUNE_GDT_SPACES_DG_BIND_ALU(_m) -# endif - -//#if HAVE_DUNE_UGGRID || HAVE_UG // <- does not work -//#define _DUNE_GDT_SPACES_DG_BIND_UG_LAYER(_m, _layer) _DUNE_GDT_SPACES_DG_BIND(_m, UG_2D, _layer, 1, 1) -//#define _DUNE_GDT_SPACES_DG_BIND_UG(_m) -// _DUNE_GDT_SPACES_DG_BIND_UG_LAYER(_m, dd_subdomain); -// _DUNE_GDT_SPACES_DG_BIND_UG_LAYER(_m, leaf); -// _DUNE_GDT_SPACES_DG_BIND_UG_LAYER(_m, level) -//#else -//#define _DUNE_GDT_SPACES_DG_BIND_UG(_m) -//#endif - -# define _DUNE_GDT_SPACES_DG_BIND_YASP_LAYER(_m, _layer) \ - _DUNE_GDT_SPACES_DG_BIND(_m, YASP_1D_EQUIDISTANT_OFFSET, _layer, 1, 1); \ - _DUNE_GDT_SPACES_DG_BIND(_m, YASP_2D_EQUIDISTANT_OFFSET, _layer, 1, 1) -# define _DUNE_GDT_SPACES_DG_BIND_YASP(_m) \ - _DUNE_GDT_SPACES_DG_BIND_YASP_LAYER(_m, dd_subdomain); \ - _DUNE_GDT_SPACES_DG_BIND_YASP_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_DG_BIND_YASP_LAYER(_m, level) - -# define DUNE_GDT_SPACES_DG_BIND(_m) \ - _DUNE_GDT_SPACES_DG_BIND_ALBERTA(_m); \ - _DUNE_GDT_SPACES_DG_BIND_ALU(_m); \ - _DUNE_GDT_SPACES_DG_BIND_YASP(_m) -//_DUNE_GDT_SPACES_DG_BIND_UG(_m); // <- does not work - -// end: this is what we need for the .so - - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_SPACES_DG_BINDINGS_HH diff --git a/python/dune/gdt/spaces/fv.hh b/python/dune/gdt/spaces/fv.hh deleted file mode 100644 index 2b31c30d37c5be0b298fdb5f2750e7484989bf12..0000000000000000000000000000000000000000 --- a/python/dune/gdt/spaces/fv.hh +++ /dev/null @@ -1,80 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_SPACES_FV_BINDINGS_HH -#define PYTHON_DUNE_GDT_SPACES_FV_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <python/dune/xt/grid/grids.bindings.hh> - -# include <dune/gdt/spaces/fv.hh> -# include <python/dune/gdt/spaces/interface.hh> - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_SPACES_FV_BIND_GDT(_m, _GRID, _layer, _r, _rC) \ - Dune::GDT::bindings::SpaceInterface< \ - Dune::GDT:: \ - FvSpaceProvider<_GRID, Dune::XT::Grid::Layers::_layer, Dune::GDT::Backends::gdt, double, _r, _rC>>:: \ - bind(_m) - -/* -#if HAVE_ALBERTA -#define _DUNE_GDT_SPACES_FV_BIND_GDT_ALBERTA_LAYER(_m, _layer) \ - _DUNE_GDT_SPACES_FV_BIND_GDT(_m, ALBERTA_2D, _layer, 1, 1) -#define _DUNE_GDT_SPACES_FV_BIND_GDT_ALBERTA(_m) \ - _DUNE_GDT_SPACES_FV_BIND_GDT_ALBERTA_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_FV_BIND_GDT_ALBERTA_LAYER(_m, level) -#else -*/ -# define _DUNE_GDT_SPACES_FV_BIND_GDT_ALBERTA(_m) -//#endif - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_SPACES_FV_BIND_GDT_ALU_LAYER(_m, _layer) \ - _DUNE_GDT_SPACES_FV_BIND_GDT(_m, ALU_2D_SIMPLEX_CONFORMING, _layer, 1, 1) -# define _DUNE_GDT_SPACES_FV_BIND_GDT_ALU(_m) \ - _DUNE_GDT_SPACES_FV_BIND_GDT_ALU_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_FV_BIND_GDT_ALU_LAYER(_m, level) -# else -# define _DUNE_GDT_SPACES_FV_BIND_GDT_ALU(_m) -# endif - -/* -#if HAVE_DUNE_UGGRID || HAVE_UG -#define _DUNE_GDT_SPACES_FV_BIND_GDT_UG_LAYER(_m, _layer) _DUNE_GDT_SPACES_FV_BIND_GDT(_m, UG_2D, _layer, 1, 1) -#define _DUNE_GDT_SPACES_FV_BIND_GDT_UG(_m) \ - _DUNE_GDT_SPACES_FV_BIND_GDT_UG_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_FV_BIND_GDT_UG_LAYER(_m, level) -#else -*/ -# define _DUNE_GDT_SPACES_FV_BIND_GDT_UG(_m) -//#endif - -# define _DUNE_GDT_SPACES_FV_BIND_GDT_YASP_LAYER(_m, _layer) \ - _DUNE_GDT_SPACES_FV_BIND_GDT(_m, YASP_2D_EQUIDISTANT_OFFSET, _layer, 1, 1) -# define _DUNE_GDT_SPACES_FV_BIND_GDT_YASP(_m) \ - _DUNE_GDT_SPACES_FV_BIND_GDT_YASP_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_FV_BIND_GDT_YASP_LAYER(_m, level) - -# define DUNE_GDT_SPACES_FV_BIND(_m) \ - _DUNE_GDT_SPACES_FV_BIND_GDT_ALBERTA(_m); \ - _DUNE_GDT_SPACES_FV_BIND_GDT_ALU(_m); \ - _DUNE_GDT_SPACES_FV_BIND_GDT_UG(_m); \ - _DUNE_GDT_SPACES_FV_BIND_GDT_YASP(_m) - -// end: this is what we need for the .so - - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_SPACES_FV_BINDINGS_HH diff --git a/python/dune/gdt/spaces/interface.hh b/python/dune/gdt/spaces/interface.hh deleted file mode 100644 index 9871cae7aa06b7cc0bf3922ef037374584524632..0000000000000000000000000000000000000000 --- a/python/dune/gdt/spaces/interface.hh +++ /dev/null @@ -1,557 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_SPACES_INTERFACE_BINDINGS_HH -#define PYTHON_DUNE_GDT_SPACES_INTERFACE_BINDINGS_HH -// TODO: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <dune/pybindxi/pybind11.h> - -# include <dune/xt/common/string.hh> -# include <python/dune/xt/grid/grids.bindings.hh> -# include <python/dune/xt/grid/layers.bindings.hh> -# include <dune/xt/grid/dd/subdomains/grid.hh> -# include <dune/xt/grid/gridprovider/provider.hh> -# include <dune/xt/grid/type_traits.hh> - -# include <dune/gdt/playground/spaces/restricted.hh> -# include <dune/gdt/spaces.hh> -# include <dune/gdt/type_traits.hh> - -# include <dune/gdt/spaces/interface.hh> -# include <dune/gdt/spaces/cg.hh> -# include <dune/gdt/spaces/dg.hh> -# include <dune/gdt/spaces/fv.hh> - -namespace Dune { -namespace GDT { -namespace bindings { - - -template <Backends backend> -struct backend_name -{ - static_assert(AlwaysFalse<typename internal::backend_dependent_typename<backend>::type>::value, - "Please add a specialization for this backend!"); - - static std::string value() - { - return ""; - } -}; - -template <> -struct backend_name<Backends::gdt> -{ - static std::string value() - { - return "gdt"; - } -}; - - -template <SpaceType tp> -struct space_type_name -{ - static_assert(AlwaysFalse<typename internal::space_type_dependent_typename<tp>::type>::value, - "Please add a specialization for this space type!"); - - static std::string value() - { - return ""; - } -}; - -template <> -struct space_type_name<SpaceType::cg> -{ - static std::string value() - { - return "cg"; - } -}; - -template <> -struct space_type_name<SpaceType::block_cg> -{ - static std::string value() - { - return "block_cg"; - } -}; - -template <> -struct space_type_name<SpaceType::dg> -{ - static std::string value() - { - return "dg"; - } -}; - -template <> -struct space_type_name<SpaceType::block_dg> -{ - static std::string value() - { - return "block_dg"; - } -}; - -template <> -struct space_type_name<SpaceType::fv> -{ - static std::string value() - { - return "fv"; - } -}; - -template <> -struct space_type_name<SpaceType::block_fv> -{ - static std::string value() - { - return "block_fv"; - } -}; - -template <> -struct space_type_name<SpaceType::rt> -{ - static std::string value() - { - return "rt"; - } -}; - -template <> -struct space_type_name<SpaceType::block_rt> -{ - static std::string value() - { - return "block_rt"; - } -}; - - -namespace internal { - - -template <class G, XT::Grid::Layers layer, Backends backend, size_t r, size_t rC, XT::Grid::Backends g> -struct space_name_base -{ - static std::string value_wo_grid() - { - using XT::Common::to_string; - return XT::Grid::bindings::layer_name<layer>::value() + "_" + XT::Grid::bindings::backend_name<g>::value() + "_to_" - + to_string(r) + "x" + to_string(rC) + "_" + backend_name<backend>::value(); - } - - static std::string value() - { - return XT::Grid::bindings::grid_name<G>::value() + "_" + value_wo_grid(); - } -}; - - -} // namespace internal - - -template <class P> -struct space_name -{ - static_assert(AlwaysFalse<P>::value, "Please add a specialization for this space provider!"); - - static std::string value() - { - return ""; - } -}; - -template <class G, XT::Grid::Layers layer, Backends backend, int p, size_t r, size_t rC, XT::Grid::Backends g> -struct space_name<CgSpaceProvider<G, layer, backend, p, double, r, rC, g>> -{ - static std::string value() - { - return space_type_name<SpaceType::cg>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value() + "_p" + XT::Common::to_string(p) - + "_space"; - } - - static std::string value_wo_grid() - { - return space_type_name<SpaceType::cg>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value_wo_grid() + "_p" + XT::Common::to_string(p) - + "_space"; - } -}; - -template <class G, XT::Grid::Layers layer, Backends backend, int p, size_t r, size_t rC, XT::Grid::Backends g> -struct space_name<BlockCgSpaceProvider<G, layer, backend, p, double, r, rC, g>> -{ - static std::string value() - { - return space_type_name<SpaceType::block_cg>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value() + "_p" + XT::Common::to_string(p) - + "_space"; - } - - static std::string value_wo_grid() - { - return space_type_name<SpaceType::block_cg>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value_wo_grid() + "_p" + XT::Common::to_string(p) - + "_space"; - } -}; - -template <class G, XT::Grid::Layers layer, Backends backend, int p, size_t r, size_t rC, XT::Grid::Backends g> -struct space_name<DgSpaceProvider<G, layer, backend, p, double, r, rC, g>> -{ - static std::string value() - { - return space_type_name<SpaceType::dg>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value() + "_p" + XT::Common::to_string(p) - + "_space"; - } - - static std::string value_wo_grid() - { - return space_type_name<SpaceType::dg>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value_wo_grid() + "_p" + XT::Common::to_string(p) - + "_space"; - } -}; - -template <class G, XT::Grid::Layers layer, Backends backend, int p, size_t r, size_t rC, XT::Grid::Backends g> -struct space_name<BlockDgSpaceProvider<G, layer, backend, p, double, r, rC, g>> -{ - static std::string value() - { - return space_type_name<SpaceType::block_dg>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value() + "_p" + XT::Common::to_string(p) - + "_space"; - } - - static std::string value_wo_grid() - { - return space_type_name<SpaceType::block_dg>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value_wo_grid() + "_p" + XT::Common::to_string(p) - + "_space"; - } -}; - -template <class G, XT::Grid::Layers layer, Backends backend, size_t r, size_t rC, XT::Grid::Backends g> -struct space_name<FvSpaceProvider<G, layer, backend, double, r, rC, g>> -{ - static std::string value() - { - return space_type_name<SpaceType::fv>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value() + "_space"; - } - - static std::string value_wo_grid() - { - return space_type_name<SpaceType::fv>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value_wo_grid() + "_space"; - } -}; - -template <class G, XT::Grid::Layers layer, Backends backend, size_t r, size_t rC, XT::Grid::Backends g> -struct space_name<BlockFvSpaceProvider<G, layer, backend, double, r, rC, g>> -{ - static std::string value() - { - return space_type_name<SpaceType::block_fv>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value() + "_space"; - } - - static std::string value_wo_grid() - { - return space_type_name<SpaceType::block_fv>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value_wo_grid() + "_space"; - } -}; - -template <class G, XT::Grid::Layers layer, Backends backend, int p, size_t r, size_t rC, XT::Grid::Backends g> -struct space_name<RtSpaceProvider<G, layer, backend, p, double, r, rC, g>> -{ - static std::string value() - { - return space_type_name<SpaceType::rt>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value() + "_p" + XT::Common::to_string(p) - + "_space"; - } - - static std::string value_wo_grid() - { - return space_type_name<SpaceType::rt>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value_wo_grid() + "_p" + XT::Common::to_string(p) - + "_space"; - } -}; - -template <class G, XT::Grid::Layers layer, Backends backend, int p, size_t r, size_t rC, XT::Grid::Backends g> -struct space_name<BlockRtSpaceProvider<G, layer, backend, p, double, r, rC, g>> -{ - static std::string value() - { - return space_type_name<SpaceType::block_rt>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value() + "_p" + XT::Common::to_string(p) - + "_space"; - } - - static std::string value_wo_grid() - { - return space_type_name<SpaceType::block_rt>::value() + "_" - + internal::space_name_base<G, layer, backend, r, rC, g>::value_wo_grid() + "_p" + XT::Common::to_string(p) - + "_space"; - } -}; - -template <class G, - XT::Grid::Layers l, - SpaceType tp, - Backends b, - int p, - class R, - size_t r, - size_t rC, - XT::Grid::Backends g> -struct space_name<SpaceProvider<G, l, tp, b, p, R, r, rC, g>> -{ - static std::string value() - { - return space_type_name<tp>::value() + "_" + internal::space_name_base<G, l, b, r, rC, g>::value() + "_p" - + XT::Common::to_string(p) + "_space"; - } - - static std::string value_wo_grid() - { - return space_type_name<tp>::value() + "_" + internal::space_name_base<G, l, b, r, rC, g>::value_wo_grid() + "_p" - + XT::Common::to_string(p) + "_space"; - } -}; - - -template <class S> -class SpaceInterfaceWoFactory -{ - static_assert(is_space<S>::value, ""); - -public: - typedef S type; - typedef pybind11::class_<type> bound_type; - - static bound_type bind(pybind11::module& m, const std::string& space_name) - { - namespace py = pybind11; - using namespace pybind11::literals; - - const auto ClassName = XT::Common::to_camel_case(space_name /*space_name<SP>::value()*/); - - bound_type c(m, ClassName.c_str(), ClassName.c_str()); - - c.def_property_readonly("dimDomain", [](const type& /*self*/) { return S::dimDomain; }); - c.def_property_readonly("dimRange", [](const type& /*self*/) { return S::dimRange; }); - c.def_property_readonly("dimRangeCols", [](const type& /*self*/) { return S::dimRangeCols; }); - c.def_property_readonly("polOrder", [](const type& /*self*/) { return S::polOrder; }); - c.def_property_readonly_static("dimDomain", [](const type& /*self*/) { return S::dimDomain; }); - c.def_property_readonly_static("dimRange", [](const type& /*self*/) { return S::dimRange; }); - c.def_property_readonly_static("dimRangeCols", [](const type& /*self*/) { return S::dimRangeCols; }); - c.def_property_readonly_static("polOrder", [](const type& /*self*/) { return S::polOrder; }); - - c.def("size", [](const type& self) { return self.mapper().size(); }); - c.def("visualize", - [](const type& self, const std::string& filename) { self.visualize(filename); }, - "filename"_a = ""); - c.def("compute_pattern", - [](const type& self, const std::string tp) { - if (tp == "default") - return self.compute_pattern(); - else if (tp == "volume") - return self.compute_volume_pattern(); - else if (tp == "face") - return self.compute_face_pattern(); - else if (tp == "face_and_volume") - return self.compute_face_and_volume_pattern(); - else - DUNE_THROW(XT::Common::Exceptions::wrong_input_given, - " type has to be one of ('default', volume', 'face', 'face_and_volume'), is '" << tp << "'!"); - // we will never get here - return XT::LA::SparsityPatternDefault(); - }, - "type"_a = "default"); - - return c; - } // ... bind(...) -}; // class SpaceInterfaceWoFactory - - -template <class SP> -class SpaceInterface -{ - typedef typename SP::type S; - static_assert(is_space<S>::value, ""); - using G = XT::Grid::extract_grid_t<typename S::GridLayerType>; - - template <bool is_dd_subdomain_layer = (SP::grid_layer == XT::Grid::Layers::dd_subdomain), bool anything = true> - struct factory_methods - { - static void addbind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - const std::string factory_method_name = "make_" + space_name<SP>::value_wo_grid(); - - m.def(factory_method_name.c_str(), - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& grid_provider, int level) { - return SP::create(grid_provider, level); - }, - "grid_provider"_a, - "level"_a = 0, - py::keep_alive<0, 1>()); - } - }; - - template <bool anything> - struct factory_methods<false, anything> - { - static void addbind(pybind11::module& m) - { - namespace py = pybind11; - using namespace pybind11::literals; - const std::string factory_method_name = "make_" + space_name<SP>::value_wo_grid(); - - m.def(factory_method_name.c_str(), - [](XT::Grid::GridProvider<G>& grid_provider, int level) { return SP::create(grid_provider, level); }, - "grid_provider"_a, - "level"_a = 0, - py::keep_alive<0, 1>()); - m.def(factory_method_name.c_str(), - [](XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& grid_provider, int level) { - return SP::create(grid_provider, level); - }, - "grid_provider"_a, - "level"_a = 0, - py::keep_alive<0, 1>()); - } - }; - -public: - typedef S type; - typedef pybind11::class_<type> bound_type; - -private: - template <XT::Grid::Backends backend, - XT::Grid::Layers layer, - bool is_dd = (layer == XT::Grid::Layers::dd_subdomain || layer == XT::Grid::Layers::dd_subdomain_boundary - || layer == XT::Grid::Layers::dd_subdomain_coupling - || layer == XT::Grid::Layers::dd_subdomain_oversampled)> - struct restriction_methods // true - { - static void addbind(bound_type& c) - { - namespace py = pybind11; - using namespace pybind11::literals; - - typedef GDT::RestrictedSpace<S, typename XT::Grid::Layer<G, layer, backend>::type> RestrictedSpaceType; - - c.def(std::string("restrict_to_" + XT::Grid::bindings::layer_name<layer>::value() + "_" - + XT::Grid::bindings::backend_name<backend>::value()) - .c_str(), - [](type& self, - XT::Grid::GridProvider<G, XT::Grid::DD::SubdomainGrid<G>>& grid_provider, - const int level_or_subdomain = -1) { - return RestrictedSpaceType(self, grid_provider.template layer<layer, backend>(level_or_subdomain)); - }, - "grid_provider"_a, - "level_or_subdomain"_a, - py::keep_alive<1, 0>()); - } - }; // struct restriction_methods - - template <XT::Grid::Backends backend, XT::Grid::Layers layer> - struct restriction_methods<backend, layer, false> - { - static void addbind(bound_type& c) - { - namespace py = pybind11; - using namespace pybind11::literals; - - typedef GDT::RestrictedSpace<S, typename XT::Grid::Layer<G, layer, backend>::type> RestrictedSpaceType; - - c.def(std::string("restrict_to_" + XT::Grid::bindings::layer_name<layer>::value() + "_" - + XT::Grid::bindings::backend_name<backend>::value()) - .c_str(), - [](type& self, XT::Grid::GridProvider<G>& grid_provider, const int level = -1) { - return RestrictedSpaceType(self, grid_provider.template layer<layer, backend>(level)); - }, - "grid_provider"_a, - "level"_a, - py::keep_alive<1, 0>()); - restriction_methods<backend, layer, true>::addbind(c); - } - }; // struct restriction_methods<..., false> - - template <XT::Grid::Backends backend, XT::Grid::Layers layer> - static void addbind_restricted(pybind11::module& m, bound_type& c, const std::string sp_name) - { - using namespace pybind11::literals; - - typedef GDT::RestrictedSpace<S, typename XT::Grid::Layer<G, layer, backend>::type> RestrictedSpaceType; - - try { // we might not be the first to add this RestrictedSpace - const auto restricted_space_name = sp_name + "_restricted_to_" + XT::Grid::bindings::layer_name<layer>::value() - + "_" + XT::Grid::bindings::backend_name<backend>::value(); - auto restricted_space = SpaceInterfaceWoFactory<RestrictedSpaceType>::bind(m, restricted_space_name); - restricted_space.def("restrict", - [](RestrictedSpaceType& self, const XT::LA::IstlDenseVector<double>& unrestricted_vector) { - return self.mapper().restrict(unrestricted_vector); - }, - "unrestricted_vector"_a); - restricted_space.def("extend", - [](RestrictedSpaceType& self, const XT::LA::IstlDenseVector<double>& restricted_vector) { - return self.mapper().extend(restricted_vector); - }, - "restricted_vector"_a); - } catch (std::runtime_error&) { - } - - restriction_methods<backend, layer>::addbind(c); - } // ... addbind_restricted(...) - -public: - static bound_type bind(pybind11::module& m) - { - const auto sp_name = space_name<SP>::value(); - auto c = SpaceInterfaceWoFactory<S>::bind(m, sp_name); - - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::dd_subdomain>(m, c, sp_name); - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::dd_subdomain_boundary>(m, c, sp_name); - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::dd_subdomain_coupling>(m, c, sp_name); - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::dd_subdomain_oversampled>(m, c, sp_name); - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::leaf>(m, c, sp_name); - addbind_restricted<XT::Grid::Backends::view, XT::Grid::Layers::level>(m, c, sp_name); - - factory_methods<>::addbind(m); - return c; - } // ... bind(...) -}; // class SpaceInterface - - -} // namespace bindings -} // namespace GDT -} // namespace Dune - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_SPACES_INTERFACE_BINDINGS_HH diff --git a/python/dune/gdt/spaces/rt.hh b/python/dune/gdt/spaces/rt.hh deleted file mode 100644 index 1fc867fe474da70d8697757cf06625bbc106c95f..0000000000000000000000000000000000000000 --- a/python/dune/gdt/spaces/rt.hh +++ /dev/null @@ -1,50 +0,0 @@ -// This file is part of the dune-gdt project: -// https://github.com/dune-community/dune-gdt -// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved. -// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) -// or GPL-2.0+ (http://opensource.org/licenses/gpl-license) -// with "runtime exception" (http://www.dune-project.org/license.html) -// Authors: -// Felix Schindler (2017 - 2018) -// René Fritze (2018) -// Tobias Leibner (2018) - -#ifndef PYTHON_DUNE_GDT_SPACES_RT_BINDINGS_HH -#define PYTHON_DUNE_GDT_SPACES_RT_BINDINGS_HH -// Todo: python bindings need to be updated to the new-master -#if 0 // HAVE_DUNE_PYBINDXI - -# include <python/dune/xt/grid/grids.bindings.hh> - -# include <python/dune/gdt/spaces/interface.hh> -# include <dune/gdt/spaces/hdiv/raviart-thomas.hh> - - -// begin: this is what we need for the .so - -# define _DUNE_GDT_SPACES_RT_BIND(_m, _GRID, _layer) \ - Dune::GDT::bindings::SpaceInterface<Dune::GDT::RtSpaceProvider<_GRID, \ - Dune::XT::Grid::Layers::_layer, \ - Dune::GDT::Backends::gdt, \ - 0, \ - double, \ - _GRID::dimension, \ - 1>>::bind(_m) - -# if HAVE_DUNE_ALUGRID -# define _DUNE_GDT_SPACES_RT_BIND_ALU_LAYER(_m, _layer) \ - _DUNE_GDT_SPACES_RT_BIND(_m, ALU_2D_SIMPLEX_CONFORMING, _layer) -# define _DUNE_GDT_SPACES_RT_BIND_ALU(_m) \ - _DUNE_GDT_SPACES_RT_BIND_ALU_LAYER(_m, leaf); \ - _DUNE_GDT_SPACES_RT_BIND_ALU_LAYER(_m, level) -# else -# define _DUNE_GDT_SPACES_RT_BIND_ALU(_m) -# endif - -# define DUNE_GDT_SPACES_RT_BIND(_m) _DUNE_GDT_SPACES_RT_BIND_ALU(_m) - -// end: this is what we need for the .so - - -#endif // HAVE_DUNE_PYBINDXI -#endif // PYTHON_DUNE_GDT_SPACES_RT_BINDINGS_HH diff --git a/python/dune/gdt/usercode.cc b/python/dune/gdt/usercode.cc index b54d6753eac0ef0f17b45ffbf365c044ab2bee32..989cf947ffaedb4e412319882f50ad894e4fd053 100644 --- a/python/dune/gdt/usercode.cc +++ b/python/dune/gdt/usercode.cc @@ -25,9 +25,7 @@ PYBIND11_MODULE(usercode, m) py::module::import("dune.xt.la"); py::module::import("dune.xt.grid"); py::module::import("dune.xt.functions"); - - Dune::XT::Common::bindings::addbind_exceptions(m); - Dune::XT::Common::bindings::add_initialization(m, "dune.gdt"); + py::module::import("dune.gdt.discretefunction"); // put your bindings below } // PYBIND11_MODULE(usercode, ...) diff --git a/python/test/base.py b/python/test/base.py index c3080c308f4ed1887b58d42e800f71edd156c46f..77bae28bcb14eda1fb9c70d4a79ca4020047753f 100644 --- a/python/test/base.py +++ b/python/test/base.py @@ -1,4 +1,3 @@ - import pytest from dune.xt.common.test import load_all_submodule @@ -6,5 +5,3 @@ from dune.xt.common.test import load_all_submodule def test_load_all(): import dune.gdt as gdt load_all_submodule(gdt) - -