OGS
Ehlers.cpp
Go to the documentation of this file.
1 
10 #include "Ehlers.h"
11 
12 #include <boost/math/special_functions/pow.hpp>
13 
14 #include "LinearElasticIsotropic.h"
17 
18 namespace MPL = MaterialPropertyLib;
19 
43 namespace MaterialLib
44 {
45 namespace Solids
46 {
47 namespace Ehlers
48 {
49 template <int DisplacementDim>
51 {
52  return std::sqrt(2.0 / 3.0 * Invariants::FrobeniusNorm(eps_p.D.eval()));
53 }
54 
61 template <int DisplacementDim>
64 
65 template <int DisplacementDim>
67 {
68  static int const KelvinVectorSize =
71  using KelvinVector =
73 
75  : value{stress},
76  D{Invariants::deviatoric_projection * stress},
77  I_1{Invariants::trace(stress)},
78  J_2{Invariants::J2(D)},
79  J_3{Invariants::J3(D)}
80  {
81  }
82 
85  double I_1;
86  double J_2;
87  double J_3;
88 
90 };
91 
93 struct OnePlusGamma_pTheta final
94 {
95  OnePlusGamma_pTheta(double const gamma_p, double const theta,
96  double const m_p)
97  : value{1 + gamma_p * theta},
98  pow_m_p{std::pow(value, m_p)},
100  {
101  }
102 
103  double const value;
104  double const pow_m_p;
105  double const pow_m_p1;
106 };
107 
108 template <int DisplacementDim>
111  double const sqrtPhi, double const alpha_p, double const beta_p,
112  double const delta_p, double const epsilon_p)
113 {
114  return 3 *
115  (alpha_p * s.I_1 +
116  4 * boost::math::pow<2>(delta_p) * boost::math::pow<3>(s.I_1)) /
117  (2 * sqrtPhi) +
118  3 * beta_p + 6 * epsilon_p * s.I_1;
119 }
120 
121 template <int DisplacementDim>
124  OnePlusGamma_pTheta const& one_gt, double const sqrtPhi,
125  typename SolidEhlers<DisplacementDim>::KelvinVector const& dtheta_dsigma,
126  double const gamma_p, double const m_p)
127 {
128  return (one_gt.pow_m_p *
129  (s.D + s.J_2 * m_p * gamma_p * dtheta_dsigma / one_gt.value)) /
130  (2 * sqrtPhi);
131 }
132 
133 template <int DisplacementDim>
136  double const k)
137 {
138  double const I_1_squared = boost::math::pow<2>(s.I_1);
139  assert(s.J_2 != 0);
140 
141  return std::sqrt(s.J_2 * std::pow(1 + mp.gamma * s.J_3 /
142  (s.J_2 * std::sqrt(s.J_2)),
143  mp.m) +
144  mp.alpha / 2. * I_1_squared +
145  boost::math::pow<2>(mp.delta) *
146  boost::math::pow<2>(I_1_squared)) +
147  mp.beta * s.I_1 + mp.epsilon * I_1_squared - k;
148 }
149 
150 template <int DisplacementDim>
154  double const eps_V,
158  double const eps_p_V,
159  double const eps_p_V_dot,
160  double const eps_p_eff_dot,
161  double const lambda,
162  double const k,
163  MaterialProperties const& mp)
164 {
165  static int const KelvinVectorSize =
168  using KelvinVector =
170 
171  auto const& P_dev = Invariants::deviatoric_projection;
172  auto const& identity2 = Invariants::identity2;
173 
174  double const theta = s.J_3 / (s.J_2 * std::sqrt(s.J_2));
175 
177  // calculate stress residual
178  residual.template segment<KelvinVectorSize>(0).noalias() =
179  s.value / mp.G - 2 * (eps_D - eps_p_D) -
180  mp.K / mp.G * (eps_V - eps_p_V) * identity2;
181 
182  // deviatoric plastic strain
183  KelvinVector const sigma_D_inverse_D =
185  KelvinVector const dtheta_dsigma =
186  theta * sigma_D_inverse_D - 3. / 2. * theta / s.J_2 * s.D;
187 
188  OnePlusGamma_pTheta const one_gt{mp.gamma_p, theta, mp.m_p};
189  double const sqrtPhi = std::sqrt(
190  s.J_2 * one_gt.pow_m_p + mp.alpha_p / 2. * boost::math::pow<2>(s.I_1) +
191  boost::math::pow<2>(mp.delta_p) * boost::math::pow<4>(s.I_1));
192  KelvinVector const flow_D = plasticFlowDeviatoricPart(
193  s, one_gt, sqrtPhi, dtheta_dsigma, mp.gamma_p, mp.m_p);
194  KelvinVector const lambda_flow_D = lambda * flow_D;
195 
196  residual.template segment<KelvinVectorSize>(KelvinVectorSize).noalias() =
197  eps_p_D_dot - lambda_flow_D;
198 
199  // plastic volume strain
200  {
201  double const flow_V = plasticFlowVolumetricPart<DisplacementDim>(
202  s, sqrtPhi, mp.alpha_p, mp.beta_p, mp.delta_p, mp.epsilon_p);
203  residual(2 * KelvinVectorSize, 0) = eps_p_V_dot - lambda * flow_V;
204  }
205 
206  // evolution of plastic equivalent strain
207  residual(2 * KelvinVectorSize + 1) =
208  eps_p_eff_dot -
209  std::sqrt(2. / 3. * lambda_flow_D.transpose() * lambda_flow_D);
210 
211  // yield function (for plastic multiplier)
212  residual(2 * KelvinVectorSize + 2) = yieldFunction(mp, s, k) / mp.G;
213  return residual;
214 }
215 
216 template <int DisplacementDim>
218  double const dt,
220  double const lambda,
221  MaterialProperties const& mp)
222 {
223  static int const KelvinVectorSize =
226  using KelvinVector =
228  using KelvinMatrix =
230 
231  auto const& P_dev = Invariants::deviatoric_projection;
232  auto const& identity2 = Invariants::identity2;
233 
234  double const theta = s.J_3 / (s.J_2 * std::sqrt(s.J_2));
235  OnePlusGamma_pTheta const one_gt{mp.gamma_p, theta, mp.m_p};
236 
237  // inverse of deviatoric stress tensor
238  if (Invariants::determinant(s.D) == 0)
239  {
240  OGS_FATAL("Determinant is zero. Matrix is non-invertable.");
241  }
242  // inverse of sigma_D
243  KelvinVector const sigma_D_inverse = MathLib::KelvinVector::inverse(s.D);
244  KelvinVector const sigma_D_inverse_D = P_dev * sigma_D_inverse;
245 
246  KelvinVector const dtheta_dsigma =
247  theta * sigma_D_inverse_D - 3. / 2. * theta / s.J_2 * s.D;
248 
249  // deviatoric flow
250  double const sqrtPhi = std::sqrt(
251  s.J_2 * one_gt.pow_m_p + mp.alpha_p / 2. * boost::math::pow<2>(s.I_1) +
252  boost::math::pow<2>(mp.delta_p) * boost::math::pow<4>(s.I_1));
253  KelvinVector const flow_D = plasticFlowDeviatoricPart(
254  s, one_gt, sqrtPhi, dtheta_dsigma, mp.gamma_p, mp.m_p);
255  KelvinVector const lambda_flow_D = lambda * flow_D;
256 
259 
260  // G_11
261  jacobian.template block<KelvinVectorSize, KelvinVectorSize>(0, 0)
262  .noalias() = KelvinMatrix::Identity();
263 
264  // G_12
265  jacobian
266  .template block<KelvinVectorSize, KelvinVectorSize>(0, KelvinVectorSize)
267  .noalias() = 2 * KelvinMatrix::Identity();
268 
269  // G_13
270  jacobian.template block<KelvinVectorSize, 1>(0, 2 * KelvinVectorSize)
271  .noalias() = mp.K / mp.G * identity2;
272 
273  // G_14 and G_15 are zero
274 
275  // G_21 -- derivative of deviatoric flow
276 
277  double const gm_p = mp.gamma_p * mp.m_p;
278  // intermediate variable for derivative of deviatoric flow
279  KelvinVector const M0 = s.J_2 / one_gt.value * dtheta_dsigma;
280  // derivative of Phi w.r.t. sigma
281  KelvinVector const dPhi_dsigma =
282  one_gt.pow_m_p * (s.D + gm_p * M0) +
283  (mp.alpha_p * s.I_1 +
284  4 * boost::math::pow<2>(mp.delta_p) * boost::math::pow<3>(s.I_1)) *
285  identity2;
286 
287  // intermediate variable for derivative of deviatoric flow
288  KelvinMatrix const M1 =
289  one_gt.pow_m_p *
290  (s.D * dPhi_dsigma.transpose() + gm_p * M0 * dPhi_dsigma.transpose());
291  // intermediate variable for derivative of deviatoric flow
292  KelvinMatrix const M2 =
293  one_gt.pow_m_p * (P_dev + s.D * gm_p * M0.transpose());
294  // second derivative of theta
295  KelvinMatrix const d2theta_dsigma2 =
296  theta * P_dev * sOdotS<DisplacementDim>(sigma_D_inverse) * P_dev +
297  sigma_D_inverse_D * dtheta_dsigma.transpose() -
298  3. / 2. * theta / s.J_2 * P_dev -
299  3. / 2. * dtheta_dsigma / s.J_2 * s.D.transpose() +
300  3. / 2. * theta / boost::math::pow<2>(s.J_2) * s.D * s.D.transpose();
301 
302  // intermediate variable for derivative of deviatoric flow
303  KelvinMatrix const M3 =
304  gm_p * one_gt.pow_m_p1 *
305  ((s.D + (gm_p - mp.gamma_p) * M0) * dtheta_dsigma.transpose() +
306  s.J_2 * d2theta_dsigma2);
307 
308  // derivative of flow_D w.r.t. sigma
309  KelvinMatrix const dflow_D_dsigma =
310  (-M1 / (4 * boost::math::pow<3>(sqrtPhi)) + (M2 + M3) / (2 * sqrtPhi)) *
311  mp.G;
312  jacobian
313  .template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, 0)
314  .noalias() = -lambda * dflow_D_dsigma;
315 
316  // G_22
317  jacobian
318  .template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize,
319  KelvinVectorSize)
320  .noalias() = KelvinMatrix::Identity() / dt;
321 
322  // G_23 and G_24 are zero
323 
324  // G_25
325  jacobian
326  .template block<KelvinVectorSize, 1>(KelvinVectorSize,
327  2 * KelvinVectorSize + 2)
328  .noalias() = -flow_D;
329 
330  // G_31
331  {
332  // derivative of flow_V w.r.t. sigma
333  KelvinVector const dflow_V_dsigma =
334  3 * mp.G *
335  (-(mp.alpha_p * s.I_1 + 4 * boost::math::pow<2>(mp.delta_p) *
336  boost::math::pow<3>(s.I_1)) /
337  (4 * boost::math::pow<3>(sqrtPhi)) * dPhi_dsigma +
338  (mp.alpha_p * identity2 +
339  12 * boost::math::pow<2>(mp.delta_p * s.I_1) * identity2) /
340  (2 * sqrtPhi) +
341  2 * mp.epsilon_p * identity2);
342 
343  jacobian.template block<1, KelvinVectorSize>(2 * KelvinVectorSize, 0)
344  .noalias() = -lambda * dflow_V_dsigma.transpose();
345  }
346 
347  // G_32 is zero
348 
349  // G_33
350  jacobian(2 * KelvinVectorSize, 2 * KelvinVectorSize) = 1. / dt;
351 
352  // G_34 is zero
353 
354  // G_35
355  {
356  double const flow_V = plasticFlowVolumetricPart<DisplacementDim>(
357  s, sqrtPhi, mp.alpha_p, mp.beta_p, mp.delta_p, mp.epsilon_p);
358  jacobian(2 * KelvinVectorSize, 2 * KelvinVectorSize + 2) = -flow_V;
359  }
360 
361  // increment of effectiv plastic strain
362  double const eff_flow =
363  std::sqrt(2. / 3. * lambda_flow_D.transpose() * lambda_flow_D);
364 
365  if (eff_flow > 0)
366  {
367  // intermediate variable for derivative of plastic jacobian
368  KelvinVector const eff_flow23_lambda_flow_D =
369  -2 / 3. / eff_flow * lambda_flow_D;
370  // G_41
371  jacobian
372  .template block<1, KelvinVectorSize>(2 * KelvinVectorSize + 1, 0)
373  .noalias() = lambda * dflow_D_dsigma * eff_flow23_lambda_flow_D;
374  // G_45
375  jacobian(2 * KelvinVectorSize + 1, 2 * KelvinVectorSize + 2) =
376  eff_flow23_lambda_flow_D.transpose() * flow_D;
377  }
378 
379  // G_42 and G_43 are zero
380 
381  // G_44
382  jacobian(2 * KelvinVectorSize + 1, 2 * KelvinVectorSize + 1) = 1. / dt;
383 
384  // G_51
385  {
386  double const one_gt_pow_m = std::pow(one_gt.value, mp.m);
387  double const gm = mp.gamma * mp.m;
388  // derivative of yield function w.r.t. sigma
389  KelvinVector const dF_dsigma =
390  mp.G *
391  (one_gt_pow_m * (s.D + gm * M0) +
392  (mp.alpha * s.I_1 + 4 * boost::math::pow<2>(mp.delta) *
393  boost::math::pow<3>(s.I_1)) *
394  identity2) /
395  (2. * sqrtPhi) +
396  mp.G * (mp.beta + 2 * mp.epsilon_p * s.I_1) * identity2;
397 
398  jacobian
399  .template block<1, KelvinVectorSize>(2 * KelvinVectorSize + 2, 0)
400  .noalias() = dF_dsigma.transpose() / mp.G;
401  }
402 
403  // G_54
404  jacobian(2 * KelvinVectorSize + 2, 2 * KelvinVectorSize + 1) =
405  -mp.kappa * mp.hardening_coefficient / mp.G;
406 
407  // G_52, G_53, G_55 are zero
408  return jacobian;
409 }
410 
413 template <int DisplacementDim>
415  double const K, double const G)
416 {
417  static int const KelvinVectorSize =
420 
421  auto const& P_dev = Invariants::deviatoric_projection;
422  auto const& P_sph = Invariants::spherical_projection;
423  auto const& I =
425 
426  return -2. * I * P_dev - 3. * K / G * I * P_sph;
427 }
428 
429 inline double calculateIsotropicHardening(double const kappa,
430  double const hardening_coefficient,
431  double const eps_p_eff)
432 {
433  return kappa * (1. + eps_p_eff * hardening_coefficient);
434 }
435 
436 template <int DisplacementDim>
438  double const G, double const K,
439  typename SolidEhlers<DisplacementDim>::KelvinVector const& sigma_prev,
440  typename SolidEhlers<DisplacementDim>::KelvinVector const& eps,
441  typename SolidEhlers<DisplacementDim>::KelvinVector const& eps_prev,
442  double const eps_V)
443 {
444  static int const KelvinVectorSize =
447  auto const& P_dev = Invariants::deviatoric_projection;
448 
449  // dimensionless initial hydrostatic pressure
450  double const pressure_prev = Invariants::trace(sigma_prev) / (-3. * G);
451  // initial strain invariant
452  double const e_prev = Invariants::trace(eps_prev);
453  // dimensioness hydrostatic stress increment
454  double const pressure = pressure_prev - K / G * (eps_V - e_prev);
455  // dimensionless deviatoric initial stress
456  typename SolidEhlers<DisplacementDim>::KelvinVector const sigma_D_prev =
457  P_dev * sigma_prev / G;
458  // dimensionless deviatoric stress
459  typename SolidEhlers<DisplacementDim>::KelvinVector const sigma_D =
460  sigma_D_prev + 2 * P_dev * (eps - eps_prev);
461  return sigma_D - pressure * Invariants::identity2;
462 }
463 
466 template <typename ResidualVector, typename KelvinVector>
467 std::tuple<KelvinVector, PlasticStrain<KelvinVector>, double>
468 splitSolutionVector(ResidualVector const& solution)
469 {
470  static auto const size = KelvinVector::SizeAtCompileTime;
471  return std::forward_as_tuple(
472  solution.template segment<size>(size * 0),
473  PlasticStrain<KelvinVector>{solution.template segment<size>(size * 1),
474  solution[size * 2], solution[size * 2 + 1]},
475  solution[size * 2 + 2]);
476 }
477 
478 template <int DisplacementDim>
480  NumLib::NewtonRaphsonSolverParameters nonlinear_solver_parameters,
481  MaterialPropertiesParameters material_properties,
482  std::unique_ptr<DamagePropertiesParameters>&& damage_properties,
483  TangentType tangent_type)
484  : _nonlinear_solver_parameters(std::move(nonlinear_solver_parameters)),
485  _mp(std::move(material_properties)),
486  _damage_properties(std::move(damage_properties)),
487  _tangent_type(tangent_type)
488 {
489 }
490 
491 template <int DisplacementDim>
493  double const /*t*/,
494  ParameterLib::SpatialPosition const& /*x*/,
495  double const /*dt*/,
496  KelvinVector const& eps,
497  KelvinVector const& sigma,
499  material_state_variables) const
500 {
501  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
502  &material_state_variables) != nullptr);
503 
504  auto const& eps_p = static_cast<StateVariables<DisplacementDim> const&>(
505  material_state_variables)
506  .eps_p;
508  auto const& identity2 = Invariants::identity2;
509  return (eps - eps_p.D - eps_p.V / 3 * identity2).dot(sigma) / 2;
510 }
511 
512 template <int DisplacementDim>
513 std::optional<std::tuple<typename SolidEhlers<DisplacementDim>::KelvinVector,
514  std::unique_ptr<typename MechanicsBase<
515  DisplacementDim>::MaterialStateVariables>,
518  MaterialPropertyLib::VariableArray const& variable_array_prev,
519  MaterialPropertyLib::VariableArray const& variable_array, double const t,
520  ParameterLib::SpatialPosition const& x, double const dt,
522  material_state_variables) const
523 {
524  auto const& eps_m = std::get<MPL::SymmetricTensor<DisplacementDim>>(
525  variable_array[static_cast<int>(MPL::Variable::mechanical_strain)]);
526  auto const& eps_m_prev = std::get<MPL::SymmetricTensor<DisplacementDim>>(
527  variable_array_prev[static_cast<int>(
528  MPL::Variable::mechanical_strain)]);
529  auto const& sigma_prev = std::get<MPL::SymmetricTensor<DisplacementDim>>(
530  variable_array_prev[static_cast<int>(MPL::Variable::stress)]);
531 
532  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
533  &material_state_variables) != nullptr);
534 
536  static_cast<StateVariables<DisplacementDim> const&>(
537  material_state_variables);
538  state.setInitialConditions();
539 
541 
542  // volumetric strain
543  double const eps_V = Invariants::trace(eps_m);
544 
545  auto const& P_dev = Invariants::deviatoric_projection;
546  // deviatoric strain
547  KelvinVector const eps_D = P_dev * eps_m;
548 
549  // do the evaluation once per function call.
550  MaterialProperties const mp(t, x, _mp);
551 
552  KelvinVector sigma = predict_sigma<DisplacementDim>(
553  mp.G, mp.K, sigma_prev, eps_m, eps_m_prev, eps_V);
554 
555  KelvinMatrix tangentStiffness;
556 
558  // Quit early if sigma is zero (nothing to do) or if we are still in elastic
559  // zone.
560  if ((sigma.squaredNorm() == 0 ||
562  mp, s,
564  state.eps_p.eff)) < 0))
565  {
566  tangentStiffness = elasticTangentStiffness<DisplacementDim>(
567  mp.K - 2. / 3 * mp.G, mp.G);
568  }
569  else
570  {
571  // Linear solver for the newton loop is required after the loop with the
572  // same matrix. This saves one decomposition.
573  Eigen::FullPivLU<Eigen::Matrix<double, JacobianResidualSize,
574  JacobianResidualSize, Eigen::RowMajor>>
575  linear_solver;
576 
577  {
578  static int const KelvinVectorSize =
580  DisplacementDim);
581  using KelvinVector =
583  using ResidualVectorType =
584  Eigen::Matrix<double, JacobianResidualSize, 1>;
585  using JacobianMatrix =
586  Eigen::Matrix<double, JacobianResidualSize,
587  JacobianResidualSize, Eigen::RowMajor>;
588 
589  JacobianMatrix jacobian;
590 
591  // Agglomerated solution vector construction. It is later split
592  // into individual parts by splitSolutionVector().
593  ResidualVectorType solution;
594  solution << sigma, state.eps_p.D, state.eps_p.V, state.eps_p.eff, 0;
595 
596  auto const update_residual = [&](ResidualVectorType& residual)
597  {
598  auto const& eps_p_D =
599  solution.template segment<KelvinVectorSize>(
600  KelvinVectorSize);
601  KelvinVector const eps_p_D_dot =
602  (eps_p_D - state.eps_p_prev.D) / dt;
603 
604  double const& eps_p_V = solution[KelvinVectorSize * 2];
605  double const eps_p_V_dot = (eps_p_V - state.eps_p_prev.V) / dt;
606 
607  double const& eps_p_eff = solution[KelvinVectorSize * 2 + 1];
608  double const eps_p_eff_dot =
609  (eps_p_eff - state.eps_p_prev.eff) / dt;
610 
611  double const k_hardening = calculateIsotropicHardening(
613  solution[KelvinVectorSize * 2 + 1]);
614  residual = calculatePlasticResidual<DisplacementDim>(
615  eps_D, eps_V, s,
616  solution.template segment<KelvinVectorSize>(
617  KelvinVectorSize),
618  eps_p_D_dot, solution[KelvinVectorSize * 2], eps_p_V_dot,
619  eps_p_eff_dot, solution[KelvinVectorSize * 2 + 2],
620  k_hardening, mp);
621  };
622 
623  auto const update_jacobian = [&](JacobianMatrix& jacobian)
624  {
625  jacobian = calculatePlasticJacobian<DisplacementDim>(
626  dt, s, solution[KelvinVectorSize * 2 + 2], mp);
627  };
628 
629  auto const update_solution =
630  [&](ResidualVectorType const& increment)
631  {
632  solution += increment;
634  mp.G * solution.template segment<KelvinVectorSize>(0)};
635  };
636 
637  auto newton_solver = NumLib::NewtonRaphson<
638  decltype(linear_solver), JacobianMatrix,
639  decltype(update_jacobian), ResidualVectorType,
640  decltype(update_residual), decltype(update_solution)>(
641  linear_solver, update_jacobian, update_residual,
642  update_solution, _nonlinear_solver_parameters);
643 
644  auto const success_iterations = newton_solver.solve(jacobian);
645 
646  if (!success_iterations)
647  {
648  return {};
649  }
650 
651  // If the Newton loop didn't run, the linear solver will not be
652  // initialized.
653  // This happens usually for the first iteration of the first
654  // timestep.
655  if (*success_iterations == 0)
656  {
657  linear_solver.compute(jacobian);
658  }
659 
660  std::tie(sigma, state.eps_p, std::ignore) =
661  splitSolutionVector<ResidualVectorType, KelvinVector>(solution);
662  }
663 
664  // Calculate residual derivative w.r.t. strain
665  Eigen::Matrix<double, JacobianResidualSize, KelvinVectorSize,
666  Eigen::RowMajor>
667  dresidual_deps =
668  Eigen::Matrix<double, JacobianResidualSize, KelvinVectorSize,
669  Eigen::RowMajor>::Zero();
670  dresidual_deps.template block<KelvinVectorSize, KelvinVectorSize>(0, 0)
671  .noalias() = calculateDResidualDEps<DisplacementDim>(mp.K, mp.G);
672 
673  if (_tangent_type == TangentType::Elastic)
674  {
675  tangentStiffness =
676  elasticTangentStiffness<DisplacementDim>(mp.K, mp.G);
677  }
678  else if (_tangent_type == TangentType::Plastic ||
679  _tangent_type == TangentType::PlasticDamageSecant)
680  {
681  tangentStiffness =
682  mp.G *
683  linear_solver.solve(-dresidual_deps)
684  .template block<KelvinVectorSize, KelvinVectorSize>(0, 0);
685  if (_tangent_type == TangentType::PlasticDamageSecant)
686  {
687  tangentStiffness *= 1 - state.damage.value();
688  }
689  }
690  else
691  {
692  OGS_FATAL(
693  "Unimplemented tangent type behaviour for the tangent type "
694  "'{:d}'.",
695  _tangent_type);
696  }
697  }
698 
699  KelvinVector sigma_final = mp.G * sigma;
700 
701  return {std::make_tuple(
702  sigma_final,
703  std::unique_ptr<
706  static_cast<StateVariables<DisplacementDim> const&>(state)}},
707  tangentStiffness)};
708 }
709 
710 template <int DisplacementDim>
711 std::vector<typename MechanicsBase<DisplacementDim>::InternalVariable>
713 {
714  return {{"damage.kappa_d", 1,
715  [](typename MechanicsBase<
716  DisplacementDim>::MaterialStateVariables const& state,
717  std::vector<double>& cache) -> std::vector<double> const&
718  {
719  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
720  &state) != nullptr);
721  auto const& ehlers_state =
722  static_cast<StateVariables<DisplacementDim> const&>(state);
723 
724  cache.resize(1);
725  cache.front() = ehlers_state.damage.kappa_d();
726  return cache;
727  },
730  {
731  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
732  &state) != nullptr);
733  auto& ehlers_state =
734  static_cast<StateVariables<DisplacementDim>&>(state);
735 
736  return {&ehlers_state.damage.kappa_d(), 1};
737  }},
738  {"damage.value", 1,
739  [](typename MechanicsBase<
740  DisplacementDim>::MaterialStateVariables const& state,
741  std::vector<double>& cache) -> std::vector<double> const&
742  {
743  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
744  &state) != nullptr);
745  auto const& ehlers_state =
746  static_cast<StateVariables<DisplacementDim> const&>(state);
747 
748  cache.resize(1);
749  cache.front() = ehlers_state.damage.value();
750  return cache;
751  },
754  {
755  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
756  &state) != nullptr);
757  auto& ehlers_state =
758  static_cast<StateVariables<DisplacementDim>&>(state);
759 
760  return {&ehlers_state.damage.value(), 1};
761  }},
762  {"eps_p.D", KelvinVector::RowsAtCompileTime,
763  [](typename MechanicsBase<
764  DisplacementDim>::MaterialStateVariables const& state,
765  std::vector<double>& cache) -> std::vector<double> const&
766  {
767  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
768  &state) != nullptr);
769  auto const& ehlers_state =
770  static_cast<StateVariables<DisplacementDim> const&>(state);
771 
772  cache.resize(KelvinVector::RowsAtCompileTime);
773  MathLib::toVector<KelvinVector>(
774  cache, KelvinVector::RowsAtCompileTime) =
776  ehlers_state.eps_p.D);
777 
778  return cache;
779  },
782  {
783  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
784  &state) != nullptr);
785  auto& ehlers_state =
786  static_cast<StateVariables<DisplacementDim>&>(state);
787 
788  return {
789  ehlers_state.eps_p.D.data(),
790  static_cast<std::size_t>(KelvinVector::RowsAtCompileTime)};
791  }},
792  {"eps_p.V", 1,
793  [](typename MechanicsBase<
794  DisplacementDim>::MaterialStateVariables const& state,
795  std::vector<double>& cache) -> std::vector<double> const&
796  {
797  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
798  &state) != nullptr);
799  auto const& ehlers_state =
800  static_cast<StateVariables<DisplacementDim> const&>(state);
801 
802  cache.resize(1);
803  cache.front() = ehlers_state.eps_p.V;
804  return cache;
805  },
808  {
809  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
810  &state) != nullptr);
811  auto& ehlers_state =
812  static_cast<StateVariables<DisplacementDim>&>(state);
813 
814  return {&ehlers_state.eps_p.V, 1};
815  }},
816  {"eps_p.eff", 1,
817  [](typename MechanicsBase<
818  DisplacementDim>::MaterialStateVariables const& state,
819  std::vector<double>& cache) -> std::vector<double> const&
820  {
821  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
822  &state) != nullptr);
823  auto const& ehlers_state =
824  static_cast<StateVariables<DisplacementDim> const&>(state);
825 
826  cache.resize(1);
827  cache.front() = ehlers_state.eps_p.eff;
828  return cache;
829  },
832  {
833  assert(dynamic_cast<StateVariables<DisplacementDim> const*>(
834  &state) != nullptr);
835  auto& ehlers_state =
836  static_cast<StateVariables<DisplacementDim>&>(state);
837 
838  return {&ehlers_state.eps_p.eff, 1};
839  }}};
840 }
841 
842 template class SolidEhlers<2>;
843 template class SolidEhlers<3>;
844 
845 template <>
848 {
850 
851  result(0, 0) = v(0) * v(0);
852  result(0, 1) = result(1, 0) = v(3) * v(3) / 2.;
853  result(0, 2) = result(2, 0) = v(5) * v(5) / 2.;
854  result(0, 3) = result(3, 0) = v(0) * v(3);
855  result(0, 4) = result(4, 0) = v(3) * v(5) / std::sqrt(2.);
856  result(0, 5) = result(5, 0) = v(0) * v(5);
857 
858  result(1, 1) = v(1) * v(1);
859  result(1, 2) = result(2, 1) = v(4) * v(4) / 2.;
860  result(1, 3) = result(3, 1) = v(3) * v(1);
861  result(1, 4) = result(4, 1) = v(1) * v(4);
862  result(1, 5) = result(5, 1) = v(3) * v(4) / std::sqrt(2.);
863 
864  result(2, 2) = v(2) * v(2);
865  result(2, 3) = result(3, 2) = v(5) * v(4) / std::sqrt(2.);
866  result(2, 4) = result(4, 2) = v(4) * v(2);
867  result(2, 5) = result(5, 2) = v(5) * v(2);
868 
869  result(3, 3) = v(0) * v(1) + v(3) * v(3) / 2.;
870  result(3, 4) = result(4, 3) =
871  v(3) * v(4) / 2. + v(5) * v(1) / std::sqrt(2.);
872  result(3, 5) = result(5, 3) =
873  v(0) * v(4) / std::sqrt(2.) + v(3) * v(5) / 2.;
874 
875  result(4, 4) = v(1) * v(2) + v(4) * v(4) / 2.;
876  result(4, 5) = result(5, 4) =
877  v(3) * v(2) / std::sqrt(2.) + v(5) * v(4) / 2.;
878 
879  result(5, 5) = v(0) * v(2) + v(5) * v(5) / 2.;
880  return result;
881 }
882 
883 template <>
886 {
888 
889  result(0, 0) = v(0) * v(0);
890  result(0, 1) = result(1, 0) = v(3) * v(3) / 2.;
891  result(0, 2) = result(2, 0) = 0;
892  result(0, 3) = result(3, 0) = v(0) * v(3);
893 
894  result(1, 1) = v(1) * v(1);
895  result(1, 2) = result(2, 1) = 0;
896  result(1, 3) = result(3, 1) = v(3) * v(1);
897 
898  result(2, 2) = v(2) * v(2);
899  result(2, 3) = result(3, 2) = 0;
900 
901  result(3, 3) = v(0) * v(1) + v(3) * v(3) / 2.;
902 
903  return result;
904 }
905 
906 } // namespace Ehlers
907 } // namespace Solids
908 } // namespace MaterialLib
#define OGS_FATAL(...)
Definition: Error.h:26
std::vector< typename MechanicsBase< DisplacementDim >::InternalVariable > getInternalVariables() const override
Definition: Ehlers.cpp:712
std::optional< std::tuple< KelvinVector, std::unique_ptr< typename MechanicsBase< DisplacementDim >::MaterialStateVariables >, KelvinMatrix > > integrateStress(MaterialPropertyLib::VariableArray const &variable_array_prev, MaterialPropertyLib::VariableArray const &variable_array, double const t, ParameterLib::SpatialPosition const &x, double const dt, typename MechanicsBase< DisplacementDim >::MaterialStateVariables const &material_state_variables) const override
Definition: Ehlers.cpp:517
Eigen::Matrix< double, JacobianResidualSize, JacobianResidualSize, Eigen::RowMajor > JacobianMatrix
Definition: Ehlers.h:286
MathLib::KelvinVector::KelvinMatrixType< DisplacementDim > KelvinMatrix
Definition: Ehlers.h:300
MathLib::KelvinVector::KelvinVectorType< DisplacementDim > KelvinVector
Definition: Ehlers.h:298
Eigen::Matrix< double, JacobianResidualSize, 1 > ResidualVectorType
Definition: Ehlers.h:284
SolidEhlers(NumLib::NewtonRaphsonSolverParameters nonlinear_solver_parameters, MaterialPropertiesParameters material_properties, std::unique_ptr< DamagePropertiesParameters > &&damage_properties, TangentType tangent_type)
Definition: Ehlers.cpp:479
double computeFreeEnergyDensity(double const, ParameterLib::SpatialPosition const &, double const, KelvinVector const &eps, KelvinVector const &sigma, typename MechanicsBase< DisplacementDim >::MaterialStateVariables const &material_state_variables) const override
Definition: Ehlers.cpp:492
std::optional< int > solve(JacobianMatrix &jacobian) const
Definition: NewtonRaphson.h:56
SolidEhlers< DisplacementDim >::KelvinVector plasticFlowDeviatoricPart(PhysicalStressWithInvariants< DisplacementDim > const &s, OnePlusGamma_pTheta const &one_gt, double const sqrtPhi, typename SolidEhlers< DisplacementDim >::KelvinVector const &dtheta_dsigma, double const gamma_p, double const m_p)
Definition: Ehlers.cpp:122
MathLib::KelvinVector::KelvinMatrixType< DisplacementDim > calculateDResidualDEps(double const K, double const G)
Definition: Ehlers.cpp:414
std::tuple< KelvinVector, PlasticStrain< KelvinVector >, double > splitSolutionVector(ResidualVector const &solution)
Definition: Ehlers.cpp:468
SolidEhlers< DisplacementDim >::JacobianMatrix calculatePlasticJacobian(double const dt, PhysicalStressWithInvariants< DisplacementDim > const &s, double const lambda, MaterialProperties const &mp)
Definition: Ehlers.cpp:217
double plasticFlowVolumetricPart(PhysicalStressWithInvariants< DisplacementDim > const &s, double const sqrtPhi, double const alpha_p, double const beta_p, double const delta_p, double const epsilon_p)
Definition: Ehlers.cpp:109
SolidEhlers< DisplacementDim >::ResidualVectorType calculatePlasticResidual(MathLib::KelvinVector::KelvinVectorType< DisplacementDim > const &eps_D, double const eps_V, PhysicalStressWithInvariants< DisplacementDim > const &s, MathLib::KelvinVector::KelvinVectorType< DisplacementDim > const &eps_p_D, MathLib::KelvinVector::KelvinVectorType< DisplacementDim > const &eps_p_D_dot, double const eps_p_V, double const eps_p_V_dot, double const eps_p_eff_dot, double const lambda, double const k, MaterialProperties const &mp)
Definition: Ehlers.cpp:152
MathLib::KelvinVector::KelvinMatrixType< 3 > sOdotS< 3 >(MathLib::KelvinVector::KelvinVectorType< 3 > const &v)
Definition: Ehlers.cpp:846
double calculateIsotropicHardening(double const kappa, double const hardening_coefficient, double const eps_p_eff)
Definition: Ehlers.cpp:429
MathLib::KelvinVector::KelvinMatrixType< DisplacementDim > sOdotS(MathLib::KelvinVector::KelvinVectorType< DisplacementDim > const &v)
MathLib::KelvinVector::KelvinMatrixType< 2 > sOdotS< 2 >(MathLib::KelvinVector::KelvinVectorType< 2 > const &v)
Definition: Ehlers.cpp:884
double yieldFunction(MaterialProperties const &mp, PhysicalStressWithInvariants< DisplacementDim > const &s, double const k)
Definition: Ehlers.cpp:134
SolidEhlers< DisplacementDim >::KelvinVector predict_sigma(double const G, double const K, typename SolidEhlers< DisplacementDim >::KelvinVector const &sigma_prev, typename SolidEhlers< DisplacementDim >::KelvinVector const &eps, typename SolidEhlers< DisplacementDim >::KelvinVector const &eps_prev, double const eps_V)
Definition: Ehlers.cpp:437
std::array< VariableType, static_cast< int >(Variable::number_of_variables)> VariableArray
Definition: VariableType.h:108
Eigen::Matrix< double, 4, 1 > kelvinVectorToSymmetricTensor(Eigen::Matrix< double, 4, 1, Eigen::ColMajor, 4, 1 > const &v)
Eigen::Matrix< double, kelvin_vector_dimensions(DisplacementDim), 1, Eigen::ColMajor > KelvinVectorType
Definition: KelvinVector.h:48
constexpr int kelvin_vector_dimensions(int const displacement_dim)
Kelvin vector dimensions for given displacement dimension.
Definition: KelvinVector.h:23
Eigen::Matrix< double, kelvin_vector_dimensions(DisplacementDim), kelvin_vector_dimensions(DisplacementDim), Eigen::RowMajor > KelvinMatrixType
Definition: KelvinVector.h:56
Eigen::Matrix< double, 4, 1, Eigen::ColMajor, 4, 1 > inverse(Eigen::Matrix< double, 4, 1, Eigen::ColMajor, 4, 1 > const &v)
Holds powers of 1 + gamma_p*theta to base 0, m_p, and m_p-1.
Definition: Ehlers.cpp:94
OnePlusGamma_pTheta(double const gamma_p, double const theta, double const m_p)
Definition: Ehlers.cpp:95
PhysicalStressWithInvariants(KelvinVector const &stress)
Definition: Ehlers.cpp:74
MathLib::KelvinVector::KelvinVectorType< DisplacementDim > KelvinVector
Definition: Ehlers.cpp:72
Damage damage
damage part of the state.
Definition: Ehlers.h:246
PlasticStrain< KelvinVector > eps_p
plastic part of the state.
Definition: Ehlers.h:245
double getEquivalentPlasticStrain() const override
Definition: Ehlers.cpp:50
PlasticStrain< KelvinVector > eps_p_prev
plastic part of the state.
Definition: Ehlers.h:249