Skip to content
Snippets Groups Projects
rodassemblertest.cc 21.44 KiB
#include <config.h>

#include <dune/grid/onedgrid.hh>

#include <dune/istl/io.hh>

#include <dune/gfe/rigidbodymotion.hh>
#include <dune/gfe/rodassembler.hh>

// Number of degrees of freedom: 
// 7 (x, y, z, q_1, q_2, q_3, q_4) for a spatial rod
const int blocksize = 6;

using namespace Dune;

void infinitesimalVariation(RigidBodyMotion<double,3>& c, double eps, int i)
{
    if (i<3)
        c.r[i] += eps;
    else {
        Dune::FieldVector<double,3> axial(0);
        axial[i-3] = eps;
        SkewMatrix<double,3> variation(axial);
        c.q = c.q.mult(Rotation<double,3>::exp(variation));
    }
}

template <class GridType>
void strainFD(const std::vector<RigidBodyMotion<double,3> >& x, 
              double pos,
              Dune::array<Dune::FieldMatrix<double,2,6>, 6>& fdStrainDerivatives,
              const RodAssembler<GridType,3>& assembler) 
{
    assert(x.size()==2);
    double eps = 1e-8;

    typename GridType::template Codim<0>::EntityPointer element = assembler.grid_->template leafbegin<0>();

    // ///////////////////////////////////////////////////////////
    //   Compute gradient by finite-difference approximation
    // ///////////////////////////////////////////////////////////
    std::vector<RigidBodyMotion<double,3> > forwardSolution = x;
    std::vector<RigidBodyMotion<double,3> > backwardSolution = x;
    
    for (size_t i=0; i<x.size(); i++) {
        
        Dune::FieldVector<double,6> fdGradient;
        
        for (int j=0; j<6; j++) {
            
            infinitesimalVariation(forwardSolution[i], eps, j);
            infinitesimalVariation(backwardSolution[i], -eps, j);
            
//             fdGradient[j] = (assembler.computeEnergy(forwardSolution) - assembler.computeEnergy(backwardSolution))
//                 / (2*eps);
            Dune::FieldVector<double,6> strain;
            strain = assembler.getStrain(forwardSolution, element, pos);
            strain -= assembler.getStrain(backwardSolution, element, pos);
            strain /= 2*eps;
            
            for (int m=0; m<6; m++)
                fdStrainDerivatives[m][i][j] = strain[m];

            forwardSolution[i] = x[i];
            backwardSolution[i] = x[i];
        }
        
    }

}


template <class GridType>
void strain2ndOrderFD(const std::vector<RigidBodyMotion<double,3> >& x, 
                      double pos,
                      Dune::array<Dune::Matrix<Dune::FieldMatrix<double,6,6> >, 3>& translationDer,
                      Dune::array<Dune::Matrix<Dune::FieldMatrix<double,3,3> >, 3>& rotationDer,
                      const RodAssembler<GridType,3>& assembler) 
{
    assert(x.size()==2);
    double eps = 1e-3;

    typename GridType::template Codim<0>::EntityPointer element = assembler.grid_->template leafbegin<0>();

    for (int m=0; m<3; m++) {
        
        translationDer[m].setSize(2,2);
        translationDer[m] = 0;
        
        rotationDer[m].setSize(2,2);
        rotationDer[m] = 0;

    }

    // ///////////////////////////////////////////////////////////
    //   Compute gradient by finite-difference approximation
    // ///////////////////////////////////////////////////////////
    std::vector<RigidBodyMotion<double,3> > forwardSolution = x;
    std::vector<RigidBodyMotion<double,3> > backwardSolution = x;
    
    std::vector<RigidBodyMotion<double,3> > forwardForwardSolution = x;
    std::vector<RigidBodyMotion<double,3> > forwardBackwardSolution = x;
    std::vector<RigidBodyMotion<double,3> > backwardForwardSolution = x;
    std::vector<RigidBodyMotion<double,3> > backwardBackwardSolution = x;

    for (int i=0; i<2; i++) {
        
        for (int j=0; j<3; j++) {

            for (int k=0; k<2; k++) {

                for (int l=0; l<3; l++) {

                    if (i==k && j==l) {

                        infinitesimalVariation(forwardSolution[i], eps, j+3);
                        infinitesimalVariation(backwardSolution[i], -eps, j+3);
            
                        // Second derivative
//                         fdHessian[j][k] = (assembler.computeEnergy(forwardSolution) 
//                                            - 2*assembler.computeEnergy(x) 
//                                            + assembler.computeEnergy(backwardSolution)) / (eps*eps);
                        
                        Dune::FieldVector<double,6> strain;
                        strain = assembler.getStrain(forwardSolution, element, pos);
                        strain += assembler.getStrain(backwardSolution, element, pos);
                        strain.axpy(-2, assembler.getStrain(x, element, pos));
                        strain /= eps*eps;
            
                        for (int m=0; m<3; m++)
                            rotationDer[m][i][k][j][l] = strain[3+m];

                        forwardSolution = x;
                        backwardSolution = x;

                    } else {

                        infinitesimalVariation(forwardForwardSolution[i],   eps, j+3);
                        infinitesimalVariation(forwardForwardSolution[k],   eps, l+3);
                        infinitesimalVariation(forwardBackwardSolution[i],  eps, j+3);
                        infinitesimalVariation(forwardBackwardSolution[k], -eps, l+3);
                        infinitesimalVariation(backwardForwardSolution[i], -eps, j+3);
                        infinitesimalVariation(backwardForwardSolution[k],  eps, l+3);
                        infinitesimalVariation(backwardBackwardSolution[i],-eps, j+3);
                        infinitesimalVariation(backwardBackwardSolution[k],-eps, l+3);


//                         fdHessian[j][k] = (assembler.computeEnergy(forwardForwardSolution)
//                                            + assembler.computeEnergy(backwardBackwardSolution)
//                                            - assembler.computeEnergy(forwardBackwardSolution)
//                                            - assembler.computeEnergy(backwardForwardSolution)) / (4*eps*eps);

                        Dune::FieldVector<double,6> strain;
                        strain  = assembler.getStrain(forwardForwardSolution, element, pos);
                        strain += assembler.getStrain(backwardBackwardSolution, element, pos);
                        strain -= assembler.getStrain(forwardBackwardSolution, element, pos);
                        strain -= assembler.getStrain(backwardForwardSolution, element, pos);
                        strain /= 4*eps*eps;


                        for (int m=0; m<3; m++)
                            rotationDer[m][i][k][j][l] = strain[3+m];
                        
                        forwardForwardSolution   = x;
                        forwardBackwardSolution  = x;
                        backwardForwardSolution  = x;
                        backwardBackwardSolution = x;


                    }

                }

            }
        }
        
    }

}


template <class GridType>
void strain2ndOrderFD2(const std::vector<RigidBodyMotion<double,3> >& x, 
                       double pos,
                       Dune::FieldVector<double,1> shapeGrad[2],
                       Dune::FieldVector<double,1> shapeFunction[2],
                       Dune::array<Dune::Matrix<Dune::FieldMatrix<double,6,6> >, 3>& translationDer,
                       Dune::array<Dune::Matrix<Dune::FieldMatrix<double,3,3> >, 3>& rotationDer,
                       const RodAssembler<GridType,3>& assembler) 
{
    assert(x.size()==2);
    double eps = 1e-3;

    for (int m=0; m<3; m++) {
        
        translationDer[m].setSize(2,2);
        translationDer[m] = 0;
        
        rotationDer[m].setSize(2,2);
        rotationDer[m] = 0;

    }

    // ///////////////////////////////////////////////////////////
    //   Compute gradient by finite-difference approximation
    // ///////////////////////////////////////////////////////////
    std::vector<RigidBodyMotion<double,3> > forwardSolution = x;
    std::vector<RigidBodyMotion<double,3> > backwardSolution = x;
    
    for (int k=0; k<2; k++) {
        
        for (int l=0; l<3; l++) {

            infinitesimalVariation(forwardSolution[k], eps, l+3);
            infinitesimalVariation(backwardSolution[k], -eps, l+3);
                
            Dune::array<Dune::FieldMatrix<double,2,6>, 6> forwardStrainDer;
            assembler.strainDerivative(forwardSolution, pos, shapeGrad, shapeFunction, forwardStrainDer);

            Dune::array<Dune::FieldMatrix<double,2,6>, 6> backwardStrainDer;
            assembler.strainDerivative(backwardSolution, pos, shapeGrad, shapeFunction, backwardStrainDer);
            
            for (int i=0; i<2; i++) {
                for (int j=0; j<3; j++) {
                    for (int m=0; m<3; m++) {
                        rotationDer[m][i][k][j][l] = (forwardStrainDer[m][i][j]-backwardStrainDer[m][i][j]) / (2*eps);
                    }
                }
            }

            forwardSolution = x;
            backwardSolution = x;
            
        }
        
    }
    
}





template <class GridType>
void expHessianFD()
{
    using namespace Dune;
    double eps = 1e-3;

    // ///////////////////////////////////////////////////////////
    //   Compute gradient by finite-difference approximation
    // ///////////////////////////////////////////////////////////
    SkewMatrix<double,3> forward;
    SkewMatrix<double,3> backward;
    
    SkewMatrix<double,3> forwardForward;
    SkewMatrix<double,3> forwardBackward;
    SkewMatrix<double,3> backwardForward;
    SkewMatrix<double,3> backwardBackward;

    for (int i=0; i<3; i++) {
        
        for (int j=0; j<3; j++) {

            Quaternion<double> hessian;

            if (i==j) {

                forward = backward = 0;
                forward.axial()[i]  += eps;
                backward.axial()[i] -= eps;
                
                // Second derivative
                //                         fdHessian[j][k] = (assembler.computeEnergy(forward) 
                //                                            - 2*assembler.computeEnergy(x) 
                //                                            + assembler.computeEnergy(backward)) / (eps*eps);
                
                hessian  = Rotation<double,3>::exp(forward);
                hessian += Rotation<double,3>::exp(backward);
                SkewMatrix<double,3> zero(0);
                hessian.axpy(-2, Rotation<double,3>::exp(zero));
                hessian /= eps*eps;
                
            } else {
                
                forwardForward = forwardBackward = 0;
                backwardForward = backwardBackward = 0;

                forwardForward.axial()[i]   += eps;
                forwardForward.axial()[j]   += eps;
                forwardBackward.axial()[i]  += eps;
                forwardBackward.axial()[j]  -= eps;
                backwardForward.axial()[i]  -= eps;
                backwardForward.axial()[j]  += eps;
                backwardBackward.axial()[i] -= eps;
                backwardBackward.axial()[j] -= eps;
                
                
                hessian  = Rotation<double,3>::exp(forwardForward);
                hessian += Rotation<double,3>::exp(backwardBackward);
                hessian -= Rotation<double,3>::exp(forwardBackward);
                hessian -= Rotation<double,3>::exp(backwardForward);
                hessian /= 4*eps*eps;
                
            }

            printf("i: %d,  j: %d    ", i, j);
            std::cout << hessian << std::endl;
            
        }
        
    }
}


template <class GridType>
void gradientFDCheck(const std::vector<RigidBodyMotion<double,3> >& x, 
                     const Dune::BlockVector<Dune::FieldVector<double,6> >& gradient, 
                     const RodAssembler<GridType,3>& assembler)
{
#ifndef ABORT_ON_ERROR
    static int gradientError = 0;
    double maxError = -1;
#endif
    double eps = 1e-6;

    // ///////////////////////////////////////////////////////////
    //   Compute gradient by finite-difference approximation
    // ///////////////////////////////////////////////////////////

    std::vector<RigidBodyMotion<double,3> > forwardSolution = x;
    std::vector<RigidBodyMotion<double,3> > backwardSolution = x;

    for (size_t i=0; i<x.size(); i++) {
        
        Dune::FieldVector<double,6> fdGradient;
        
        for (int j=0; j<6; j++) {
            
            infinitesimalVariation(forwardSolution[i],   eps, j);
            infinitesimalVariation(backwardSolution[i], -eps, j);
            
            fdGradient[j] = (assembler.computeEnergy(forwardSolution) - assembler.computeEnergy(backwardSolution))
                / (2*eps);
            
            forwardSolution[i] = x[i];
            backwardSolution[i] = x[i];
        }
        
        if ( (fdGradient-gradient[i]).two_norm() > 1e-6 ) {
#ifdef ABORT_ON_ERROR
            std::cout << "Differing gradients at " << i 
                      << "!  (" << (fdGradient-gradient[i]).two_norm() / gradient[i].two_norm()
                      << ")    Analytical: " << gradient[i] << ",  fd: " << fdGradient << std::endl;
            //std::cout << "Current configuration " << std::endl;
            for (size_t j=0; j<x.size(); j++)
                std::cout << x[j] << std::endl;
            //abort();
#else
            gradientError++;
            maxError = std::max(maxError, (fdGradient-gradient[i]).two_norm());
#endif
        }
        
    }

#ifndef ABORT_ON_ERROR
    std::cout << gradientError << " errors in the gradient corrected  (max: " << maxError << ")!" << std::endl;
#endif

}


template <class GridType>
void hessianFDCheck(const std::vector<RigidBodyMotion<double,3> >& x, 
                    const Dune::BCRSMatrix<Dune::FieldMatrix<double,6,6> >& hessian, 
                    const RodAssembler<GridType,3>& assembler)
{
#ifndef ABORT_ON_ERROR
    static int hessianError = 0;
#endif
    double eps = 1e-2;

    typedef typename Dune::BCRSMatrix<Dune::FieldMatrix<double,6,6> >::row_type::const_iterator ColumnIterator;

    // ///////////////////////////////////////////////////////////
    //   Compute gradient by finite-difference approximation
    // ///////////////////////////////////////////////////////////
    std::vector<RigidBodyMotion<double,3> > forwardSolution = x;
    std::vector<RigidBodyMotion<double,3> > backwardSolution = x;

    std::vector<RigidBodyMotion<double,3> > forwardForwardSolution = x;
    std::vector<RigidBodyMotion<double,3> > forwardBackwardSolution = x;
    std::vector<RigidBodyMotion<double,3> > backwardForwardSolution = x;
    std::vector<RigidBodyMotion<double,3> > backwardBackwardSolution = x;
    

    // ///////////////////////////////////////////////////////////////
    //   Loop over all blocks of the outer matrix
    // ///////////////////////////////////////////////////////////////
    for (size_t i=0; i<hessian.N(); i++) {

        ColumnIterator cIt    = hessian[i].begin();
        ColumnIterator cEndIt = hessian[i].end();

        for (; cIt!=cEndIt; ++cIt) {

            // ////////////////////////////////////////////////////////////////////////////
            //   Compute a finite-difference approximation of this hessian matrix block
            // ////////////////////////////////////////////////////////////////////////////

            Dune::FieldMatrix<double,6,6> fdHessian;

            for (int j=0; j<6; j++) {

                for (int k=0; k<6; k++) {

                    if (i==cIt.index() && j==k) {

                        infinitesimalVariation(forwardSolution[i],   eps, j);
                        infinitesimalVariation(backwardSolution[i], -eps, j);

                        // Second derivative
                        fdHessian[j][k] = (assembler.computeEnergy(forwardSolution) 
                                           + assembler.computeEnergy(backwardSolution) 
                                           - 2*assembler.computeEnergy(x) 
                                           ) / (eps*eps);

                        forwardSolution[i]  = x[i];
                        backwardSolution[i] = x[i];

                    } else {

                        infinitesimalVariation(forwardForwardSolution[i],             eps, j);
                        infinitesimalVariation(forwardForwardSolution[cIt.index()],   eps, k);
                        infinitesimalVariation(forwardBackwardSolution[i],            eps, j);
                        infinitesimalVariation(forwardBackwardSolution[cIt.index()], -eps, k);
                        infinitesimalVariation(backwardForwardSolution[i],           -eps, j);
                        infinitesimalVariation(backwardForwardSolution[cIt.index()],  eps, k);
                        infinitesimalVariation(backwardBackwardSolution[i],          -eps, j);
                        infinitesimalVariation(backwardBackwardSolution[cIt.index()],-eps, k);


                        fdHessian[j][k] = (assembler.computeEnergy(forwardForwardSolution)
                                           + assembler.computeEnergy(backwardBackwardSolution)
                                           - assembler.computeEnergy(forwardBackwardSolution)
                                           - assembler.computeEnergy(backwardForwardSolution)) / (4*eps*eps);

                        forwardForwardSolution[i]             = x[i];
                        forwardForwardSolution[cIt.index()]   = x[cIt.index()];
                        forwardBackwardSolution[i]            = x[i];
                        forwardBackwardSolution[cIt.index()]  = x[cIt.index()];
                        backwardForwardSolution[i]            = x[i];
                        backwardForwardSolution[cIt.index()]  = x[cIt.index()];
                        backwardBackwardSolution[i]           = x[i];
                        backwardBackwardSolution[cIt.index()] = x[cIt.index()];
                        
                    }
                            
                }

            }
                //exit(0);
            // /////////////////////////////////////////////////////////////////////////////
            //   Compare analytical and fd Hessians
            // /////////////////////////////////////////////////////////////////////////////

            Dune::FieldMatrix<double,6,6> diff = fdHessian;
            diff -= *cIt;

            if ( diff.frobenius_norm() > 1e-5 ) {
#ifdef ABORT_ON_ERROR
                std::cout << "Differing hessians at [(" << i << ", "<< cIt.index() << ")]!" << std::endl
                          << "Analytical: " << std::endl << *cIt << std::endl
                          << "fd: " << std::endl << fdHessian << std::endl;
                abort();
#else
                hessianError++;
#endif
            }

        }

    }

#ifndef ABORT_ON_ERROR
    std::cout << hessianError << " errors in the Hessian corrected!" << std::endl;
#endif

}


int main (int argc, char *argv[]) try
{
    typedef std::vector<RigidBodyMotion<double,3> > SolutionType;

    // ///////////////////////////////////////
    //    Create the grid
    // ///////////////////////////////////////
    typedef OneDGrid GridType;
    GridType grid(1, 0, 1);

    SolutionType x(grid.size(1));

    // //////////////////////////
    //   Initial solution
    // //////////////////////////
    FieldVector<double,3>  xAxis(0);
    xAxis[0] = 1;
    FieldVector<double,3>  zAxis(0);
    zAxis[2] = 1;

    for (size_t i=0; i<x.size(); i++) {
        x[i].r[0] = 0;    // x
        x[i].r[1] = 0;                 // y
        x[i].r[2] = double(i)/(x.size()-1);                 // z
        //x[i].r[2] = i+5;
        x[i].q = Quaternion<double>::identity();
        //x[i].q = Quaternion<double>(zAxis, M_PI/2 * double(i)/(x.size()-1));
    }

    //x.back().r[1] = 0.1;
    //x.back().r[2] = 2;
    //x.back().q = Quaternion<double>(zAxis, M_PI/4);

    std::cout << "Left boundary orientation:" << std::endl;
    std::cout << "director 0:  " << x[0].q.director(0) << std::endl;
    std::cout << "director 1:  " << x[0].q.director(1) << std::endl;
    std::cout << "director 2:  " << x[0].q.director(2) << std::endl;
    std::cout << std::endl;
    std::cout << "Right boundary orientation:" << std::endl;
    std::cout << "director 0:  " << x[x.size()-1].q.director(0) << std::endl;
    std::cout << "director 1:  " << x[x.size()-1].q.director(1) << std::endl;
    std::cout << "director 2:  " << x[x.size()-1].q.director(2) << std::endl;
//     exit(0);

    //x[0].r[2] = -1;

    // ///////////////////////////////////////////
    //   Create a solver for the rod problem
    // ///////////////////////////////////////////
    RodLocalStiffness<GridType::LeafGridView,double> localStiffness(grid.leafGridView(),
                                                                    0.01, 0.0001, 0.0001, 2.5e5, 0.3);


    RodAssembler<GridType::LeafGridView,3> rodAssembler(grid.leafGridView(), &localStiffness);

    std::cout << "Energy: " << rodAssembler.computeEnergy(x) << std::endl;

    double pos = (argc==2) ? atof(argv[1]) : 0.5;

    FieldVector<double,1> shapeGrad[2];
    shapeGrad[0] = -1;
    shapeGrad[1] =  1;

    FieldVector<double,1> shapeFunction[2];
    shapeFunction[0] = 1-pos;
    shapeFunction[1] =  pos;

    exit(0);
    BlockVector<FieldVector<double,6> > rhs(x.size());
    BCRSMatrix<FieldMatrix<double,6,6> > hessianMatrix;
    MatrixIndexSet indices(grid.size(1), grid.size(1));
    rodAssembler.getNeighborsPerVertex(indices);
    indices.exportIdx(hessianMatrix);

    rodAssembler.assembleGradient(x, rhs);
    rodAssembler.assembleMatrix(x, hessianMatrix);
    
    gradientFDCheck(x, rhs, rodAssembler);
    hessianFDCheck(x, hessianMatrix, rodAssembler);
        
    // //////////////////////////////
 } catch (Exception e) {

    std::cout << e << std::endl;

 }