// Jacobian for stress update algorithm void FiniteStrainPlasticMaterial::getJac(const RankTwoTensor & sig, const RankFourTensor & E_ijkl, Real flow_incr, RankFourTensor & dresid_dsig) { RankTwoTensor sig_dev, df_dsig, flow_dirn; RankTwoTensor dfi_dft, dfi_dsig; RankFourTensor dft_dsig, dfd_dft, dfd_dsig; Real sig_eqv; Real f1, f2, f3; RankFourTensor temp; sig_dev = sig.deviatoric(); sig_eqv = getSigEqv(sig); df_dsig = dyieldFunction_dstress(sig); flow_dirn = flowPotential(sig); f1 = 3.0 / (2.0 * sig_eqv); f2 = f1 / 3.0; f3 = 9.0 / (4.0 * Utility::pow<3>(sig_eqv)); dft_dsig = f1 * _deltaMixed - f2 * _deltaOuter - f3 * sig_dev.outerProduct(sig_dev); dfd_dsig = dft_dsig; dresid_dsig = E_ijkl.invSymm() + dfd_dsig * flow_incr; }
/** * Get unitary flow tensor in deviatoric direction, modified Cam-Clay */ void RedbackMechMaterialCC::getFlowTensor(const RankTwoTensor & sig, Real q, Real p, Real pc, RankTwoTensor & flow_tensor) { if (pc > 0) pc *= -1; flow_tensor = 3.0 * sig.deviatoric() / (_slope_yield_surface * _slope_yield_surface); flow_tensor.addIa((2.0 * p - pc) / 3.0); //(p > 0 ? 1:-1) // TODO: do we need to normalise? If so, do we need the sqrt(3/2) factor? // flow_tensor /= std::pow(2.0/3.0,0.5)*flow_tensor.L2norm(); }
/** * Get flow tensor in deviatoric direction, modified Cam-Clay */ void RedbackMechMaterialCC::getFlowTensor(const RankTwoTensor & sig, Real /*q*/, Real p, Real /*q_y*/, Real /*p_y*/, Real yield_stress, RankTwoTensor & flow_tensor) { Real pc = -yield_stress; flow_tensor = 3.0 * sig.deviatoric() / (_slope_yield_surface * _slope_yield_surface); flow_tensor.addIa((2.0 * p - pc - 2*_shift_ellipse) / 3.0); }
//Obtain derivative of flow potential w.r.t. stress (plastic flow direction) void FiniteStrainRatePlasticMaterial::getFlowTensor(const RankTwoTensor & sig, Real /*yield_stress*/, RankTwoTensor & flow_tensor) { RankTwoTensor sig_dev; Real sig_eqv, val; sig_eqv = getSigEqv(sig); sig_dev = sig.deviatoric(); val = 0.0; if (sig_eqv > 1e-8) val = 3.0 / (2.0 * sig_eqv); flow_tensor = sig_dev * val; }
//Jacobian for stress update algorithm void FiniteStrainRatePlasticMaterial::getJac(const RankTwoTensor & sig, const RankFourTensor & E_ijkl, Real flow_incr, Real yield_stress, RankFourTensor & dresid_dsig) { unsigned i, j, k ,l; RankTwoTensor sig_dev, flow_tensor, flow_dirn,fij; RankTwoTensor dfi_dft; RankFourTensor dft_dsig, dfd_dft, dfd_dsig, dfi_dsig; Real sig_eqv; Real f1, f2, f3; Real dfi_dseqv; sig_dev = sig.deviatoric(); sig_eqv = getSigEqv(sig); getFlowTensor(sig, yield_stress, flow_tensor); flow_dirn = flow_tensor; dfi_dseqv = _ref_pe_rate * _dt * _exponent * std::pow(macaulayBracket(sig_eqv / yield_stress - 1.0), _exponent - 1.0) / yield_stress; for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j) for (k = 0; k < 3; ++k) for (l = 0; l < 3; ++l) dfi_dsig(i,j,k,l) = flow_dirn(i,j) * flow_dirn(k,l) * dfi_dseqv; //d_flow_increment/d_sig f1 = 0.0; f2 = 0.0; f3 = 0.0; if (sig_eqv > 1e-8) { f1 = 3.0 / (2.0 * sig_eqv); f2 = f1 / 3.0; f3 = 9.0 / (4.0 * std::pow(sig_eqv, 3.0)); } for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j) for (k = 0; k < 3; ++k) for (l = 0; l < 3; ++l) dft_dsig(i,j,k,l) = f1 * deltaFunc(i,k) * deltaFunc(j,l) - f2 * deltaFunc(i,j) * deltaFunc(k,l) - f3 * sig_dev(i,j) * sig_dev(k,l); //d_flow_dirn/d_sig - 2nd part dfd_dsig = dft_dsig; //d_flow_dirn/d_sig dresid_dsig = E_ijkl.invSymm() + dfd_dsig * flow_incr + dfi_dsig; //Jacobian }
RankFourTensor TensorMechanicsPlasticJ2::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 mu = E_ijkl(0, 1, 0, 1); Real h = 3 * mu + dyieldStrength(intnl); RankTwoTensor sij = stress.deviatoric(); Real sII = stress.secondInvariant(); Real equivalent_stress = std::sqrt(3.0 * sII); Real zeta = cumulative_pm[0] / (1.0 + 3.0 * mu * cumulative_pm[0] / equivalent_stress); return E_ijkl - 3.0 * mu * mu / sII / h * sij.outerProduct(sij) - 4.0 * mu * mu * zeta * dflowPotential_dstress(stress, intnl); }
//Jacobian for stress update algorithm void FiniteStrainRatePlasticMaterial::getJac(const RankTwoTensor & sig, const RankFourTensor & E_ijkl, Real flow_incr, Real yield_stress, RankFourTensor & dresid_dsig) { RankTwoTensor sig_dev, flow_tensor, flow_dirn,fij; RankTwoTensor dfi_dft; RankFourTensor dfd_dft, dfd_dsig, dfi_dsig; Real sig_eqv; Real f1, f2, f3; Real dfi_dseqv; sig_dev = sig.deviatoric(); sig_eqv = getSigEqv(sig); getFlowTensor(sig, yield_stress, flow_tensor); flow_dirn = flow_tensor; dfi_dseqv = _ref_pe_rate * _dt * _exponent * std::pow(macaulayBracket(sig_eqv / yield_stress - 1.0), _exponent - 1.0) / yield_stress; dfi_dsig = flow_dirn.outerProduct(flow_dirn) * dfi_dseqv; //d_flow_increment/d_sig f1 = 0.0; f2 = 0.0; f3 = 0.0; if (sig_eqv > 1e-8) { f1 = 3.0 / (2.0 * sig_eqv); f2 = f1 / 3.0; f3 = 9.0 / (4.0 * std::pow(sig_eqv, 3.0)); } dfd_dsig = f1 * _deltaMixed - f2 * _deltaOuter - f3 * sig_dev.outerProduct(sig_dev); //d_flow_dirn/d_sig - 2nd part //Jacobian dresid_dsig = E_ijkl.invSymm() + dfd_dsig * flow_incr + dfi_dsig; }
void RecomputeRadialReturn::computeStress(RankTwoTensor & strain_increment, RankTwoTensor & inelastic_strain_increment, RankTwoTensor & stress_new) { // Given the stretching, update the inelastic strain // Compute the stress in the intermediate configuration while retaining the stress history // compute the deviatoric trial stress and trial strain from the current intermediate configuration RankTwoTensor deviatoric_trial_stress = stress_new.deviatoric(); // compute the effective trial stress Real dev_trial_stress_squared = deviatoric_trial_stress.doubleContraction(deviatoric_trial_stress); Real effective_trial_stress = std::sqrt(3.0 / 2.0 * dev_trial_stress_squared); //If the effective trial stress is zero, so should the inelastic strain increment be zero //In that case skip the entire iteration if the effective trial stress is zero if (effective_trial_stress != 0.0) { computeStressInitialize(effective_trial_stress); // Use Newton sub-iteration to determine the scalar effective inelastic strain increment Real scalar_effective_inelastic_strain = 0; unsigned int iteration = 0; Real residual = 10; // use a large number here to guarantee at least one loop through while Real norm_residual = 10; Real first_norm_residual = 10; // create an output string with iteration information when errors occur std::string iteration_output; while (iteration < _max_its && norm_residual > _absolute_tolerance && (norm_residual/first_norm_residual) > _relative_tolerance) { iterationInitialize(scalar_effective_inelastic_strain); residual = computeResidual(effective_trial_stress, scalar_effective_inelastic_strain); norm_residual = std::abs(residual); if (iteration == 0) { first_norm_residual = norm_residual; if (first_norm_residual == 0) first_norm_residual = 1; } Real derivative = computeDerivative(effective_trial_stress, scalar_effective_inelastic_strain); scalar_effective_inelastic_strain -= residual / derivative; if (_output_iteration_info || _output_iteration_info_on_error) { iteration_output = "In the element " + Moose::stringify(_current_elem->id()) + + " and the qp point " + Moose::stringify(_qp) + ": \n" + + " iteration = " + Moose::stringify(iteration ) + "\n" + + " effective trial stress = " + Moose::stringify(effective_trial_stress) + "\n" + + " scalar effective inelastic strain = " + Moose::stringify(scalar_effective_inelastic_strain) +"\n" + + " relative residual = " + Moose::stringify(norm_residual/first_norm_residual) + "\n" + + " relative tolerance = " + Moose::stringify(_relative_tolerance) + "\n" + + " absolute residual = " + Moose::stringify(norm_residual) + "\n" + + " absolute tolerance = " + Moose::stringify(_absolute_tolerance) + "\n"; } iterationFinalize(scalar_effective_inelastic_strain); ++iteration; } if (_output_iteration_info) _console << iteration_output << std::endl; if (iteration == _max_its && norm_residual > _absolute_tolerance && (norm_residual/first_norm_residual) > _relative_tolerance) { if (_output_iteration_info_on_error) Moose::err << iteration_output; mooseError("Exceeded maximum iterations in RecomputeRadialReturn solve for material: " << _name << ". Rerun with 'output_iteration_info_on_error = true' for more information."); } // compute inelastic strain increments while avoiding a potential divide by zero inelastic_strain_increment = deviatoric_trial_stress; inelastic_strain_increment *= (3.0 / 2.0 * scalar_effective_inelastic_strain / effective_trial_stress); } else inelastic_strain_increment.zero(); strain_increment -= inelastic_strain_increment; stress_new = _elasticity_tensor[_qp] * (strain_increment + _elastic_strain_old[_qp]); computeStressFinalize(inelastic_strain_increment); }
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 RedbackMechMaterialCC::getJac(const RankTwoTensor & sig, const RankFourTensor & E_ijkl, Real flow_incr, Real sig_eqv, Real pressure, Real p_yield_stress, Real q_yield_stress, Real pc, RankFourTensor & dresid_dsig) { unsigned i, j, k, l; RankTwoTensor sig_dev, flow_dirn_vol, flow_dirn_dev, fij, flow_dirn, flow_tensor; RankTwoTensor dfi_dft; RankFourTensor dfd_dsig, dfi_dsig; Real f1, f2; Real dfi_dseqv_dev, dfi_dseqv_vol, dfi_dseqv; pc *= -1; sig_dev = sig.deviatoric(); dfi_dseqv = getDerivativeFlowIncrement(sig, pressure, sig_eqv, pc, q_yield_stress, p_yield_stress); getFlowTensor(sig, sig_eqv, pressure, pc, flow_dirn); /* The following calculates the tensorial derivative (Jacobian) of the residual with respect to stress, dr_dsig * It consists of two terms: The first is * dr_dsig = (dfi_dseqv_dev*flow_dirn_dev(k,l)) * flow_dirn_dev(i,j) * which is the tensorial product of the flow increment tensor times the flow direction tensor * * The second is the product of the flow increment tensor times the derivative of the flow direction tensor * with respect to the stress tensor. See also REDBACK's documentation * */ // This loop calculates the first term for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j) for (k = 0; k < 3; ++k) for (l = 0; l < 3; ++l) dfi_dsig(i, j, k, l) = flow_dirn(i, j) * flow_dirn(k, l) * dfi_dseqv; // Real flow_tensor_norm = flow_dirn.L2norm(); // This loop calculates the second term. Read REDBACK's documentation // (same as J2 plasticity case) f1 = 0.0; f2 = 0.0; if (sig_eqv > 1e-8) { f1 = 3.0 / (_slope_yield_surface * _slope_yield_surface); f2 = 2.0 / 9.0 - 1.0 / (_slope_yield_surface * _slope_yield_surface); } for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j) for (k = 0; k < 3; ++k) for (l = 0; l < 3; ++l) dfd_dsig(i, j, k, l) = f1 * deltaFunc(i, k) * deltaFunc(j, l) - f2 * deltaFunc(i, j) * deltaFunc(k, l); // d_flow_dirn/d_sig - 2nd part (J2 plasticity) // dfd_dsig = dft_dsig1/flow_tensor_norm - 3.0 * dft_dsig2 / // (2*sig_eqv*flow_tensor_norm*flow_tensor_norm*flow_tensor_norm); //d_flow_dirn/d_sig // TODO: check if the previous two lines (i.e normalizing the flow vector) should be activated or not. Currently we // are using the non-unitary flow vector dresid_dsig = E_ijkl.invSymm() + dfd_dsig * flow_incr + dfi_dsig; // Jacobian }
void RedbackMechMaterialCC::getJac(const RankTwoTensor & sig, const RankFourTensor & E_ijkl, Real flow_incr, Real sig_eqv, Real pressure, Real p_yield_stress, Real q_yield_stress, Real yield_stress, RankFourTensor & dresid_dsig) { unsigned i, j, k, l; RankTwoTensor sig_dev, flow_dirn_vol, flow_dirn_dev, fij, flow_dirn, flow_tensor; RankTwoTensor dfi_dft; RankFourTensor dfd_dsig, dfi_dsig; Real f1, f2, f3; Real dfi_dp, dfi_dseqv; Real pc = -yield_stress; sig_dev = sig.deviatoric(); getDerivativeFlowIncrement(dfi_dp, dfi_dseqv, sig, pressure, sig_eqv, pc, q_yield_stress, p_yield_stress); getFlowTensor(sig, sig_eqv, pressure, q_yield_stress, p_yield_stress, yield_stress, flow_dirn); /* The following calculates the tensorial derivative (Jacobian) of the *residual with respect to stress, dr_dsig * It consists of two terms: The first is * dr_dsig = (dfi_dseqv_dev*flow_dirn_dev(k,l)) * flow_dirn_dev(i,j) * which is the tensorial product of the flow increment tensor times the flow *direction tensor * * The second is the product of the flow increment tensor times the derivative *of the flow direction tensor * with respect to the stress tensor. See also REDBACK's documentation * */ f1 = 0.0; f2 = 0.0; f3 = 0.0; if (sig_eqv > 1e-10) { f1 = 3.0 / (_slope_yield_surface * _slope_yield_surface); f2 = 2.0 / 9.0 - 1.0 / (_slope_yield_surface * _slope_yield_surface); f3 = 3.0 / (2.0 * sig_eqv); } // This loop calculates the first term for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j) for (k = 0; k < 3; ++k) for (l = 0; l < 3; ++l) dfi_dsig(i, j, k, l) = flow_dirn(i, j) * (f3 * sig_dev(k, l) * dfi_dseqv + dfi_dp * deltaFunc(k, l) / 3.0); // This loop calculates the second term. for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j) for (k = 0; k < 3; ++k) for (l = 0; l < 3; ++l) dfd_dsig(i, j, k, l) = f1 * deltaFunc(i, k) * deltaFunc(j, l) + f2 * deltaFunc(i, j) * deltaFunc(k, l); dresid_dsig = E_ijkl.invSymm() + dfd_dsig * flow_incr + dfi_dsig; // Jacobian }