/******************************************************************************/
/* LYNX, a MOOSE-based application */
/* */
/* Copyright (C) 2017 by Antoine B. Jacquey and Mauro Cacace */
/* GFZ Potsdam, German Research Centre for Geosciences */
/* */
/* This program is free software: you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation, either version 3 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see */
/******************************************************************************/
#include "LynxDamageDeformation.h"
#include "libmesh/utility.h"
registerMooseObject("LynxApp", LynxDamageDeformation);
template <>
InputParameters
validParams()
{
InputParameters params = validParams();
params.addClassDescription("Class calculating the deformation of a material following a "
"damage viscoelasto-(visco)plastic rheology.");
// Coupled variables
params.addCoupledVar("damage", "The damage variable.");
params.addCoupledVar("porosity", "The porosity variable.");
// Elastic moduli parameters
params.addParam>("damage_modulus",
"The third elastic damage modulus for the damage rheology.");
// Damage-Plasticity parameters
params.addParam>(
"friction_angle",
"The friction angle of the material for the pressure-dependant part of the yield stress.");
params.addParam>("cohesion",
"The constant coefficient of the yield stress corresponding "
"to the cohesion of the material.");
params.addParam>(
"porous_coeff",
"The porous coefficient controlling the capped yield in the damage rheology.");
params.addParam>(
"porous_coeff_linear", "The linear dependency of the porous coefficient to porosity.");
params.addParam>(
"plastic_viscosity",
"The reference viscosity in the generalized Duvaut-Lions viscoplastic formulation.");
params.addParam>("damage_viscosity",
"The reference viscosity in the damage rheology.");
return params;
}
LynxDamageDeformation::LynxDamageDeformation(const InputParameters & parameters)
: LynxDeformationBase(parameters),
// Coupled variables
_coupled_dam(isCoupled("damage")),
_damage(_coupled_dam ? coupledValue("damage") : _zero),
_damage_old(_coupled_dam ? coupledValueOld("damage") : _zero),
_coupled_phi(isCoupled("porosity")),
_porosity(_coupled_phi ? coupledValue("porosity") : _zero),
// Elastic moduli parameters
_damage_modulus(isParamValid("damage_modulus") ? getLynxParam("damage_modulus")
: std::vector(_n_composition, 0.0)),
// Damage-Plasticity parameters
_friction_angle(isParamValid("friction_angle") ? getLynxParam("friction_angle")
: std::vector(_n_composition, 0.0)),
_cohesion(isParamValid("cohesion") ? getLynxParam("cohesion")
: std::vector(_n_composition, 0.0)),
_porous_coeff(isParamValid("porous_coeff") ? getLynxParam("porous_coeff")
: std::vector(_n_composition, 0.0)),
_porous_coeff_linear(isParamValid("porous_coeff_linear")
? getLynxParam("porous_coeff_linear")
: std::vector(_n_composition, 0.0)),
_one_on_plastic_eta(isParamValid("plastic_viscosity") ? getLynxParam("plastic_viscosity")
: std::vector(_n_composition, 0.0)),
_one_on_damage_eta(isParamValid("damage_viscosity") ? getLynxParam("damage_viscosity")
: std::vector(_n_composition, 0.0)),
// Stress properties
_dstress_ddamage(declareProperty("dstress_ddamage")),
_ddamage_rate_dstrain(declareProperty("ddamage_rate_dstrain")),
// Damage properties
_damage_rate(declareProperty("damage_rate"))
{
_has_plasticity = isParamValid("friction_angle");
// Grabing the inverse of plastic and damage viscosities
for (unsigned int i = 0; i < _n_composition; ++i)
{
if (_one_on_plastic_eta[i] < 0.0)
mooseError("LynxDamageDeformation: 'plastic_viscosity' cannot be negative!");
else if (_one_on_plastic_eta[i] > 0.0)
_one_on_plastic_eta[i] = 1.0 / _one_on_plastic_eta[i];
if (_one_on_damage_eta[i] < 0.0)
mooseError("LynxDamageDeformation: 'damage_viscosity' cannot be negative!");
else if (_one_on_damage_eta[i] > 0.0)
_one_on_damage_eta[i] = 1.0 / _one_on_damage_eta[i];
}
// Damage-Plasticity structure
if (_has_plasticity)
_damage_plasticity = new damage_plasticity();
}
void
LynxDamageDeformation::initializeQpDeformation()
{
// Initialize yield derivative
_dyield_dp_tr = 0.0;
_dyield_dq_tr = 0.0;
LynxDeformationBase::initializeQpDeformation();
}
void
LynxDamageDeformation::plasticCorrection(Real & pressure, RankTwoTensor & stress_dev)
{
Real eqv_stress = std::sqrt(1.5) * stress_dev.L2norm();
RankTwoTensor flow_dir = (eqv_stress != 0.0) ? stress_dev / eqv_stress : RankTwoTensor();
computeDamageProperties(pressure, eqv_stress);
// Check wether the yield is capped
if (_damage_plasticity->_p_cr == 0.0)
{
// No capped yield - only deviatoric correction
_plastic_yield_function[_qp] = computePlasticityYield(pressure, eqv_stress);
// Plastic correction
if (_plastic_yield_function[_qp] > 0.0)
{
Real plastic_incr = plasticIncrement(pressure, eqv_stress);
_plastic_strain_incr[_qp] = 1.5 * plastic_incr * flow_dir;
stress_dev -= 3.0 * _G[_qp] * plastic_incr * flow_dir;
_elastic_strain[_qp] -= _plastic_strain_incr[_qp];
// Update yield
_plastic_yield_function[_qp] -= 3.0 * _G[_qp] * plastic_incr;
}
}
else
{
// Capped yield
Real yield_squared = computeConvexPlasticityYield2(pressure, eqv_stress);
_plastic_yield_function[_qp] =
(yield_squared > 0.0) ? std::sqrt(yield_squared) : -std::sqrt(-yield_squared);
if (_plastic_yield_function[_qp] > 0.0)
{
Real vol_plastic_incr = 0.0, eqv_plastic_incr = 0.0;
Real rho_0 = convexPlasticIncrement(vol_plastic_incr, eqv_plastic_incr);
_plastic_strain_incr[_qp] = 1.5 * eqv_plastic_incr * flow_dir;
_plastic_strain_incr[_qp].addIa(-vol_plastic_incr / 3.0);
pressure -= _K[_qp] * vol_plastic_incr;
stress_dev -= 3.0 * _G[_qp] * eqv_plastic_incr * flow_dir;
eqv_stress = std::sqrt(1.5) * stress_dev.L2norm();
_elastic_strain[_qp] -= _plastic_strain_incr[_qp];
// Update yield
_plastic_yield_function[_qp] =
std::sqrt(Utility::pow<2>(pressure - _damage_plasticity->_p_r) +
Utility::pow<2>(eqv_stress - _damage_plasticity->_q_r)) -
rho_0;
}
}
}
void
LynxDamageDeformation::damageCorrection()
{
// Get flow direction
RankTwoTensor stress_dev = _stress[_qp].deviatoric();
Real eqv_stress = std::sqrt(1.5) * stress_dev.doubleContraction(stress_dev);
RankTwoTensor flow_direction = (eqv_stress != 0.0) ? stress_dev / eqv_stress : RankTwoTensor();
Real xi = strainRatio(_elastic_strain[_qp]);
// Damage stress
RankTwoTensor damaged_stress =
_damage_plasticity->_gamma * (xi - 2.0 * _damage_plasticity->_xi0) * _elastic_strain[_qp];
damaged_stress.addIa(_damage_plasticity->_gamma * _elastic_strain[_qp].L2norm());
// Correct stress
_stress[_qp] -= _damage[_qp] * damaged_stress;
// Damage rate
if ((_plastic_yield_function[_qp] > 0.0))
_damage_rate[_qp] = _damage_plasticity->_eta_d * _plastic_yield_function[_qp];
else
_damage_rate[_qp] = 0.0;
// Off diagonal components
_dstress_ddamage[_qp] = -damaged_stress;
_ddamage_rate_dstrain[_qp] =
_damage_plasticity->_eta_d * 3.0 * _G[_qp] * _dyield_dq_tr * flow_direction;
_ddamage_rate_dstrain[_qp].addIa(-_damage_plasticity->_eta_d * _K[_qp] * _dyield_dp_tr);
}
RankFourTensor
LynxDamageDeformation::damageTangentOperator(const RankFourTensor & tme)
{
// Build damage correction to the elasticity tensor
Real xi = strainRatio(_elastic_strain[_qp]);
RankTwoTensor e = (_elastic_strain[_qp].L2norm() != 0.0)
? _elastic_strain[_qp] / _elastic_strain[_qp].L2norm()
: RankTwoTensor();
RankFourTensor damaged_tensor =
_damage_plasticity->_gamma *
((xi - 2.0 * _damage_plasticity->_xi0) * _identity_four + e.outerProduct(_identity_two) +
_identity_two.outerProduct(e) - xi * e.outerProduct(e));
RankFourTensor damage_operator = _damage[_qp] * damaged_tensor * tme;
if ((_damage_rate[_qp] > 0.0) && (_damage_old[_qp] != 1.0) &&
(_damage_rate[_qp] < (1.0 - _damage_old[_qp]) / _dt))
damage_operator -= _dstress_ddamage[_qp].outerProduct(_ddamage_rate_dstrain[_qp]) * _dt;
return damage_operator;
}
Real
LynxDamageDeformation::computePlasticityYield(const Real & pressure, const Real & eqv_stress)
{
return eqv_stress - _damage_plasticity->_alpha0 * pressure - _damage_plasticity->_k0;
}
Real
LynxDamageDeformation::plasticIncrement(const Real & /*pressure*/, const Real & eqv_stress)
{
Real eqv_p_strain_incr = 0.0;
Real vp_correction = 1.0;
eqv_p_strain_incr = _plastic_yield_function[_qp] / (3.0 * _G[_qp]);
// Viscoplastic correction
if (_damage_plasticity->_eta_p != 0.0)
{
vp_correction = (3.0 * _G[_qp]) * _dt * _damage_plasticity->_eta_p /
(1.0 + 3.0 * _G[_qp] * _dt * _damage_plasticity->_eta_p);
eqv_p_strain_incr *= vp_correction;
}
// Update yield
_plastic_yield_function[_qp] -= (3.0 * _G[_qp]) * eqv_p_strain_incr;
// Tangent operator
if (_fe_problem.currentlyComputingJacobian())
{
_stress_corr_p =
(eqv_stress != 0.0) ? (eqv_stress - 3.0 * _G[_qp] * eqv_p_strain_incr) / eqv_stress : 1.0;
_dp_dp_tr_p = 1.0;
_dp_dq_tr_p = 0.0;
_dq_dp_tr_p = _damage_plasticity->_alpha0 * vp_correction;
_dq_dq_tr_p = 1.0 - vp_correction;
// Update yield derivatives
_dyield_dp_tr = _dq_dp_tr_p - _damage_plasticity->_alpha0 * _dp_dp_tr_p;
_dyield_dq_tr = _dq_dq_tr_p - _damage_plasticity->_alpha0 * _dp_dq_tr_p;
}
return eqv_p_strain_incr;
}
Real
LynxDamageDeformation::computeConvexPlasticityYield2(const Real & pressure, const Real & eqv_stress)
{
if ((pressure == 0.0) && (eqv_stress == 0.0))
return 0.0;
updateDamageConvexParameters(pressure, eqv_stress);
return Utility::pow<2>(eqv_stress) - _damage_plasticity->_alpha2 *
Utility::pow<2>(pressure + _damage_plasticity->_p_k) *
((0.0 < pressure + _damage_plasticity->_p_k) -
(pressure + _damage_plasticity->_p_k < 0.0));
}
Real
LynxDamageDeformation::computeConvexPlasticityYield2(const Real & rho)
{
Real p = _damage_plasticity->_p_r + rho * _damage_plasticity->_rp;
Real q = _damage_plasticity->_q_r + rho * _damage_plasticity->_rq;
return computeConvexPlasticityYield2(p, q);
}
Real
LynxDamageDeformation::convexPlasticIncrement(Real & vol_plastic_incr, Real & eqv_plastic_incr)
{
Real vp_correction = 1.0;
// Find projection on convex yield
Real rho_neg = 0.0;
Real rho_pos = _damage_plasticity->_rho_tr;
Real rho_0 = getConvexProjection(rho_neg, rho_pos);
// Update projections
Real p_0 = _damage_plasticity->_p_r + rho_0 * _damage_plasticity->_rp;
Real q_0 = _damage_plasticity->_q_r + rho_0 * _damage_plasticity->_rq;
// Plastic strain
vol_plastic_incr = (_damage_plasticity->_p_tr - p_0) / _K[_qp];
eqv_plastic_incr = (_damage_plasticity->_q_tr - q_0) / (3.0 * _G[_qp]);
// Viscoplastic correction
if (_damage_plasticity->_eta_p != 0.0)
{
Real F_tr = _damage_plasticity->_rho_tr - rho_0;
Real delta_p = std::sqrt(Utility::pow<2>(vol_plastic_incr) + Utility::pow<2>(eqv_plastic_incr));
vp_correction = (F_tr * _damage_plasticity->_eta_p * _dt / delta_p) /
(1.0 + F_tr * _damage_plasticity->_eta_p * _dt / delta_p);
vol_plastic_incr *= vp_correction;
eqv_plastic_incr *= vp_correction;
}
// Tangent operator
if (_fe_problem.currentlyComputingJacobian())
{
_stress_corr_p = (_damage_plasticity->_q_tr != 0.0)
? (_damage_plasticity->_q_tr -
3.0 * _G[_qp] * eqv_plastic_incr) / _damage_plasticity->_q_tr
: 1.0;
Real dF2_dp0 = dConvexPlasticYield2_dp(p_0, q_0) / dConvexPlasticYield2(rho_0);
Real dF2_dq0 = dConvexPlasticYield2_dq(p_0, q_0) / dConvexPlasticYield2(rho_0);
// _dp_dp_tr_p =
// _dp_r_dp_tr + (1.0 - vp_correction) + vp_correction * rho_0 / _rho_tr * dF2_dq0 * _rq;
// _dp_dq_tr_p = _dp_r_dq_tr - vp_correction * rho_0 / _rho_tr * dF2_dq0 * _rp;
// _dq_dp_tr_p = -vp_correction * rho_0 / _rho_tr * dF2_dp0 * _rq;
// _dq_dq_tr_p = (1.0 - vp_correction) + vp_correction * rho_0 / _rho_tr * dF2_dp0 * _rp;
_dp_dp_tr_p = (1.0 - vp_correction) + vp_correction * rho_0 / _damage_plasticity->_rho_tr *
dF2_dq0 * _damage_plasticity->_rq;
_dp_dq_tr_p =
-vp_correction * rho_0 / _damage_plasticity->_rho_tr * dF2_dq0 * _damage_plasticity->_rp;
_dq_dp_tr_p =
-vp_correction * rho_0 / _damage_plasticity->_rho_tr * dF2_dp0 * _damage_plasticity->_rq;
_dq_dq_tr_p = (1.0 - vp_correction) + vp_correction * rho_0 / _damage_plasticity->_rho_tr *
dF2_dp0 * _damage_plasticity->_rp;
// Update yield derivatives
Real rho = (1.0 - vp_correction) * _damage_plasticity->_rho_tr + vp_correction * rho_0;
_dyield_dp_tr = _damage_plasticity->_rp * (1.0 - rho_0 / rho * dF2_dp0) * _dp_dp_tr_p +
_damage_plasticity->_rq * (1.0 - rho_0 / rho * dF2_dq0) * _dq_dp_tr_p;
_dyield_dq_tr = _damage_plasticity->_rp * (1.0 - rho_0 / rho * dF2_dp0) * _dp_dq_tr_p +
_damage_plasticity->_rq * (1.0 - rho_0 / rho * dF2_dq0) * _dq_dq_tr_p;
}
return rho_0;
}
void
LynxDamageDeformation::computeDamageProperties(const Real & pressure, const Real & eqv_stress)
{
updateDamageParameters();
_damage_plasticity->_alpha0 = std::sqrt(2.0) * _G[_qp] / _K[_qp] *
std::sqrt((3.0 - Utility::pow<2>(_damage_plasticity->_xi0)) /
Utility::pow<2>(_damage_plasticity->_xi0));
// Properties for convex yield
if (_damage_plasticity->_p_cr != 0.0)
{
// Pressure to fake cohesion
_damage_plasticity->_p_k = _damage_plasticity->_k0 / _damage_plasticity->_alpha0;
// Trial pressure - deviatoric stress
_damage_plasticity->_p_tr = pressure;
_damage_plasticity->_q_tr = eqv_stress;
// Reference point for convex yield
_damage_plasticity->_p_r = convexReferencePressure();
_damage_plasticity->_q_r = 0.0;
// Trial distance
_damage_plasticity->_rho_tr = std::sqrt(Utility::pow<2>(pressure - _damage_plasticity->_p_r) +
Utility::pow<2>(eqv_stress - _damage_plasticity->_q_r));
// Projection direction
_damage_plasticity->_rp = (_damage_plasticity->_rho_tr != 0.0) ?
(_damage_plasticity->_p_tr - _damage_plasticity->_p_r) / _damage_plasticity->_rho_tr : 0.0;
_damage_plasticity->_rq = (_damage_plasticity->_rho_tr != 0.0) ?
(_damage_plasticity->_q_tr - _damage_plasticity->_q_r) / _damage_plasticity->_rho_tr : 0.0;
}
}
void
LynxDamageDeformation::updateDamageParameters()
{
Real sin_phi = std::sin(averageProperty(_friction_angle) * libMesh::pi / 180.0);
Real xi0 = -std::sqrt(3.0) / std::sqrt(1.0 + 1.5 * Utility::pow<2>(_K[_qp] / _G[_qp] * sin_phi));
Real porous_coeff =
averageProperty(_porous_coeff) + averageProperty(_porous_coeff_linear) * _porosity[_qp];
Real p_cr = (porous_coeff != 0.0) ? _K[_qp] * (std::sqrt(3.0) + xi0) / (3.0 * porous_coeff) : 0.0;
Real k0 = std::sqrt(3.0) * averageProperty(_cohesion) *
std::cos(averageProperty(_friction_angle) * libMesh::pi / 180.0);
_damage_plasticity->fill(xi0,
averageProperty(_damage_modulus),
p_cr,
k0,
averageProperty(_one_on_plastic_eta),
averageProperty(_one_on_damage_eta));
}
void
LynxDamageDeformation::updateDamageConvexParameters(const Real & pressure, const Real & eqv_stress)
{
Real pq_term =
(pressure != 0.0)
? 1.0 / (1.0 + 0.5 * Utility::pow<2>(_K[_qp] * eqv_stress / (_G[_qp] * pressure)))
: 0.0;
_damage_plasticity->_xi_cr =
(pressure > 0.0)
? _damage_plasticity->_xi0 - (std::sqrt(3.0) + _damage_plasticity->_xi0) * pressure /
_damage_plasticity->_p_cr * pq_term
: _damage_plasticity->_xi0;
_damage_plasticity->_alpha2 = (_damage_plasticity->_xi_cr != 0.0)
? 2.0 * Utility::pow<2>(_G[_qp] / _K[_qp]) *
(3.0 - Utility::pow<2>(_damage_plasticity->_xi_cr)) /
Utility::pow<2>(_damage_plasticity->_xi_cr)
: 0.0;
_damage_plasticity->_dxi_cr_dp = (pressure != 0.0)
? -(_damage_plasticity->_xi0 - _damage_plasticity->_xi_cr) /
pressure * (3.0 - 2.0 * pq_term)
: 0.0;
_damage_plasticity->_dxi_cr_dq =
(eqv_stress != 0.0) ? 2.0 * (_damage_plasticity->_xi0 - _damage_plasticity->_xi_cr) /
eqv_stress * (1.0 - pq_term)
: 0.0;
_damage_plasticity->_dalpha2_dxi_cr =
(_damage_plasticity->_xi_cr != 0.0)
? -12.0 * Utility::pow<2>(_G[_qp] / _K[_qp]) / Utility::pow<3>(_damage_plasticity->_xi_cr)
: 0.0;
}
Real
LynxDamageDeformation::convexReferencePressure()
{
// Real p_proj =
// (1.0 - Utility::pow<2>(_damage_plasticity->_alpha0) * _K[_qp] /
// (3.0 * _G[_qp] + Utility::pow<2>(_damage_plasticity->_alpha0) * _K[_qp])) *
// _damage_plasticity->_p_tr +
// _damage_plasticity->_alpha0 * _K[_qp] * _damage_plasticity->_q_tr /
// (3.0 * _G[_qp] + Utility::pow<2>(_damage_plasticity->_alpha0) * _K[_qp]);
Real p_proj = _damage_plasticity->_q_tr / _damage_plasticity->_alpha0 - _damage_plasticity->_p_k;
if (_damage_plasticity->_q_tr == 0.0)
return _damage_plasticity->_p_tr;
else if (p_proj < -_damage_plasticity->_p_k)
return -_damage_plasticity->_p_k;
else if (p_proj > _damage_plasticity->_p_cr)
return 2.0 * _damage_plasticity->_p_cr / 3.0;
else
return p_proj;
}
Real
LynxDamageDeformation::dConvexPlasticYield2(const Real & rho)
{
Real p = _damage_plasticity->_p_r + rho * _damage_plasticity->_rp;
Real q = _damage_plasticity->_q_r + rho * _damage_plasticity->_rq;
return dConvexPlasticYield2_dp(p, q) * _damage_plasticity->_rp +
dConvexPlasticYield2_dq(p, q) * _damage_plasticity->_rq;
}
Real
LynxDamageDeformation::dConvexPlasticYield2_dp(const Real & pressure, const Real & eqv_stress)
{
if ((pressure == 0.0) && (eqv_stress == 0.0))
return 0.0;
updateDamageConvexParameters(pressure, eqv_stress);
return -(_damage_plasticity->_dalpha2_dxi_cr * _damage_plasticity->_dxi_cr_dp *
(pressure + _damage_plasticity->_p_k) +
2.0 * _damage_plasticity->_alpha2) *
(pressure + _damage_plasticity->_p_k) *
((0.0 < pressure + _damage_plasticity->_p_k) -
(pressure + _damage_plasticity->_p_k < 0.0));
}
Real
LynxDamageDeformation::dConvexPlasticYield2_dq(const Real & pressure, const Real & eqv_stress)
{
if ((pressure == 0.0) && (eqv_stress == 0.0))
return 0.0;
updateDamageConvexParameters(pressure, eqv_stress);
return 2.0 * eqv_stress -
_damage_plasticity->_dalpha2_dxi_cr * _damage_plasticity->_dxi_cr_dq *
Utility::pow<2>(
pressure +
_damage_plasticity->_p_k); // *
// ((0.0 < pressure + _damage_plasticity->_p_k) -
// (pressure + _damage_plasticity->_p_k < 0.0));
}
Real
LynxDamageDeformation::getConvexProjection(const Real & x1, const Real & x2)
{
// Machine floating-point precision
const Real eps = std::numeric_limits::epsilon();
// Declare some stuff here
Real a = x1, b = x2, c = x2, d, e, fa = computeConvexPlasticityYield2(a),
fb = computeConvexPlasticityYield2(b), fc, p, q, r, s, tol1, xm;
// Chek if x1 and x2 bracket a root
if (fa * fb > 0.0) // fa and fb are of the same sign
throw MooseException("LynxDamageDeformation: in Brent's method, the points x1 and x2 must "
"bracket a root of the function!\n");
fc = fb;
for (unsigned int iter = 0; iter < _itmax; ++iter)
{
if (fb * fc > 0.0) // fb and fc are of the same sign
{
// Rename a, b, c and adjust bounding interval d
c = a;
fc = fa;
e = d = b - a;
}
if (std::abs(fc) < std::abs(fb))
{
a = b;
b = c;
c = a;
fa = fb;
fb = fc;
fc = fa;
}
// Convergence check
tol1 = 2.0 * eps * std::abs(b) + 0.5 * _tol;
xm = 0.5 * (c - b);
if (std::abs(xm) <= tol1 || fb == 0.0) // Exit of the algorithm
return b;
if (std::abs(e) >= tol1 && std::abs(fa) > std::abs(fb))
{
s = fb / fa;
if (a == c)
{
p = 2.0 * xm * s;
q = 1.0 - s;
}
else
{
q = fa / fc;
r = fb / fc;
p = s * (2.0 * xm * q * (q - r) - (b - a) * (r - 1.0));
q = (q - 1.0) * (r - 1.0) * (s - 1.0);
}
// Check wether in bounds
if (p > 0.0)
q = -q;
p = std::abs(p);
Real min1 = 3.0 * xm * q - std::abs(tol1 * q);
Real min2 = std::abs(e * q);
if (2.0 * p < (min1 < min2 ? min1 : min2))
{
// Accept interpolation
e = d;
d = p / q;
}
else
{
// Interpolation failed, use bisection
d = xm;
e = d;
}
}
else
{
// Bounds decreasing too slowly, use bisection
d = xm;
e = d;
}
// Move last guess to a
a = b;
fa = fb;
// Evaluate new trial root
if (std::abs(d) > tol1)
b += d;
else
b += (xm < 0 ? -std::abs(tol1) : std::abs(tol1));
fb = computeConvexPlasticityYield2(b);
}
throw MooseException(
"LynxDamageDeformation: maximum number of iterations exceeded in solveBrent!");
}
Real
LynxDamageDeformation::strainRatio(const RankTwoTensor & elastic_strain)
{
const Real strain_v = elastic_strain.trace();
const Real strain_norm = elastic_strain.L2norm();
if (strain_norm != 0.0)
return strain_v / strain_norm;
else
return -std::sqrt(3.0);
}
RankTwoTensor
LynxDamageDeformation::rotatedElasticStrain(const RankTwoTensor & elastic_strain)
{
const Real strain_v = elastic_strain.trace();
RankTwoTensor strain_rot = spinRotation(elastic_strain.deviatoric());
strain_rot.addIa(strain_v / 3.0);
return strain_rot;
}