Skip to content
Snippets Groups Projects
convergencetest.cc 5.02 KiB
Newer Older
#include "config.h"

#include <iostream>

#if !HAVE_DUNE_FOAMGRID
#error "Need dune-foamgrid for the definition of the convergence test"
#endif

#if !HAVE_DUNE_LOCALFUNCTIONS
#error "Need dune-localfunctions for the definition of the convergence test"
#endif

#include <dune/common/parallel/mpihelper.hh> // An initializer of MPI
#include <dune/common/test/testsuite.hh>
#include <dune/curvedgrid/curvedgrid.hh>
#include <dune/foamgrid/foamgrid.hh>
#include <dune/geometry/quadraturerules.hh>
#include <dune/grid/io/file/gmshreader.hh>
#include <dune/localfunctions/lagrange/pk.hh>

#if WRITE_FILES
#include <dune/vtk/vtkwriter.hh>
#include <dune/vtk/datacollectors/lagrangedatacollector.hh>
#endif

// 1 .. Sphere
// 2 .. Ellipsoid
// 3 .. Torus
// 4 .. Cylinder
#ifndef GEOMETRY_TYPE
#define GEOMETRY_TYPE 1
#endif

#if GEOMETRY_TYPE == 1
#include <dune/curvedgrid/geometries/sphere.hh>
#elif GEOMETRY_TYPE == 2
#include <dune/curvedgrid/geometries/ellipsoid.hh>
#elif GEOMETRY_TYPE == 3
#include <dune/curvedgrid/geometries/torus.hh>
#elif GEOMETRY_TYPE == 4
#include <dune/curvedgrid/geometries/cylinder.hh>
#error "Unknown GEOMETRY_TYPE. Must bei either 1, 2, 3, or 4"
#endif

// polynomial order of geometry
#ifndef GEOMETRY_ORDER
#define GEOMETRY_ORDER 3
#endif

#include "convergence.hh"

const int order = GEOMETRY_ORDER;
const int quad_order = order+6;
const int num_levels = 5;

int main (int argc, char** argv)
{
  using namespace Dune;
  MPIHelper::instance(argc, argv);

  using HostGrid = FoamGrid<2,3>;
#if GEOMETRY_TYPE == 1
  std::unique_ptr<HostGrid> hostGrid = GmshReader<HostGrid>::read( DUNE_GRID_PATH "sphere.msh");
  auto gridFct = sphereGridFunction<HostGrid>(1.0);
#elif GEOMETRY_TYPE == 2
  std::unique_ptr<HostGrid> hostGrid = GmshReader<HostGrid>::read( DUNE_GRID_PATH "ellipsoid3.msh");
  auto gridFct = ellipsoidGridFunction<HostGrid>(1.0, 0.75, 1.25);
#elif GEOMETRY_TYPE == 3
  std::unique_ptr<HostGrid> hostGrid = GmshReader<HostGrid>::read( DUNE_GRID_PATH "torus2.msh");
  auto gridFct = torusGridFunction<HostGrid>(2.0, 1.0);
#elif GEOMETRY_TYPE == 4
  std::unique_ptr<HostGrid> hostGrid = GmshReader<HostGrid>::read( DUNE_GRID_PATH "cylinder.msh");
  auto gridFct = cylinderGridFunction<HostGrid>(1.0);
  CurvedGrid grid(*hostGrid, gridFct, order);
  using Grid = decltype(grid);
  std::vector<typename Grid::ctype> inf_errors, L2_errors, normal_errors, curvature_errors, edge_lengths;
  for (int i = 0; i < num_levels; ++i) {
    if (i > 0)
      grid.globalRefine(1);

#if WRITE_FILES
    using DC = LagrangeDataCollector<typename Grid::LeafGridView, order>;
    VtkUnstructuredGridWriter<typename Grid::LeafGridView, DC> writer(grid.leafGridView());
    writer.write("level_" + std::to_string(i) + ".vtu");
#endif

    std::cout << "level = " << i << std::endl;
    inf_errors.push_back( inf_error(grid, gridFct.f(), quad_order) );
    L2_errors.push_back( L2_error(grid, gridFct.f(), quad_order) );
    normal_errors.push_back( normal_error(grid, gridFct.f(), quad_order) );
    curvature_errors.push_back( curvature_error(grid, gridFct.f(), quad_order) );
    edge_lengths.push_back( edge_length(grid) );
  }

  using std::log;
  using std::abs;

  // calculate the experimental order of convergence
  std::vector<typename Grid::ctype> eocInf(num_levels, 0), eocL2(num_levels, 0), eocNormal(num_levels, 0), eocCurvature(num_levels, 0);
  for (int i = 1; i < num_levels; ++i) {
    eocInf[i]       = log(inf_errors[i]/inf_errors[i-1]) / log(edge_lengths[i]/edge_lengths[i-1]);
    eocL2[i]        = log(L2_errors[i]/L2_errors[i-1]) / log(edge_lengths[i]/edge_lengths[i-1]);
    eocNormal[i]    = log(normal_errors[i]/normal_errors[i-1]) / log(edge_lengths[i]/edge_lengths[i-1]);
    eocCurvature[i] = log(curvature_errors[i]/curvature_errors[i-1]) / log(edge_lengths[i]/edge_lengths[i-1]);
  }

  TestSuite test;
  test.check(abs(eocInf.back()    - (order+1)) < 0.5, "|d|_L^inf != order+1");
  test.check(abs(eocL2.back()     - (order+1)) < 0.5, "|d|_L^2 != order+1");
  test.check(abs(eocNormal.back() - (order+0)) < 0.5, "|n - nh|_L^2 != order");
  test.check(abs(eocCurvature.back()   - (order-1)) < 0.5, "|H - Hh|_L^2 != order-1");


  auto print_line = [](auto i, const auto& data, auto accept) {
    std::cout << i;
    for (const auto& d : data) {
      std::cout << '\t' << "| ";
      if (accept(d))
        std::cout << d;
      else
        std::cout << '\t';
    }
    std::cout << std::endl;
  };

  auto print_break = [] {
    std::cout.width(8 + 9*16);
    std::cout.fill('-');
    std::cout << '-' << std::endl;
    std::cout.fill(' ');
  };

  std::cout.setf(std::ios::scientific);
  print_line("level", std::vector<std::string>{"h       ","err_inf", "eoc_inf", "err_L2", "eoc_L2", "err_norm", "eoc_norm", "err_curv", "eoc_curv"},
    [](auto&&) { return true; });
  print_break();

  for (int i = 0; i < num_levels; ++i)
    print_line(i, std::vector<typename Grid::ctype>{edge_lengths[i], inf_errors[i], eocInf[i], L2_errors[i], eocL2[i], normal_errors[i], eocNormal[i], curvature_errors[i], eocCurvature[i]},
      [](auto&&) { return true; });

  return test.exit();
}