
/*************************************************************************
* File:	aga10.cpp	
* Description:	Manages overall process of calculating speed of sound
*	or C*; creates and uses objects based on Detail and Therm classes
*	Contains the following functions:
*	AGA10_Init(), AGA10_UnInit(), SOS(), Crit(), Cperf(), CRi()
* Version:	ver 1.7	2002.11.17
* Author:	W.B. Peterson
*Revisions:
*Copyright (c) 2002  American Gas Association

**************************************************************************/

#include "aga10.h" #include "therm.h" #include "detail.h"  #include "math.h"


//Create file-scope pointers to objects we will need; one of Therm class

//and one of Detail class.

static Therm *ptTherm ; static Detail *ptDetail ;

/**************************************************************************

*	Function	:	AGA10_Init()
*	Arguments	:	void
*	Returns	:	int
*	Purpose	:	Initializes library; creates required objects
*	Revisions	:	
**************************************************************************/

 int AGA10_Init(void)

{
//create object for calculating density if (NULL == (ptDetail = new Detail))
{
return MEMORY_ALLOCATION_ERROR ;
}

//create object for calculating thermodynamic properties
if (NULL == (ptTherm = new Therm))

{
return MEMORY_ALLOCATION_ERROR ;
}

return AGA10_INITIALIZED ;

}// AGA10_Init


/**************************************************************************

*	Function	:	AGA10_UnInit()
*	Arguments	:	void
*	Returns	:	int
*	Purpose	:	Un-initializes library; deletes objects
*	Revisions	:	
**************************************************************************/

 int AGA10_UnInit(void)

{
// delete the objects (if they exist) if (ptDetail) delete ptDetail ;
if (ptTherm) delete ptTherm ; return 0 ;

}// AGA10_UnInit


/**************************************************************************
*	Function	:	SOS()
*	Arguments	:	Pointers to external AGA10 data struct
*	Returns	:	double
*	Purpose	:	calculates speed of sound and other parameters
*	Revisions	:	
**************************************************************************/

 double SOS(AGA10STRUCT *ptAGA10)

{
// check if library is ready; initialize if necessary if (NULL == ptDetail || NULL == ptTherm)

{
AGA10_UnInit() ;
AGA10_Init() ;

}

//Call function to calculate densities and thermodynamic properties ptTherm->Run(ptAGA10, ptDetail) ;

//the basic sound speed calculation doesn't calculate C*; initialize to zero ptAGA10->dCstar = 0.0 ;

//return the speed of sound to caller

return ptAGA10->dSOS ;

}// VOS()


/**************************************************************************

*	Function	:	Crit()
*	Arguments	:	Pointers to external AGA10 data struct, Detail and Therm
*			objects and a double precision float (gas velocity in plenum)
*	Returns	:	double
*	Purpose	:	calculates C*
*	Revisions	:	
**************************************************************************/

 double Crit(AGA10STRUCT *ptAGA10, double dPlenumVelocity)

{
//variables local to function double DH, DDH, S, H;
double tolerance = 1.0 ; double R, P, T, Z ;

int i ;

//check objects for readiness; try to initialize if not if (NULL == ptDetail || NULL == ptTherm)

{
AGA10_UnInit() ;

if (AGA10_INITIALIZED != AGA10_Init())
{

ptAGA10->lStatus = MEMORY_ALLOCATION_ERROR ; return 0.0 ;

}
}

//begin by calculating densities and thermodynamic properties ptTherm->Run(ptAGA10, ptDetail) ;

//DH is enthalpy change from plenum to throat; this is our initial guess

DH = (ptAGA10->dSOS * ptAGA10->dSOS - dPlenumVelocity * dPlenumVelocity)	/ 2.0 ;

//trap plenum conditions before we alter the data stucture's contents S = ptAGA10->dS ;

H = ptAGA10->dH ;

R = ptAGA10->dRhof ; P = ptAGA10->dPf ; Z = ptAGA10->dZf ; T = ptAGA10->dTf ;

//initialize delta of DH to an arbitrary value outside of

//convergence tolerance
DDH = 10.0 ;

//Via simple repetition, search for a pressure, temperature and sound speed

//at a nozzle throat which provide constant enthalpy, given the entropy known
//at the plenum. Abort if loop executes more than 100 times without convergence. for (i = 1; i < MAX_NUM_OF_ITERATIONS; i++)

{

// calculate P and T to satisfy H and S ptTherm->HS_Mode(ptAGA10, ptDetail, H - DH, S, true) ;

//calculate new thermo, including SOS ptTherm->Run(ptAGA10, ptDetail) ;

//hold DH for tolerance check

DDH = DH ;

// recalculate DH

DH = (ptAGA10->dSOS * ptAGA10->dSOS - dPlenumVelocity * dPlenumVelocity) / 2.0 ;

// end loop if tolerance reached

if (fabs(DDH - DH) < tolerance) break ;
}

//C* is the real gas critical flow constant (not to be confused with Cperf or CRi) ptAGA10->dCstar = (ptAGA10->dRhof * ptAGA10->dSOS) / sqrt(R * P * Z) ;

//put the original plenum pressure and temperature back

ptAGA10->dPf = P ; ptAGA10->dTf = T ;

//restore fluid props to plenum conditions ptTherm->Run(ptAGA10, ptDetail) ;

//return the critical flow function to caller return ptAGA10->dCstar ;

}// Crit()



/**************************************************************************
*	Function	:	Cperf()
*	Arguments	:	pointer to external AGA10 data struct
*	Returns	:	double
*	Purpose	:	calculates isentropic perfect gas critical flow function
*	Revisions	:	
**************************************************************************/

double Cperf(AGA10STRUCT *ptAGA10)

{

double k, root, exponent ;

k = ptAGA10->dKappa ; root = 2.0 / (k + 1.0) ;
exponent = (k + 1.0) / (k - 1.0) ;

// isentropic perfect gas critical flow function C*i return(sqrt(k * pow(root, exponent))) ;

}// Cperf
/**************************************************************************
*	Function	:	CRi()
*	Arguments	:	pointer to external AGA10 data struct
*	Returns	:	double
*	Purpose	:	calculates isentropic real gas critical flow function CRi
*	Revisions	:	
**************************************************************************/


double CRi(AGA10STRUCT *ptAGA10)

{

return (Cperf(ptAGA10) / sqrt(ptAGA10->dZf)) ;
}// CRi()
