// reverse active linear loads. Leave rest alone // input is analysis time in seconds // if LINEAR_VALUE, set finalTime to time when load returns to zero MatPtLoadBC *MatPtLoadBC::ReverseLinearLoad(double bctime,double *finalTime,bool holdFirst) { switch(style) { case LINEAR_VALUE: if(bctime>=GetBCFirstTime()) { SetBCOffset(BCValue(bctime)); if(holdFirst) { // change to offset (set above) with zero slope to get a constant load holdValue = GetBCValue(); holding = true; SetBCValue(0.); } else { // get unloading slope (units/time) double bcvalue = holding ? -holdValue : -GetBCValue() ; // change to offset+(slope)*(time-ftime) by setting offset (above), new slope, and new first time SetBCValueCU(bcvalue); SetBCFirstTimeCU(bctime); // find time when BC returns to zero // new BC is offset+value*(mstime-ftime), which is zero when mstime = ftime-offset/value *finalTime = GetBCFirstTime() - GetBCOffset()/GetBCValue(); } } break; default: break; } return (MatPtLoadBC *)GetNextObject(); }
// increment external load on a particle // input is analysis time in seconds MatPtLoadBC *MatPtLoadBC::AddMPLoad(double bctime) { if(style!=SILENT) { double mstime=1000.*bctime; Vector *pFext=mpm[ptNum-1]->GetPFext(); if(direction==X_DIRECTION) pFext->x+=BCValue(mstime); else if(direction==Y_DIRECTION) pFext->y+=BCValue(mstime); else pFext->z+=BCValue(mstime); } else { double mp=mpm[ptNum-1]->mp; // in g int matnum=mpm[ptNum-1]->MatID(); double cd=theMaterials[matnum]->WaveSpeed(FALSE,mpm[ptNum-1]); // in mm/sec (2D or isotropic only) double cs=theMaterials[matnum]->ShearWaveSpeed(FALSE,mpm[ptNum-1]); // in mm/sec Vector pVel=mpm[ptNum-1]->vel; Vector *pFext=mpm[ptNum-1]->GetPFext(); // get forces in g-mm/sec^2 if(direction==X_DIRECTION) { pFext->x-=mp*cd*pVel.x/(2.*mpmgrid.partx); pFext->y-=mp*cs*pVel.y/(2.*mpmgrid.partx); pFext->z-=mp*cs*pVel.z/(2.*mpmgrid.partx); } else if(direction==Y_DIRECTION) { pFext->x-=mp*cs*pVel.x/(2.*mpmgrid.party); pFext->y-=mp*cd*pVel.y/(2.*mpmgrid.party); pFext->z-=mp*cs*pVel.z/(2.*mpmgrid.party); } else { pFext->x-=mp*cs*pVel.x/(2.*mpmgrid.partz); pFext->y-=mp*cs*pVel.y/(2.*mpmgrid.partz); pFext->z-=mp*cd*pVel.z/(2.*mpmgrid.partz); } } return (MatPtLoadBC *)GetNextObject(); }
// hold active linear loads at current values. Leave rest alone // input is analysis time in seconds MatPtLoadBC *MatPtLoadBC::MakeConstantLoad(double bctime) { switch(style) { case LINEAR_VALUE: if(bctime>=GetBCFirstTime()) { style=CONSTANT_VALUE; SetBCValueCU(BCValue(bctime)); } break; default: break; } return (MatPtLoadBC *)GetNextObject(); }
// hold active linear loads at current values. Leave rest alone // input is analysis time in seconds MatPtLoadBC *MatPtLoadBC::MakeConstantLoad(double bctime) { double mstime=1000.*bctime; switch(style) { case LINEAR_VALUE: if(mstime>=ftime) { style=CONSTANT_VALUE; value=BCValue(mstime); } break; default: break; } return (MatPtLoadBC *)GetNextObject(); }
// reverse active linear loads. Leave rest alone // input is analysis time in seconds // if LINEAR_VALUE, set finalTime to time when load returns to zero MatPtLoadBC *MatPtLoadBC::ReverseLinearLoad(double bctime,double *finalTime) { double mstime=1000.*bctime; switch(style) { case LINEAR_VALUE: if(mstime>=ftime) { offset=BCValue(mstime); value=-value; ftime=mstime; // new BC is offset+value*(mstime-ftime), which is zero when mstime = ftime-offset/value *finalTime = 0.001*(ftime - offset/value); } break; default: break; } return (MatPtLoadBC *)GetNextObject(); }
// increment external load on a particle // input is analysis time in seconds // (only called when diffusion is active) MatPtFluxBC *MatPtFluxBC::AddMPFlux(double bctime) { // condition value is g/(mm^2-sec), Divide by rho*csat to get potential flux in mm/sec // find this flux and then add (times area) to get mm^3-potential/sec MPMBase *mpmptr = mpm[ptNum-1]; MaterialBase *matptr = theMaterials[mpmptr->MatID()]; // Flux is a scalar and we need int_(face) F Ni(x) dA // Since F is constant, only need integral which is done by CPDI methods // which has be generalized to work for GIMP too // We use X_DIRECTION for bcDIR for efficiency. For Silent BC, change to // Normal direction to all caculation of n Vector fluxMag; ZeroVector(&fluxMag); int bcDir=X_DIRECTION; if(style==SILENT) { TransportProperties t; matptr->GetTransportProps(mpmptr,fmobj->np,&t); Tensor *D = &(t.diffusionTensor); // D in mm^2/sec, Dc in 1/mm if(fmobj->IsThreeD()) { fluxMag.x = D->xx*mpmptr->pDiffusion[gGRADx] + D->xy*mpmptr->pDiffusion[gGRADy] + D->xz*mpmptr->pDiffusion[gGRADz]; fluxMag.y = D->xy*mpmptr->pDiffusion[gGRADx] + D->yy*mpmptr->pDiffusion[gGRADy] + D->yz*mpmptr->pDiffusion[gGRADz]; fluxMag.z = D->xz*mpmptr->pDiffusion[gGRADx] + D->yz*mpmptr->pDiffusion[gGRADy] + D->zz*mpmptr->pDiffusion[gGRADz]; } else { fluxMag.x = D->xx*mpmptr->pDiffusion[gGRADx] + D->xy*mpmptr->pDiffusion[gGRADy]; fluxMag.y = D->xy*mpmptr->pDiffusion[gGRADx] + D->yy*mpmptr->pDiffusion[gGRADy]; } bcDir = N_DIRECTION; } else if(direction==EXTERNAL_FLUX) { // csatrho = rho0 V0 csat/V (units g/mm^3) double csatrho = mpmptr->GetRho()*mpmptr->GetConcSaturation()/mpmptr->GetRelativeVolume(); fluxMag.x = BCValue(bctime)/csatrho; } else { // coupled surface flux and ftime is bath concentration // time variable (t) is replaced by c-cbath, where c is the particle potential and cbath is bath potential varTime = mpmptr->pPreviousConcentration-GetBCFirstTime(); GetPosition(&varXValue,&varYValue,&varZValue,&varRotValue); double currentValue = fabs(scale*function->Val()); if(varTime>0.) currentValue=-currentValue; // csatrho = rho0 V0 csat/V (units g/mm^3) double csatrho = mpmptr->GetRho()*mpmptr->GetConcSaturation()/mpmptr->GetRelativeVolume(); fluxMag.x = currentValue/csatrho; } // get corners and direction from material point int cElem[4],numDnds; Vector corners[4],tscaled; double ratio = mpmptr->GetTractionInfo(face,bcDir,cElem,corners,&tscaled,&numDnds); // compact CPDI nodes into list of nodes (nds) and final shape function term (fn) // May need up to 8 (in 3D) for each of the numDnds (2 in 2D or 4 in 3D) int nds[8*numDnds+1]; double fn[8*numDnds+1]; int numnds = CompactCornerNodes(numDnds,corners,cElem,ratio,nds,fn); // add force to each node int i; for(i=1;i<=numnds;i++) diffusion->AddFluxCondition(nd[nds[i]],DotVectors(&fluxMag,&tscaled)*fn[i],false); return (MatPtFluxBC *)GetNextObject(); }