/*************************************************************************
* 文件:	aga10.c	
* 描述:	管理计算声速或C*的整体流程
*       创建并使用基于Detail和Therm类的对象
*       包含以下函数:
*       AGA10_Init(), AGA10_UnInit(), SOS(), Crit(), Cperf(), CRi()
* 版本:	ver 1.7	2002.11.17
* 作者:	W.B. Peterson
* 修订:
* 版权 (c) 2002  美国天然气协会

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

#include "NGCal.h" 
#include "Therm.h" 
#include "Detail.h"

// 创建文件作用域的对象指针：一个Therm类对象和一个Detail类对象
static Therm *ptTherm;
static Detail *ptDetail;

/**************************************************************************
*	函数	:	AGA10_Init()
*	参数	:	void
*	返回值	:	int
*	功能	:	初始化库；创建所需对象
*	修订	:	
**************************************************************************/

 int NGCal_Init(void)
{
	ptDetail = (Detail *)malloc(sizeof(Detail));
    // 创建用于计算密度的对象
    if (NULL == ptDetail )
    {
        return MEMORY_ALLOCATION_ERROR;
    }

    // 创建用于计算热力学性质的对象
		 ptTherm = (Therm *)malloc(sizeof(Therm));
    if (NULL == ptTherm )
    {
        return MEMORY_ALLOCATION_ERROR;
    }

    return AGA10_INITIALIZED;
}

/**************************************************************************
*	函数	:	AGA10_UnInit()
*	参数	:	void
*	返回值	:	int
*	功能	:	反初始化库；删除对象
*	修订	:	
**************************************************************************/

 int NGCal_UnInit(void)
{
    // 删除对象（如果存在）
    if (ptDetail) free( ptDetail);
    if (ptTherm) free (ptTherm);
    return 0;
}

/**************************************************************************
*	函数	:	SOS()
*	参数	:	指向外部AGA10数据结构的指针
*	返回值	:	double
*	功能	:	计算声速和其他参数
*	修订	:	
**************************************************************************/

 double SOS(AGA10STRUCT *ptAGA10)
{
    // 检查库是否就绪；必要时初始化
    if (NULL == ptDetail || NULL == ptTherm)
    {
        NGCal_UnInit();
        NGCal_Init();
    }

    // 调用函数计算密度和热力学性质
    ptTherm->Run(ptTherm,ptAGA10, ptDetail);

    // 基本声速计算不计算C*；初始化为零
    ptAGA10->dCstar = 0.0;

    // 返回声速给调用者
    return ptAGA10->dSOS;
}

/**************************************************************************
*	函数	:	Crit()
*	参数	:	指向外部AGA10数据结构的指针、Detail和Therm对象以及一个双精度浮点数（管道中的气体速度）
*	返回值	:	double
*	功能	:	计算C*
*	修订	:	
**************************************************************************/

 double Crit(AGA10STRUCT *ptAGA10, double dPlenumVelocity)
{
    // 函数局部变量
    double DH, DDH, S, H;
    double tolerance = 1.0;
    double R, P, T, Z;
    int i;

    // 检查对象是否就绪；如果未就绪则尝试初始化
    if (NULL == ptDetail || NULL == ptTherm)
    {
        NGCal_UnInit();
        if (AGA10_INITIALIZED != NGCal_Init())
        {
            ptAGA10->lStatus = MEMORY_ALLOCATION_ERROR;
            return 0.0;
        }
    }

    // 首先计算密度和热力学性质
    ptTherm->Run(ptTherm,ptAGA10, ptDetail);

    // DH是从管道到喉部的焓变；这是我们的初始猜测值
    DH = (ptAGA10->dSOS * ptAGA10->dSOS - dPlenumVelocity * dPlenumVelocity) / 2.0;

    // 在我们改变数据结构内容之前捕获管道条件
    S = ptAGA10->dS;
    H = ptAGA10->dH;
    R = ptAGA10->dRhof;
    P = ptAGA10->dPf;
    Z = ptAGA10->dZf;
    T = ptAGA10->dTf;

    // 将DH的增量初始化为超出收敛容差的任意值
    DDH = 10.0;

    // 通过简单重复，搜索喷嘴喉部的压力、温度和声速，
    // 在给定管道熵的情况下提供恒定焓。
    // 如果循环执行超过100次仍未收敛，则中止。
    for (i = 1; i < MAX_NUM_OF_ITERATIONS; i++)
    {
        // 计算满足H和S的P和T
        ptTherm->HS_Mode(ptTherm,ptAGA10, ptDetail, H - DH, S, true);

        // 计算新的热力学性质，包括SOS
        ptTherm->Run(ptTherm,ptAGA10, ptDetail);

        // 保存DH用于容差检查
        DDH = DH;

        // 重新计算DH
        DH = (ptAGA10->dSOS * ptAGA10->dSOS - dPlenumVelocity * dPlenumVelocity) / 2.0;

        // 如果达到容差则结束循环
        if (fabs(DDH - DH) < tolerance) break;
    }

    // C*是真实气体临界流常数（不要与Cperf或CRi混淆）
    ptAGA10->dCstar = (ptAGA10->dRhof * ptAGA10->dSOS) / sqrt(R * P * Z);

    // 恢复原始管道压力和温度
    ptAGA10->dPf = P;
    ptAGA10->dTf = T;

    // 将流体属性恢复为管道条件
    ptTherm->Run(ptTherm,ptAGA10, ptDetail);

    // 返回临界流函数给调用者
    return ptAGA10->dCstar;
}

/**************************************************************************
*	函数	:	Cperf()
*	参数	:	指向外部AGA10数据结构的指针
*	返回值	:	double
*	功能	:	计算等熵完美气体临界流函数
*	修订	:	
**************************************************************************/

double Cperf(AGA10STRUCT *ptAGA10)
{
    double k, root, exponent;
    k = ptAGA10->dKappa;
    root = 2.0 / (k + 1.0);
    exponent = (k + 1.0) / (k - 1.0);

    // 等熵完美气体临界流函数C*i
    return(sqrt(k * pow(root, exponent)));
}

/**************************************************************************
*	函数	:	CRi()
*	参数	:	指向外部AGA10数据结构的指针
*	返回值	:	double
*	功能	:	计算等熵真实气体临界流函数CRi
*	修订	:	
**************************************************************************/

double CRi(AGA10STRUCT *ptAGA10)
{
    return (Cperf(ptAGA10) / sqrt(ptAGA10->dZf));
}

