Newer
Older
#ifndef COSSERAT_ENERGY_LOCAL_STIFFNESS_HH
#define COSSERAT_ENERGY_LOCAL_STIFFNESS_HH
#include <dune/common/fmatrix.hh>
#include <dune/grid/common/quadraturerules.hh>
#include "localgeodesicfestiffness.hh"
#include "localgeodesicfefunction.hh"

Oliver Sander
committed
#include <dune/gfe/rigidbodymotion.hh>

Oliver Sander
committed
template<class GridView, int dim>
class CosseratEnergyLocalStiffness

Oliver Sander
committed
: public LocalGeodesicFEStiffness<GridView,RigidBodyMotion<dim> >
{
// grid types
typedef typename GridView::Grid::ctype DT;

Oliver Sander
committed
typedef RigidBodyMotion<dim> TargetSpace;
typedef typename TargetSpace::ctype RT;
typedef typename GridView::template Codim<0>::Entity Entity;
// some other sizes
enum {gridDim=GridView::dimension};

Oliver Sander
committed
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/** \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;
}

Oliver Sander
committed
/** \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 Dune::array<TargetSpace, gridDim+1>& localSolution) const;

Oliver Sander
committed
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
{
return mu_ * std::pow(L_c_ * curl(DR).frobenius_norm(),q_);

Oliver Sander
committed
}
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];
}
return mu_ * sym(RT_DR3).frobenius_norm2()
+ mu_c_ * skew(RT_DR3).frobenius_norm2()
/** \todo Is this sym correct? It is in the paper, but not in the notes */
+ mu_*lambda_/(2*mu_+lambda_) * traceSquared(sym(RT_DR3));

Oliver Sander
committed
}
/** \brief The shell thickness */
double thickness_;
/** \brief Lame constants */
double mu_, lambda_;

Oliver Sander
committed
/** \brief Cosserat couple modulus, preferably 0 */
double mu_c_;
/** \brief Length scale parameter */
double L_c_;
/** \brief Curvature exponent */
double q_;

Oliver Sander
committed
template <class GridView, int dim>
typename CosseratEnergyLocalStiffness<GridView, dim>::RT CosseratEnergyLocalStiffness<GridView, dim>::
energy(const Entity& element,
const Dune::array<RigidBodyMotion<dim>, gridDim+1>& localSolution) const
{
RT energy = 0;
assert(element.type().isSimplex());
LocalGeodesicFEFunction<gridDim, double, TargetSpace> localGeodesicFEFunction(localSolution);
int quadOrder = 1;//gridDim;
const Dune::QuadratureRule<double, gridDim>& quad
= Dune::QuadratureRules<double, gridDim>::rule(element.type(), quadOrder);
for (size_t pt=0; pt<quad.size(); pt++) {
// Local position of the quadrature point
const Dune::FieldVector<double,gridDim>& quadPos = quad[pt].position();
const double integrationElement = element.geometry().integrationElement(quadPos);
const Dune::FieldMatrix<double,gridDim,gridDim>& jacobianInverseTransposed = element.geometry().jacobianInverseTransposed(quadPos);
double weight = quad[pt].weight() * integrationElement;

Oliver Sander
committed
// 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);
// The derivative of the function defined on the actual element
Dune::FieldMatrix<double, TargetSpace::EmbeddedTangentVector::size, gridDim> derivative(0);
for (size_t comp=0; comp<referenceDerivative.N(); comp++)
jacobianInverseTransposed.umv(referenceDerivative[comp], derivative[comp]);

Oliver Sander
committed
/////////////////////////////////////////////////////////
// compute U, the Cosserat strain
/////////////////////////////////////////////////////////
dune_static_assert(dim>=gridDim, "Codim of the grid must be nonnegative");

Oliver Sander
committed
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
//
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}

Oliver Sander
committed
value.q.getFirstDerivativesOfDirectors(dd_dq);
//

Oliver Sander
committed
for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
for (int k=0; k<gridDim; k++) {
for (int l=0; l<4; l++)
DR[i][j][k] += dd_dq[i][j][l] * DR_quat[l][k];
}
// Add the local energy density

Oliver Sander
committed
if (gridDim==2) {
energy += weight * thickness_ * quadraticMembraneEnergy(U);
energy += weight * thickness_ * curvatureEnergy(DR);
energy += weight * std::pow(thickness_,3) / 12.0 * bendingEnergy(R,DR);

Oliver Sander
committed
} else if (gridDim==3) {
energy += weight * quadraticMembraneEnergy(U);
energy += weight * curvatureEnergy(DR);
} else
DUNE_THROW(Dune::NotImplemented, "CosseratEnergyStiffness for 1d grids");

Oliver Sander
committed
return energy;