// This method handles the pressure equation of state. Its tasks are // 1. Calculate the new pressure // 2. Update particle pressure // 3. Increment the particle energy // 4. Call plasticLaw to see if it wants to change the shear modulus // 5. Optionally change delV (which is passed by reference) // Notes: // delV is incremental volume change on this step. // J is total volume change at end of step (but it is 1 for low-strain materials) void IsoPlasticity::UpdatePressure(MPMBase *mptr,double &delV,double J,int np,PlasticProperties *p,ResidualStrains *res,double eres) const { // pressure change double dP = -p->Kred*delV; mptr->IncrementPressure(dP); // work energy is dU = -P dV + s.de(total) // Here do hydrostatic term // Work energy increment per unit mass (dU/(rho0 V0)) (uJ/g) double avgP = mptr->GetPressure()-0.5*dP; mptr->AddWorkEnergyAndResidualEnergy(-avgP*delV,-3.*avgP*eres); // heat energy is Cv dT - dPhi // Here do Cv dT term and dPhi is done later IncrementHeatEnergy(mptr,res->dT,0.,0.); }
// 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 dvzz,double dvxy,double dvyx, double dvxz,double dvzx,double dvyz,double dvzy,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; double deyyr=dvyy-eres; double dezzr=dvzz-eres; // use in plane strain only double dgxy=dvxy+dvyx; double dgxz=dvxz+dvzx; double dgyz=dvyz+dvzy; // rotational strain increments (particle updated by Hypo3D) double dwrotxy=dvyx-dvxy; double dwrotxz=dvzx-dvxz; double dwrotyz=dvzy-dvyz; // allow arbitrary equation of state for pressure UpdatePressure(mptr,delV,Jnew,np,p,res,eres); // Elastic deviatoric stress increment Tensor *ep=mptr->GetStrainTensor(); Tensor *sp=mptr->GetStressTensor(); Tensor stk,st0=*sp; double dsig[6]; double thirdDelV = delV/3.; dsig[XX] = 2.*p->Gred*(dexxr-thirdDelV); dsig[YY] = 2.*p->Gred*(deyyr-thirdDelV); dsig[ZZ] = 2.*p->Gred*(dezzr-thirdDelV); dsig[YZ] = p->Gred*dgyz; dsig[XZ] = p->Gred*dgxz; dsig[XY] = p->Gred*dgxy; stk.xx = st0.xx + dsig[XX]; stk.yy = st0.yy + dsig[YY]; stk.zz = st0.zz + dsig[ZZ]; stk.yz = st0.yz + dsig[YZ]; stk.xz = st0.xz + dsig[XZ]; stk.xy = st0.xy + dsig[XY]; // Calculate plastic potential f = ||s|| - sqrt(2/3)*sy(alpha,rate,...) HardeningAlpha alpha; plasticLaw->UpdateTrialAlpha(mptr,np,&alpha); // initialize to last value 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 to total strain ep->xx+=dvxx; ep->yy+=dvyy; ep->zz+=dvzz; ep->xy+=dgxy; ep->xz+=dgxz; ep->yz+=dgyz; // update stress (need to make hypoelastic) Hypo3DCalculations(mptr,dwrotxy,dwrotxz,dwrotyz,dsig); // work energy increment per unit mass (dU/(rho0 V0)) (uJ/g) mptr->AddWorkEnergy(0.5*((st0.xx+sp->xx)*dvxx + (st0.yy+sp->yy)*dvyy + (st0.zz+sp->zz)*dvzz + (st0.yz+sp->yz)*dgyz + (st0.xz+sp->xz)*dgxz + (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 material chance to update history variables that change in elastic updates ElasticUpdateFinished(mptr,np,delTime); return; } // Find direction of plastic strain and lambda for this plastic state // Base class finds it numerically, subclass can override if solvable by more efficient meethods Tensor dfds; GetDfDsigma(strial,&stk,np,&dfds); double lambdak = plasticLaw->SolveForLambdaBracketed(mptr,np,strial,&stk,p->Gred,1.,1.,delTime,&alpha,p->hardProps); // Now have lambda, finish update on this particle // 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 double dgxzp = 2.*lambdak*dfds.xz; // 2 for engineering plastic shear strain double dgyzp = 2.*lambdak*dfds.yz; // 2 for engineering plastic shear strain Tensor *eplast=mptr->GetPlasticStrainTensor(); eplast->xx += dexxp; eplast->yy += deyyp; eplast->zz += dezzp; eplast->xy += dgxyp; eplast->xz += dgxzp; eplast->yz += dgyzp; // Elastic strain increments on particle ep->xx += (dvxx-dexxp); ep->yy += (dvyy-deyyp); ep->zz += (dvzz-dezzp); dgxy -= dgxyp; ep->xy += dgxy; dgxz -= dgxzp; ep->xz += dgxz; dgyz -= dgyzp; ep->yz += dgyz; // Elastic strain increment minus the residual terms by now subtracting plastic parts dexxr -= dexxp; deyyr -= deyyp; dezzr -= dezzp; // plain strain only //dgxy, dgxz, dgyz done above // increment particle deviatoric stresses dsig[XX] -= 2.*p->Gred*dexxp; dsig[YY] -= 2.*p->Gred*deyyp; dsig[ZZ] -= 2.*p->Gred*dezzp; dsig[YZ] -= p->Gred*dgyzp; dsig[XZ] -= p->Gred*dgxzp; dsig[XY] -= p->Gred*dgxyp; Hypo3DCalculations(mptr,dwrotxy,dwrotxz,dwrotyz,dsig); // work energy increment per unit mass (dU/(rho0 V0)) (uJ/g) double workEnergy = 0.5*((st0.xx+sp->xx)*dvxx + (st0.yy+sp->yy)*dvzz + (st0.zz+sp->zz)*dvzz + (st0.yz+sp->yz)*dgyz + (st0.xz+sp->xz)*dgxz + (st0.xy+sp->xy)*dgxy); // plastic strain work double plastEnergy = lambdak*(sp->xx*dfds.xx + sp->yy*dfds.yy + sp->zz*dfds.zz + 2.*sp->xy*dfds.xy + 2.*sp->xz*dfds.xz + 2.*sp->yz*dfds.yz); // 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 adiabatic heating occurs) // The Cv(dT-dTq0) was done already in update pressure IncrementHeatEnergy(mptr,0.,0.,dispEnergy); // The cumulative dissipated energy is tracked in plastic energy // Setting the disp energy allows heating if mechanical energy is on mptr->AddPlastEnergy(dispEnergy); // update internal variables plasticLaw->UpdatePlasticInternal(mptr,np,&alpha); }
// Apply Constitutive law, check np to know what type void TaitLiquid::MPMConstitutiveLaw(MPMBase *mptr,Matrix3 du,double delTime,int np,void *properties, ResidualStrains *res,int historyOffset) const { #ifdef NO_SHEAR_MODEL // get incremental deformation gradient const Matrix3 dF = du.Exponential(incrementalDefGradTerms); // decompose dF into dR and dU Matrix3 dR; Matrix3 dU = dF.RightDecompose(&dR,NULL); // current deformation gradient double detdF = dF.determinant(); Matrix3 pF = mptr->GetDeformationGradientMatrix(); Matrix3 F = dR*pF; if(np==THREED_MPM) F.Scale(pow(detdF,1./3.)); else F.Scale2D(sqrt(detdF)); // new deformation matrix with volume change onle mptr->SetDeformationGradientMatrix(F); #else #ifdef ELASTIC_B_MODEL // get incremental deformation gradient const Matrix3 dF = du.Exponential(incrementalDefGradTerms); double detdF = dF.determinant(); // current deformation gradient Matrix3 pF = mptr->GetDeformationGradientMatrix(); // new deformation matrix const Matrix3 F = dF*pF; mptr->SetDeformationGradientMatrix(F); #else // Update total deformation gradient, and calculate trial B double detdF = IncrementDeformation(mptr,du,NULL,np); #endif #endif // Get new J and save result on the particle double J = detdF * mptr->GetHistoryDble(J_History,historyOffset); mptr->SetHistoryDble(J_History,J,historyOffset); #ifdef ELASTIC_B_MODEL // store pressure strain as elastic B Tensor *pB = mptr->GetAltStrainTensor() ; if(np==THREED_MPM || np==AXISYMMETRIC_MPM) { double J23 = pow(J,2./3.); pB->xx = J23; pB->yy = J23; pB->zz = J23; } else { pB->xx = J; pB->yy = J; } #endif // account for residual stresses double dJres = GetIncrementalResJ(mptr,res); double Jres = dJres * mptr->GetHistoryDble(J_History+1,historyOffset); mptr->SetHistoryDble(J_History+1,Jres,historyOffset); double Jeff = J/Jres; // new Kirchhoff pressure (over rho0) from Tait equation double p0=mptr->GetPressure(); double pressure = J*TAIT_C*Ksp*(exp((1.-Jeff)/TAIT_C)-1.); mptr->SetPressure(pressure); // incremental energy per unit mass - dilational part double avgP = 0.5*(p0+pressure); double delV = 1. - 1./detdF; double workEnergy = -avgP*delV; // incremental residual energy per unit mass double delVres = 1. - 1./dJres; double resEnergy = -avgP*delVres; // viscosity term = 2 eta (0.5(grad v) + 0.5*(grad V)^T - (1/3) tr(grad v) I) = 2 eta dev(grad v) // (i.e., deviatoric part of the symmetric strain tensor, 2 is for conversion to engineering shear strain) // simple shear rate = |2 dev(grad v)| Matrix3 shear; double c[3][3]; double shearRate; c[0][0] = (2.*du(0,0)-du(1,1)-du(2,2))/3.; c[1][1] = (2.*du(1,1)-du(0,0)-du(2,2))/3.; c[2][2] = (2.*du(2,2)-du(0,0)-du(1,1))/3.; c[0][1] = 0.5*(du(0,1)+du(1,0)); c[1][0] = c[0][1]; shearRate = c[0][0]*c[0][0] + c[1][1]*c[1][1] + c[2][2]*c[2][2] + 2.*c[0][1]*c[0][1]; if(np==THREED_MPM) { c[0][2] = 0.5*(du(0,2)+du(2,0)); c[2][0] = c[0][2]; c[1][2] = 0.5*(du(1,2)+du(2,1)); c[2][1] = c[1][2]; shearRate += 2.*(c[0][2]*c[0][2] + c[1][2]*c[1][2]); shear.set(c); } else shear.set(c[0][0],c[0][1],c[1][0],c[1][1],c[2][2]); shearRate = 2.*sqrt(shearRate)/delTime; // Store shear rate mptr->SetHistoryDble(J_History+2,shearRate,historyOffset); // Get effective visocisy double twoetaspRate = 0.; if(numViscosity==1) { twoetaspRate = TwoEtasp[0]; } else { shearRate = log10(shearRate); if(shearRate < logShearRate[0]) twoetaspRate = TwoEtasp[0]; else if(shearRate > logShearRate[numViscosity-1]) twoetaspRate = TwoEtasp[numViscosity-1]; else { // interpolate for(int i=1;i<numViscosity;i++) { if(shearRate <= logShearRate[i]) { // between i-1 and i double fract = (logShearRate[i]-shearRate)/(logShearRate[i]-logShearRate[i-1]); twoetaspRate = fract*TwoEtasp[i-1] + (1.-fract)*TwoEtasp[i]; break; } } } } // Get Kirchoff shear stress (over rho0) shear.Scale(J*twoetaspRate/delTime); // update deviatoric stress Tensor *sp=mptr->GetStressTensor(); sp->xx = shear(0,0); sp->yy = shear(1,1); sp->zz = shear(2,2); sp->xy = shear(0,1); if(np==THREED_MPM) { sp->xz = shear(0,2); sp->yz = shear(1,2); } // shear work per unit mass = tau.du = tau.tau*delTime/twoetaspRate double shearWork = sp->xx*sp->xx + sp->yy*sp->yy + sp->zz*sp->zz + 2.*sp->xy*sp->xy; if(np==THREED_MPM) shearWork += 2.*(sp->xz*sp->xz + sp->yz*sp->yz); shearWork *= delTime/twoetaspRate; mptr->AddWorkEnergyAndResidualEnergy(workEnergy+shearWork,resEnergy); // particle isentropic temperature increment dT/T = - J (K/K0) gamma0 Delta(V)/V // Delta(V)/V = 1. - 1/detdF (total volume) double Kratio = Jeff*(1.+pressure/(TAIT_C*Ksp)); double dTq0 = -J*Kratio*gamma0*mptr->pPreviousTemperature*delV; // heat energy is Cv (dT - dTq0) -dPhi // Here do Cv (dT - dTq0) // dPhi = shearWork is lost due to shear term IncrementHeatEnergy(mptr,res->dT,dTq0,shearWork); }
// 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); }
/* Take increments in strain and calculate new Particle: strains, rotation strain, stresses, strain energy, 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 Neohookean::MPMConstitutiveLaw(MPMBase *mptr,Matrix3 du,double delTime,int np,void *properties, ResidualStrains *res,int historyOffset) const { // Update strains and rotations and Left Cauchy strain double detDf = IncrementDeformation(mptr,du,NULL,np); // get pointer to new left Cauchy strain Tensor *B = mptr->GetAltStrainTensor(); // account for residual stresses double dJres = GetIncrementalResJ(mptr,res); double Jres = dJres*mptr->GetHistoryDble(J_History+1,historyOffset); mptr->SetHistoryDble(J_History+1,Jres,historyOffset); double resStretch = pow(Jres,1./3.); double Jres23 = resStretch*resStretch; // Deformation gradients and Cauchy tensor differ in plane stress if(np==PLANE_STRESS_MPM) { // Find B->zz required to have zero stress in z direction double arg = B->xx*B->yy - B->xy*B->xy; double xn; Tensor *ep=mptr->GetStrainTensor(); switch(UofJOption) { case J_MINUS_1_SQUARED: { double a = pr.Lamesp*arg + pr.Gsp*pow(Jres,4./3.); double b = pr.Lamesp*sqrt(arg); xn = Jres*(b + sqrt(b*b + 4.*pr.Gsp*a))/(2.*a); xn *= xn; break; } case LN_J_SQUARED: { xn = B->zz; double fx,fxp,xnp1,Jres23 = pow(Jres,2./3.); int iter=1; while(iter<20) { // get f and df/dxn fx = pr.Gsp*(xn-Jres23) + 0.5*pr.Lamesp*Jres23*log(xn*arg/(Jres*Jres)); fxp = pr.Gsp + pr.Lamesp*Jres23/(2*xn); // new prediction for solution xnp1 = xn - fx/fxp; if(fabs(xn-xnp1)<1e-10) break; xn = xnp1; iter+=1; } break; } case HALF_J_SQUARED_MINUS_1_MINUS_LN_J: default: xn = Jres*Jres*(pr.Lamesp+2.*pr.Gsp)/(pr.Lamesp*arg+2.*pr.Gsp*pow(Jres,4./3.)); break; } // Done and xn = new B->zz = Fzz^2 = dFzz*(old Bzz)*dFzz = dFzz^2*(old Bzz), // and Fzz = dFzz*(old Fzz) = 1 + ep->zz //cout << xn << "," << pow(Jres,2./3.)*pr.Lamesp*(xn*arg/(Jres*Jres)-1.) + 2.*pr.Gsp*(xn-pow(Jres,2./3.)) << endl;; double dFzz = sqrt(xn/B->zz); B->zz = xn; // particle strain ezz now known ep->zz = dFzz*(1.+ep->zz) - 1.; // incremental J changes detDf *= dFzz; } // Increment J and save it in history data double J = detDf*mptr->GetHistoryDble(J_History,historyOffset); mptr->SetHistoryDble(J_History,J,historyOffset); // for incremental energy, store initial stress Tensor *sporig=mptr->GetStressTensor(); Tensor st0 = *sporig; // account for residual stresses double Jeff = J/Jres; // update pressure double p0=mptr->GetPressure(); double Pterm = J*GetVolumetricTerms(Jeff,pr.Lamesp) + Jres*pr.Gsp*((B->xx+B->yy+B->zz)/(3.*Jres23) - 1.); // artifical viscosity double delV = 1. - 1./detDf; // total volume change double QAVred = 0.,AVEnergy=0.; if(delV<0. && artificialViscosity) { QAVred = GetArtificalViscosity(delV/delTime,sqrt(pr.Ksp)*J); if(ConductionTask::AVHeating) AVEnergy = fabs(QAVred*delV); } double Pfinal = -Pterm + QAVred; // set the pressure mptr->SetPressure(Pfinal); // incremental energy - dilational part double avgP = 0.5*(p0+Pfinal); double dilEnergy = -avgP*delV; // incremental residual energy double delVres = 1. - 1./dJres; double resEnergy = -avgP*delVres; // Account for density change in specific stress // i.e.. Get (Kirchoff Stress)/rho0 double GJeff = resStretch*pr.Gsp; // = J*(Jres^(1/3) G/J) to get Kirchoff // find deviatoric (Cauchy stress)J/rho0 = deviatoric (Kirchoff stress)/rho0 Tensor *sp=mptr->GetStressTensor(); double I1third = (B->xx+B->yy+B->zz)/3.; sp->xx = GJeff*(B->xx-I1third); sp->yy = GJeff*(B->yy-I1third); sp->zz = GJeff*(B->zz-I1third); sp->xy = GJeff*B->xy; if(np==THREED_MPM) { sp->xz = GJeff*B->xz; sp->yz = GJeff*B->yz; } // incremental work energy = shear energy 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)*(du(0,1)+du(1,0))); if(np==THREED_MPM) { shearEnergy += 0.5*((sp->xz+st0.xz)*(du(0,2)+du(2,0)) + (sp->yz+st0.yz)*(du(1,2)+du(2,1))); } // strain energy double dU = dilEnergy + shearEnergy; mptr->AddWorkEnergyAndResidualEnergy(dU,resEnergy); // particle isentropic temperature increment double Kratio; // = rho_0 K/(rho K_0) double Jeff1third = pow(Jeff,1./3.); double Gterm = pr.Gsp*(1. - Jeff1third*Jeff1third + 2./(3.*Jeff1third)); switch(UofJOption) { case J_MINUS_1_SQUARED: Kratio = pr.Lamesp+Jeff + Gterm; break; case LN_J_SQUARED: Kratio = pr.Lamesp*(1-log(Jeff))/(Jeff*Jeff) + Gterm; break; case HALF_J_SQUARED_MINUS_1_MINUS_LN_J: default: Kratio = 0.5*(Jeff + 1./Jeff); break; } Kratio /= pr.Ksp; double dTq0 = -J*Kratio*gamma0*mptr->pPreviousTemperature*delV; // thermodynamics heat and temperature IncrementHeatEnergy(mptr,res->dT,dTq0,QAVred); }
/* 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); }
/* For 3D 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 */ void Elastic::MPMConstLaw(MPMBase *mptr,double dvxx,double dvyy,double dvzz,double dvxy,double dvyx, double dvxz,double dvzx,double dvyz,double dvzy,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; ep->zz += dvzz; double dgamxy = dvxy+dvyx; ep->xy += dgamxy; double dgamxz = dvxz+dvzx; ep->xz += dgamxz; double dgamyz = dvyz+dvzy; ep->yz += dgamyz; // rotational strain increments (particle updated by Hypo3D) double dwrotxy = dvyx-dvxy; double dwrotxz = dvzx-dvxz; double dwrotyz = dvzy-dvyz; // residual strains (thermal and moisture) (isotropic only) double exxr = p->alpha[0]*res->dT; double eyyr = p->alpha[1]*res->dT; double ezzr = p->alpha[2]*res->dT; double eyzr = p->alpha[3]*res->dT; double exzr = p->alpha[4]*res->dT; double exyr = p->alpha[5]*res->dT; if(DiffusionTask::active) { exxr += p->beta[0]*res->dC; eyyr += p->beta[1]*res->dC; ezzr += p->beta[2]*res->dC; eyzr += p->beta[3]*res->dC; exzr += p->beta[4]*res->dC; exyr += p->beta[5]*res->dC; } // effective strains double dvxxeff = dvxx-exxr; double dvyyeff = dvyy-eyyr; double dvzzeff = dvzz-ezzr; double dgamyzeff = dgamyz-eyzr; double dgamxzeff = dgamxz-exzr; double dgamxyeff = dgamxy-exyr; // save initial stresses Tensor *sp=mptr->GetStressTensor(); Tensor st0=*sp; // stress increments double delsp[6]; int i; for(i=0;i<6;i++) { delsp[i] = p->C[i][0]*dvxxeff + p->C[i][1]*dvyyeff + p->C[i][2]*dvzzeff + p->C[i][3]*dgamyzeff + p->C[i][4]*dgamxzeff + p->C[i][5]*dgamxyeff; } // update stress (need to make hypoelastic) Hypo3DCalculations(mptr,dwrotxy,dwrotxz,dwrotyz,delsp); // work energy increment per unit mass (dU/(rho0 V0)) mptr->AddWorkEnergyAndResidualEnergy( 0.5*((st0.xx+sp->xx)*dvxx + (st0.yy+sp->yy)*dvyy + (st0.zz+sp->zz)*dvzz + (st0.yz+sp->yz)*dgamyz + (st0.xz+sp->xz)*dgamxz + (st0.xy+sp->xy)*dgamxy), 0.5*((st0.xx+sp->xx)*exxr + (st0.yy+sp->yy)*eyyr + (st0.zz+sp->zz)*ezzr + (st0.yz+sp->yz)*eyzr + (st0.xz+sp->xz)*exzr + (st0.xy+sp->xy)*exyr)); // track heat energy IncrementHeatEnergy(mptr,res->dT,0.,0.); }
// Apply Constitutive law, check np to know what type void TaitLiquid::MPMConstitutiveLaw(MPMBase *mptr,Matrix3 du,double delTime,int np,void *properties,ResidualStrains *res) const { #ifdef NO_SHEAR_MODEL // get incremental deformation gradient const Matrix3 dF = du.Exponential(incrementalDefGradTerms); // decompose dF into dR and dU Matrix3 dR; Matrix3 dU = dF.RightDecompose(&dR,NULL); // current deformation gradient double detdF = dF.determinant(); Matrix3 pF = mptr->GetDeformationGradientMatrix(); Matrix3 F = dR*pF; if(np==THREED_MPM) F.Scale(pow(detdF,1./3.)); else F.Scale2D(sqrt(detdF)); // new deformation matrix with volume change onle mptr->SetDeformationGradientMatrix(F); #else // Update total deformation gradient, and calculate trial B double detdF = IncrementDeformation(mptr,du,NULL,np); #endif // Get new J and save result on the particle double J = detdF * mptr->GetHistoryDble(J_history); mptr->SetHistoryDble(J_history,J); // account for residual stresses double dresStretch,resStretch = GetResidualStretch(mptr,dresStretch,res); double Jres = resStretch*resStretch*resStretch; double Jeff = J/Jres; // new Kirchhoff pressure (over rho0) from Tait equation double p0=mptr->GetPressure(); double pressure = J*TAIT_C*Ksp*(exp((1.-Jeff)/TAIT_C)-1.); mptr->SetPressure(pressure); // incremental energy per unit mass - dilational part double avgP = 0.5*(p0+pressure); double delV = 1. - 1./detdF; double workEnergy = -avgP*delV; // incremental residual energy per unit mass double delVres = 1. - 1./(dresStretch*dresStretch*dresStretch); double resEnergy = -avgP*delVres; // viscosity term = 2 eta (0.5(grad v) + 0.5*(grad V)^T - (1/3) tr(grad v) I) // (i.e., divatoric part of the symmetric strain tensor, 2 is for conversion to engineering shear strain) Matrix3 shear; double c[3][3]; c[0][0] = (2.*du(0,0)-du(1,1)-du(2,2))/3.; c[1][1] = (2.*du(1,1)-du(0,0)-du(2,2))/3.; c[2][2] = (2.*du(2,2)-du(0,0)-du(1,1))/3.; c[0][1] = 0.5*(du(0,1)+du(1,0)); c[1][0] = c[0][1]; if(np==THREED_MPM) { c[0][2] = 0.5*(du(0,2)+du(2,0)); c[2][0] = c[0][2]; c[1][2] = 0.5*(du(1,2)+du(2,1)); c[2][1] = c[1][2]; shear.set(c); } else shear.set(c[0][0],c[0][1],c[1][0],c[1][1],c[2][2]); // Get Kirchoff shear stress (over rho0) shear.Scale(J*TwoEtasp/delTime); // update deviatoric stress Tensor *sp=mptr->GetStressTensor(); sp->xx = shear(0,0); sp->yy = shear(1,1); sp->zz = shear(2,2); sp->xy = shear(0,1); if(np==THREED_MPM) { sp->xz = shear(0,2); sp->yz = shear(1,2); } // shear work per unit mass = tau.du = tau.tau*delTime/TwoEtasp double shearWork = sp->xx*sp->xx + sp->yy*sp->yy + sp->zz*sp->zz + 2.*sp->xy*sp->xy; if(np==THREED_MPM) shearWork += 2.*(sp->xz*sp->xz + sp->yz*sp->yz); shearWork *= delTime/TwoEtasp; mptr->AddWorkEnergyAndResidualEnergy(workEnergy+shearWork,resEnergy); // particle isentropic temperature increment dT/T = - J (K/K0) gamma0 Delta(V)/V // Delta(V)/V = 1. - 1/detdF (total volume) double Kratio = Jeff*(1.+pressure/(TAIT_C*Ksp)); double dTq0 = -J*Kratio*gamma0*mptr->pPreviousTemperature*delV; // heat energy is Cv (dT - dTq0) -dPhi // Here do Cv (dT - dTq0) // dPhi = shearWork is lost due to shear term IncrementHeatEnergy(mptr,res->dT,dTq0,shearWork); }
// This method handles the pressure equation of state. Its tasks are // 1. Calculate the new pressure // 2. Update particle pressure // 3. Increment the particle energy due to dilation // 4. Call plasticLaw to see if it wants to change the shear modulus // J = V(T,c)/V0(T,c), Jeff = V(T,c)/V0(Tref,cref), Jres = V0(T,c)/V0(Tref,cref) = J/Jeff // Jtot = V(T,c)/V0(Trec,cref), Jres = V0(T,c)/V0(Tref,cref) for free expansion, J = V(T,c)/V0(T,c) // Jn+1 = (detdF/detdFres) Jn, Jresn+1 = detdFres Jresn, Jtot = detdF Jtotn // detdFres = (1+dres)^3 (approximately) // Here Tref and cref are starting conditions and T and c are current temperature and moisture void HEMGEOSMaterial::UpdatePressure(MPMBase *mptr,double J,double detdF,int np,double Jeff, double delTime,HEPlasticProperties *p,ResidualStrains *res,double detdFres) const { // J is total volume change - may need to reference to free-swelling volume if that works // Note that swelling looks like a problem because the sums of strains needs to be adjusted // to stress-free state // previous pressure double P,P0 = mptr->GetPressure(); double delV = 1. - 1./detdF; double dTq0; // M-G EOS // Want specific pressure or pressure over current density (using J = rho0/rho) if(J>1.) { // new compression J(k+1) = 1-x(k+1) double x = 1.-J; // compression law // denominator = 1 - S1*x - S2*x^2 - S3*x^3 double denom = 1./(1. - x*(S1 + x*(S2 + x*S3))); // law not valid if denominator passes zero if(denom<0) { cout << "# Excessive x = " << x << endl; mptr->Describe(); } // current effective and reduced (by rho0) bulk modulus p->Kred = C0squared*(1.-0.5*gamma0*x)*denom*denom; // Pressure from bulk modulus and an energy term double e = mptr->GetInternalEnergy(); P = J*(p->Kred*x + gamma0*e); // particle isentropic temperature increment dTq0 = -J*gamma0*mptr->pPreviousTemperature*delV; } else { // In tension hyperelastic law P = - K0(J-1) p->Kred = C0squared*Jeff; P = -J*C0squared*(Jeff-1.); //P = P0 - J*p->Kred*delV; // particle isentropic temperature increment double Kratio = Jeff; dTq0 = -J*Kratio*gamma0*mptr->pPreviousTemperature*delV; } // artifical viscosity // delV is total incremental volumetric strain = total Delta(V)/V double QAVred = 0.,AVEnergy=0.; if(delV<0. && artificialViscosity) { double c = sqrt(p->Kred*J/1000.); // m/sec QAVred = GetArtificalViscosity(delV/delTime,c); if(ConductionTask::AVHeating) AVEnergy = fabs(QAVred*delV); } // set final pressure mptr->SetPressure(P+QAVred); // work energy is dU = -P dV + s.de(total) // Here do hydrostatic terms, deviatoric later double avgP = 0.5*(P0+P); double delVres = 1. - 1./detdFres; mptr->AddWorkEnergyAndResidualEnergy(-avgP*delV,-avgP*delVres); // heat energy is Cv (dT - dTq0) - dPhi - |QAVred*delV| // Here do Cv (dT - dTq0) - |QAVred*delV| term and dPhi is done later IncrementHeatEnergy(mptr,res->dT,dTq0,AVEnergy); // SCGL and SL shear modulus and save Gratio = Jeff G/G0 for later calculations // Note: Jeff in Gred and Gratio is so that where they are used, they give // specific Cauchy stress p->Gred = G1sp * plasticLaw->GetShearRatio(mptr,avgP,Jeff,p->hardProps); }
/* Take increments in strain and calculate new Particle: strains, rotation strain, stresses, strain energy, 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 Mooney::MPMConstitutiveLaw(MPMBase *mptr,Matrix3 du,double delTime,int np,void *properties, ResidualStrains *res,int historyOffset) const { // incremental energy, store initial stress Tensor *sporig=mptr->GetStressTensor(); Tensor st0 = *sporig; // Update strains and rotations and Left Cauchy strain double detDf = IncrementDeformation(mptr,du,NULL,np); // get pointer to new left Cauchy strain Tensor *B = mptr->GetAltStrainTensor(); // account for residual stresses double dJres = GetIncrementalResJ(mptr,res); double Jres = dJres*mptr->GetHistoryDble(J_History+1,historyOffset); mptr->SetHistoryDble(J_History+1,Jres,historyOffset); // Deformation gradients and Cauchy tensor differ in plane stress if(np==PLANE_STRESS_MPM) { // Find B->zz required to have zero stress in z direction // fixed arguments double arg = B->xx*B->yy - B->xy*B->xy; double arg12 = sqrt(arg); double arg16 = pow(arg,1./6.); double arg2 = B->xx+B->yy; // Newton-Rapheson starting at B.zz = 1 // In tests finds answer in 3 or less steps Tensor *ep=mptr->GetStrainTensor(); double xn16,xn12,xnp1,xn = (1.+ep->zz)*(1.+ep->zz); double fx,fxp,J13,J0,J2,Jeff; int iter=1; double mJ2P,mdJ2PdJ; // solution for B.zz in xn and J = sqrt(xn*arg) with dJ/dxn = arg/(2 sqrt(xn*arg)) // Solving f=0 where f = 3J^2 Kterm + Jres*G1(2*xn-arg2)J^(1/3) + Jres*G2(xn*arg2 - 2*arg)/J^(1/3) // where J^(1/3) = (xn*arg)^(1/6) // df/dxn = d(3J^2 Kterm)/dJ dJ/dxn // + Jres*G1((14*xn-arg2)/(6*xn))J^(1/3) // + Jres*G2((5*xn*arg2+2*arg)/(6*xn))/J^(1/3) while(iter<20) { xn16 = pow(xn,1./6.); xn12 = sqrt(xn); J13 = xn16*arg16; J0 = xn12*arg12; J2 = J0*J0; Jeff = J0/Jres; // get f and df/dxn GetNewtonPressureTerms(Jeff, Ksp, mJ2P, mdJ2PdJ); fx = 3.*Jres*mJ2P + G1sp*(2.*xn-arg2)*J13 + G2sp*(xn*arg2-2.*arg)/J13; fxp = (1.5*J0/xn)*mdJ2PdJ + G1sp*J13*(14.*xn-arg2)/(6.*xn) + G2sp*(2.*arg+5.*xn*arg2)/(6.*J13*xn); // new prediction for solution xnp1 = xn - fx/fxp; //cout << iter << ": " << xn << "," << xnp1 << "," << fabs(xn-xnp1) << endl; if(fabs(xn-xnp1)<1e-10) break; xn = xnp1; iter+=1; } if(iter>=20) cout << "# Not enough iterations in plane stress Mooney-Rivlin material" << endl; // Done and xn = new B->zz = Fzz^2 = dFzz*(old Bzz)*dFzz = dFzz^2*(old Bzz), // and Fzz = dFzz*(old Fzz) = 1 + ep->zz double dFzz = sqrt(xn/B->zz); B->zz = xn; // particle strain ezz now known ep->zz = dFzz*(1.+ep->zz) - 1.; // incremental J changes detDf *= dFzz; } // Increment J and save it in history data double J = detDf*mptr->GetHistoryDble(J_History,historyOffset); mptr->SetHistoryDble(J_History,J,historyOffset); // account for residual stresses double Jeff = J/Jres; // update pressure double p0=mptr->GetPressure(); double Kterm = J*GetVolumetricTerms(Jeff,Ksp); // times J to get Kirchoff stress // artifical viscosity double delV = 1. - 1./detDf; // total volume change double QAVred = 0.,AVEnergy=0.; if(delV<0. && artificialViscosity) { QAVred = GetArtificalViscosity(delV/delTime,sqrt(Ksp*J),mptr); if(ConductionTask::AVHeating) AVEnergy = fabs(QAVred*delV); } double Pfinal = -Kterm + QAVred; // set the pressure mptr->SetPressure(Pfinal); // incremental energy - dilational part double avgP = 0.5*(p0+Pfinal); double dilEnergy = -avgP*delV; // incremental residual energy double delVres = 1. - 1./dJres; double resEnergy = -avgP*delVres; // Account for density change in specific stress // i.e.. Get (Cauchy Stress)/rho = J*(Cauchy Stress)/rho0 = (Kirchoff Stress)/rho0 double J23 = pow(J, 2./3.); double J43 = J23*J23; double JforG1 = J23/Jres; // J^(5/3)/(Jres J) = J^(2/3)/Jres to get Kirchoff stress double JforG2 = J43/Jres; // J^(7/3)/(Jres J) = J^(4/3)/Jres to get Kirchoff stress //JforG1 *= Jres; // this uses Jeff to get Kirchoff stress //JforG2 *= Jres; // this uses Jeff to get Kirchoff stress // find deviatoric (Cauchy stress)J/rho0 = deviatoric (Kirchoff stress)/rho0 Tensor *sp=mptr->GetStressTensor(); sp->xx = (2*B->xx-B->yy-B->zz)*G1sp/(3.*JforG1) + (B->xx*(B->yy+B->zz)-2*B->yy*B->zz-B->xy*B->xy)*G2sp/(3.*JforG2); sp->yy = (2*B->yy-B->xx-B->zz)*G1sp/(3.*JforG1) + (B->yy*(B->xx+B->zz)-2*B->xx*B->zz-B->xy*B->xy)*G2sp/(3.*JforG2); sp->zz = (2*B->zz-B->xx-B->yy)*G1sp/(3.*JforG1) + (B->zz*(B->xx+B->yy)-2*B->xx*B->yy+2.*B->xy*B->xy)*G2sp/(3.*JforG2); sp->xy = B->xy*G1sp/JforG1 + (B->zz*B->xy)*G2sp/JforG2; if(np==THREED_MPM) { sp->xx += (2.*B->yz*B->yz-B->xz*B->xz)*G2sp/(3.*JforG2); sp->yy += (2.*B->xz*B->xz-B->yz*B->yz)*G2sp/(3.*JforG2); sp->zz -= (B->xz*B->xz+B->yz*B->yz)*G2sp/(3.*JforG2); sp->xy -= B->xz*B->yz*G2sp/JforG2; sp->xz = B->xz*G1sp/JforG1 + (B->yy*B->xz-B->xy*B->yz)*G2sp/JforG2; sp->yz = B->yz*G1sp/JforG1 + (B->xx*B->yz-B->xy*B->xz)*G2sp/JforG2; } // incremental work energy = shear energy 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)*(du(0,1)+du(1,0))); if(np==THREED_MPM) { shearEnergy += 0.5*((sp->xz+st0.xz)*(du(0,2)+du(2,0)) + (sp->yz+st0.yz)*(du(1,2)+du(2,1))); } // strain energy double dU = dilEnergy + shearEnergy; mptr->AddWorkEnergyAndResidualEnergy(dU,resEnergy); // thermodynamics depends on whether or not this is a rubber double dTq0; if(rubber) { // convert internal energy to temperature change dTq0 = dU/GetHeatCapacity(mptr); } else { // elastic particle isentropic temperature increment double Kratio; // = rho_0 K/(rho K_0) switch(UofJOption) { case J_MINUS_1_SQUARED: Kratio = Jeff; break; case LN_J_SQUARED: Kratio = (1-log(Jeff))/(Jeff*Jeff); break; case HALF_J_SQUARED_MINUS_1_MINUS_LN_J: default: Kratio = 0.5*(Jeff + 1./Jeff); break; } dTq0 = -J*Kratio*gamma0*mptr->pPreviousTemperature*delV; } IncrementHeatEnergy(mptr,res->dT,dTq0,QAVred); }
/* Take increments in strain and calculate new Particle: strains, rotation strain, stresses, strain energy, du 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,int historyOffset) const { // current previous deformation gradient and stretch Matrix3 pFnm1 = mptr->GetDeformationGradientMatrix(); // get incremental deformation gradient and decompose it const Matrix3 dF = du.Exponential(incrementalDefGradTerms); Matrix3 dR; Matrix3 dVstretch = dF.LeftDecompose(&dR,NULL); // decompose to get previous stretch Matrix3 Vnm1 = pFnm1.LeftDecompose(NULL,NULL); // get strain increments de = (dV-I) dR Vnma dRT dVstretch(0,0) -= 1.; dVstretch(1,1) -= 1.; dVstretch(2,2) -= 1.; Matrix3 Vrot = Vnm1.RMRT(dR); Matrix3 detot = dVstretch*Vrot; // Update total deformation gradient Matrix3 pF = dF*pFnm1; mptr->SetDeformationGradientMatrix(pF); // 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 dTq0 = 0.,dispEnergy = 0.; double traceDe = detot.trace(); double delV = traceDe - 3.*eres; #ifdef USE_KIRCHOFF_STRESS // tracking J double detdF = dF.determinant(); double **h =(double **)(mptr->GetHistoryPtr(0)); double J = detdF*h[mptrHistory][MGJ_HISTORY]; h[mptrHistory][MGJ_HISTORY] = J; UpdatePressure(mptr,delV,res,eres,detdF,J,delTime,dTq0,dispEnergy); #else UpdatePressure(mptr,delV,res,eres,&dF,delTime,dTq0,dispEnergy); #endif // deviatoric strains increment in de // Actually de is finding 2*(dev e) to avoid many multiplies by two Tensor de; double dV = traceDe/3.; de.xx = 2.*(detot(0,0) - dV); de.yy = 2.*(detot(1,1) - dV); de.zz = 2.*(detot(2,2) - dV); de.xy = 2.*detot(0,1); if(np==THREED_MPM) { de.xz = 2.*detot(0,2); de.yz = 2.*detot(1,2); } // Find initial 2*e(t) (deviatoric strain) in ed Tensor ed; double thirdV = Vrot.trace()/3.; ed.xx = 2.*(Vrot(0,0)-thirdV); ed.yy = 2.*(Vrot(1,1)-thirdV); ed.zz = 2.*(Vrot(2,2)-thirdV); ed.xy = 2.*Vrot(0,1); if(np==THREED_MPM) { ed.xz = 2.*Vrot(0,2); ed.yz = 2.*Vrot(1,2); } // increment particle deviatoric stresses - elastic part 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; } // get internal variable increments, update them, add to incremental stress, and get dissipated energy6 Tensor dak; double **ak =(double **)(mptr->GetHistoryPtr(0)); 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; // add to stress increments dsig[XX] -= TwoGkred[k]*dak.xx; dsig[YY] -= TwoGkred[k]*dak.yy; dsig[ZZ] -= TwoGkred[k]*dak.zz; dsig[XY] -= TwoGkred[k]*dak.xy; // dissipation 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)); // extra terms for 3D if(np==THREED_MPM) { // internal variables 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; // stresses dsig[XZ] -= TwoGkred[k]*dak.xz; dsig[YZ] -= TwoGkred[k]*dak.yz; // dissipation 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)); } } // Update particle deviatoric stresses Tensor *sp=mptr->GetStressTensor(); //Tensor st0 = *sp; if(np==THREED_MPM) { // incremental rotate of prior stress Matrix3 stn(sp->xx,sp->xy,sp->xz,sp->xy,sp->yy,sp->yz,sp->xz,sp->yz,sp->zz); Matrix3 str = stn.RMRT(dR); #ifdef USE_KIRCHOFF_STRESS // convert sigma(n)/rho(n) to sigma(n)/rho(n+1) and add dsigma/rho(n+1) sp->xx = detdF*str(0,0)+J*dsig[XX]; sp->yy = detdF*str(1,1)+J*dsig[YY]; sp->xy = detdF*str(0,1)+J*dsig[XY]; sp->zz = detdF*str(2,2)+J*dsig[ZZ]; sp->yz = detdF*str(1,2)+J*dsig[YZ]; sp->xz = detdF*str(0,2)+J*dsig[XZ]; #else sp->xx = str(0,0)+dsig[XX]; sp->yy = str(1,1)+dsig[YY]; sp->xy = str(0,1)+dsig[XY]; sp->zz = str(2,2)+dsig[ZZ]; sp->yz = str(1,2)+dsig[YZ]; sp->xz = str(0,2)+dsig[XZ]; #endif } else { // incremental rotate of prior stress Matrix3 stn(sp->xx,sp->xy,sp->xy,sp->yy,sp->zz); Matrix3 str = stn.RMRT(dR); #ifdef USE_KIRCHOFF_STRESS // convert sigma(n)/rho(n) to sigma(n)/rho(n+1) and add dsigma/rho(n+1) sp->xx = detdF*str(0,0)+J*dsig[XX]; sp->yy = detdF*str(1,1)+J*dsig[YY]; sp->xy = detdF*str(0,1)+J*dsig[XY]; sp->zz = detdF*sp->zz+J*dsig[ZZ]; #else sp->xx = str(0,0)+dsig[XX]; sp->yy = str(1,1)+dsig[YY]; sp->xy = str(0,1)+dsig[XY]; sp->zz += dsig[ZZ]; #endif } // incremental work energy = shear energy (dilation and residual energy done in update pressure) double shearEnergy = sp->xx*detot(0,0) + sp->yy*detot(1,1) + sp->zz*detot(2,2) + sp->xy*de.xy; if(np==THREED_MPM) { shearEnergy += sp->xz*de.xz + sp->yz*de.yz; } mptr->AddWorkEnergyAndResidualEnergy(shearEnergy,0.); // disispated energy per unit mass (dPhi/(rho0 V0)) (nJ/g) 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,res->dT,dTq0,dispEnergy); }
// To allow some subclasses to support large deformations, the initial calculation for incremental // deformation gradient (the dvij), volume change (delV) can be // handled first by the subclass. This mtehod then finishes the constitutive law void IsoPlasticity::LRPlasticityConstLaw(MPMBase *mptr,double dexx,double deyy,double dezz,double dgxy, double dgxz,double dgyz,double delTime,int np,double delV,double eres, PlasticProperties *p,ResidualStrains *res,Matrix3 *dR) const { // here dvij is total strain increment, dexxr is relative strain by subtracting off eres double dexxr=dexx-eres; double deyyr=deyy-eres; double dezzr=dezz-eres; // allow arbitrary equation of state for pressure double dTq0 = 0.,dispEnergy = 0.; UpdatePressure(mptr,delV,np,p,res,eres,dTq0,dispEnergy); // Elastic deviatoric stress increment Tensor *sp=mptr->GetStressTensor(); Tensor stk; //Tensor st0=*sp; double dsig[6]; double thirdDelV = delV/3.; dsig[XX] = 2.*p->Gred*(dexxr-thirdDelV); dsig[YY] = 2.*p->Gred*(deyyr-thirdDelV); dsig[ZZ] = 2.*p->Gred*(dezzr-thirdDelV); dsig[YZ] = p->Gred*dgyz; dsig[XZ] = p->Gred*dgxz; dsig[XY] = p->Gred*dgxy; // incremental rotate of prior strain Tensor *eplast=mptr->GetAltStrainTensor(); Matrix3 etn(eplast->xx,0.5*eplast->xy,0.5*eplast->xz,0.5*eplast->xy,eplast->yy,0.5*eplast->yz, 0.5*eplast->xz,0.5*eplast->yz,eplast->zz); Matrix3 etr = etn.RMRT(*dR); Matrix3 stn(sp->xx,sp->xy,sp->xz,sp->xy,sp->yy,sp->yz,sp->xz,sp->yz,sp->zz); Matrix3 str = stn.RMRT(*dR); // trial deviatoric stress stk.xx = str(0,0) + dsig[XX]; stk.yy = str(1,1) + dsig[YY]; stk.zz = str(2,2) + dsig[ZZ]; stk.yz = str(1,2) + dsig[YZ]; stk.xz = str(0,2) + dsig[XZ]; stk.xy = str(0,1) + dsig[XY]; // Calculate plastic potential f = ||s|| - sqrt(2/3)*sy(alpha,rate,...) HardeningAlpha alpha; plasticLaw->UpdateTrialAlpha(mptr,np,&alpha,0); // initialize to last value 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 // set in-plane deviatoric stress *sp = stk; // rotate plastic strain eplast->xx = etr(0,0); eplast->yy = etr(1,1); eplast->zz = etr(2,2); eplast->xy = 2.*etr(0,1); eplast->xz = 2.*etr(0,2); eplast->yz = 2.*etr(1,2); // work energy increment per unit mass (dU/(rho0 V0)) (nJ/g) mptr->AddWorkEnergy(sp->xx*dexx + sp->yy*deyy + sp->zz*dezz + sp->yz*dgyz + sp->xz*dgxz + sp->xy*dgxy); //mptr->AddWorkEnergy(0.5*((st0.xx+sp->xx)*dexx + (st0.yy+sp->yy)*deyy + (st0.zz+sp->zz)*dezz // + (st0.yz+sp->yz)*dgyz + (st0.xz+sp->xz)*dgxz + (st0.xy+sp->xy)*dgxy)); // give material chance to update history variables that change in elastic updates plasticLaw->ElasticUpdateFinished(mptr,np,delTime,0); // heat energy from pressure and any pressure method items IncrementHeatEnergy(mptr,res->dT,dTq0,dispEnergy); return; } // Find direction of plastic strain and lambda for this plastic state // Base class finds it numerically, subclass can override if solvable by more efficient meethods Tensor dfds; GetDfDsigma(strial,&stk,np,&dfds); double lambdak = plasticLaw->SolveForLambdaBracketed(mptr,np,strial,&stk,p->Gred,1.,1.,delTime,&alpha,p->hardProps,0); // Now have lambda, finish update on this particle // 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 double dgxzp = 2.*lambdak*dfds.xz; // 2 for engineering plastic shear strain double dgyzp = 2.*lambdak*dfds.yz; // 2 for engineering plastic shear strain // incremental plastic strain eplast->xx = etr(0,0) + dexxp; eplast->yy = etr(1,1) + deyyp; eplast->zz = etr(2,2) + dezzp; eplast->xy = 2.*etr(0,1) + dgxyp; eplast->xz = 2.*etr(0,2) + dgxzp; eplast->yz = 2.*etr(1,2) + dgyzp; // increment particle deviatoric stresses sp->xx = stk.xx - 2.*p->Gred*dexxp; sp->yy = stk.yy - 2.*p->Gred*deyyp; sp->zz = stk.zz - 2.*p->Gred*dezzp; sp->yz = stk.yz - p->Gred*dgyzp; sp->xz = stk.xz - p->Gred*dgxzp; sp->xy = stk.xy - p->Gred*dgxyp; // work energy increment per unit mass (dU/(rho0 V0)) (nJ/g) double workEnergy = sp->xx*dexx + sp->yy*dezz + sp->zz*dezz + sp->yz*dgyz + sp->xz*dgxz + sp->xy*dgxy; //double workEnergy = 0.5*((st0.xx+sp->xx)*dexx + (st0.yy+sp->yy)*dezz + (st0.zz+sp->zz)*dezz // + (st0.yz+sp->yz)*dgyz + (st0.xz+sp->xz)*dgxz + (st0.xy+sp->xy)*dgxy); // total work mptr->AddWorkEnergy(workEnergy); // plastic strain work double plastEnergy = lambdak*(sp->xx*dfds.xx + sp->yy*dfds.yy + sp->zz*dfds.zz + 2.*sp->xy*dfds.xy + 2.*sp->xz*dfds.xz + 2.*sp->yz*dfds.yz); // and subtrace q dalpa disispated energy per unit mass (dPhi/(rho0 V0)) (nJ/g) double qdalphaTerm = lambdak*SQRT_TWOTHIRDS*plasticLaw->GetYieldIncrement(mptr,np,delTime,&alpha,p->hardProps); dispEnergy += plastEnergy - qdalphaTerm; // The cumulative dissipated energy is tracked in plastic energy // Setting the disp energy allows heating if mechanical energy is on mptr->AddPlastEnergy(dispEnergy); // 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 adiabatic heating occurs) // The Cv(dT-dTq0) was done already in update pressure IncrementHeatEnergy(mptr,res->dT,dTq0,dispEnergy); // update internal variables plasticLaw->UpdatePlasticInternal(mptr,np,&alpha,0); }
// To allow some subclasses to support large deformations, the initial calculation for incremental // deformation gradient (the dvij), volume change (delV) // handled first by the subclass. This method then finishes the constitutive law void IsoPlasticity::LRPlasticityConstLaw(MPMBase *mptr,double dexx,double deyy,double dgxy, double dezz,double delTime,int np,double delV,double eres, PlasticProperties *p,ResidualStrains *res,Matrix3 *dR) const { // here deij is total strain increment, dexxr is relative strain by subtracting off eres double dexxr = dexx-eres; double deyyr = deyy-eres; double dezzr = dezz-eres; // In plane strain trial dezz=0, but not in axisymmetric // allow arbitrary equation of state for pressure double P0 = mptr->GetPressure(); double dTq0 = 0.,dispEnergy = 0.; UpdatePressure(mptr,delV,np,p,res,eres,dTq0,dispEnergy); double Pfinal = mptr->GetPressure(); // Deviatoric stress increment Tensor *sp=mptr->GetStressTensor(); Tensor dels,stk; //Tensor 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; // incremental rotate of plastic strain Tensor *eplast=mptr->GetAltStrainTensor(); Matrix3 etn(eplast->xx,0.5*eplast->xy,0.5*eplast->xy,eplast->yy,eplast->zz); Matrix3 etr = etn.RMRT(*dR); eplast->xx = etr(0,0); eplast->yy = etr(1,1); eplast->xy = 2.*etr(0,1); // incremental rotation of stress Matrix3 stn(sp->xx,sp->xy,sp->xy,sp->yy,sp->zz); Matrix3 str = stn.RMRT(*dR); // trial deviatoric stress stk.xx = str(0,0) + dels.xx; stk.yy = str(1,1) + dels.yy; stk.zz = str(2,2) + dels.zz; stk.xy = str(0,1) + dels.xy; // Calculate plastic potential f = ||s|| - sqrt(2/3)*sy(alpha,rate,...) HardeningAlpha alpha; plasticLaw->UpdateTrialAlpha(mptr,np,&alpha,0); // 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 // set in plane deviatoric stress sp->xx = stk.xx; sp->xy = stk.xy; sp->yy = stk.yy; sp->zz = stk.zz; // work energy increment per unit mass (dU/(rho0 V0)) (by midpoint rule) (nJ/g) // energy units are also Pa mm^3/g, i.e., same as stress units if(np==AXISYMMETRIC_MPM) { mptr->AddWorkEnergy(sp->xx*dexx + sp->yy*deyy + sp->xy*dgxy + sp->zz*dezz); //mptr->AddWorkEnergy(0.5*((st0.xx+sp->xx)*dexx + (st0.yy+sp->yy)*deyy + (st0.xy+sp->xy)*dgxy + (st0.zz+sp->zz)*dezz)); } else if(np==PLANE_STRESS_MPM) { // zz deformation mptr->IncrementDeformationGradientZZ(-p->psLr2G*(dexxr+deyyr) + eres); mptr->AddWorkEnergy(sp->xx*dexx + sp->yy*deyy + sp->xy*dgxy); //mptr->AddWorkEnergy(0.5*((st0.xx+sp->xx)*dexx + (st0.yy+sp->yy)*deyy + (st0.xy+sp->xy)*dgxy)); } else { mptr->AddWorkEnergy(sp->xx*dexx + sp->yy*deyy + sp->xy*dgxy); //mptr->AddWorkEnergy(0.5*((st0.xx+sp->xx)*dexx + (st0.yy+sp->yy)*deyy + (st0.xy+sp->xy)*dgxy)); } // give subclass material chance to update history variables that change in elastic updates plasticLaw->ElasticUpdateFinished(mptr,np,delTime,0); // heat energy from pressure and any pressure method items IncrementHeatEnergy(mptr,res->dT,dTq0,dispEnergy); 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,0); // 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-sp->xx; dels.yy = syy+Pfinal-sp->yy; dels.xy = txy-sp->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 // zz deformation mptr->IncrementDeformationGradientZZ(-p->psLr2G*(dexxr+deyyr - lambdak*(dfds.xx+dfds.yy)) + eres + lambdak*dfds.zz); // 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 two 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 eplast->xx += dexxp; eplast->yy += deyyp; eplast->zz += dezzp; eplast->xy += dgxyp; // 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 // update in-plane stressees sp->xx = str(0,0) + dels.xx; sp->yy = str(1,1) + dels.yy; sp->xy = str(0,1) + dels.xy; // Elastic work increment per unit mass (dU/(rho0 V0)) (nJ/g) double workEnergy = sp->xx*dexx + sp->yy*deyy + sp->xy*dgxy; //double workEnergy = 0.5*((st0.xx+sp->xx)*dexx + (st0.yy+sp->yy)*deyy + (st0.xy+sp->xy)*dgxy); if(np==AXISYMMETRIC_MPM) { workEnergy += sp->zz*dezz; //workEnergy += 0.5*(st0.zz+sp->zz)*dezz; } // total work mptr->AddWorkEnergy(workEnergy); // plastic strain work double plastEnergy = lambdak*(sp->xx*dfds.xx + sp->yy*dfds.yy + sp->zz*dfds.zz + 2.*sp->xy*dfds.xy); // dand subtract q dalpha to get isispated energy per unit mass (dPhi/(rho0 V0)) (nJ/g) double qdalphaTerm = lambdak*SQRT_TWOTHIRDS*plasticLaw->GetYieldIncrement(mptr,np,delTime,&alpha,p->hardProps); dispEnergy += plastEnergy - qdalphaTerm; // The cumulative dissipated energy is tracked in plastic energy mptr->AddPlastEnergy(dispEnergy); // 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) IncrementHeatEnergy(mptr,res->dT,dTq0,dispEnergy); // update internal variables plasticLaw->UpdatePlasticInternal(mptr,np,&alpha,0); }
/* Take increments in strain and calculate new Particle: strains, rotation strain, stresses, strain energy, 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 HEIsotropic::MPMConstitutiveLaw(MPMBase *mptr,Matrix3 du,double delTime,int np,void *properties, ResidualStrains *res,int historyOffset) const { HEPlasticProperties *p = (HEPlasticProperties *)properties; // store initial stress Tensor *sp = mptr->GetStressTensor(); Tensor st0 = *sp; // Compute Elastic Predictor // ============================================ // Update total deformation gradient, and calculate trial B Tensor Btrial; double detdF = IncrementDeformation(mptr,du,&Btrial,np); // Deformation gradients and Cauchy tensor differ in plane stress and plane strain // This code handles plane strain, axisymmetric, and 3D - Plane stress is blocked double J = detdF * mptr->GetHistoryDble(J_History,historyOffset); mptr->SetHistoryDble(J_History,J,historyOffset); // Stocking J // J is determinant of F (or sqrt root of determinant of B), Jeff is normalized to residual stretch double dJres = GetIncrementalResJ(mptr,res); double Jres = dJres * mptr->GetHistoryDble(J_History+1,historyOffset); mptr->SetHistoryDble(J_History+1,Jres,historyOffset); double Jeff = J/Jres; // Get hydrostatic stress component in subroutine double dTq0 = 0.,dispEnergy = 0.; UpdatePressure(mptr,J,detdF,np,Jeff,delTime,p,res,dJres,historyOffset,dTq0,dispEnergy); // Others constants double J23 = pow(J, 2./3.)/Jres; // find Trial (Cauchy stress)/rho0 // (Trial_s/rho0 = Trial_s*rho/(rho*rho0) = (Trial_tau*rho/rho0^2) = (1/J)*(Trial_tau/rho0) Tensor stk = GetTrialDevStressTensor(&Btrial,J*J23,np,p->Gred); // Checking for plastic loading // ============================================ // Get magnitude of the deviatoric stress tensor // ||s|| = sqrt(s.s) // Set alpint for particle HardeningAlpha alpha; plasticLaw->UpdateTrialAlpha(mptr,np,&alpha,historyOffset); // Trial stress state double magnitude_strial = GetMagnitudeS(&stk,np); double gyld = plasticLaw->GetYield(mptr,np,delTime,&alpha,p->hardProps); double ftrial = magnitude_strial-SQRT_TWOTHIRDS*gyld; //cout << " #magnitude_strial = "<< magnitude_strial<< " GetYield = "<< gyld<< " ftrial = "<< ftrial<< endl; //cout << " #yldred = "<< yldred << " Epred = "<< Epred << " gyld = "<< gyld <<" alpint = "<< alpint<< " ftrial = "<< ftrial<< endl; // these will be needed for elastic or plastic Tensor *pB = mptr->GetAltStrainTensor(); //============================ // TEST //============================ if(ftrial<=0.) { // if elastic //============================ // save on particle *pB = Btrial; // Get specifique stress i.e. (Cauchy Stress)/rho = J*(Cauchy Stress)/rho0 = (Kirchoff Stress)/rho0 // The deviatoric stress was calculated as (Cauchy Stress)/rho, so need to scale by J to get correct stress sp->xx = J*stk.xx; sp->yy = J*stk.yy; sp->xy = J*stk.xy; sp->zz = J*stk.zz; // work energy per unit mass (U/(rho0 V0)) and we are using // W(F) as the energy density per reference volume V0 (U/V0) and not current volume V double workEnergy = 0.5*((st0.xx+sp->xx)*du(0,0) + (st0.yy+sp->yy)*du(1,1) + (st0.zz+sp->zz)*du(2,2) + (st0.xy+sp->xy)*(du(1,0)+du(0,1))); if(np==THREED_MPM) { sp->xz = J*stk.xz; sp->yz = J*stk.yz; workEnergy += 0.5*((st0.yz+sp->yz)*(du(2,1)+du(1,2)) + (st0.xz+sp->xz)*(du(2,0)+du(0,2))); } mptr->AddWorkEnergy(workEnergy); // residual energy or sigma.deres - it is zero here for isotropic material // because deviatoric stress is traceless and deres has zero shear terms // residual energy due to pressure was added in the pressure update // heat energy is Cv(dT-dTq0) - dPhi, all from pressure update IncrementHeatEnergy(mptr,res->dT,dTq0,dispEnergy); // give material chance to update history variables that change in elastic updates plasticLaw->ElasticUpdateFinished(mptr,np,delTime,historyOffset); return; } // Plastic behavior - Return Mapping algorithm //===================================================== // if plastic // JAN: Use hardening law method (which can now use other laws too) double Ie1bar = (Btrial.xx+Btrial.yy+Btrial.zz)/(3.*J23); double MUbar = Jres*p->Gred*Ie1bar; // Find lambda for this plastic state double dlambda = plasticLaw->SolveForLambdaBracketed(mptr,np,magnitude_strial,&stk, MUbar,1.,1.,delTime,&alpha,p->hardProps,historyOffset); // update deviatoric stress (need to scale by J to get to Kirchoff stress/rho Tensor nk = GetNormalTensor(&stk,magnitude_strial,np); //cout << "nk.xx = " << nk.xx << "nk.xy = " << nk.xy << endl; double twoMuLam = 2.*MUbar*dlambda; sp->xx = J*(stk.xx - twoMuLam*nk.xx); sp->yy = J*(stk.yy - twoMuLam*nk.yy); sp->zz = J*(stk.zz - twoMuLam*nk.zz); sp->xy = J*(stk.xy - twoMuLam*nk.xy); if(np == THREED_MPM) { sp->xz = J*(stk.xz - twoMuLam*nk.xz); sp->yz = J*(stk.yz - twoMuLam*nk.yz); } // save on particle double twoThirdsLamI1bar = 2.*dlambda*Ie1bar; pB->xx = Btrial.xx - twoThirdsLamI1bar*nk.xx; pB->yy = Btrial.yy - twoThirdsLamI1bar*nk.yy; pB->zz = Btrial.zz - twoThirdsLamI1bar*nk.zz; pB->xy = Btrial.xy - twoThirdsLamI1bar*nk.xy; if(np == THREED_MPM) { pB->xz = Btrial.xz - twoThirdsLamI1bar*nk.xz; pB->yz = Btrial.yz - twoThirdsLamI1bar*nk.yz; } /* Old method collecting B from stresses pB->xx = (sp->xx/p->Gred+Ie1bar)*J23; pB->yy = (sp->yy/p->Gred+Ie1bar)*J23; pB->zz = (sp->zz/p->Gred+Ie1bar)*J23; pB->xy = sp->xy*J23/p->Gred; if(np == THREED_MPM) { pB->xz = sp->xz*J23/p->Gred; pB->yz = sp->yz*J23/p->Gred; } */ // strain energy per unit mass (U/(rho0 V0)) and we are using double workEnergy = 0.5*((st0.xx+sp->xx)*du(0,0) + (st0.yy+sp->yy)*du(1,1) + (st0.zz+sp->zz)*du(2,2) + (st0.xy+sp->xy)*(du(1,0)+du(0,1))); if(np==THREED_MPM) { workEnergy += 0.5*((st0.yz+sp->yz)*(du(2,1)+du(1,2)) + (st0.xz+sp->xz)*(du(2,0)+du(0,2))); } // total work mptr->AddWorkEnergy(workEnergy); // residual energy or sigma.deres - it is zero here for isotropic material // because deviatoric stress is traceless and deres has zero shear terms // residual energy due to pressure was added in the pressure update // Plastic work increment per unit mass (dw/(rho0 V0)) (nJ/g) dispEnergy += dlambda*(sp->xx*nk.xx + sp->yy*nk.yy + sp->zz*nk.zz + 2.*sp->xy*nk.xy); if(np==THREED_MPM) dispEnergy += 2.*dlambda*(sp->xz*nk.xz + sp->yz*nk.yz); // Subtract q.dalpha to get final disispated energy per unit mass (dPhi/(rho0 V0)) (nJ/g) dispEnergy -= dlambda*SQRT_TWOTHIRDS*plasticLaw->GetYieldIncrement(mptr,np,delTime,&alpha,p->hardProps); // The cumulative dissipated energy is tracked in plastic energy mptr->AddPlastEnergy(dispEnergy); // heat energy is Cv(dT-dTq0) - dPhi IncrementHeatEnergy(mptr,res->dT,dTq0,dispEnergy); // update internal variables in the plastic law plasticLaw->UpdatePlasticInternal(mptr,np,&alpha,historyOffset); }
/* 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.); }
/* Take increments in strain and calculate new Particle: strains, rotation strain, stresses, strain energy, 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 ClampedNeohookean::MPMConstitutiveLaw(MPMBase *mptr,Matrix3 du,double delTime,int np,void *properties, ResidualStrains *res,int historyOffset) const { // Update total deformation gradient, and calculate trial B Tensor Btrial; double detDF = IncrementDeformation(mptr,du,&Btrial,np); // global J double J = detDF * mptr->GetHistoryDble(J_History,historyOffset); mptr->SetHistoryDble(J_History,J,historyOffset); // convert Btrial to matrix to get eigenvalues and check for clamping Matrix3 Belas(Btrial.xx,Btrial.xy,Btrial.xz, Btrial.xy,Btrial.yy,Btrial.yz, Btrial.xz,Btrial.yz,Btrial.zz); if(np!=THREED_MPM) Belas.setIs2D(true); // get Eigenvalues and Eigenvectors Vector lam2 = Belas.Eigenvalues(); // clamp eigenvalues if needed bool clamped = false; if(lam2.x<lamMin2 || lam2.x>lamMax2 || lam2.y<lamMin2 || lam2.y>lamMax2 || lam2.z<lamMin2 || lam2.z>lamMax2) clamped = true; // Get Je and Jp, adjusting if clamped double Je,Jp; Matrix3 Ucol; if(clamped) { // Find Belas = U.LAM.UT Ucol = Belas.Eigenvectors(lam2); // clamp values now if(lam2.x<lamMin2) lam2.x = lamMin2; else if(lam2.x>lamMax2) lam2.x = lamMax2; if(lam2.y<lamMin2) lam2.y = lamMin2; else if(lam2.y>lamMax2) lam2.y = lamMax2; if(lam2.z<lamMin2) lam2.z = lamMin2; else if(lam2.z>lamMax2) lam2.z = lamMax2; Matrix3 UcolT = Ucol.Transpose(); Matrix3 Lam(lam2.x,0.,0.,lam2.y,lam2.z); Matrix3 LamUcolT = Lam*UcolT; Belas = Ucol*LamUcolT; // get Je and Jp Je = sqrt(lam2.x*lam2.y*lam2.z); Jp = J/Je; mptr->SetHistoryDble(JP_HISTORY,Jp,historyOffset); } else { Jp = mptr->GetHistoryDble(JP_HISTORY,historyOffset); Je = J/Jp; if(elasticModel==ELASTIC_DISNEY) Ucol = Belas.Eigenvectors(lam2); } // store B elastic Tensor *sp=mptr->GetStressTensor(); Tensor *B = mptr->GetAltStrainTensor(); B->xx = Belas(0,0); B->yy = Belas(1,1); B->zz = Belas(2,2); B->xy = Belas(0,1); if(np==THREED_MPM) { B->xz = Belas(0,2); B->yz = Belas(1,2); } // change mechanical properties by hardening double arg = exp(hardening*(1.-Jp)); double altGsp = pr.Gsp*arg; double altLamesp = pr.Lamesp*arg; // account for residual stresses double dJres = GetIncrementalResJ(mptr,res); double Jres = dJres*mptr->GetHistoryDble(J_History+1,historyOffset); mptr->SetHistoryDble(J_History+1,Jres,historyOffset); double resStretch = pow(Jres,1./3.); double Jres23 = resStretch*resStretch; // account for residual stresses relative to elastic J double Jeff = Je/Jres; // for incremental energy, store initial stress and pressure Tensor *sporig=mptr->GetStressTensor(); Tensor st0 = *sporig; double Pfinal,p0=mptr->GetPressure(); if(elasticModel==ELASTIC_DISNEY) { // Use model from Disney paper // Get Cauchy stress/rho0 double sig[3][3]; double lam[3]; lam[0]=sqrt(lam2.x)/resStretch; lam[1]=sqrt(lam2.y)/resStretch; lam[2]=sqrt(lam2.z)/resStretch; for(int i=0;i<3;i++) { for(int j=i;j<3;j++) { sig[i][j] = 0.; for(int k=0;k<3;k++) { sig[i][j] += (2.*altGsp*lam[k]*(lam[k]-1)/Jeff + altLamesp*(Jeff-1))*Ucol(i,k)*Ucol(j,k); } } } // update pressure (*J to get Kirchoff pressure) Pfinal = -J*(sig[0][0]+sig[1][1]+sig[2][2])/3.; mptr->SetPressure(Pfinal); // get and set deviatoric stress // find eviatoric (Kirchoff stress)/rho0 = deviatoric (Cauchy stress)J/rho0 sp->xx = J*sig[0][0]+Pfinal; sp->yy = J*sig[1][1]+Pfinal; sp->zz = J*sig[2][2]+Pfinal; sp->xy = J*sig[0][1]; if(np==THREED_MPM) { sp->xz = J*sig[0][2]; sp->yz = J*sig[1][2]; } } else { // Use standard neo-Hookean law // update pressure (*J to get Kirchoff pressure) Pfinal = -J*(GetVolumetricTerms(Jeff,altLamesp) + (altGsp/Jeff)*((B->xx+B->yy+B->zz)/(3.*Jres23) - 1.)); mptr->SetPressure(Pfinal); // Account for density change in specific stress // i.e.. Get (Kirchoff Stress)/rho0 double GJeff = J*resStretch*altGsp/Je; // = J*(Jres^(1/3) G/Je) to get Kirchoff // find deviatoric (Kirchoff stress)/rho0 = deviatoric (Cauchy stress)J/rho0 double I1third = (B->xx+B->yy+B->zz)/3.; sp->xx = GJeff*(B->xx-I1third); sp->yy = GJeff*(B->yy-I1third); sp->zz = GJeff*(B->zz-I1third); sp->xy = GJeff*B->xy; if(np==THREED_MPM) { sp->xz = GJeff*B->xz; sp->yz = GJeff*B->yz; } } // work and residual energies double delV = 1. - 1./detDF; // total volume change double avgP = 0.5*(p0+Pfinal); double dilEnergy = -avgP*delV; // incremental residual energy double delVres = 1. - 1./dJres; double resEnergy = -avgP*delVres; // incremental work energy = shear energy 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)*(du(0,1)+du(1,0))); if(np==THREED_MPM) { shearEnergy += 0.5*((sp->xz+st0.xz)*(du(0,2)+du(2,0)) + (sp->yz+st0.yz)*(du(1,2)+du(2,1))); } // strain energy double dU = dilEnergy + shearEnergy; mptr->AddWorkEnergyAndResidualEnergy(dU,resEnergy); // thermodynamics heat and temperature // Should find energy dissipated by plasticity and add in third term IncrementHeatEnergy(mptr,res->dT,0.,0.); }
// Once stress deformation has been decomposed, finish calculations in the material axis system // When stress are found, they are rotated back to the global axes (using Rtot and dR) // Similar, strain increments are rotated back to find work energy (done in global system) void Elastic::LRElasticConstitutiveLaw(MPMBase *mptr,Matrix3 de,Matrix3 er,Matrix3 Rtot,Matrix3 dR, Matrix3 *Rnmatot,int np,void *properties,ResidualStrains *res) const { // effective strains double dvxxeff = de(0,0)-er(0,0); double dvyyeff = de(1,1)-er(1,1); double dvzzeff = de(2,2)-er(2,2); double dgamxy = 2.*de(0,1); // save initial stresses Tensor *sp=mptr->GetStressTensor(); //Tensor st0=*sp; // stress increments // cast pointer to material-specific data ElasticProperties *p = GetElasticPropertiesPointer(properties); if(np==THREED_MPM) { double dgamyz = 2.*de(1,2); double dgamxz = 2.*de(0,2); // update sigma = dR signm1 dRT + Rtot dsigma RtotT double dsigyz = p->C[3][3]*dgamyz; double dsigxz = p->C[4][4]*dgamxz; double dsigxy = p->C[5][5]*dgamxy; Matrix3 dsig(p->C[0][0]*dvxxeff + p->C[0][1]*dvyyeff + p->C[0][2]*dvzzeff, dsigxy, dsigxz, dsigxy, p->C[1][0]*dvxxeff + p->C[1][1]*dvyyeff + p->C[1][2]*dvzzeff, dsigyz, dsigxz, dsigyz, p->C[2][0]*dvxxeff + p->C[2][1]*dvyyeff + p->C[2][2]*dvzzeff); Matrix3 dsigrot = dsig.RMRT(Rtot); Matrix3 stn(sp->xx,sp->xy,sp->xz,sp->xy,sp->yy,sp->yz,sp->xz,sp->yz,sp->zz); Matrix3 str = stn.RMRT(dR); sp->xx = str(0,0) + dsigrot(0,0); sp->yy = str(1,1) + dsigrot(1,1); sp->zz = str(2,2) + dsigrot(2,2); sp->xy = str(0,1) + dsigrot(0,1); sp->xz = str(0,2) + dsigrot(0,2); sp->yz = str(1,2) + dsigrot(1,2); // stresses are in global coordinates so need to rotate strain and residual // strain to get work energy increment per unit mass (dU/(rho0 V0)) Matrix3 derot = de.RMRT(Rtot); Matrix3 errot = er.RMRT(Rtot); mptr->AddWorkEnergyAndResidualEnergy(sp->xx*derot(0,0) + sp->yy*derot(1,1) + sp->zz*derot(2,2) + 2.*(sp->yz*derot(1,2) + sp->xz*derot(0,2) + sp->xy*derot(0,1)), sp->xx*errot(0,0) + sp->yy*errot(1,1) + sp->zz*errot(2,2) + 2.*(sp->yz*errot(1,2) + sp->xz*errot(0,2) + sp->xy*errot(0,1)) ); //mptr->AddWorkEnergyAndResidualEnergy(0.5*((st0.xx+sp->xx)*derot(0,0) + (st0.yy+sp->yy)*derot(1,1) // + (st0.zz+sp->zz)*derot(2,2)) + (st0.yz+sp->yz)*derot(1,2) // + (st0.xz+sp->xz)*derot(0,2) + (st0.xy+sp->xy)*derot(0,1), // 0.5*((st0.xx+sp->xx)*errot(0,0) + (st0.yy+sp->yy)*errot(1,1) // + (st0.zz+sp->zz)*errot(2,2)) + (st0.yz+sp->yz)*errot(1,2) // + (st0.xz+sp->xz)*errot(0,2) + (st0.xy+sp->xy)*errot(0,1)); } else { // find stress increment // this does xx, yy, and xy only. zz done later if needed double dsxx,dsyy; if(np==AXISYMMETRIC_MPM) { dsxx = p->C[1][1]*dvxxeff + p->C[1][2]*dvyyeff + p->C[4][1]*dvzzeff ; dsyy = p->C[1][2]*dvxxeff + p->C[2][2]*dvyyeff + p->C[4][2]*dvzzeff; } else { dsxx = p->C[1][1]*dvxxeff + p->C[1][2]*dvyyeff; dsyy = p->C[1][2]*dvxxeff + p->C[2][2]*dvyyeff; } double dsxy = p->C[3][3]*dgamxy; // update sigma = dR signm1 dRT + Rtot dsigma RtotT Matrix3 dsig(dsxx,dsxy,dsxy,dsyy,0.); Matrix3 dsigrot = dsig.RMRT(Rtot); Matrix3 stn(sp->xx,sp->xy,sp->xy,sp->yy,sp->zz); Matrix3 str = stn.RMRT(dR); sp->xx = str(0,0) + dsigrot(0,0); sp->yy = str(1,1) + dsigrot(1,1); sp->xy = str(0,1) + dsigrot(0,1); // stresses are in global coordinate so need to rotate strain and residual // strain to get work energy increment per unit mass (dU/(rho0 V0)) double ezzr = er(2,2); Matrix3 derot = de.RMRT(Rtot); Matrix3 errot = er.RMRT(Rtot); // work and residual strain energy increments and sigma or F in z direction double workEnergy = sp->xx*derot(0,0) + sp->yy*derot(1,1) + 2.0*sp->xy*derot(0,1); double resEnergy = sp->xx*errot(0,0) + sp->yy*errot(1,1) + 2.*sp->xy*errot(0,1); //double workEnergy = 0.5*((st0.xx+sp->xx)*derot(0,0) + (st0.yy+sp->yy)*derot(1,1)) + (st0.xy+sp->xy)*derot(0,1); //double resEnergy = 0.5*((st0.xx+sp->xx)*errot(0,0) + (st0.yy+sp->yy)*errot(1,1)) + (st0.xy+sp->xy)*errot(0,1); if(np==PLANE_STRAIN_MPM) { // need to add back terms to get from reduced cte to actual cte sp->zz += p->C[4][1]*(dvxxeff+p->alpha[5]*ezzr) + p->C[4][2]*(dvyyeff+p->alpha[6]*ezzr) - p->C[4][4]*ezzr; // extra residual energy increment per unit mass (dU/(rho0 V0)) (by midpoint rule) (nJ/g) resEnergy += sp->zz*ezzr; //resEnergy += 0.5*(st0.zz+sp->zz)*ezzr; } else if(np==PLANE_STRESS_MPM) { // zz deformation mptr->IncrementDeformationGradientZZ(p->C[4][1]*dvxxeff + p->C[4][2]*dvyyeff + ezzr); } else { // axisymmetric hoop stress sp->zz += p->C[4][1]*dvxxeff + p->C[4][2]*dvyyeff + p->C[4][4]*dvzzeff; // extra work and residual energy increment per unit mass (dU/(rho0 V0)) (by midpoint rule) (nJ/g) workEnergy += sp->zz*de(2,2); resEnergy += sp->zz*ezzr; //workEnergy += 0.5*(st0.zz+sp->zz)*de(2,2); //resEnergy += 0.5*(st0.zz+sp->zz)*ezzr; } mptr->AddWorkEnergyAndResidualEnergy(workEnergy, resEnergy); } // track heat energy IncrementHeatEnergy(mptr,res->dT,0.,0.); }