From e409cad67f90b8bb9ea3cdd73e7c6579a39da395 Mon Sep 17 00:00:00 2001 From: Felix Schindler <felix.schindler@wwu.de> Date: Mon, 9 Jul 2018 22:24:05 +0200 Subject: [PATCH] [local.integrands] add penalty-only IPDG variants --- dune/gdt/local/integrands/elliptic-ipdg.hh | 643 +++++++++++++++++++++ 1 file changed, 643 insertions(+) diff --git a/dune/gdt/local/integrands/elliptic-ipdg.hh b/dune/gdt/local/integrands/elliptic-ipdg.hh index 4e1aabd09..5bbdcfc2f 100644 --- a/dune/gdt/local/integrands/elliptic-ipdg.hh +++ b/dune/gdt/local/integrands/elliptic-ipdg.hh @@ -1478,6 +1478,649 @@ public: }; // class BoundaryRHS #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> +{ + using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F>; + using ThisType = InnerOnlyPenalty<I, F, method>; + +public: + using typename BaseType::IntersectionType; + using typename BaseType::E; + using BaseType::d; + using typename BaseType::LocalTestBasisType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::DomainType; + + using DiffusionFactorType = XT::Functions::GridFunctionInterface<E, 1, 1, F>; + using DiffusionTensorType = XT::Functions::GridFunctionInterface<E, d, d, F>; + + InnerOnlyPenalty(const DiffusionFactorType& diffusion_factor, + const DiffusionTensorType& diffusion_tensor, + const double beta = internal::default_beta(d)) + : BaseType(diffusion_factor.parameter_type() + diffusion_tensor.parameter_type()) + , beta_(beta) + , diffusion_factor_(diffusion_factor) + , diffusion_tensor_(diffusion_tensor) + , local_diffusion_factor_in_(diffusion_factor_.local_function()) + , local_diffusion_factor_out_(diffusion_factor_.local_function()) + , local_diffusion_tensor_in_(diffusion_tensor_.local_function()) + , local_diffusion_tensor_out_(diffusion_tensor_.local_function()) + { + } + + InnerOnlyPenalty(const ThisType& other) + : BaseType(other.parameter_type()) + , beta_(other.beta_) + , diffusion_factor_(other.diffusion_factor_) + , diffusion_tensor_(other.diffusion_tensor_) + , local_diffusion_factor_in_(diffusion_factor_.local_function()) + , local_diffusion_factor_out_(diffusion_factor_.local_function()) + , local_diffusion_tensor_in_(diffusion_tensor_.local_function()) + , local_diffusion_tensor_out_(diffusion_tensor_.local_function()) + { + } + + InnerOnlyPenalty(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_factor_in_->bind(inside_element); + local_diffusion_tensor_in_->bind(inside_element); + local_diffusion_factor_out_->bind(outside_element); + local_diffusion_tensor_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_factor_in_->order(param), local_diffusion_factor_out_->order(param)) + + std::max(local_diffusion_tensor_in_->order(), local_diffusion_tensor_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)); + } + +private: + template <Method m, class Anything = void> + struct IPDG + { + static_assert(AlwaysFalse<Anything>::value, "Other methods are not implemented yet!"); + + template <class R> + static inline F delta_plus(const FieldVector<R, 1>& /*diffusion_factor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_ne*/, + const FieldVector<R, d>& /*normal*/) + { + static_assert(AlwaysFalse<R>::value, "Other methods are not implemented yet!"); + return 0.; + } + + template <class R> + static inline F delta_minus(const FieldVector<R, 1>& /*diffusion_factor_en*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_en*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_en*/, + const FieldVector<R, d>& /*normal*/) + { + static_assert(AlwaysFalse<R>::value, "Other methods are not implemented yet!"); + return 0.; + } + + template <class R> + static inline F gamma(const R& /*delta_plus*/, const R& /*delta_minus*/) + { + static_assert(AlwaysFalse<R>::value, "Other methods are not implemented yet!"); + return 0.; + } + + template <class R> + static inline F penalty(const FieldVector<R, 1>& /*diffusion_factor_en*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_en*/, + const FieldVector<R, 1>& /*diffusion_factor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_ne*/, + const FieldVector<R, d>& /*normal*/, + const R& /*sigma*/, + const R& /*gamma*/, + const R& /*h*/, + const R& /*beta*/) + { + static_assert(AlwaysFalse<R>::value, "Other methods are not implemented yet!"); + return 0.; + } + + template <class R> + static inline F weight_plus(const R& /*delta_plus*/, const R& /*delta_minus*/) + { + static_assert(AlwaysFalse<R>::value, "Other methods are not implemented yet!"); + return 0.; + } + + template <class R> + static inline F weight_minus(const R& /*delta_plus*/, const R& /*delta_minus*/) + { + static_assert(AlwaysFalse<R>::value, "Other methods are not implemented yet!"); + return 0.; + } + }; // struct IPDG<...> + + template <class Anything> + struct IPDG<Method::swipdg, Anything> + { + template <class R> + static inline F delta_plus(const FieldVector<R, 1>& /*diffusion_factor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& diffusion_ne, + const FieldVector<R, d>& normal) + { + return normal * (diffusion_ne * normal); + } + + template <class R> + static inline F delta_minus(const FieldVector<R, 1>& /*diffusion_factor_en*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_en*/, + const XT::Common::FieldMatrix<R, d, d>& diffusion_en, + const FieldVector<R, d>& normal) + { + return normal * (diffusion_en * normal); + } + + template <class R> + static inline F gamma(const R& delta_plus, const R& delta_minus) + { + return (delta_plus * delta_minus) / (delta_plus + delta_minus); + } + + template <class R> + static inline F penalty(const FieldVector<R, 1>& /*diffusion_factor_en*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_en*/, + const FieldVector<R, 1>& /*diffusion_factor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_ne*/, + const FieldVector<R, d>& /*normal*/, + const R& sigma, + const R& gamma, + const R& h, + const R& beta) + { + return (sigma * gamma) / std::pow(h, beta); + } + + template <class R> + static inline F weight_plus(const R& delta_plus, const R& delta_minus) + { + return delta_minus / (delta_plus + delta_minus); + } + + template <class R> + static inline F weight_minus(const R& delta_plus, const R& delta_minus) + { + return delta_plus / (delta_plus + delta_minus); + } + }; // struct IPDG<Method::swipdg, ...> + + template <class Anything> + struct IPDG<Method::swipdg_affine_factor, Anything> + { + template <class R> + static inline F delta_plus(const FieldVector<R, 1>& /*diffusion_factor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& diffusion_tensor_ne, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_ne*/, + const FieldVector<R, d>& normal) + { + return normal * (diffusion_tensor_ne * normal); + } + + template <class R> + static inline F delta_minus(const FieldVector<R, 1>& /*diffusion_factor_en*/, + const XT::Common::FieldMatrix<R, d, d>& diffusion_tensor_en, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_en*/, + const FieldVector<R, d>& normal) + { + return normal * (diffusion_tensor_en * normal); + } + + template <class R> + static inline F gamma(const R& delta_plus, const R& delta_minus) + { + return (delta_plus * delta_minus) / (delta_plus + delta_minus); + } + + template <class R> + static inline F penalty(const FieldVector<R, 1>& diffusion_factor_en, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_en*/, + const FieldVector<R, 1>& diffusion_factor_ne, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_ne*/, + const FieldVector<R, d>& /*normal*/, + const R& sigma, + const R& gamma, + const R& h, + const R& beta) + { + return (0.5 * (diffusion_factor_en + diffusion_factor_ne) * sigma * gamma) / std::pow(h, beta); + } + + template <class R> + static inline F weight_plus(const R& delta_plus, const R& delta_minus) + { + return delta_minus / (delta_plus + delta_minus); + } + + template <class R> + static inline F weight_minus(const R& delta_plus, const R& delta_minus) + { + return delta_plus / (delta_plus + delta_minus); + } + }; // struct IPDG<Method::swipdg_affine_factor, ...> + + template <class Anything> + struct IPDG<Method::swipdg_affine_tensor, Anything> + { + template <class R> + static inline F delta_plus(const FieldVector<R, 1>& diffusion_factor_ne, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_ne*/, + const FieldVector<R, d>& /*normal*/) + { + return diffusion_factor_ne; + } + + template <class R> + static inline F delta_minus(const FieldVector<R, 1>& diffusion_factor_en, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_en*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_en*/, + const FieldVector<R, d>& /*normal*/) + { + return diffusion_factor_en; + } + + template <class R> + static inline F gamma(const R& delta_plus, const R& delta_minus) + { + return (delta_plus * delta_minus) / (delta_plus + delta_minus); + } + + template <class R> + static inline F penalty(const FieldVector<R, 1>& /*diffusion_factor_en*/, + const XT::Common::FieldMatrix<R, d, d>& diffusion_tensor_en, + const FieldVector<R, 1>& /*diffusion_factor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& diffusion_tensor_ne, + const FieldVector<R, d>& normal, + const R& sigma, + const R& gamma, + const R& h, + const R& beta) + { + return (normal * (((diffusion_tensor_en + diffusion_tensor_ne) * 0.5) * normal) * sigma * gamma) + / std::pow(h, beta); + } + + template <class R> + static inline F weight_plus(const R& delta_plus, const R& delta_minus) + { + return delta_minus / (delta_plus + delta_minus); + } + + template <class R> + static inline F weight_minus(const R& delta_plus, const R& delta_minus) + { + return delta_plus / (delta_plus + delta_minus); + } + }; // struct IPDG<Method::swipdg_affine_tensor, ...> + + template <class Anything> + struct IPDG<Method::sipdg, Anything> + { + template <class R> + static inline F delta_plus(const FieldVector<R, 1>& /*diffusion_factor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_ne*/, + const FieldVector<R, d>& /*normal*/) + { + return 1.0; + } + + template <class R> + static inline F delta_minus(const FieldVector<R, 1>& /*diffusion_factor_en*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_en*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_en*/, + const FieldVector<R, d>& /*normal*/) + { + return 1.0; + } + + template <class R> + static inline F gamma(const R& /*delta_plus*/, const R& /*delta_minus*/) + { + return 1.0; + } + + template <class R> + static inline F penalty(const FieldVector<R, 1>& /*diffusion_factor_en*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_en*/, + const FieldVector<R, 1>& /*diffusion_factor_ne*/, + const XT::Common::FieldMatrix<R, d, d>& /*diffusion_tensor_ne*/, + const FieldVector<R, d>& /*normal*/, + const R& sigma, + const R& /*gamma*/, + const R& h, + const R& beta) + { + return sigma / std::pow(h, beta); + } + + template <class R> + static inline F weight_plus(const R& /*delta_plus*/, const R& /*delta_minus*/) + { + return 0.5; + } + + template <class R> + static inline F weight_minus(const R& /*delta_plus*/, const R& /*delta_minus*/) + { + return 0.5; + } + }; // struct IPDG<Method::sipdg, ...> + +public: + 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_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); + // 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_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); + // ... data functions + const auto diffusion_factor_in = local_diffusion_factor_in_->evaluate(point_in_inside_reference_element, param); + const auto diffusion_tensor_in = local_diffusion_tensor_in_->evaluate(point_in_inside_reference_element, param); + const auto diffusion_factor_out = local_diffusion_factor_out_->evaluate(point_in_outside_reference_element, param); + const auto diffusion_tensor_out = local_diffusion_tensor_out_->evaluate(point_in_outside_reference_element, param); + const auto diffusion_in = diffusion_tensor_in * diffusion_factor_in; + const auto diffusion_out = diffusion_tensor_out * diffusion_factor_out; + // compute penalty factor (see Epshteyn, Riviere, 2007) + const size_t max_polorder = + std::max(test_basis_inside.order(param), + std::max(ansatz_basis_inside.order(param), + std::max(test_basis_outside.order(param), ansatz_basis_outside.order(param)))); + const F sigma = internal::inner_sigma(max_polorder); + // compute weighting (see Ern, Stephansen, Zunino 2007) + const F delta_plus = IPDG<method>::delta_plus(diffusion_factor_out, diffusion_tensor_out, diffusion_out, normal); + const F delta_minus = IPDG<method>::delta_minus(diffusion_factor_in, diffusion_tensor_in, diffusion_in, normal); + const F gamma = IPDG<method>::gamma(delta_plus, delta_minus); + const F penalty = IPDG<method>::penalty(diffusion_factor_in, + diffusion_tensor_out, + diffusion_factor_out, + diffusion_tensor_in, + normal, + sigma, + gamma, + this->intersection().geometry().volume(), + beta_); + // compute integrand + 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 beta_; + const DiffusionFactorType& diffusion_factor_; // These are just required ... + const DiffusionTensorType& diffusion_tensor_; // ... for the copy ctor atm. + std::unique_ptr<typename DiffusionFactorType::LocalFunctionType> local_diffusion_factor_in_; + std::unique_ptr<typename DiffusionFactorType::LocalFunctionType> local_diffusion_factor_out_; + std::unique_ptr<typename DiffusionTensorType::LocalFunctionType> local_diffusion_tensor_in_; + std::unique_ptr<typename DiffusionTensorType::LocalFunctionType> local_diffusion_tensor_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_; +}; // 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> +{ + using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I, 1, 1, F, F, 1, 1, F>; + using ThisType = DirichletBoundaryLhsOnlyPenalty<I, F, method>; + +public: + using typename BaseType::IntersectionType; + using typename BaseType::E; + using BaseType::d; + using typename BaseType::LocalTestBasisType; + using typename BaseType::LocalAnsatzBasisType; + using typename BaseType::DomainType; + + using DiffusionFactorType = XT::Functions::GridFunctionInterface<E, 1, 1, F>; + using DiffusionTensorType = XT::Functions::GridFunctionInterface<E, d, d, F>; + + DirichletBoundaryLhsOnlyPenalty(const DiffusionFactorType& diffusion_factor, + const DiffusionTensorType& diffusion_tensor, + const double beta = internal::default_beta(d)) + : BaseType(diffusion_factor.parameter_type() + diffusion_tensor.parameter_type()) + , beta_(beta) + , diffusion_factor_(diffusion_factor) + , diffusion_tensor_(diffusion_tensor) + , local_diffusion_factor_(diffusion_factor_.local_function()) + , local_diffusion_tensor_(diffusion_tensor_.local_function()) + { + } + + DirichletBoundaryLhsOnlyPenalty(const ThisType& other) + : BaseType(other.parameter_type()) + , beta_(other.beta_) + , diffusion_factor_(other.diffusion_factor_) + , diffusion_tensor_(other.diffusion_tensor_) + , local_diffusion_factor_(diffusion_factor_.local_function()) + , local_diffusion_tensor_(diffusion_tensor_.local_function()) + { + } + + DirichletBoundaryLhsOnlyPenalty(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_factor_->bind(inside_element); + local_diffusion_tensor_->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_factor_->order(param) + local_diffusion_tensor_->order(param) + + test_basis_inside.order(param) + ansatz_basis_inside.order(param); + } + +private: + template <Method m, class Anything = void> + struct IPDG + { + static_assert(AlwaysFalse<Anything>::value, "Other methods are not implemented yet!"); + + template <class R> + static inline F gamma(const XT::Common::FieldMatrix<R, d, d>& /*diffusion*/, const FieldVector<R, d>& /*normal*/) + { + static_assert(AlwaysFalse<R>::value, "Other methods are not implemented yet!"); + return 0.; + } + + template <class R> + static inline F penalty(const R& /*sigma*/, const R& /*gamma*/, const R& /*h*/, const R& /*beta*/) + { + static_assert(AlwaysFalse<R>::value, "Other methods are not implemented yet!"); + return 0.; + } + }; // struct IPDG<...> + + template <class Anything> + struct IPDG<Method::swipdg, Anything> + { + template <class R> + static inline F gamma(const XT::Common::FieldMatrix<R, d, d>& diffusion, const FieldVector<R, d>& normal) + { + return normal * (diffusion * normal); + } + + template <class R> + static inline F penalty(const R& sigma, const R& gamma, const R& h, const R& beta) + { + return (sigma * gamma) / std::pow(h, beta); + } + }; // struct IPDG<Method::swipdg, ...> + + template <class Anything> + struct IPDG<Method::swipdg_affine_factor, Anything> : public IPDG<Method::swipdg, Anything> + { + }; + + template <class Anything> + struct IPDG<Method::swipdg_affine_tensor, Anything> : public IPDG<Method::swipdg, Anything> + { + }; + + template <class Anything> + struct IPDG<Method::sipdg, Anything> + { + template <class R> + static inline F gamma(const XT::Common::FieldMatrix<R, d, d>& /*diffusion*/, const FieldVector<R, d>& /*normal*/) + { + return 1.0; + } + + template <class R> + static inline F penalty(const R& sigma, const R& /*gamma*/, const R& h, const R& beta) + { + return sigma / std::pow(h, beta); + } + }; // struct IPDG<Method::sipdg, ...> + +public: + 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_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); // This is on purpose ... + ensure_size_and_clear(result_out_in, rows_out, cols_in); // ... (including the resize), otherwise ... + ensure_size_and_clear(result_out_out, rows_out, cols_out); // ... we could not use this in the standard assembler. + // 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); + ansatz_basis_inside.evaluate(point_in_inside_reference_element, ansatz_basis_values_, param); + // ... data functions + const auto diffusion_factor = local_diffusion_factor_->evaluate(point_in_inside_reference_element, param); + const auto diffusion_tensor = local_diffusion_tensor_->evaluate(point_in_inside_reference_element, param); + const auto diffusion = diffusion_tensor * diffusion_factor; + // compute penalty (see Epshteyn, Riviere, 2007) + const size_t max_polorder = std::max(test_basis_inside.order(param), ansatz_basis_inside.order(param)); + const F sigma = internal::boundary_sigma(max_polorder); + // compute weighting (see Ern, Stephansen, Zunino 2007) + const F gamma = IPDG<method>::gamma(diffusion, normal); + const F penalty = IPDG<method>::penalty(sigma, gamma, this->intersection().geometry().volume(), beta_); + // compute integrand + 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_values_[jj] * test_basis_values_[ii]; + } // ... evaluate(...) + +private: + const double beta_; + const DiffusionFactorType& diffusion_factor_; // These are just required ... + const DiffusionTensorType& diffusion_tensor_; // ... for the copy ctor atm. + std::unique_ptr<typename DiffusionFactorType::LocalFunctionType> local_diffusion_factor_; + std::unique_ptr<typename DiffusionTensorType::LocalFunctionType> local_diffusion_tensor_; + 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_; +}; // DirichletBoundaryLhsOnlyPenalty } // namespace LocalEllipticIpdgIntegrands } // namespace GDT -- GitLab