From 4815767308d9508fa89cbdf0effeca88e9428bfb Mon Sep 17 00:00:00 2001 From: Oliver Sander <sander@igpm.rwth-aachen.de> Date: Mon, 13 Jun 2011 11:32:29 +0000 Subject: [PATCH] complete the implementation of the energy. Not seriously tested, but at least it doesn't crash [[Imported from SVN: r7423]] --- dune/gfe/cosseratenergystiffness.hh | 203 +++++++++++++++++++++++++++- 1 file changed, 196 insertions(+), 7 deletions(-) diff --git a/dune/gfe/cosseratenergystiffness.hh b/dune/gfe/cosseratenergystiffness.hh index 93e7be3a..6496e267 100644 --- a/dune/gfe/cosseratenergystiffness.hh +++ b/dune/gfe/cosseratenergystiffness.hh @@ -21,16 +21,142 @@ class CosseratEnergyLocalStiffness // some other sizes enum {gridDim=GridView::dimension}; + + + /** \brief Compute the symmetric part of a matrix A, i.e. \f$ \frac 12 (A + A^T) \f$ */ + static Dune::FieldMatrix<double,dim,dim> sym(const Dune::FieldMatrix<double,dim,dim>& A) + { + Dune::FieldMatrix<double,dim,dim> result; + for (int i=0; i<dim; i++) + for (int j=0; j<dim; j++) + result[i][j] = 0.5 * (A[i][j] + A[j][i]); + return result; + } + + /** \brief Compute the antisymmetric part of a matrix A, i.e. \f$ \frac 12 (A - A^T) \f$ */ + static Dune::FieldMatrix<double,dim,dim> skew(const Dune::FieldMatrix<double,dim,dim>& A) + { + Dune::FieldMatrix<double,dim,dim> result; + for (int i=0; i<dim; i++) + for (int j=0; j<dim; j++) + result[i][j] = 0.5 * (A[i][j] - A[j][i]); + return result; + } + + /** \brief Return the square of the trace of a matrix */ + static double traceSquared(const Dune::FieldMatrix<double,dim,dim>& A) + { + double trace = 0; + for (int i=0; i<dim; i++) + trace += A[i][i]; + return trace*trace; + } + + /** \brief Compute the (row-wise) curl of a matrix R \f$ + \param DR The partial derivatives of the matrix R + */ + static Dune::FieldMatrix<double,dim,dim> curl(const Tensor3<double,dim,dim,dim>& DR) + { + Dune::FieldMatrix<double,dim,dim> result; + + for (int i=0; i<dim; i++) { + result[i][0] = DR[i][2][1] - DR[i][1][2]; + result[i][1] = DR[i][0][2] - DR[i][2][0]; + result[i][2] = DR[i][1][0] - DR[i][0][1]; + } + + return result; + } + public: - //! Dimension of a tangent space - enum { blocksize = TargetSpace::TangentVector::size }; + /** \brief Constructor with a set of material parameters + * \param parameters The material parameters + */ + CosseratEnergyLocalStiffness(const Dune::ParameterTree& parameters) + { + // The shell thickness + thickness_ = parameters.template get<double>("thickness"); + + // Lame constants + mu_ = parameters.template get<double>("mu"); + lambda_ = parameters.template get<double>("lambda"); + + // Cosserat couple modulus, preferably 0 + mu_c_ = parameters.template get<double>("mu_c"); + + // Length scale parameter + L_c_ = parameters.template get<double>("L_c"); + + // Curvature exponent + q_ = parameters.template get<double>("q"); + } /** \brief Assemble the energy for a single element */ RT energy (const Entity& e, const std::vector<TargetSpace>& localSolution) const; + + RT quadraticMembraneEnergy(const Dune::FieldMatrix<double,3,3>& U) const + { + Dune::FieldMatrix<double,3,3> UMinus1 = U; + for (int i=0; i<dim; i++) + UMinus1[i][i] -= 1; + + return mu_ * sym(UMinus1).frobenius_norm2() + + mu_c_ * skew(UMinus1).frobenius_norm2() + + (mu_*lambda_)/(2*mu_ + lambda_) * traceSquared(sym(UMinus1)); + } + + RT curvatureEnergy(const Tensor3<double,3,3,3>& DR) const + { + /** \todo The factor 12 appears here and later, we everything is summed up. Is that correct? */ + return mu_ * thickness_/12.0 * std::pow(L_c_ * curl(DR).frobenius_norm(),q_); + } + + RT bendingEnergy(const Dune::FieldMatrix<double,dim,dim>& R, const Tensor3<double,3,3,3>& DR) const + { + // The derivative of the third director + /** \brief There is no real need to have DR3 as a separate object */ + Dune::FieldMatrix<double,3,3> DR3; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + DR3[i][j] = DR[i][2][j]; + + // left-multiply with R^T + Dune::FieldMatrix<double,3,3> RT_DR3; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) { + RT_DR3[i][j] = 0; + for (int k=0; k<3; k++) + RT_DR3[i][j] += R[k][i] * DR3[k][j]; + } + + + + /** \todo The factor 12 appears here and later, we everything is summed up. Is that correct? */ + return std::pow(thickness_,3)/12.0 * (mu_ * sym(RT_DR3).frobenius_norm2() + + mu_c_ * skew(RT_DR3).frobenius_norm2() + /** \brief Is this really traceSquared? */ + + mu_*lambda_/(2*mu_+lambda_) * traceSquared(RT_DR3)); + } + + /** \brief The shell thickness */ + double thickness_; + + /** \brief Lame constants */ + double mu_, lambda_; + /** \brief Cosserat couple modulus, preferably 0 */ + double mu_c_; + + /** \brief Length scale parameter */ + double L_c_; + + /** \brief Curvature exponent */ + double q_; + + }; template <class GridView, int dim> @@ -59,6 +185,9 @@ energy(const Entity& element, const Dune::FieldMatrix<double,gridDim,gridDim>& jacobianInverseTransposed = element.geometry().jacobianInverseTransposed(quadPos); double weight = quad[pt].weight() * integrationElement; + + // The value of the local function + RigidBodyMotion<dim> value = localGeodesicFEFunction.evaluate(quadPos); // The derivative of the local function defined on the reference element Dune::FieldMatrix<double, TargetSpace::EmbeddedTangentVector::size, gridDim> referenceDerivative = localGeodesicFEFunction.evaluateDerivative(quadPos); @@ -68,15 +197,75 @@ energy(const Entity& element, for (size_t comp=0; comp<referenceDerivative.N(); comp++) jacobianInverseTransposed.umv(referenceDerivative[comp], derivative[comp]); - + + ///////////////////////////////////////////////////////// + // compute U, the Cosserat strain + ///////////////////////////////////////////////////////// + dune_static_assert(dim==(gridDim+1), "Grid must have codim 1"); + + // + Dune::FieldMatrix<double,dim,dim> R; + value.q.matrix(R); + + /// \f$ \hat{F} = (\nabla m | \overline{R}_3) \f$ + Dune::FieldMatrix<double,dim,dim> F; + for (int i=0; i<dim; i++) + for (int j=0; j<gridDim; j++) + F[i][j] = derivative[i][j]; + + for (int i=0; i<dim; i++) + F[i][dim-1] = R[i][dim-1]; + + // U = R^T F + Dune::FieldMatrix<double,dim,dim> U; + for (int i=0; i<dim; i++) + for (int j=0; j<dim; j++) { + U[i][j] = 0; + for (int k=0; k<dim; k++) + U[i][j] += R[k][i] * F[k][j]; + } + + ////////////////////////////////////////////////////////// + // Compute the derivative of the rotation + // Note: we need it in matrix coordinates + ////////////////////////////////////////////////////////// + + // derivative of the rotation part in quaternion coordinates + Dune::FieldMatrix<double,4,gridDim> DR_quat; + for (int i=0; i<4; i++) + for (int j=0; j<gridDim; j++) + DR_quat[i][j] = derivative[i+3][j]; + + // transform to matrix coordinates: + // first get the derivative of the embedding of H_1 into R^{3\times3} + Dune::array<Dune::FieldMatrix<double,3 , 4>, 3> dd_dq; + value.q.getFirstDerivativesOfDirectors(dd_dq); + + // + Tensor3<double,3,3,3> DR; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<gridDim; k++) { + DR[i][j][k] = 0; + for (int l=0; l<4; l++) + DR[i][j][k] += dd_dq[i][j][l] * DR_quat[l][k]; + } + + // If the grid is only 2d we fill up the partial derivatives wrt z by zeros + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + DR[i][j][2] = 0; + + + // Add the local energy density - // The Frobenius norm is the correct norm here if the metric of TargetSpace is the identity. - // (And if the metric of the domain space is the identity, which it always is here.) - energy += weight * derivative.frobenius_norm2(); + energy += weight * thickness_ * quadraticMembraneEnergy(U); + energy += weight * thickness_ * curvatureEnergy(DR); + energy += weight * thickness_ * thickness_ * thickness_ / 12.0 * bendingEnergy(R,DR); } - return 0.5 * energy; + return energy; } #endif -- GitLab