// If needed, a material can initialize particle state // For example, ideal gas initializes to base line pressure // Such a class must pass on the super class after its own initializations void MaterialBase::SetInitialParticleState(MPMBase *mptr,int np) const { if(isolatedSystemAndParticles) { // need to add initial heat energy, because special cases in this mode // will ignore the Cv dT term double Cv = GetHeatCapacity(mptr); // in nJ/(g-K) mptr->AddHeatEnergy(Cv*(mptr->pTemperature-thermal.reference)); // initial entropy kept to zero, could add something here if ever needed } }
// Increment heat energy using Cv(dT-dTq0) - dPhi, where Cv*dTq0 + dPhi = Cv dTad is total // dispated energy (it can by provided as either a temperature rise or an energy) // dTq0 is temperature rise due to material mechanisms if the process was adiabatic // dPhi is dissipated energy that is converted to temperature rise void MaterialBase::IncrementHeatEnergy(MPMBase *mptr,double dT,double dTq0,double dPhi) const { double Cv = GetHeatCapacity(mptr); // in nJ/(g-K) double dispEnergy = Cv*dTq0 + dPhi; // = Cv dTad // Isolated means no conduction and no thermal ramp (and in future if have other ways // to change particle temperature, those are not active either) // In this mode, adiabatic has dq=0 and isothermal releases all as heat if(isolatedSystemAndParticles) { // Here dText = 0 // If adiabatic, dq = 0 (nothing to add) // If isothermal dq = -Cv dTad if(!ConductionTask::adiabatic) { mptr->AddHeatEnergy(-dispEnergy); mptr->AddEntropy(-dispEnergy/mptr->pPreviousTemperature); } } else { // For non isolated particle use dq = Cv(dT-dTad) // If adiabatic, the Cv dT term in next step will include Cv dTad from // this step to give particle dq = 0. If isothermal, it will not and // dq will be disspated heat double totalHeat = Cv*dT - dispEnergy; mptr->AddHeatEnergy(totalHeat); if(ConductionTask::adiabatic) { double dTad = dispEnergy/Cv; mptr->AddEntropy(Cv*dT/mptr->pPreviousTemperature - dispEnergy/(mptr->pPreviousTemperature+dTad)); } else { mptr->AddEntropy(totalHeat/mptr->pPreviousTemperature); } } // The dispated energy is added here, but only if adiabatic, in which case it will be // converted to particle temperature rise later in the calculations. This temperature // change works with conduction on or off if(ConductionTask::adiabatic) mptr->AddDispEnergy(dispEnergy); }
// For Cp heat capacity in nJ/(g-K) double MaterialBase::GetCpHeatCapacity(MPMBase *mptr) const { return GetHeatCapacity(mptr)+GetCpMinusCv(mptr); }
/* 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); }
double delTime,double &dTq0,double &AVEnergy) const #else void Viscoelastic::UpdatePressure(MPMBase *mptr,double delV,ResidualStrains *res,double eres,const Matrix3 *dF, double delTime,double &dTq0,double &AVEnergy) const #endif { if(pressureLaw==LINEAR_PRESSURE) { // pressure change #ifdef USE_KIRCHOFF_STRESS double dP = (detdF-1.)*mptr->GetPressure()-J*Kered*delV; #else double dP = -Kered*delV; #endif // artifical viscosity // delV is total incremental volumetric strain = total Delta(V)/V double QAVred = 0.; if(delV<0. && artificialViscosity) { // Wants K/rho #ifdef USE_KIRCHOFF_STRESS QAVred = GetArtificalViscosity(delV/delTime,sqrt(Kered*J)); #else QAVred = GetArtificalViscosity(delV/delTime,sqrt(Kered)); #endif if(ConductionTask::AVHeating) AVEnergy += fabs(QAVred*delV); } // increment pressure mptr->IncrementPressure(dP+QAVred); // work energy is dU = -P dV + s.de(total) // Here do hydrostatic term // Work energy increment per unit mass (dU/(rho0 V0)) (nJ/g) double avgP = mptr->GetPressure()-0.5*dP; mptr->AddWorkEnergyAndResidualEnergy(-avgP*delV,-3.*avgP*eres); // Isoentropic temperature rise = -(K alpha T)/(rho Cv) (dV/V) dTq0 += -Kered*CTE*mptr->pPreviousTemperature*(delV+3*eres)/GetHeatCapacity(mptr);; } else { // 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 // history pointer double **h =(double **)(mptr->GetHistoryPtr(0)); #ifndef USE_KIRCHOFF_STRESS // tracking J double detdF = dF->determinant(); double J = detdF*h[mptrHistory][MGJ_HISTORY]; h[mptrHistory][MGJ_HISTORY] = J; #endif // account for residual strains (needed in tension, but must always track) double dJres = exp(3.*CTE*res->dT); double Jres = dJres*h[mptrHistory][MGJRES_HISTORY]; h[mptrHistory][MGJRES_HISTORY] = Jres; // previous pressure double P,P0 = mptr->GetPressure(); double delVMG = 1. - 1./detdF; // (Vnp1-Vn)/Vnp1 double Kred; // 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) { #pragma omp critical (output) { cout << "# Excessive x = " << x << endl; mptr->Describe(); } } // current effective and reduced (by rho0) bulk modulus Kred = C0squared*(1.-0.5*gamma0*x)*denom*denom; // Pressure from bulk modulus and an energy term double e = mptr->GetInternalEnergy(); #ifdef USE_KIRCHOFF_STRESS P = J*(Kred*x + gamma0*e); #else P = Kred*x + gamma0*e; #endif // particle isentropic temperature increment dTq0 += -J*gamma0*mptr->pPreviousTemperature*delVMG; } else { // In tension hyperelastic law P = - K0(J-1) double Jeff = J/Jres; Kred = C0squared*Jeff; #ifdef USE_KIRCHOFF_STRESS P = -J*C0squared*(Jeff-1.); #else P = -C0squared*(Jeff-1.); #endif // particle isentropic temperature increment double Kratio = Jeff; dTq0 += -J*Kratio*gamma0*mptr->pPreviousTemperature*delVMG; } // artifical viscosity // delVMG is total incremental volumetric strain = total Delta(V)/V double QAVred = 0.; if(delVMG<0. && artificialViscosity) { QAVred = GetArtificalViscosity(delVMG/delTime,sqrt(Kred*J)); if(ConductionTask::AVHeating) AVEnergy += fabs(QAVred*delVMG); } // 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./dJres; mptr->AddWorkEnergyAndResidualEnergy(-avgP*delVMG,-avgP*delVres); } }