Skip to content
Snippets Groups Projects
mixed-cosserat-continuum.cc 18.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include <config.h>
    
    #define SECOND_ORDER
    
    #include <fenv.h>
    
    // Includes for the ADOL-C automatic differentiation library
    // Need to come before (almost) all others.
    #include <adolc/adouble.h>
    #include <adolc/drivers/drivers.h>    // use of "Easy to Use" drivers
    #include <adolc/taping.h>
    
    #include <dune/gfe/adolcnamespaceinjections.hh>
    #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/gmshreader.hh>
    
    #include <dune/fufem/boundarypatch.hh>
    #include <dune/fufem/functiontools/boundarydofs.hh>
    #include <dune/fufem/functiontools/basisinterpolator.hh>
    #include <dune/fufem/functionspacebases/p1nodalbasis.hh>
    #include <dune/fufem/functionspacebases/p2nodalbasis.hh>
    #include <dune/fufem/dunepython.hh>
    
    #include <dune/solvers/solvers/iterativesolver.hh>
    #include <dune/solvers/norms/energynorm.hh>
    
    #include <dune/gfe/rigidbodymotion.hh>
    #include <dune/gfe/mixedlocalgfeadolcstiffness.hh>
    #include <dune/gfe/mixedcosseratenergy.hh>
    #include <dune/gfe/cosseratvtkwriter.hh>
    #include <dune/gfe/mixedgfeassembler.hh>
    #include <dune/gfe/mixedriemanniantrsolver.hh>
    
    // grid dimension
    const int dim = 2;
    
    using namespace Dune;
    
    // Dirichlet boundary data for the shear/wrinkling example
    class WrinklingDirichletValues
    : public Dune::VirtualFunction<FieldVector<double,dim>, FieldVector<double,3> >
    {
      FieldVector<double,2> upper_;
      double homotopy_;
    public:
      WrinklingDirichletValues(FieldVector<double,2> upper, double homotopy)
      : upper_(upper), homotopy_(homotopy)
      {}
    
      void evaluate(const FieldVector<double,dim>& in, FieldVector<double,3>& out) const
      {
        out = 0;
        for (int i=0; i<dim; i++)
          out[i] = in[i];
    
        //     if (out[1] > 1-1e-3)
        if (out[1] > upper_[1]-1e-4)
          out[0] += 0.003*homotopy_;
      }
    };
    
    class WongPellegrinoDirichletValuesPythonWriter
    {
      FieldVector<double,2> upper_;
      double homotopy_;
    public:
    
      WongPellegrinoDirichletValuesPythonWriter(FieldVector<double,2> upper, double homotopy)
      : upper_(upper), homotopy_(homotopy)
      {}
    
      void writeDeformation()
      {
        Python::runStream()
            << std::endl << "def deformationDirichletValues(x):"
            << std::endl << "    out = [x[0], x[1], 0]"
            << std::endl << "    if x[1] > " << upper_[1]-1e-4 << ":"
            << std::endl << "        out[0] += 0.003 * " << homotopy_
            << std::endl << "    return out";
      }
    
      void writeOrientation()
      {
        Python::runStream()
            << std::endl << "def orientationDirichletValues(x):"
            << std::endl << "    rotation = [[1,0,0], [0, 1, 0], [0, 0, 1]]"
            << std::endl << "    return rotation";
      }
    
    };
    
    
    class TwistedStripDirichletValuesPythonWriter
    {
      FieldVector<double,2> upper_;
      double homotopy_;
      double totalAngle_;
    public:
    
      TwistedStripDirichletValuesPythonWriter(FieldVector<double,2> upper, double homotopy)
      : upper_(upper), homotopy_(homotopy)
      {
        totalAngle_ = 6*M_PI;
      }
    
      void writeDeformation()
      {
        Python::runStream()
            << std::endl << "def deformationDirichletValues(x):"
            << std::endl << "    upper = [" << upper_[0] << ", " << upper_[1] << "]"
            << std::endl << "    homotopy = " << homotopy_
            << std::endl << "    angle = " << totalAngle_ << " * x[0]/upper[0]"
            << std::endl << "    angle *= homotopy"
    
            // center of rotation
            << std::endl << "    center = [0, 0, 0]"
            << std::endl << "    center[1] = upper[1]/2.0"
    
            << std::endl << "    rotation = numpy.array([[1,0,0], [0, math.cos(angle), -math.sin(angle)], [0, math.sin(angle), math.cos(angle)]])"
    
            << std::endl << "    inEmbedded = [x[0]-center[0], x[1]-center[1], 0-center[2]]"
    
            // Matrix-vector product
            << std::endl << "    out = [rotation[0][0]*inEmbedded[0]+rotation[0][1]*inEmbedded[1], rotation[1][0]*inEmbedded[0]+rotation[1][1]*inEmbedded[1], rotation[2][0]*inEmbedded[0]+rotation[2][1]*inEmbedded[1]]"
    
            << std::endl << "    out = [out[0]+center[0], out[1]+center[1], out[2]+center[2]]"
            << std::endl << "    return out";
      }
    
      void writeOrientation()
      {
        Python::runStream()
            << std::endl << "def orientationDirichletValues(x):"
            << std::endl << "    upper = [" << upper_[0] << ", " << upper_[1] << "]"
            << std::endl << "    angle = " << totalAngle_ << " * x[0]/upper[0];"
            << std::endl << "    angle *= " << homotopy_
    
            << std::endl << "    rotation = numpy.array([[1,0,0], [0, math.cos(angle), -math.sin(angle)], [0, math.sin(angle), math.cos(angle)]])"
            << std::endl << "    return rotation";
      }
    
    };
    
    
    /** \brief A constant vector-valued function, for simple Neumann boundary values */
    struct NeumannFunction
        : public Dune::VirtualFunction<FieldVector<double,dim>, FieldVector<double,3> >
    {
        NeumannFunction(const FieldVector<double,3> values,
                        double homotopyParameter)
        : values_(values),
          homotopyParameter_(homotopyParameter)
        {}
    
        void evaluate(const FieldVector<double, dim>& x, FieldVector<double,3>& out) const {
            out = 0;
            out.axpy(homotopyParameter_, values_);
        }
    
        FieldVector<double,3> values_;
        double homotopyParameter_;
    };
    
    
    int main (int argc, char *argv[]) try
    {
        // initialize MPI, finalize is done automatically on exit
        Dune::MPIHelper& mpiHelper = MPIHelper::instance(argc, argv);
    
        // Start Python interpreter
        Python::start();
        Python::Reference main = Python::import("__main__");
        Python::run("import math");
    
        //feenableexcept(FE_INVALID);
    
        typedef std::vector<RealTuple<double,3> > DeformationSolutionType;
        typedef std::vector<Rotation<double,3> >  OrientationSolutionType;
    
        // parse data file
        ParameterTree parameterSet;
        if (argc != 2)
          DUNE_THROW(Exception, "Usage: ./mixed-cosserat-continuum <parameter file>");
    
        ParameterTreeParser::readINITree(argv[1], parameterSet);
    
        ParameterTreeParser::readOptions(argc, argv, 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", "");
    
        // ///////////////////////////////////////
        //    Create the grid
        // ///////////////////////////////////////
        typedef std::conditional<dim==1,OneDGrid,UGGrid<dim> >::type GridType;
    
        shared_ptr<GridType> grid;
    
        FieldVector<double,dim> lower(0), upper(1);
    
        if (parameterSet.get<bool>("structuredGrid")) {
    
            lower = parameterSet.get<FieldVector<double,dim> >("lower");
            upper = parameterSet.get<FieldVector<double,dim> >("upper");
    
            array<unsigned int,dim> elements = parameterSet.get<array<unsigned int,dim> >("elements");
            grid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements);
    
        } else {
            std::string path                = parameterSet.get<std::string>("path");
            std::string gridFile            = parameterSet.get<std::string>("gridFile");
            grid = shared_ptr<GridType>(GmshReader<GridType>::read(path + "/" + gridFile));
        }
    
        grid->globalRefine(numLevels-1);
    
        grid->loadBalance();
    
        if (mpiHelper.rank()==0)
          std::cout << "There are " << grid->leafGridView().comm().size() << " processes" << std::endl;
    
        typedef GridType::LeafGridView GridView;
        GridView gridView = grid->leafGridView();
    
        typedef P2NodalBasis<GridView,double> DeformationFEBasis;
    
        typedef P1NodalBasis<GridView,double> OrientationFEBasis;
    
    
        DeformationFEBasis deformationFEBasis(gridView);
        OrientationFEBasis orientationFEBasis(gridView);
    
        // /////////////////////////////////////////
        //   Read Dirichlet values
        // /////////////////////////////////////////
    
        BitSetVector<1> dirichletVertices(gridView.size(dim), false);
        BitSetVector<1> neumannVertices(gridView.size(dim), false);
    
        GridType::Codim<dim>::LeafIterator vIt    = gridView.begin<dim>();
        GridType::Codim<dim>::LeafIterator vEndIt = gridView.end<dim>();
    
        const GridView::IndexSet& indexSet = gridView.indexSet();
    
        // Make Python function that computes which vertices are on the Dirichlet boundary,
        // based on the vertex positions.
        std::string lambda = std::string("lambda x: (") + parameterSet.get<std::string>("dirichletVerticesPredicate") + std::string(")");
        PythonFunction<FieldVector<double,dim>, bool> pythonDirichletVertices(Python::evaluate(lambda));
    
        // Same for the Neumann boundary
        lambda = std::string("lambda x: (") + parameterSet.get<std::string>("neumannVerticesPredicate", "0") + std::string(")");
        PythonFunction<FieldVector<double,dim>, bool> pythonNeumannVertices(Python::evaluate(lambda));
    
        for (; vIt!=vEndIt; ++vIt) {
    
            bool isDirichlet;
            pythonDirichletVertices.evaluate(vIt->geometry().corner(0), isDirichlet);
            dirichletVertices[indexSet.index(*vIt)] = isDirichlet;
    
            bool isNeumann;
            pythonNeumannVertices.evaluate(vIt->geometry().corner(0), isNeumann);
            neumannVertices[indexSet.index(*vIt)] = isNeumann;
    
        }
    
        BoundaryPatch<GridView> dirichletBoundary(gridView, dirichletVertices);
        BoundaryPatch<GridView> neumannBoundary(gridView, neumannVertices);
    
        if (mpiHelper.rank()==0)
          std::cout << "Neumann boundary has " << neumannBoundary.numFaces() << " faces\n";
    
    
        BitSetVector<1> deformationDirichletNodes(deformationFEBasis.size(), false);
        constructBoundaryDofs(dirichletBoundary,deformationFEBasis,deformationDirichletNodes);
    
        BitSetVector<3> deformationDirichletDofs(deformationFEBasis.size(), false);
        for (size_t i=0; i<deformationFEBasis.size(); i++)
          if (deformationDirichletNodes[i][0])
            for (int j=0; j<3; j++)
              deformationDirichletDofs[i][j] = true;
    
        BitSetVector<1> orientationDirichletNodes(orientationFEBasis.size(), false);
        constructBoundaryDofs(dirichletBoundary,orientationFEBasis,orientationDirichletNodes);
    
        BitSetVector<3> orientationDirichletDofs(orientationFEBasis.size(), false);
        for (size_t i=0; i<orientationFEBasis.size(); i++)
          if (orientationDirichletNodes[i][0])
            for (int j=0; j<3; j++)
              orientationDirichletDofs[i][j] = true;
    
        // //////////////////////////
        //   Initial iterate
        // //////////////////////////
    
        DeformationSolutionType xDisp(deformationFEBasis.size());
    
        lambda = std::string("lambda x: (") + parameterSet.get<std::string>("initialDeformation") + std::string(")");
        PythonFunction<FieldVector<double,dim>, FieldVector<double,3> > pythonInitialDeformation(Python::evaluate(lambda));
    
        std::vector<FieldVector<double,3> > v;
        Functions::interpolate(deformationFEBasis, v, pythonInitialDeformation);
    
        for (size_t i=0; i<xDisp.size(); i++)
          xDisp[i] = v[i];
    
        OrientationSolutionType xOrient(orientationFEBasis.size());
    #if 0
        lambda = std::string("lambda x: (") + parameterSet.get<std::string>("initialDeformation") + std::string(")");
        PythonFunction<FieldVector<double,dim>, FieldVector<double,3> > pythonInitialDeformation(Python::evaluate(lambda));
    
        std::vector<FieldVector<double,3> > v;
        Functions::interpolate(feBasis, v, pythonInitialDeformation);
    
        for (size_t i=0; i<x.size(); i++)
          xDisp[i] = v[i];
    #endif
        ////////////////////////////////////////////////////////
        //   Main homotopy loop
        ////////////////////////////////////////////////////////
    
        // Output initial iterate (of homotopy loop)
        CosseratVTKWriter<GridType>::writeMixed<DeformationFEBasis,OrientationFEBasis>(deformationFEBasis,xDisp,
                                                                                       orientationFEBasis,xOrient,
    
                                                                                       resultPath + "mixed-cosserat_homotopy_0");
    
    
        for (int i=0; i<numHomotopySteps; i++) {
    
            double homotopyParameter = (i+1)*(1.0/numHomotopySteps);
            if (mpiHelper.rank()==0)
                std::cout << "Homotopy step: " << i << ",    parameter: " << homotopyParameter << std::endl;
    
    
        // ////////////////////////////////////////////////////////////
        //   Create an assembler for the energy functional
        // ////////////////////////////////////////////////////////////
    
        const ParameterTree& materialParameters = parameterSet.sub("materialParameters");
    
        shared_ptr<NeumannFunction> neumannFunction;
        if (parameterSet.hasKey("neumannValues"))
            neumannFunction = make_shared<NeumannFunction>(parameterSet.get<FieldVector<double,3> >("neumannValues"),
                                                           homotopyParameter);
    
    
            if (mpiHelper.rank() == 0) {
                std::cout << "Material parameters:" << std::endl;
                materialParameters.report();
            }
    
        // Assembler using ADOL-C
        MixedCosseratEnergy<GridView,
                            DeformationFEBasis::LocalFiniteElement,
                            OrientationFEBasis::LocalFiniteElement,
                            3,adouble> cosseratEnergyADOLCLocalStiffness(materialParameters,
                                                                         &neumannBoundary,
                                                                         neumannFunction.get());
    
        MixedLocalGFEADOLCStiffness<GridView,
                                    DeformationFEBasis::LocalFiniteElement,
                                    RealTuple<double,3>,
                                    OrientationFEBasis::LocalFiniteElement,
                                    Rotation<double,3> > localGFEADOLCStiffness(&cosseratEnergyADOLCLocalStiffness);
    
        MixedGFEAssembler<DeformationFEBasis,
                          RealTuple<double,3>,
                          OrientationFEBasis,
                          Rotation<double,3> > assembler(deformationFEBasis, orientationFEBasis, &localGFEADOLCStiffness);
    
        // /////////////////////////////////////////////////
        //   Create a Riemannian trust-region solver
        // /////////////////////////////////////////////////
    
        MixedRiemannianTrustRegionSolver<GridType,
                                         DeformationFEBasis, RealTuple<double,3>,
                                         OrientationFEBasis, Rotation<double,3> > solver;
        solver.setup(*grid,
                     &assembler,
                     xDisp,
                     xOrient,
                     deformationDirichletDofs,
                     orientationDirichletDofs,
                     tolerance,
                     maxTrustRegionSteps,
                     initialTrustRegionRadius,
                     multigridIterations,
                     mgTolerance,
                     mu, nu1, nu2,
                     baseIterations,
                     baseTolerance,
                     instrumented);
    
            ////////////////////////////////////////////////////////
            //   Set Dirichlet values
            ////////////////////////////////////////////////////////
    
            if (parameterSet.get<std::string>("problem") == "twisted-strip")
            {
              TwistedStripDirichletValuesPythonWriter twistedStripDirichletValuesPythonWriter(upper, homotopyParameter);
              twistedStripDirichletValuesPythonWriter.writeDeformation();
              twistedStripDirichletValuesPythonWriter.writeOrientation();
    
            } else if (parameterSet.get<std::string>("problem") == "wong-pellegrino")
            {
              WongPellegrinoDirichletValuesPythonWriter wongPellegrinoDirichletValuesPythonWriter(upper, homotopyParameter);
              wongPellegrinoDirichletValuesPythonWriter.writeDeformation();
              wongPellegrinoDirichletValuesPythonWriter.writeOrientation();
    
            } else if (parameterSet.get<std::string>("problem") == "wriggers-L-shape")
            {
    
            } else
              DUNE_THROW(Exception, "Unknown problem type");
    
            PythonFunction<FieldVector<double,dim>, FieldVector<double,3> >   deformationDirichletValues(main.get("deformationDirichletValues"));
            PythonFunction<FieldVector<double,dim>, FieldMatrix<double,3,3> > orientationDirichletValues(main.get("orientationDirichletValues"));
    
            std::vector<FieldVector<double,3> > ddV;
            Functions::interpolate(deformationFEBasis, ddV, deformationDirichletValues, deformationDirichletDofs);
    
            std::vector<FieldMatrix<double,3,3> > dOV;
            Functions::interpolate(orientationFEBasis, dOV, orientationDirichletValues, orientationDirichletDofs);
    
            for (size_t j=0; j<xDisp.size(); j++)
              if (deformationDirichletNodes[j][0])
                xDisp[j] = ddV[j];
    
            for (size_t j=0; j<xOrient.size(); j++)
              if (orientationDirichletNodes[j][0])
                xOrient[j].set(dOV[j]);
    
            // /////////////////////////////////////////////////////
            //   Solve!
            // /////////////////////////////////////////////////////
    
            solver.setInitialIterate(xDisp,xOrient);
            solver.solve();
    
            //x = solver.getSol();
    
            // Output result of each homotopy step
            std::stringstream iAsAscii;
            iAsAscii << i+1;
            CosseratVTKWriter<GridType>::writeMixed<DeformationFEBasis,OrientationFEBasis>(deformationFEBasis,xDisp,
                                                                                           orientationFEBasis,xOrient,
    
                                                                                           resultPath + "mixed-cosserat_homotopy_" + iAsAscii.str());