From 64e4853ea1d926677104c7694b51f96bc0a80f33 Mon Sep 17 00:00:00 2001
From: Felix Albrecht <mail@felixalbrecht.de>
Date: Wed, 2 Oct 2013 20:00:38 +0200
Subject: [PATCH] [common.convergence-study] added for arbitrary
 norms/discretizations

---
 dune/stuff/common/convergence-study.hh | 167 +++++++++++++++++++++++++
 1 file changed, 167 insertions(+)
 create mode 100644 dune/stuff/common/convergence-study.hh

diff --git a/dune/stuff/common/convergence-study.hh b/dune/stuff/common/convergence-study.hh
new file mode 100644
index 000000000..1602d2e2b
--- /dev/null
+++ b/dune/stuff/common/convergence-study.hh
@@ -0,0 +1,167 @@
+// This file is part of the dune-gdt project:
+//   http://users.dune-project.org/projects/dune-gdt
+// Copyright holders: Felix Albrecht
+// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
+
+#ifndef DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH
+#define DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH
+
+#include <vector>
+#include <map>
+#include <iostream>
+
+#include <dune/common/exceptions.hh>
+
+#include <dune/stuff/common/string.hh>
+
+namespace Dune {
+namespace Stuff {
+namespace Common {
+
+
+class ConvergenceStudy
+{
+public:
+  virtual ~ConvergenceStudy()
+  {
+  }
+
+  virtual std::string identifier() const = 0;
+
+  virtual size_t num_refinements() const = 0;
+
+  virtual std::vector<std::string> provided_norms() const = 0;
+
+  virtual size_t expected_rate(const std::string type) const = 0;
+
+  virtual double norm_reference_solution(const std::string type) = 0;
+
+  virtual size_t current_grid_size() const = 0;
+
+  virtual double current_grid_width() const = 0;
+
+  virtual void compute_on_current_refinement() = 0;
+
+  virtual double current_error_norm(const std::string type) = 0;
+
+  virtual void refine() = 0;
+
+  std::map<std::string, std::vector<double>> run(std::ostream& out = std::cout)
+  {
+    if (provided_norms().size() == 0)
+      DUNE_THROW(Dune::InvalidStateException, "You have to provide at least one norm!");
+    std::map<std::string, std::vector<double>> ret;
+    for (const auto& norm : provided_norms())
+      ret[norm] = std::vector<double>();
+
+    // print table header
+    out << identifier() << std::endl;
+    if (identifier().size() > 22 * (provided_norms().size() + 1))
+      out << Stuff::Common::whitespaceify(identifier(), '=') << std::endl;
+    else {
+      out << "=====================";
+      for (size_t nn = 0; nn < provided_norms().size(); ++nn)
+        out << "======================";
+    }
+    out << "\n";
+    // * print line of grid and norms
+    out << "        grid         ";
+    for (const auto& norm : provided_norms()) {
+      std::string relative_norm_str = "";
+      if (norm.empty())
+        relative_norm_str = "??? (relative)";
+      else if (norm.size() <= 8)
+        relative_norm_str = norm + " (relative)";
+      else if (norm.size() <= 12)
+        relative_norm_str = norm + " (rel.)";
+      else
+        relative_norm_str  = norm.substr(0, 11) + ". (rel.)";
+      const double missing = (19.0 - relative_norm_str.size()) / 2.0;
+      for (size_t ii = 0; ii < missing; ++ii)
+        relative_norm_str += " ";
+      assert(relative_norm_str.size() <= 19);
+      out << "| " << std::setw(19) << relative_norm_str << " ";
+    }
+    out << "\n";
+    // * print thin delimiter
+    out << "---------------------";
+    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
+      out << "+---------------------";
+    out << "\n";
+    // * print size/width/error/EOC markers
+    out << "     size |    width ";
+    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
+      out << "|    error |      EOC ";
+    out << "\n";
+    // * print thick delimiter
+    out << "==========+==========";
+    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
+      out << "+==========+==========";
+    out << std::endl;
+
+    // prepare data structures
+    std::map<std::string, double> reference_norm;
+    std::map<std::string, double> last_relative_error;
+    for (const auto& norm : provided_norms()) {
+      reference_norm[norm]      = norm_reference_solution(norm);
+      last_relative_error[norm] = 0.0;
+    }
+    double last_grid_width = current_grid_width();
+
+    // iterate
+    for (size_t ii = 0; ii <= num_refinements(); ++ii) {
+      // print delimiter
+      if (ii > 0) {
+        out << "----------+----------";
+        for (size_t nn = 0; nn < provided_norms().size(); ++nn)
+          out << "+----------+----------";
+        out << "\n";
+      }
+
+      // print grid size
+      out << " " << std::setw(8) << current_grid_size() << std::flush;
+      // print grid with
+      out << " | " << std::setw(8) << std::setprecision(2) << std::scientific << current_grid_width() << std::flush;
+
+      // loop over all norms/columns
+      for (const auto& norm : provided_norms()) {
+        // compute and print relative error
+        const double relative_error = current_error_norm(norm) / reference_norm[norm];
+        ret[norm].push_back(relative_error);
+        out << " | " << std::setw(8) << std::setprecision(2) << std::scientific << relative_error << std::flush;
+        // print eoc
+        out << " | ";
+        if (ii == 0)
+          out << std::setw(8) << "----" << std::flush;
+        else {
+          const double eoc_value =
+              std::log(relative_error / last_relative_error[norm]) / std::log(current_grid_width() / last_grid_width);
+          std::stringstream eoc_string;
+          eoc_string << std::setw(8) << std::setprecision(2) << std::fixed << eoc_value;
+          if (eoc_value > (0.9 * expected_rate(norm)))
+            out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::green) << std::flush;
+          else if (eoc_value > 0.0)
+            out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::brown) << std::flush;
+          else
+            out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::red) << std::flush;
+        }
+        // update
+        last_relative_error[norm] = relative_error;
+      } // loop over all norms/columns
+      out << std::endl;
+      // update
+      last_grid_width = current_grid_width();
+      if (ii < num_refinements())
+        refine();
+    } // iterate
+
+    return ret;
+  } // ... run(...)
+}; // class ConvergenceStudy
+
+
+} // namespace Common
+} // namespace Stuff
+} // namespace Dune
+
+#endif // DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH
-- 
GitLab