RankFourTensor TensorMechanicsPlasticMeanCapTC::consistentTangentOperator(const RankTwoTensor & trial_stress, Real intnl_old, const RankTwoTensor & stress, Real intnl, const RankFourTensor & E_ijkl, const std::vector<Real> & cumulative_pm) const { if (!_use_custom_cto) return TensorMechanicsPlasticModel::consistentTangentOperator(trial_stress, intnl_old, stress, intnl, E_ijkl, cumulative_pm); Real df_dq; Real alpha; if (trial_stress.trace() >= tensile_strength(intnl_old)) { df_dq = -dtensile_strength(intnl); alpha = 1.0; } else { df_dq = dcompressive_strength(intnl); alpha = -1.0; } RankTwoTensor elas; for (unsigned int i = 0; i < 3; ++i) for (unsigned int j = 0; j < 3; ++j) for (unsigned int k = 0; k < 3; ++k) elas(i, j) += E_ijkl(i, j, k, k); const Real hw = -df_dq + alpha * elas.trace(); return E_ijkl - alpha / hw * elas.outerProduct(elas); }
RankTwoTensor TensorMechanicsPlasticTensile::dyieldFunction_dstress(const RankTwoTensor & stress, Real /*intnl*/) const { Real mean_stress = stress.trace() / 3.0; RankTwoTensor dmean_stress = stress.dtrace() / 3.0; Real sin3Lode = stress.sin3Lode(_lode_cutoff, 0); if (sin3Lode <= _sin3tt) { // the non-edge-smoothed version std::vector<Real> eigvals; std::vector<RankTwoTensor> deigvals; stress.dsymmetricEigenvalues(eigvals, deigvals); Real denom = std::sqrt(smooth(stress) + Utility::pow<2>(eigvals[2] - mean_stress)); return dmean_stress + (0.5 * dsmooth(stress) * dmean_stress + (eigvals[2] - mean_stress) * (deigvals[2] - dmean_stress)) / denom; } else { // the edge-smoothed version Real kk = _aaa + _bbb * sin3Lode + _ccc * Utility::pow<2>(sin3Lode); RankTwoTensor dkk = (_bbb + 2.0 * _ccc * sin3Lode) * stress.dsin3Lode(_lode_cutoff); Real sibar2 = stress.secondInvariant(); RankTwoTensor dsibar2 = stress.dsecondInvariant(); Real denom = std::sqrt(smooth(stress) + sibar2 * Utility::pow<2>(kk)); return dmean_stress + (0.5 * dsmooth(stress) * dmean_stress + 0.5 * dsibar2 * Utility::pow<2>(kk) + sibar2 * kk * dkk) / denom; } }
Real TensorMechanicsPlasticDruckerPrager::yieldFunction(const RankTwoTensor & stress, Real intnl) const { Real aaa; Real bbb; bothAB(intnl, aaa, bbb); return std::sqrt(stress.secondInvariant()) + stress.trace() * bbb - aaa; }
Real TensorMechanicsPlasticDruckerPrager::dyieldFunction_dintnl(const RankTwoTensor & stress, Real intnl) const { Real daaa; Real dbbb; dbothAB(intnl, daaa, dbbb); return stress.trace() * dbbb - daaa; }
void TensorMechanicsPlasticMeanCapTC::activeConstraints(const std::vector<Real> & f, const RankTwoTensor & stress, Real intnl, const RankFourTensor & Eijkl, std::vector<bool> & act, RankTwoTensor & returned_stress) const { act.assign(1, false); if (f[0] <= _f_tol) { returned_stress = stress; return; } const Real tr = stress.trace(); const Real t_str = tensile_strength(intnl); Real str; Real dirn; if (tr >= t_str) { str = t_str; dirn = 1.0; } else { str = compressive_strength(intnl); dirn = -1.0; } RankTwoTensor n; // flow direction for (unsigned i = 0; i < 3; ++i) for (unsigned j = 0; j < 3; ++j) for (unsigned k = 0; k < 3; ++k) n(i, j) += dirn * Eijkl(i, j, k, k); // returned_stress = stress - gamma*n // and taking the trace of this and using // Tr(returned_stress) = str, gives // gamma = (Tr(stress) - str)/Tr(n) Real gamma = (stress.trace() - str) / n.trace(); for (unsigned i = 0; i < 3; ++i) for (unsigned j = 0; j < 3; ++j) returned_stress(i, j) = stress(i, j) - gamma * n(i, j); act[0] = true; }
Real TensorMechanicsPlasticOrthotropic::yieldFunction(const RankTwoTensor & stress, Real intnl) const { const RankTwoTensor j2prime = _l1 * stress; const RankTwoTensor j3prime = _l2 * stress; return _b * stress.trace() + std::pow(std::pow(-j2prime.generalSecondInvariant(), 3.0 / 2.0) - j3prime.det(), 1.0 / 3.0) - yieldStrength(intnl); }
RankFourTensor TensorMechanicsPlasticTensile::dflowPotential_dstress(const RankTwoTensor & stress, const Real & intnl) const { Real mean_stress = stress.trace()/3.0; RankTwoTensor dmean_stress = stress.dtrace()/3.0; Real sin3Lode = stress.sin3Lode(_lode_cutoff, 0); if (sin3Lode <= _sin3tt) { // the non-edge-smoothed version std::vector<Real> eigvals; std::vector<RankTwoTensor> deigvals; std::vector<RankFourTensor> d2eigvals; stress.dsymmetricEigenvalues(eigvals, deigvals); stress.d2symmetricEigenvalues(d2eigvals); Real denom = std::sqrt(_small_smoother2 + std::pow(eigvals[2] - mean_stress, 2)); RankFourTensor dr_dstress = (eigvals[2] - mean_stress)*d2eigvals[2]/denom; for (unsigned i = 0 ; i < 3 ; ++i) for (unsigned j = 0 ; j < 3 ; ++j) for (unsigned k = 0 ; k < 3 ; ++k) for (unsigned l = 0 ; l < 3 ; ++l) dr_dstress(i, j, k, l) += (1 - std::pow((eigvals[2] - mean_stress)/denom, 2))*(deigvals[2](i, j) - dmean_stress(i, j))*(deigvals[2](k, l) - dmean_stress(k, l))/denom; return dr_dstress; } else { // the edge-smoothed version RankTwoTensor dsin3Lode = stress.dsin3Lode(_lode_cutoff); Real kk = _aaa + _bbb*sin3Lode + _ccc*std::pow(sin3Lode, 2); RankTwoTensor dkk = (_bbb + 2*_ccc*sin3Lode)*dsin3Lode; RankFourTensor d2kk = (_bbb + 2*_ccc*sin3Lode)*stress.d2sin3Lode(_lode_cutoff); for (unsigned i = 0 ; i < 3 ; ++i) for (unsigned j = 0 ; j < 3 ; ++j) for (unsigned k = 0 ; k < 3 ; ++k) for (unsigned l = 0 ; l < 3 ; ++l) d2kk(i, j, k, l) += 2*_ccc*dsin3Lode(i, j)*dsin3Lode(k, l); Real sibar2 = stress.secondInvariant(); RankTwoTensor dsibar2 = stress.dsecondInvariant(); RankFourTensor d2sibar2 = stress.d2secondInvariant(); Real denom = std::sqrt(_small_smoother2 + sibar2*std::pow(kk, 2)); RankFourTensor dr_dstress = (0.5*d2sibar2*std::pow(kk, 2) + sibar2*kk*d2kk)/denom; for (unsigned i = 0 ; i < 3 ; ++i) for (unsigned j = 0 ; j < 3 ; ++j) for (unsigned k = 0 ; k < 3 ; ++k) for (unsigned l = 0 ; l < 3 ; ++l) { dr_dstress(i, j, k, l) += (dsibar2(i, j)*dkk(k, l)*kk + dkk(i, j)*dsibar2(k, l)*kk + sibar2*dkk(i, j)*dkk(k, l))/denom; dr_dstress(i, j, k, l) -= (0.5*dsibar2(i, j)*std::pow(kk, 2) + sibar2*kk*dkk(i, j))*(0.5*dsibar2(k, l)*std::pow(kk, 2) + sibar2*kk*dkk(k, l))/std::pow(denom, 3); } return dr_dstress; } }
RankTwoTensor TensorMechanicsPlasticMeanCapTC::df_dsig(const RankTwoTensor & stress, Real intnl) const { const Real tr = stress.trace(); const Real t_str = tensile_strength(intnl); if (tr >= t_str) return stress.dtrace(); const Real c_str = compressive_strength(intnl); if (tr <= c_str) return -stress.dtrace(); return - std::cos(M_PI * (tr - c_str) / (t_str - c_str)) * stress.dtrace(); }
RankFourTensor TensorMechanicsPlasticMeanCapTC::dflowPotential_dstress(const RankTwoTensor & stress, Real intnl) const { const Real tr = stress.trace(); const Real t_str = tensile_strength(intnl); if (tr >= t_str) return RankFourTensor(); const Real c_str = compressive_strength(intnl); if (tr <= c_str) return RankFourTensor(); return M_PI / (t_str - c_str) * std::sin(M_PI * (tr - c_str) / (t_str - c_str)) * stress.dtrace().outerProduct(stress.dtrace()); }
Real TensorMechanicsPlasticMeanCapTC::hardPotential(const RankTwoTensor & stress, Real intnl) const { // This is the key for this whole class! const Real tr = stress.trace(); const Real t_str = tensile_strength(intnl); if (tr >= t_str) return -1.0; // this will serve to *increase* the internal parameter (so internal parameter will be a measure of volumetric strain) const Real c_str = compressive_strength(intnl); if (tr <= c_str) return 1.0; // this will serve to *decrease* the internal parameter (so internal parameter will be a measure of volumetric strain) return std::cos(M_PI * (tr - c_str) / (t_str - c_str)); // this interpolates C2 smoothly between 1 and -1 }
Real TensorMechanicsPlasticTensile::smooth(const RankTwoTensor & stress) const { Real smoother2 = _small_smoother2; if (_tip_scheme == "cap") { Real x = stress.trace() / 3.0 - _cap_start; Real p = 0; if (x > 0) p = x * (1 - std::exp(-_cap_rate * x)); smoother2 += Utility::pow<2>(p); } return smoother2; }
Real TensorMechanicsPlasticMeanCapTC::dhardPotential_dintnl(const RankTwoTensor & stress, Real intnl) const { const Real tr = stress.trace(); const Real t_str = tensile_strength(intnl); if (tr >= t_str) return 0.0; const Real c_str = compressive_strength(intnl); if (tr <= c_str) return 0.0; const Real dt = dtensile_strength(intnl); const Real dc = dcompressive_strength(intnl); return - std::sin(M_PI * (tr - c_str) / (t_str - c_str)) * M_PI / std::pow(t_str - c_str, 2) * ((tr - t_str) * dc - (tr - c_str) * dt); }
Real TensorMechanicsPlasticMeanCapTC::dyieldFunction_dintnl(const RankTwoTensor & stress, Real intnl) const { const Real tr = stress.trace(); const Real t_str = tensile_strength(intnl); if (tr >= t_str) return -dtensile_strength(intnl); const Real c_str = compressive_strength(intnl); if (tr <= c_str) return dcompressive_strength(intnl); const Real dt = dtensile_strength(intnl); const Real dc = dcompressive_strength(intnl); return (dc - dt) / M_PI * std::sin(M_PI * (tr - c_str) / (t_str - c_str)) + 1.0 / (t_str - c_str) * std::cos(M_PI * (tr - c_str) / (t_str - c_str)) * ((tr - c_str) * dt - (tr - t_str) * dc ); }
//Obtain deviatoric stress tensor RankTwoTensor FiniteStrainPlasticMaterial::getSigDev(RankTwoTensor sig) { // Real sig_eqv,sij; RankTwoTensor identity; RankTwoTensor sig_dev; for (int i=0; i<3; i++) identity(i,i)=1.0; sig_dev=sig-identity*sig.trace()/3.0; return sig_dev; }
Real TensorMechanicsPlasticMeanCapTC::yieldFunction(const RankTwoTensor & stress, Real intnl) const { const Real tr = stress.trace(); const Real t_str = tensile_strength(intnl); if (tr >= t_str) return tr - t_str; const Real c_str = compressive_strength(intnl); if (tr <= c_str) return -(tr - c_str); // the following is zero at tr = t_str, and at tr = c_str // it also has derivative = 1 at tr = t_str, and derivative = -1 at tr = c_str // it also has second derivative = 0, at these points. // This makes the complete yield function C2 continuous. return (c_str - t_str) / M_PI * std::sin(M_PI * (tr - c_str) / (t_str - c_str)); }
Real TensorMechanicsPlasticTensile::dsmooth(const RankTwoTensor & stress) const { Real dsmoother2 = 0; if (_tip_scheme == "cap") { Real x = stress.trace() / 3.0 - _cap_start; Real p = 0; Real dp_dx = 0; if (x > 0) { p = x * (1 - std::exp(-_cap_rate * x)); dp_dx = (1 - std::exp(-_cap_rate * x)) + x * _cap_rate * std::exp(-_cap_rate * x); } dsmoother2 += 2.0 * p * dp_dx; } return dsmoother2; }
Real TensorMechanicsPlasticTensile::yieldFunction(const RankTwoTensor & stress, const Real & intnl) const { Real mean_stress = stress.trace()/3.0; Real sin3Lode = stress.sin3Lode(_lode_cutoff, 0); if (sin3Lode <= _sin3tt) { // the non-edge-smoothed version std::vector<Real> eigvals; stress.symmetricEigenvalues(eigvals); return mean_stress + std::sqrt(_small_smoother2 + std::pow(eigvals[2] - mean_stress, 2)) - tensile_strength(intnl); } else { // the edge-smoothed version Real kk = _aaa + _bbb*sin3Lode + _ccc*std::pow(sin3Lode, 2); Real sibar2 = stress.secondInvariant(); return mean_stress + std::sqrt(_small_smoother2 + sibar2*std::pow(kk, 2)) - tensile_strength(intnl); } }
Real TensorMechanicsPlasticTensile::d2smooth(const RankTwoTensor & stress) const { Real d2smoother2 = 0; if (_tip_scheme == "cap") { Real x = stress.trace()/3.0 - _cap_start; Real p = 0; Real dp_dx = 0; Real d2p_dx2 = 0; if (x > 0) { p = x*(1 - std::exp(-_cap_rate*x)); dp_dx = (1 - std::exp(-_cap_rate*x)) + x*_cap_rate*std::exp(-_cap_rate*x); d2p_dx2 = 2*_cap_rate*std::exp(-_cap_rate*x) - x*std::pow(_cap_rate, 2)*std::exp(-_cap_rate*x); } d2smoother2 += 2*std::pow(dp_dx, 2) + 2*p*d2p_dx2; } return d2smoother2; }
void CappedDruckerPragerCosseratStressUpdate::setStressAfterReturn(const RankTwoTensor & stress_trial, Real p_ok, Real q_ok, Real /*gaE*/, const std::vector<Real> & /*intnl*/, const yieldAndFlow & /*smoothed_q*/, const RankFourTensor & /*Eijkl*/, RankTwoTensor & stress) const { // symm_stress is the symmetric part of the stress tensor. // symm_stress = (s_ij+s_ji)/2 + de_ij tr(stress) / 3 // = q / q_trial * (s_ij^trial+s_ji^trial)/2 + de_ij p / 3 // = q / q_trial * (symm_stress_ij^trial - de_ij tr(stress^trial) / 3) + de_ij p / 3 const Real p_trial = stress_trial.trace(); RankTwoTensor symm_stress = RankTwoTensor(RankTwoTensor::initIdentity) / 3.0 * (p_ok - (_in_q_trial == 0.0 ? 0.0 : p_trial * q_ok / _in_q_trial)); if (_in_q_trial > 0) symm_stress += q_ok / _in_q_trial * 0.5 * (stress_trial + stress_trial.transpose()); stress = symm_stress + 0.5 * (stress_trial - stress_trial.transpose()); }
RankFourTensor TensorMechanicsPlasticTensile::dflowPotential_dstress(const RankTwoTensor & stress, Real /*intnl*/) const { Real mean_stress = stress.trace() / 3.0; RankTwoTensor dmean_stress = stress.dtrace() / 3.0; Real sin3Lode = stress.sin3Lode(_lode_cutoff, 0); if (sin3Lode <= _sin3tt) { // the non-edge-smoothed version std::vector<Real> eigvals; std::vector<RankTwoTensor> deigvals; std::vector<RankFourTensor> d2eigvals; stress.dsymmetricEigenvalues(eigvals, deigvals); stress.d2symmetricEigenvalues(d2eigvals); Real denom = std::sqrt(smooth(stress) + Utility::pow<2>(eigvals[2] - mean_stress)); Real denom3 = Utility::pow<3>(denom); RankTwoTensor numer_part = deigvals[2] - dmean_stress; RankTwoTensor numer_full = 0.5 * dsmooth(stress) * dmean_stress + (eigvals[2] - mean_stress) * numer_part; Real d2smooth_over_denom = d2smooth(stress) / denom; RankFourTensor dr_dstress = (eigvals[2] - mean_stress) * d2eigvals[2] / denom; for (unsigned i = 0; i < 3; ++i) for (unsigned j = 0; j < 3; ++j) for (unsigned k = 0; k < 3; ++k) for (unsigned l = 0; l < 3; ++l) { dr_dstress(i, j, k, l) += 0.5 * d2smooth_over_denom * dmean_stress(i, j) * dmean_stress(k, l); dr_dstress(i, j, k, l) += numer_part(i, j) * numer_part(k, l) / denom; dr_dstress(i, j, k, l) -= numer_full(i, j) * numer_full(k, l) / denom3; } return dr_dstress; } else { // the edge-smoothed version RankTwoTensor dsin3Lode = stress.dsin3Lode(_lode_cutoff); Real kk = _aaa + _bbb * sin3Lode + _ccc * Utility::pow<2>(sin3Lode); RankTwoTensor dkk = (_bbb + 2.0 * _ccc * sin3Lode) * dsin3Lode; RankFourTensor d2kk = (_bbb + 2.0 * _ccc * sin3Lode) * stress.d2sin3Lode(_lode_cutoff); for (unsigned i = 0; i < 3; ++i) for (unsigned j = 0; j < 3; ++j) for (unsigned k = 0; k < 3; ++k) for (unsigned l = 0; l < 3; ++l) d2kk(i, j, k, l) += 2.0 * _ccc * dsin3Lode(i, j) * dsin3Lode(k, l); Real sibar2 = stress.secondInvariant(); RankTwoTensor dsibar2 = stress.dsecondInvariant(); RankFourTensor d2sibar2 = stress.d2secondInvariant(); Real denom = std::sqrt(smooth(stress) + sibar2 * Utility::pow<2>(kk)); Real denom3 = Utility::pow<3>(denom); Real d2smooth_over_denom = d2smooth(stress) / denom; RankTwoTensor numer_full = 0.5 * dsmooth(stress) * dmean_stress + 0.5 * dsibar2 * kk * kk + sibar2 * kk * dkk; RankFourTensor dr_dstress = (0.5 * d2sibar2 * Utility::pow<2>(kk) + sibar2 * kk * d2kk) / denom; for (unsigned i = 0; i < 3; ++i) for (unsigned j = 0; j < 3; ++j) for (unsigned k = 0; k < 3; ++k) for (unsigned l = 0; l < 3; ++l) { dr_dstress(i, j, k, l) += 0.5 * d2smooth_over_denom * dmean_stress(i, j) * dmean_stress(k, l); dr_dstress(i, j, k, l) += (dsibar2(i, j) * dkk(k, l) * kk + dkk(i, j) * dsibar2(k, l) * kk + sibar2 * dkk(i, j) * dkk(k, l)) / denom; dr_dstress(i, j, k, l) -= numer_full(i, j) * numer_full(k, l) / denom3; } return dr_dstress; } }
bool TensorMechanicsPlasticJ2::returnMap(const RankTwoTensor & trial_stress, Real intnl_old, const RankFourTensor & E_ijkl, Real ep_plastic_tolerance, RankTwoTensor & returned_stress, Real & returned_intnl, std::vector<Real> & dpm, RankTwoTensor & delta_dp, std::vector<Real> & yf, bool & trial_stress_inadmissible) const { if (!(_use_custom_returnMap)) return TensorMechanicsPlasticModel::returnMap(trial_stress, intnl_old, E_ijkl, ep_plastic_tolerance, returned_stress, returned_intnl, dpm, delta_dp, yf, trial_stress_inadmissible); yf.resize(1); Real yf_orig = yieldFunction(trial_stress, intnl_old); yf[0] = yf_orig; if (yf_orig < _f_tol) { // the trial_stress is admissible trial_stress_inadmissible = false; return true; } trial_stress_inadmissible = true; Real mu = E_ijkl(0, 1, 0, 1); // Perform a Newton-Raphson to find dpm when // residual = 3*mu*dpm - trial_equivalent_stress + yieldStrength(intnl_old + dpm) = 0 Real trial_equivalent_stress = yf_orig + yieldStrength(intnl_old); Real residual; Real jac; dpm[0] = 0; unsigned int iter = 0; do { residual = 3.0 * mu * dpm[0] - trial_equivalent_stress + yieldStrength(intnl_old + dpm[0]); jac = 3.0 * mu + dyieldStrength(intnl_old + dpm[0]); dpm[0] += -residual / jac; if (iter > _max_iters) // not converging return false; iter++; } while (residual * residual > _f_tol * _f_tol); // set the returned values yf[0] = 0; returned_intnl = intnl_old + dpm[0]; RankTwoTensor nn = 1.5 * trial_stress.deviatoric() / trial_equivalent_stress; // = dyieldFunction_dstress(trial_stress, intnl_old) = // the normal to the yield surface, at the trial // stress returned_stress = 2.0 / 3.0 * nn * yieldStrength(returned_intnl); returned_stress.addIa(1.0 / 3.0 * trial_stress.trace()); delta_dp = nn * dpm[0]; return true; }
void CappedDruckerPragerCosseratStressUpdate::consistentTangentOperator( const RankTwoTensor & /*stress_trial*/, Real /*p_trial*/, Real /*q_trial*/, const RankTwoTensor & stress, Real /*p*/, Real q, Real gaE, const yieldAndFlow & smoothed_q, const RankFourTensor & Eijkl, bool compute_full_tangent_operator, RankFourTensor & cto) const { if (!compute_full_tangent_operator) { cto = Eijkl; return; } RankFourTensor EAijkl; for (unsigned i = 0; i < _tensor_dimensionality; ++i) for (unsigned j = 0; j < _tensor_dimensionality; ++j) for (unsigned k = 0; k < _tensor_dimensionality; ++k) for (unsigned l = 0; l < _tensor_dimensionality; ++l) { cto(i, j, k, l) = 0.5 * (Eijkl(i, j, k, l) + Eijkl(j, i, k, l)); EAijkl(i, j, k, l) = 0.5 * (Eijkl(i, j, k, l) - Eijkl(j, i, k, l)); } const RankTwoTensor s_over_q = (q == 0.0 ? RankTwoTensor() : (0.5 * (stress + stress.transpose()) - stress.trace() * RankTwoTensor(RankTwoTensor::initIdentity) / 3.0) / q); const RankTwoTensor E_s_over_q = Eijkl.innerProductTranspose(s_over_q); // not symmetric in kl const RankTwoTensor Ekl = RankTwoTensor(RankTwoTensor::initIdentity).initialContraction(Eijkl); // symmetric in kl for (unsigned i = 0; i < _tensor_dimensionality; ++i) for (unsigned j = 0; j < _tensor_dimensionality; ++j) for (unsigned k = 0; k < _tensor_dimensionality; ++k) for (unsigned l = 0; l < _tensor_dimensionality; ++l) { cto(i, j, k, l) -= (i == j) * (1.0 / 3.0) * (Ekl(k, l) * (1.0 - _dp_dpt) + 0.5 * E_s_over_q(k, l) * (-_dp_dqt)); cto(i, j, k, l) -= s_over_q(i, j) * (Ekl(k, l) * (-_dq_dpt) + 0.5 * E_s_over_q(k, l) * (1.0 - _dq_dqt)); } if (smoothed_q.dg[1] != 0.0) { const RankFourTensor Tijab = _Ehost * (gaE / _Epp) * smoothed_q.dg[1] * d2qdstress2(stress); RankFourTensor inv = RankFourTensor(RankFourTensor::initIdentitySymmetricFour) + Tijab; try { inv = inv.transposeMajor().invSymm(); } catch (const MooseException & e) { // Cannot form the inverse, so probably at some degenerate place in stress space. // Just return with the "best estimate" of the cto. mooseWarning("CappedDruckerPragerCosseratStressUpdate: Cannot invert 1+T in consistent " "tangent operator computation at quadpoint ", _qp, " of element ", _current_elem->id()); return; } cto = (cto.transposeMajor() * inv).transposeMajor(); } cto += EAijkl; }
bool TensorMechanicsPlasticMeanCapTC::returnMap(const RankTwoTensor & trial_stress, Real intnl_old, const RankFourTensor & E_ijkl, Real ep_plastic_tolerance, RankTwoTensor & returned_stress, Real & returned_intnl, std::vector<Real> & dpm, RankTwoTensor & delta_dp, std::vector<Real> & yf, bool & trial_stress_inadmissible) const { if (!(_use_custom_returnMap)) return TensorMechanicsPlasticModel::returnMap(trial_stress, intnl_old, E_ijkl, ep_plastic_tolerance, returned_stress, returned_intnl, dpm, delta_dp, yf, trial_stress_inadmissible); yf.resize(1); Real yf_orig = yieldFunction(trial_stress, intnl_old); yf[0] = yf_orig; if (yf_orig < _f_tol) { // the trial_stress is admissible trial_stress_inadmissible = false; return true; } trial_stress_inadmissible = true; // In the following we want to solve // trial_stress - stress = E_ijkl * dpm * r ...... (1) // and either // stress.trace() = tensile_strength(intnl) ...... (2a) // intnl = intnl_old + dpm ...... (3a) // or // stress.trace() = compressive_strength(intnl) ... (2b) // intnl = intnl_old - dpm ...... (3b) // The former (2a and 3a) are chosen if // trial_stress.trace() > tensile_strength(intnl_old) // while the latter (2b and 3b) are chosen if // trial_stress.trace() < compressive_strength(intnl_old) // The variables we want to solve for are stress, dpm // and intnl. We do this using a Newton approach, starting // with stress=trial_stress and intnl=intnl_old and dpm=0 const bool tensile_failure = (trial_stress.trace() >= tensile_strength(intnl_old)); const Real dirn = (tensile_failure ? 1.0 : -1.0); RankTwoTensor n; // flow direction, which is E_ijkl * r for (unsigned i = 0; i < 3; ++i) for (unsigned j = 0; j < 3; ++j) for (unsigned k = 0; k < 3; ++k) n(i, j) += dirn * E_ijkl(i, j, k, k); const Real n_trace = n.trace(); // Perform a Newton-Raphson to find dpm when // residual = trial_stress.trace() - tensile_strength(intnl) - dpm * n.trace() [for tensile_failure=true] // or // residual = trial_stress.trace() - compressive_strength(intnl) - dpm * n.trace() [for tensile_failure=false] Real trial_trace = trial_stress.trace(); Real residual; Real jac; dpm[0] = 0; unsigned int iter = 0; do { if (tensile_failure) { residual = trial_trace - tensile_strength(intnl_old + dpm[0]) - dpm[0] * n_trace; jac = -dtensile_strength(intnl_old + dpm[0]) - n_trace; } else { residual = trial_trace - compressive_strength(intnl_old - dpm[0]) - dpm[0] * n_trace; jac = -dcompressive_strength(intnl_old - dpm[0]) - n_trace; } dpm[0] += -residual/jac; if (iter > _max_iters) // not converging return false; iter++; } while (residual*residual > _f_tol*_f_tol); // set the returned values yf[0] = 0; returned_intnl = intnl_old + dirn * dpm[0]; returned_stress = trial_stress - dpm[0] * n; delta_dp = dpm[0] * dirn * returned_stress.dtrace(); return true; }