// 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;
}
Exemple #3
0
// 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();
}