// allocate crack and material velocity fields needed for time step on real nodes
// tried critical sections when nodes changed, but it was slower
// can't use ghost nodes, because need to test all on real nodes
//
// This task only used if have cracks or in multimaterial mode
void InitVelocityFieldsTask::Execute(void)
{
	CommonException *initErr = NULL;
	
	int tp = fmobj->GetTotalNumberOfPatches();
	
#pragma omp parallel
	{
		int nds[maxShapeNodes];
		double fn[maxShapeNodes];
		
		int pn = GetPatchNumber();
		
		// do non-rigid and rigid contact materials in patch pn
		for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_CONTACT;block++)
		{   // get material point (only in this patch)
			MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(block);
			
			while(mpmptr!=NULL)
			{	const MaterialBase *matID = theMaterials[mpmptr->MatID()];		// material object for this particle
				const int matfld = matID->GetField();                           // material velocity field
				
				// get nodes and shape function for material point p
				const ElementBase *elref = theElements[mpmptr->ElemID()];		// element containing this particle
				
				// don't actually need shape functions, but need to screen out zero shape function
				// like done in subsequent tasks, otherwise node numbers will not align correctly
				// only thing used from return are numnds and nds
				int numnds;
				elref->GetShapeFunctions(&numnds,fn,nds,mpmptr);
				
				// Only need to decipher crack velocity field if has cracks (firstCrack!=NULL)
				//      and if this material allows cracks.
#ifdef COMBINE_RIGID_MATERIALS
				bool decipherCVF = firstCrack!=NULL && block!=FIRST_RIGID_CONTACT;
#else
				bool decipherCVF = firstCrack!=NULL;
#endif
				
				// Check each node
				for(int i=1;i<=numnds;i++)
				{	// use real node in this loop
					NodalPoint *ndptr = nd[nds[i]];
					
					// always zero when no cracks (or when ignoring cracks)
					short vfld = 0;
					
					// If need, find vlocity field and for each field set location
					// (above or below crack) and crack number (1 based) or 0 for NO_CRACK
					if(decipherCVF)
					{	// in CRAMP, find crack crossing and appropriate velocity field
						CrackField cfld[2];
						cfld[0].loc = NO_CRACK;			// NO_CRACK=0, ABOVE_CRACK=1, or BELOW_CRACK=2
						cfld[1].loc = NO_CRACK;
						int cfound=0;
						Vector norm;					// track normal vector for crack plane
						
						CrackHeader *nextCrack = firstCrack;
						while(nextCrack!=NULL)
						{	vfld = nextCrack->CrackCross(mpmptr->pos.x,mpmptr->pos.y,ndptr->x,ndptr->y,&norm);
							if(vfld!=NO_CRACK)
							{	cfld[cfound].loc=vfld;
								cfld[cfound].norm=norm;
								
#ifdef IGNORE_CRACK_INTERACTIONS
								// appears to always be same crack, and stop when found one
								cfld[cfound].crackNum=1;
								break;
#endif
								
								// Get crack number (default code does not ignore interactions)
								cfld[cfound].crackNum=nextCrack->GetNumber();
								cfound++;
								
								// stop if found two because code can only handle two interacting cracks
								// It exits loop now to go ahead with the first two found, by physics may be off
								if(cfound>1) break;
							}
							nextCrack=(CrackHeader *)nextCrack->GetNextObject();
						}
						
						
						// find (and allocate if needed) the velocity field
						// Use vfld=0 if no cracks found
						if(cfound>0)
						{   // In parallel, this is critical code
#pragma omp critical
							{   try
								{   vfld = ndptr->AddCrackVelocityField(matfld,cfld);
								}
								catch(CommonException err)
								{   if(initErr==NULL)
									initErr = new CommonException(err);
								}
							}
						}
						
						// set material point velocity field for this node
						mpmptr->vfld[i] = vfld;
					}
					
					// make sure material velocity field is created too
					// (Note: when maxMaterialFields==1 (Singe Mat Mode), mvf[0] is always there
					//        so no need to create it here)
					if(maxMaterialFields>1 && ndptr->NeedsMatVelocityField(vfld,matfld))
					{   // If parallel, this is critical code
#pragma omp critical
						{   try
							{   ndptr->AddMatVelocityField(vfld,matfld);
							}
							catch(CommonException err)
							{   if(initErr==NULL)
								initErr = new CommonException(err);
							}
						}
						
					}
				}
				
				// next material point
				mpmptr = (MPMBase *)mpmptr->GetNextObject();
			}
		}
	}
		
	// was there an error?
	if(initErr!=NULL) throw *initErr;
	
	// copy crack and material fields on real nodes to ghost nodes
	if(tp>1)
	{   for(int pn=0;pn<tp;pn++)
		patches[pn]->InitializationReduction();
	}
}
Ejemplo n.º 2
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.º 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();
}
Ejemplo n.º 4
0
// Get mass matrix, find dimensionless particle locations,
//	and find grid momenta
void InitializationTask::Execute(void)
{
	CommonException *initErr = NULL;
	
	// Zero Mass Matrix and vectors
	warnings.BeginStep();
    
	int tp = fmobj->GetTotalNumberOfPatches();
#pragma omp parallel
	{
        // zero all nodal variables on real nodes
#pragma omp for
		for(int i=1;i<=nnodes;i++)
			nd[i]->InitializeForTimeStep();
		
        // zero ghost nodes in patch for this thread
        int pn = GetPatchNumber();
        patches[pn]->InitializeForTimeStep();

		// particle calculations get xipos for particles and if doing CPDI
        // precalculate CPDI info needed for subsequent shape functions
#pragma omp for nowait
		for(int p=0;p<nmpmsRC;p++)
        {   MPMBase *mpmptr = mpm[p];                                       // pointer
			const ElementBase *elref = theElements[mpmptr->ElemID()];		// element containing this particle
			try
			{	elref->GetShapeFunctionData(mpmptr);
			}
			catch(CommonException err)
			{	if(initErr==NULL)
				{
#pragma omp critical
					initErr = new CommonException(err);
				}
			}
		}
	}
	
	// was there an error?
	if(initErr!=NULL) throw *initErr;
    
	// allocate crack and material velocity fields needed for time step on real nodes
    // tried critical sections when nodes changed, but it was slower
    // can't use ghost nodes, because need to test all on real nodes
	if(firstCrack!=NULL || maxMaterialFields>1)
	{
#pragma omp parallel
        {
            int nds[maxShapeNodes];
            double fn[maxShapeNodes];
            
            //for(int pn=0;pn<tp;pn++) {
            int pn = GetPatchNumber();
		
            // do non-rigid and rigid contact materials in patch pn
            for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_CONTACT;block++)
            {   // get material point (only in this patch)
                MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(block);
                
                while(mpmptr!=NULL)
                {	const MaterialBase *matID = theMaterials[mpmptr->MatID()];		// material object for this particle
                    const int matfld = matID->GetField();                           // material velocity field
                    
                    // get nodes and shape function for material point p
                    const ElementBase *elref = theElements[mpmptr->ElemID()];		// element containing this particle
                    
                    // don't actually need shape functions, but need to screen out zero shape function
                    // like done in subsequent tasks, otherwise node numbers will not align correctly
                    // only think used from return are numnds and nds
                    int numnds;
                    elref->GetShapeFunctions(&numnds,fn,nds,mpmptr);
                    
                    // Add particle property to each node in the element
                    for(int i=1;i<=numnds;i++)
                    {	// use real node in this loop
                        NodalPoint *ndptr = nd[nds[i]];
                        
                        // always zero when no cracks
                        short vfld = 0;
#ifdef COMBINE_RIGID_MATERIALS
                        // when combining rigid particles, extrapolate all to field 0 and later
                        // copy to other active fields
                        if(firstCrack!=NULL && block!=FIRST_RIGID_CONTACT)
#else
                        if(firstCrack!=NULL)
#endif
                        {	// in CRAMP, find crack crossing and appropriate velocity field
                            CrackField cfld[2];
                            cfld[0].loc = NO_CRACK;			// NO_CRACK, ABOVE_CRACK, or BELOW_CRACK
                            cfld[1].loc = NO_CRACK;
                            int cfound=0;
                            Vector norm;
                            
                            CrackHeader *nextCrack = firstCrack;
                            while(nextCrack!=NULL)
                            {	vfld = nextCrack->CrackCross(mpmptr->pos.x,mpmptr->pos.y,ndptr->x,ndptr->y,&norm);
                                if(vfld!=NO_CRACK)
                                {	cfld[cfound].loc=vfld;
                                    cfld[cfound].norm=norm;
#ifdef IGNORE_CRACK_INTERACTIONS
                                    cfld[cfound].crackNum=1;	// appears to always be same crack, and stop when found one
                                    break;
#else
                                    cfld[cfound].crackNum=nextCrack->GetNumber();
                                    cfound++;
                                    if(cfound>1) break;			// stop if found two, if there are more then two, physics will be off
#endif
                                }
                                nextCrack=(CrackHeader *)nextCrack->GetNextObject();
                            }
                                
                            
                            // find (and allocate if needed) the velocity field
                            // Use vfld=0 if no cracks found
                            if(cfound>0)
                            {   // In parallel, this is critical code
#pragma omp critical
                                {   try
                                    {   vfld = ndptr->AddCrackVelocityField(matfld,cfld);
                                    }
                                    catch(CommonException err)
                                    {   if(initErr==NULL)
                                            initErr = new CommonException(err);
                                    }
                                }
                            }
                            
                            // set material point velocity field for this node
                            mpmptr->vfld[i] = vfld;
                        }
                        
                        // make sure material velocity field is created too
                        if(maxMaterialFields>1 && ndptr->NeedsMatVelocityField(vfld,matfld))
                        {   // If parallel, this is critical code
#pragma omp critical
                            {   try
                                {   ndptr->AddMatVelocityField(vfld,matfld);
                                }
                                catch(CommonException err)
                                {   if(initErr==NULL)
                                        initErr = new CommonException(err);
                                }
                            }
                            
                        }
                    }
                    
                    // next material point
                    mpmptr = (MPMBase *)mpmptr->GetNextObject();
                }
            }
            //}           // end for loop when not in parallel
		}
    
        // was there an error?
        if(initErr!=NULL) throw *initErr;

		// copy crack and material fields on real nodes to ghost nodes
		if(tp>1)
        {   for(int pn=0;pn<tp;pn++)
				patches[pn]->InitializationReduction();
		}
	}
    	
    // Update forces applied to particles
	MatPtLoadBC::SetParticleFext(mtime);
	
	// remove contact conditions
	CrackNode::RemoveCrackNodes();
	MaterialInterfaceNode::RemoveInterfaceNodes();
	
    // turn off isothermal ramp when done and ramp step initialization
	thermal.CheckDone(mtime);
	
}	
Ejemplo n.º 5
0
// Calculate J and K at crack tips
CustomTask *CalcJKTask::StepCalculation(void)
{
    // skip if not needed
    if(!getJKThisStep) return nextTask;
    
    int nds[maxShapeNodes];
    double fn[maxShapeNodes];
	//double xDeriv[maxShapeNodes],yDeriv[maxShapeNodes],zDeriv[maxShapeNodes];
    
    // set up strain fields for crack extrapolations
//#pragma omp parallel private(nds,fn,xDeriv,yDeriv,zDeriv)
#pragma omp parallel private(nds,fn)
    {	// in case 2D planar
        //for(int i=0;i<maxShapeNodes;i++) zDeriv[i] = 0.;
        
#pragma omp for
        for(int i=1;i<=nnodes;i++)
            nd[i]->ZeroDisp();
	
        // zero displacement fields on ghost nodes
        int pn = MPMTask::GetPatchNumber();
        patches[pn]->ZeroDisp();
        
        // loop over only non-rigid particles in patch that do not ignore cracks
        MPMBase *mpnt = patches[pn]->GetFirstBlockPointer(FIRST_NONRIGID);
        while(mpnt!=NULL)
        {   // material reference
            const MaterialBase *matref = theMaterials[mpnt->MatID()];
		
            // find shape functions and derviatives
            int numnds;
            const ElementBase *elref = theElements[mpnt->ElemID()];
            //elref->GetShapeGradients(&numnds,fn,nds,xDeriv,yDeriv,zDeriv,mpnt);
			elref->GetShapeFunctions(&numnds,fn,nds,mpnt);
		
            // Add particle property to each node in the element
            NodalPoint *ndmi;
            short vfld;
            double fnmp;
            for(int i=1;i<=numnds;i++)
            {   // global mass matrix
                vfld=(short)mpnt->vfld[i];				// velocity field to use
                fnmp=fn[i]*mpnt->mp;
                
                // get node pointer
                ndmi = MPMTask::GetNodePointer(pn,nds[i]);
			
                // get 2D gradient terms (dimensionless) and track material (if needed)
                int activeMatField = matref->GetActiveField();
				Matrix3 gradU = mpnt->GetDisplacementGradientMatrix();
                ndmi->AddUGradient(vfld,fnmp,gradU(0,0),gradU(0,1),gradU(1,0),gradU(1,1),activeMatField,mpnt->mp);

				// GRID_JTERMS
				double rho = matref->GetRho(NULL);
				if(JGridEnergy)
				{	// Add velocity (scaled by sqrt(rho) such that v^2 is 2 X grid kinetic energy in nJ/mm^3)
					// In axisymmetric, kinetic energy density is 2 pi (0.5 m v^2)/(2 pi rp Ap), but since m = rho rp Ap
					//		kinetic energy density is still 0.5 rho v^2
					ndmi->AddGridVelocity(vfld,fnmp*sqrt(rho),mpnt->vel.x,mpnt->vel.y);
					
					// scale by rho to get actual stress
					fnmp *= rho;
				}
				else
				{	// scale by rho to get specific energy and actual stress
					fnmp *= rho;
					
					// get energy and rho*energy has units nJ/mm^3
					// In axisymmetric, energy density is 2 pi m U/(2 pi rp Ap), but since m = rho rp Ap
					//		energy density is still rho*energy
					ndmi->AddEnergy(vfld,fnmp,mpnt->vel.x,mpnt->vel.y,mpnt->GetWorkEnergy());
				}
			
                // get a nodal stress (rho*stress has units N/m^2 = uN/mm^2)
                Tensor sp = mpnt->ReadStressTensor();
                ndmi->AddStress(vfld,fnmp,&sp);
            }
            
            // next non-rigid material point
            mpnt = (MPMBase *)mpnt->GetNextObject();
        }
    }
        
    // copy ghost to real nodes
    int totalPatches = fmobj->GetTotalNumberOfPatches();
    if(totalPatches>1)
    {	for(int j=0;j<totalPatches;j++)
            patches[j]->JKTaskReduction();
    }
 	
    // finish strain fields
#pragma omp parallel for
    for(int i=1;i<=nnodes;i++)
        nd[i]->CalcStrainField();
    
    // No Do the J Integral calculations
    
	int inMat;
    Vector d,C;
    CrackSegment *crkTip;

    CrackHeader *nextCrack=firstCrack;
    while(nextCrack!=NULL)
    {   nextCrack->JIntegral();         // crack-axis components of J-integral
        
        // if material known, find KI and KII for crack tips
        if(getJKThisStep & NEED_K)
        {   for(int i=START_OF_CRACK;i<=END_OF_CRACK;i++)
            {   crkTip=nextCrack->GetCrackTip(i);
                inMat=crkTip->tipMatnum;
                if(inMat>0)
                {   //C=crkTip->C;		// will be crack segment property
                    C.x=0.0; C.y=0.0; ; C.z=0.;
                    
                    // find normal and shear COD
					nextCrack->GetCOD(crkTip,d,true);
					d.z=0.;

					// convert to K
                    crkTip->sif=theMaterials[inMat-1]->ConvertJToK(d,C,crkTip->Jint,fmobj->np);
                }
                else
                {   crkTip->sif.x=0;
                    crkTip->sif.y=0;
                }
            }
        }

        // next crack
        nextCrack=(CrackHeader *)nextCrack->GetNextObject();
    }
    
    return nextTask;
}
// Get mass matrix, find dimensionless particle locations,
//	and find grid momenta
void ExtrapolateRigidBCsTask::Execute(void)
{
	double fn[maxShapeNodes];
	
	// undo dynamic velocity, temp, and conc BCs from rigid materials
	// and get pointer to first empty one in reuseRigid...BC
	ProjectRigidBCsTask::UnsetRigidBCs((BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,
				  (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC);
	ProjectRigidBCsTask::UnsetRigidBCs((BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC,
				  (BoundaryCondition **)&firstRigidTempBC,(BoundaryCondition **)&reuseRigidTempBC);
	ProjectRigidBCsTask::UnsetRigidBCs((BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC,
				  (BoundaryCondition **)&firstRigidConcBC,(BoundaryCondition **)&reuseRigidConcBC);
	
	int i,numnds,setFlags;
	Vector rvel;
	bool hasDir[3];
	double tempValue,concValue;
	
	// this loop not parallel because of possible function in getting rigid settings
	// also will usually be small loop
	for(int p=nmpmsRC;p<nmpms;p++)
	{	// bet material point and the rigid material
		MPMBase *mpmptr = mpm[p];
		const RigidMaterial *rigid = (RigidMaterial *)theMaterials[mpmptr->MatID()];				// material object for this particle
		
		// get rigid particle velocity
		// Get directions set, others will be zero
		setFlags = rigid->SetDirection();
		ZeroVector(&rvel);
		if(rigid->GetVectorSetting(&rvel,hasDir,mtime,&mpmptr->pos))
		{	if(hasDir[0]) mpmptr->vel.x = rvel.x;
			if(hasDir[1]) mpmptr->vel.y = rvel.y;
			if(hasDir[2]) mpmptr->vel.z = rvel.z;
		}
		else
		{	if(setFlags&CONTROL_X_DIRECTION) rvel.x = mpmptr->vel.x;
			if(setFlags&CONTROL_Y_DIRECTION) rvel.y = mpmptr->vel.y;
			if(setFlags&CONTROL_Z_DIRECTION) rvel.z = mpmptr->vel.z;
		}
		
		// get rigid particle temperature
		if(rigid->RigidTemperature())
		{	setFlags += CONTROL_TEMPERATURE;
			if(rigid->GetValueSetting(&tempValue,mtime,&mpmptr->pos)) mpmptr->pTemperature = tempValue;
		}
		
		// concentration
		if(rigid->RigidConcentration())
		{	setFlags += CONTROL_CONCENTRATION;
			if(rigid->GetValueSetting(&concValue,mtime,&mpmptr->pos)) mpmptr->pConcentration = concValue;
		}
		
		// get nodes and shape function for material point p
		const ElementBase *elref = theElements[mpmptr->ElemID()];		// element containing this particle
		elref->ShapeFunction(mpmptr->GetNcpos(),FALSE,&fn[1],NULL,NULL,NULL);
		numnds=elref->NumberNodes();
		
		// Add particle property to each node in the element
		for(i=1;i<=numnds;i++)
		{   // get node pointer and set values
			int mi=elref->nodes[i-1];		// 1 based node
			
			// it might possible need a velocity field (does nothing in single material mode or if already there)
			nd[mi]->AddMatVelocityField(0,0);
			
			// add BC info
			nd[mi]->AddRigidBCInfo(mpmptr,fn[i],setFlags,&rvel);
		}
	}
	
	// read nodal settings, rezero their used values, and set boundary conditions
	for(int i=1;i<=nnodes;i++)
	{	NodalPoint *ndptr = nd[i];
		setFlags = ndptr->ReadAndZeroRigidBCInfo(&rvel,&tempValue,&concValue);
		
		if(setFlags&CONTROL_X_DIRECTION)
		{	ProjectRigidBCsTask::SetRigidBCs(i,-40,X_DIRECTION,rvel.x,0.,0,
						(BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,
						(BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC);
		}
		if(setFlags&CONTROL_X_DIRECTION)
		{	ProjectRigidBCsTask::SetRigidBCs(i,-40,Y_DIRECTION,rvel.y,0.,0,
						(BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,
						(BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC);
		}
		if(setFlags&CONTROL_X_DIRECTION)
		{	ProjectRigidBCsTask::SetRigidBCs(i,-40,Z_DIRECTION,rvel.z,0.,0,
						(BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,
						(BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC);
		}
		if(setFlags&CONTROL_TEMPERATURE)
		{	ProjectRigidBCsTask::SetRigidBCs(i,0,TEMP_DIRECTION,tempValue,0.,0,
						(BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC,
						(BoundaryCondition **)&firstRigidTempBC,(BoundaryCondition **)&reuseRigidTempBC);
		}
		if(setFlags&CONTROL_CONCENTRATION)
		{	ProjectRigidBCsTask::SetRigidBCs(i,0,CONC_DIRECTION,concValue,0.,0,
						(BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC,
						(BoundaryCondition **)&firstRigidConcBC,(BoundaryCondition **)&reuseRigidConcBC);
		}
	}
	
	// if any left over rigid BCs, delete them now
	ProjectRigidBCsTask::RemoveRigidBCs((BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,(BoundaryCondition **)&firstRigidVelocityBC);
	ProjectRigidBCsTask::RemoveRigidBCs((BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC,(BoundaryCondition **)&firstRigidTempBC);
	ProjectRigidBCsTask::RemoveRigidBCs((BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC,(BoundaryCondition **)&firstRigidConcBC);
}
Ejemplo n.º 7
0
// Get mass matrix, find dimensionless particle locations,
//	and find grid momenta
void MassAndMomentumTask::Execute(void)
{   
	CommonException *massErr = NULL;
    double fn[maxShapeNodes],xDeriv[maxShapeNodes],yDeriv[maxShapeNodes],zDeriv[maxShapeNodes];
    int nds[maxShapeNodes];

#pragma mark ... UPDATE RIGID CONTACT PARTICLES
    // Set rigid BC contact material velocities first (so loop can be parallel)
	// GetVectorSetting() uses globals and therefore can't be parallel
    if(nmpmsRC>nmpmsNR)
    {   Vector newvel;
        bool hasDir[3];
        for(int p=nmpmsNR;p<nmpmsRC;p++)
        {   MPMBase *mpmptr = mpm[p];
            const RigidMaterial *matID = (RigidMaterial *)theMaterials[mpm[p]->MatID()];
            if(matID->GetVectorSetting(&newvel,hasDir,mtime,&mpmptr->pos))
            {   // change velocity if functions being used, otherwise keep velocity constant
                if(hasDir[0]) mpmptr->vel.x = newvel.x;
                if(hasDir[1]) mpmptr->vel.y = newvel.y;
                if(hasDir[2]) mpmptr->vel.z = newvel.z;
            }
        }
    }
	
	// loop over non-rigid and rigid contact particles - this parallel part changes only particle p
	// mass, momenta, etc are stored on ghost nodes, which are sent to real nodes in next non-parallel loop
    //for(int pn=0;pn<4;pn++)
#pragma omp parallel private(fn,xDeriv,yDeriv,zDeriv,nds)
	{
        // thread for patch pn
		int pn = GetPatchNumber();
        
		// in case 2D planar
        for(int i=0;i<maxShapeNodes;i++) zDeriv[i] = 0.;
        
#pragma mark ... EXTRAPOLATE NONRIGID PARTICLES
		try
		{	for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_CONTACT;block++)
			{	MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(block);
				while(mpmptr!=NULL)
                {   const MaterialBase *matID = theMaterials[mpmptr->MatID()];		// material object for this particle
					int matfld = matID->GetField();									// material velocity field
					
					// get nodes and shape function for material point p
					int i,numnds;
					const ElementBase *elref = theElements[mpmptr->ElemID()];		// element containing this particle
					if(fmobj->multiMaterialMode)
						elref->GetShapeGradients(&numnds,fn,nds,xDeriv,yDeriv,zDeriv,mpmptr);
					else
						elref->GetShapeFunctions(&numnds,fn,nds,mpmptr);
					
					// Add particle property to each node in the element
					short vfld;
					NodalPoint *ndptr;
					for(i=1;i<=numnds;i++)
					{   // get node pointer
                        ndptr = GetNodePointer(pn,nds[i]);
						
						// momentum vector (and allocate velocity field if needed)
						vfld = mpmptr->vfld[i];
						ndptr->AddMassMomentum(mpmptr,vfld,matfld,fn[i],xDeriv[i],yDeriv[i],zDeriv[i],
											   1,block==FIRST_NONRIGID);
					}
					
					// next material point
					mpmptr = (MPMBase *)mpmptr->GetNextObject();
				}
			}
		}
		catch(CommonException err)
        {   if(massErr==NULL)
			{
#pragma omp critical
				massErr = new CommonException(err);
			}
		}
        catch(...)
        {   cout << "Unknown exception in MassAndMomentumTask()" << endl;
        }
	}
	
	// throw now - only possible error if too many CPDI nodes in 3D
	if(massErr!=NULL) throw *massErr;
    
	// reduction of ghost node forces to real nodes
	int totalPatches = fmobj->GetTotalNumberOfPatches();
	if(totalPatches>1)
	{	for(int pn=0;pn<totalPatches;pn++)
			patches[pn]->MassAndMomentumReduction();
	}
    
#pragma mark ... RIGID BOUNDARY CONDITIONS
	// undo dynamic velocity, temp, and conc BCs from rigid materials
    // and get pointer to first empty one in reuseRigid...BC
	UnsetRigidBCs((BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,
				  (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC);
	UnsetRigidBCs((BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC,
				  (BoundaryCondition **)&firstRigidTempBC,(BoundaryCondition **)&reuseRigidTempBC);
	UnsetRigidBCs((BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC,
				  (BoundaryCondition **)&firstRigidConcBC,(BoundaryCondition **)&reuseRigidConcBC);
	
	// For Rigid BC materials create velocity BC on each node in the element
	for(int p=nmpmsRC;p<nmpms;p++)
	{	MPMBase *mpmptr = mpm[p];										// pointer
		
		int matid0 = mpmptr->MatID();
		const MaterialBase *matID = theMaterials[matid0];				// material object for this particle
		RigidMaterial *rigid=(RigidMaterial *)matID;

		const ElementBase *elref = theElements[mpmptr->ElemID()];		// element containing this particle
		int numnds=elref->NumberNodes();
		
		double rvalue;
		for(int i=1;i<=numnds;i++)
		{   int mi=elref->nodes[i-1];		// 1 based node
			
			// look for setting function in one to three directions
			// GetVectorSetting() returns true if function has set the velocity, otherwise it return FALSE
			bool hasDir[3];
			Vector rvel;
			if(rigid->GetVectorSetting(&rvel,hasDir,mtime,&mpmptr->pos))
			{   // velocity set by 1 to 3 functions as determined by hasDir[i]
				if(hasDir[0])
				{	mpmptr->vel.x = rvel.x;
					SetRigidBCs(mi,matid0,X_DIRECTION,rvel.x,0.,rigid->mirrored,
							(BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,
							(BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC);
				}
				if(hasDir[1])
				{	mpmptr->vel.y = rvel.y;
					SetRigidBCs(mi,matid0,Y_DIRECTION,rvel.y,0.,rigid->mirrored,
								(BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,
								(BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC);
				}
				if(hasDir[2])
				{	mpmptr->vel.z = rvel.z;
					SetRigidBCs(mi,matid0,Z_DIRECTION,rvel.z,0.,rigid->mirrored,
								(BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,
								(BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC);
				}
			}
			else
			{   // velocity set by particle velocity in selected directions
				if(rigid->RigidDirection(X_DIRECTION))
				{	SetRigidBCs(mi,matid0,X_DIRECTION,mpmptr->vel.x,0.,rigid->mirrored,
									(BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,
									(BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC);
				}
				if(rigid->RigidDirection(Y_DIRECTION))
				{	SetRigidBCs(mi,matid0,Y_DIRECTION,mpmptr->vel.y,0.,rigid->mirrored,
								(BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,
								(BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC);
				}
				if(rigid->RigidDirection(Z_DIRECTION))
				{	SetRigidBCs(mi,matid0,Z_DIRECTION,mpmptr->vel.z,0.,rigid->mirrored,
								(BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,
								(BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC);
				}
			}
			
			// temperature
			if(rigid->RigidTemperature())
			{	if(rigid->GetValueSetting(&rvalue,mtime,&mpmptr->pos)) mpmptr->pTemperature=rvalue;
				SetRigidBCs(mi,matid0,TEMP_DIRECTION,mpmptr->pTemperature,0.,0,
							(BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC,
							(BoundaryCondition **)&firstRigidTempBC,(BoundaryCondition **)&reuseRigidTempBC);
			}
			
			// concentration
			if(rigid->RigidConcentration())
			{	if(rigid->GetValueSetting(&rvalue,mtime,&mpmptr->pos)) mpmptr->pConcentration=rvalue;
				SetRigidBCs(mi,matid0,CONC_DIRECTION,mpmptr->pConcentration,0.,0,
							(BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC,
							(BoundaryCondition **)&firstRigidConcBC,(BoundaryCondition **)&reuseRigidConcBC);
			}
		}
	}
	
	// if any left over rigid BCs, delete them now
	RemoveRigidBCs((BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,(BoundaryCondition **)&firstRigidVelocityBC);
	RemoveRigidBCs((BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC,(BoundaryCondition **)&firstRigidTempBC);
	RemoveRigidBCs((BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC,(BoundaryCondition **)&firstRigidConcBC);
	
#ifdef COMBINE_RIGID_MATERIALS
	bool combineRigid = firstCrack!=NULL && fmobj->multiMaterialMode && fmobj->hasRigidContactParticles;
#endif
	
#pragma mark ... POST EXTRAPOLATION TASKS
	// Post mass and momentum extrapolation calculations on nodes
#pragma omp parallel
	{
		// variables for each thread
		CrackNode *firstCrackNode=NULL,*lastCrackNode=NULL;
		MaterialInterfaceNode *firstInterfaceNode=NULL,*lastInterfaceNode=NULL;
		
		// Each pass in this loop should be independent
#pragma omp for nowait
		for(int i=1;i<=nnodes;i++)
		{	// node reference
			NodalPoint *ndptr = nd[i];
			
			try
            {
#ifdef COMBINE_RIGID_MATERIALS
                // combine rigid fields if necessary
                if(combineRigid)
                    ndptr->CopyRigidParticleField();
#endif
				// Get total nodal masses and count materials if multimaterial mode
				ndptr->CalcTotalMassAndCount();

				// multimaterial contact
				if(fmobj->multiMaterialMode)
					ndptr->MaterialContactOnNode(timestep,MASS_MOMENTUM_CALL,&firstInterfaceNode,&lastInterfaceNode);
				
				// crack contact
				if(firstCrack!=NULL)
					ndptr->CrackContact(FALSE,0.,&firstCrackNode,&lastCrackNode);
				
				// get transport values on nodes
				TransportTask *nextTransport=transportTasks;
				while(nextTransport!=NULL)
					nextTransport = nextTransport->GetNodalValue(ndptr);
			}
			catch(CommonException err)
			{	if(massErr==NULL)
				{
#pragma omp critical
					massErr = new CommonException(err);
				}
			}
		}

#pragma omp critical
		{
			// link up crack nodes
			if(lastCrackNode != NULL)
			{	if(CrackNode::currentCNode != NULL)
					firstCrackNode->SetPrevBC(CrackNode::currentCNode);
				CrackNode::currentCNode = lastCrackNode;
			}
			
			// link up interface nodes
			if(lastInterfaceNode != NULL)
			{	if(MaterialInterfaceNode::currentIntNode != NULL)
					firstInterfaceNode->SetPrevBC(MaterialInterfaceNode::currentIntNode);
				MaterialInterfaceNode::currentIntNode = lastInterfaceNode;
			}
		}
	}
	
	// throw any errors
	if(massErr!=NULL) throw *massErr;
    
#pragma mark ... IMPOSE BOUNDARY CONDITIONS
    
	// Impose transport BCs and extrapolate gradients to the particles
	TransportTask *nextTransport=transportTasks;
	while(nextTransport!=NULL)
    {   nextTransport->ImposeValueBCs(mtime);
		nextTransport = nextTransport->GetGradients(mtime);
	}
	
	// locate BCs with reflected nodes
    if(firstRigidVelocityBC!=NULL)
    {   NodalVelBC *nextBC=firstRigidVelocityBC;
        double mstime=1000.*mtime;
        //cout << "# Find Reflected Nodes" << endl;
        while(nextBC!=NULL)
            nextBC = nextBC->SetMirroredVelBC(mstime);
    }
	
	// used to call class methods for material contact and crack contact here
	// Impose velocity BCs
	NodalVelBC::GridMomentumConditions(TRUE);

}
Ejemplo n.º 8
0
// Get total grid point forces (except external forces)
// throws CommonException()
void GridForcesTask::Execute(void)
{
	CommonException *forceErr = NULL;
	
	// need to be private in threads
#ifdef CONST_ARRAYS
	double fn[MAX_SHAPE_NODES],xDeriv[MAX_SHAPE_NODES],yDeriv[MAX_SHAPE_NODES],zDeriv[MAX_SHAPE_NODES];
	int ndsArray[MAX_SHAPE_NODES];
#else
	double fn[maxShapeNodes],xDeriv[maxShapeNodes],yDeriv[maxShapeNodes],zDeriv[maxShapeNodes];
	int ndsArray[maxShapeNodes];
#endif

	// loop over non-rigid particles - this parallel part changes only particle p
	// forces are stored on ghost nodes, which are sent to real nodes in next non-parallel loop
#pragma omp parallel private(ndsArray,fn,xDeriv,yDeriv,zDeriv)
	{	// in case 2D planar
        for(int i=0;i<maxShapeNodes;i++) zDeriv[i] = 0.;
        
        // patch for this thread
        int pn = GetPatchNumber();
        
		try
		{	MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(FIRST_NONRIGID);
			while(mpmptr!=NULL)
			{	const MaterialBase *matref = theMaterials[mpmptr->MatID()];		// material class (read only)
				int matfld = matref->GetField(); 
				
				// get transport tensors (if needed)
				TransportProperties t;
				if(transportTasks!=NULL)
					matref->GetTransportProps(mpmptr,fmobj->np,&t);
				
				// find shape functions and derviatives
				const ElementBase *elemref = theElements[mpmptr->ElemID()];
				int *nds = ndsArray;
				elemref->GetShapeGradients(fn,&nds,xDeriv,yDeriv,zDeriv,mpmptr);
				int numnds = nds[0];
				
				// Add particle property to buffer on the material point (needed to allow parallel code)
				short vfld;
				NodalPoint *ndptr;
				for(int i=1;i<=numnds;i++)
				{	vfld = (short)mpmptr->vfld[i];					// crack velocity field to use
					
					// total force vector = internal + external forces
					//	(in g mm/sec^2 or micro N)
					Vector theFrc;
					mpmptr->GetFintPlusFext(&theFrc,fn[i],xDeriv[i],yDeriv[i],zDeriv[i]);
					
					// add body forces (do in outside loop now)
					
					// add the total force to nodal point
                    ndptr = GetNodePointer(pn,nds[i]);
					ndptr->AddFtotTask3(vfld,matfld,&theFrc);
					
#ifdef CHECK_NAN
                    if(theFrc.x!=theFrc.x || theFrc.y!=theFrc.y || theFrc.z!=theFrc.z)
                    {
#pragma omp critical (output)
						{	cout << "\n# GridForcesTask::Execute: bad nodal force vfld = " << vfld << ", matfld = " << matfld;
							PrintVector(" theFrc = ",&theFrc);
							cout << endl;
							ndptr->Describe();
						}
                    }
#endif
					// transport forces
					TransportTask *nextTransport=transportTasks;
					while(nextTransport!=NULL)
						nextTransport=nextTransport->AddForces(ndptr,mpmptr,fn[i],xDeriv[i],yDeriv[i],zDeriv[i],&t);
				}

				// next material point
				mpmptr = (MPMBase *)mpmptr->GetNextObject();
			}
		}
		catch(CommonException& err)
		{	if(forceErr==NULL)
			{
#pragma omp critical (error)
				forceErr = new CommonException(err);
			}
		}
		catch(std::bad_alloc&)
		{	if(forceErr==NULL)
			{
#pragma omp critical (error)
				forceErr = new CommonException("Memory error","GridForcesTask::Execute");
			}
		}
		catch(...)
		{	if(forceErr==NULL)
			{
#pragma omp critical (error)
				forceErr = new CommonException("Unexpected error","GridForcesTask::Execute");
			}
		}
	}
	
	// throw errors now
	if(forceErr!=NULL) throw *forceErr;
	
	// reduction of ghost node forces to real nodes
	int totalPatches = fmobj->GetTotalNumberOfPatches();
	if(totalPatches>1)
	{	for(int pn=0;pn<totalPatches;pn++)
			patches[pn]->GridForcesReduction();
	}
	
}
// Get total grid point forces (except external forces)
void UpdateStrainsLastContactTask::Execute(void)
{
	CommonException *uslErr = NULL;
	
	int nds[maxShapeNodes];
	double fn[maxShapeNodes],xDeriv[maxShapeNodes],yDeriv[maxShapeNodes],zDeriv[maxShapeNodes];
	
#pragma omp parallel private(nds,fn,xDeriv,yDeriv,zDeriv)
	{
		// in case 2D planar
		for(int i=0;i<maxShapeNodes;i++) zDeriv[i] = 0.;
		
		try
		{
#pragma omp for
			// zero again (which finds new positions for contact rigid particle data on the nodes)
			for(int i=1;i<=nnodes;i++)
				nd[i]->RezeroNodeTask6(timestep);
			
			// zero ghost nodes on this patch
			int pn = GetPatchNumber();
			patches[pn]->RezeroNodeTask6(timestep);
			
			// loop over non-rigid particles only - this parallel part changes only particle p
			// mass, momenta, etc are stored on ghost nodes, which are sent to real nodes in next non-parallel loop
			MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(FIRST_NONRIGID);
			while(mpmptr!=NULL)
			{   const MaterialBase *matref = theMaterials[mpmptr->MatID()];
				int matfld = matref->GetField();
				
				// find shape functions (why ever need gradients?)
				const ElementBase *elref = theElements[mpmptr->ElemID()];
				int numnds;
				if(fmobj->multiMaterialMode)
				{   // Need gradients for volume gradient
					elref->GetShapeGradients(&numnds,fn,nds,xDeriv,yDeriv,zDeriv,mpmptr);
				}
				else
					elref->GetShapeFunctions(&numnds,fn,nds,mpmptr);
				
				short vfld;
				NodalPoint *ndptr;
				for(int i=1;i<=numnds;i++)
				{   // get node pointer
					ndptr = GetNodePointer(pn,nds[i]);
					
					// add mass and momentum this task
					vfld = (short)mpmptr->vfld[i];
					ndptr->AddMassMomentumLast(mpmptr,vfld,matfld,fn[i],xDeriv[i],yDeriv[i],zDeriv[i]);
				}
				
				// next non-rigid material point
				mpmptr = (MPMBase *)mpmptr->GetNextObject();
			}
		}
		catch(CommonException err)
		{	if(uslErr==NULL)
			{
#pragma omp critical
				uslErr = new CommonException(err);
			}
		}
	}
	
	// throw errors now
	if(uslErr!=NULL) throw *uslErr;
	
	// reduction of ghost node forces to real nodes
	int totalPatches = fmobj->GetTotalNumberOfPatches();
	if(totalPatches>1)
	{	for(int pn=0;pn<totalPatches;pn++)
			patches[pn]->MassAndMomentumReductionLast();
	}
	
	// grid temperature is never updated unless needed here
	// update nodal values for transport properties (when coupled to strain)
	TransportTask *nextTransport=transportTasks;
	while(nextTransport!=NULL)
		nextTransport=nextTransport->UpdateNodalValues(timestep);
	
	// adjust momenta for multimaterial contact
	if(fmobj->multiMaterialMode)
	{	for(int i=1;i<=nnodes;i++)
			nd[i]->MaterialContactOnNode(timestep,UPDATE_STRAINS_LAST_CALL,NULL,NULL);
	}
	
	// adjust momenta for crack contact
	if(firstCrack!=NULL) CrackNode::ContactOnKnownNodes();
	
	// impose grid boundary conditions
	NodalVelBC::GridMomentumConditions(FALSE);
	
	// update strains based on current velocities
	UpdateStrainsFirstTask::FullStrainUpdate(strainTimestep,(fmobj->mpmApproach==USAVG_METHOD),fmobj->np);
}
Ejemplo n.º 10
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.);
    }
}
Ejemplo n.º 11
0
// Get mass matrix, find dimensionless particle locations,
//	and find grid momenta
void MassAndMomentumTask::Execute(void)
{   
	CommonException *massErr = NULL;
    double fn[maxShapeNodes],xDeriv[maxShapeNodes],yDeriv[maxShapeNodes],zDeriv[maxShapeNodes];
    int nds[maxShapeNodes];

#pragma mark ... UPDATE RIGID CONTACT PARTICLES
    // Set rigid BC contact material velocities first (so loop can be parallel)
	// GetVectorSetting() uses globals and therefore can't be parallel
    if(nmpmsRC>nmpmsNR)
    {   Vector newvel;
        bool hasDir[3];
        for(int p=nmpmsNR;p<nmpmsRC;p++)
        {   MPMBase *mpmptr = mpm[p];
            const RigidMaterial *matID = (RigidMaterial *)theMaterials[mpm[p]->MatID()];
            if(matID->GetVectorSetting(&newvel,hasDir,mtime,&mpmptr->pos))
            {   // change velocity if functions being used, otherwise keep velocity constant
                if(hasDir[0]) mpmptr->vel.x = newvel.x;
                if(hasDir[1]) mpmptr->vel.y = newvel.y;
                if(hasDir[2]) mpmptr->vel.z = newvel.z;
            }
        }
    }
	
	// loop over non-rigid and rigid contact particles - this parallel part changes only particle p
	// mass, momenta, etc are stored on ghost nodes, which are sent to real nodes in next non-parallel loop
    //for(int pn=0;pn<4;pn++)
#pragma omp parallel private(fn,xDeriv,yDeriv,zDeriv,nds)
	{
        // thread for patch pn
		int pn = GetPatchNumber();
        
		// in case 2D planar
        for(int i=0;i<maxShapeNodes;i++) zDeriv[i] = 0.;
        
#pragma mark ... EXTRAPOLATE NONRIGID AND RIGID CONTACT PARTICLES
		try
		{	for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_CONTACT;block++)
			{	MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(block);
				while(mpmptr!=NULL)
                {   const MaterialBase *matID = theMaterials[mpmptr->MatID()];		// material object for this particle
					int matfld = matID->GetField();									// material velocity field
					
					// get nodes and shape function for material point p
					int i,numnds;
					const ElementBase *elref = theElements[mpmptr->ElemID()];		// element containing this particle
					if(fmobj->multiMaterialMode)
						elref->GetShapeGradients(&numnds,fn,nds,xDeriv,yDeriv,zDeriv,mpmptr);
					else
						elref->GetShapeFunctions(&numnds,fn,nds,mpmptr);
					
					// Add particle property to each node in the element
					short vfld;
					NodalPoint *ndptr;
					for(i=1;i<=numnds;i++)
					{   // get node pointer
                        ndptr = GetNodePointer(pn,nds[i]);
						
						// add mass and momentum (and maybe contact stuff) to this node
						vfld = mpmptr->vfld[i];
						ndptr->AddMassMomentum(mpmptr,vfld,matfld,fn[i],xDeriv[i],yDeriv[i],zDeriv[i],
											   1,block==FIRST_NONRIGID);
					}
					
					// next material point
					mpmptr = (MPMBase *)mpmptr->GetNextObject();
				}
			}
		}
		catch(CommonException err)
        {   if(massErr==NULL)
			{
#pragma omp critical
				massErr = new CommonException(err);
			}
		}
        catch(...)
        {   cout << "Unknown exception in MassAndMomentumTask()" << endl;
        }
	}
	
	// throw now - only possible error if too many CPDI nodes in 3D
	if(massErr!=NULL) throw *massErr;
    
	// reduction of ghost node forces to real nodes
	int totalPatches = fmobj->GetTotalNumberOfPatches();
	if(totalPatches>1)
	{	for(int pn=0;pn<totalPatches;pn++)
			patches[pn]->MassAndMomentumReduction();
	}
    
}