//Jacobian for stress update algorithm void FiniteStrainPlasticMaterial::getJac(RankTwoTensor sig, RankFourTensor E_ijkl, Real flow_incr, RankFourTensor* dresid_dsig) { RankTwoTensor sig_dev, flow_tensor, flow_dirn; RankTwoTensor dfi_dft,dfi_dsig; RankFourTensor dft_dsig,dfd_dft,dfd_dsig; Real sig_eqv/*,val*/; Real f1,f2,f3; RankFourTensor temp; sig_dev=getSigDev(sig); sig_eqv=getSigEqv(sig); getFlowTensor(sig,&flow_tensor); flow_dirn=flow_tensor; f1=3.0/(2.0*sig_eqv); f2=f1/3.0; f3=9.0/(4.0*pow(sig_eqv,3.0)); for (int i=0;i<3;i++) for (int j=0;j<3;j++) for (int k=0;k<3;k++) for (int 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); dfd_dsig=dft_dsig; *dresid_dsig=E_ijkl.invSymm()+dfd_dsig*flow_incr; }
// 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; }
//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 }
//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 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 }
/** * Implements the return-map algorithm via a Newton-Raphson process. * This idea is fully explained in Simo and Hughes "Computational * Inelasticity" Springer 1997, for instance, as well as many other * books on plasticity. * The basic idea is as follows. * Given: sig_old - the stress at the start of the "time step" * plastic_strain_old - the plastic strain at the start of the "time step" * eqvpstrain_old - equivalent plastic strain at the start of the "time step" * (In general we would be given some number of internal * parameters that the yield function depends upon.) * delta_d - the prescribed strain increment for this "time step" * we want to determine the following parameters at the end of this "time step": * sig - the stress * plastic_strain - the plastic strain * eqvpstrain - the equivalent plastic strain (again, in general, we would * have an arbitrary number of internal parameters). * * To determine these parameters, introduce * the "yield function", f * the "consistency parameter", flow_incr * the "flow potential", flow_dirn_ij * the "internal potential", internalPotential (in general there are as many internalPotential * functions as there are internal parameters). * All three of f, flow_dirn_ij, and internalPotential, are functions of * sig and eqvpstrain. * To find sig, plastic_strain and eqvpstrain, we need to solve the following * resid_ij = 0 * f = 0 * rep = 0 * This is done by using Newton-Raphson. * There are 8 equations here: six from resid_ij=0 (more generally there are nine * but in this case resid is symmetric); one from f=0; one from rep=0 (more generally, for N * internal parameters there are N of these equations). * * resid_ij = flow_incr*flow_dirn_ij - (plastic_strain - plastic_strain_old)_ij * = flow_incr*flow_dirn_ij - (E^{-1}(trial_stress - sig))_ij * Here trial_stress = E*(strain - plastic_strain_old) * sig = E*(strain - plastic_strain) * Note: flow_dirn_ij is evaluated at sig and eqvpstrain (not the old values). * * f is the yield function, evaluated at sig and eqvpstrain * * rep = -flow_incr*internalPotential - (eqvpstrain - eqvpstrain_old) * Here internalPotential are evaluated at sig and eqvpstrain (not the old values). * * The Newton-Raphson procedure has sig, flow_incr, and eqvpstrain as its * variables. Therefore we need the derivatives of resid_ij, f, and rep * with respect to these parameters * * In this associative J2 with isotropic hardening, things are a little more specialised. * (1) f = sqrt(3*s_ij*s_ij/2) - K(eqvpstrain) (this is called "isotropic hardening") * (2) associativity means that flow_dirn_ij = df/d(sig_ij) = s_ij*sqrt(3/2/(s_ij*s_ij)), and * this means that flow_dirn_ij*flow_dirn_ij = 3/2, so when resid_ij=0, we get * (plastic_strain_dot)_ij*(plastic_strain_dot)_ij = (3/2)*flow_incr^2, where * plastic_strain_dot = plastic_strain - plastic_strain_old * (3) The definition of equivalent plastic strain is through * eqvpstrain_dot = sqrt(2*plastic_strain_dot_ij*plastic_strain_dot_ij/3), so * using (2), we obtain eqvpstrain_dot = flow_incr, and this yields * internalPotential = -1 in the "rep" equation. */ void FiniteStrainPlasticMaterial::returnMap(const RankTwoTensor & sig_old, const Real eqvpstrain_old, const RankTwoTensor & plastic_strain_old, const RankTwoTensor & delta_d, const RankFourTensor & E_ijkl, RankTwoTensor & sig, Real & eqvpstrain, RankTwoTensor & plastic_strain) { // the yield function, must be non-positive // Newton-Raphson sets this to zero if trial stress enters inadmissible region Real f; // the consistency parameter, must be non-negative // change in plastic strain in this timestep = flow_incr*flow_potential Real flow_incr = 0.0; // direction of flow defined by the potential RankTwoTensor flow_dirn; // Newton-Raphson sets this zero // resid_ij = flow_incr*flow_dirn_ij - (plastic_strain - plastic_strain_old) RankTwoTensor resid; // Newton-Raphson sets this zero // rep = -flow_incr*internalPotential - (eqvpstrain - eqvpstrain_old) Real rep; // change in the stress (sig) in a Newton-Raphson iteration RankTwoTensor ddsig; // change in the consistency parameter in a Newton-Raphson iteration Real dflow_incr = 0.0; // change in equivalent plastic strain in one Newton-Raphson iteration Real deqvpstrain = 0.0; // convenience variable that holds the change in plastic strain incurred during the return // delta_dp = plastic_strain - plastic_strain_old // delta_dp = E^{-1}*(trial_stress - sig), where trial_stress = E*(strain - plastic_strain_old) RankTwoTensor delta_dp; // d(yieldFunction)/d(stress) RankTwoTensor df_dsig; // d(resid_ij)/d(sigma_kl) RankFourTensor dr_dsig; // dr_dsig_inv_ijkl*dr_dsig_klmn = 0.5*(de_ij de_jn + de_ij + de_jm), where de_ij = 1 if i=j, but // zero otherwise RankFourTensor dr_dsig_inv; // d(yieldFunction)/d(eqvpstrain) Real fq; // yield stress at the start of this "time step" (ie, evaluated with // eqvpstrain_old). It is held fixed during the Newton-Raphson return, // even if eqvpstrain != eqvpstrain_old. Real yield_stress; // measures of whether the Newton-Raphson process has converged Real err1, err2, err3; // number of Newton-Raphson iterations performed unsigned int iter = 0; // maximum number of Newton-Raphson iterations allowed unsigned int maxiter = 100; // plastic loading occurs if yieldFunction > toly Real toly = 1.0e-8; // Assume this strain increment does not induce any plasticity // This is the elastic-predictor sig = sig_old + E_ijkl * delta_d; // the trial stress eqvpstrain = eqvpstrain_old; plastic_strain = plastic_strain_old; yield_stress = getYieldStress(eqvpstrain); // yield stress at this equivalent plastic strain if (yieldFunction(sig, yield_stress) > toly) { // the sig just calculated is inadmissable. We must return to the yield surface. // This is done iteratively, using a Newton-Raphson process. delta_dp.zero(); sig = sig_old + E_ijkl * delta_d; // this is the elastic predictor flow_dirn = flowPotential(sig); resid = flow_dirn * flow_incr - delta_dp; // Residual 1 - refer Hughes Simo f = yieldFunction(sig, yield_stress); rep = -eqvpstrain + eqvpstrain_old - flow_incr * internalPotential(); // Residual 3 rep=0 err1 = resid.L2norm(); err2 = std::abs(f); err3 = std::abs(rep); while ((err1 > _rtol || err2 > _ftol || err3 > _eptol) && iter < maxiter) // Stress update iteration (hardness fixed) { iter++; df_dsig = dyieldFunction_dstress(sig); getJac(sig, E_ijkl, flow_incr, dr_dsig); // gets dr_dsig = d(resid_ij)/d(sig_kl) fq = dyieldFunction_dinternal(eqvpstrain); // d(f)/d(eqvpstrain) /** * The linear system is * ( dr_dsig flow_dirn 0 )( ddsig ) ( - resid ) * ( df_dsig 0 fq )( dflow_incr ) = ( - f ) * ( 0 1 -1 )( deqvpstrain ) ( - rep ) * The zeroes are: d(resid_ij)/d(eqvpstrain) = flow_dirn*d(df/d(sig_ij))/d(eqvpstrain) = 0 * and df/d(flow_dirn) = 0 (this is always true, even for general hardening and * non-associative) * and d(rep)/d(sig_ij) = -flow_incr*d(internalPotential)/d(sig_ij) = 0 */ dr_dsig_inv = dr_dsig.invSymm(); /** * Because of the zeroes and ones, the linear system is not impossible to * solve by hand. * NOTE: andy believes there was originally a sign-error in the next line. The * next line is unchanged, however andy's definition of fq is negative of * the original definition of fq. andy can't see any difference in any tests! */ dflow_incr = (f - df_dsig.doubleContraction(dr_dsig_inv * resid) + fq * rep) / (df_dsig.doubleContraction(dr_dsig_inv * flow_dirn) - fq); ddsig = dr_dsig_inv * (-resid - flow_dirn * dflow_incr); // from solving the top row of linear system, given dflow_incr deqvpstrain = rep + dflow_incr; // from solving the bottom row of linear system, given dflow_incr // update the variables flow_incr += dflow_incr; delta_dp -= E_ijkl.invSymm() * ddsig; sig += ddsig; eqvpstrain += deqvpstrain; // evaluate the RHS equations ready for next Newton-Raphson iteration flow_dirn = flowPotential(sig); resid = flow_dirn * flow_incr - delta_dp; f = yieldFunction(sig, yield_stress); rep = -eqvpstrain + eqvpstrain_old - flow_incr * internalPotential(); err1 = resid.L2norm(); err2 = std::abs(f); err3 = std::abs(rep); } if (iter >= maxiter) mooseError("Constitutive failure"); plastic_strain += delta_dp; } }
/* *Solves for incremental plastic rate of deformation tensor and stress in unrotated frame. *Input: Strain incrment, 4th order elasticity tensor, stress tensor in previous incrmenent and *plastic rate of deformation tensor gradient. */ void FiniteStrainPlasticMaterial::solveStressResid(RankTwoTensor sig_old,RankTwoTensor delta_d,RankFourTensor E_ijkl, RankTwoTensor *dp, RankTwoTensor *sig) { RankTwoTensor sig_new,delta_dp,dpn; RankTwoTensor flow_tensor, flow_dirn; RankTwoTensor resid,ddsig; RankFourTensor dr_dsig,dr_dsig_inv; Real /*sig_eqv,*/flow_incr,f,dflow_incr; Real err1,err2,err3; unsigned int plastic_flag; unsigned int iter,maxiter=100; Real eqvpstrain,eqvpstrain_old,deqvpstrain,fq,rep; Real yield_stress; sig_new=sig_old+E_ijkl*delta_d; eqvpstrain_old=eqvpstrain=_eqv_plastic_strain_old[_qp]; yield_stress=getYieldStress(eqvpstrain); plastic_flag=isPlastic(sig_new,yield_stress);//Check of plasticity for elastic predictor if (plastic_flag==1) { iter=0; dflow_incr=0.0; flow_incr=0.0; delta_dp.zero(); deqvpstrain=0.0; sig_new=sig_old+E_ijkl*delta_d; getFlowTensor(sig_new,&flow_tensor); flow_dirn=flow_tensor; resid=flow_dirn*flow_incr-delta_dp;//Residual 1 - refer Hughes Simo f=getSigEqv(sig_new)-yield_stress;//Residual 2 - f=0 rep=-eqvpstrain+eqvpstrain_old+flow_incr;//Residual 3 rep=0 err1=resid.L2norm(); err2=fabs(f); err3=fabs(rep); while ((err1 > _rtol || err2 > _ftol || err3 > _eptol) && iter < maxiter )//Stress update iteration (hardness fixed) { iter++; getJac(sig_new,E_ijkl,flow_incr,&dr_dsig);//Jacobian dr_dsig_inv=dr_dsig.invSymm(); fq=getdYieldStressdPlasticStrain(eqvpstrain); dflow_incr=(f-flow_tensor.doubleContraction(dr_dsig_inv*resid)+fq*rep)/(flow_tensor.doubleContraction(dr_dsig_inv*flow_dirn)-fq); ddsig=dr_dsig_inv*(-resid-flow_dirn*dflow_incr); flow_incr+=dflow_incr; delta_dp-=E_ijkl.invSymm()*ddsig; sig_new+=ddsig; deqvpstrain=rep+dflow_incr; eqvpstrain+=deqvpstrain; getFlowTensor(sig_new,&flow_tensor); flow_dirn=flow_tensor; resid=flow_dirn*flow_incr-delta_dp; f=getSigEqv(sig_new)-yield_stress; rep=-eqvpstrain+eqvpstrain_old+flow_incr; err1=resid.L2norm(); err2=fabs(f); err3=fabs(rep); } if (iter>=maxiter) { _stress[_qp](2,2)=1e6; printf("Constitutive Error: Too many iterations %f %f %f \n",err1,err2, err3);//Convergence failure return; } dpn=*dp+delta_dp; } *dp=dpn;//Plastic strain in unrotated configuration *sig=sig_new; _eqv_plastic_strain[_qp]=eqvpstrain; }
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 }
/* *Solves for incremental plastic rate of deformation tensor and stress in unrotated frame. *Input: Strain incrment, 4th order elasticity tensor, stress tensor in previous incrmenent and *plastic rate of deformation tensor. */ void FiniteStrainRatePlasticMaterial::returnMap(const RankTwoTensor & sig_old, const RankTwoTensor & delta_d, const RankFourTensor & E_ijkl, RankTwoTensor & dp, RankTwoTensor & sig) { RankTwoTensor sig_new, delta_dp, dpn; RankTwoTensor flow_tensor, flow_dirn; RankTwoTensor resid,ddsig; RankFourTensor dr_dsig, dr_dsig_inv; Real flow_incr, flow_incr_tmp; Real err1, err3, tol1, tol3; unsigned int iterisohard, iter, maxiterisohard = 20, maxiter = 50; Real eqvpstrain; Real yield_stress, yield_stress_prev; tol1 = 1e-10; tol3 = 1e-6; iterisohard = 0; eqvpstrain = std::pow(2.0/3.0,0.5) * dp.L2norm(); yield_stress = getYieldStress(eqvpstrain); err3 = 1.1 * tol3; while (err3 > tol3 && iterisohard < maxiterisohard) //Hardness update iteration { iterisohard++; iter = 0; delta_dp.zero(); sig_new = sig_old + E_ijkl * delta_d; flow_incr=_ref_pe_rate*_dt * std::pow(macaulayBracket(getSigEqv(sig_new) / yield_stress - 1.0), _exponent); getFlowTensor(sig_new, yield_stress, flow_tensor); flow_dirn = flow_tensor; resid = flow_dirn * flow_incr - delta_dp; err1 = resid.L2norm(); while (err1 > tol1 && iter < maxiter) //Stress update iteration (hardness fixed) { iter++; getJac(sig_new, E_ijkl, flow_incr, yield_stress, dr_dsig); //Jacobian dr_dsig_inv = dr_dsig.invSymm(); ddsig = -dr_dsig_inv * resid; sig_new += ddsig; //Update stress delta_dp -= E_ijkl.invSymm() * ddsig; //Update plastic rate of deformation tensor flow_incr_tmp = _ref_pe_rate * _dt * std::pow(macaulayBracket(getSigEqv(sig_new) / yield_stress - 1.0), _exponent); if (flow_incr_tmp < 0.0) //negative flow increment not allowed mooseError("Constitutive Error-Negative flow increment: Reduce time increment."); flow_incr = flow_incr_tmp; getFlowTensor(sig_new, yield_stress, flow_tensor); flow_dirn = flow_tensor; resid = flow_dirn * flow_incr - delta_dp; //Residual err1=resid.L2norm(); } if (iter>=maxiter)//Convergence failure mooseError("Constitutive Error-Too many iterations: Reduce time increment.\n"); //Convergence failure dpn = dp + delta_dp; eqvpstrain = std::pow(2.0/3.0, 0.5) * dpn.L2norm(); yield_stress_prev = yield_stress; yield_stress = getYieldStress(eqvpstrain); err3 = std::abs(yield_stress-yield_stress_prev); } if (iterisohard>=maxiterisohard) mooseError("Constitutive Error-Too many iterations in Hardness Update:Reduce time increment.\n"); //Convergence failure dp = dpn; //Plastic rate of deformation tensor in unrotated configuration sig = sig_new; }
bool FiniteStrainPlasticBase::returnMap(const RankTwoTensor & stress_old, const RankTwoTensor & plastic_strain_old, const std::vector<Real> & intnl_old, const RankTwoTensor & delta_d, const RankFourTensor & E_ijkl, RankTwoTensor & stress, RankTwoTensor & plastic_strain, std::vector<Real> & intnl, std::vector<Real> & f, unsigned int & iter) { // Assume this strain increment does not induce any plasticity // This is the elastic-predictor stress = stress_old + E_ijkl * delta_d; // the trial stress plastic_strain = plastic_strain_old; for (unsigned i = 0; i < intnl_old.size() ; ++i) intnl[i] = intnl_old[i]; iter = 0; yieldFunction(stress, intnl, f); Real nr_res2 = 0; for (unsigned i = 0 ; i < f.size() ; ++i) nr_res2 += 0.5*std::pow( std::max(f[i], 0.0)/_f_tol[i], 2); if (nr_res2 < 0.5) // a purely elastic increment. // All output variables have been calculated return true; // So, from here on we know that the trial stress // is inadmissible, and we have to return from that // value to the yield surface. There are three // types of constraints we have to satisfy, listed // below, and calculated in calculateConstraints(...) // Plastic strain constraint, L2 norm must be zero (up to a tolerance) RankTwoTensor epp; // Yield function constraint passed to this function as // std::vector<Real> & f // Each yield function must be <= 0 (up to tolerance) // Internal constraint(s), must be zero (up to a tolerance) std::vector<Real> ic; // During the Newton-Raphson procedure, we'll be // changing the following parameters in order to // (attempt to) satisfy the constraints. RankTwoTensor dstress; // change in stress std::vector<Real> dpm; // change in plasticity multipliers ("consistency parameters") std::vector<Real> dintnl; // change in internal parameters // The following are used in the Newton-Raphson // Inverse of E_ijkl (assuming symmetric) RankFourTensor E_inv = E_ijkl.invSymm(); // convenience variable that holds the change in plastic strain incurred during the return // delta_dp = plastic_strain - plastic_strain_old // delta_dp = E^{-1}*(trial_stress - stress), where trial_stress = E*(strain - plastic_strain_old) RankTwoTensor delta_dp; // The "consistency parameters" (plastic multipliers) // Change in plastic strain in this timestep = pm*flowPotential // Each pm must be non-negative std::vector<Real> pm; pm.assign(numberOfYieldFunctions(), 0.0); // whether line-searching was successful bool ls_success = true; // The Newton-Raphson loops while (nr_res2 > 0.5 && iter < _max_iter && ls_success) { iter++; // calculate dstress, dpm and dintnl for one full Newton-Raphson step nrStep(stress, intnl_old, intnl, pm, E_inv, delta_dp, dstress, dpm, dintnl); // perform a line search // The line-search will exit with updated values ls_success = lineSearch(nr_res2, stress, intnl_old, intnl, pm, E_inv, delta_dp, dstress, dpm, dintnl, f, epp, ic); } if (iter >= _max_iter || !ls_success) { stress = stress_old; for (unsigned i = 0; i < intnl_old.size() ; ++i) intnl[i] = intnl_old[i]; return false; } else { plastic_strain += delta_dp; return true; } }