Skip to content
Snippets Groups Projects
cosserat-continuum.cc 10.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include <config.h>
    
    #include <fenv.h>
    
    #define RIGIDBODYMOTION3
    
    #include <dune/common/bitsetvector.hh>
    #include <dune/common/parametertree.hh>
    #include <dune/common/parametertreeparser.hh>
    
    #include <dune/grid/uggrid.hh>
    #include <dune/grid/onedgrid.hh>
    #include <dune/grid/geometrygrid.hh>
    #include <dune/grid/utility/structuredgridfactory.hh>
    
    #include <dune/grid/io/file/amirameshreader.hh>
    #include <dune/grid/io/file/amirameshwriter.hh>
    
    
    #include <dune/fufem/boundarypatch.hh>
    
    
    #include <dune/solvers/solvers/iterativesolver.hh>
    #include <dune/solvers/norms/energynorm.hh>
    
    #include <dune/gfe/rotation.hh>
    #include <dune/gfe/unitvector.hh>
    #include <dune/gfe/realtuple.hh>
    
    #include <dune/gfe/cosseratenergystiffness.hh>
    
    #include <dune/gfe/cosseratamirameshwriter.hh>
    
    #include <dune/gfe/geodesicfeassembler.hh>
    #include <dune/gfe/riemanniantrsolver.hh>
    
    // grid dimension
    const int dim = 2;
    
    // Image space of the geodesic fe functions
    #ifdef RIGIDBODYMOTION3
    typedef RigidBodyMotion<3> TargetSpace;
    #endif
    
    // Tangent vector of the image space
    
    const int blocksize = TargetSpace::TangentVector::dimension;
    
    void dirichletValues(const FieldVector<double,dim>& in, FieldVector<double,3>& out)
    {
        out = 0;
        for (int i=0; i<dim; i++)
            out[i] = in[i];
        
        out[0] = 2.2;
    }
    
    void dirichletValues(const FieldVector<double,dim>& in, FieldVector<double,3>& out,
                         double homotopy
    )
    
    {
        double angle = M_PI/4;
    
        angle *= homotopy;
        
        // center of rotation
    
        FieldVector<double,3> center(0);
        center[1] = 0.5;
        
        FieldMatrix<double,3,3> rotation(0);
        rotation[0][0] = 1;
        rotation[1][1] =  std::cos(angle);
        rotation[1][2] = -std::sin(angle);
        rotation[2][1] =  std::sin(angle);
        rotation[2][2] =  std::cos(angle);
    
        FieldVector<double,3> inEmbedded(0);
        for (int i=0; i<dim; i++)
            inEmbedded[i] = in[i];
        inEmbedded -= center;
        
        rotation.mv(inEmbedded, out);
        
        out += center;
    }
    
    struct NeumannFunction
        : public Dune::VirtualFunction<FieldVector<double,dim>, FieldVector<double,3> >
    {
    
        NeumannFunction(double homotopyParameter)
        : homotopyParameter_(homotopyParameter)
        {}
        
    
        void evaluate(const FieldVector<double, dim>& x, FieldVector<double,3>& out) const {
            out = 0;
    
            out[0] = -40*homotopyParameter_;
    
        double homotopyParameter_;
    
    int main (int argc, char *argv[]) try
    {
        //feenableexcept(FE_INVALID);
    
        typedef std::vector<TargetSpace> SolutionType;
    
        // parse data file
        ParameterTree parameterSet;
        if (argc==2)
            ParameterTreeParser::readINITree(argv[1], parameterSet);
        else
            ParameterTreeParser::readINITree("cosserat-continuum.parset", parameterSet);
    
        // read solver settings
        const int numLevels                   = parameterSet.get<int>("numLevels");
    
        int numHomotopySteps                  = parameterSet.get<int>("numHomotopySteps");
    
        const double tolerance                = parameterSet.get<double>("tolerance");
        const int maxTrustRegionSteps         = parameterSet.get<int>("maxTrustRegionSteps");
        const double initialTrustRegionRadius = parameterSet.get<double>("initialTrustRegionRadius");
        const int multigridIterations         = parameterSet.get<int>("numIt");
        const int nu1                         = parameterSet.get<int>("nu1");
        const int nu2                         = parameterSet.get<int>("nu2");
        const int mu                          = parameterSet.get<int>("mu");
        const int baseIterations              = parameterSet.get<int>("baseIt");
        const double mgTolerance              = parameterSet.get<double>("mgTolerance");
        const double baseTolerance            = parameterSet.get<double>("baseTolerance");
        const bool instrumented               = parameterSet.get<bool>("instrumented");
        std::string resultPath                = parameterSet.get("resultPath", "");
    
        // read problem settings
        std::string path                = parameterSet.get<std::string>("path");
        std::string gridFile            = parameterSet.get<std::string>("gridFile");
    
        // ///////////////////////////////////////
        //    Create the grid
        // ///////////////////////////////////////
        typedef std::conditional<dim==1,OneDGrid,UGGrid<dim> >::type GridType;
        array<unsigned int,dim> elements;
    
        elements[0] = 10;
    
        FieldVector<double,dim> upper(1);
    
        upper[0] = 10;
    
        shared_ptr<GridType> gridPtr = StructuredGridFactory<GridType>::createCubeGrid(FieldVector<double,dim>(0),
    
                                                                                          elements);
        GridType& grid = *gridPtr.get();
    
        grid.globalRefine(numLevels-1);
    
        SolutionType x(grid.size(dim));
    
        // /////////////////////////////////////////
        //   Read Dirichlet values
        // /////////////////////////////////////////
    
    
        BitSetVector<1> allNodes(grid.size(dim));
        allNodes.setAll();
    
        BoundaryPatch<GridType::LeafGridView> dirichletBoundary(grid.leafView(), allNodes);
    
        BitSetVector<blocksize> dirichletNodes(grid.size(dim), false);
        for (int i=0; i<dirichletNodes.size(); i++) {
            // Only translation dofs are Dirichlet
            if (dirichletBoundary.containsVertex(i))
                for (int j=0; j<3; j++)
                    dirichletNodes[i][j] = true;
        }
    
    #else
        BitSetVector<blocksize> dirichletNodes(grid.size(dim), false);
    
        BitSetVector<1> neumannNodes(grid.size(dim), false);
    
    
        GridType::Codim<dim>::LeafIterator vIt    = grid.leafbegin<dim>();
        GridType::Codim<dim>::LeafIterator vEndIt = grid.leafend<dim>();
        
        for (; vIt!=vEndIt; ++vIt) {
    
            if (vIt->geometry().corner(0)[0] < 1.0+1e-3 /* or vIt->geometry().corner(0)[0] > upper[0]-1e-3*/ ) {
    
                // Only translation dofs are Dirichlet
                for (int j=0; j<3; j++)
                    dirichletNodes[grid.leafIndexSet().index(*vIt)][j] = true;
            }
    
            if (vIt->geometry().corner(0)[0] > upper[0]-1e-3 ) {
                neumannNodes[grid.leafIndexSet().index(*vIt)][0] = true;
            }
    
    
    
        //////////////////////////////////////////////////////////////////////////////
        //   Assemble Neumann term
        //////////////////////////////////////////////////////////////////////////////
    
        typedef P1NodalBasis<typename GridType::LeafGridView,double> P1Basis;
        P1Basis p1Basis(grid.leafView());
        
        BoundaryPatch<typename GridType::LeafGridView> neumannBoundary(grid.leafView(), neumannNodes);
    
        std::cout << "Neumann boundary has " << neumannBoundary.numFaces() << " faces\n";
    
    
        // //////////////////////////
        //   Initial solution
        // //////////////////////////
    
        FieldVector<double,3> yAxis(0);
        yAxis[1] = 1;
    
    
        vIt    = grid.leafbegin<dim>();
    
    
        for (; vIt!=vEndIt; ++vIt) {
            int idx = grid.leafIndexSet().index(*vIt);
    
            x[idx].r = 0;
            for (int i=0; i<dim; i++)
                x[idx].r[i] = vIt->geometry().corner(0)[i];
    
            // x[idx].q is the identity, set by the default constructor
    
        }
    
    
        ////////////////////////////////////////////////////////
        //   Main homotopy loop
        ////////////////////////////////////////////////////////
    
        for (int i=0; i<numHomotopySteps; i++) {
    
            double homotopyParameter = (i+1)*(1.0/numHomotopySteps);
            std::cout << "Homotopy step: " << i << ",    parameter: " << homotopyParameter << std::endl;
    
    
    
        // ////////////////////////////////////////////////////////////
    
        //   Create an assembler for the energy functional
    
        // ////////////////////////////////////////////////////////////
    
        const ParameterTree& materialParameters = parameterSet.sub("materialParameters");
    
        NeumannFunction neumannFunction(homotopyParameter);
    
        CosseratEnergyLocalStiffness<GridType::LeafGridView,
                                     typename P1Basis::LocalFiniteElement,
    
                                     3> cosseratEnergyLocalStiffness(materialParameters,
                                                                     &neumannBoundary,
                                                                     &neumannFunction);
    
        GeodesicFEAssembler<P1Basis,TargetSpace> assembler(grid.leafView(),
    
                                                                          &cosseratEnergyLocalStiffness);
    
    
        // /////////////////////////////////////////////////
        //   Create a Riemannian trust-region solver
        // /////////////////////////////////////////////////
    
        RiemannianTrustRegionSolver<GridType,TargetSpace> solver;
        solver.setup(grid, 
                     &assembler,
                     x,
                     dirichletNodes,
                     tolerance,
                     maxTrustRegionSteps,
                     initialTrustRegionRadius,
                     multigridIterations,
                     mgTolerance,
                     mu, nu1, nu2,
                     baseIterations,
                     baseTolerance,
                     instrumented);
        
    
            ////////////////////////////////////////////////////////
            //   Set Dirichlet values
            ////////////////////////////////////////////////////////
            
            for (vIt=grid.leafbegin<dim>(); vIt!=vEndIt; ++vIt) {
    
                int idx = grid.leafIndexSet().index(*vIt);
                if (dirichletNodes[idx][0] and vIt->geometry().corner(0)[0] > upper[0]-1e-3) {
                
                    // Only the positions have Dirichlet values
                    dirichletValues(vIt->geometry().corner(0), x[idx].r,
                                    homotopyParameter);
    
                }
    
            }
    
            // /////////////////////////////////////////////////////
            //   Solve!
            // /////////////////////////////////////////////////////
    
            std::cout << "Energy: " << assembler.computeEnergy(x) << std::endl;
            //exit(0);
    
            solver.setInitialSolution(x);
            solver.solve();
    
        // //////////////////////////////
        //   Output result
        // //////////////////////////////
        
    
        CosseratAmiraMeshWriter<GridType>::write(grid,x,"cosserat");
    
        // finally: compute the average deformation of the Neumann boundary
        // That is what we need for the locking tests
        FieldVector<double,3> averageDef(0);
        for (size_t i=0; i<x.size(); i++)
            if (neumannNodes[i][0])
                averageDef += x[i].r;
        averageDef /= neumannNodes.count();
        
        std::cout << "average deflection: " << averageDef << std::endl;
        
    
        // //////////////////////////////
     } catch (Exception e) {
    
        std::cout << e << std::endl;
    
     }