diff --git a/src/rodassembler.cc b/src/rodassembler.cc index 074a14f6331ae0c2821c863fd07061706bf35f14..2827907480cf10a382ab0dd67e6fb9fed491f928 100644 --- a/src/rodassembler.cc +++ b/src/rodassembler.cc @@ -7,6 +7,156 @@ #include <dune/disc/shapefunctions/lagrangeshapefunctions.hh> + +template <class GridType, class RT> +RT RodLocalStiffness<GridType, RT>:: +energy(const EntityPointer& element, + const std::vector<Configuration>& localSolution, + const std::vector<Configuration>& localReferenceConfiguration, + int k) +{ + RT energy = 0; + + //const typename GridType::Traits::LeafIndexSet& indexSet = grid_->leafIndexSet(); + + double elementEnergy = 0; + + // Extract local solution on this element + const Dune::LagrangeShapeFunctionSet<double, double, 1> & baseSet + = Dune::LagrangeShapeFunctions<double, double, 1>::general(element->type(), k); + int numOfBaseFct = baseSet.size(); + + // /////////////////////////////////////////////////////////////////////////////// + // The following two loops are a reduced integration scheme. We integrate + // the transverse shear and extensional energy with a first-order quadrature + // formula, even though it should be second order. This prevents shear-locking + // /////////////////////////////////////////////////////////////////////////////// + + const int shearingPolOrd = 2; + const Dune::QuadratureRule<double, 1>& shearingQuad + = Dune::QuadratureRules<double, 1>::rule(element->type(), shearingPolOrd); + + for (size_t pt=0; pt<shearingQuad.size(); pt++) { + + // Local position of the quadrature point + const Dune::FieldVector<double,1>& quadPos = shearingQuad[pt].position(); + + const double integrationElement = element->geometry().integrationElement(quadPos); + + double weight = shearingQuad[pt].weight() * integrationElement; + + Dune::FieldVector<double,6> strain = getStrain(localSolution, element, quadPos); + + // The reference strain + Dune::FieldVector<double,6> referenceStrain = getStrain(localReferenceConfiguration, element, quadPos); + + for (int i=0; i<3; i++) { + energy += weight * 0.5 * A_[i] * (strain[i] - referenceStrain[i]) * (strain[i] - referenceStrain[i]); + elementEnergy += weight * 0.5 * A_[i] * (strain[i] - referenceStrain[i]) * (strain[i] - referenceStrain[i]); + } + } + + // Get quadrature rule + const int polOrd = 2; + const Dune::QuadratureRule<double, 1>& bendingQuad = Dune::QuadratureRules<double, 1>::rule(element->type(), polOrd); + + for (size_t pt=0; pt<bendingQuad.size(); pt++) { + + // Local position of the quadrature point + const Dune::FieldVector<double,1>& quadPos = bendingQuad[pt].position(); + + double weight = bendingQuad[pt].weight() * element->geometry().integrationElement(quadPos); + + Dune::FieldVector<double,6> strain = getStrain(localSolution, element, quadPos); + + // The reference strain + Dune::FieldVector<double,6> referenceStrain = getStrain(localReferenceConfiguration, element, quadPos); + + // Part II: the bending and twisting energy + for (int i=0; i<3; i++) { + energy += weight * 0.5 * K_[i] * (strain[i+3] - referenceStrain[i+3]) * (strain[i+3] - referenceStrain[i+3]); + elementEnergy += weight * 0.5 * K_[i] * (strain[i+3] - referenceStrain[i+3]) * (strain[i+3] - referenceStrain[i+3]); + } + + } + + return energy; +} + +template <class GridType, class RT> +Dune::FieldVector<double, 6> RodLocalStiffness<GridType, RT>:: +getStrain(const std::vector<Configuration>& localSolution, + const EntityPointer& element, + const Dune::FieldVector<double,1>& pos) const +{ + if (!element->isLeaf()) + DUNE_THROW(Dune::NotImplemented, "Only for leaf elements"); + + assert(localSolution.size() == 2); + + // Strain defined on each element + Dune::FieldVector<double, 6> strain(0); + + // Extract local solution on this element + const Dune::LagrangeShapeFunctionSet<double, double, 1> & baseSet + = Dune::LagrangeShapeFunctions<double, double, 1>::general(element->type(), 1); + int numOfBaseFct = baseSet.size(); + + const Dune::FieldMatrix<double,1,1>& inv = element->geometry().jacobianInverseTransposed(pos); + + // /////////////////////////////////////// + // Compute deformation gradient + // /////////////////////////////////////// + Dune::FieldVector<double,1> shapeGrad[numOfBaseFct]; + + for (int dof=0; dof<numOfBaseFct; dof++) { + + for (int i=0; i<1; i++) + shapeGrad[dof][i] = baseSet[dof].evaluateDerivative(0,i,pos); + + // multiply with jacobian inverse + Dune::FieldVector<double,1> tmp(0); + inv.umv(shapeGrad[dof], tmp); + shapeGrad[dof] = tmp; + + } + + // ////////////////////////////////// + // Interpolate + // ////////////////////////////////// + + Dune::FieldVector<double,3> r_s; + for (int i=0; i<3; i++) + r_s[i] = localSolution[0].r[i]*shapeGrad[0][0] + localSolution[1].r[i]*shapeGrad[1][0]; + + // Interpolate the rotation at the quadrature point + Quaternion<double> q = Quaternion<double>::interpolate(localSolution[0].q, localSolution[1].q, pos); + + // Get the derivative of the rotation at the quadrature point by interpolating in $H$ + Quaternion<double> q_s = Quaternion<double>::interpolateDerivative(localSolution[0].q, localSolution[1].q, + pos, 1/shapeGrad[1]); + + // ///////////////////////////////////////////// + // Sum it all up + // ///////////////////////////////////////////// + + // Part I: the shearing and stretching strain + strain[0] = r_s * q.director(0); // shear strain + strain[1] = r_s * q.director(1); // shear strain + strain[2] = r_s * q.director(2); // stretching strain + + // Part II: the Darboux vector + + Dune::FieldVector<double,3> u = darboux(q, q_s); + + strain[3] = u[0]; + strain[4] = u[1]; + strain[5] = u[2]; + + return strain; +} + + template <class GridType> void Dune::RodAssembler<GridType>:: getNeighborsPerVertex(MatrixIndexSet& nb) const @@ -377,6 +527,208 @@ getLocalMatrix( EntityPointer &entity, } +template <class GridType> +void Dune::RodAssembler<GridType>:: +assembleMatrixFD(const std::vector<Configuration>& sol, + BCRSMatrix<MatrixBlock>& matrix) const +{ + double eps = 1e-2; + + typedef typename Dune::BCRSMatrix<Dune::FieldMatrix<double,6,6> >::row_type::iterator ColumnIterator; + + // /////////////////////////////////////////////////////////// + // Compute gradient by finite-difference approximation + // /////////////////////////////////////////////////////////// + std::vector<Configuration> forwardSolution = sol; + std::vector<Configuration> backwardSolution = sol; + + std::vector<Configuration> forwardForwardSolution = sol; + std::vector<Configuration> forwardBackwardSolution = sol; + std::vector<Configuration> backwardForwardSolution = sol; + std::vector<Configuration> backwardBackwardSolution = sol; + + // //////////////////////////////////////////////////// + // Create local assembler + // //////////////////////////////////////////////////// + + Dune::array<double,3> K = {K_[0], K_[1], K_[2]}; + Dune::array<double,3> A = {A_[0], A_[1], A_[2]}; + RodLocalStiffness<GridType,double> localStiffness(K, A); + + // ////////////////////////////////////////////////////////////////// + // Store pointers to all elements so we can access them by index + // ////////////////////////////////////////////////////////////////// + + const typename GridType::Traits::LeafIndexSet& indexSet = grid_->leafIndexSet(); + + std::vector<EntityPointer> elements(grid_->size(0),grid_->template leafbegin<0>()); + + typename GridType::template Codim<0>::LeafIterator eIt = grid_->template leafbegin<0>(); + typename GridType::template Codim<0>::LeafIterator eEndIt = grid_->template leafend<0>(); + + for (; eIt!=eEndIt; ++eIt) + elements[indexSet.index(*eIt)] = eIt; + + std::vector<Configuration> localReferenceConfiguration(2); + std::vector<Configuration> localSolution(2); + + // /////////////////////////////////////////////////////////////// + // Loop over all blocks of the outer matrix + // /////////////////////////////////////////////////////////////// + for (int i=0; i<matrix.N(); i++) { + + ColumnIterator cIt = matrix[i].begin(); + ColumnIterator cEndIt = matrix[i].end(); + + for (; cIt!=cEndIt; ++cIt) { + + // //////////////////////////////////////////////////////////////////////////// + // Compute a finite-difference approximation of this hessian matrix block + // //////////////////////////////////////////////////////////////////////////// + + for (int j=0; j<6; j++) { + + for (int k=0; k<6; k++) { + + if (i==cIt.index() && j==k) { + + double forwardEnergy = 0; + double solutionEnergy = 0; + double backwardEnergy = 0; + + infinitesimalVariation(forwardSolution[i], eps, j); + infinitesimalVariation(backwardSolution[i], -eps, j); + + if (i != grid_->size(1)-1) { + + localReferenceConfiguration[0] = referenceConfiguration_[i]; + localReferenceConfiguration[1] = referenceConfiguration_[i+1]; + + localSolution[0] = forwardSolution[i]; + localSolution[1] = forwardSolution[i+1]; + + forwardEnergy += localStiffness.energy(elements[i], localSolution, localReferenceConfiguration); + + localSolution[0] = sol[i]; + localSolution[1] = sol[i+1]; + + solutionEnergy += localStiffness.energy(elements[i], localSolution, localReferenceConfiguration); + + localSolution[0] = backwardSolution[i]; + localSolution[1] = backwardSolution[i+1]; + + backwardEnergy += localStiffness.energy(elements[i], localSolution, localReferenceConfiguration); + + } + + if (i != 0) { + + localReferenceConfiguration[0] = referenceConfiguration_[i-1]; + localReferenceConfiguration[1] = referenceConfiguration_[i]; + + localSolution[0] = forwardSolution[i-1]; + localSolution[1] = forwardSolution[i]; + + forwardEnergy += localStiffness.energy(elements[i-1], localSolution, localReferenceConfiguration); + + localSolution[0] = sol[i-1]; + localSolution[1] = sol[i]; + + solutionEnergy += localStiffness.energy(elements[i-1], localSolution, localReferenceConfiguration); + + localSolution[0] = backwardSolution[i-1]; + localSolution[1] = backwardSolution[i]; + + backwardEnergy += localStiffness.energy(elements[i-1], localSolution, localReferenceConfiguration); + + } + + // Second derivative + (*cIt)[j][k] = (forwardEnergy - 2*solutionEnergy + backwardEnergy) / (eps*eps); + + forwardSolution[i] = sol[i]; + backwardSolution[i] = sol[i]; + + } else { + + double forwardForwardEnergy = 0; + double forwardBackwardEnergy = 0; + double backwardForwardEnergy = 0; + double backwardBackwardEnergy = 0; + + 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); + + std::set<int> elementsInvolved; + if (i>0) + elementsInvolved.insert(i-1); + if (i<grid_->size(1)-1) + elementsInvolved.insert(i); + if (cIt.index()>0) + elementsInvolved.insert(cIt.index()-1); + if (cIt.index()<grid_->size(1)-1) + elementsInvolved.insert(cIt.index()); + + for (typename std::set<int>::iterator it = elementsInvolved.begin(); + it != elementsInvolved.end(); + ++it) { + + localReferenceConfiguration[0] = referenceConfiguration_[*it]; + localReferenceConfiguration[1] = referenceConfiguration_[*it+1]; + + localSolution[0] = forwardForwardSolution[*it]; + localSolution[1] = forwardForwardSolution[*it+1]; + + forwardForwardEnergy += localStiffness.energy(elements[*it], localSolution, localReferenceConfiguration); + + localSolution[0] = forwardBackwardSolution[*it]; + localSolution[1] = forwardBackwardSolution[*it+1]; + + forwardBackwardEnergy += localStiffness.energy(elements[*it], localSolution, localReferenceConfiguration); + + localSolution[0] = backwardForwardSolution[*it]; + localSolution[1] = backwardForwardSolution[*it+1]; + + backwardForwardEnergy += localStiffness.energy(elements[*it], localSolution, localReferenceConfiguration); + + localSolution[0] = backwardBackwardSolution[*it]; + localSolution[1] = backwardBackwardSolution[*it+1]; + + backwardBackwardEnergy += localStiffness.energy(elements[*it], localSolution, localReferenceConfiguration); + + + } + + (*cIt)[j][k] = (forwardForwardEnergy + backwardBackwardEnergy + - forwardBackwardEnergy - backwardForwardEnergy) / (4*eps*eps); + + forwardForwardSolution[i] = sol[i]; + forwardForwardSolution[cIt.index()] = sol[cIt.index()]; + forwardBackwardSolution[i] = sol[i]; + forwardBackwardSolution[cIt.index()] = sol[cIt.index()]; + backwardForwardSolution[i] = sol[i]; + backwardForwardSolution[cIt.index()] = sol[cIt.index()]; + backwardBackwardSolution[i] = sol[i]; + backwardBackwardSolution[cIt.index()] = sol[cIt.index()]; + + } + + } + + } + + } + + } + +} + template <class GridType> void Dune::RodAssembler<GridType>:: strainDerivative(const std::vector<Configuration>& localSolution, diff --git a/src/rodassembler.hh b/src/rodassembler.hh index 106dc3153db86c94d5eaed73bf3276a90ed29e66..fe98940a3b0d2a115299f7cac133ea91806c2fee 100644 --- a/src/rodassembler.hh +++ b/src/rodassembler.hh @@ -5,10 +5,118 @@ #include <dune/common/fmatrix.hh> #include <dune/istl/matrixindexset.hh> #include <dune/istl/matrix.hh> +#include <dune/disc/operators/localstiffness.hh> #include "../../common/boundarypatch.hh" #include "configuration.hh" +template<class GridType, class RT> +class RodLocalStiffness + : public Dune::LocalStiffness<RodLocalStiffness<GridType,RT>,GridType,RT,6> +{ + // grid types + typedef typename GridType::ctype DT; + typedef typename GridType::template Codim<0>::Entity Entity; + typedef typename GridType::template Codim<0>::EntityPointer EntityPointer; + + // some other sizes + enum {dim=GridType::dimension}; + +public: + // define the number of components of your system, this is used outside + // to allocate the correct size of (dense) blocks with a FieldMatrix + enum {m=6}; + + enum {SIZE = Dune::LocalStiffness<RodLocalStiffness,GridType,RT,m>::SIZE}; + + // types for matrics, vectors and boundary conditions + typedef Dune::FieldMatrix<RT,m,m> MBlockType; // one entry in the stiffness matrix + typedef Dune::FieldVector<RT,m> VBlockType; // one entry in the global vectors + typedef Dune::array<Dune::BoundaryConditions::Flags,m> BCBlockType; // componentwise boundary conditions + + // ///////////////////////////////// + // The material parameters + // ///////////////////////////////// + + /** \brief Material constants */ + double K_[3]; + double A_[3]; + + //! Default Constructor + RodLocalStiffness () + { + // this->currentsize_ = 0; + + // For the time being: all boundary conditions are homogeneous Neumann + // This means no boundary condition handling is done at all + for (int i=0; i<Dune::LocalStiffness<RodLocalStiffness,GridType,RT,m>::SIZE; i++) + for (size_t j=0; j<this->bctype[i].size(); j++) + this->bctype[i][j] = Dune::BoundaryConditions::neumann; + } + + //! Default Constructor + RodLocalStiffness (const Dune::array<double,3>& K, const Dune::array<double,3>& A) + { + for (int i=0; i<3; i++) { + K_[i] = K[i]; + A_[i] = A[i]; + } + // this->currentsize_ = 0; + + // For the time being: all boundary conditions are homogeneous Neumann + // This means no boundary condition handling is done at all + for (int i=0; i<Dune::LocalStiffness<RodLocalStiffness,GridType,RT,m>::SIZE; i++) + for (size_t j=0; j<this->bctype[i].size(); j++) + this->bctype[i][j] = Dune::BoundaryConditions::neumann; + } + + //! assemble local stiffness matrix for given element and order + /*! On exit the following things have been done: + - The stiffness matrix for the given entity and polynomial degree has been assembled and is + accessible with the mat() method. + - The boundary conditions have been evaluated and are accessible with the bc() method + - The right hand side has been assembled. It contains either the value of the essential boundary + condition or the assembled source term and neumann boundary condition. It is accessible via the rhs() method. + @param[in] e a codim 0 entity reference + \param[in] localSolution Current local solution, because this is a nonlinear assembler + @param[in] k order of Lagrange basis + */ + template<typename TypeTag> + void assemble (const Entity& e, + const Dune::BlockVector<Dune::FieldVector<double, dim> >& localSolution, + int k=1); + + + RT energy (const EntityPointer& e, + const std::vector<Configuration>& localSolution, + const std::vector<Configuration>& localReferenceConfiguration, + int k=1); + + Dune::FieldVector<double, 6> getStrain(const std::vector<Configuration>& localSolution, + const EntityPointer& element, + const Dune::FieldVector<double,1>& pos) const; + + template <class T> + static Dune::FieldVector<T,3> darboux(const Quaternion<T>& q, const Dune::FieldVector<T,4>& q_s) + { + Dune::FieldVector<double,3> u; // The Darboux vector + + u[0] = 2 * (q.B(0) * q_s); + u[1] = 2 * (q.B(1) * q_s); + u[2] = 2 * (q.B(2) * q_s); + + return u; + } + + + //! should allow to assmble boundary conditions only +// template<typename Tag> +// void assembleBoundaryCondition (const Entity& e, int k=1) +// { +// } + +}; + namespace Dune { @@ -44,6 +152,17 @@ namespace Dune /** \brief The stress-free configuration */ std::vector<Configuration> referenceConfiguration_; + /** \todo Only for the fd approximations */ + static void infinitesimalVariation(Configuration& c, double eps, int i) + { + if (i<3) + c.r[i] += eps; + else + c.q = c.q.mult(Quaternion<double>::exp((i==3)*eps, + (i==4)*eps, + (i==5)*eps)); + } + public: //! ??? @@ -106,11 +225,16 @@ namespace Dune //exit(0); } - /** \brief Assemble the tangent stiffness matrix and the right hand side + /** \brief Assemble the tangent stiffness matrix */ void assembleMatrix(const std::vector<Configuration>& sol, BCRSMatrix<MatrixBlock>& matrix) const; + /** \brief Assemble the tangent stiffness matrix using a finite difference approximation + */ + void assembleMatrixFD(const std::vector<Configuration>& sol, + BCRSMatrix<MatrixBlock>& matrix) const; + void strainDerivative(const std::vector<Configuration>& localSolution, double pos, FieldVector<double,1> shapeGrad[2],