Ejemplo n.º 1
0
// Update particle position, velocity, temp, and conc
// throws CommonException()
void UpdateParticlesTask::Execute(void)
{
	CommonException *upErr = NULL;
#ifdef CONST_ARRAYS
	int ndsArray[MAX_SHAPE_NODES];
	double fn[MAX_SHAPE_NODES];
#else
	int ndsArray[maxShapeNodes];
	double fn[maxShapeNodes];
#endif
    
    // Damping terms on the grid or on the particles
    //      particleAlpha   =  (1-beta)/dt + pdamping(t)
    //      gridAlpha       = -m*(1-beta)/dt + damping(t)
    double particleAlpha = bodyFrc.GetParticleDamping(mtime);
	double gridAlpha = bodyFrc.GetDamping(mtime);

	//		nonPICGridAlpha = damping(t)
	//		globalPIC       = (1-beta)/dt
    double nonPICGridAlpha = bodyFrc.GetNonPICDamping(mtime);
    double globalPIC = bodyFrc.GetPICDamping();

    // Update particle position, velocity, temp, and conc
#pragma omp parallel for private(ndsArray,fn)
    for(int p=0;p<nmpmsNR;p++)
	{	MPMBase *mpmptr = mpm[p];
		
		try
		{	// get shape functions
			const ElementBase *elemRef = theElements[mpmptr->ElemID()];
			int *nds = ndsArray;
			elemRef->GetShapeFunctions(fn,&nds,mpmptr);
			int numnds = nds[0];
			
			// Update particle position and velocity
			const MaterialBase *matRef=theMaterials[mpmptr->MatID()];
			int matfld=matRef->GetField();
            
			// Allow material to override global settings
            double localParticleAlpha = particleAlpha;
            double localGridAlpha = gridAlpha;
            matRef->GetMaterialDamping(localParticleAlpha,localGridAlpha,nonPICGridAlpha,globalPIC);
			
			// data structure for extrapolations
			GridToParticleExtrap *gp = new GridToParticleExtrap;
			
			// acceleration on the particle
			gp->acc = mpmptr->GetAcc();
			ZeroVector(gp->acc);
			
			// extrapolate nodal velocity from grid to particle
			ZeroVector(&gp->vgpnp1);
			
			// only two possible transport tasks
			double rate[2];
			rate[0] = rate[1] = 0.;
			int task;
			TransportTask *nextTransport;
			
			// Loop over nodes
			for(int i=1;i<=numnds;i++)
			{	// increment velocity and acceleraton
				const NodalPoint *ndptr = nd[nds[i]];
                short vfld = (short)mpmptr->vfld[i];
				
				// increment
				ndptr->IncrementDelvaTask5(vfld,matfld,fn[i],gp);

#ifdef CHECK_NAN
				// conditionally compiled check for nan velocities
                if(gp->vgpnp1.x!=gp->vgpnp1.x || gp->vgpnp1.y!=gp->vgpnp1.y || gp->vgpnp1.z!=gp->vgpnp1.z)
                {
#pragma omp critical (output)
					{	cout << "\n# UpdateParticlesTask::Execute: bad material velocity field for vfld=" << vfld << "matfld=" << matfld << " fn[i]=" << fn[i] << endl;;
						PrintVector("#  Particle velocity vgpn1 = ",&gp->vgpnp1);
						cout << endl;
						ndptr->Describe();
					}
                }
#endif
				
				// increment transport rates
				nextTransport=transportTasks;
				task=0;
				while(nextTransport!=NULL)
					nextTransport=nextTransport->IncrementTransportRate(ndptr,fn[i],rate[task++]);
			}

			// Find grid damping acceleration parts =  ag*Vgp(n) = ag*(Vgp(n+1) - Agp(n)*dt)
			Vector accExtra = gp->vgpnp1;
			AddScaledVector(&accExtra, gp->acc, -timestep);
			ScaleVector(&accExtra,localGridAlpha);
			
			// update position, and must be before velocity update because updates need initial velocity
            // This section does second order update
			mpmptr->MovePosition(timestep,&gp->vgpnp1,&accExtra,localParticleAlpha);
			
			// update velocity in mm/sec
			mpmptr->MoveVelocity(timestep,&accExtra);
			
			// update transport values
			nextTransport=transportTasks;
			task=0;
			while(nextTransport!=NULL)
				nextTransport=nextTransport->MoveTransportValue(mpmptr,timestep,rate[task++]);
			
			// energy coupling here adds adiabtic temperature rise
			if(ConductionTask::adiabatic)
			{	double dTad = mpmptr->GetBufferClear_dTad();			// in K
				mpmptr->pTemperature += dTad;							// in K
			}
			
			// delete grid to particle extrap data
			delete gp;
			
		}
		catch(CommonException& err)
		{	if(upErr==NULL)
			{
#pragma omp critical (error)
				upErr = new CommonException(err);
			}
		}
		catch(std::bad_alloc&)
		{	if(upErr==NULL)
			{
#pragma omp critical (error)
				upErr = new CommonException("Memory error","UpdateParticlesTask::Execute");
			}
		}
		catch(...)
		{	if(upErr==NULL)
			{
#pragma omp critical (error)
				upErr = new CommonException("Unexpected error","UpdateParticlesTask::Execute");
			}
		}
    }
	
	// throw any errors
	if(upErr!=NULL) throw *upErr;
    
    // rigid materials move at their current velocity
    for(int p=nmpmsNR;p<nmpms;p++)
    {	mpm[p]->MovePosition(timestep);
    }
}
Ejemplo n.º 2
0
// 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;
}
Ejemplo n.º 3
0
/*	Calculate change in momentum when there is contact. Return true or false if an adjustment was calculated
	If BC at the node, the delta momemtum should be zero in fixed direction
	Only called if both verified are verified and have 1 or more particles
	This method should ignore material that are ignoring cracks
*/
bool CrackSurfaceContact::GetDeltaMomentum(NodalPoint *np,Vector *delPa,CrackVelocityField *cva,CrackVelocityField *cvb,
											Vector *normin,int number,bool postUpdate,double deltime,int *inContact)
{
	// first determine if there is contact
	*inContact=IN_CONTACT;
	
	// velocities above and below
	bool hasParticles;
	double massa,massb;
	Vector pka=cva->GetCMatMomentum(hasParticles,&massa);
	Vector pkb=cvb->GetCMatMomentum(hasParticles,&massb);
	double mnode=1./(massa+massb);
	
	// screen low masses
	double aratio=massa*mnode;
	if(aratio<1.e-6 || aratio>0.999999) return false;
	//if(aratio<1.e-3 || aratio>0.999) return FALSE;
	
	// find Delta p_a (see notes)
	CopyScaleVector(delPa,&pkb,massa*mnode);
	AddScaledVector(delPa,&pka,-massb*mnode);
	
	// get normalized normal vector and find Delta p_a . n (actual (vb-va).n = dotn*(ma+mb)/(ma*mb))
	Vector norm;
	CopyScaleVector(&norm,normin,1./sqrt(DotVectors2D(normin,normin)));
	double dotn=DotVectors2D(delPa,&norm);
	
	// With the first check, any movement apart will be taken as noncontact
	// Also, frictional contact assume dvel<0.
	if(dotn>=0.)
		*inContact=SEPARATED;
	else
	{	// if approaching, check displacements
        // (Note: to use only velocity, skip the following displacement check)
		Vector dispa=cva->GetCMDisplacement(np,true);
		dispa.x/=massa;
		dispa.y/=massa;
		Vector dispb=cvb->GetCMDisplacement(np,true);
		dispb.x/=massb;
		dispb.y/=massb;
		
		// normal cod
		double dnorm=(dispb.x-dispa.x)*norm.x + (dispb.y-dispa.y)*norm.y
                        - mpmgrid.GetNormalCODAdjust(&norm,NULL,0);
		if(postUpdate)
		{	double dvel=(massa+massb)*dotn/(massa*massb);
			dnorm+=dvel*deltime;
		}
		
		// if current displacement positive then no contact
		if(dnorm >= 0.) *inContact=SEPARATED;
	}
	
	// if separated, then no contact unless possibly needed for an imperfect interface
	if(crackContactLaw[number]->ContactIsDone(*inContact==IN_CONTACT)) return false;
	
	// Now need to change momentum. For imperfect interface, change only for perfect directions
	double mredDE;
	if(crackContactLaw[number]->IsFrictionalContact())
	{	bool getHeating = postUpdate && ConductionTask::crackContactHeating;
		double mred = (massa*massb)/(massa+massb);
		double contactArea = 1.;
		if(crackContactLaw[number]->FrictionLawNeedsContactArea())
		{	// Angled path correction (2D only)
			double dist = mpmgrid.GetPerpendicularDistance(&norm, NULL, 0.);
			
			// Area correction method (new): sqrt(2*vmin/vtot)*vtot/dist = sqrt(2*vmin*vtot)/dist
			double vola = cva->GetVolumeNonrigid(true),volb = cvb->GetVolumeNonrigid(true),voltot=vola+volb;
			contactArea = sqrt(2.0*fmin(vola,volb)*voltot)/dist;
			if(fmobj->IsAxisymmetric()) contactArea *= np->x;
		}
		if(!crackContactLaw[number]->GetFrictionalDeltaMomentum(delPa,&norm,dotn,&mredDE,mred,
										getHeating,contactArea,*inContact==IN_CONTACT,deltime,NULL))
		{	return false;
		}
		if(mredDE>0.)
		{	double qrate = mredDE/mred;
			NodalPoint::frictionWork += qrate;
		
			// As heat source need nJ/sec or multiply by 1/timestep
			// Note that this is after transport rates are calculated (by true in last parameter)
			conduction->AddFluxCondition(np,fabs(qrate/deltime),true);
		}
	}
	else
	{
		// Contact handled here only perfect interface (Dt or Dn < 0)
		// Imperfect interfaces are handled as forces later
		if(crackContactLaw[number]->IsPerfectTangentialInterface())
		{	if(!crackContactLaw[number]->IsPerfectNormalInterface(*inContact==IN_CONTACT))
			{	// prefect in tangential, but imperfect in normal direction
				// make stick in tangential direction only
				AddScaledVector(delPa,&norm,-dotn);
			}
			// else perfect in both so return with the stick conditions already in delPa
		}
		else if(crackContactLaw[number]->IsPerfectNormalInterface(*inContact==IN_CONTACT))
		{	// perfect in normal direction, but imperfect in tangential direction
			// make stick in normal direction only
			CopyScaleVector(delPa,&norm,dotn);
		}
		else
		{	// no change in momentum, just imperfect interface forces later and nothing changed here
			return false;
		}
		
	}
	
	return true;
}
Ejemplo n.º 4
0
/*	Calculate change in momentum when there is contact. Return true or false if an adjustment was calculated
	If BC at the node, the delta momemtum should be zero in fixed direction
	Only called if both verified are verified and have 1 or more particles
	This method should ignore material that are ignoring cracks
*/
bool CrackSurfaceContact::GetDeltaMomentum(NodalPoint *np,Vector *delPa,CrackVelocityField *cva,CrackVelocityField *cvb,
											Vector *normin,int number,bool postUpdate,double deltime,int *inContact)
{
	// first determine if there is contact
	*inContact=IN_CONTACT;
	
	// velocities above and below
	bool hasParticles;
	double massa,massb;
	Vector pka=cva->GetCMatMomentum(hasParticles,&massa);
	Vector pkb=cvb->GetCMatMomentum(hasParticles,&massb);
	double mnode=1./(massa+massb);
	
	// screen low masses
	double aratio=massa*mnode;
	if(aratio<1.e-6 || aratio>0.999999) return false;
	//if(aratio<1.e-3 || aratio>0.999) return FALSE;
	
	// find Delta p_a (see notes)
	CopyScaleVector(delPa,&pkb,massa*mnode);
	AddScaledVector(delPa,&pka,-massb*mnode);
	
	// get normalized normal vector and find Delta p_a . n (actual (vb-va).n = dotn*(ma+mb)/(ma*mb))
	Vector norm;
	CopyScaleVector(&norm,normin,1./sqrt(DotVectors2D(normin,normin)));
	double dotn=DotVectors2D(delPa,&norm);
	
	// With the first check, any movement apart will be taken as noncontact
	// Also, frictional contact assume dvel<0.
	if(dotn>=0.)
		*inContact=SEPARATED;
	else
	{	// if approaching, check displacements
        // (Note: to use only velocity, skip the following displacement check)
		Vector dispa=cva->GetCMDisplacement(np,true);
		dispa.x/=massa;
		dispa.y/=massa;
		Vector dispb=cvb->GetCMDisplacement(np,true);
		dispb.x/=massb;
		dispb.y/=massb;
		
		// normal cod
		double dnorm=(dispb.x-dispa.x)*norm.x + (dispb.y-dispa.y)*norm.y
                        - mpmgrid.GetNormalCODAdjust(&norm,NULL,0);
		if(postUpdate)
		{	double dvel=(massa+massb)*dotn/(massa*massb);
			dnorm+=dvel*deltime;
		}
		
		// if current displacement positive then no contact
		if(dnorm >= 0.) *inContact=SEPARATED;
	}
	
	// if separated, then no contact unless possibly needed for an imperfect interface
	if(*inContact==SEPARATED && CrackContactLaw[number].law!=IMPERFECT_INTERFACE) return false;
	
	// Now need to change momentum. For imperfect interface, may or may not need a change
	Vector tang;
	double dott,mu;
	
    switch(CrackContactLaw[number].law)
    {	case STICK:
            break;
			
        case FRICTIONLESS:
			CopyScaleVector(delPa,&norm,dotn);
            break;
			
        case FRICTIONAL:
			CopyVector(&tang,delPa);
			AddScaledVector(&tang,&norm,-dotn);
			dott=sqrt(DotVectors2D(&tang,&tang));
			if(!DbleEqual(dott,0.))
			{	ScaleVector(&tang,1./dott);
				dott=DotVectors2D(delPa,&tang);
				if(dott<0.)
				{	ScaleVector(&tang,-1.);
					dott=-dott;
				}
				mu=-CrackContactLaw[number].friction;
				if(dott>mu*dotn)
				{	AddScaledVector(&norm,&tang,mu);
					CopyScaleVector(delPa,&norm,dotn);
                    
                    // get frictional heating part - this is g mm^2/sec^2 = nJ
                    // Note: only add frictional heating during momentum update (when frictional
                    //   force is appropriate) and only if conduction is on.
                    if(postUpdate && ConductionTask::crackContactHeating)
                    {   if(np->NodeHasNonrigidParticles())
                        {   Vector Ftdt;
                            CopyScaleVector(&Ftdt,&tang,mu*dotn);
                            double qrate = (massa+massb)*DotVectors2D(&Ftdt,delPa)/(massa*massb);
                            
                            // As heat source need nJ/sec or multiply by 1/timestep
                            // Note that this is after transport rates are calculated (by true in last parameter)
                            conduction->AddFluxCondition(np,fabs(qrate/deltime),true);
                        }
                    }
				}
			}
            break;
			
		case IMPERFECT_INTERFACE:
			// Contact handled here only perfect interface (Dt or Dn < 0)
			// Imperfect interfaces are handled as forces later
			if(CrackContactLaw[number].Dt<0)
			{	if( (*inContact==SEPARATED && CrackContactLaw[number].Dn>=0.) ||
				   (*inContact==IN_CONTACT && CrackContactLaw[number].Dnc>=0.) )
				{	// prefect in tangential, but imperfect in normal direction
					// make stick in tangential direction only
					AddScaledVector(delPa,&norm,-dotn);
				}
				// else perfect in both so return with the stick conditions already in delPa
			}
			else if( (*inContact==SEPARATED && CrackContactLaw[number].Dn<0.) ||
					(*inContact==IN_CONTACT && CrackContactLaw[number].Dnc<0.) )
			{	// perfect in normal direction, but imperfect in tangential direction
				// make stick in normal direction only
				CopyScaleVector(delPa,&norm,dotn);
			}
			else
			{	// no change in momentum, just imperfect interface forces later and nothing changed here
				return false;
			}
			break;
			
        default:
            break;
    }
	
	return true;
}
Ejemplo n.º 5
0
// Update particle position, velocity, temp, and conc
void UpdateParticlesTask::Execute(void)
{
	CommonException *upErr = NULL;
	
	int numnds,nds[maxShapeNodes];
	double fn[maxShapeNodes];
	Vector vgpnp1;
    
    // Damping terms on the grid or on the particles
    //      particleAlpha   =  alpha(PIC)/dt + pdamping(t)
    //      gridAlpha       = -alpha(PIC)/dt + damping(t)
    double particleAlpha = bodyFrc.GetParticleDamping(mtime);
	double gridAlpha = bodyFrc.GetDamping(mtime);

	// copy to local values (OSParticulas uses to implement material damping)
	double localParticleAlpha = particleAlpha;
	double localGridAlpha = gridAlpha;

    // Update particle position, velocity, temp, and conc
#pragma omp parallel for private(numnds,nds,fn,vgpnp1)
    for(int p=0;p<nmpmsNR;p++)
	{	MPMBase *mpmptr = mpm[p];
		
		try
		{	// get shape functions
			const ElementBase *elemRef = theElements[mpmptr->ElemID()];
			elemRef->GetShapeFunctions(&numnds,fn,nds,mpmptr);
			
			// Update particle position and velocity
			const MaterialBase *matRef=theMaterials[mpmptr->MatID()];
			int matfld=matRef->GetField();
			
			Vector *acc=mpmptr->GetAcc();
			ZeroVector(acc);
			ZeroVector(&vgpnp1);
			double rate[2];         // only two possible transport tasks
			rate[0] = rate[1] = 0.;
			int task;
			TransportTask *nextTransport;
            short vfld;
			
			// Loop over nodes
			for(int i=1;i<=numnds;i++)
			{	// increment velocity and acceleraton
				const NodalPoint *ndptr = nd[nds[i]];
                vfld = (short)mpmptr->vfld[i];
				ndptr->IncrementDelvaTask5(vfld,matfld,fn[i],&vgpnp1,acc);

#ifdef CHECK_NAN
                if(vgpnp1.x!=vgpnp1.x || vgpnp1.y!=vgpnp1.y || vgpnp1.z!=vgpnp1.z)
                {   cout << "\n# UpdateParticlesTask::Execute: bad material velocity field for vfld = " << vfld << endl;
                    ndptr->Describe();
                }
#endif
				
				// increment transport rates
				nextTransport=transportTasks;
				task=0;
				while(nextTransport!=NULL)
					nextTransport=nextTransport->IncrementTransportRate(ndptr,fn[i],rate[task++]);
			}
			
			// Find vgpn
			Vector vgpn = vgpnp1;
			AddScaledVector(&vgpn,acc,-timestep);
            
			// find effective grid acceleration and velocity
			AddScaledVector(acc,&vgpn,-localGridAlpha);
			AddScaledVector(&vgpnp1,&vgpn,-timestep*localGridAlpha);
			
			// update position, and must be before velocity update because updates need initial velocity
            // This section does second order update
			mpmptr->MovePosition(timestep,&vgpnp1,0.5*timestep,localParticleAlpha);

			// update velocity in mm/sec
			mpmptr->MoveVelocity(timestep,localParticleAlpha);
			
			// update transport values
			nextTransport=transportTasks;
			task=0;
			while(nextTransport!=NULL)
				nextTransport=nextTransport->MoveTransportValue(mpmptr,timestep,rate[task++]);
			
			// thermal ramp
			thermal.UpdateParticleTemperature(&mpmptr->pTemperature,timestep);
			
			// energy coupling here if conduction not doing it
			if(!ConductionTask::active)
			{	if(ConductionTask::adiabatic)
				{	double energy = mpmptr->GetDispEnergy();				// in nJ/g
					double Cv = matRef->GetHeatCapacity(mpmptr);			// in nJ/(g-K)
					mpmptr->pTemperature += energy/Cv;                      // in K
				}
				mpmptr->SetDispEnergy(0.);
			}
		}
		catch(CommonException err)
		{	if(upErr==NULL)
			{
#pragma omp critical
				upErr = new CommonException(err);
			}
		}
    }
	
	// throw any errors
	if(upErr!=NULL) throw *upErr;
    
    // rigid materials move at their current velocity
    for(int p=nmpmsNR;p<nmpms;p++)
    {	mpm[p]->MovePosition(timestep,&mpm[p]->vel,0.,0.);
    }
}