/* This is called after PreliminaryCalcs() and just before first MPM time step and it
		is only called if the material is actually in use by one or more particles
	If material cannot be used in current analysis type throw an exception
	Subclass that overrides must pass on to super class
 */
void MaterialBase::ValidateForUse(int np) const
{	int i;
	
	for(i=0;i<=1;i++)
	{	if(i==1 && criterion[i]==NO_PROPAGATION) break;		// skip if no alternate criterion
		if(tractionMat[i]>0)
		{	if(tractionMat[i]>nmat)
			{	throw CommonException("Material with undefined traction law material for propagation",
									  "MaterialBase::ValidateForUse");
			}
			if(!theMaterials[tractionMat[i]-1]->isTractionLaw())
			{	throw CommonException("Material with propagation material that is not a traction law",
									  "MaterialBase::ValidateForUse");
			}
		}
	}
	
	// check for unsupported alternate propagation criterion
	if(criterion[1]==STEADYSTATEGROWTH)
	{	throw CommonException("The alternate propagation criterion cannot be steady state crack growth.",
							  "MaterialBase::ValidateForUse");
	}
	
	if(ConductionTask::active || ConductionTask::adiabatic)
	{	if(heatCapacity<=0. && !Rigid())
		{	throw CommonException("Thermal conduction and/or mechanical energy cannot be done using materials that have zero heat capacity.",
								  "MaterialBase::ValidateForUse");
		}
	}
}
Example #2
0
// called once at start of MPM analysis - initialize and print info
CustomTask *CarnotCycle::Initialize(void)
{
    cout << "Carnot Cyle Simulation." << endl;
	
	// time interval
	cout << "   Step 1: Isothermal expansion to " << V1rel << "*V0" << endl;
	cout << "   Step 2: Adibatic expansion to temperature " << T2 << endl;
	if(V3rel>0.)
		cout << "   Step 3: Isothermal compression to " << V3rel << "*V0" << endl;
	else
		cout << "   Step 3: Isothermal compression to V3/V0 = V2/V1" << endl;
	cout << "   Step 2: Adibatic compression to temperature " << thermal.reference << endl;
	
	if(V1rel<1.)
		throw CommonException("The first expansion volume (V1rel) must be greater than 1","CarnotCycle::Initialize()");
	if(T2>thermal.reference || T2<0)
		throw CommonException("The second temperature, T2, must be less than the reference temperature.","CarnotCycle::Initialize()");
	if(V3rel>0. and V3rel<1.)
		throw CommonException("The thirds expansion volume (V3rel) must be greater than 1","CarnotCycle::Initialize()");
	
	// initial settings
	carnotStep = 0;
	ConductionTask::adiabatic = FALSE;
	MaterialBase::isolatedSystemAndParticles = FALSE;
	
    return nextTask;
}
Example #3
0
// called once at start of MPM analysis - initialize and print info
CustomTask *VTKArchive::Initialize(void)
{
    cout << "Archive grid results to VTK files." << endl;
	
	if(!mpmgrid.IsStructuredGrid())
		throw CommonException("VTKArchive task requires use of a generated grid","VTKArchive::Initialize");
	
	// time interval
	cout << "   Archive time: ";
	if(customArchiveTime>0)
	{	cout << customArchiveTime << " ms";
		customArchiveTime/=1000.;				// convert to sec
		if(nextCustomArchiveTime<0.)
		{	nextCustomArchiveTime=0.0;
			cout << endl;
		}
		else
		{	cout << ", starting at " << nextCustomArchiveTime << " ms" << endl;
			nextCustomArchiveTime/=1000.;				// convert to sec
		}
	}
	else
		cout << "same as particle archives" << endl;
	
	// quantities
	unsigned int q;
	cout << "   Archiving: " ;
	int len=14;
	for(q=0;q<quantity.size();q++)
	{	char *name=quantityName[q];
		if(len+strlen(name)>70)
		{	cout << "\n      ";
			len=3;
		}
		cout << name;
        if(quantity[q]==VTK_VOLUMEGRADIENT)
        {   if(qparam[q]<0)
			{   cout << endl;
				throw CommonException("VTKArchive volumegradient must be set to an available material","VTKArchive::Initialize");
			}
            int matnum = intArgs[qparam[q]];
            cout << " (material #" << matnum << ")";
            len+=14;		// this is for matnum<10, but exact length does not matter
			if(matnum<1 || matnum>nmat)
            {   cout << endl;
                throw CommonException("VTKArchive volumegradient must be for an available material","VTKArchive::Initialize");
            }
            qparam[q] = matnum;
        }
		if(q<quantity.size()-1) cout << ", ";
		len+=strlen(name)+2;
	}
	cout << endl;
	
    return nextTask;
}
Example #4
0
// if analysis not allowed, throw an exception
void HEMGEOSMaterial::ValidateForUse(int np) const
{
	if(thermal.reference<=0)
	{	throw CommonException("MGEOSMaterial material requires the simulation to set the stress free temperature in degrees K",
							  "MGSCGLMaterial::ValidateForUse");
	}
    
    if(np==PLANE_STRESS_MPM)
    {	throw CommonException("MGEOSMaterial material has not yet been updated to do plane stress calculations",
                              "MGSCGLMaterial::ValidateForUse");
    }
	
	// call super class
	HEIsotropic::ValidateForUse(np);
}
// Print contact law settings for cracks and finalize variables
void CrackSurfaceContact::Output(void)
{
	// allocate memory for custom crack contact laws
	char *p=new char[(numberOfCracks+1)*sizeof(ContactLaw *)];
	crackContactLaw=(ContactLaw **)p;
	
	// Global material contact law (must be set,if not force to frictionless)
	crackContactLawID = MaterialBase::GetContactLawNum(crackContactLawID);
	if(crackContactLawID<0)
		throw CommonException("Crack settings must select a default contact law","CrackSurfaceContact::Output");
	crackContactLaw[0] = (ContactLaw *)theMaterials[crackContactLawID];
	cout << "Default Contact Law: " << crackContactLaw[0]->name << " (number " << (crackContactLawID+1) << ")" << endl;
	if(crackContactLaw[0]->IsImperfectInterface()) hasImperfectInterface=true;
	
	// print other settings
	cout << "Contact Detection: Normal cod < 0 AND normal dv < 0" << endl;
    mpmgrid.OutputContactByDisplacements();
	if(GetMoveOnlySurfaces())
		cout << "Crack Plane Updating: Average of the crack surfaces" << endl;
	else
		cout << "Crack Plane Updating: Use center of mass velocity" << endl;
	if(GetPreventPlaneCrosses())
		cout << "Crack Plane Crosses: surface particles moved back to the current plane" << endl;
	else
		cout << "Crack Plane Crosses: ignored" << endl;
}
Example #6
0
// check if analysis is allowed
// throws CommonException()
void TaitLiquid::ValidateForUse(int np) const
{	if(np==PLANE_STRESS_MPM)
    {	throw CommonException("TaitLiquid material cannot do 2D plane stress analysis",
                          "TaitLiquid::ValidateForUse");
    }

    return HyperElastic::ValidateForUse(np);
}
void ActorList::addActor(Actor::ptr p_Actor)
{
	if (m_Actors.find(p_Actor->getId()) != m_Actors.end())
	{
		throw CommonException("You may not add an already existing actor", __LINE__, __FILE__);
	}

	m_Actors[p_Actor->getId()] = p_Actor;
}
Example #8
0
// plane stress not allowed in viscoelasticity
void Viscoelastic::ValidateForUse(int np) const
{	if(np==PLANE_STRESS_MPM)
	{	throw CommonException("Viscoelastic materials are not allowed in plane stress calculations",
							  "Viscoelastic::ValidateForUse");
	}
	
	//call super class (why can't call super class?)
	MaterialBase::ValidateForUse(np);
}
Example #9
0
// plane stress not allowed in viscoelasticity
// throws CommonException()
void HEIsotropic::ValidateForUse(int np) const
{	if(np==PLANE_STRESS_MPM)
    {	throw CommonException("HEIsotropic materials cannot be used in plane stress MPM yet",
                                "HEIsotropic::ValidateForUse");
    }
	
	//call super class (why can't call super class?)
	HyperElastic::ValidateForUse(np);
}
// plane stress not allowed in viscoelasticity
// throws CommonException()
void ClampedNeohookean::ValidateForUse(int np) const
{	if(np==PLANE_STRESS_MPM)
	{	throw CommonException("Clamped Neohookean material cannot be used in plane stress MPM yet",
						  "ClampedNeohookean::ValidateForUse");
	}
	
	//call super class (why can't call super class?)
	Neohookean::ValidateForUse(np);
}
// 3D not allowed
void BistableIsotropic::ValidateForUse(int np) const
{	if(np==THREED_MPM || np==AXISYMMETRIC_MPM)
	{	throw CommonException("BistableIsotropic materials cannot do 3D or Axisymmetric MPM analysis",
							  "BistableIsotropic::ValidateForUse");
	}
	
	// call super class (why can't call super class?)
	IsotropicMat::ValidateForUse(np);
}
// Print contact law settings for cracks and finalize variables
void CrackSurfaceContact::MaterialOutput(void)
{
	// Global material contact law (must be set,if not force to frictionless)
	materialContactLawID = MaterialBase::GetContactLawNum(materialContactLawID);
	if(materialContactLawID<0)
		throw CommonException("Multimaterial mode must select a default contact law","CrackSurfaceContact::MaterialOutput");
	materialContactLaw = (ContactLaw *)theMaterials[materialContactLawID];
	cout << "Default Contact Law: " << materialContactLaw->name << " (number " << (materialContactLawID+1) << ")" << endl;
	if(materialContactLaw->IsImperfectInterface()) hasImperfectInterface=true;
	
	// print contact detection method
	char join[3];
	join[0]=0;
	cout << "Contact Detection: ";
	if(materialContactVmin>0.)
	{	cout << "(Vrel >= " << materialContactVmin << ")";
		strcpy(join," & ");
	}
	cout << join << "(Normal dv < 0)";
	strcpy(join," & ");
	if(displacementCheck)
	{	cout << join << "(Normal cod < 0)" << endl;
        mpmgrid.OutputContactByDisplacements();
	}
	else
		cout << endl;
	
	cout << "Normal Calculation: ";
	switch(materialNormalMethod)
	{	case MAXIMUM_VOLUME_GRADIENT:
			cout << " gradient of material or paired material (if all nonrigid), or the rigid material (if" << endl;
			cout << "                   one rigid material), that has highest magnitude. When has rigid" << endl;
			cout << "                   material, prefer rigid material gradient with bias factor = " << rigidGradientBias;
			rigidGradientBias*=rigidGradientBias;       // squared as needed in algorithm
			break;
		case MAXIMUM_VOLUME:
			cout << " gradient of material with maximum volume";
			break;
		case AVERAGE_MAT_VOLUME_GRADIENTS:
			cout << " volume-weighted mean gradient of material and other materials lumped (if all nonrigid)," << endl;
			cout << "                   on just the rigid material (if one rigid material). When has rigid" << endl;
			cout << "                   material, prefer rigid material gradient with bias factor = " << rigidGradientBias;
			rigidGradientBias*=rigidGradientBias;       // squared as needed in algorithm
			break;
		case EACH_MATERIALS_MASS_GRADIENT:
			cout << " each material's own mass gradient";
			break;
		case SPECIFIED_NORMAL:
			cout << " use the specified normal of ";
			PrintVector("",&contactNormal);
		default:
			break;
	}
	cout << endl;
}
Example #13
0
// report a file error to some file
void ArchiveData::FileError(const char *msg,const char *filename,const char *method)
{	char errNo[50];
	sprintf(errNo,"%d",errno);
	char *errMsg=new char[strlen(msg)+strlen(filename)+strlen(errNo)+15];
	strcpy(errMsg,msg);
	strcat(errMsg," (file: ");
	strcat(errMsg,filename);
	strcat(errMsg,", #");
	strcat(errMsg,errNo);
	strcat(errMsg,").");
	throw CommonException(errMsg,method);
}
SpellInstance::ptr SpellFactory::createSpellInstance(const std::string& p_Spell, Vector3 p_Direction)
{
	auto spellDef = m_SpellDefinitionMap.find(p_Spell);
	if (spellDef == m_SpellDefinitionMap.end())
	{
		throw CommonException("Can not create spell from a missing spell definition (" + p_Spell + ")", __LINE__, __FILE__);
	}

	SpellInstance::ptr instance(new SpellInstance);
	instance->init(spellDef->second, p_Direction);

	return instance;
}
Example #15
0
// Create global archive file
void ArchiveData::CreateGlobalFile(void)
{
    FILE *fp;
	char fline[1000];
	GlobalQuantity *nextGlobal;
	
	// skip if none, but error if tried to define global quantities
	if(globalTime<0.)
	{   globalTime=-1.;
		if(firstGlobal!=NULL)
			throw CommonException("<GlobalArchive> was used but never activated with a <GlobalArchiveTime> command.","ArchiveData::CreateGlobalFile");
		return;
	}
	
	// get relative path name to the file
	globalFile=new char[strlen(outputDir)+strlen(archiveRoot)+8];
	sprintf(globalFile,"%s%s.global",outputDir,archiveRoot);
	
    // create and open the file
    if((fp=fopen(globalFile,"w"))==NULL) goto abort;
	
	// write color
	strcpy(fline,"#setColor");
	nextGlobal=firstGlobal;
	while(nextGlobal!=NULL)
	    nextGlobal=nextGlobal->AppendColor(fline);
	strcat(fline,"\n");
	if(fwrite(fline,strlen(fline),1,fp)!=1) goto abort;
	
	// write name
	strcpy(fline,"#setName");
	nextGlobal=firstGlobal;
	while(nextGlobal!=NULL)
		nextGlobal=nextGlobal->AppendName(fline);
	strcat(fline,"\n");
	if(fwrite(fline,strlen(fline),1,fp)!=1) goto abort;
	
	// close the file
    if(fclose(fp)!=0) goto abort;
	
	// section in output file
    PrintSection("ARCHIVED GLOBAL RESULTS");
    cout << "Global data file: " << archiveRoot << ".global" << endl;
	cout << endl;
	
	return;

abort:
	FileError("Global archive file creation failed",globalFile,"ArchiveData::CreateGlobalFile");
}
// Print contact law settings (if has one) and finalize crack law and set if has imperfect interface
void CrackSurfaceContact::CustomCrackContactOutput(int &customCrackID,int number)
{
	// no custom law was set
	if(customCrackID<0)
	{	crackContactLaw[number] = crackContactLaw[0];
		return;
	}
	
	// custom law
	customCrackID = MaterialBase::GetContactLawNum(customCrackID);
	if(customCrackID<0)
		throw CommonException("Custom crack contact must select a default contact law","CrackSurfaceContact::Output");
	crackContactLaw[number] = (ContactLaw *)theMaterials[customCrackID];
	cout << "    Custom Contact Law: " << crackContactLaw[number]->name << " (number " << (customCrackID+1) << ")" << endl;
	if(crackContactLaw[number]->IsImperfectInterface()) hasImperfectInterface=true;
}
// on start up initialize number of CPDI nodes (if needed)
// done here in case need more initializations in the future
// throws CommonException() if CPDI type is not allowed
void ElementBase::InitializeCPDI(bool isThreeD)
{
    if(isThreeD)
    {   if(useGimp == LINEAR_CPDI)
        {   numCPDINodes = 8;
        }
        else if(useGimp == QUADRATIC_CPDI)
        {	throw CommonException("qCPDI is not yet implemented for 3D (use lCPDI instead).","ElementBase::InitializeCPDI");
        }
    }
    else
    {   if(useGimp == LINEAR_CPDI || useGimp==LINEAR_CPDI_AS)
        {   numCPDINodes = 4;
        }
        else if(useGimp == QUADRATIC_CPDI)
        {   numCPDINodes = 9;
        }
    }
}
Example #18
0
// when set, return total number of materials if this is a new one, or 1 if not in multimaterial mode
// not thread safe due to push_back()
int MaterialBase::SetField(int fieldNum,bool multiMaterials,int matid,int &activeNum)
{	if(!multiMaterials)
	{	if(field<0)
		{	field=0;
			activeField=activeNum;
			fieldNum=1;
			activeNum++;
			activeMatIDs.push_back(matid);
            int altBuffer,matBuffer = SizeOfMechanicalProperties(altBuffer);
            if(matBuffer > maxPropertyBufferSize) maxPropertyBufferSize = matBuffer;
            if(altBuffer > maxAltBufferSize) maxAltBufferSize = altBuffer;
		}
	}
	else
	{	if(field<0)
		{	// if sharing a field, look up shared material.
			if(shareMatField>0)
			{	if(shareMatField>nmat)
				{	throw CommonException("Material class trying to share velocity field with an undefined material type",
										  "MaterialBase::SetField");
				}
			
				// must match for rigid feature
				MaterialBase *matRef = theMaterials[shareMatField-1];
				if(matRef->Rigid() != Rigid())
				{	throw CommonException("Material class trying to share velocity field with an incompatible material type",
										  "MaterialBase::SetField");
				}
			
				// base material cannot share too
				if(matRef->GetShareMatField()>=0)
				{	throw CommonException("Material class trying to share velocity field with a material that share's its field",
										  "MaterialBase::SetField");
				}

				// set field to other material (and set other material if needed
				field = matRef->GetField();
				if(field<0)
				{	fieldNum = matRef->SetField(fieldNum,multiMaterials,shareMatField-1,activeNum);
					field = fieldNum-1;
				}
			}
			else
			{	field=fieldNum;
				fieldNum++;
				
				// fieldMatIDs[i] for i=0 to # materials is material index for that material velocity field
				// when materials share fields, it points to the based shared material
				fieldMatIDs.push_back(matid);
			}
			
			// for first particle using this material, add to active material IDs and check required
			// material buffer sizes
			if(activeNum>=0)
			{	activeField=activeNum;
				activeNum++;
				activeMatIDs.push_back(matid);
                int altBuffer,matBuffer = SizeOfMechanicalProperties(altBuffer);
                if(matBuffer > maxPropertyBufferSize) maxPropertyBufferSize = matBuffer;
                if(altBuffer > maxAltBufferSize) maxAltBufferSize = altBuffer;
			}
		}
	}
	return fieldNum;
}
// Called when custom tasks are all done on a step
// throw CommonException() to end simulation
CustomTask *ReverseLoad::FinishForStep(void)
{
    // change to true trigger or on end of holding phase
	bool status = false;
    
    // after checking decide if stop or if final hold phase
    switch(reversed)
    {   case REVERSED_PHASE:
            // once reversed, check if reached final time and then exit
            // othersize just continue
            if(style==REVERSE && mtime>finalTime)
                throw CommonException("Load or displacement has returned to zero","ReverseLoad::FinishForStep");
            break;
        
        case HOLDING_PHASE:
            // change status to true if done with holding phase
            if(mtime>endHoldTime) status=true;
            break;
        
        case CHECKING_PHASE:
        default:
            // check global quantity
            if(quantity>=0)
            {	// see if has passed desider value
                status = archiver->PassedLastArchived(quantity,finalLength);
            }
            
            // check cracks
            else if(propagateTask->theResult!=NOGROWTH)
            {	// check desired crack or all cracks
                int cnum=0;
                CrackHeader *nextCrack=firstCrack;
                while(nextCrack!=NULL)
                {	cnum++;
                    if(crackNum==0 || crackNum==cnum)
                    {   // found crack, check the length
                        if(nextCrack->Length()>finalLength) status = true;
                        
                        // exit if critical or only one crack to check
                        if(status || crackNum==cnum) break;
                    }
                    nextCrack=(CrackHeader *)nextCrack->GetNextObject();
                }
            }
            break;
    }
    
    // if status is false, then nothing to do
    if(!status) return nextTask;
	
    // Print message that task has been triggered
    if(reversed == CHECKING_PHASE)
    {   if(quantity>=0)
        {	if(style==ABORT && holdTime<0.)
                throw CommonException("Global quantity has reached specified value","ReverseLoad::FinishForStep");
            
            cout << "# Critical global quantity reached at time t: " << mtime*UnitsController::Scaling(1.e3)
				<< " " << UnitsController::Label(ALTTIME_UNITS) << endl;
        }
        else
        {	if(style==ABORT && holdTime<0.)
                throw CommonException("Crack has reached specified length","ReverseLoad::FinishForStep");
            
            // stop propgation
            propagateTask->ArrestGrowth(TRUE);
            cout << "# Crack growth arrested at time t: " << mtime*UnitsController::Scaling(1.e3)
				<< " " << UnitsController::Label(ALTTIME_UNITS) << endl;
        }
        
        // final time if reversing
        finalTime = 2.*mtime;
        
        // if holding, wait to trigger change until latter
        if(holdTime>0.)
        {   reversed = HOLDING_PHASE;
            endHoldTime = mtime + holdTime;
            finalTime = 2.*mtime + holdTime;
        }
        else
        {   reversed = REVERSED_PHASE ;
            finalTime = 2.*mtime;
        }
    }
    else
    {   // if an abort after holding, exit now
       if(style==ABORT)
            throw CommonException("ReverseLoad task hold time has ended","ReverseLoad::FinishForStep");
        
        // message that hold time is over
        cout << "# ReverseLoad task hold time ended at t:" << mtime*UnitsController::Scaling(1.e3)
			<< " " << UnitsController::Label(ALTTIME_UNITS) << endl;
        reversed = REVERSED_PHASE;
    }
    
    // REVERSE: reverse linear loads, zero constant loads, reverse or zero constant velocity rigid particles
    // HOLD: make linear loads constant, stop constant velocity rigid particles
    // ABORT: here is holding, treat like a HOLD
    // finalTime will be twice current time, or if any reversed linear loads, the time last one gets to zero
    if(style!=NOCHANGE)
    {   // load BCs
        MatPtLoadBC *nextLoad=firstLoadedPt;
        while(nextLoad!=NULL)
        {	if(style==REVERSE)
                nextLoad=nextLoad->ReverseLinearLoad(mtime,&finalTime,reversed==HOLDING_PHASE);
            else
                nextLoad=nextLoad->MakeConstantLoad(mtime);
        }
        
        // traction BCs
        MatPtTractionBC *nextTraction=firstTractionPt;
        while(nextTraction!=NULL)
        {	if(style==REVERSE)
                nextTraction=(MatPtTractionBC *)nextTraction->ReverseLinearLoad(mtime,&finalTime,reversed==HOLDING_PHASE);
            else
                nextTraction=(MatPtTractionBC *)nextTraction->MakeConstantLoad(mtime);
        }
        
        // reverse rigid particles at constant velocity
        int p;
        for(p=nmpmsNR;p<nmpms;p++)
        {	RigidMaterial *mat = (RigidMaterial *)theMaterials[mpm[p]->MatID()];
            if(mat->IsConstantVelocity())
            {	if(style==REVERSE)
                    mpm[p]->ReverseParticle(reversed==HOLDING_PHASE,holdTime>0.);
                else
                    mpm[p]->StopParticle();
            }
        }
    }
	
	return nextTask;
}
// return dimensionless location for material points
void ElementBase::MPMPoints(short numPerElement,Vector *mpos) const
{
    int i,j,k;
    double fxn[MaxElNd],row,zrow;
    
    if(NumberSides()==4)
    {	switch(numPerElement)
        {   case 4:
                // ENI or FNI - 2D only
                mpos[0].x=-.5;
                mpos[0].y=-.5;
                mpos[0].z=0.;
                mpos[1].x=.5;
                mpos[1].y=-.5;
                mpos[1].z=0.;
                mpos[2].x=-.5;
                mpos[2].y=.5;
                mpos[2].z=0.;
                mpos[3].x=.5;
                mpos[3].y=.5;
                mpos[3].z=0.;
                break;
            case 1:
                // CM of square or brick
                mpos[0].x=0.;
                mpos[0].y=0.;
				mpos[0].z=0.;
				break;
			case 8:
				// 3D box
                mpos[0].x=-.5;
                mpos[0].y=-.5;
				mpos[0].z=-.5;
                mpos[1].x=.5;
                mpos[1].y=-.5;
				mpos[1].z=-.5;
                mpos[2].x=-.5;
                mpos[2].y=.5;
				mpos[2].z=-.5;
                mpos[3].x=.5;
                mpos[3].y=.5;
				mpos[3].z=-.5;
                mpos[4].x=-.5;
                mpos[4].y=-.5;
				mpos[4].z=.5;
                mpos[5].x=.5;
                mpos[5].y=-.5;
				mpos[5].z=.5;
                mpos[6].x=-.5;
                mpos[6].y=.5;
				mpos[6].z=.5;
                mpos[7].x=.5;
                mpos[7].y=.5;
				mpos[7].z=.5;
				break;
            case 9:
                // 2D
                k=0;
                row = -2./3.;
                for(j=0;j<3;j++)
                {   mpos[k].x=-2./3.;
                    mpos[k].y=row;
                    mpos[k].z=0.;
                    mpos[k+1].x=0.;
                    mpos[k+1].y=row;
                    mpos[k+1].z=0.;
                    mpos[k+2].x=2./3.;
                    mpos[k+2].y=row;
                    mpos[k+2].z=0.;
                    k += 3;
                    row += 2./3.;
                }
                break;
            case 16:
                // 2D
                k=0;
                row = -0.75;
                for(j=0;j<4;j++)
                {   mpos[k].x=-0.75;
                    mpos[k].y=row;
                    mpos[k].z=0.;
                    mpos[k+1].x=-.25;
                    mpos[k+1].y=row;
                    mpos[k+1].z=0.;
                    mpos[k+2].x=.25;
                    mpos[k+2].y=row;
                    mpos[k+2].z=0.;
                    mpos[k+3].x=.75;
                    mpos[k+3].y=row;
                    mpos[k+3].z=0.;
                    k += 4;
                    row += 0.5;
                }
                break;
            case 25:
                // 2D
                k=0;
                row = -0.8;
                for(j=0;j<5;j++)
                {   mpos[k].x=-0.8;
                    mpos[k].y=row;
                    mpos[k].z=0.;
                    mpos[k+1].x=-.4;
                    mpos[k+1].y=row;
                    mpos[k+1].z=0.;
                    mpos[k+2].x=0.;
                    mpos[k+2].y=row;
                    mpos[k+2].z=0.;
                    mpos[k+3].x=.4;
                    mpos[k+3].y=row;
                    mpos[k+3].z=0.;
                    mpos[k+4].x=.8;
                    mpos[k+4].y=row;
                    mpos[k+4].z=0.;
                    k += 5;
                    row += 0.4;
                }
                break;
            case 27:
                // 3D
                k=0;
                zrow = -2./3.;
                for(i=0;i<3;i++)
                {   row = -2./3.;
                    for(j=0;j<3;j++)
                    {   mpos[k].x=-2./3.;
                        mpos[k].y=row;
                        mpos[k].z=zrow;
                        mpos[k+1].x=0.;
                        mpos[k+1].y=row;
                        mpos[k+1].z=zrow;
                        mpos[k+2].x=2./3.;
                        mpos[k+2].y=row;
                        mpos[k+2].z=zrow;
                        k += 3;
                        row += 2./3.;
                    }
                    zrow += 2./3.;
                }
                break;
            default:
                throw CommonException("Invalid number of material points per element.","ElementBase::MPMPoints");
                break;
        }
    }
    
    // covert to x-y-z locations
    for(k=0;k<numPerElement;k++)
    {	ShapeFunction(&mpos[k],FALSE,fxn,NULL,NULL,NULL);
		ZeroVector(&mpos[k]);
        for(j=0;j<NumberNodes();j++)
        {   mpos[k].x+=nd[nodes[j]]->x*fxn[j];
            mpos[k].y+=nd[nodes[j]]->y*fxn[j];
            mpos[k].z+=nd[nodes[j]]->z*fxn[j];
        }
    }
}
Example #21
0
void NairnFEA::FEAAnalysis()
{
    char nline[200];
    int result;
    int i;
    NodalDispBC *nextBC;
    double times[5];

#pragma mark --- TASK 0: INITIALIZE
    // start timer
    times[0]=CPUTime();
    
    // get problem size and other initialization
    nsize=nnodes*nfree + numConstraints;
    nband=GetBandWidth();
	
    if(np==AXI_SYM)
    {	xax='r';
        yax='z';
        zax='t';
    }
    
    // Stiffness matrix info
    PrintSection("TOTAL STIFFNESS MATRIX");
    sprintf(nline,"Initial number of equations:%6d     Initial bandwidth:%6d",nsize,nband);
    cout << nline << endl << endl;

#pragma mark --- TASK 1: ALLOCATE R VECTOR
    // Allocate reaction vector and load with nodal loads and edge loads
    rm=(double *)malloc(sizeof(double)*(nsize+1));
    if(rm==NULL) throw CommonException("Memory error allocating reaction vector (rm)","NairnFEA::FEAAnalysis");
    for(i=1;i<=nsize;i++) rm[i]=0.;
    
    // add nodal loads to rm[] vector
    NodalLoad *nextLoad=firstLoadBC;
    while(nextLoad!=NULL)
    	nextLoad=nextLoad->Reaction(rm,np,nfree);
	
	// add stresses on element edges to rm[] vector
	ForcesOnEdges();

#pragma mark --- TASK 2: GET STIFFNESS MATRIX
    // allocate and fill global stiffness matrix, st[][], and reaction vector, rm[]
    times[1]=CPUTime();
    BuildStiffnessMatrix();

#pragma mark --- TASK 3: DISPLACEMENT BCs
    // Impose displacement boundary conditions and rotate
	//     nodes for skew boundary conditions
    nextBC=firstDispBC;
    while(nextBC!=NULL)
    	nextBC=nextBC->FixOrRotate(st,rm,nsize,nband,nfree);
    
#pragma mark --- TASK 4: INVERT STIFFNESS MATRIX
    // Solve linear system for nodal displacements
    times[2]=CPUTime();
    double *work=(double *)malloc(sizeof(double)*(nsize+1));
	if(work==NULL) throw CommonException("Memory error allocating work vector for linear solver",
                                        "NairnFEA::FEAAnalysis");
    result=gelbnd(st,nsize,nband,rm,work,0);
    if(result==1)
    {	throw CommonException("Linear solver error: matrix is singular. Check boundary conditions.\n  (Hint: turn on resequencing to check for mesh connectivity problem)",
                                "NairnFEA::FEAAnalysis");
    }
    else if(result==-1)
	{	cout << "Linear solver warning: solution process was close to singular. Results might be invalid." << endl;
    }
    free(work);
    free(st);
	free(stiffnessMemory);
    
#pragma mark --- TASK 5a: UNSKEW ROTATED NODES

    nextBC=firstDispBC;
    while(nextBC!=NULL)
    	nextBC=nextBC->Unrotate(rm,nfree);
    
#pragma mark --- TASK 6: OUTPUT RESULTS

	// time to here for performance evaluation
    double execTime=ElapsedTime();						// elpased time in secs
    times[3]=CPUTime();
    
    // Print Displacements
    DisplacementResults();
    
    // Calculate forces, stresses, and energy
    //	print element forces and stresses
    ForceStressEnergyResults();
    
    // Average nodal stresses
    AvgNodalStresses();
    
    // reactivities at fixed nodes
    ReactionResults();
    
    // strain energies
    EnergyResults();
    
    // execution times
    times[4]=CPUTime();
    PrintSection("EXECUTION TIMES AND MEMORY");
    cout << "1. Allocate Memory: " << (times[1]-times[0]) << " secs" << endl;		
    cout << "2. Build Stiffness Matrix: " << (times[2]-times[1]) << " secs" << endl;
    cout << "3. Solve Linear System: " << (times[3]-times[2]) << " secs" << endl;
    cout << "4. Write Results: " << (times[4]-times[3]) << " secs" << endl;
    cout << "5. Total Execution CPU Time: " << times[3] << " secs" << endl;
    cout << "6. Total Execution Elapsed Time: " << execTime << " secs" << endl;
	cout << "7. Scaling: " << times[3]/execTime << endl;
    
    //---------------------------------------------------
    // Trailer
    cout << "\n***** NAIRNFEA RUN COMPLETED\n";
}
Example #22
0
// Archive the results if it is time
void ArchiveData::ArchiveResults(double atime)
{
	double rho,rho0;
    double sxx,syy,sxy;
    char fname[500],fline[500];
    int i,p;
    CrackHeader *nextCrack;
	
	// test global archiving
	GlobalArchive(atime);
    
    // see if desired
    if(atime<nextArchTime) return;
    nextArchTime+=archTime;
	
	// exit if using delayed archiving
	if(atime>0.9*timestep && atime<firstArchTime) return;
    
    // get relative path name to the file
    sprintf(fname,"%s%s.%d",outputDir,archiveRoot,fmobj->mstep);
    
    // output step number, time, and file name to results file
    for(i=strlen(fname);i>=0;i--)
    {	if(fname[i]=='/') break;
    }
    sprintf(fline,"%7d %15.7e  %s",fmobj->mstep,1000.*atime,&fname[i+1]);
    cout << fline << endl;

    // open the file
	ofstream afile;
	try
	{	afile.open(fname, ios::out | ios::binary);
		if(!afile.is_open())
			FileError("Cannot open an archive file",fname,"ArchiveData::ArchiveResults");
		
		// write header created in SetArchiveHeader
		*timeStamp=1000.*atime;
		afile.write(archHeader,HEADER_LENGTH);
		if(afile.bad())
			FileError("File error writing archive file header",fname,"ArchiveData::ArchiveResults");
	}
	catch(CommonException err)
	{   // give up on hopefully temporary file problem
		cout << "# " << err.Message() << endl;
		cout << "# Will try to continue" << endl;
		if(afile.is_open()) afile.close();
		return;
	}
		
	// allocate space for one material point
	long blen=recSize;
	char *aptr=(char *)malloc(blen);
	if(aptr==NULL)
		throw CommonException("Out of memory allocating buffer for archive file","ArchiveData::ArchiveResults");
    
    // all material points
    for(p=0;p<nmpms;p++)
	{	// buffer is for one particle
    	char *app=aptr;
		
		// must have these defaults
	   
		// element ID
        *(int *)app=mpm[p]->ArchiveElemID();
        app+=sizeof(int);
        
		// mass (g)
        *(double *)app=mpm[p]->mp;
        app+=sizeof(double);
        
		// material ID
        *(short *)app=mpm[p]->ArchiveMatID();
        app+=sizeof(short);
		// fill in two zeros for byte alignment
		*app=0;
		app+=1;
		*app=0;
		app+=1;
        
		// 3D has three angles, 2D has one angle and thickness
		if(threeD)
		{	// 3 material rotation angles in degrees
			*(double *)app=mpm[p]->GetRotationZInDegrees();
			app+=sizeof(double);
			*(double *)app=mpm[p]->GetRotationYInDegrees();
			app+=sizeof(double);
			*(double *)app=mpm[p]->GetRotationXInDegrees();
			app+=sizeof(double);
		}
		else
		{	// material rotation angle in degrees
			*(double *)app=mpm[p]->GetRotationZInDegrees();
			app+=sizeof(double);
			
			// thickness (2D) in mm
			*(double *)app=mpm[p]->thickness();
			app+=sizeof(double);
		}
        
		// (x,y,z) position (mm)
        *(double *)app=mpm[p]->pos.x;
        app+=sizeof(double);
        
        *(double *)app=mpm[p]->pos.y;
        app+=sizeof(double);
		
		if(threeD)
		{	*(double *)app=mpm[p]->pos.z;
			app+=sizeof(double);
		}

		// original (x,y,z) position (mm)
        *(double *)app=mpm[p]->origpos.x;
        app+=sizeof(double);
                
        *(double *)app=mpm[p]->origpos.y;
        app+=sizeof(double);

		if(threeD)
		{	*(double *)app=mpm[p]->origpos.z;
			app+=sizeof(double);
		}

        // velocity (mm/sec)
        if(mpmOrder[ARCH_Velocity]=='Y')
        {   *(double *)app=mpm[p]->vel.x;
            app+=sizeof(double);
                
            *(double *)app=mpm[p]->vel.y;
            app+=sizeof(double);
			
			if(threeD)
			{	*(double *)app=mpm[p]->vel.z;
				app+=sizeof(double);
			}
        }

        // stress - internally it is N/m^2 cm^3/g, output in N/m^2 or Pa
        //          internal SI units are kPa/(kg/m^3)
		// For large deformation, need to convert Kirchoff Stress/rho0 to Cauchy stress
        int matid = mpm[p]->MatID();
        rho0=theMaterials[matid]->rho;
        rho = rho0/theMaterials[matid]->GetCurrentRelativeVolume(mpm[p]);
        Tensor sp = mpm[p]->ReadStressTensor();
        sxx=rho*sp.xx;
        syy=rho*sp.yy;
        sxy=rho*sp.xy;
        if(mpmOrder[ARCH_Stress]=='Y')
        {   *(double *)app=sxx;
            app+=sizeof(double);
                
            *(double *)app=syy;
            app+=sizeof(double);
            
			*(double *)app=rho*sp.zz;
            app+=sizeof(double);
                
            *(double *)app=sxy;
            app+=sizeof(double);
			
			if(threeD)
            {	*(double *)app=rho*sp.xz;
				app+=sizeof(double);
				
            	*(double *)app=rho*sp.yz;
				app+=sizeof(double);
			}
        }

        // elastic strain (absolute)
        if(mpmOrder[ARCH_Strain]=='Y')
		{	Tensor *ep=mpm[p]->GetStrainTensor();
			*(double *)app=ep->xx;
            app+=sizeof(double);
                
            *(double *)app=ep->yy;
            app+=sizeof(double);
            
			*(double *)app=ep->zz;
            app+=sizeof(double);
                
            *(double *)app=ep->xy;
            app+=sizeof(double);
			
			if(threeD)
            {	*(double *)app=ep->xz;
				app+=sizeof(double);
				
            	*(double *)app=ep->yz;
				app+=sizeof(double);
			}
        }
        
        // plastic strain (absolute)
        if(mpmOrder[ARCH_PlasticStrain]=='Y')
		{	Tensor *eplast=mpm[p]->GetPlasticStrainTensor();
            *(double *)app=eplast->xx;
            app+=sizeof(double);
                
            *(double *)app=eplast->yy;
            app+=sizeof(double);
                
            *(double *)app=eplast->zz;
            app+=sizeof(double);
                
            *(double *)app=eplast->xy;
            app+=sizeof(double);
			
			if(threeD)
            {	*(double *)app=eplast->xz;
				app+=sizeof(double);
				
            	*(double *)app=eplast->yz;
				app+=sizeof(double);
			}
        }
        
        // external work (cumulative) in J
        if(mpmOrder[ARCH_WorkEnergy]=='Y')
		{	*(double *)app=1.0e-6*mpm[p]->mp*mpm[p]->GetWorkEnergy();
            app+=sizeof(double);
        }
                
        // temperature
        if(mpmOrder[ARCH_DeltaTemp]=='Y')
        {   *(double *)app=mpm[p]->pTemperature;
            app+=sizeof(double);
        }
        
        // total plastic energy (Volume*energy) in J
        // energies in material point based on energy per unit mass
        // here need mass * U/(rho0 V0)
        if(mpmOrder[ARCH_PlasticEnergy]=='Y')
        {   *(double *)app=1.0e-6*mpm[p]->mp*mpm[p]->GetPlastEnergy();
            app+=sizeof(double);
        }
                
        // shear components (absolute)
        if(mpmOrder[ARCH_ShearComponents]=='Y')
        {   *(double *)app=mpm[p]->GetDuDy();
            app+=sizeof(double);
                
            *(double *)app=mpm[p]->GetDvDx();
            app+=sizeof(double);
        }

        // total strain energy (Volume*energy) in J
        // energies in material point based on energy per unit mass
        // here need mass * U/(rho0 V0)
        // internal units are same as stress: N/m^2 cm^3/g = microJ/g = mJ/kg
		// note that rho*energy has units J/m^3 = N/m^2 (if rho in g/cm^3)
        if(mpmOrder[ARCH_StrainEnergy]=='Y')
        {   *(double *)app=1.0e-6*mpm[p]->mp*mpm[p]->GetStrainEnergy();
            app+=sizeof(double);
        }
        
        // material history data on particle (whatever units the material chooses)
        if(mpmOrder[ARCH_History]=='Y')
        {   *(double *)app=theMaterials[mpm[p]->MatID()]->GetHistory(1,mpm[p]->GetHistoryPtr());
            app+=sizeof(double);
        }
		else if(mpmOrder[ARCH_History]!='N')
		{	if(mpmOrder[ARCH_History]&0x01)
			{   *(double *)app=theMaterials[mpm[p]->MatID()]->GetHistory(1,mpm[p]->GetHistoryPtr());
				app+=sizeof(double);
			}
			if(mpmOrder[ARCH_History]&0x02)
			{   *(double *)app=theMaterials[mpm[p]->MatID()]->GetHistory(2,mpm[p]->GetHistoryPtr());
				app+=sizeof(double);
			}
			if(mpmOrder[ARCH_History]&0x04)
			{   *(double *)app=theMaterials[mpm[p]->MatID()]->GetHistory(3,mpm[p]->GetHistoryPtr());
				app+=sizeof(double);
			}
			if(mpmOrder[ARCH_History]&0x08)
			{   *(double *)app=theMaterials[mpm[p]->MatID()]->GetHistory(4,mpm[p]->GetHistoryPtr());
				app+=sizeof(double);
			}
		}
		
		// concentration and gradients convert to wt fraction units using csat for this material
        if(mpmOrder[ARCH_Concentration]=='Y')
		{	double csat=theMaterials[mpm[p]->MatID()]->concSaturation;
		
           *(double *)app=mpm[p]->pConcentration*csat;
            app+=sizeof(double);
			
			if(mpm[p]->pDiffusion!=NULL)
			{	*(double *)app=mpm[p]->pDiffusion->Dc.x*csat;
				app+=sizeof(double);
				
				*(double *)app=mpm[p]->pDiffusion->Dc.y*csat;
				app+=sizeof(double);
				
				if(threeD)
				{	*(double *)app=mpm[p]->pDiffusion->Dc.z*csat;
					app+=sizeof(double);
				}
			}
			else
 			{	*(double *)app=0.;
				app+=sizeof(double);
				
				*(double *)app=0.;
				app+=sizeof(double);
				
				if(threeD)
				{	*(double *)app=0.;
					app+=sizeof(double);
				}
			}
       }
		
        // total heat energy (Volume*energy) in J
        // energies in material point based on energy per unit mass
        // here need mass * U/(rho0 V0)
        // internal units are same as stress: N/m^2 cm^3/g = microJ/g = mJ/kg
		// note that rho*energy has units J/m^3 = N/m^2 (if rho in g/cm^3)
        if(mpmOrder[ARCH_HeatEnergy]=='Y')
        {   *(double *)app=1.0e-6*mpm[p]->mp*mpm[p]->GetHeatEnergy();
            app+=sizeof(double);
        }
		
		// element crossings since last archive - now cumulative
        if(mpmOrder[ARCH_ElementCrossings]=='Y')
        {	*(int *)app=mpm[p]->GetElementCrossings();
			app+=sizeof(int);
		}
		
		// here=initial angle z (degrees) while angle(above)=here-0.5*180*wxy/PI (degrees)
		//		Thus 0.5*180*wxy/PI = here-angle(above) or wxy = (PI/90)*(here-angle(above))
		// here=initial angle y (degrees) while angle(above)=here+0.5*180*wrot.xz/PI_CONSTANT (degrees)
		//		Thus 0.5*180*wxz/PI = -(here-angle(above)) or wxz = -(PI/90)*(here-angle(above))
		// here=initial angle x (degrees) while angle(above)=here-0.5*180.*wrot.yz/PI_CONSTANT; (degrees)
		//		Thus 0.5*180*wyz/PI = (here-angle(above)) or wyz = (PI/90)*(here-angle(above))
        if(mpmOrder[ARCH_RotStrain]=='Y')
		{	if(threeD)
			{	*(double *)app=mpm[p]->GetAnglez0InDegrees();
				app+=sizeof(double);
				*(double *)app=mpm[p]->GetAngley0InDegrees();
				app+=sizeof(double);
				*(double *)app=mpm[p]->GetAnglex0InDegrees();
				app+=sizeof(double);
			}
			else
        	{	*(double *)app=mpm[p]->GetAnglez0InDegrees();
				app+=sizeof(double);
			}
		}
		
        // padding
        if(mpmRecSize<recSize)
            app+=recSize-mpmRecSize;
        
        // reversing bytes?
        if(fmobj->GetReverseBytes())
        {   app-=recSize;
        
            // defaults
            app+=Reverse(app,sizeof(int));			// element
            app+=Reverse(app,sizeof(double));		// mass
            app+=Reverse(app,sizeof(short))+2;		// material ID
            app+=Reverse(app,sizeof(double));		// angle
            app+=Reverse(app,sizeof(double));		// thickness or dihedral
            app+=Reverse(app,sizeof(double));		// position
            app+=Reverse(app,sizeof(double));
			if(threeD) app+=Reverse(app,sizeof(double));
            app+=Reverse(app,sizeof(double));		// orig position
            app+=Reverse(app,sizeof(double));
			if(threeD) app+=Reverse(app,sizeof(double));
    
            // velocity (mm/sec)
            if(mpmOrder[ARCH_Velocity]=='Y')
            {	app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
				if(threeD) app+=Reverse(app,sizeof(double));
            }
    
            // stress 2D (in N/m^2)
            if(mpmOrder[ARCH_Stress]=='Y')
            {	app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
				if(threeD)
				{	app+=Reverse(app,sizeof(double));
					app+=Reverse(app,sizeof(double));
				}
            }

            // strain 2D (absolute)
            if(mpmOrder[ARCH_Strain]=='Y')
            {	app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
				if(threeD)
				{	app+=Reverse(app,sizeof(double));
					app+=Reverse(app,sizeof(double));
				}
            }
            
            // plastic strain (absolute)
            if(mpmOrder[ARCH_PlasticStrain]=='Y')
            {	app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
				if(threeD)
				{	app+=Reverse(app,sizeof(double));
					app+=Reverse(app,sizeof(double));
				}
            }
            
            // work energy (cumulative) in J
            if(mpmOrder[ARCH_WorkEnergy]=='Y')
                app+=Reverse(app,sizeof(double));
                    
            // temperature
            if(mpmOrder[ARCH_DeltaTemp]=='Y')
                app+=Reverse(app,sizeof(double));
            
            // total plastic energy
            if(mpmOrder[ARCH_PlasticEnergy]=='Y')
                app+=Reverse(app,sizeof(double));
                    
            // shear components
            if(mpmOrder[ARCH_ShearComponents]=='Y')
            {	app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
            }
    
            // total strain energy
            if(mpmOrder[ARCH_StrainEnergy]=='Y')
                app+=Reverse(app,sizeof(double));
                    
            // material history data on particle
            if(mpmOrder[ARCH_History]=='Y')
                app+=Reverse(app,sizeof(double));
			else if(mpmOrder[ARCH_History]!='N')
			{	if(mpmOrder[ARCH_History]&0x01) app+=Reverse(app,sizeof(double));
				if(mpmOrder[ARCH_History]&0x02) app+=Reverse(app,sizeof(double));
				if(mpmOrder[ARCH_History]&0x04) app+=Reverse(app,sizeof(double));
				if(mpmOrder[ARCH_History]&0x08) app+=Reverse(app,sizeof(double));
			}
                    
            // concentration and gradients
            if(mpmOrder[ARCH_Concentration]=='Y')
            {	app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
                app+=Reverse(app,sizeof(double));
				if(threeD)
					app+=Reverse(app,sizeof(double));
            }
			
            // total strain energy
            if(mpmOrder[ARCH_HeatEnergy]=='Y')
                app+=Reverse(app,sizeof(double));

            // element crossings
            if(mpmOrder[ARCH_ElementCrossings]=='Y')
                app+=Reverse(app,sizeof(int));
			
			// rotational strain
			if(mpmOrder[ARCH_RotStrain]=='Y')
             {	app+=Reverse(app,sizeof(double));
 				if(threeD)
				{	app+=Reverse(app,sizeof(double));
 					app+=Reverse(app,sizeof(double));
				}
            }
			
			// padding
            if(mpmRecSize<recSize)
                app+=recSize-mpmRecSize;
        }
		
		// write this particle (ofstream should buffer for us)
		try
		{	afile.write(aptr,blen);
			if(afile.bad())
				FileError("File error writing material point data",fname,"ArchiveData::ArchiveResults");
		}
		catch(CommonException err)
		{   // give up on hopefully temporary file problem
			cout << "# " << err.Message() << endl;
			cout << "# Will try to continue" << endl;
			afile.close();
			free(aptr);
			return;
		}
    }
    
	// clear material point record buffer
	free(aptr);
    
    // add the cracks
    nextCrack=firstCrack;
    while(nextCrack!=NULL)
    {	nextCrack->Archive(afile);
        nextCrack=(CrackHeader *)nextCrack->GetNextObject();
    }
    
    // close the file
	try
	{	afile.close();
		if(afile.bad())
			FileError("File error closing an archive file",fname,"ArchiveData::ArchiveResults");
	}
	catch(CommonException err)
	{   // give up on hopefully temporary file problem
		cout << "# " << err.Message() << endl;
		cout << "# Will try to continue" << endl;
	}
}
// Calculate CPDI nodes, optional shape functions and optional gradients
// numDnds - number of nodes in the particle domain
// cpdi[i]->ncpos - array of coordinates for corner nodes (numDnds of them)
// cpdi[i]->inElem - the element they are in
// cpdi[i]->ws - shape function weights (numNds of them)
// cpdi[i]->wg - gradient weights (numNds of them)
// throws CommonException() if too many CPDI nodes
int ElementBase::GetCPDIFunctions(int *nds,double *fn,double *xDeriv,double *yDeriv,double *zDeriv,MPMBase *mpmptr) const
{
	int i,j,numnds;
	CPDIDomain **cpdi = mpmptr->GetCPDIInfo();
    
	// Need 8X8 for linear CPDI in 3D, 8X4 for linear in 2D and 9X4 for quadratic in 2D (max is 64)
	int cnodes[64],ncnds=0;         // corner nodes and counter for those nodes
	double wsSi[64];				// hold ws * Si(xa)
	Vector wgSi[64];				// hold wg * Si(xa)
	
	// loop over the domain nodes
	for(i=0;i<numCPDINodes;i++)
	{	// get straight grid shape functions
		ElementBase *elem = theElements[cpdi[i]->inElem];
		elem->GetNodes(&numnds,nds);
		elem->ShapeFunction(&cpdi[i]->ncpos,FALSE,&fn[1],NULL,NULL,NULL);
		
		// loop over shape grid shape functions and collect in arrays
		for(j=1;j<=numnds;j++)
		{   cnodes[ncnds] = nds[j];
			wsSi[ncnds] = cpdi[i]->ws*fn[j];
			if(xDeriv!=NULL) CopyScaleVector(&wgSi[ncnds], &cpdi[i]->wg, fn[j]);
			ncnds++;
		}
	}
	
    /*
    if(xDeriv!=NULL)
	{	cout << "Initial:" << endl;
		for(i=0;i<ncnds;i++)
		{   cout << "# node = " << cnodes[i] << ", ws*Si = " << wsSi[i] << ", wgx*Si = " << wgSi[i].x << ", wgy*Si = " << wgSi[i].y << endl;
		}
	}
    */
	
	// shell sort by node numbers in cnodes[] (always 16 for linear CPDI)
	int lognb2=(int)(log((double)ncnds)*1.442695022+1.0e-5);	// log base 2
	int k=ncnds,l,cmpNode;
	double cmpWsSi;
	Vector cmpWgSi;
	for(l=1;l<=lognb2;l++)
	{	k>>=1;		// divide by 2
		for(j=k;j<ncnds;j++)
		{	i=j-k;
			cmpNode = cnodes[j];
			cmpWsSi = wsSi[j];
			if(xDeriv!=NULL) cmpWgSi = wgSi[j];
			
			// Back up until find insertion point
			while(i>=0 && cnodes[i]>cmpNode)
			{	cnodes[i+k] = cnodes[i];
				wsSi[i+k] = wsSi[i];
				if(xDeriv!=NULL) wgSi[i+k] = wgSi[i];
				i-=k;
			}
			
			// Insert point
			cnodes[i+k]=cmpNode;
			wsSi[i+k]=cmpWsSi;
			if(xDeriv!=NULL) wgSi[i+k]=cmpWgSi;
		}
	}

    /*
 	if(xDeriv!=NULL)
    {   for(j=1;j<ncnds;j++)
        {   if(cnodes[j]<cnodes[j-1])
            {
#pragma omp critical (output)
                {   cout << "Not Sorted: " << endl;
                    for(i=0;i<ncnds;i++)
                    {   cout << "# node = " << cnodes[i] << ", ws*Si = " << wsSi[i] << ", wgx*Si = " << wgSi[i].x << ", wgy*Si = " << wgSi[i].y << endl;
                    }
                }
                break;
            }
        }
	}
    */
	
	// compact same node number
	int count = 0;
	nds[0] = -1;
	fn[0] = 1.;
	for(i=0;i<ncnds;i++)
	{   if(cnodes[i] == nds[count])
		{   fn[count] += wsSi[i];
			if(xDeriv!=NULL)
			{	xDeriv[count] += wgSi[i].x;
				yDeriv[count] += wgSi[i].y;
                zDeriv[count] += wgSi[i].z;
			}
		}
		else
		{	if(fn[count]>1.e-10)
			{	count++;		// keep only if shape is nonzero
				if(count>=maxShapeNodes)
                {	cout << "# Found " << count-1 << " nodes; need room for remaining nodes:" << endl;
                    for(j=i;j<ncnds;j++)
                    {   cout << "#   node = " << cnodes[j] << ", ws*Si = " << endl;
                    }
					throw CommonException("Too many CPDI nodes found; increase maxShapeNodes in source code by at least number of remaining nodes","ElementBase::GetCPDIFunctions");
				}
			}
			nds[count] = cnodes[i];
			fn[count] = wsSi[i];
			if(xDeriv!=NULL)
			{	xDeriv[count] = wgSi[i].x;
				yDeriv[count] = wgSi[i].y;
                zDeriv[count] = wgSi[i].z;
			}
		}
	}
	if(fn[count]<=1.e-10) count--;
	return count;
}
Example #24
0
// start results file before proceeding to analysis
// throws CommonException()
void CommonAnalysis::StartResultsOutput(void)
{
    //--------------------------------------------------
    // Analysis Title
    PrintAnalysisTitle();
    cout << "Written by: Nairn Research Group, Oregon State University\n"
         << "Date: " << __DATE__ << "\n"
         << "Source: " << svninfo << "\n"
         << "Units: ";
    UnitsController::OutputUnits();
    cout << "\n"
#ifdef _OPENMP
         << "Processors: " << numProcs << "\n"
#endif
         << endl;


    //--------------------------------------------------
    // Description
    PrintSection("ANALYSIS DESCRIPTION");
    cout << GetDescription() << endl;

    /* development flags
     *
     *	Current Flags in Use in MPM Code
     *	 none
     *
     */
    int i;
    bool hasFlags=FALSE;
    for(i=0; i<NUMBER_DEVELOPMENT_FLAGS; i++)
    {   if(dflag[i]!=0)
        {   cout << "Development Flag #" << i << " = " << dflag[i] << endl;
            cout << "... WARNING: unrecognized developer flag specified" << endl;
            hasFlags=TRUE;
        }
    }
    if(hasFlags) cout << endl;

    //--------------------------------------------------
    // Analysis Type
    PrintAnalysisType();

    // start section (Background Grid)
#ifdef MPM_CODE
    PrintSection("NODES AND ELEMENTS (Background Grid)");
#else
    PrintSection("NODES AND ELEMENTS");
#endif

    //---------------------------------------------------
    // Nodes
    char hline[200];
    if(nnodes==0 || nelems<0)
        throw CommonException("No nodes or elements were defined in the input file.","CommonAnalysis::StartResultsOutput");
    sprintf(hline,"Nodes: %d       Elements: %d\n",nnodes,nelems);
    cout << hline;
    sprintf(hline,"DOF per node: %d     ",nfree);
    cout << hline;

    // analysis type
    switch(np)
    {
    case PLANE_STRAIN:
        cout << "2D Plane Strain Analysis\n";
        break;

    case PLANE_STRESS:
        cout << "2D Plane Stress Analysis\n";
        break;

    case AXI_SYM:
        cout << "Axisymmetric Analysis\n";
        break;

    case PLANE_STRAIN_MPM:
        cout << "2D Plane Strain MPM" << MPMAugmentation() << " Analysis\n";
        break;

    case PLANE_STRESS_MPM:
        cout << "2D Plane Stress MPM" << MPMAugmentation() << " Analysis\n";
        break;

    case THREED_MPM:
        cout << "3D MPM" << MPMAugmentation() << " Analysis\n";
        break;

    case AXISYMMETRIC_MPM:
        cout << "Axisymmetric MPM" << MPMAugmentation() << " Analysis\n";
        break;

    default:
        throw CommonException("No FEA or MPM analysis type was provided.","CommonAnalysis::StartResultsOutput");
    }
#ifdef MPM_CODE
    cout << "Incremental F Terms: " << MaterialBase::incrementalDefGradTerms << endl;
#endif
    cout << endl;

    //---------------------------------------------------
    // Nodes
    sprintf(hline,"NODAL POINT COORDINATES (in %s)",UnitsController::Label(CULENGTH_UNITS));
    PrintSection(hline);
    archiver->ArchiveNodalPoints(np);

    //---------------------------------------------------
    // Elements
    PrintSection("ELEMENT DEFINITIONS");
    archiver->ArchiveElements(np);

    //---------------------------------------------------
    // Defined Materials
    const char *err;
#ifdef MPM_CODE
    sprintf(hline,"DEFINED MATERIALS\n       (Note: moduli and stresses in %s, thermal exp. coeffs in ppm/K)\n       (      density in %s)",
            UnitsController::Label(PRESSURE_UNITS),UnitsController::Label(DENSITY_UNITS));
#else
    sprintf(hline,"DEFINED MATERIALS\n       (Note: moduli in %s, thermal exp. coeffs in ppm/K)",
            UnitsController::Label(PRESSURE_UNITS));
#endif
    PrintSection(hline);
    if(theMaterials==NULL)
        throw CommonException("No materials were defined.","CommonAnalysis::StartResultsOutput");
    for(i=0; i<nmat; i++)
    {   err=theMaterials[i]->VerifyAndLoadProperties(np);
        theMaterials[i]->PrintMaterial(i+1);
        cout << endl;
        if(err!=NULL)
        {   cout << "Invalid material properties\n   " << err << endl;
            throw CommonException("See material error above.","CommonAnalysis::StartResultsOutput");
        }
    }

    // finish with analysis specific items
    MyStartResultsOutput();

    //---------------------------------------------------
    // initialize timers
#ifdef _OPENMP
    startTime = omp_get_wtime();
#else
    time(&startTime);
#endif
    startCPU=clock();
}
Example #25
0
void NairnFEA::BuildStiffnessMatrix(void)
{
    int i,j,iel,mi0,ni0,mi,ni,mj0,nj0,ind,mj,nj;
    int numnds,ii,jj;
    
    // allocate memory for stiffness matrix and zero it
	
	// st[] are pointers to rows of the stiffness matrix
    st = (double **)malloc(sizeof(double *)*(nsize+1));
    if(st==NULL) throw CommonException("Memory error creating stiffness matrix pointers (st)",
											"NairnFEA::BuildStiffnessMatrix");
											
	// allocate all in one contiguous block for better speed in algorithms
    stiffnessMemory = (double *)malloc(sizeof(double)*(nsize*nband));
    if(stiffnessMemory==NULL) throw CommonException("Memory error creating stiffness matrix memory block",
											"NairnFEA::BuildStiffnessMatrix");
											
	// allocate each row
	int baseAddr=0;
    for(i=1;i<=nsize;i++)
	{	st[i]=&stiffnessMemory[baseAddr];
		st[i]--;					// to make it 1 based
		baseAddr+=nband;
        for(j=1;j<=nband;j++) st[i][j]=0.;
    }
    
    // Loop over all elements
    for(iel=0;iel<nelems;iel++)
    {	// Get element stiffness matrix
        theElements[iel]->Stiffness(np);
        
        /*Transfer element stiffness matrix to global stiffness matrix
                m,n address in global and element matrices, respectively
                i,j refer to row and column
                0 refers to base address */
        numnds=theElements[iel]->NumberNodes();
        for(i=1;i<=numnds;i++)
        {   mi0=nfree*(theElements[iel]->NodeIndex(i));
            ni0=nfree*(i-1);
            for(j=1;j<=numnds;j++)
            {	if(theElements[iel]->NodeIndex(j)>=theElements[iel]->NodeIndex(i))
                {   mj0=nfree*(theElements[iel]->NodeIndex(j));
                    nj0=nfree*(j-1);
                    for(ii=1;ii<=nfree;ii++)
                    {	mi=mi0+ii;
                        ni=ni0+ii;
                        for(jj=1;jj<=nfree;jj++)
                        {   mj=mj0+jj;
                            ind=mj-mi+1;
                            if(ind>0)
                            {	nj=nj0+jj;
                                st[mi][ind]+=se[ni][nj];
                            }
                        }
                    }
                }
            }
        }
		
        /* Transfer element load vector into global load vector
                m,n are adresses in global and element vectors */
        for(i=1;i<=numnds;i++)
        {   mi0=nfree*(theElements[iel]->NodeIndex(i));
            ni0=nfree*(i-1);
            for(ii=1;ii<=nfree;ii++)
            {	mi=mi0+ii;
                ni=ni0+ii;
                rm[mi]+=re[ni];
            }
        }
    }
	
	// terms for contraints with Lagrange multiplier DOFs
	if(firstConstraint!=NULL)
	{	int nbase=nsize-numConstraints;
		Constraint *nextConstraint=firstConstraint;
		while(nextConstraint!=NULL)
        {	numnds=nextConstraint->NumberNodes();
			mj=nbase+nextConstraint->GetLambdaNum();		// mj > mi always
			for(i=1;i<=numnds;i++)
			{   mi=nextConstraint->NodalDof(i,nfree);
				st[mi][mj-mi+1]+=nextConstraint->GetCoeff(i);
			}
			rm[mj]+=nextConstraint->GetQ();
			nextConstraint=(Constraint *)nextConstraint->GetNextObject();
		}
	}
}
Example #26
0
// finish start of FEA results file
void NairnFEA::MyStartResultsOutput(void)
{
    char hline[200];
    int i;
    
    //---------------------------------------------------
    // Temperature
    PrintSection("THERMAL LOAD");
	if(temperatureExpr!=NULL)
	{	if(!CreateFunction(temperatureExpr))
			throw CommonException("The temperature expression is not a valid function","NairnFEA::MyStartResultsOutput");
		for(i=1;i<=nnodes;i++)
		{	nd[i]->gTemperature = FunctionValue(1,nd[i]->x,nd[i]->y,0.,0.,0.,0.)-stressFreeTemperature;
		}
		DeleteFunction();
	}
	else
	{	// unknown, but may have been set in explicit node commands
		temperatureExpr=new char[2];
		strcpy(temperatureExpr,"?");
	}
	
	sprintf(hline,"T0: %.2lf C\nT: %s C",stressFreeTemperature,temperatureExpr);
	cout << hline << endl;
	if(stressFreeTemperature!=0)
	{	sprintf(hline,"T-T0: %s - %.2lf C",temperatureExpr,stressFreeTemperature);
		cout << hline << endl;
	}
	cout << endl;
    
    //---------------------------------------------------
    // Fixed Displacements
	if(firstDispBC!=NULL)
	{	PrintSection("NODAL POINTS WITH FIXED DISPLACEMENTS");
		cout << " Node  DOF  Displacement (mm)  Axis        Angle\n"
		<< "----------------------------------------------------\n";
		NodalDispBC *nextBC=firstDispBC;
		while(nextBC!=NULL)
			nextBC=nextBC->PrintBC(cout);
		cout << endl;
	}
    
    //---------------------------------------------------
    // Loaded Nodes
	if(firstLoadBC!=NULL)
	{	PrintSection("NODAL POINTS WITH APPLIED LOADS");
		cout << " Node  DOF       Load (N)\n"
			<< "------------------------------\n";
		NodalLoad *nextLoad=firstLoadBC;
		while(nextLoad!=NULL)
			nextLoad=nextLoad->PrintLoad();
		cout << endl;
	}

    //---------------------------------------------------
    // Stress element faces
	if(firstEdgeBC!=NULL)
	{	PrintSection("FACES WITH APPLIED STRESS (MPa)");
		cout << " Elem  Fc   Type      Nodal Stress     Nodal Stress     Nodal Stress\n"
			<< "----------------------------------------------------------------------\n";
		EdgeBC *nextEdge=firstEdgeBC;
		while(nextEdge!=NULL)
			nextEdge=nextEdge->PrintEdgeLoad();
		cout << endl;
	}
	
    //---------------------------------------------------
    // Periodic directions
	if(periodic.dof)
    {	PrintSection("PERIODIC DIRECTIONS");
		// x periodic, but y not (not allowed for axisymmetric)
		if(fmobj->periodic.dof==1)
		{	sprintf(hline,"x direction from %g to %g mm",periodic.xmin,periodic.xmax);
			cout << hline << endl;
			if(periodic.fixDu)
			{	sprintf(hline,"   Displacement jump fixed at %g mm for exx = %g",periodic.du,periodic.du/(periodic.xmax-periodic.xmin));
				cout << hline << endl;
			}
			if(periodic.fixDudy)
			{	sprintf(hline,"   Displacement jump slope fixed at %g",periodic.dudy);
				cout << hline << endl;
			}
		}
		
		// y periodic, but x not (only option for axisymmetrix - z periodic, but r not)
		else if(fmobj->periodic.dof==2)
		{	char pax = fmobj->IsAxisymmetric() ? 'z' : 'y' ;
			sprintf(hline,"%c direction from %g to %g mm",pax,periodic.ymin,periodic.ymax);
			cout << hline << endl;
			if(periodic.fixDv)
			{	sprintf(hline,"   Displacement jump fixed at %g mm for e%c%c = %g",periodic.dv,pax,pax,periodic.dv/(periodic.ymax-periodic.ymin));
				cout << hline << endl;
			}
			if(periodic.fixDvdx)
			{	sprintf(hline,"   Displacement jump slope fixed at %g",periodic.dvdx);
				cout << hline << endl;
			}
		}
		
		// x and y both periodic (not allowed for axisymmetric)
		else
		{	sprintf(hline,"x direction from %g to %g mm",periodic.xmin,periodic.xmax);
			cout << hline << endl;
			if(periodic.fixDu)
			{	sprintf(hline,"   Displacement jump fixed at %g mm for exx = %g",periodic.du,periodic.du/(periodic.xmax-periodic.xmin));
				cout << hline << endl;
			}
			if(periodic.fixDvdx)
			{	sprintf(hline,"   Displacement jump dv fixed at %g",periodic.dvdx);
				cout << hline << endl;
			}
			sprintf(hline,"y direction from %g to %g mm",periodic.ymin,periodic.ymax);
			cout << hline << endl;
			if(periodic.fixDv)
			{	sprintf(hline,"   Displacement jump fixed at %g mm for eyy = %g",periodic.dv,periodic.dv/(periodic.ymax-periodic.ymin));
				cout << hline << endl;
			}
			if(periodic.fixDudy)
			{	sprintf(hline,"   Displacement jump du fixed at %g",periodic.dudy);
				cout << hline << endl;
				
				// if both Dudy and Dvdx then global shear is specified
				if(periodic.fixDvdx)
				{	double b=periodic.dvdx/(periodic.xmax-periodic.xmin);
					double d=periodic.dudy/(periodic.ymax-periodic.ymin);
					sprintf(hline,"    for gxy = %g and rotation = %g",b+d,(d-b)/2);
					cout << hline << endl;
				}
			}
		}
		cout << endl;
	}
}
Example #27
0
// To support CPDI find nodes in the particle domain, find their elements,
// their natural coordinates, and weighting values for gradient calculations
// Should be done only once per time step and here only for axisynmmetric
// and linear CPDI
// throws CommonException() if particle corner has left the grid
void MatPointAS::GetCPDINodesAndWeights(int cpdiType)
{	
	// get polygon vectors - these are from particle to edge
    //      and generalize semi width lp in 1D GIMP
	Vector r1,r2,c;
    GetSemiSideVectors(&r1,&r2,NULL);

	// truncate domain by shrinking if any have x < 0, but keep particle in the middle
	if(pos.x-fabs(r1.x+r2.x)<0.)
	{	// make pos.x-shrink*fabs(r1.x+r2.x) very small and positive
		double shrink = (pos.x-mpmgrid.GetCellXSize()*1.e-10)/fabs(r1.x+r2.x);
		r1.x *= shrink;
		r1.y *= shrink;
		r2.x *= shrink;
		r2.y *= shrink;
	}
	
    // Particle domain area is area of the full parallelogram
    // Assume positive due to orientation of initial vectors, and sign probably does not matter
    double Ap = 4.*(r1.x*r2.y - r1.y*r2.x);
    
	try
	{	// nodes at four courves in ccw direction
		c.x = pos.x-r1.x-r2.x;
		c.y = pos.y-r1.y-r2.y;
		cpdi[0]->inElem = mpmgrid.FindElementFromPoint(&c)-1;
		theElements[cpdi[0]->inElem]->GetXiPos(&c,&cpdi[0]->ncpos);
		
		c.x = pos.x+r1.x-r2.x;
		c.y = pos.y+r1.y-r2.y;
		cpdi[1]->inElem = mpmgrid.FindElementFromPoint(&c)-1;
		theElements[cpdi[1]->inElem]->GetXiPos(&c,&cpdi[1]->ncpos);
		
		c.x = pos.x+r1.x+r2.x;
		c.y = pos.y+r1.y+r2.y;
		cpdi[2]->inElem = mpmgrid.FindElementFromPoint(&c)-1;
		theElements[cpdi[2]->inElem]->GetXiPos(&c,&cpdi[2]->ncpos);
		
		c.x = pos.x-r1.x+r2.x;
		c.y = pos.y-r1.y+r2.y;
		cpdi[3]->inElem = mpmgrid.FindElementFromPoint(&c)-1;
		theElements[cpdi[3]->inElem]->GetXiPos(&c,&cpdi[3]->ncpos);
		
		// shape weights
		double rxsum = r1.x+r2.x;
		double rxdiff = r1.x-r2.x;
		cpdi[0]->ws = 0.25 - rxsum/(12.*pos.x);
		cpdi[1]->ws = 0.25 + rxdiff/(12.*pos.x);
		cpdi[2]->ws = 0.25 + rxsum/(12.*pos.x);
		cpdi[3]->ws = 0.25 - rxdiff/(12.*pos.x);
		
		// gradient weighting values
		Ap = 1./Ap;
		double beta = r1.x*r1.y - r2.x*r2.y;
		double rysum = r1.y+r2.y;
		double rydiff = r1.y-r2.y;
		cpdi[0]->wg.x = (rydiff - beta/(3.*pos.x))*Ap;
		cpdi[0]->wg.y = -rxdiff*Ap*4.*cpdi[0]->ws;
		double tipwt =  0.25/pos.x;
		cpdi[0]->wg.z = tipwt;
		
		cpdi[1]->wg.x = (rysum + beta/(3.*pos.x))*Ap;
		cpdi[1]->wg.y = -rxsum*Ap*4.*cpdi[1]->ws;
		cpdi[1]->wg.z = tipwt;
		
		cpdi[2]->wg.x = -(rydiff + beta/(3.*pos.x))*Ap;
		cpdi[2]->wg.y = rxdiff*Ap*4.*cpdi[2]->ws;
		cpdi[2]->wg.z = tipwt;
		
		cpdi[3]->wg.x = -(rysum - beta/(3.*pos.x))*Ap;
		cpdi[3]->wg.y = rxsum*Ap*4.*cpdi[3]->ws;;
		cpdi[3]->wg.z = tipwt;
	}
		
    catch(CommonException err)
    {   char msg[200];
        sprintf(msg,"A CPDI particle domain node has left the grid: %s",err.Message());
        throw CommonException(msg,"MatPointAS::GetCPDINodesAndWeights");
    }
    
    // traction BC area saves 1/2 surface area of particle domain on the various edges
    if(faceArea!=NULL)
    {   faceArea->x = sqrt(r1.x*r1.x+r1.y*r1.y)*mpmgrid.GetThickness();			// edges 1 and 3
        faceArea->y = sqrt(r2.x*r2.x+r2.y*r2.y)*mpmgrid.GetThickness();			// edges 2 and 4
    }
}
Example #28
0
// To support traction boundary conditions, find the deformed edge, natural coordinates of
// the corners along the edge, elements for those edges, and a normal vector in direction
// of the traction
// return ratio of second nodal weight to first one
// throws CommonException() if traction edge has left the grid
double MatPointAS::GetTractionInfo(int face,int dof,int *cElem,Vector *corners,Vector *tscaled,int *numDnds)
{
    *numDnds = 2;
    double faceWt,ratio=1.,r1mag,r2mag;
    double rp=pos.x;
    Vector r1,r2;
    
    if(ElementBase::useGimp==UNIFORM_GIMP_AS)
    {   double r1x,r2y;
        GetUndeformedSemiSides(&r1x,&r2y,NULL);
        r1.x = r1x;
        r1.y = 0.;
        r2.x = 0.;
        r2.y = r2y;

        // truncate if extends into r<0
        if(pos.x-r1.x<0.)
        {   r1.x = 0.5*(pos.x+r1.x);
            rp = r1.x;
        }
        
        // get magnitudes
        r1mag = r1.x;
        r2mag = r2.y;
    }
    
    else
    {   // always LINEAR_CPDI_AS
	
        // get polygon vectors - these are from particle to edge
        //      and generalize semi width lp in 1D GIMP
        GetSemiSideVectors(&r1,&r2,NULL);
        
        // truncate by shrinking domain if any have x < 0, but keep particle in the middle
        if(pos.x-fabs(r1.x+r2.x)<0.)
        {	// make pos.x-shrink*fabs(r1.x+r2.x) very small and positive
            double shrink = (pos.x-mpmgrid.GetCellXSize()*1.e-10)/fabs(r1.x+r2.x);
            r1.x *= shrink;
            r1.y *= shrink;
            r2.x *= shrink;
            r2.y *= shrink;
        }
        
        // get magnitudes
        r1mag = sqrt(r1.x*r1.x + r1.y*r1.y);
        r2mag = sqrt(r2.x*r2.x + r2.y*r2.y);
    }
    
    // Find corners
	Vector c1,c2;
	switch(face)
	{	case 1:
			// lower edge
			c1.x = rp-r1.x-r2.x;         // node 1
			c1.y = pos.y-r1.y-r2.y;
			c2.x = rp+r1.x-r2.x;         // node 2
            c2.y = pos.y+r1.y-r2.y;
			faceWt = r1mag*(rp - r2.x - r1.x/3.);			// node 1, node 2 should be plus
			ratio = r1mag*(rp - r2.x + r1.x/3.)/faceWt;		// find the ratio
			break;
			
		case 2:
			// right edge
			c1.x = rp+r1.x-r2.x;         // node 2
			c1.y = pos.y+r1.y-r2.y;
			c2.x = rp+r1.x+r2.x;         // node 3
			c2.y = pos.y+r1.y+r2.y;
			faceWt = r2mag*(rp + r1.x - r2.x/3.);			// node 2, node 3 should be plus
			ratio = r2mag*(rp + r1.x + r2.x/3.)/faceWt;		// find the ratio
			break;
			
		case 3:
			// top edge
			c1.x = rp+r1.x+r2.x;         // node 3
			c1.y = pos.y+r1.y+r2.y;
			c2.x = rp-r1.x+r2.x;         // node 4
			c2.y = pos.y-r1.y+r2.y;
			faceWt = r1mag*(rp + r2.x + r1.x/3.);			// node 3, node 4 should be minus
			ratio = r1mag*(rp + r2.x - r1.x/3.)/faceWt;		// find the ratio
			break;
			
		default:
			// left edge
			c1.x = rp-r1.x+r2.x;         // node 4
			c1.y = pos.y-r1.y+r2.y;
			c2.x = rp-r1.x-r2.x;         // node 1
			c2.y = pos.y-r1.y-r2.y;
			faceWt = r2mag*(rp - r1.x + r2.x/3.);			// node 4, node 1 should be minus
			ratio = r2mag*(rp - r1.x - r2.x/3.)/faceWt;		// find the ratio
			break;
	}
	
	// get elements
	try
	{	cElem[0] = mpmgrid.FindElementFromPoint(&c1)-1;
		theElements[cElem[0]]->GetXiPos(&c1,&corners[0]);
		
		cElem[1] = mpmgrid.FindElementFromPoint(&c2)-1;
		theElements[cElem[1]]->GetXiPos(&c2,&corners[1]);
	}
    catch(CommonException err)
    {   char msg[200];
        sprintf(msg,"A Traction edge node has left the grid: %s",err.Message());
        throw CommonException(msg,"MatPointAS::GetTractionInfo");
    }
	
    // get traction normal vector by radial integral for first node no the edge
    ZeroVector(tscaled);
	double ex,ey,enorm;
	switch(dof)
	{	case 1:
			// normal is x direction
			tscaled->x = faceWt;
			break;
        case 2:
            // normal is y direction
            tscaled->y = faceWt;
            break;
		case N_DIRECTION:
			// cross product of edge vector with (0,0,1) = (ey, -ex)
			ex = c2.y-c1.y;
			ey = c1.x-c2.x;
		case T1_DIRECTION:
			if(dof==T1_DIRECTION)
			{	ex = c2.x-c1.x;
				ey = c2.y-c1.y;
			}
			// load in direction specified by normalized (ex,ey)
			enorm = sqrt(ex*ex+ey*ey);
			tscaled->x = ex*faceWt/enorm;
			tscaled->y = ey*faceWt/enorm;
			break;
		default:
			// normal is z direction (not used here)
            tscaled->z = faceWt;
			break;
	}
	
	// return ratio of second nodal weight to first one
	return ratio;
}
Example #29
0
// Adjust time step now
CustomTask *CarnotCycle::StepCalculation(void)
{
    
    int p;
	MaterialBase *matID;
	
	double Vrel = 0.;
	int numgas = 0;
	double Tgas = 0.;
    
    // loop over nonrigid material points
    for(p=0;p<nmpmsNR;p++)
	{	numgas++;
		Vrel += mpm[p]->GetRelativeVolume();
		Tgas += mpm[p]->pPreviousTemperature;
	}
	
	// get averages
	Vrel /= (double)numgas;
	Tgas /= (double)numgas;
	
	switch(carnotStep)
	{	case 0:
			carnotStep = 1;
			cout << "# Step 1: isothermal expansion" << endl;
            ConductionTask::adiabatic = FALSE;
			break;
			
		case 1:
			// stop when Vrel reaches V1rel
			if(Vrel >= V1rel)
			{	// switch to adibatic expanion
				carnotStep = 2;
				ConductionTask::adiabatic = TRUE;
				cout << "# Step 2: adibatic expansion" << endl;
			}
			break;
		
		case 2:
			// stop when T cools to T2
			if(Tgas<=T2)
			{	// switch to pause
				carnotStep = 3;
				ConductionTask::adiabatic = FALSE;
				V2rel = Vrel;
				
				// find velocity
				for(p=0;p<nmpms;p++)
				{	// verify material is defined and sets if field number (in in multimaterial mode)
					matID=theMaterials[mpm[p]->MatID()];	// material object for this particle
					if(matID->Rigid())
						mpm[p]->ReverseParticle(false,false);
					else
						mpm[p]->StopParticle();
				}
				
				// estimate next volume
				if(V3rel<1.)
					V3rel = V2rel/V1rel;
				
				cout << "# Step 2: isothermal compression to " << V3rel << "*V0" << endl;
			}
			break;
		
		case 3:
			// stop when Vrel reaches V3rel
			if(Vrel <= V3rel)
			{	// switch to adibatic compression
				carnotStep = 4;
				ConductionTask::adiabatic = TRUE;
				cout << "# Step 4: adibatic compression" << endl;
			}
			break;
		
		case 4:
			// done when T increases to thermal.reference, or when volume returns to 1
			if(Tgas>=thermal.reference)
				throw CommonException("Carnot cycle is complete","CarnotCycle::StepCalculation()");
			//if(Vrel<=1.)
			//	throw CommonException("Carnot cycle is complete","CarnotCycle::StepCalculation()");
			break;
		
		default:
			break;
	}

    return nextTask;
}
// See if any particles have changed elements
// Stop if off the grid
// throws CommonException()
void ResetElementsTask::Execute(void)
{
	// update feedback damping now if needed
	bodyFrc.UpdateAlpha(timestep,mtime);
	
	// how many patches?
	int totalPatches = fmobj->GetTotalNumberOfPatches();
	
#ifdef PARALLEL_RESET
	// initialize error
	CommonException *resetErr = NULL;

	// parallel over patches
#pragma omp parallel
	{
        // thread for patch pn
		int pn = GetPatchNumber();
        
		try
		{	// resetting all element types
			for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_BC;block++)
			{	// get first material point in this block
				MPMBase *mptr = patches[pn]->GetFirstBlockPointer(block);
				MPMBase *prevMptr = NULL;		// previous one of this type in current patch
				while(mptr!=NULL)
				{	int status = ResetElement(mptr);
					
					if(status==LEFT_GRID)
					{	// particle has left the grid
						mptr->IncrementElementCrossings();
						
						// enter warning only if this particle did not leave the grid before
						if(!mptr->HasLeftTheGridBefore())
						{	int result = warnings.Issue(fmobj->warnParticleLeftGrid,-1);
							if(result==REACHED_MAX_WARNINGS || result==GAVE_WARNING)
							{
#pragma omp critical (output)
								{	mptr->Describe();
								}
								// abort if needed
								if(result==REACHED_MAX_WARNINGS)
								{	char errMsg[100];
									sprintf(errMsg,"Too many particles have left the grid\n  (plot x displacement to see last one).");
									mptr->origpos.x=-1.e6;
									throw CommonException(errMsg,"ResetElementsTask::Execute");
								}
							}
							
							// set this particle has left the grid once
							mptr->SetHasLeftTheGridBefore(TRUE);
						}
						
						// bring back to the previous element
						ReturnToElement(mptr);
					}
					
					else if(status==NEW_ELEMENT && totalPatches>1)
					{	// did it also move to a new patch?
						int newpn = mpmgrid.GetPatchForElement(mptr->ElemID());
						if(pn != newpn)
						{	if(!patches[pn]->AddMovingParticle(mptr,patches[newpn],prevMptr))
							{	throw CommonException("Out of memory storing data for particle changing patches","ResetElementsTask::Execute");
							}
						}
					}
					
					else if(status==LEFT_GRID_NAN)
					{
#pragma omp critical (output)
						{	cout << "# Particle has left the grid and position is nan" << endl;
							mptr->Describe();
						}
						throw CommonException("Particle has left the grid and position is nan","ResetElementsTask::Execute");
					}
					
					// next material point and update previous particle
					prevMptr = mptr;
					mptr = (MPMBase *)mptr->GetNextObject();
				}
			}
		}
		catch(CommonException& err)
        {   if(resetErr==NULL)
			{
#pragma omp critical (error)
				resetErr = new CommonException(err);
			}
		}
		catch(std::bad_alloc&)
        {   if(resetErr==NULL)
			{
#pragma omp critical (error)
				resetErr = new CommonException("Memory error","ResetElementsTask::Execute");
			}
		}
		catch(...)
        {   if(resetErr==NULL)
			{
#pragma omp critical (error)
				resetErr = new CommonException("Unexepected error","ResetElementsTask::Execute");
			}
		}
	}

	// throw now if was an error
	if(resetErr!=NULL) throw *resetErr;
    
	// reduction phase moves the particles
	for(int pn=0;pn<totalPatches;pn++)
		patches[pn]->MoveParticlesToNewPatches();
	
#else
	
	int status;
	MPMBase *mptr,*prevMptr,*nextMptr;
	for(int pn=0;pn<totalPatches;pn++)
	{	for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_BC;block++)
		{	// get first material point in this block
			mptr = patches[pn]->GetFirstBlockPointer(block);
			prevMptr = NULL;		// previous one of this type in current patch
			while(mptr!=NULL)
			{	status = ResetElement(mptr);
				
				if(status==LEFT_GRID)
				{	// particle has left the grid
					mptr->IncrementElementCrossings();
				
					// enter warning only if this particle did not leave the grid before
					if(!mptr->HasLeftTheGridBefore())
					{	int result = warnings.Issue(fmobj->warnParticleLeftGrid,-1);
						if(result==REACHED_MAX_WARNINGS || result==GAVE_WARNING)
						{	mptr->Describe();
							// abort if needed
							if(result==REACHED_MAX_WARNINGS)
							{	char errMsg[100];
								sprintf(errMsg,"Too many particles have left the grid\n  (plot x displacement to see last one).");
								mptr->origpos.x=-1.e6;
								throw CommonException(errMsg,"ResetElementsTask::Execute");
							}
						}
						
						// set this particle has left the grid once
						mptr->SetHasLeftTheGridBefore(TRUE);
					}
				
					// bring back to the previous element
					ReturnToElement(mptr);
				}
				
				else if(status==NEW_ELEMENT && totalPatches>1)
				{	int newpn = mpmgrid.GetPatchForElement(mptr->ElemID());
					if(pn != newpn)
					{	// next material point read before move this particle
						nextMptr = (MPMBase *)mptr->GetNextObject();
						
						// move particle mptr
						patches[pn]->RemoveParticleAfter(mptr,prevMptr);
						patches[newpn]->AddParticle(mptr);
						
						// next material point is now after the prevMptr, which stays the same, which may be NULL
						mptr = nextMptr;
						continue;
					}
				}
				
				else if(status==LEFT_GRID_NAN)
				{	cout << "# Particle has left the grid and position is nan" << endl;
					mptr->Describe();
					throw CommonException("Particle has left the grid and position is nan","ResetElementsTask::Execute");
				}
				
				// next material point and update previous particle
				prevMptr = mptr;
				mptr = (MPMBase *)mptr->GetNextObject();
			}
		}
	}
#endif
}