oomph::ConstitutiveLaw Class Referenceabstract

#include <constitutive_laws.h>

+ Inheritance diagram for oomph::ConstitutiveLaw:

Public Member Functions

 ConstitutiveLaw ()
 Empty constructor. More...
 
virtual ~ConstitutiveLaw ()
 Empty virtual destructor. More...
 
virtual void calculate_second_piola_kirchhoff_stress (const DenseMatrix< double > &g, const DenseMatrix< double > &G, DenseMatrix< double > &sigma)=0
 
virtual void calculate_d_second_piola_kirchhoff_stress_dG (const DenseMatrix< double > &g, const DenseMatrix< double > &G, const DenseMatrix< double > &sigma, RankFourTensor< double > &d_sigma_dG, const bool &symmetrize_tensor=true)
 
virtual void calculate_second_piola_kirchhoff_stress (const DenseMatrix< double > &g, const DenseMatrix< double > &G, DenseMatrix< double > &sigma_dev, DenseMatrix< double > &G_contra, double &Gdet)
 
virtual void calculate_d_second_piola_kirchhoff_stress_dG (const DenseMatrix< double > &g, const DenseMatrix< double > &G, const DenseMatrix< double > &sigma, const double &detG, const double &interpolated_solid_p, RankFourTensor< double > &d_sigma_dG, DenseMatrix< double > &d_detG_dG, const bool &symmetrize_tensor=true)
 
virtual void calculate_second_piola_kirchhoff_stress (const DenseMatrix< double > &g, const DenseMatrix< double > &G, DenseMatrix< double > &sigma_dev, DenseMatrix< double > &Gcontra, double &gen_dil, double &inv_kappa)
 
virtual void calculate_d_second_piola_kirchhoff_stress_dG (const DenseMatrix< double > &g, const DenseMatrix< double > &G, const DenseMatrix< double > &sigma, const double &gen_dil, const double &inv_kappa, const double &interpolated_solid_p, RankFourTensor< double > &d_sigma_dG, DenseMatrix< double > &d_gen_dil_dG, const bool &symmetrize_tensor=true)
 
virtual bool requires_incompressibility_constraint ()=0
 

Protected Member Functions

bool is_matrix_square (const DenseMatrix< double > &M)
 Test whether a matrix is square. More...
 
bool are_matrices_of_equal_dimensions (const DenseMatrix< double > &M1, const DenseMatrix< double > &M2)
 Test whether two matrices are of equal dimensions. More...
 
void error_checking_in_input (const DenseMatrix< double > &g, const DenseMatrix< double > &G, DenseMatrix< double > &sigma)
 
double calculate_contravariant (const DenseMatrix< double > &Gcov, DenseMatrix< double > &Gcontra)
 The function to calculate the contravariant tensor from a covariant one. More...
 
void calculate_d_contravariant_dG (const DenseMatrix< double > &Gcov, RankFourTensor< double > &dGcontra_dG, DenseMatrix< double > &d_detG_dG)
 

Detailed Description

///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// A class for constitutive laws for elements that solve the equations of solid mechanics based upon the principle of virtual displacements. In that formulation, the information required from a constitutive law is the (2nd Piola-Kirchhoff) stress tensor \( \sigma^{ij} \) as a function of the (Green) strain \( \gamma^{ij} \):

\[ \sigma^{ij} = \sigma^{ij}(\gamma_{ij}). \]

The Green strain is defined as

\[ \gamma_{ij} = \frac{1}{2} (G_{ij} - g_{ij}), \ \ \ \ \ \ \ \ \ \ \ (1) \]

where \(G_{ij} \) and \( g_{ij}\) are the metric tensors in the deformed and undeformed (stress-free) configurations, respectively. A specific ConstitutiveLaw needs to be implement the pure virtual function

virtual void calculate_second_piola_kirchhoff_stress(const DenseMatrix< double > &g, const DenseMatrix< double > &G, DenseMatrix< double > &sigma)=0

Equation (1) shows that the strain may be calculated from the undeformed and deformed metric tensors. Frequently, these tensors are also required in the constitutive law itself. To avoid unnecessary re-computation of these quantities, we pass the deformed and undeformed metric tensor to calculate_second_piola_kirchhoff_stress(...) rather than the strain tensor itself.

The functional form of the constitutive equation is different for compressible/incompressible/near-incompressible behaviour and we provide interfaces that are appropriate for all of these cases.

  1. Compressible Behaviour:
    If the material is compressible, the stress can be computed from the deformed and undeformed metric tensors,

    \[ \sigma^{ij} = \sigma^{ij}(\gamma_{ij}) = \sigma^{ij}\bigg( \frac{1}{2} (G_{ij} - g_{ij})\bigg), \]

    using the interface

    // 2nd Piola Kirchhoff stress tensor
    // Metric tensor in the undeformed (stress-free) configuration
    // Metric tensor in the deformed configuration
    // Compute stress from the two metric tensors:
    JacobiRotation< float > G
    Definition: Jacobi_makeGivens.cpp:2
    #define DIM
    Definition: linearised_navier_stokes_elements.h:44
    int sigma
    Definition: calibrate.py:179




  2. Incompressible Behaviour:
    If the material is incompressible, its deformation is constrained by the condition that

    \[ \det G_{ij} - \det g_{ij}= 0 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (2) \]

    which ensures that the volume of infinitesimal material elements remains constant during the deformation. This condition is typically enforced by a Lagrange multiplier which plays the role of a pressure. In such cases, the stress tensor has form

    \[ \sigma^{ij} = -p G^{ij} + \overline{\sigma}^{ij}\big(\gamma_{kl}\big), \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (3) \]

    where only the deviatoric part of the stress tensor, \( \overline{\sigma}^{ij}, \) depends directly on the strain. The pressure \( p \) needs to be determined independently from (2). Given the deformed and undeformed metric tensors, the computation of the stress tensor \( \sigma^{ij} \) for an incompressible material therefore requires the computation of the following quantities:

    • The deviatoric stress \( \overline{\sigma}^{ij} \)
    • The contravariant deformed metric tensor \( G^{ij} \)
    • The determinant of the deformed metric tensors, \( \det G_{ij}, \) which is required in equation (2) whose solution determines the pressure.


These quantities can be obtained from the following interface

// Deviatoric part of the 2nd Piola Kirchhoff stress tensor
// Metric tensor in the undeformed (stress-free) configuration
// Metric tensor in the deformed configuration
// Determinant of the deformed metric tensor
double Gdet;
// Contravariant deformed metric tensor
// Compute stress from the two metric tensors:
calculate_second_piola_kirchhoff_stress(g,G,sigma_dev,G_contra,Gdet);




  1. Nearly Incompressible Behaviour:
    If the material is nearly incompressible, it is advantageous to split the stress into its deviatoric and hydrostatic parts by writing the constitutive law in the form

    \[ \sigma^{ij} = -p G^{ij} + \overline{\sigma}^{ij}\big(\gamma_{kl}\big), \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (3) \]

    where the deviatoric part of the stress tensor, \( \overline{\sigma}^{ij}, \) depends on the strain. This form of the constitutive law is identical to that of the incompressible case and it involves a pressure \( p \) which needs to be determined from an additional equation. In the incompressible case, this equation was given by the incompressibility constraint (2). Here, we need to augment the constitutive law (3) by a separate equation for the pressure. Generally this takes the form

    \[ p = - \kappa \ d \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (4) \]

    where \( \kappa \) is the "bulk modulus", a material property that needs to be specified by the constitutive law. \( d \) is the (generalised) dilatation, i.e. the relative change in the volume of an infinitesimal material element (or some suitable generalised quantitiy that is related to it). As the material approaches incompressibility, \( \kappa \to \infty\), so that infinitely large pressures would be required to achieve any change in volume. To facilitate the implementation of (4) as the equation for the pressure, we re-write it in the form

    \[ p \ \frac{1}{\kappa} + d\big(g_{ij},G_{ij}\big) = 0 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (5) \]

    which only involves quantities that remain finite as we approach true incompressibility.
    Given the deformed and undeformed metric tensors, the computation of the stress tensor \( \sigma^{ij} \) for a nearly incompressible material therefore requires the computation of the following quantities:

    • The deviatoric stress \( \overline{\sigma}^{ij} \)
    • The contravariant deformed metric tensor \( G^{ij} \)
    • The generalised dilatation \( d \)
    • The inverse of the bulk modulus \( \kappa \)


These quantities can be obtained from the following interface

// Deviatoric part of the 2nd Piola Kirchhoff stress tensor
// Metric tensor in the undeformed (stress-free) configuration
// Metric tensor in the deformed configuration
// Contravariant deformed metric tensor
// Inverse of the bulk modulus
double inv_kappa;
// Generalised dilatation
double gen_dil;
// Compute stress from the two metric tensors:
calculate_second_piola_kirchhoff_stress(g,G,sigma_dev,G_contra,inv_kappa,gen_dil);

Constructor & Destructor Documentation

◆ ConstitutiveLaw()

oomph::ConstitutiveLaw::ConstitutiveLaw ( )
inline

Empty constructor.

501 {}

◆ ~ConstitutiveLaw()

virtual oomph::ConstitutiveLaw::~ConstitutiveLaw ( )
inlinevirtual

Empty virtual destructor.

505 {}

Member Function Documentation

◆ are_matrices_of_equal_dimensions()

bool oomph::ConstitutiveLaw::are_matrices_of_equal_dimensions ( const DenseMatrix< double > &  M1,
const DenseMatrix< double > &  M2 
)
protected

Test whether two matrices are of equal dimensions.

This function is used to check whether matrices are of equal dimension.

54  {
55  // If the numbers of rows and columns are not the same, then the
56  // matrices are not of equal dimension
57  if ((M1.nrow() != M2.nrow()) || (M1.ncol() != M2.ncol()))
58  {
59  return false;
60  }
61  else
62  {
63  return true;
64  }
65  }
M1<< 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12;Map< MatrixXf > M2(M1.data(), 6, 2)
MatrixXf M1
Definition: Tutorial_SlicingCol.cpp:1

References M1, and M2().

Referenced by calculate_contravariant(), calculate_d_second_piola_kirchhoff_stress_dG(), and error_checking_in_input().

◆ calculate_contravariant()

double oomph::ConstitutiveLaw::calculate_contravariant ( const DenseMatrix< double > &  Gcov,
DenseMatrix< double > &  Gcontra 
)
protected

The function to calculate the contravariant tensor from a covariant one.

Calculate a contravariant tensor from a covariant tensor, and return the determinant of the covariant tensor.

Three dimensions

115  {
116  // Initial error checking
117 #ifdef PARANOID
118  // Test that the matrices are of the same dimension
119  if (!are_matrices_of_equal_dimensions(Gdown, Gup))
120  {
121  throw OomphLibError("Matrices passed to calculate_contravariant() are "
122  "not of equal dimension",
125  }
126 #endif
127 
128  // Find the dimension of the matrix
129  unsigned dim = Gdown.ncol();
130 
131  // If it's not square, I don't know what to do (yet)
132 #ifdef PARANOID
133  if (!is_matrix_square(Gdown))
134  {
135  std::string error_message =
136  "Matrix passed to calculate_contravariant() is not square\n";
137  error_message += "non-square matrix inversion not implemented yet!\n";
138 
139  throw OomphLibError(
141  }
142 #endif
143 
144  // Define the determinant of the matrix
145  double det = 0.0;
146 
147  // Now the inversion depends upon the dimension of the matrix
148  switch (dim)
149  {
150  // Zero dimensions
151  case 0:
152  throw OomphLibError("Zero dimensional matrix",
155  break;
156 
157  // One dimension
158  case 1:
159  // The determinant is just the value of the only entry
160  det = Gdown(0, 0);
161  // The inverse is just the inverse of the value
162  Gup(0, 0) = 1.0 / Gdown(0, 0);
163  break;
164 
165 
166  // Two dimensions
167  case 2:
168  // Calculate the determinant
169  det = Gdown(0, 0) * Gdown(1, 1) - Gdown(0, 1) * Gdown(1, 0);
170  // Calculate entries of the contravariant tensor (inverse)
171  Gup(0, 0) = Gdown(1, 1) / det;
172  Gup(0, 1) = -Gdown(0, 1) / det;
173  Gup(1, 0) = -Gdown(1, 0) / det;
174  Gup(1, 1) = Gdown(0, 0) / det;
175  break;
176 
178  case 3:
179  // Calculate the determinant of the matrix
180  det = Gdown(0, 0) * Gdown(1, 1) * Gdown(2, 2) +
181  Gdown(0, 1) * Gdown(1, 2) * Gdown(2, 0) +
182  Gdown(0, 2) * Gdown(1, 0) * Gdown(2, 1) -
183  Gdown(0, 0) * Gdown(1, 2) * Gdown(2, 1) -
184  Gdown(0, 1) * Gdown(1, 0) * Gdown(2, 2) -
185  Gdown(0, 2) * Gdown(1, 1) * Gdown(2, 0);
186 
187  // Calculate entries of the inverse matrix
188  Gup(0, 0) =
189  (Gdown(1, 1) * Gdown(2, 2) - Gdown(1, 2) * Gdown(2, 1)) / det;
190  Gup(0, 1) =
191  -(Gdown(0, 1) * Gdown(2, 2) - Gdown(0, 2) * Gdown(2, 1)) / det;
192  Gup(0, 2) =
193  (Gdown(0, 1) * Gdown(1, 2) - Gdown(0, 2) * Gdown(1, 1)) / det;
194  Gup(1, 0) =
195  -(Gdown(1, 0) * Gdown(2, 2) - Gdown(1, 2) * Gdown(2, 0)) / det;
196  Gup(1, 1) =
197  (Gdown(0, 0) * Gdown(2, 2) - Gdown(0, 2) * Gdown(2, 0)) / det;
198  Gup(1, 2) =
199  -(Gdown(0, 0) * Gdown(1, 2) - Gdown(0, 2) * Gdown(1, 0)) / det;
200  Gup(2, 0) =
201  (Gdown(1, 0) * Gdown(2, 1) - Gdown(1, 1) * Gdown(2, 0)) / det;
202  Gup(2, 1) =
203  -(Gdown(0, 0) * Gdown(2, 1) - Gdown(0, 1) * Gdown(2, 0)) / det;
204  Gup(2, 2) =
205  (Gdown(0, 0) * Gdown(1, 1) - Gdown(0, 1) * Gdown(1, 0)) / det;
206  break;
207 
208  default:
209  throw OomphLibError("Dimension of matrix must be 0, 1, 2 or 3\n",
212  break;
213  }
214 
215  // Return the determinant of the matrix
216  return (det);
217  }
bool is_matrix_square(const DenseMatrix< double > &M)
Test whether a matrix is square.
Definition: constitutive_laws.cc:36
bool are_matrices_of_equal_dimensions(const DenseMatrix< double > &M1, const DenseMatrix< double > &M2)
Test whether two matrices are of equal dimensions.
Definition: constitutive_laws.cc:52
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86

References are_matrices_of_equal_dimensions(), is_matrix_square(), oomph::DenseMatrix< T >::ncol(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::Global_string_for_annotation::string().

Referenced by oomph::GeneralisedHookean::calculate_second_piola_kirchhoff_stress(), and oomph::IsotropicStrainEnergyFunctionConstitutiveLaw::calculate_second_piola_kirchhoff_stress().

◆ calculate_d_contravariant_dG()

void oomph::ConstitutiveLaw::calculate_d_contravariant_dG ( const DenseMatrix< double > &  Gdown,
RankFourTensor< double > &  d_Gup_dG,
DenseMatrix< double > &  d_detG_dG 
)
protected

Calculate the derivatives of the contravariant tensor and the derivatives of the determinant of the covariant tensor with respect to the components of the covariant tensor

The function to calculate the derivatives of the contravariant tensor and determinant of covariant tensor with respect to the components of the covariant tensor

Three dimensions

229  {
230  // Find the dimension of the matrix
231  const unsigned dim = Gdown.ncol();
232 
233  // If it's not square, I don't know what to do (yet)
234 #ifdef PARANOID
235  if (!is_matrix_square(Gdown))
236  {
237  std::string error_message =
238  "Matrix passed to calculate_contravariant() is not square\n";
239  error_message += "non-square matrix inversion not implemented yet!\n";
240 
241  throw OomphLibError(
243  }
244 #endif
245 
246  // Define the determinant of the matrix
247  double det = 0.0;
248 
249  // Now the inversion depends upon the dimension of the matrix
250  switch (dim)
251  {
252  // Zero dimensions
253  case 0:
254  throw OomphLibError("Zero dimensional matrix",
257  break;
258 
259  // One dimension
260  case 1:
261  // There is only one entry, so derivatives are easy
262  d_detG_dG(0, 0) = 1.0;
263  d_Gup_dG(0, 0, 0, 0) = -1.0 / (Gdown(0, 0) * Gdown(0, 0));
264  break;
265 
266 
267  // Two dimensions
268  case 2:
269  // Calculate the determinant
270  det = Gdown(0, 0) * Gdown(1, 1) - Gdown(0, 1) * Gdown(1, 0);
271 
272  // Calculate the derivatives of the determinant
273  d_detG_dG(0, 0) = Gdown(1, 1);
274  // Need to use symmetry here
275  d_detG_dG(0, 1) = d_detG_dG(1, 0) = -2.0 * Gdown(0, 1);
276  d_detG_dG(1, 1) = Gdown(0, 0);
277 
278  // Calculate the "upper triangular" derivatives of the contravariant
279  // tensor
280  {
281  const double det2 = det * det;
282  d_Gup_dG(0, 0, 0, 0) = -Gdown(1, 1) * d_detG_dG(0, 0) / det2;
283  d_Gup_dG(0, 0, 0, 1) = -Gdown(1, 1) * d_detG_dG(0, 1) / det2;
284  d_Gup_dG(0, 0, 1, 1) =
285  1.0 / det - Gdown(1, 1) * d_detG_dG(1, 1) / det2;
286 
287  d_Gup_dG(0, 1, 0, 0) = Gdown(0, 1) * d_detG_dG(0, 0) / det2;
288  d_Gup_dG(0, 1, 0, 1) =
289  -1.0 / det + Gdown(0, 1) * d_detG_dG(0, 1) / det2;
290  d_Gup_dG(0, 1, 1, 1) = Gdown(0, 1) * d_detG_dG(1, 1) / det2;
291 
292  d_Gup_dG(1, 1, 0, 0) =
293  1.0 / det - Gdown(0, 0) * d_detG_dG(0, 0) / det2;
294  d_Gup_dG(1, 1, 0, 1) = -Gdown(0, 0) * d_detG_dG(0, 1) / det2;
295  d_Gup_dG(1, 1, 1, 1) = -Gdown(0, 0) * d_detG_dG(1, 1) / det2;
296  }
297 
298  // Calculate entries of the contravariant tensor (inverse)
299  // Gup(0,0) = Gdown(1,1)/det;
300  // Gup(0,1) = -Gdown(0,1)/det;
301  // Gup(1,0) = -Gdown(1,0)/det;
302  // Gup(1,1) = Gdown(0,0)/det;
303  break;
304 
306  case 3:
307  // This is not yet implemented
308  throw OomphLibError(
309  "Analytic derivatives of metric tensors not yet implemented in 3D\n",
312 
313  // Calculate the determinant of the matrix
314  det = Gdown(0, 0) * Gdown(1, 1) * Gdown(2, 2) +
315  Gdown(0, 1) * Gdown(1, 2) * Gdown(2, 0) +
316  Gdown(0, 2) * Gdown(1, 0) * Gdown(2, 1) -
317  Gdown(0, 0) * Gdown(1, 2) * Gdown(2, 1) -
318  Gdown(0, 1) * Gdown(1, 0) * Gdown(2, 2) -
319  Gdown(0, 2) * Gdown(1, 1) * Gdown(2, 0);
320 
321  // Calculate entries of the inverse matrix
322  // Gup(0,0) = (Gdown(1,1)*Gdown(2,2) - Gdown(1,2)*Gdown(2,1))/det;
323  // Gup(0,1) = -(Gdown(0,1)*Gdown(2,2) - Gdown(0,2)*Gdown(2,1))/det;
324  // Gup(0,2) = (Gdown(0,1)*Gdown(1,2) - Gdown(0,2)*Gdown(1,1))/det;
325  // Gup(1,0) = -(Gdown(1,0)*Gdown(2,2) - Gdown(1,2)*Gdown(2,0))/det;
326  // Gup(1,1) = (Gdown(0,0)*Gdown(2,2) - Gdown(0,2)*Gdown(2,0))/det;
327  // Gup(1,2) = -(Gdown(0,0)*Gdown(1,2) - Gdown(0,2)*Gdown(1,0))/det;
328  // Gup(2,0) = (Gdown(1,0)*Gdown(2,1) - Gdown(1,1)*Gdown(2,0))/det;
329  // Gup(2,1) = -(Gdown(0,0)*Gdown(2,1) - Gdown(0,1)*Gdown(2,0))/det;
330  // Gup(2,2) = (Gdown(0,0)*Gdown(1,1) - Gdown(0,1)*Gdown(1,0))/det;
331  break;
332 
333  default:
334  throw OomphLibError("Dimension of matrix must be 0, 1, 2 or 3\n",
337  break;
338  }
339  }
unsigned long ncol() const
Return the number of columns of the matrix.
Definition: matrices.h:491

References is_matrix_square(), oomph::DenseMatrix< T >::ncol(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and oomph::Global_string_for_annotation::string().

◆ calculate_d_second_piola_kirchhoff_stress_dG() [1/3]

void oomph::ConstitutiveLaw::calculate_d_second_piola_kirchhoff_stress_dG ( const DenseMatrix< double > &  g,
const DenseMatrix< double > &  G,
const DenseMatrix< double > &  sigma,
const double detG,
const double interpolated_solid_p,
RankFourTensor< double > &  d_sigma_dG,
DenseMatrix< double > &  d_detG_dG,
const bool symmetrize_tensor = true 
)
virtual

Calculate the derivatives of the contravariant 2nd Piola Kirchhoff stress tensor \( \sigma^{ij}\). with respect to the deformed metric tensor. Also return the derivatives of the determinant of the deformed metric tensor with respect to the deformed metric tensor. This form is appropriate for truly-incompressible materials. The default implementation uses finite differences for the derivatives that depend on the constitutive law, but not for the derivatives of the determinant, which are generic. / If the boolean flag symmetrize_tensor is false, only the "upper triangular" entries of the tensor will be filled in. This is a useful efficiency when using the derivatives in Jacobian calculations.

Calculate the derivatives of the contravariant 2nd Piola Kirchhoff stress tensor \( \sigma^{ij}\). with respect to the deformed metric tensor. Also return the derivatives of the determinant of the deformed metric tensor with respect to the deformed metric tensor. This form is appropriate for truly-incompressible materials. The default implementation uses finite differences for the derivatives that depend on the constitutive law, but not for the derivatives of the determinant, which are generic.

462  {
463  // Initial error checking
464 #ifdef PARANOID
465  // Test that the matrices are of the same dimension
467  {
468  throw OomphLibError("Matrices passed are not of equal dimension",
471  }
472 #endif
473 
474  // Find the dimension of the matrix (assuming that it's square)
475  const unsigned dim = G.ncol();
476 
477  // FD step
478  const double eps_fd = GeneralisedElement::Default_fd_jacobian_step;
479 
480  // Advanced metric tensor etc.
481  DenseMatrix<double> G_pls(dim, dim);
482  DenseMatrix<double> sigma_dev_pls(dim, dim);
483  DenseMatrix<double> Gup_pls(dim, dim);
484  double detG_pls;
485 
486  // Copy across
487  for (unsigned i = 0; i < dim; i++)
488  {
489  for (unsigned j = 0; j < dim; j++)
490  {
491  G_pls(i, j) = G(i, j);
492  }
493  }
494 
495  // Do FD -- only w.r.t. to upper indices, exploiting symmetry.
496  // NOTE: We exploit the symmetry of the stress and metric tensors
497  // by incrementing G(i,j) and G(j,i) simultaenously and
498  // only fill in the "upper" triangles without copying things
499  // across the lower triangle. This is taken into account
500  // in the remaining code further below.
501  for (unsigned i = 0; i < dim; i++)
502  {
503  for (unsigned j = i; j < dim; j++)
504  {
505  G_pls(i, j) += eps_fd;
506  G_pls(j, i) = G_pls(i, j);
507 
508  // Get advanced stress
510  g, G_pls, sigma_dev_pls, Gup_pls, detG_pls);
511 
512 
513  // Derivative of determinant of deformed metric tensor
514  d_detG_dG(i, j) = (detG_pls - detG) / eps_fd;
515 
516  // Derivatives of deviatoric stress and "upper" deformed metric
517  // tensor
518  for (unsigned ii = 0; ii < dim; ii++)
519  {
520  for (unsigned jj = ii; jj < dim; jj++)
521  {
522  d_sigma_dG(ii, jj, i, j) =
523  (sigma_dev_pls(ii, jj) - interpolated_solid_p * Gup_pls(ii, jj) -
524  sigma(ii, jj)) /
525  eps_fd;
526  }
527  }
528 
529  // Reset
530  G_pls(i, j) = G(i, j);
531  G_pls(j, i) = G(j, i);
532  }
533  }
534 
535  // If we are symmetrising the tensor, do so
536  if (symmetrize_tensor)
537  {
538  for (unsigned i = 0; i < dim; i++)
539  {
540  for (unsigned j = 0; j < i; j++)
541  {
542  d_detG_dG(i, j) = d_detG_dG(j, i);
543 
544  for (unsigned ii = 0; ii < dim; ii++)
545  {
546  for (unsigned jj = 0; jj < ii; jj++)
547  {
548  d_sigma_dG(ii, jj, i, j) = d_sigma_dG(jj, ii, j, i);
549  }
550  }
551  }
552  }
553  }
554  }
int i
Definition: BiCGSTAB_step_by_step.cpp:9
static double Default_fd_jacobian_step
Definition: elements.h:1198
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2

References are_matrices_of_equal_dimensions(), calculate_second_piola_kirchhoff_stress(), oomph::GeneralisedElement::Default_fd_jacobian_step, G, i, j, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and calibrate::sigma.

◆ calculate_d_second_piola_kirchhoff_stress_dG() [2/3]

void oomph::ConstitutiveLaw::calculate_d_second_piola_kirchhoff_stress_dG ( const DenseMatrix< double > &  g,
const DenseMatrix< double > &  G,
const DenseMatrix< double > &  sigma,
const double gen_dil,
const double inv_kappa,
const double interpolated_solid_p,
RankFourTensor< double > &  d_sigma_dG,
DenseMatrix< double > &  d_gen_dil_dG,
const bool symmetrize_tensor = true 
)
virtual

Calculate the derivatives of the contravariant 2nd Piola Kirchoff stress tensor with respect to the deformed metric tensor. Also return the derivatives of the generalised dilatation, \( d, \) with respect to the deformed metric tensor. This form is appropriate for near-incompressible materials. The default implementation uses finite differences. If the boolean flag symmetrize_tensor is false, only the "upper triangular" entries of the tensor will be filled in. This is a useful efficiency when using the derivatives in Jacobian calculations.

Calculate the derivatives of the contravariant 2nd Piola Kirchoff stress tensor with respect to the deformed metric tensor. Also return the derivatives of the generalised dilatation, \( d, \) with respect to the deformed metric tensor. This form is appropriate for near-incompressible materials. The default implementation uses finite differences.

576  {
577  // Initial error checking
578 #ifdef PARANOID
579  // Test that the matrices are of the same dimension
581  {
582  throw OomphLibError("Matrices passed are not of equal dimension",
585  }
586 #endif
587 
588  // Find the dimension of the matrix (assuming that it's square)
589  const unsigned dim = G.ncol();
590 
591  // FD step
592  const double eps_fd = GeneralisedElement::Default_fd_jacobian_step;
593 
594  // Advanced metric tensor etc
595  DenseMatrix<double> G_pls(dim, dim);
596  DenseMatrix<double> sigma_dev_pls(dim, dim);
597  DenseMatrix<double> Gup_pls(dim, dim);
598  double gen_dil_pls;
599  double inv_kappa_pls;
600 
601  // Copy across
602  for (unsigned i = 0; i < dim; i++)
603  {
604  for (unsigned j = 0; j < dim; j++)
605  {
606  G_pls(i, j) = G(i, j);
607  }
608  }
609 
610  // Do FD -- only w.r.t. to upper indices, exploiting symmetry.
611  // NOTE: We exploit the symmetry of the stress and metric tensors
612  // by incrementing G(i,j) and G(j,i) simultaenously and
613  // only fill in the "upper" triangles without copying things
614  // across the lower triangle. This is taken into account
615  // in the remaining code further below.
616  for (unsigned i = 0; i < dim; i++)
617  {
618  for (unsigned j = i; j < dim; j++)
619  {
620  G_pls(i, j) += eps_fd;
621  G_pls(j, i) = G_pls(i, j);
622 
623  // Get advanced stress
625  g, G_pls, sigma_dev_pls, Gup_pls, gen_dil_pls, inv_kappa_pls);
626 
627  // Derivative of generalised dilatation
628  d_gen_dil_dG(i, j) = (gen_dil_pls - gen_dil) / eps_fd;
629 
630  // Derivatives of deviatoric stress and "upper" deformed metric
631  // tensor
632  for (unsigned ii = 0; ii < dim; ii++)
633  {
634  for (unsigned jj = ii; jj < dim; jj++)
635  {
636  d_sigma_dG(ii, jj, i, j) =
637  (sigma_dev_pls(ii, jj) - interpolated_solid_p * Gup_pls(ii, jj) -
638  sigma(ii, jj)) /
639  eps_fd;
640  }
641  }
642 
643  // Reset
644  G_pls(i, j) = G(i, j);
645  G_pls(j, i) = G(j, i);
646  }
647  }
648 
649  // If we are symmetrising the tensor, do so
650  if (symmetrize_tensor)
651  {
652  for (unsigned i = 0; i < dim; i++)
653  {
654  for (unsigned j = 0; j < i; j++)
655  {
656  d_gen_dil_dG(i, j) = d_gen_dil_dG(j, i);
657 
658  for (unsigned ii = 0; ii < dim; ii++)
659  {
660  for (unsigned jj = 0; jj < ii; jj++)
661  {
662  d_sigma_dG(ii, jj, i, j) = d_sigma_dG(jj, ii, j, i);
663  }
664  }
665  }
666  }
667  }
668  }

References are_matrices_of_equal_dimensions(), calculate_second_piola_kirchhoff_stress(), oomph::GeneralisedElement::Default_fd_jacobian_step, G, i, j, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and calibrate::sigma.

◆ calculate_d_second_piola_kirchhoff_stress_dG() [3/3]

void oomph::ConstitutiveLaw::calculate_d_second_piola_kirchhoff_stress_dG ( const DenseMatrix< double > &  g,
const DenseMatrix< double > &  G,
const DenseMatrix< double > &  sigma,
RankFourTensor< double > &  d_sigma_dG,
const bool symmetrize_tensor = true 
)
virtual

Calculate the derivatives of the contravariant 2nd Piola Kirchhoff stress tensor with respect to the deformed metric tensor. Arguments are the covariant undeformed and deformed metric tensor, the current value of the stress tensor and the rank four tensor in which to return the derivatives of the stress tensor The default implementation uses finite differences, but can be overloaded for constitutive laws in which an analytic formulation is possible. If the boolean flag symmetrize_tensor is false, only the "upper triangular" entries of the tensor will be filled in. This is a useful efficiency when using the derivatives in Jacobian calculations.

Calculate the derivatives of the contravariant 2nd Piola Kirchhoff stress tensor with respect to the deformed metric tensor. Arguments are the covariant undeformed and deformed metric tensor and the matrix in which to return the derivatives of the stress tensor The default implementation uses finite differences, but can be overloaded for constitutive laws in which an analytic formulation is possible.

358  {
359  // Initial error checking
360 #ifdef PARANOID
361  // Test that the matrices are of the same dimension
363  {
364  throw OomphLibError("Matrices passed are not of equal dimension",
367  }
368 #endif
369 
370  // Find the dimension of the matrix (assuming that it's square)
371  const unsigned dim = G.ncol();
372 
373  // Find the dimension
374  // FD step
375  const double eps_fd = GeneralisedElement::Default_fd_jacobian_step;
376 
377  // Advanced metric tensor
378  DenseMatrix<double> G_pls(dim, dim);
379  DenseMatrix<double> sigma_pls(dim, dim);
380 
381  // Copy across the original value
382  for (unsigned i = 0; i < dim; i++)
383  {
384  for (unsigned j = 0; j < dim; j++)
385  {
386  G_pls(i, j) = G(i, j);
387  }
388  }
389 
390  // Do FD -- only w.r.t. to upper indices, exploiting symmetry.
391  // NOTE: We exploit the symmetry of the stress and metric tensors
392  // by incrementing G(i,j) and G(j,i) simultaenously and
393  // only fill in the "upper" triangles without copying things
394  // across the lower triangle. This is taken into account
395  // in the solid mechanics codes.
396  for (unsigned i = 0; i < dim; i++)
397  {
398  for (unsigned j = i; j < dim; j++)
399  {
400  G_pls(i, j) += eps_fd;
401  G_pls(j, i) = G_pls(i, j);
402 
403  // Get advanced stress
404  this->calculate_second_piola_kirchhoff_stress(g, G_pls, sigma_pls);
405 
406  for (unsigned ii = 0; ii < dim; ii++)
407  {
408  for (unsigned jj = ii; jj < dim; jj++)
409  {
410  d_sigma_dG(ii, jj, i, j) =
411  (sigma_pls(ii, jj) - sigma(ii, jj)) / eps_fd;
412  }
413  }
414 
415  // Reset
416  G_pls(i, j) = G(i, j);
417  G_pls(j, i) = G(j, i);
418  }
419  }
420 
421  // If we are symmetrising the tensor, do so
422  if (symmetrize_tensor)
423  {
424  for (unsigned i = 0; i < dim; i++)
425  {
426  for (unsigned j = 0; j < i; j++)
427  {
428  for (unsigned ii = 0; ii < dim; ii++)
429  {
430  for (unsigned jj = 0; jj < ii; jj++)
431  {
432  d_sigma_dG(ii, jj, i, j) = d_sigma_dG(jj, ii, j, i);
433  }
434  }
435  }
436  }
437  }
438  }

References are_matrices_of_equal_dimensions(), calculate_second_piola_kirchhoff_stress(), oomph::GeneralisedElement::Default_fd_jacobian_step, G, i, j, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and calibrate::sigma.

Referenced by oomph::PVDEquationsWithPressure< DIM >::get_d_stress_dG_upper(), and oomph::PVDEquations< DIM >::get_d_stress_dG_upper().

◆ calculate_second_piola_kirchhoff_stress() [1/3]

virtual void oomph::ConstitutiveLaw::calculate_second_piola_kirchhoff_stress ( const DenseMatrix< double > &  g,
const DenseMatrix< double > &  G,
DenseMatrix< double > &  sigma 
)
pure virtual

Calculate the contravariant 2nd Piola Kirchhoff stress tensor. Arguments are the covariant undeformed and deformed metric tensor and the matrix in which to return the stress tensor

Implemented in oomph::IsotropicStrainEnergyFunctionConstitutiveLaw, oomph::GeneralisedHookean, and oomph::AnisotropicHookean.

Referenced by calculate_d_second_piola_kirchhoff_stress_dG(), oomph::AxisymmetricPVDEquations::get_stress(), oomph::PVDEquations< DIM >::get_stress(), oomph::AxisymmetricPVDEquationsWithPressure::get_stress(), and oomph::PVDEquationsWithPressure< DIM >::get_stress().

◆ calculate_second_piola_kirchhoff_stress() [2/3]

virtual void oomph::ConstitutiveLaw::calculate_second_piola_kirchhoff_stress ( const DenseMatrix< double > &  g,
const DenseMatrix< double > &  G,
DenseMatrix< double > &  sigma_dev,
DenseMatrix< double > &  G_contra,
double Gdet 
)
inlinevirtual

Calculate the deviatoric part \( \overline{ \sigma^{ij}}\) of the contravariant 2nd Piola Kirchhoff stress tensor \( \sigma^{ij}\). Also return the contravariant deformed metric tensor and the determinant of the deformed metric tensor. This form is appropriate for truly-incompressible materials for which \( \sigma^{ij} = - p G^{ij} +\overline{ \sigma^{ij}} \) where the "pressure" \( p \) is determined by \( \det G_{ij} - \det g_{ij} = 0 \).

Reimplemented in oomph::IsotropicStrainEnergyFunctionConstitutiveLaw, and oomph::GeneralisedHookean.

553  {
554  throw OomphLibError(
555  "Incompressible formulation not implemented for this constitutive law",
558  }

References OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ calculate_second_piola_kirchhoff_stress() [3/3]

virtual void oomph::ConstitutiveLaw::calculate_second_piola_kirchhoff_stress ( const DenseMatrix< double > &  g,
const DenseMatrix< double > &  G,
DenseMatrix< double > &  sigma_dev,
DenseMatrix< double > &  Gcontra,
double gen_dil,
double inv_kappa 
)
inlinevirtual

Calculate the deviatoric part of the contravariant 2nd Piola Kirchoff stress tensor. Also return the contravariant deformed metric tensor, the generalised dilatation, \( d, \) and the inverse of the bulk modulus \( \kappa\). This form is appropriate for near-incompressible materials for which \( \sigma^{ij} = -p G^{ij} + \overline{ \sigma^{ij}} \) where the "pressure" \( p \) is determined from \( p / \kappa - d =0 \).

Reimplemented in oomph::IsotropicStrainEnergyFunctionConstitutiveLaw, and oomph::GeneralisedHookean.

599  {
600  throw OomphLibError(
601  "Near-incompressible formulation not implemented for constitutive law",
604  }

References OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

◆ error_checking_in_input()

void oomph::ConstitutiveLaw::error_checking_in_input ( const DenseMatrix< double > &  g,
const DenseMatrix< double > &  G,
DenseMatrix< double > &  sigma 
)
protected

Check for errors in the input, i.e. check that the dimensions of the arrays are all consistent

This function is used to provide simple error (bounce) checks on the input to any calculate_second_piola_kirchhoff_stress

74  {
75  // Test whether the undeformed metric tensor is square
76  if (!is_matrix_square(g))
77  {
78  throw OomphLibError("Undeformed metric tensor not square",
81  }
82 
83  // If the deformed metric tensor does not have the same dimension as
84  // the undeformed tensor, complain
86  {
87  std::string error_message = "Deformed metric tensor does \n";
88  error_message +=
89  "not have same dimensions as the undeformed metric tensor\n";
90 
91  throw OomphLibError(
93  }
94 
95  // If the stress tensor does not have the same dimensions as the others
96  // complain.
98  {
99  std::string error_message =
100  "Strain tensor passed to calculate_green_strain() does \n";
101  error_message +=
102  "not have same dimensions as the undeformed metric tensor\n";
103 
104  throw OomphLibError(
106  }
107  }

References are_matrices_of_equal_dimensions(), G, is_matrix_square(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, calibrate::sigma, and oomph::Global_string_for_annotation::string().

Referenced by oomph::GeneralisedHookean::calculate_second_piola_kirchhoff_stress(), and oomph::IsotropicStrainEnergyFunctionConstitutiveLaw::calculate_second_piola_kirchhoff_stress().

◆ is_matrix_square()

bool oomph::ConstitutiveLaw::is_matrix_square ( const DenseMatrix< double > &  M)
protected

Test whether a matrix is square.

This function is used to check whether a matrix is square.

37  {
38  // If the number rows and columns is not equal, the matrix is not square
39  if (M.nrow() != M.ncol())
40  {
41  return false;
42  }
43  else
44  {
45  return true;
46  }
47  }

Referenced by calculate_contravariant(), calculate_d_contravariant_dG(), and error_checking_in_input().

◆ requires_incompressibility_constraint()


The documentation for this class was generated from the following files: