From 401c98cf1b376c8821634d15678a4feef868ed64 Mon Sep 17 00:00:00 2001 From: Felix Schindler <felix.schindler@wwu.de> Date: Sun, 5 Aug 2018 17:56:38 +0200 Subject: [PATCH] [test] complete rewrite and modernize of InstationaryEocStudy --- dune/gdt/test/instationary-eocstudies/base.hh | 338 ++++++++++++++++++ dune/gdt/test/instationary-eocstudy.hh | 312 ---------------- dune/gdt/test/instationary-testcase.hh | 100 ------ 3 files changed, 338 insertions(+), 412 deletions(-) create mode 100644 dune/gdt/test/instationary-eocstudies/base.hh delete mode 100644 dune/gdt/test/instationary-eocstudy.hh delete mode 100644 dune/gdt/test/instationary-testcase.hh diff --git a/dune/gdt/test/instationary-eocstudies/base.hh b/dune/gdt/test/instationary-eocstudies/base.hh new file mode 100644 index 000000000..372d5967f --- /dev/null +++ b/dune/gdt/test/instationary-eocstudies/base.hh @@ -0,0 +1,338 @@ +// 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_TEST_INSTATIONARY_EOCSTUDIES_BASE_HH +#define DUNE_GDT_TEST_INSTATIONARY_EOCSTUDIES_BASE_HH + +#include <cmath> +#include <functional> +#include <memory> + +#include <dune/grid/io/file/dgfparser/dgfparser.hh> + +#include <dune/xt/common/convergence-study.hh> +#include <dune/xt/common/fvector.hh> +#include <dune/xt/common/test/gtest/gtest.h> +#include <dune/xt/la/container.hh> +#include <dune/xt/la/container/vector-array/list.hh> +#include <dune/xt/la/type_traits.hh> +#include <dune/xt/grid/gridprovider/provider.hh> +#include <dune/xt/grid/type_traits.hh> +#include <dune/xt/functions/lambda/function.hh> + +#include <dune/gdt/exceptions.hh> +#include <dune/gdt/functionals/localizable-functional.hh> +#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/product.hh> +#include <dune/gdt/operators/interfaces.hh> +#include <dune/gdt/operators/localizable-bilinear-form.hh> +#include <dune/gdt/prolongations.hh> +#include <dune/gdt/spaces/bochner.hh> +#include <dune/gdt/spaces/interface.hh> +#include <dune/gdt/type_traits.hh> + +namespace Dune { +namespace GDT { +namespace Test { + + +template <class GridView, size_t m_ = 1, XT::LA::Backends la = XT::LA::Backends::istl_sparse> +class InstationaryEocStudy : public XT::Common::ConvergenceStudy, public ::testing::Test +{ + static_assert(XT::Grid::is_view<GridView>::value, ""); + +protected: + using GV = GridView; + using G = typename GridView::Grid; + static const constexpr size_t m = m_; + using D = double; + static const constexpr size_t d = G::dimension; + using R = double; + using E = XT::Grid::extract_entity_t<GV>; + using DomainType = XT::Common::FieldVector<D, d>; + using RangeType = XT::Common::FieldVector<D, m>; + using GP = XT::Grid::GridProvider<G>; + using S = SpaceInterface<GV, m>; + using V = typename XT::LA::Container<R, la>::VectorType; + using DF = DiscreteFunction<V, GV, m>; + using BS = BochnerSpace<GV, m>; + using O = OperatorInterface<V, GV, m>; + +public: + InstationaryEocStudy(const double T_end, + const size_t num_refinements = 3, + const size_t num_additional_refinements_for_reference = 2, + std::function<void(const DiscreteBochnerFunction<V, GV, m>&, const std::string&)> visualizer = + [](const auto& /*solution*/, const auto& /*prefix*/) { /*no visualization by default*/ }) + : T_end_(T_end) + , num_refinements_(num_refinements) + , num_additional_refinements_for_reference_(num_additional_refinements_for_reference) + , visualize_(visualizer) + , current_refinement_(std::numeric_limits<size_t>::max()) + , current_data_() + , current_grid_(nullptr) + , current_space_(nullptr) + , reference_grid_(nullptr) + , reference_space_(nullptr) + , current_solution_on_reference_grid_(nullptr) + , reference_solution_on_reference_grid_(nullptr) + { + } + + virtual size_t num_refinements() const override + { + return num_refinements_; + } + + virtual std::vector<std::string> targets() const override + { + return {"h", "dt"}; + } + + virtual std::vector<std::string> norms() const override + { + return {"L_infty/L_1", "L_infty/L_2", "L_2/L_2"}; + } + + virtual std::vector<std::string> estimates() const override + { + return {}; + } + + virtual std::string discretization_info_title() const override + { + return " |grid| | #DoFs"; + } + +protected: + virtual GP make_initial_grid() = 0; + + virtual std::unique_ptr<S> make_space(const GP& current_grid) = 0; + + virtual double estimate_dt(const S& space) = 0; + +public: + virtual std::string discretization_info(const size_t refinement_level) override + { + auto& self = *this; + if (current_refinement_ != refinement_level) { + // clear the current state + current_grid_.reset(); + current_space_.reset(); + current_solution_on_reference_grid_.reset(); + // compute on this refinement + current_grid_ = std::make_unique<GP>(make_initial_grid()); + for (size_t ref = 0; ref < refinement_level; ++ref) + current_grid_->global_refine(DGFGridInfo<G>::refineStepsForHalf()); + current_space_ = make_space(*current_grid_); + double grid_size = 0; + double grid_width = 0.; + for (auto&& grid_element : elements(current_space_->grid_view())) { + grid_size += 1; + grid_width = std::max(grid_width, XT::Grid::entity_diameter(grid_element)); + } + current_refinement_ = refinement_level; + current_data_.clear(); + current_data_["target"]["h"] = grid_width; + current_data_["target"]["dt"] = self.estimate_dt(*current_space_); + current_data_["info"]["num_grid_elements"] = grid_size; + current_data_["info"]["num_dofs"] = current_space_->mapper().size(); + } + const auto lfill_nicely = [&](const auto& number, const auto& len) { + std::string ret; + using XT::Common::to_string; + if (std::log10(number) < len) + ret = this->lfill(to_string(number), len); + else { + std::stringstream ss; + ss << std::setprecision(2) << std::scientific << number; + ret = this->lfill(ss.str(), len); + } + return ret; + }; + return lfill_nicely(current_data_["info"]["num_grid_elements"], 7) + " | " + + lfill_nicely(current_data_["info"]["num_dofs"], 7); + } // ... discretization_info(...) + +protected: + virtual std::unique_ptr<O> make_lhs_operator(const S& space) = 0; + + virtual XT::LA::ListVectorArray<V> solve(const S& space, const double T_end, const double dt) = 0; + + virtual void compute_reference_solution() + { + if (reference_solution_on_reference_grid_) + return; + reference_grid_ = std::make_unique<GP>(make_initial_grid()); + for (size_t ref = 0; ref < num_refinements_ + num_additional_refinements_for_reference_; ++ref) + reference_grid_->global_refine(DGFGridInfo<G>::refineStepsForHalf()); + reference_space_ = make_space(*reference_grid_); + reference_solution_on_reference_grid_ = + std::make_unique<XT::LA::ListVectorArray<V>>(solve(*reference_space_, T_end_, estimate_dt(*reference_space_))); + // visualize + const BS reference_bochner_space(*reference_space_, + time_points_from_vector_array(*reference_solution_on_reference_grid_)); + visualize_(make_discrete_bochner_function(reference_bochner_space, *reference_solution_on_reference_grid_), + "reference_solution_on_refinement_" + + XT::Common::to_string(num_refinements_ + num_additional_refinements_for_reference_)); + } // ... compute_reference_solution(...) + +public: + virtual std::map<std::string, std::map<std::string, double>> + compute(const size_t refinement_level, const std::vector<std::string>& only_these) override + { + auto& self = *this; + if (current_refinement_ != refinement_level) + self.discretization_info(refinement_level); + DUNE_THROW_IF(!current_space_, InvalidStateException, ""); + // compute current solution + const auto& current_space = *current_space_; + Timer timer; + auto solution_on_current_grid = solve(current_space, T_end_, current_data_["target"]["dt"]); + current_data_["info"]["time_to_solution"] = timer.elapsed(); + // visualize + const BS current_bochner_space(current_space, time_points_from_vector_array(solution_on_current_grid)); + visualize_(make_discrete_bochner_function(current_bochner_space, solution_on_current_grid), + "solution_on_refinement_" + XT::Common::to_string(refinement_level)); + const auto coarse_solution = make_discrete_bochner_function(current_bochner_space, solution_on_current_grid); + // determine wether we need a reference solution + // compute statistics + std::vector<std::string> actual_norms = self.filter(self.norms(), only_these); + // - norms + if (!actual_norms.empty()) { + self.compute_reference_solution(); + DUNE_THROW_IF(!reference_space_, InvalidStateException, ""); + const auto& reference_space = *reference_space_; + DUNE_THROW_IF(!reference_solution_on_reference_grid_, InvalidStateException, ""); + auto& u = *reference_solution_on_reference_grid_; + // prolong + const BS reference_bochner_space(reference_space, + time_points_from_vector_array(*reference_solution_on_reference_grid_)); + current_solution_on_reference_grid_ = std::make_unique<XT::LA::ListVectorArray<V>>( + prolong<V>(coarse_solution, reference_bochner_space).dof_vectors()); + auto& u_h = *current_solution_on_reference_grid_; + while (!actual_norms.empty()) { + const auto norm_id = actual_norms.back(); + const auto components = XT::Common::tokenize(norm_id, "/"); + actual_norms.pop_back(); + // compute Bochner norm + DUNE_THROW_IF(components.size() != 2, + XT::Common::Exceptions::wrong_input_given, + "I do not know how to compute the following norm: " << norm_id); + const auto temporal_norm_id = components[0]; + const auto spatial_norm_id = components[1]; + // - spatial component + std::function<double(const DF&)> spatial_norm; + if (spatial_norm_id == "L_1") { + spatial_norm = [&](const DF& func) { + auto localizable_functional = make_localizable_functional(reference_space.grid_view(), func); + localizable_functional.append(LocalElementIntegralFunctional<E>(LocalElementAbsIntegrand<E>())); + localizable_functional.assemble(); + return localizable_functional.result(); + }; + } else if (spatial_norm_id == "L_2") { + spatial_norm = [&](const DF& func) { + auto localizable_product = make_localizable_bilinear_form(reference_space.grid_view(), func, func); + localizable_product.append(LocalElementIntegralBilinearForm<E>(LocalElementProductIntegrand<E>())); + localizable_product.assemble(); + return std::sqrt(localizable_product.result()); + }; + } else + DUNE_THROW(XT::Common::Exceptions::wrong_input_given, + "I do not know how to compute the spatial norm '" << spatial_norm_id << "'!"); + // - temporal component + if (temporal_norm_id == "L_infty") { + double result = 0; + for (size_t ii = 0; ii < u.length(); ++ii) + result = std::max(result, + spatial_norm(make_discrete_function(reference_space, u[ii].vector() - u_h[ii].vector()))); + current_data_["norm"][norm_id] = result; + } else if (temporal_norm_id == "L_2") { + const XT::Functions::LambdaFunction<1> spatial_norm_function(1, [&](const auto& time, const auto& /*param*/) { + const auto u_t = make_discrete_bochner_function(reference_bochner_space, u).evaluate(time); + const auto u_h_t = make_discrete_bochner_function(reference_bochner_space, u_h).evaluate(time); + return spatial_norm(make_discrete_function(reference_space, u_t - u_h_t)); + }); + auto temporal_grid_view = reference_bochner_space.temporal_space().grid_view(); + using TE = XT::Grid::extract_entity_t<decltype(temporal_grid_view)>; + const auto& spatial_norm_as_temporal_grid_function = spatial_norm_function.template as_grid_function<TE>(); + auto localizable_temporal_product = make_localizable_bilinear_form( + temporal_grid_view, spatial_norm_as_temporal_grid_function, spatial_norm_as_temporal_grid_function); + localizable_temporal_product.append(LocalElementIntegralBilinearForm<TE>(LocalElementProductIntegrand<TE>())); + localizable_temporal_product.assemble(); + current_data_["norm"][norm_id] = localizable_temporal_product.result(); + } else + DUNE_THROW(XT::Common::Exceptions::wrong_input_given, + "I do not know how to compute the temporal norm '" << temporal_norm_id << "'!"); + } + } + // - estimates + std::vector<std::string> actual_estimates = self.filter(self.estimates(), only_these); + DUNE_THROW_IF(!actual_estimates.empty(), + XT::Common::Exceptions::wrong_input_given, + "I did not know how to compute the following estimates: " << actual_estimates); + return current_data_; + } // ... compute_on_current_refinement(...) + +protected: + static std::vector<double> time_points_from_vector_array(const XT::LA::ListVectorArray<V>& va) + { + std::vector<double> time_points; + time_points.reserve(va.length()); + for (const auto& note : va.notes()) + time_points.emplace_back(note.get("_t").at(0)); + return time_points; + } + + const double T_end_; + const size_t num_refinements_; + const size_t num_additional_refinements_for_reference_; + const std::function<void(const DiscreteBochnerFunction<V, GV, m>&, const std::string&)> visualize_; + size_t current_refinement_; + std::map<std::string, std::map<std::string, double>> current_data_; + std::unique_ptr<GP> current_grid_; + std::unique_ptr<S> current_space_; + std::unique_ptr<GP> reference_grid_; + std::unique_ptr<S> reference_space_; + std::unique_ptr<XT::LA::ListVectorArray<V>> current_solution_on_reference_grid_; + std::unique_ptr<XT::LA::ListVectorArray<V>> reference_solution_on_reference_grid_; +}; // struct InstationaryEocStudy + + +template <class V, class GV, size_t m> +XT::LA::ListVectorArray<V> solve_instationary_system_explicit_euler(const DiscreteFunction<V, GV, m>& initial_values, + const OperatorInterface<V, GV, m>& spatial_op, + const double T_end, + const double dt) +{ + // initial values + XT::LA::ListVectorArray<V> solution( + spatial_op.source_space().mapper().size(), /*length=*/0, /*reserve=*/std::ceil(T_end / (dt))); + solution.append(initial_values.dofs().vector(), {"_t", 0.}); + // timestepping + double time = 0.; + while (time < T_end + dt) { + time += dt; + const auto& u_n = solution.back().vector(); + auto u_n_plus_one = u_n - spatial_op.apply(u_n, {{"_t", {time}}, {"_dt", {dt}}}) * dt; + solution.append(std::move(u_n_plus_one), {"_t", time}); + } + return solution; +} // ... solve_instationary_system_explicit_euler(...) + + +} // namespace Tests +} // namespace GDT +} // namespace Dune + +#endif // DUNE_GDT_TEST_INSTATIONARY_EOCSTUDIES_BASE_HH diff --git a/dune/gdt/test/instationary-eocstudy.hh b/dune/gdt/test/instationary-eocstudy.hh deleted file mode 100644 index dcfeb37cb..000000000 --- a/dune/gdt/test/instationary-eocstudy.hh +++ /dev/null @@ -1,312 +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 (2016 - 2017) -// Rene Milk (2016 - 2018) -// Tobias Leibner (2016 - 2017) - -#ifndef DUNE_GDT_TEST_INSTATIONARY_EOCSTUDY_HH -#define DUNE_GDT_TEST_INSTATIONARY_EOCSTUDY_HH - -#include <dune/xt/common/convergence-study.hh> -#include <dune/xt/common/exceptions.hh> - -#include <dune/xt/grid/information.hh> - -#include <dune/gdt/projections.hh> -#include <dune/gdt/prolongations.hh> - -namespace Dune { -namespace GDT { -namespace Test { - - -template <class TestCaseImp, class DiscretizerImp> -class InstationaryEocStudy : public XT::Common::ConvergenceStudy -{ - typedef XT::Common::ConvergenceStudy BaseType; - -protected: - typedef TestCaseImp TestCaseType; - typedef DiscretizerImp Discretizer; - typedef typename Discretizer::DiscretizationType DiscretizationType; - typedef typename TestCaseType::GridType GridType; - typedef typename Discretizer::ProblemType ProblemType; - typedef typename DiscretizationType::DiscreteSolutionType DiscreteSolutionType; - typedef typename DiscretizationType::DiscreteFunctionType DiscreteFunctionType; - typedef typename DiscreteSolutionType::key_type TimeFieldType; - - typedef typename TestCaseType::InitialValueType InitialValueType; - typedef typename TestCaseType::LevelGridViewType GridLayerType; - -public: - InstationaryEocStudy(TestCaseType& test_case, - const std::vector<std::string> only_these_norms = {}, - const std::string visualize_prefix = "transport_test") - : BaseType(only_these_norms) - , test_case_(test_case) - , current_refinement_(0) - , last_computed_refinement_(std::numeric_limits<size_t>::max()) - , grid_widths_(num_refinements() + 1, -1.0) - , time_to_solution_(0) - , reference_solution_computed_(false) - , discrete_exact_solution_computed_(false) - , current_discretization_(nullptr) - , current_solution_on_level_(nullptr) - , reference_discretization_(nullptr) - , reference_solution_(nullptr) - , current_solution_(nullptr) - , discrete_exact_solution_(nullptr) - , visualize_prefix_(visualize_prefix) - { - } - - virtual ~InstationaryEocStudy() = default; - - virtual size_t num_refinements() const override final - { - return test_case_.num_refinements(); - } - - virtual std::vector<std::string> provided_norms() const override final - { - std::vector<std::string> ret = available_norms(); - for (auto estimator : available_estimators()) { - if (is_norm(estimator)) - DUNE_THROW(XT::Common::Exceptions::internal_error, - "We do not want to handle the case that norms and estimators have the same name!"); - ret.push_back(estimator); - } - return ret; - } // ... provided_norms(...) - - virtual double norm_reference_solution(const std::string type) override final - { - if (is_norm(type)) { - compute_reference_solution(); - assert(reference_solution_); - if (test_case_.provides_exact_solution()) { - compute_discrete_exact_solution_vector(); - assert(discrete_exact_solution_); - return compute_norm(*discrete_exact_solution_, type); - } else { - return compute_norm(*reference_solution_, type); - } - } else - return 1.0; - } // ... norm_reference_solution(...) - - virtual size_t current_num_DoFs() override final - { - assert(current_refinement_ <= num_refinements()); - const int level = test_case_.level_of(current_refinement_); - return test_case_.grid().size(level, 0); - } // ... current_num_DoFs(...) - - virtual size_t current_grid_size() const override final - { - assert(current_refinement_ <= num_refinements()); - const int level = test_case_.level_of(current_refinement_); - return test_case_.grid().size(level, 0); - } // ... current_grid_size(...) - - virtual double current_grid_width() override final - { - assert(current_refinement_ <= num_refinements()); - if (grid_widths_[current_refinement_] < 0.0) { - const int level = test_case_.level_of(current_refinement_); - const auto grid_layer = test_case_.template layer<XT::Grid::Layers::level, XT::Grid::Backends::view>(level); - grid_widths_[current_refinement_] = XT::Grid::dimensions(grid_layer).entity_width.max(); - assert(grid_widths_[current_refinement_] > 0.0); - } - return grid_widths_[current_refinement_]; - } // ... current_grid_width(...) - - virtual double compute_on_current_refinement() override final - { - if (current_refinement_ != last_computed_refinement_) { - assert(current_refinement_ <= num_refinements()); - // compute solution - Timer timer; - current_discretization_ = XT::Common::make_unique<DiscretizationType>(Discretizer::discretize( - test_case_, test_case_, test_case_.level_of(current_refinement_), test_case_.periodic_directions())); - current_solution_on_level_ = XT::Common::make_unique<DiscreteSolutionType>(current_discretization_->solve()); - time_to_solution_ = timer.elapsed(); - // prolong to reference grid part - compute_reference_solution(); - assert(reference_solution_); - if (!current_solution_) - current_solution_ = XT::Common::make_unique<DiscreteSolutionType>(*reference_solution_); - // time prolongation - DiscreteSolutionType time_prolongated_current_solution_on_level; - const auto time_prolongated_current_solution_on_level_it_end = time_prolongated_current_solution_on_level.end(); - auto current_solution_on_level_it = current_solution_on_level_->begin(); - const auto current_solution_on_level_it_last = --current_solution_on_level_->end(); - const auto current_solution_it_end = current_solution_->end(); - auto last_time = current_solution_->begin()->first; - for (auto current_solution_it = current_solution_->begin(); current_solution_it != current_solution_it_end; - ++current_solution_it) { - const auto time = current_solution_it->first; - const auto time_on_level = current_solution_on_level_it->first; - const auto inserted_it = time_prolongated_current_solution_on_level.emplace_hint( - time_prolongated_current_solution_on_level_it_end, time, current_solution_on_level_it->second); - if (time_on_level < time && current_solution_on_level_it != current_solution_on_level_it_last) { - // compute weighted average of the two values of current_solution_on_level_ - inserted_it->second.vector() = (current_solution_on_level_it->second.vector() * (time_on_level - last_time) - + (++current_solution_on_level_it)->second.vector() * (time - time_on_level)) - * (1.0 / (time - last_time)); - } - last_time = time; - } - // spatial prolongation - for (auto current_solution_it = current_solution_->begin(); current_solution_it != current_solution_it_end; - ++current_solution_it) - prolong(time_prolongated_current_solution_on_level.at(current_solution_it->first), - (*current_solution_it).second); - last_computed_refinement_ = current_refinement_; - // visualize - if (!visualize_prefix_.empty()) { - size_t counter = 0; - for (auto current_solution_it = current_solution_->begin(); current_solution_it != current_solution_it_end; - ++current_solution_it, ++counter) - current_solution_it->second.visualize(visualize_prefix_ + "_solution_" - + Dune::XT::Common::to_string(current_refinement_), - Dune::XT::Common::to_string(counter)); - } - } - return time_to_solution_; - } // ... compute_on_current_refinement(...) - - virtual double current_error_norm(const std::string type) override final - { - // get current solution - assert(current_refinement_ <= num_refinements()); - compute_on_current_refinement(); - assert(last_computed_refinement_ == current_refinement_); - if (is_norm(type)) { - assert(current_solution_); - compute_reference_solution(); - assert(reference_discretization_); - // compute error - std::unique_ptr<DiscreteSolutionType> difference; - if (test_case_.provides_exact_solution()) { - compute_discrete_exact_solution_vector(); - assert(discrete_exact_solution_); - difference = Dune::XT::Common::make_unique<DiscreteSolutionType>(*discrete_exact_solution_); - } else { - assert(reference_solution_); - difference = Dune::XT::Common::make_unique<DiscreteSolutionType>(*reference_solution_); - } - for (auto& difference_at_time : *difference) { - auto time = difference_at_time.first; - assert(current_solution_->count(time) && "Time steps must be the same"); - difference_at_time.second.vector() = difference_at_time.second.vector() - current_solution_->at(time).vector(); - } - return compute_norm(*difference, type); - } else { - assert(current_solution_on_level_); - return estimate(*current_solution_on_level_, type); - } - } // ... current_error_norm(...) - - virtual void refine() override final - { - if (current_refinement_ <= num_refinements()) - ++current_refinement_; - } - - std::map<std::string, std::vector<double>> run(std::ostream& out, const bool print_timings = false) - { - return BaseType::run(false, out, print_timings); - } - -protected: - void compute_reference_solution() - { - if (!reference_solution_computed_) { - reference_discretization_ = XT::Common::make_unique<DiscretizationType>(Discretizer::discretize( - test_case_, test_case_, test_case_.reference_level(), test_case_.periodic_directions())); - reference_solution_ = XT::Common::make_unique<DiscreteSolutionType>(reference_discretization_->solve()); - reference_solution_computed_ = true; - if (!visualize_prefix_.empty()) { - size_t counter = 0; - const auto reference_solution_it_end = reference_solution_->end(); - for (auto reference_solution_it = reference_solution_->begin(); - reference_solution_it != reference_solution_it_end; - ++reference_solution_it, ++counter) - reference_solution_it->second.visualize(visualize_prefix_ + "_reference" - + Dune::XT::Common::to_string(current_refinement_), - Dune::XT::Common::to_string(counter)); - } - } - } // ... compute_reference_solution() - - void compute_discrete_exact_solution_vector() - { - if (!discrete_exact_solution_computed_) { - discrete_exact_solution_ = Dune::XT::Common::make_unique<DiscreteSolutionType>(); - compute_reference_solution(); - const auto exact_solution = test_case_.exact_solution(); - const auto reference_solution_it_end = reference_solution_->end(); - for (auto reference_solution_it = reference_solution_->begin(); - reference_solution_it != reference_solution_it_end; - ++reference_solution_it) { - const double time = reference_solution_it->first; - const auto inserted_it = discrete_exact_solution_->emplace_hint( - discrete_exact_solution_->end(), time, reference_solution_it->second); - project_l2(*exact_solution, inserted_it->second, 0, {"t", time}); - } - if (!visualize_prefix_.empty()) { - size_t counter = 0; - const auto discrete_exact_solution_it_end = discrete_exact_solution_->end(); - for (auto discrete_exact_solution_it = discrete_exact_solution_->begin(); - discrete_exact_solution_it != discrete_exact_solution_it_end; - ++discrete_exact_solution_it, ++counter) - discrete_exact_solution_it->second.visualize(visualize_prefix_ + "_exact_solution" - + Dune::XT::Common::to_string(current_refinement_), - Dune::XT::Common::to_string(counter)); - } - discrete_exact_solution_computed_ = true; - } - } - - bool is_norm(const std::string type) const - { - const auto norms = available_norms(); - return std::find(norms.begin(), norms.end(), type) != norms.end(); - } - - virtual std::vector<std::string> available_norms() const = 0; - - virtual std::vector<std::string> available_estimators() const = 0; - - virtual double estimate(const DiscreteSolutionType& solution, const std::string type) = 0; - - virtual double compute_norm(const DiscreteSolutionType& solution, const std::string type) = 0; - - TestCaseType& test_case_; - size_t current_refinement_; - size_t last_computed_refinement_; - mutable std::vector<double> grid_widths_; - double time_to_solution_; - bool reference_solution_computed_; - bool discrete_exact_solution_computed_; - std::unique_ptr<DiscretizationType> current_discretization_; - std::unique_ptr<DiscreteSolutionType> current_solution_on_level_; - std::unique_ptr<DiscretizationType> reference_discretization_; - std::unique_ptr<DiscreteSolutionType> reference_solution_; - std::unique_ptr<DiscreteSolutionType> current_solution_; - std::unique_ptr<DiscreteSolutionType> discrete_exact_solution_; - const std::string visualize_prefix_; -}; // class InstationaryEocStudy - - -} // namespace Tests -} // namespace GDT -} // namespace Dune - -#endif // DUNE_GDT_TEST_INSTATIONARY_EOCSTUDY_HH diff --git a/dune/gdt/test/instationary-testcase.hh b/dune/gdt/test/instationary-testcase.hh deleted file mode 100644 index c7a2bc8b3..000000000 --- a/dune/gdt/test/instationary-testcase.hh +++ /dev/null @@ -1,100 +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 (2016 - 2017) -// Rene Milk (2016 - 2018) -// Tobias Leibner (2017) - -#ifndef DUNE_GDT_TEST_INSTATIONARY_TESTCASE_HH -#define DUNE_GDT_TEST_INSTATIONARY_TESTCASE_HH - -#include <dune/xt/common/exceptions.hh> - -#include <dune/xt/grid/type_traits.hh> -#include <dune/xt/grid/information.hh> -#include <dune/xt/grid/gridprovider/eoc.hh> - -namespace Dune { -namespace GDT { -namespace Test { - - -/** - * \tparam ProblemType has to provide a type SolutionType which - * defines the type of the solution of the problem. - * TODO: choose suitable SolutionType for Problems (provide Interface?) - */ -template <class GridImp, class ProblemImp> -class InstationaryTestCase : public XT::Grid::EOCGridProvider<GridImp> -{ - typedef XT::Grid::EOCGridProvider<GridImp> EocBaseType; - -public: - typedef ProblemImp ProblemType; - typedef typename ProblemType::InitialValueType InitialValueType; - typedef typename ProblemType::SolutionType SolutionType; - -public: - template <class... Args> - InstationaryTestCase(const double divide_t_end_by_this, Args&&... args) - : EocBaseType(std::forward<Args>(args)...) - , divide_t_end_by_this_(divide_t_end_by_this) - , zero_() - { - } - - virtual ~InstationaryTestCase() = default; - - virtual const ProblemType& problem() const = 0; - - virtual void print_header(std::ostream& out = std::cout) const - { - out << "+===============================================================+\n" - << "|+=============================================================+|\n" - << "|| This is a GDT::Tests:InstationaryTestCase, please provide ||\n" - << "|| a meaningful message by implementing `print_header()` ||\n" - << "|+=============================================================+|\n" - << "+===============================================================+" << std::endl; - } - - virtual bool provides_exact_solution() const - { - return false; - } - - virtual std::bitset<GridImp::dimension> periodic_directions() const - { - return std::bitset<GridImp::dimension>(); - } - - virtual double t_end() const - { - return problem().t_end() / divide_t_end_by_this_; - } - - virtual const std::shared_ptr<const SolutionType> exact_solution() const - { - if (provides_exact_solution()) - DUNE_THROW(XT::Common::Exceptions::you_have_to_implement_this, - "If provides_exact_solution() is true, exact_solution() has to be implemented!"); - else - DUNE_THROW(XT::Common::Exceptions::you_are_using_this_wrong, - "Do not call exact_solution() if provides_exact_solution() is false!"); - return zero_; - } - -private: - const double divide_t_end_by_this_; - const std::shared_ptr<const SolutionType> zero_; -}; // class InstationaryTestCase - - -} // namespace Tests -} // namespace GDT -} // namespace Dune - -#endif // DUNE_GDT_TEST_INSTATIONARY_TESTCASE_HH -- GitLab