Skip to content
Snippets Groups Projects
mixedriemannianpnsolvertest.cc 10.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include <config.h>
    
    // 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/bitsetvector.hh>
    #include <dune/common/typetraits.hh>
    #include <dune/common/tuplevector.hh>
    
    #include <dune/functions/functionspacebases/compositebasis.hh>
    #include <dune/functions/functionspacebases/interpolate.hh>
    #include <dune/functions/functionspacebases/lagrangebasis.hh>
    #include <dune/functions/functionspacebases/powerbasis.hh>
    
    #include <dune/fufem/boundarypatch.hh>
    #include <dune/fufem/functiontools/boundarydofs.hh>
    
    #include <dune/grid/utility/structuredgridfactory.hh>
    #include <dune/grid/uggrid.hh>
    
    #include <dune/gfe/assemblers/cosseratenergystiffness.hh>
    #include <dune/gfe/assemblers/geodesicfeassembler.hh>
    #include <dune/gfe/assemblers/geodesicfeassemblerwrapper.hh>
    #include <dune/gfe/assemblers/localgeodesicfeadolcstiffness.hh>
    #include <dune/gfe/assemblers/mixedgfeassembler.hh>
    #include <dune/gfe/mixedriemannianpnsolver.hh>
    #include <dune/gfe/riemannianpnsolver.hh>
    #include <dune/gfe/spaces/productmanifold.hh>
    #include <dune/gfe/spaces/realtuple.hh>
    #include <dune/gfe/spaces/rotation.hh>
    
    /** \file
     * \brief This test compares the MixedRiemannianPNSolver to the RiemannianPNSolver.
     */
    
    // grid dimension
    const int gridDim = 2;
    
    // target dimension
    const int dim = 3;
    
    //order of the finite element spaces, they need to be the same to compare!
    const int displacementOrder = 2;
    const int rotationOrder = displacementOrder;
    
    using namespace Dune;
    using namespace Indices;
    
    //differentiation method: ADOL-C
    using ValueType = adouble;
    
    //Types for the mixed space
    using DisplacementVector = std::vector<RealTuple<double,dim> >;
    using RotationVector =  std::vector<Rotation<double,dim> >;
    using Vector = TupleVector<DisplacementVector, RotationVector>;
    using BlockTupleVector = TupleVector<BlockVector<RealTuple<double,dim> >, BlockVector<Rotation<double,dim> > >;
    const int dimRotationTangent = Rotation<double,dim>::TangentVector::dimension;
    
    
    int main (int argc, char *argv[])
    {
      MPIHelper::instance(argc, argv);
    
      /////////////////////////////////////////////////////////////////////////
      //    Create the grid
      /////////////////////////////////////////////////////////////////////////
      using GridType = UGGrid<gridDim>;
      auto grid = StructuredGridFactory<GridType>::createCubeGrid({0.0,0.0}, {1.0,1.0}, {2,2});
      grid->globalRefine(2);
      grid->loadBalance();
    
      using GridView = GridType::LeafGridView;
      GridView gridView = grid->leafGridView();
    
      /////////////////////////////////////////////////////////////////////////
      //  Create a composite basis and a Lagrange FE basis
      /////////////////////////////////////////////////////////////////////////
    
      using namespace Functions::BasisFactory;
    
      auto compositeBasis = makeBasis(
        gridView,
        composite(
          power<dim>(
            lagrange<displacementOrder>()
            ),
          power<dim>(
            lagrange<rotationOrder>()
            )
          ));
    
      using CompositeBasis = decltype(compositeBasis);
    
      using DeformationFEBasis = Functions::LagrangeBasis<GridView,displacementOrder>;
      DeformationFEBasis deformationFEBasis(gridView);
    
      /////////////////////////////////////////////////////////////////////////
      //  Create the Neumann and Dirichlet boundary
      /////////////////////////////////////////////////////////////////////////
    
      std::function<bool(FieldVector<double,gridDim>)> isNeumann = [](FieldVector<double,gridDim> coordinate) {
                                                                     return coordinate[0] > 0.99; //Neumann for upper boundary
                                                                   };
      std::function<bool(FieldVector<double,gridDim>)> isDirichlet = [](FieldVector<double,gridDim> coordinate) {
                                                                       return coordinate[0] < 0.01; //Dircichlet for lower boundary
                                                                     };
    
      BitSetVector<1> neumannVertices(gridView.size(gridDim), false);
      BitSetVector<1> dirichletVertices(gridView.size(gridDim), false);
      const GridView::IndexSet& indexSet = gridView.indexSet();
    
      for (auto&& vertex : vertices(gridView)) {
        neumannVertices[indexSet.index(vertex)] = isNeumann(vertex.geometry().corner(0));
        dirichletVertices[indexSet.index(vertex)] = isDirichlet(vertex.geometry().corner(0));
      }
    
      BoundaryPatch<GridView> neumannBoundary(gridView, neumannVertices);
      BoundaryPatch<GridView> dirichletBoundary(gridView, dirichletVertices);
    
      BitSetVector<1> dirichletNodes(compositeBasis.size({0}),false);
    #if DUNE_VERSION_GTE(DUNE_FUFEM, 2, 10)
      Fufem::markBoundaryPatchDofs(dirichletBoundary, deformationFEBasis, dirichletNodes);
    #else
      constructBoundaryDofs(dirichletBoundary, deformationFEBasis, dirichletNodes);
    #endif
    
      typedef MultiTypeBlockVector<std::vector<FieldVector<double,dim> >, std::vector<FieldVector<double,dimRotationTangent> > > VectorForBit;
      using BitVector = Solvers::DefaultBitVector_t<VectorForBit>;
    
      BitVector dirichletDofs;
      dirichletDofs[_0].resize(compositeBasis.size({0}));
      dirichletDofs[_1].resize(compositeBasis.size({1}));
      for (size_t i = 0; i < compositeBasis.size({0}); i++) {
        for (size_t j = 0; j < dim; j++)
          dirichletDofs[_0][i][j] = dirichletNodes[i][0];
        for (size_t j = 0; j < dimRotationTangent; j++)
          dirichletDofs[_1][i][j] = dirichletNodes[i][0];
      }
    
      /////////////////////////////////////////////////////////////////////////
      //  Create the energy functions with their parameters
      /////////////////////////////////////////////////////////////////////////
    
      //Surface-Cosserat-Energy-Parameters
      ParameterTree parameters;
      parameters["thickness"] = "1";
      parameters["mu"] = "2.7191e+4";
      parameters["lambda"] = "4.4364e+4";
      parameters["mu_c"] = "0";
      parameters["L_c"] = "0.01";
      parameters["q"] = "2";
      parameters["kappa"] = "1";
    
      parameters["b1"] = "1";
      parameters["b2"] = "1";
      parameters["b3"] = "1";
    
    
      FieldVector<double,dim> values_ = {3e4,2e4,1e4};
      auto neumannFunction = [&](FieldVector<double, gridDim>){
                               return values_;
                             };
    
    
      auto cosseratEnergy = std::make_shared<CosseratEnergyLocalStiffness<decltype(compositeBasis), dim, ValueType> >(parameters,
                                                                                                                      &neumannBoundary,
                                                                                                                      neumannFunction,
                                                                                                                      nullptr);
    
    
      using RBM = GFE::ProductManifold<RealTuple<double,dim>, Rotation<double, dim> >;
    
    
      LocalGeodesicFEADOLCStiffness<CompositeBasis,RBM> mixedLocalGFEADOLCStiffness(cosseratEnergy);
    
      MixedGFEAssembler<CompositeBasis, RBM> mixedAssembler(compositeBasis, mixedLocalGFEADOLCStiffness);
    
      using GFEAssemblerWrapper = GFE::GeodesicFEAssemblerWrapper<CompositeBasis, DeformationFEBasis, RBM>;
    
      GFEAssemblerWrapper assembler(&mixedAssembler, deformationFEBasis);
    
      /////////////////////////////////////////////////////////////////////////
      //  Prepare the iterate x where we want to assemble - identity in 2D with z = 0
      /////////////////////////////////////////////////////////////////////////
      auto deformationPowerBasis = makeBasis(
        gridView,
        power<gridDim>(
          lagrange<displacementOrder>()
          ));
      BlockVector<FieldVector<double,gridDim> > identity(compositeBasis.size({0}));
      Functions::interpolate(deformationPowerBasis, identity, [](FieldVector<double,gridDim> x){
        return x;
      });
      BlockVector<FieldVector<double,dim> > initialDeformation(compositeBasis.size({0}));
      initialDeformation = 0;
    
      Vector x;
      x[_0].resize(compositeBasis.size({0}));
      x[_1].resize(compositeBasis.size({1}));
      std::vector<RBM> xRBM(compositeBasis.size({0}));
      BitSetVector<RBM::TangentVector::dimension> dirichletDofsRBM(compositeBasis.size({0}), false);
    
      for (std::size_t i = 0; i < compositeBasis.size({0}); i++) {
        for (int j = 0; j < gridDim; j++)
          initialDeformation[i][j] = identity[i][j];
        x[_0][i] = initialDeformation[i];
        xRBM[i][_0] = x[_0][i];
        for (int j = 0; j < dim; j ++) { // Displacement part
          dirichletDofsRBM[i][j] = dirichletDofs[_0][i][j];
        }
        xRBM[i][_1] = x[_1][i]; // Rotation part
        for (int j = dim; j < RBM::TangentVector::dimension; j ++)
          dirichletDofsRBM[i][j] = dirichletDofs[_1][i][j-dim];
      }
    
      //////////////////////////////////////////////////////////////////////////////
      //  Create a MixedRiemannianPNSolver and a normal RiemannianPNSolver
      //  and compare one solver step!
      //////////////////////////////////////////////////////////////////////////////
    
      const double tolerance = 1e-7;
      const int maxSolverSteps = 1;
      const double initialRegularization = 100;
      const bool instrumented = false;
      GFE::MixedRiemannianProximalNewtonSolver<CompositeBasis, DeformationFEBasis, RealTuple<double,dim>, DeformationFEBasis, Rotation<double,dim>, BitVector> mixedSolver;
      mixedSolver.setup(*grid,
                        &mixedAssembler,
                        x,
                        dirichletDofs,
                        tolerance,
                        maxSolverSteps,
                        initialRegularization,
                        instrumented);
      mixedSolver.setInitialIterate(x);
      mixedSolver.solve();
      x = mixedSolver.getSol();
    
      RiemannianProximalNewtonSolver<DeformationFEBasis, RBM, GFEAssemblerWrapper> solver;
      solver.setup(*grid,
                   &assembler,
                   xRBM,
                   dirichletDofsRBM,
                   tolerance,
                   maxSolverSteps,
                   initialRegularization,
                   instrumented);
      solver.setInitialIterate(xRBM);
      solver.solve();
      xRBM = solver.getSol();
    
      BlockTupleVector xMixed;
      BlockTupleVector xNotMixed;
      xNotMixed[_0].resize(compositeBasis.size({0}));
      xNotMixed[_1].resize(compositeBasis.size({1}));
      xMixed[_0].resize(compositeBasis.size({0}));
      xMixed[_1].resize(compositeBasis.size({1}));
      for (std::size_t i = 0; i < xRBM.size(); i++)
      {
        xNotMixed[_0][i] = xRBM[i][_0];
        xNotMixed[_1][i] = xRBM[i][_1];
        xMixed[_0][i] = x[_0][i];
        xMixed[_1][i] = x[_1][i];
        auto difference0 = xMixed[_0][i].globalCoordinates();
        auto difference1 = xMixed[_1][i].globalCoordinates();
        difference0 -= xNotMixed[_0][i].globalCoordinates();
        difference1 -= xNotMixed[_1][i].globalCoordinates();
        if (difference0.two_norm() > 1e-1 || difference1.two_norm() > 1e-1) {
          std::cerr << std::setprecision(9);
          std::cerr << "At index " << i << " the solution calculated by the MixedRiemannianPNSolver is "
                    << xMixed[_0][i] << " and " << xMixed[_1][i] << " but "
                    << xNotMixed[_0][i] << " and " << xNotMixed[_1][i]
                    << " (calculated by the RiemannianProximalNewtonSolver) was expected!" << std::endl;
          return 1;
        }
      }
    }