/* Take increments in strain and calculate new Particle: strains, rotation strain, plastic strain, stresses, strain energy, plastic energy, dissipated energy, angle dvij are (gradient rates X time increment) to give deformation gradient change For Axisymmetry: x->R, y->Z, z->theta, np==AXISYMMETRIC_MPM, otherwise dvzz=0 This material tracks pressure and stores deviatoric stress only in particle stress tensor */ void Viscoelastic::MPMConstitutiveLaw(MPMBase *mptr,Matrix3 du,double delTime,int np,void *properties,ResidualStrains *res) const { // Effective strain by deducting thermal strain (no shear thermal strain because isotropic) double eres=CTE*res->dT; if(DiffusionTask::active) eres+=CME*res->dC; // update pressure double delV = du.trace() - 3.*eres; UpdatePressure(mptr,delV,res,eres); // deviatoric strains increment // Actually find 2*de to avoid many multiples by two Tensor de; double dV = du.trace()/3.; de.xx = 2.*(du(0,0) - dV); de.yy = 2.*(du(1,1) - dV); de.zz = 2.*(du(2,2) - dV); de.xy = du(0,1)+du(1,0); if(np==THREED_MPM) { de.xz = du(0,2)+du(2,0); de.yz = du(1,2)+du(2,1); } // Find initial 2*e(t) in ed Tensor *ep=mptr->GetStrainTensor(); Tensor ed = *ep; double thirdV = (ed.xx+ed.yy+ed.zz)/3.; ed.xx = 2.*(ed.xx-thirdV); ed.yy = 2.*(ed.yy-thirdV); ed.zz = 2.*(ed.zz-thirdV); // Increment total strains on the particle ep->xx += du(0,0); ep->yy += du(1,1); ep->zz += du(2,2); ep->xy += de.xy; if(np==THREED_MPM) { ep->xz += de.xz; ep->yz += de.yz; } // get internal variable increments and update them too Tensor dak; double **ak =(double **)(mptr->GetHistoryPtr()); int k; for(k=0;k<ntaus;k++) { double tmp = exp(-delTime/tauk[k]); double tmpm1 = tmp-1.; double tmpp1 = tmp+1.; double arg = 0.25*delTime/tauk[k]; // 0.25 because e's have factor of 2 dak.xx = tmpm1*ak[XX_HISTORY][k] + arg*(tmpp1*ed.xx + de.xx); dak.yy = tmpm1*ak[YY_HISTORY][k] + arg*(tmpp1*ed.yy + de.yy); dak.xy = tmpm1*ak[XY_HISTORY][k] + arg*(tmpp1*ed.xy + de.xy); dak.zz = tmpm1*ak[ZZ_HISTORY][k] + arg*(tmpp1*ed.zz + de.zz); ak[XX_HISTORY][k] += dak.xx; ak[YY_HISTORY][k] += dak.yy; ak[ZZ_HISTORY][k] += dak.zz; ak[XY_HISTORY][k] += dak.xy; if(np==THREED_MPM) { dak.xz = tmpm1*ak[XZ_HISTORY][k] + arg*(tmpp1*ed.xz + de.xz); dak.yz = tmpm1*ak[YZ_HISTORY][k] + arg*(tmpp1*ed.yz + de.yz); ak[XZ_HISTORY][k] += dak.xz; ak[YZ_HISTORY][k] += dak.yz; } } // increment particle deviatoric stresses double dsig[6]; dsig[XX] = Gered*de.xx; dsig[YY] = Gered*de.yy; dsig[ZZ] = Gered*de.zz; dsig[XY] = Gered*de.xy; if(np==THREED_MPM) { dsig[XZ] = Gered*de.xz; dsig[YZ] = Gered*de.yz; } for(k=0;k<ntaus;k++) { dsig[XX] -= TwoGkred[k]*dak.xx; dsig[YY] -= TwoGkred[k]*dak.yy; dsig[ZZ] -= TwoGkred[k]*dak.zz; dsig[XY] -= TwoGkred[k]*dak.xy; if(np==THREED_MPM) { dsig[XZ] -= TwoGkred[k]*dak.xz; dsig[YZ] -= TwoGkred[k]*dak.yz; } } // Hypoelastic increment of particle deviatoric stresses Tensor *sp=mptr->GetStressTensor(); Tensor st0 = *sp; double dwrotxy = du(1,0)-du(0,1); if(np==THREED_MPM) { double dwrotxz = du(2,0)-du(0,2); double dwrotyz = du(2,1)-du(1,2); Hypo3DCalculations(mptr,dwrotxy,dwrotxz,dwrotyz,dsig); } else { Hypo2DCalculations(mptr,-dwrotxy,dsig[XX],dsig[YY],dsig[XY]); sp->zz += dsig[ZZ]; } // incremental work energy = shear energy (dilation and residual energy done in update pressure) double shearEnergy = 0.5*((sp->xx+st0.xx)*du(0,0) + (sp->yy+st0.yy)*du(1,1) + (sp->zz+st0.zz)*du(2,2)+ (sp->xy+st0.xy)*de.xy); if(np==THREED_MPM) { shearEnergy += 0.5*((sp->xz+st0.xz)*de.xz + (sp->yz+st0.yz)*de.yz); } mptr->AddWorkEnergyAndResidualEnergy(shearEnergy,0.); // disispated energy per unit mass (dPhi/(rho0 V0)) (uJ/g) double dispEnergy = 0.; for(k=0;k<ntaus;k++) { dispEnergy += TwoGkred[k]*(dak.xx*(0.5*(ed.xx+0.5*de.xx)-ak[XX_HISTORY][k]+0.5*dak.xx) + dak.yy*(0.5*(ed.yy+0.5*de.yy)-ak[YY_HISTORY][k]+0.5*dak.yy) + dak.zz*(0.5*(ed.zz+0.5*de.zz)-ak[ZZ_HISTORY][k]+0.5*dak.zz) + dak.xy*(0.5*(ed.xy+0.5*de.xy)-ak[XY_HISTORY][k]+0.5*dak.xy)); if(np==THREED_MPM) { dispEnergy += TwoGkred[k]*(dak.xz*(0.5*(ed.xz+0.5*de.xz)-ak[XZ_HISTORY][k]+0.5*dak.xz) + dak.yz*(0.5*(ed.yz+0.5*de.yz)-ak[YZ_HISTORY][k]+0.5*dak.yz)); } } mptr->AddPlastEnergy(dispEnergy); // heat energy is Cv dT - dPhi // The dPhi is subtracted here because it will show up in next // time step within Cv dT (if adibatic heating occurs) // The Cv dT was done in update pressure IncrementHeatEnergy(mptr,0.,0.,dispEnergy); }
// To allow some subclasses to support large deformations, the initial calculation for incremental // deformation gradient (the dvij), volume change (delV) and relative volume (Jnew) can be // handled first by the subclass. This mtehod then finishes the constitutive law void IsoPlasticity::PlasticityConstLaw(MPMBase *mptr,double dvxx,double dvyy,double dvxy,double dvyx, double dvzz,double delTime,int np,double delV,double Jnew,double eres, PlasticProperties *p,ResidualStrains *res) const { // here dvij is total strain increment, dexxr is relative strain by subtracting off eres double dexxr = dvxx-eres; // trial dexx=dvxx double deyyr = dvyy-eres; // trial deyy=dvyy double dezzr = dvzz-eres; // In plane strain trial dezz=0, dvzz=0 except in axisymmetric double dgxy = dvxy+dvyx; // no need to substract residual strain double dwrotxy = dvyx-dvxy; // allow arbitrary equation of state for pressure double P0 = mptr->GetPressure(); UpdatePressure(mptr,delV,Jnew,np,p,res,eres); double Pfinal = mptr->GetPressure(); // Deviatoric stress increment Tensor *ep=mptr->GetStrainTensor(); Tensor *sp=mptr->GetStressTensor(); Tensor dels,stk,st0=*sp; double thirdDelV = delV/3.; dels.xx = 2.*p->Gred*(dexxr-thirdDelV); dels.yy = 2.*p->Gred*(deyyr-thirdDelV); if(np==PLANE_STRESS_MPM) dels.zz = Pfinal-P0; else dels.zz = 2.*p->Gred*(dezzr-thirdDelV); dels.xy = p->Gred*dgxy; // trial deviatoric stress stk.xx = st0.xx + dels.xx; stk.yy = st0.yy + dels.yy; stk.zz = st0.zz + dels.zz; stk.xy = st0.xy + dels.xy; // Calculate plastic potential f = ||s|| - sqrt(2/3)*sy(alpha,rate,...) HardeningAlpha alpha; plasticLaw->UpdateTrialAlpha(mptr,np,&alpha); // initialize to last value and zero plastic strain rate double strial = GetMagnitudeSFromDev(&stk,np); double ftrial = strial - SQRT_TWOTHIRDS*plasticLaw->GetYield(mptr,np,delTime,&alpha,p->hardProps); if(ftrial<0.) { // elastic, update stress and strain energy as usual // Add input strain increment to elastic strain on particle ep->xx += dvxx; ep->yy += dvyy; ep->xy += dgxy; // increment deviatoric stress (Units N/m^2 cm^3/g) (pressure not needed here) Hypo2DCalculations(mptr,-dwrotxy,dels.xx,dels.yy,dels.xy); // work energy increment per unit mass (dU/(rho0 V0)) (by midpoint rule) (uJ/g) // energy units are also Pa cm^3/g, i.e., same as stress units sp->zz = stk.zz; if(np==AXISYMMETRIC_MPM) { ep->zz += dvzz; mptr->AddWorkEnergy(0.5*((st0.xx+sp->xx)*dvxx + (st0.yy+sp->yy)*dvyy + (st0.xy+sp->xy)*dgxy + (st0.zz+sp->zz)*dvzz)); } else { mptr->AddWorkEnergy(0.5*((st0.xx+sp->xx)*dvxx + (st0.yy+sp->yy)*dvyy + (st0.xy+sp->xy)*dgxy)); } // heat energy is Cv(dT-dTq0) - dPhi, but dPhi is zero here // and Cv(dT-dTq0) was done in Update pressure // give subclass material chance to update history variables that change in elastic updates ElasticUpdateFinished(mptr,np,delTime); return; } // Find lambda for this plastic state // Base class finds it numerically, subclass can override if solvable by more efficient methods double lambdak = plasticLaw->SolveForLambdaBracketed(mptr,np,strial,&stk,p->Gred,p->psKred,Pfinal,delTime,&alpha,p->hardProps); // Now have lambda, finish update on this particle Tensor dfds; if(np==PLANE_STRESS_MPM) { // get final stress state double d1 = (1 + p->psKred*lambdak); double d2 = (1.+2.*p->Gred*lambdak); double n1 = (stk.xx+stk.yy-2.*Pfinal)/d1; double n2 = (-stk.xx+stk.yy)/d2; double sxx = (n1-n2)/2.; double syy = (n1+n2)/2.; double txy = stk.xy/d2; // find increment in deviatoric stress dels.xx = sxx+Pfinal-st0.xx; dels.yy = syy+Pfinal-st0.yy; dels.xy = txy-st0.xy; // get final direction dfds.xx = (2.*sxx-syy)/3.; dfds.yy = (2.*syy-sxx)/3.; dfds.zz = -(dfds.xx+dfds.yy); dfds.xy = txy; // tensorial shear strain // If fully plastic, the increment in deviatoric stress should be zero // sxx = sigmaxx+Pfinal = st0.xx, syy = sigmayy+Pfinal = st0.yy, szz = Pfinal // But first two must be wrong because trace is no longer zero? // // This is probably wrong // i.e.: n1 + 2*Pfinal = st0.xx+st0.yy // (stk.xx+stk.yy)/d1 - 2*Pfinal*(1/d1-1) = st0.xx+st0.yy // But (stk.xx+stk.yy) = (st0.xx+st0.yy) + 2.*Gred*(dexxr+deyyr-2*thirdDelV) // (st0.xx+st0.yy)(1/d1-1) - 2*Pfinal*(1/d1-1) = -2.*Gred*(dexxr+deyyr-2*thirdDelV)/d1 // (st0.xx+st0.yy-2*Pfinal)*(1-d1) = -2.*Gred*(dexxr+deyyr-2*thirdDelV) // B*Kred*lam = 2.*Gred*A or lam = 2.*Gred*A/(B*Kred) // where B = st0.xx+st0.yy-2*Pfinal, and A = (dexxr+deyyr-2*thirdDelV) // Then d1 = 1+2*Gred*A/B, n1 = ((st0.xx+st0.yy) + 2*Gred*A - 2*Pfinal)/d1 = (B+2*Gred*A)*B/(B+2*Gred*A) = B // // Also expect syy-sxx = sigmayy-sigmaxx = st0.yy-st0.xx = n2 // (stk.yy-stk.xx)/d2 = st0.yy-st0.xx // (st0.yy-st0.xx)/d2 + 2*Gred*(deyyr-dexxr)/d2 = (st0.yy-st0.xx) // (st0.yy-st0.xx)(d2-1) = - 2*Gred*(deyyr-dexxr) // lam = (deyyr-dexxr)/(st0.yy-st0.xx) // Then n2 = (st0.yy-st0.xx + 2*Gred*(deyyr-dexxr))/(1+2*Gred*(deyyr-dexxr)/(st0.yy-st0.xx)) = st0.yy-st0.xx // // But these to lam's seem to differ? // We can write } else { // get final direction GetDfDsigma(strial,&stk,np,&dfds); } // Plastic strain increments on particle double dexxp = lambdak*dfds.xx; double deyyp = lambdak*dfds.yy; double dezzp = lambdak*dfds.zz; double dgxyp = 2.*lambdak*dfds.xy; // 2 for engineering plastic shear strain Tensor *eplast=mptr->GetPlasticStrainTensor(); eplast->xx += dexxp; eplast->yy += deyyp; eplast->xy += dgxyp; eplast->zz += dezzp; // Elastic strain increments on particle ep->xx += (dvxx-dexxp); ep->yy += (dvyy-deyyp); dgxy -= dgxyp; ep->xy += dgxy; if(np==PLANE_STRESS_MPM) ep->zz += eres - p->psLr2G*(dexxr+deyyr+dezzp); else { // plain strain and axisymmetric when plastic increments is dezzp // In plain strain, dvzz=0 elastic increment is -dezzp to zz strain total is zero // Axisymmetry can have non-zero hoop strain ep->zz += (dvzz-dezzp); dezzr -= dezzp; } // Elastic strain increment minus the residual terms by now subtracting plastic parts dexxr -= dexxp; deyyr -= deyyp; //dgxy -= dgxyp; // done above //dezzr -= dezzp; // plane strain and axisymmetry done above, plain stress not needed // increment particle deviatoric stresses (plane stress increments found above) if(np!=PLANE_STRESS_MPM) { dels.xx -= 2.*p->Gred*dexxp; dels.yy -= 2.*p->Gred*deyyp; dels.xy -= p->Gred*dgxyp; dels.zz -= 2.*p->Gred*dezzp; sp->zz += dels.zz; } else sp->zz = Pfinal; // now equal to Pfinal Hypo2DCalculations(mptr,-dwrotxy,dels.xx,dels.yy,dels.xy); // Elastic work increment per unit mass (dU/(rho0 V0)) (uJ/g) double workEnergy = 0.5*((st0.xx+sp->xx)*dvxx + (st0.yy+sp->yy)*dvyy + (st0.xy+sp->xy)*dgxy); if(np==AXISYMMETRIC_MPM) { workEnergy += 0.5*(st0.zz+sp->zz)*dvzz; } // plastic strain work double plastEnergy = lambdak*(sp->xx*dfds.xx + sp->yy*dfds.yy + sp->zz*dfds.zz + 2.*sp->xy*dfds.xy); // total work mptr->AddWorkEnergy(plastEnergy + workEnergy); // disispated energy per unit mass (dPhi/(rho0 V0)) (uJ/g) double qdalphaTerm = lambdak*SQRT_TWOTHIRDS*plasticLaw->GetYieldIncrement(mptr,np,delTime,&alpha,p->hardProps); double dispEnergy = plastEnergy - qdalphaTerm; // heat energy is Cv(dT-dTq0) - dPhi // The dPhi is subtracted here because it will show up in next // time step within Cv dT (if adibatic heating occurs) // The Cv(dT-dTq0) was done in update pressure IncrementHeatEnergy(mptr,0.,0.,dispEnergy); // The cumulative dissipated energy is tracked in plastic energy mptr->AddPlastEnergy(dispEnergy); // update internal variables plasticLaw->UpdatePlasticInternal(mptr,np,&alpha); }
/* For 2D MPM analysis, take increments in strain and calculate new Particle: strains, rotation strain, stresses, strain energy, angle dvij are (gradient rates X time increment) to give deformation gradient change Assumes linear elastic, uses hypoelastic correction For Axisymmetric MPM, x->R, y->Z, x->theta, and dvzz is change in hoop strain (i.e., du/r on particle and dvzz will be zero if not axisymmetric) */ void Elastic::MPMConstLaw(MPMBase *mptr,double dvxx,double dvyy,double dvxy,double dvyx,double dvzz, double delTime,int np,void *properties,ResidualStrains *res) const { // cast pointer to material-specific data ElasticProperties *p = (ElasticProperties *)properties; // Add to total strain Tensor *ep=mptr->GetStrainTensor(); ep->xx+=dvxx; ep->yy+=dvyy; double dgam=dvxy+dvyx; ep->xy+=dgam; double dwrotxy=dvyx-dvxy; // residual strains (thermal and moisture) double erxx = p->alpha[1]*res->dT; double eryy = p->alpha[2]*res->dT; double erxy = p->alpha[3]*res->dT; double erzz = CTE3*res->dT; if(DiffusionTask::active) { erxx += p->beta[1]*res->dC; eryy += p->beta[2]*res->dC; erxy += p->beta[3]*res->dC; erzz += CME3*res->dC; } // moisture and thermal strain and temperature change // (when diffusion, conduction, OR thermal ramp active) double dvxxeff = dvxx - erxx; double dvyyeff = dvyy - eryy; double dgameff = dgam - erxy; // save initial stresses Tensor *sp=mptr->GetStressTensor(); Tensor st0=*sp; // find stress (Units N/m^2 cm^3/g) // this does xx, yy, ans xy only. zz do later if needed double c1,c2,c3; if(np==AXISYMMETRIC_MPM) { // axisymmetric strain ep->zz += dvzz; // hoop stress affect on RR, ZZ, and RZ stresses double dvzzeff = dvzz - erzz; c1=p->C[1][1]*dvxxeff + p->C[1][2]*dvyyeff + p->C[4][1]*dvzzeff + p->C[1][3]*dgameff; c2=p->C[1][2]*dvxxeff + p->C[2][2]*dvyyeff + p->C[4][2]*dvzzeff + p->C[2][3]*dgameff; c3=p->C[1][3]*dvxxeff + p->C[2][3]*dvyyeff + p->C[4][3]*dvzzeff + p->C[3][3]*dgameff; } else { c1=p->C[1][1]*dvxxeff + p->C[1][2]*dvyyeff + p->C[1][3]*dgameff; c2=p->C[1][2]*dvxxeff + p->C[2][2]*dvyyeff + p->C[2][3]*dgameff; c3=p->C[1][3]*dvxxeff + p->C[2][3]*dvyyeff + p->C[3][3]*dgameff; } Hypo2DCalculations(mptr,-dwrotxy,c1,c2,c3); // work and resdiaul strain energu increments double workEnergy = 0.5*((st0.xx+sp->xx)*dvxx + (st0.yy+sp->yy)*dvyy + (st0.xy+sp->xy)*dgam); double resEnergy = 0.5*((st0.xx+sp->xx)*erxx + (st0.yy+sp->yy)*eryy + (st0.xy+sp->xy)*erxy); if(np==PLANE_STRAIN_MPM) { // need to add back terms to get from reduced cte to actual cte sp->zz += p->C[4][1]*(dvxx+p->alpha[5]*erzz)+p->C[4][2]*(dvyy+p->alpha[6]*erzz) +p->C[4][3]*(dgam+p->alpha[7]*erzz)-p->C[4][4]*erzz; // extra residual energy increment per unit mass (dU/(rho0 V0)) (by midpoint rule) (uJ/g) resEnergy += 0.5*(st0.zz+sp->zz)*erzz; } else if(np==PLANE_STRESS_MPM) { ep->zz += p->C[4][1]*dvxxeff+p->C[4][2]*dvyyeff+p->C[4][3]*dgameff+erzz; } else { // axisymmetric hoop stress sp->zz += p->C[4][1]*dvxxeff + p->C[4][2]*dvyyeff + p->C[4][4]*(dvzz - erzz) + p->C[4][3]*dgameff; // extra work and residual energy increment per unit mass (dU/(rho0 V0)) (by midpoint rule) (uJ/g) workEnergy += 0.5*(st0.zz+sp->zz)*dvzz; resEnergy += 0.5*(st0.zz+sp->zz)*erzz; } mptr->AddWorkEnergyAndResidualEnergy(workEnergy, resEnergy); // track heat energy IncrementHeatEnergy(mptr,res->dT,0.,0.); }