Skip to content
Snippets Groups Projects
harmonicmaptest.cc 7.59 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include <config.h>
    
    #include <array>
    
    // Includes for the ADOL-C automatic differentiation library
    // Need to come before (almost) all others.
    #include <adolc/adouble.h>
    #include <dune/fufem/utilities/adolcnamespaceinjections.hh>
    
    #include <dune/common/typetraits.hh>
    #include <dune/common/bitsetvector.hh>
    
    #include <dune/common/version.hh>
    
    
    #include <dune/grid/uggrid.hh>
    #include <dune/grid/io/file/gmshreader.hh>
    
    #include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh>
    #include <dune/functions/functionspacebases/lagrangebasis.hh>
    #include <dune/functions/functionspacebases/powerbasis.hh>
    #include <dune/functions/functionspacebases/interpolate.hh>
    
    #include <dune/fufem/boundarypatch.hh>
    #include <dune/fufem/functiontools/boundarydofs.hh>
    
    #include <dune/gfe/localgeodesicfefunction.hh>
    #include <dune/gfe/localprojectedfefunction.hh>
    
    #include <dune/gfe/assemblers/localintegralstiffness.hh>
    
    #include <dune/gfe/assemblers/geodesicfeassembler.hh>
    
    #include <dune/gfe/assemblers/localintegralenergy.hh>
    #include <dune/gfe/densities/harmonicdensity.hh>
    
    #include <dune/gfe/riemanniantrsolver.hh>
    
    #include <dune/gfe/spaces/unitvector.hh>
    
    
    // grid dimension
    const int dim = 2;
    
    // Image space of the geodesic fe functions
    typedef UnitVector<double,3> TargetSpace;
    
    const int order = 1;
    
    using namespace Dune;
    
    
    int main (int argc, char *argv[])
    {
      MPIHelper::instance(argc, argv);
    
      using SolutionType = std::vector<TargetSpace>;
    
      // read problem settings
      const int numLevels                   = 4;
    
      // read solver settings
      const double tolerance                = 1e-6;
      const int maxTrustRegionSteps         = 1000;
    
      const double initialTrustRegionRadius = 0.25;
    
      const int multigridIterations         = 200;
      const int baseIterations              = 100;
      const double mgTolerance              = 1e-10;
      const double baseTolerance            = 1e-8;
    
      // ///////////////////////////////////////
      //    Create the grid
      // ///////////////////////////////////////
      using GridType = UGGrid<dim>;
    
      std::shared_ptr<GridType> grid = GmshReader<GridType>::read("grids/irregular-square.msh");
    
      grid->globalRefine(numLevels-1);
    
    
      grid->loadBalance();
    
    
      using GridView = GridType::LeafGridView;
      GridView gridView = grid->leafGridView();
    
      //////////////////////////////////////////////////////////////////////////////////
      //  Construct the scalar function space basis corresponding to the GFE space
      //////////////////////////////////////////////////////////////////////////////////
    
      using FEBasis = Functions::LagrangeBasis<GridView, order>;
      FEBasis feBasis(gridView);
      SolutionType x(feBasis.size());
    
    
      using namespace Functions::BasisFactory;
    
      // A basis for the embedding space
      auto powerBasis = makeBasis(
        gridView,
        power<TargetSpace::CoordinateType::dimension>(
          lagrange<order>(),
          blockedInterleaved()
    
    
      // A basis for the tangent space
      auto tangentBasis = makeBasis(
        gridView,
        power<TargetSpace::TangentVector::dimension>(
          lagrange<order>(),
          blockedInterleaved()
    
      ///////////////////////////////////////////
      //  Determine Dirichlet values
      ///////////////////////////////////////////
      BitSetVector<1> dirichletVertices(gridView.size(dim), false);
      const GridView::IndexSet& indexSet = gridView.indexSet();
    
      // Make predicate function that computes which vertices are on the Dirichlet boundary,
      // based on the vertex positions.
      auto dirichletVerticesPredicate = [](FieldVector<double,dim> x)
    
                                        {
                                          return (x[0] < -4.9999 or x[0] > 4.9999 or x[1] < -4.9999 or x[1] > 4.9999);
                                        };
    
    
      for (auto&& vertex : vertices(gridView))
      {
        bool isDirichlet = dirichletVerticesPredicate(vertex.geometry().corner(0));
        dirichletVertices[indexSet.index(vertex)] = isDirichlet;
      }
    
      BoundaryPatch<GridView> dirichletBoundary(gridView, dirichletVertices);
    
      BitSetVector<TargetSpace::TangentVector::dimension> dirichletNodes(powerBasis.size(), false);
    
    #if DUNE_VERSION_GTE(DUNE_FUFEM, 2, 10)
      Fufem::markBoundaryPatchDofs(dirichletBoundary,tangentBasis,dirichletNodes);
    #else
    
      constructBoundaryDofs(dirichletBoundary,tangentBasis,dirichletNodes);
    
    
      ////////////////////////////
      //  Initial iterate
      ////////////////////////////
    
      // The inverse stereographic projection through the north pole
      auto initialIterateFunction = [](FieldVector<double,dim> x) -> TargetSpace::CoordinateType
    
                                    {
                                      auto normSquared = x.two_norm2();
                                      return {2*x[0] / (normSquared+1), 2*x[1] / (normSquared+1), (normSquared-1)/ (normSquared+1)};
                                    };
    
    
      std::vector<TargetSpace::CoordinateType> v;
      Dune::Functions::interpolate(powerBasis, v, initialIterateFunction);
    
      for (size_t i=0; i<x.size(); i++)
        x[i] = v[i];
    
      //////////////////////////////////////////////////////////////
      //  Create an assembler for the Harmonic Energy Functional
      //////////////////////////////////////////////////////////////
    
    
      using InterpolationRule = LocalGeodesicFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, TargetSpace>;
    
      using InterpolationRule = GFE::LocalProjectedFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, TargetSpace,true>;
    
      using InterpolationRule = GFE::LocalProjectedFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, TargetSpace,false>;
    
      auto harmonicDensity = std::make_shared<GFE::HarmonicDensity<GridType::Codim<0>::Entity::Geometry::LocalCoordinate, TargetSpace> >();
    
      GFE::LocalIntegralStiffness<FEBasis,InterpolationRule,TargetSpace> localGFEADOLCStiffness(harmonicDensity);
    
      GeodesicFEAssembler<FEBasis,TargetSpace> assembler(feBasis, localGFEADOLCStiffness);
    
    
      ///////////////////////////////////////////////////
      //  Create a Riemannian trust-region solver
      ///////////////////////////////////////////////////
    
      RiemannianTrustRegionSolver<FEBasis,TargetSpace> solver;
      solver.setup(*grid,
                   &assembler,
                   x,
                   dirichletNodes,
                   tolerance,
                   maxTrustRegionSteps,
                   initialTrustRegionRadius,
                   multigridIterations,
                   mgTolerance,
                   3, 3, 1,   // Multigrid V-cycle
                   baseIterations,
                   baseTolerance,
                   false);   // Do not write intermediate iterates
    
      ///////////////////////////////////////////////////////
      //  Solve!
      ///////////////////////////////////////////////////////
    
      solver.setInitialIterate(x);
      solver.solve();
    
      x = solver.getSol();
    
    
    #if GEODESICINTERPOLATION
      std::size_t expectedFinalIteration = 8;
    #else
    #if CONFORMING
    
      std::size_t expectedFinalIteration = 10;
    
    #else
      std::size_t expectedFinalIteration = 6;
    #endif
    #endif
    
    
      if (solver.getStatistics().finalIteration != expectedFinalIteration)
      {
    
        std::cerr << "Trust-region solver did " << solver.getStatistics().finalIteration+1
                  << " iterations, instead of the expected '" << expectedFinalIteration+1 << "'!" << std::endl;
        return 1;
    
    #if GEODESICINTERPOLATION
      double expectedEnergy = 12.3154833;
    #else
    #if CONFORMING
    
      double expectedEnergy = 12.2927849;
    
    #else
      double expectedEnergy = 0.436857464;
    #endif
    #endif
    
      if ( std::abs(solver.getStatistics().finalEnergy - expectedEnergy) > 1e-7)
      {
    
        std::cerr << std::setprecision(9);
        std::cerr << "Final energy is " << solver.getStatistics().finalEnergy
                  << " but '" << expectedEnergy << "' was expected!" << std::endl;
        return 1;