diff --git a/dune/elasticity/assemblers/mooneyrivlinfunctionalassembler.hh b/dune/elasticity/assemblers/mooneyrivlinfunctionalassembler.hh new file mode 100644 index 0000000000000000000000000000000000000000..d68ce37392ea8bc653fe71549783ea9a8fcd7e06 --- /dev/null +++ b/dune/elasticity/assemblers/mooneyrivlinfunctionalassembler.hh @@ -0,0 +1,215 @@ +#ifndef MOONEY_RIVLIN_FUNCTIONAL_ASSEMBLER_HH +#define MOONEY_RIVLIN_FUNCTIONAL_ASSEMBLER_HH + +#include <dune/common/fvector.hh> +#include <dune/istl/bvector.hh> + +#include <dune/fufem/quadraturerules/quadraturerulecache.hh> +#include "dune/fufem/assemblers/localfunctionalassembler.hh" +#include <dune/fufem/symmetrictensor.hh> +#include <dune/fufem/functions/virtualgridfunction.hh> + +#include <dune/elasticity/common/elasticityhelpers.hh> + +/** \brief Local assembler for the linearization of a nonlinear Mooney-Rivlin energy at a displacement u + * + * \f[ + * W(u)= a tr(E(u)) + b tr(E(u))^2 + c ||E(u)||^2 + d J^2 + e J^-k, k>=2 + * \f] + * + * where + * - \f$E\f$: the nonlinear strain tensor + * - \f$tr \f$: the trace operator + * - \f$J\f$ the determinant of the deformation gradient + * - \f$\a\f$,...,\f$\e\f$ material parameters + * - \f$k\f$ controlls orientation preservation (k \approx \floor(1/(1-2nu) -1)) +*/ +template <class GridType, class TrialLocalFE> +class MooneyRivlinFunctionalAssembler : + public LocalFunctionalAssembler<GridType,TrialLocalFE, Dune::FieldVector<typename GridType::ctype ,GridType::dimension> > + +{ + static const int dim = GridType::dimension; + typedef typename GridType::ctype ctype; + typedef typename Dune::FieldVector<ctype,GridType::dimension> T; + +public: + typedef typename LocalFunctionalAssembler<GridType,TrialLocalFE,T>::Element Element; + typedef typename LocalFunctionalAssembler<GridType,TrialLocalFE,T>::LocalVector LocalVector; + typedef VirtualGridFunction<GridType, T > GridFunction; + + //! Create assembler from material parameters and discplacement + MooneyRivlinFunctionalAssembler(const Dune::shared_ptr<GridFunction> displacement, + ctype a, ctype b, ctype c, ctype d, ctype e, int k) : + a_(a),b_(b),c_(c),d_(d),e_(e),k_(k), + displacement_(displacement) + {} + + //! Create assembler from material parameters + MooneyRivlinFunctionalAssembler(ctype a, ctype b, ctype c, ctype d, ctype e, int k) : + a_(a),b_(b),c_(c),d_(d),e_(e),k_(k) + {} + + void assemble(const Element& element, LocalVector& localVector, const TrialLocalFE& tFE) const + { + + typedef typename Dune::FieldMatrix<ctype,dim,dim> FMdimdim; + typedef typename TrialLocalFE::Traits::LocalBasisType::Traits::JacobianType JacobianType; + typedef typename GridType::template Codim<0>::Geometry::LocalCoordinate LocalCoordinate; + + int rows = tFE.localBasis().size(); + + localVector.resize(rows); + localVector = 0.0; + + // get quadrature rule + const int order = (element.type().isSimplex()) + ? 6*(tFE.localBasis().order()) + : 6*(tFE.localBasis().order()*dim); + + // get quadrature rule + const Dune::template QuadratureRule<ctype, dim>& quad = QuadratureRuleCache<ctype, dim>::rule(element.type(), order, IsRefinedLocalFiniteElement<TrialLocalFE>::value(tFE) ); + + // store gradients of shape functions and base functions + std::vector<JacobianType> referenceGradients(tFE.localBasis().size()); + std::vector<T> gradients(tFE.localBasis().size()); + + // store geometry mapping of the entity + const typename ElementPointer::Entity::Geometry geometry = element.geometry(); + + // loop over quadrature points + for (size_t pt=0; pt < quad.size(); ++pt) { + + // get quadrature point + const LocalCoordinate& quadPos = quad[pt].position(); + + // get transposed inverse of Jacobian of transformation + const FMdimdim& invJacobian = geometry.jacobianInverseTransposed(quadPos); + + // get integration factor + const ctype integrationElement = geometry.integrationElement(quadPos); + + // get gradients of shape functions + tFE.localBasis().evaluateJacobian(quadPos, referenceGradients); + + // compute gradients of base functions + for (size_t i=0; i<gradients.size(); ++i) { + + // transform gradients + gradients[i] = 0.0; + invJacobian.umv(referenceGradients[i][0], gradients[i]); + + } + + // evaluate the displacement gradient at the quadrature point + typename GridFunction::DerivativeType localConfGrad; + if (displacement_->isDefinedOn(element)) + displacement_->evaluateDerivativeLocal(element, quadPos, localConfGrad); + else + displacement_->evaluateDerivative(geometry.global(quadPos),localConfGrad); + + // compute linearization of the determinante of the deformation gradient + FMdimdim linDefDet; + Dune::Elasticity::linearisedDefDet(localConfGrad,linDefDet); + + // the trace of the strain tensor + SymmetricTensor<dim> strain; + computeStrain(localConfGrad,strain); + ctype trE(0); + for (int i=0; i<dim; i++) + trE += strain(i,i); + + // make deformation gradient out of the discplacement + for (int i=0;i<dim;i++) + localConfGrad[i][i] += 1; + + // evaluate the derminante of the deformation gradient + const ctype J = localConfGrad.determinant(); + + //compute linearized strain for all shapefunctions + std::vector<Dune::array<SymmetricTensor<dim>,dim> > linStrain(rows); + + for (int i=0; i<rows; i++) + for (int k=0; k<dim; k++) { + + // The deformation gradient of the shape function + FMdimdim deformationGradient(0); + deformationGradient[k] = gradients[i]; + + // The linearized strain is the symmetric product of defGrad and (Id+localConf) + linStrain[i][k]=symmetricProduct(deformationGradient,localConfGrad); + } + + + // collect terms + FMdimdim fu(0); + + // the linearization of the trace is just deformation gradient + fu.axpy(a_+2*b_*trE,localConfGrad); + + // linearization of the compressibility function + fu.axpy(2*d_*J-e_*k_*std::pow(J,-k_-1),linDefDet); + + ctype z = quad[pt].weight()*integrationElement; + + // add vector entries + for(int row=0; row<rows; row++) { + fu.usmv(z,gradients[row],localVector[row]); + + // linearization of the tensor contraction + for (int rcomp=0;rcomp<dim;rcomp++) + localVector[row][rcomp] +=(strain*linStrain[row][rcomp])*z*2*c_; + } + } + } + + /** \brief Set new configuration. In Newton iterations this needs to be assembled more than one time.*/ + void setConfiguration(Dune::shared_ptr<GridFunction> newDisplacement) { + displacement_ = newDisplacement; + } + +private: + //! Material parameters + ctype a_; ctype b_; ctype c_; ctype d_; ctype e_; + //! Compressibility + int k_; + + /** \brief The configuration at which the functional is evaluated.*/ + Dune::shared_ptr<GridFunction> displacement_; + + //! Compute nonlinear strain tensor from the deformation gradient. + void computeStrain(const Dune::FieldMatrix<ctype, dim, dim>& grad, SymmetricTensor<dim>& strain) const { + strain = 0; + for (int i=0; i<dim ; ++i) { + strain(i,i) +=grad[i][i]; + + for (int k=0;k<dim;++k) + strain(i,i) += 0.5*grad[k][i]*grad[k][i]; + + for (int j=i+1; j<dim; ++j) { + strain(i,j) += 0.5*(grad[i][j] + grad[j][i]); + for (int k=0;k<dim;++k) + strain(i,j) += 0.5*grad[k][i]*grad[k][j]; + } + } + } + + /** \brief Compute the symmetric product of two matrices, i.e. + * 0.5*(A^T * B + B^T * A ) + */ + SymmetricTensor<dim> symmetricProduct(const Dune::FieldMatrix<ctype, dim, dim>& a, const Dune::FieldMatrix<ctype, dim, dim>& b) const { + + SymmetricTensor<dim> result(0.0); + for (int i=0;i<dim; i++) + for (int j=i;j<dim;j++) + for (int k=0;k<dim;k++) + result(i,j)+= a[k][i]*b[k][j]+b[k][i]*a[k][j]; + result *= 0.5; + + return result; + } +}; + +#endif + + diff --git a/dune/elasticity/assemblers/mooneyrivlinoperatorassembler.hh b/dune/elasticity/assemblers/mooneyrivlinoperatorassembler.hh new file mode 100644 index 0000000000000000000000000000000000000000..353ebc3078c8c874fb8982c9888bac748984a582 --- /dev/null +++ b/dune/elasticity/assemblers/mooneyrivlinoperatorassembler.hh @@ -0,0 +1,278 @@ +#ifndef MOONEY_RIVLIN_OPERATOR_ASSEMBLER_HH +#define MOONEY_RIVLIN_OPERATOR_ASSEMBLER_HH + + +#include <dune/common/fvector.hh> +#include <dune/common/fmatrix.hh> + +#include <dune/istl/matrix.hh> + +#include <dune/fufem/quadraturerules/quadraturerulecache.hh> +#include <dune/fufem/assemblers/localoperatorassembler.hh> +#include <dune/fufem/staticmatrixtools.hh> +#include <dune/fufem/symmetrictensor.hh> +#include <dune/fufem/functions/virtualgridfunction.hh> + +#include <dune/elasticity/common/elasticityhelpers.hh> + +/** \brief Assemble the second derivative of a Mooney-Rivlin material. + * + * \f[ + * W(u)= a tr(E(u)) + b tr(E(u))^2 + c ||E(u)||^2 + d J^2 + e J^-k, k>=2 + * \f] + * + * where + * - \f$E\f$: the nonlinear strain tensor + * - \f$tr \f$: the trace operator + * - \f$J\f$ the determinant of the deformation gradient + * - \f$\a\f$,...,\f$\e\f$ material parameters + * - \f$k\f$ controlls orientation preservation (k \approx \floor(1/(1-2nu) -1)) +*/ +template <class GridType, class TrialLocalFE, class AnsatzLocalFE> +class MooneyRivlinOperatorAssembler + : public LocalOperatorAssembler < GridType, TrialLocalFE, AnsatzLocalFE, Dune::FieldMatrix<typename GridType::ctype ,GridType::dimension,GridType::dimension> > +{ + + + static const int dim = GridType::dimension; + typedef typename GridType::ctype ctype; + + typedef VirtualGridFunction<GridType, Dune::FieldVector<ctype,GridType::dimension> > GridFunction; + +public: + typedef typename Dune::FieldMatrix<ctype,GridType::dimension,GridType::dimension> T; + + typedef typename LocalOperatorAssembler < GridType, TrialLocalFE, AnsatzLocalFE, T >::Element Element; + typedef typename LocalOperatorAssembler < GridType, TrialLocalFE, AnsatzLocalFE,T >::BoolMatrix BoolMatrix; + typedef typename LocalOperatorAssembler < GridType, TrialLocalFE, AnsatzLocalFE,T >::LocalMatrix LocalMatrix; + + + MooneyRivlinOperatorAssembler(const Dune::shared_ptr<GridFunction> displacement, + ctype a, ctype b, ctype c, ctype d, ctype e, int k) : + a_(a),b_(b),c_(c),d_(d),e_(e),k_(k), displacement_(displacement) + {} + + MooneyRivlinOperatorAssembler(ctype a, ctype b, ctype c, ctype d, ctype e, int k) : + a_(a),b_(b),c_(c),d_(d),e_(e),k_(k) + {} + + void indices(const Element& element, BoolMatrix& isNonZero, const TrialLocalFE& tFE, const AnsatzLocalFE& aFE) const + { + isNonZero = true; + } + + void assemble(const Element& element, LocalMatrix& localMatrix, const TrialLocalFE& tFE, const AnsatzLocalFE& aFE) const + { + typedef Dune::FieldVector<ctype,dim> FVdim; + typedef Dune::FieldMatrix<ctype,dim,dim> FMdimdim; + typedef typename TrialLocalFE::Traits::LocalBasisType::Traits::JacobianType JacobianType; + + int rows = tFE.localBasis().size(); + int cols = aFE.localBasis().size(); + + localMatrix.setSize(rows,cols); + localMatrix = 0.0; + + // get quadrature rule + const int order = (element.type().isSimplex()) + ? 6*(tFE.localBasis().order()) + : 6*(tFE.localBasis().order()*dim); + const Dune::template QuadratureRule<ctype, dim>& quad = QuadratureRuleCache<ctype, dim>::rule(element.type(), order, IsRefinedLocalFiniteElement<TrialLocalFE>::value(tFE) ); + + // store gradients of shape functions and base functions + std::vector<JacobianType> referenceGradients(tFE.localBasis().size()); + std::vector<FVdim> gradients(tFE.localBasis().size()); + + // store entity geometry mapping + const typename Element::Geometry geometry = element.geometry(); + + // loop over quadrature points + for (size_t pt=0; pt < quad.size(); ++pt) { + + // get quadrature point + const FVdim& quadPos = quad[pt].position(); + + // get transposed inverse of Jacobian of transformation + const FMdimdim& invJacobian = geometry.jacobianInverseTransposed(quadPos); + + // get integration factor + const ctype integrationElement = geometry.integrationElement(quadPos); + + // get gradients of shape functions + tFE.localBasis().evaluateJacobian(quadPos, referenceGradients); + + // compute gradients of base functions + for (size_t i=0; i<gradients.size(); ++i) { + + // transform gradients + gradients[i] = 0.0; + invJacobian.umv(referenceGradients[i][0], gradients[i]); + + } + + // evaluate displacement gradients the configuration at the quadrature point + typename GridFunction::DerivativeType localConfGrad; + if (displacement_->isDefinedOn(element)) + displacement_->evaluateDerivativeLocal(element, quadPos, localConfGrad); + else + displacement_->evaluateDerivative(geometry.global(quadPos),localConfGrad); + + // compute linearization of the determinante of the deformation gradient + FMdimdim linDefDet; + Dune::Elasticity::linearisedDefDet(localConfGrad,linDefDet); + + // compute deformation gradient of the configuration + for (int i=0;i<dim;i++) + localConfGrad[i][i] += 1; + + // evaluate the derminante of the deformation gradient + const ctype J = localConfGrad.determinant(); + + //compute linearized strain for all shapefunctions + std::vector<Dune::array<FMdimdim, dim > > defGrad(rows); + std::vector<Dune::array<SymmetricTensor<dim>,dim> > linStrain(rows); + + for (int i=0; i<rows; i++) + for (int k=0; k<dim; k++) { + + // The deformation gradient of the shape function + defGrad[i][k] = 0; + defGrad[i][k][k] = gradients[i]; + + // The linearized strain is the symmetric product of defGrad and (Id+localConf) + linStrain[i][k]=symmetricProduct(defGrad[i][k],localConfGrad); + } + + // the trace of the strain tensor + SymmetricTensor<dim> strain; + computeStrain(localConfGrad,strain); + ctype trE(0); + for (int i=0; i<dim; i++) + trE += strain(i,i); + + // ///////////////////////////////////////////////// + // Assemble matrix + // ///////////////////////////////////////////////// + ctype z = quad[pt].weight() * integrationElement; + + ctype coeff= (2*d_*J-k_*e_*std::pow(J,-k_-1))*z; + ctype coeff2 = (2*d_+k_*(k_+1)*e_*std::pow(J,-k_-2))*z; + + for (int row=0; row<rows; row++) + for (int col=0; col<cols; col++) { + + // second derivative of the trace terms + StaticMatrix::addToDiagonal(localMatrix[row][col],z*(a_ + 2*b_*trE)*((gradients[row]*gradients[col]))); + // second derivative of the determinat term + localMatrix[row][col].axpy(coeff,hessDefDet(localConfGrad,gradients[row],gradients[col])); + + FVdim rowTerm(0),colTerm(0); + linDefDet.mv(gradients[row],rowTerm); + linDefDet.mv(gradients[col],colTerm); + + FVdim traceRowTerm(0),traceColTerm(0); + localConfGrad.mv(gradients[row],traceRowTerm); + localConfGrad.mv(gradients[col],traceColTerm); + + // second derivative of the scalar product term + for (int rcomp=0; rcomp<dim; rcomp++) { + // derivative of the coefficient term in the compressibility function + localMatrix[row][col][rcomp].axpy(coeff2*rowTerm[rcomp],colTerm); + + // second derivative of the trace terms part 2 + localMatrix[row][col][rcomp].axpy(2*z*b_*traceRowTerm[rcomp],traceColTerm); + + // derivative of the scalar product terms + for (int ccomp=0; ccomp<dim; ccomp++) { + localMatrix[row][col][rcomp][ccomp] += (linStrain[row][rcomp]*linStrain[col][ccomp])*2*c_*z; + localMatrix[row][col][rcomp][ccomp] += (strain*symmetricProduct(defGrad[row][rcomp],defGrad[col][ccomp]))*z*2*c_; + } + } + + } + } + + } + + /** \brief Set new configuration to be assembled at. Needed e.g. during Newton iteration.*/ + void setConfiguration(Dune::shared_ptr<GridFunction> newConfig) { + displacement_ = newConfig; + } + +private: + + //! Material parameters + ctype a_; ctype b_; ctype c_; ctype d_; ctype e_; + int k_; + + /** \brief The configuration at which the linearized operator is evaluated.*/ + Dune::shared_ptr<GridFunction> displacement_; + + + /** \brief Compute the matrix entry that arises from the second derivative of the determinant. + * Note that it is assumed the defGrad is the deformation gradient and not the displacement gradient + */ + Dune::FieldMatrix<ctype,dim,dim> hessDefDet(const Dune::FieldMatrix<ctype,dim,dim>& defGrad, + const Dune::FieldVector<ctype,dim>& testGrad, const Dune::FieldVector<ctype,dim>& ansatzGrad) const + { + Dune::FieldMatrix<ctype, dim, dim> res(0); + + if (dim==2) { + res[0][1] = testGrad[0]*ansatzGrad[1]-ansatzGrad[0]*testGrad[1]; + res[1][0] = -res[0][1]; + return res; + } + + //compute the cross product + Dune::FieldVector<ctype,dim> cross(0); + for (int k=0; k<dim; k++) + cross[k]=testGrad[(k+1)%dim]*ansatzGrad[(k+2)%dim] -testGrad[(k+2)%dim]*ansatzGrad[(k+1)%dim]; + + // the resulting matrix is skew symmetric with entries <cross,degGrad[i]> + for (int i=0; i<dim; i++) + for (int j=i+1; j<dim; j++) { + int k= (dim-(i+j))%dim; + res[i][j] = (cross*defGrad[k])*std::pow(-1,k); + res[j][i] = -res[i][j]; + } + + return res; + } + + //! Compute nonlinear strain tensor from the deformation gradient. + void computeStrain(const Dune::FieldMatrix<ctype, dim, dim>& grad, SymmetricTensor<dim>& strain) const { + strain = 0; + for (int i=0; i<dim ; ++i) { + strain(i,i) +=grad[i][i]; + + for (int k=0;k<dim;++k) + strain(i,i) += 0.5*grad[k][i]*grad[k][i]; + + for (int j=i+1; j<dim; ++j) { + strain(i,j) += 0.5*(grad[i][j] + grad[j][i]); + for (int k=0;k<dim;++k) + strain(i,j) += 0.5*grad[k][i]*grad[k][j]; + } + } + } + + /** \brief Compute the symmetric product of two matrices, i.e. + * 0.5*(A^T * B + B^T * A ) + */ + SymmetricTensor<dim> symmetricProduct(const Dune::FieldMatrix<ctype, dim, dim>& a, const Dune::FieldMatrix<ctype, dim, dim>& b) const { + + SymmetricTensor<dim> result(0.0); + for (int i=0;i<dim; i++) + for (int j=i;j<dim;j++) + for (int k=0;k<dim;k++) + result(i,j)+= a[k][i]*b[k][j]+b[k][i]*a[k][j]; + result *= 0.5; + + return result; + } + +}; + + +#endif + diff --git a/dune/elasticity/materials/mooneyrivlinmaterial.hh b/dune/elasticity/materials/mooneyrivlinmaterial.hh new file mode 100644 index 0000000000000000000000000000000000000000..57d2a465fc9dfd2b2a5f5d6b71f20ccad1f7633e --- /dev/null +++ b/dune/elasticity/materials/mooneyrivlinmaterial.hh @@ -0,0 +1,246 @@ +#ifndef MOONEY_RIVLIN_MATERIAL +#define MOONEY_RIVLIN_MATERIAL + +#include <dune/fufem/quadraturerules/quadraturerulecache.hh> + +#include <dune/fufem/symmetrictensor.hh> +#include <dune/fufem/functions/virtualgridfunction.hh> +#include <dune/fufem/functions/basisgridfunction.hh> + +#include <dune/elasticity/assemblers/mooneyrivlinfunctionalassembler.hh> +#include <dune/elasticity/assemblers/mooneyrivlinoperatorassembler.hh> + +#include <dune/elasticity/materials/material.hh> +#warning Mooney-Rivlin Might not work properly yet + +/** \brief Class representing a hyperelastic Mooney-Rivlin material. + * + * \tparam Basis Global basis that is used for the spatial discretization. + * (This is not nice but I need a LocalFiniteElement for the local Hessian assembler :-( ) + * + * \f[ + * W(u)= a tr(E(u)) + b tr(E(u))^2 + c ||E(u)||^2 + gamma(J) + * \f] + * + * where + * - \f$E\f$: the nonlinear strain tensor + * - \f$tr \f$: the trace operator + * - \f$J\f$ the determinant of the deformation gradient + * - \f$a\f$,\f$b\f$,\f$c$\f material parameters + * - \f$\gamma$\f A 'penalty' function which enforces orientation preservation + * + * with + * \f$\gamma(J)$:= dJ^2 + e J^-k, k>=2\f + * \f$k\f$ controlls orientation preservation (k \approx \floor(1/(1-2nu) -1)) + */ +template <class Basis> +class MooneyRivlinMaterial : public Material<Basis> +{ +public: + typedef Material<Basis> Base; + typedef typename Basis::GridView::Grid GridType; + using typename Base::GlobalBasis; + using typename Base::Lfe; + using typename Base::LocalLinearization; + using typename Base::LocalHessian; + using typename Base::VectorType; + + typedef MooneyRivlinFunctionalAssembler<GridType,Lfe> MonRivLinearization; + typedef MooneyRivlinOperatorAssembler<GridType, Lfe, Lfe> MonRivHessian; + +private: + typedef typename GridType::ctype ctype; + + static const int dim = GridType::dimension; + static const int dimworld = GridType::dimensionworld; + + typedef typename GridType::template Codim<0>::Geometry::LocalCoordinate LocalCoordinate; + typedef typename GridType::template Codim<0>::LeafIterator ElementIterator; + +public: + MooneyRivlinMaterial(int k=3) : + E_(100), nu_(0.3), k_(k) + { + setupCoefficients(); + } + + template <BasisT> + MooneyRivlinMaterial(BasisT&& basis, ctype E, ctype nu, int k=3) : + Base(std::forward<BasisT>(basis)), E_(E), nu_(nu), k_(k) + { + + setupCoefficients(); + + localLinearization_ = Dune::shared_ptr<MonRivLinearization>(new MonRivLinearization(a_, b_,c_ ,d_ ,e_,k_)); + localHessian_ = Dune::shared_ptr<MonRivHessian>(new MonRivHessian(a_ , b_, c_, d_, e_,k_)); + } + + template <BasisT> + void setup(BasisT&& basis, ctype E, ctype nu) + { + E_ = E; nu_ = nu; + + setupCoefficients(); + + if (localLinearization_) + localLinearization_.reset(); + if (localHessian_) + localHessian_.reset(); + + localLinearization_ = std::shared_ptr<MonRivLinearization>(new MonRivLinearization(a_,b_,c_,d_,e_,k_)); + localHessian_ = std::shared_ptr<MonRivHessian>(new MonRivHessian(a_,b_,c_,d_,e_,k_)); + + this->setBasis(std::forward<BasisT>(basis)); + } + + void getMaterialParameters(ctype& E, ctype& nu) { + E = E_; nu = nu_; + } + + //! Evaluate the strain energy + ctype energy(const VectorType& coeff) + { + // make grid function + BasisGridFunction<Basis,VectorType> configuration(*this->basis_,coeff); + + ctype energy=0; + const GridType& grid = configuration.grid(); + + ElementIterator eIt = grid.template leafbegin<0>(); + ElementIterator eItEnd = grid.template leafend<0>(); + + for (;eIt != eItEnd; ++eIt) { + + // TODO Get proper quadrature rule + // get quadrature rule + const int order = (eIt->type().isSimplex()) ? 5 : 5*dim; + + const Dune::template QuadratureRule<ctype, dim>& quad = QuadratureRuleCache<ctype, dim>::rule(eIt->type(),order,0); + + // loop over quadrature points + for (size_t pt=0; pt < quad.size(); ++pt) { + + // get quadrature point + const LocalCoordinate& quadPos = quad[pt].position(); + + // get integration factor + const ctype integrationElement = eIt->geometry().integrationElement(quadPos); + + // evaluate displacement gradient at the quadrature point + typename BasisGridFunction<Basis,VectorType>::DerivativeType localConfGrad; + + if (configuration.isDefinedOn(*eIt)) + configuration.evaluateDerivativeLocal(*eIt, quadPos, localConfGrad); + else + configuration.evaluateDerivative(eIt->geometry().global(quadPos),localConfGrad); + + SymmetricTensor<dim> strain; + computeStrain(localConfGrad,strain); + + // the trace + ctype trE(0); + for (int i=0; i<dim; i++) + trE += strain(i,i); + + // make deformation gradient out of the discplacement + for (int i=0;i<dim;i++) + localConfGrad[i][i] += 1; + + // evaluate the derminante of the deformation gradient + const ctype J = localConfGrad.determinant(); + + ctype z = quad[pt].weight()*integrationElement; + + // W(u)= a tr(E(u)) + b tr(E(u))^2 + c ||E(u)||^2 + gamma(J) + energy += z*(a_*trE + b_*trE*trE + c_*(strain*strain) + d_*J*J + e_*std::pow(J,-k_)); + } + } + + return energy; + } + + //! Return the local assembler of the first derivative of the strain energy + LocalLinearization& firstDerivative() {return *localLinearization_;} + + //! Return the local assembler of the second derivative of the strain energy + LocalHessian& secondDerivative() {return *localHessian_;} + +private: + + //! Compute coefficients s.t. polyconvexity holds + void setupCoefficients() { + + ctype lambda = E_*nu_ / ((1+nu_)*(1-2*nu_)); + ctype mu = E_ / (2*(1+nu_)); + + // Choose coefficients in such a way that we have polyconvexity + // First/Second derivative of the compressible function part of gamma (=-kJ^(-k-1)) at 1.0 + ctype ld1 = -k_; + ctype ld2 = k_*(k_+1); + if (ld1 >=0 || ld2 <= 0) + std::cout<<"Coerciveness failed\n"; + + // Check if lame constants admit coerciveness + ctype rho= -ld1/(ld2-ld1); + + if( ( (rho < 0.5 && lambda < (1.0/rho-2.0)*mu) || lambda <= 0 || mu <= 0 )) + std::cout<<"Coerciveness failed\n"; + + //const ctype somePositiveConstant = - mu_ + rho*(lambda_+2.*mu_); + //if(somePositiveConstant <= 0) + + e_ = (lambda+2.0*mu)/(ld2-ld1); + if(e_ <= 0 ) + std::cout<<"Coerciveness failed\n"; + + // parameters a, and b are used if expressed in terms of the Green-StVenant strain tensor + // the choice of b and d is admissible but heuristic -> @TODO justified choice + d_ = (0.5*rho-0.25)*mu+0.25*rho*lambda; + if(d_ > 0.25*mu) + d_ = (rho-0.75)*mu+0.5*rho*lambda; + + ctype b_ = -mu + rho*(lambda+2.*mu)-2.*d_; + ctype c_ = -b_; + ctype a_ = b_ + mu; + + // last check if I didn't miss a condition + ctype alpha = 0.5*(mu-b_); + if(alpha <= 0 || b_ <= 0 || d_ <= 0) + std::cout<<"Coerciveness failed\n"; + } + + //! First derivative of the strain energy + std::shared_ptr<MonRivLinearization> localLinearization_; + + //! Second derivative of the strain energy + std::shared_ptr<MonRivHessian> localHessian_; + + //! Elasticity modulus + ctype E_; + //! Shear modulus + ctype nu_; + //! Exponent of the compressibility function (>= 2) + int k_; + //! Material parameters + ctype a_; ctype b_; ctype c_; ctype d_; ctype e_; + + //! Compute nonlinear strain tensor from the deformation gradient. + void computeStrain(const Dune::FieldMatrix<ctype, dim, dim>& grad, SymmetricTensor<dim>& strain) const { + strain = 0; + for (int i=0; i<dim ; ++i) { + strain(i,i) +=grad[i][i]; + + for (int k=0;k<dim;++k) + strain(i,i) += 0.5*grad[k][i]*grad[k][i]; + + for (int j=i+1; j<dim; ++j) { + strain(i,j) += 0.5*(grad[i][j] + grad[j][i]); + for (int k=0;k<dim;++k) + strain(i,j) += 0.5*grad[k][i]*grad[k][j]; + } + } + } + +}; + +#endif