// Do these edges intersect? // Inspired by paper: "A Vertex Program for Efficient Box-Plane Intersection" // by Christof Rezk Salama and Andreas Kolb, 2005 bool IntersectEdges(int i,int j,Vector *Point,Vector *n) { // Vertices of edge ij Vector Vertex_i = MakeCubeCorner(i); // vertex i Vector Edge_ij = MakeCubeCorner(j); // vertex j Edge_ij.x -=Vertex_i.x; // difference of coordinates Edge_ij.y -=Vertex_i.y; Edge_ij.z -=Vertex_i.z; // Start calculating lambda double lambda = -DotVectors(&Vertex_i,n); // numerator of lambda double denom = DotVectors(&Edge_ij,n); // denominator of lambda // Don't divide by zero if(DbleEqual(denom,0.0)) { return false; // colinear } // Calculate lambda lambda = lambda/denom; // if not in [0,1] then it doesn't intersect if(lambda>1.0 || lambda<0.0) { return false; // doesn't intersect } // Find point Point->x = Vertex_i.x +lambda*Edge_ij.x; Point->y = Vertex_i.y +lambda*Edge_ij.y; Point->z = Vertex_i.z +lambda*Edge_ij.z; return true; // it does intersect }
// Adjust change in momentum for frictional contact in tangential direction // If has component of tangential motion, calculate force depending on whether it is sticking or sliding // When frictional sliding, find tangential force (times dt) and set flag, if not set flag false // When friction heating is on, set Ftdt term and set hasFriction to true // (hasFriction (meaning has frictional heating value) must be initialized to false when called) // contactArea only provided if frictional law needs it // Normally in contact when called, but some laws might want call even when not in contact. If return // value is false, the contact should be treated as no contact bool CoulombFriction::GetFrictionalDeltaMomentum(Vector *delPi,Vector *norm,double dotn,double *mredDE,double mred, bool getHeating,double contactArea,bool inContact,double deltime,Vector *at) const { // indicate no frictional heat yet *mredDE=-1.; // stick and frictionless are easy and no heating if(frictionStyle==STICK) { // stick conditions no change return true; } else if(frictionStyle==FRICTIONLESS) { // remove tangential term CopyScaleVector(delPi,norm,dotn); return true; } // Rest implements friction sliding // The initial delPi = (-N A dt) norm + (Sstick A dt) tang = dotn norm + dott tang // where N is normal traction (positive in compression), A is contact area, and dt is timestep // get unnormalized tangential vector and its magnitude // tang = delPi - dotn norm Vector tang; CopyVector(&tang,delPi); AddScaledVector(&tang,norm,-dotn); double tangMag = sqrt(DotVectors(&tang,&tang)); // if has tangential motion, we need to change momemtum if frictional sliding is occuring if(!DbleEqual(tangMag,0.)) { ScaleVector(&tang,1./tangMag); double dott = DotVectors(delPi,&tang); // make it positive for comparison to the positive frictional force Sslide if(dott < 0.) { ScaleVector(&tang,-1.); dott = -dott; } // Let frictional sliding force be Sslide Ac dt = f(N) Ac dt // Then if dott > Sslide Ac dt (which means Sstick>Sslide) // a. Set delPi = dotn norm + Sslide Ac dt tang // For example, Coulomb friction has Fslide dt = mu(dotn) so delPi = (norm - mu tang) dotn double SslideAcDt = GetSslideAcDt(-dotn,dott,0.,mred,contactArea,inContact,deltime); if(!inContact) return false; if(dott > SslideAcDt) { CopyScaleVector(delPi,norm,dotn); AddScaledVector(delPi,&tang,SslideAcDt); // get frictional heating term as friction work times reduced mass // As heat source need Energy/sec or divide by timestep*reduced mass // Note: only add frictional heating during momentum update (when friction // force is appropriate) and only if frictional contact heat is enabled. if(getHeating) { if(at!=NULL) { double Vs = SslideAcDt*(dott-SslideAcDt); AddScaledVector(at, delPi, -1./deltime); double AsDt = SslideAcDt*DotVectors(at,&tang)*deltime; if(AsDt>Vs) { //*mredDE = Vs*(Vs/AsDt-1.)+0.5*AsDt; *mredDE = 0.5*Vs*Vs/AsDt; } else *mredDE = Vs - 0.5*AsDt; } else *mredDE = SslideAcDt*(dott-SslideAcDt); } } } // still in contact return true; }
// 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(); }