#include "NGCal.h"
#include "Detail.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define NUMBEROFCOMPONENTS 21
Detail *Detail_Construct(void) {
	Detail *pDetail = (Detail *) malloc(sizeof(Detail));
	if (!pDetail) {
		return NULL;
	}
	memset(pDetail, 0, sizeof(Detail));
	pDetail->iNCC = 0;
	for (int i = 0; i < NUMBEROFCOMPONENTS; i++) {
		pDetail->aiCID[i] = -1;
	}
	pDetail->dOldMixID = 0.0;
	pDetail->dOldPb = 0.0;
	pDetail->dOldTb = 0.0;
	pDetail->dOldPf = 0.0;
	pDetail->dOldTf = 0.0;
	for (int i = 0; i < NUMBEROFCOMPONENTS; i++) {
		pDetail->dXi[i] = 0.0;
	}
	if (Detail_table(pDetail) != 0) {
		free(pDetail);
		return NULL;
	}
	return pDetail;
}

void Detail_Destroy(Detail *pDetail) {
	if (pDetail) {
		free(pDetail);
	}
}

int Detail_compositionchange(Detail *pDetail, const NGParSTRUCT *ptNGPar) {
	double dMixID = 0.0;
	for (int i = 0; i < NUMBEROFCOMPONENTS; i++)
		dMixID += ((i + 2) * ptNGPar->adMixture[i]);
	if (dMixID != pDetail->dOldMixID) {
		pDetail->dOldMixID = dMixID;
		return 1;
	}
	return 0;
}

void Detail_Run(Detail *pDetail, NGParSTRUCT *ptNGPar) {
	const int bCompChange = Detail_compositionchange(pDetail, ptNGPar);
	ptNGPar->bForceUpdate = ptNGPar->bForceUpdate || bCompChange;
	if (ptNGPar->bForceUpdate) {
		pDetail->iNCC = 0;
		for (int i = 0; i < NUMBEROFCOMPONENTS; i++) {
			if (ptNGPar->adMixture[i] > 0.0) {
				pDetail->aiCID[pDetail->iNCC] = i;
				pDetail->dXi[pDetail->iNCC] = ptNGPar->adMixture[i];
				pDetail->iNCC++;
			}
		}
		Detail_paramdl(pDetail);
		Detail_chardl(pDetail, ptNGPar);
	}
	if (fabs(ptNGPar->dPb - pDetail->dOldPb) > P_CHG_TOL ||
	    fabs(ptNGPar->dTb - pDetail->dOldTb) > T_CHG_TOL ||
	    ptNGPar->bForceUpdate) {
		pDetail->dP = ptNGPar->dPb * 1.0e-6;
		pDetail->dT = ptNGPar->dTb;
		Detail_temp(pDetail);
		Detail_ddetail(pDetail, ptNGPar);
		ptNGPar->dDb = pDetail->dRho;
		ptNGPar->dZb = Detail_zdetail(pDetail, pDetail->dRho);
		pDetail->dRhoTP = (pDetail->dP * ptNGPar->dMrx) / (ptNGPar->dZb * RGASKJ * pDetail->dT);
		Detail_relativedensity(pDetail, ptNGPar);
		ptNGPar->dRhob = pDetail->dRhoTP;
		pDetail->dOldTb = ptNGPar->dTb;
		pDetail->dOldPb = ptNGPar->dPb;
		ptNGPar->bForceUpdate = 1;
	}
	pDetail->dP = ptNGPar->dPf * 1.0e-6;
	pDetail->dT = ptNGPar->dTf;
	if ((fabs(ptNGPar->dTf - pDetail->dOldTf) > T_CHG_TOL) || (ptNGPar->bForceUpdate)) {
		Detail_temp(pDetail);
		ptNGPar->bForceUpdate = 1;
	}
	if ((fabs(ptNGPar->dPf - pDetail->dOldPf) > P_CHG_TOL) || (ptNGPar->bForceUpdate)) {
		Detail_ddetail(pDetail, ptNGPar);
		ptNGPar->dDf = pDetail->dRho;
		ptNGPar->dZf = Detail_zdetail(pDetail, pDetail->dRho);
		pDetail->dRhoTP = (pDetail->dP * ptNGPar->dMrx) / (ptNGPar->dZf * RGASKJ * pDetail->dT);
		ptNGPar->dRhof = pDetail->dRhoTP;
		pDetail->dOldTf = ptNGPar->dTf;
		pDetail->dOldPf = ptNGPar->dPf;
	}
	if ((ptNGPar->dZb > 0.0) && (ptNGPar->dZf > 0.0)) {
		ptNGPar->dFpv = sqrt(ptNGPar->dZb / ptNGPar->dZf);
	} else {
		ptNGPar->lStatus = GENERAL_CALCULATION_FAILURE;
		ptNGPar->bForceUpdate = 0;
	}
}

int Detail_table(Detail *pDetail) {
	if (!pDetail) {
		return -1;
	}
	double adAn[58];
	double adUn[58];
	adAn[0] = 0.153832600;
	adAn[1] = 1.341953000;
	adAn[2] = -2.998583000;
	adAn[3] = -0.048312280;
	adAn[4] = 0.375796500;
	adAn[5] = -1.589575000;
	adAn[6] = -0.053588470;
	adAn[7] = 0.886594630;
	adAn[8] = -0.710237040;
	adAn[9] = -1.471722000;
	adAn[10] = 1.321850350;
	adAn[11] = -0.786659250;
	adAn[12] = 2.29129E-09;
	adAn[13] = 0.157672400;
	adAn[14] = -0.436386400;
	adAn[15] = -0.044081590;
	adAn[16] = -0.003433888;
	adAn[17] = 0.032059050;
	adAn[18] = 0.024873550;
	adAn[19] = 0.073322790;
	adAn[20] = -0.001600573;
	adAn[21] = 0.642470600;
	adAn[22] = -0.416260100;
	adAn[23] = -0.066899570;
	adAn[24] = 0.279179500;
	adAn[25] = -0.696605100;
	adAn[26] = -0.002860589;
	adAn[27] = -0.008098836;
	adAn[28] = 3.150547000;
	adAn[29] = 0.007224479;
	adAn[30] = -0.705752900;
	adAn[31] = 0.534979200;
	adAn[32] = -0.079314910;
	adAn[33] = -1.418465000;
	adAn[34] = -5.99905E-17;
	adAn[35] = 0.105840200;
	adAn[36] = 0.034317290;
	adAn[37] = -0.007022847;
	adAn[38] = 0.024955870;
	adAn[39] = 0.042968180;
	adAn[40] = 0.746545300;
	adAn[41] = -0.291961300;
	adAn[42] = 7.294616000;
	adAn[43] = -9.936757000;
	adAn[44] = -0.005399808;
	adAn[45] = -0.243256700;
	adAn[46] = 0.049870160;
	adAn[47] = 0.003733797;
	adAn[48] = 1.874951000;
	adAn[49] = 0.002168144;
	adAn[50] = -0.658716400;
	adAn[51] = 0.000205518;
	adAn[52] = 0.009776195;
	adAn[53] = -0.020487080;
	adAn[54] = 0.015573220;
	adAn[55] = 0.006862415;
	adAn[56] = -0.001226752;
	adAn[57] = 0.002850908;

	adUn[0] = 0.0;
	adUn[1] = 0.5;
	adUn[2] = 1.0;
	adUn[3] = 3.5;
	adUn[4] = -0.5;
	adUn[5] = 4.5;
	adUn[6] = 0.5;
	adUn[7] = 7.5;
	adUn[8] = 9.5;
	adUn[9] = 6.0;
	adUn[10] = 12.0;
	adUn[11] = 12.5;
	adUn[12] = -6.0;
	adUn[13] = 2.0;
	adUn[14] = 3.0;
	adUn[15] = 2.0;
	adUn[16] = 2.0;
	adUn[17] = 11.0;
	adUn[18] = -0.5;
	adUn[19] = 0.5;
	adUn[20] = 0.0;
	adUn[21] = 4.0;
	adUn[22] = 6.0;
	adUn[23] = 21.0;
	adUn[24] = 23.0;
	adUn[25] = 22.0;
	adUn[26] = -1.0;
	adUn[27] = -0.5;
	adUn[28] = 7.0;
	adUn[29] = -1.0;
	adUn[30] = 6.0;
	adUn[31] = 4.0;
	adUn[32] = 1.0;
	adUn[33] = 9.0;
	adUn[34] = -13.0;
	adUn[35] = 21.0;
	adUn[36] = 8.0;
	adUn[37] = -0.5;
	adUn[38] = 0.0;
	adUn[39] = 2.0;
	adUn[40] = 7.0;
	adUn[41] = 9.0;
	adUn[42] = 22.0;
	adUn[43] = 23.0;
	adUn[44] = 1.0;
	adUn[45] = 9.0;
	adUn[46] = 3.0;
	adUn[47] = 8.0;
	adUn[48] = 23.0;
	adUn[49] = 1.5;
	adUn[50] = 5.0;
	adUn[51] = -0.5;
	adUn[52] = 4.0;
	adUn[53] = 7.0;
	adUn[54] = 3.0;
	adUn[55] = 0.0;
	adUn[56] = 1.0;
	adUn[57] = 0.0;
	memcpy(pDetail->adAn, adAn, sizeof(adAn));
	memcpy(pDetail->adUn, adUn, sizeof(adUn));
	for (int j = 0; j < NUMBEROFCOMPONENTS; j++) {
		for (int k = j; k < NUMBEROFCOMPONENTS; k++) {
			pDetail->adTable6Eij[j][k] = 1.0;
			pDetail->adTable6Uij[j][k] = 1.0;
			pDetail->adTable6Kij[j][k] = 1.0;
			pDetail->adTable6Gij[j][k] = 1.0;
		}
	}
	pDetail->adTable6Eij[0][1] = 0.971640;
	pDetail->adTable6Eij[0][2] = 0.960644;
	pDetail->adTable6Eij[0][4] = 0.994635;
	pDetail->adTable6Eij[0][5] = 0.708218;
	pDetail->adTable6Eij[0][6] = 0.931484;
	pDetail->adTable6Eij[0][7] = 1.170520;
	pDetail->adTable6Eij[0][8] = 0.990126;
	pDetail->adTable6Eij[0][10] = 1.019530;
	pDetail->adTable6Eij[0][11] = 0.989844;
	pDetail->adTable6Eij[0][12] = 1.002350;
	pDetail->adTable6Eij[0][13] = 0.999268;
	pDetail->adTable6Eij[0][14] = 1.107274;
	pDetail->adTable6Eij[0][15] = 0.880880;
	pDetail->adTable6Eij[0][16] = 0.880973;
	pDetail->adTable6Eij[0][17] = 0.881067;
	pDetail->adTable6Eij[0][18] = 0.881161;
	pDetail->adTable6Eij[1][2] = 1.022740;
	pDetail->adTable6Eij[1][3] = 0.970120;
	pDetail->adTable6Eij[1][4] = 0.945939;
	pDetail->adTable6Eij[1][5] = 0.746954;
	pDetail->adTable6Eij[1][6] = 0.902271;
	pDetail->adTable6Eij[1][7] = 1.086320;
	pDetail->adTable6Eij[1][8] = 1.005710;
	pDetail->adTable6Eij[1][9] = 1.021000;
	pDetail->adTable6Eij[1][10] = 0.946914;
	pDetail->adTable6Eij[1][11] = 0.973384;
	pDetail->adTable6Eij[1][12] = 0.959340;
	pDetail->adTable6Eij[1][13] = 0.945520;
	pDetail->adTable6Eij[2][3] = 0.925053;
	pDetail->adTable6Eij[2][4] = 0.960237;
	pDetail->adTable6Eij[2][5] = 0.849408;
	pDetail->adTable6Eij[2][6] = 0.955052;
	pDetail->adTable6Eij[2][7] = 1.281790;
	pDetail->adTable6Eij[2][8] = 1.500000;
	pDetail->adTable6Eij[2][10] = 0.906849;
	pDetail->adTable6Eij[2][11] = 0.897362;
	pDetail->adTable6Eij[2][12] = 0.726255;
	pDetail->adTable6Eij[2][13] = 0.859764;
	pDetail->adTable6Eij[2][14] = 0.855134;
	pDetail->adTable6Eij[2][15] = 0.831229;
	pDetail->adTable6Eij[2][16] = 0.808310;
	pDetail->adTable6Eij[2][17] = 0.786323;
	pDetail->adTable6Eij[2][18] = 0.765171;
	pDetail->adTable6Eij[3][4] = 1.022560;
	pDetail->adTable6Eij[3][5] = 0.693168;
	pDetail->adTable6Eij[3][6] = 0.946871;
	pDetail->adTable6Eij[3][7] = 1.164460;
	pDetail->adTable6Eij[3][11] = 1.013060;
	pDetail->adTable6Eij[3][13] = 1.005320;
	pDetail->adTable6Eij[4][7] = 1.034787;
	pDetail->adTable6Eij[4][11] = 1.004900;
	pDetail->adTable6Eij[6][14] = 1.008692;
	pDetail->adTable6Eij[6][15] = 1.010126;
	pDetail->adTable6Eij[6][16] = 1.011501;
	pDetail->adTable6Eij[6][17] = 1.012821;
	pDetail->adTable6Eij[6][18] = 1.014089;
	pDetail->adTable6Eij[7][8] = 1.100000;
	pDetail->adTable6Eij[7][10] = 1.300000;
	pDetail->adTable6Eij[7][11] = 1.300000;
	pDetail->adTable6Uij[0][1] = 0.886106;
	pDetail->adTable6Uij[0][2] = 0.963827;
	pDetail->adTable6Uij[0][4] = 0.990877;
	pDetail->adTable6Uij[0][6] = 0.736833;
	pDetail->adTable6Uij[0][7] = 1.156390;
	pDetail->adTable6Uij[0][11] = 0.992291;
	pDetail->adTable6Uij[0][13] = 1.003670;
	pDetail->adTable6Uij[0][14] = 1.302576;
	pDetail->adTable6Uij[0][15] = 1.191904;
	pDetail->adTable6Uij[0][16] = 1.205769;
	pDetail->adTable6Uij[0][17] = 1.219634;
	pDetail->adTable6Uij[0][18] = 1.233498;
	pDetail->adTable6Uij[1][2] = 0.835058;
	pDetail->adTable6Uij[1][3] = 0.816431;
	pDetail->adTable6Uij[1][4] = 0.915502;
	pDetail->adTable6Uij[1][6] = 0.993476;
	pDetail->adTable6Uij[1][7] = 0.408838;
	pDetail->adTable6Uij[1][11] = 0.993556;
	pDetail->adTable6Uij[2][3] = 0.969870;
	pDetail->adTable6Uij[2][6] = 1.045290;
	pDetail->adTable6Uij[2][8] = 0.900000;
	pDetail->adTable6Uij[2][14] = 1.066638;
	pDetail->adTable6Uij[2][15] = 1.077634;
	pDetail->adTable6Uij[2][16] = 1.088178;
	pDetail->adTable6Uij[2][17] = 1.098291;
	pDetail->adTable6Uij[2][18] = 1.108021;
	pDetail->adTable6Uij[3][4] = 1.065173;
	pDetail->adTable6Uij[3][6] = 0.971926;
	pDetail->adTable6Uij[3][7] = 1.616660;
	pDetail->adTable6Uij[3][10] = 1.250000;
	pDetail->adTable6Uij[3][11] = 1.250000;
	pDetail->adTable6Uij[3][12] = 1.250000;
	pDetail->adTable6Uij[3][13] = 1.250000;
	pDetail->adTable6Uij[6][14] = 1.028973;
	pDetail->adTable6Uij[6][15] = 1.033754;
	pDetail->adTable6Uij[6][16] = 1.038338;
	pDetail->adTable6Uij[6][17] = 1.042735;
	pDetail->adTable6Uij[6][18] = 1.046966;
	pDetail->adTable6Kij[0][1] = 1.003630;
	pDetail->adTable6Kij[0][2] = 0.995933;
	pDetail->adTable6Kij[0][4] = 1.007619;
	pDetail->adTable6Kij[0][6] = 1.000080;
	pDetail->adTable6Kij[0][7] = 1.023260;
	pDetail->adTable6Kij[0][11] = 0.997596;
	pDetail->adTable6Kij[0][13] = 1.002529;
	pDetail->adTable6Kij[0][14] = 0.982962;
	pDetail->adTable6Kij[0][15] = 0.983565;
	pDetail->adTable6Kij[0][16] = 0.982707;
	pDetail->adTable6Kij[0][17] = 0.981849;
	pDetail->adTable6Kij[0][18] = 0.980991;
	pDetail->adTable6Kij[1][2] = 0.982361;
	pDetail->adTable6Kij[1][3] = 1.007960;
	pDetail->adTable6Kij[1][6] = 0.942596;
	pDetail->adTable6Kij[1][7] = 1.032270;
	pDetail->adTable6Kij[2][3] = 1.008510;
	pDetail->adTable6Kij[2][6] = 1.007790;
	pDetail->adTable6Kij[2][14] = 0.910183;
	pDetail->adTable6Kij[2][15] = 0.895362;
	pDetail->adTable6Kij[2][16] = 0.881152;
	pDetail->adTable6Kij[2][17] = 0.867520;
	pDetail->adTable6Kij[2][18] = 0.854406;
	pDetail->adTable6Kij[3][4] = 0.986893;
	pDetail->adTable6Kij[3][6] = 0.999969;
	pDetail->adTable6Kij[3][7] = 1.020340;
	pDetail->adTable6Kij[6][14] = 0.968130;
	pDetail->adTable6Kij[6][15] = 0.962870;
	pDetail->adTable6Kij[6][16] = 0.957828;
	pDetail->adTable6Kij[6][17] = 0.952441;
	pDetail->adTable6Kij[6][18] = 0.948338;
	pDetail->adTable6Gij[0][2] = 0.807653;
	pDetail->adTable6Gij[0][7] = 1.957310;
	pDetail->adTable6Gij[1][2] = 0.982746;
	pDetail->adTable6Gij[2][3] = 0.370296;
	pDetail->adTable6Gij[2][5] = 1.673090;



	return 0;
}

void Detail_paramdl(Detail *pDetail) {
	for (int j = 0; j < NUMBEROFCOMPONENTS; j++) {
		pDetail->adTable5Qi[j] = 0.0;
		pDetail->adTable5Fi[j] = 0.0;
		pDetail->adTable5Si[j] = 0.0;
		pDetail->adTable5Wi[j] = 0.0;
	}
	pDetail->adTable5Qi[2] = 0.690000;
	pDetail->adTable5Qi[5] = 1.067750;
	pDetail->adTable5Qi[6] = 0.633276;
	pDetail->adTable5Fi[7] = 1.0000;
	pDetail->adTable5Si[5] = 1.5822;
	pDetail->adTable5Si[6] = 0.3900;
	pDetail->adTable5Wi[5] = 1.0000;
	for (int j = pDetail->iNCC - 1; j >= 0; j--) {
		const double adTable5Ki[21] = {
			0.4619255, 0.4479153, 0.4557489, 0.5279209, 0.5837490, 0.3825868, 0.4618263, 0.3514916, 0.4533894, 0.4186954,
			0.6406937, 0.6341423, 0.6738577, 0.6798307, 0.7175118, 0.7525189, 0.7849550, 0.8152731, 0.8437826, 0.3589888,
			0.4216551
		};
		const double adTable5Mri[21] = {
			16.0430, 28.0135, 44.0100, 30.0700, 44.0970, 18.0153, 34.0820, 2.0159, 28.0100, 31.9988, 58.1230, 58.1230,
			72.1500, 72.1500, 86.1770, 100.2040, 114.2310, 128.2580, 142.2850, 4.0026, 39.9480
		};
		pDetail->dMri[j] = adTable5Mri[pDetail->aiCID[j]];
		pDetail->dKi[j] = adTable5Ki[pDetail->aiCID[j]];
	}
	for (int j = 0; j < pDetail->iNCC; j++) {
		const double adTable5Gi[21] = {
			0.000000, 0.027815, 0.189065, 0.079300, 0.141239, 0.332500, 0.088500, 0.034369, 0.038953, 0.021000, 0.256692,
			0.281835, 0.332267, 0.366911, 0.289731, 0.337542, 0.383381, 0.427354, 0.469659, 0.000000, 0.000000
		};
		const double adTable5Ei[21] = {
			151.318300, 99.737780, 241.960600, 244.166700, 298.118300, 514.015600, 296.355000, 26.957940, 105.534800,
			122.766700, 324.068900, 337.638900, 365.599900, 370.682300, 402.636293, 427.722630, 450.325022, 470.840891,
			489.558373, 2.610111, 119.629900
		};
		pDetail->dGi[j] = adTable5Gi[pDetail->aiCID[j]];
		pDetail->dEi[j] = adTable5Ei[pDetail->aiCID[j]];
	}
	for (int j = 0; j < pDetail->iNCC; j++) {
		pDetail->dQi[j] = pDetail->adTable5Qi[pDetail->aiCID[j]];
		pDetail->dFi[j] = 0.0;
		if (pDetail->aiCID[j] == 7) pDetail->dFi[j] = pDetail->adTable5Fi[7];
		pDetail->dSi[j] = pDetail->adTable5Si[pDetail->aiCID[j]];
		pDetail->dWi[j] = pDetail->adTable5Wi[pDetail->aiCID[j]];
	}
	for (int j = 0; j < pDetail->iNCC; j++) {
		for (int k = j; k < pDetail->iNCC; k++) {
			pDetail->dUij[j][k] = pDetail->adTable6Uij[pDetail->aiCID[j]][pDetail->aiCID[k]];
			pDetail->dKij[j][k] = pDetail->adTable6Kij[pDetail->aiCID[j]][pDetail->aiCID[k]];
			pDetail->dEij[j][k] = pDetail->adTable6Eij[pDetail->aiCID[j]][pDetail->aiCID[k]];
			pDetail->dGij[j][k] = pDetail->adTable6Gij[pDetail->aiCID[j]][pDetail->aiCID[k]];
		}
	}
}

void Detail_dhvMol(Detail *pDetail, NGParSTRUCT *ptNGPar) {
	const double adTableHhvMol[4][NUMBEROFCOMPONENTS] = {
		{  //0
			892.97, 0, 0, 1564.34, 2224.01, 45.074, 562.94, 286.63, 282.8, 0, 2874.2, 2883.82, 3535.98, 3542.89,
			4203.23, 4862.87, 5522.4, 6182.91, 6842.69, 0, 0
		},
		{   //15
			891.56, 0, 0, 1562.14, 2221.1, 44.43, 562.38, 286.15, 282.91, 0, 2870.58, 2879.76, 3531.68, 3538.6,
			4198.24, 4857.18, 5516.01, 6175.82, 6834.9, 0, 0
		},
		{  //20
			891.09, 0, 0, 1561.41, 2220.13, 44.22, 562.19, 285.99, 282.95, 0, 2869.38, 2878.57, 3530.24, 3537.17,
			4196.58, 4855.29, 5513.88, 6173.46, 6832.31, 0, 0
		},
		{  //25
			890.63, 0, 0, 1560.69, 2219.17, 44.016, 562.01, 285.83, 282.98, 0, 2868.2, 2877.4, 3528.83, 3535.77,
			4194.95, 4853.43, 5511.8, 6171.15, 6829.77, 0, 0
		}
	};

	const double adTableLhvMol[4][NUMBEROFCOMPONENTS] = {
		{  //0
			802.82, 0, 0, 1429.12, 2043.71, 0, 517.87, 241.56, 282.8, 0, 2648.83, 2658.45, 3265.54, 3272.45, 3887.71,
			4502.28, 5116.73, 5732.17, 6346.88, 0, 0
		},
		{  //15
			802.69, 0, 0, 1428.84, 2043.37, 0, 517.95, 241.72, 282.91, 0, 2648.42, 2657.6, 3265.08, 3272, 3887.21,
			4501.72, 5116.11, 5731.49, 6346.14, 0, 0
		},
		{ //20
			802.65, 0, 0, 1428.74, 2043.23, 0, 517.97, 241.76, 282.95, 0, 2648.26, 2657.45, 3264.89, 3271.83, 3887.01,
			4501.49, 5115.87, 5731.22, 6345.85, 0, 0
		},
		{  //25
			802.6, 0, 0, 1428.64, 2043.11, 0, 517.99, 241.81, 282.98, 0, 2648.12, 2657.32, 3264.73, 3271.67, 3886.84,
			4501.3, 5115.66, 5730.99, 6345.59, 0, 0
		}
	};
	for (int i = 0; i <NUMBEROFCOMPONENTS; i++) {
		switch (ptNGPar->dCbtj)
		{
			case 0:
				ptNGPar->dHhvMol += adTableHhvMol[0][i] * ptNGPar->adMixture[i];
				ptNGPar->dLhvMol +=adTableLhvMol[0][i] * ptNGPar->adMixture[i];
				break;
			case 1:
				ptNGPar->dHhvMol += adTableHhvMol[1][i] * ptNGPar->adMixture[i];
				ptNGPar->dLhvMol += adTableLhvMol[1][i] * ptNGPar->adMixture[i];
				break;
			case 2:
				ptNGPar->dHhvMol += adTableHhvMol[2][i] * ptNGPar->adMixture[i];
				ptNGPar->dLhvMol += adTableLhvMol[2][i] * ptNGPar->adMixture[i];
				break;
			default: ;
		}
	}
}

void Detail_chardl(Detail *pDetail, NGParSTRUCT *ptNGPar)
{
	double tmfrac = 0.0;

	for (int j = 0; j < pDetail->iNCC; j++) {
		tmfrac += pDetail->dXi[j];
	}
	for (int j = 0; j < pDetail->iNCC; j++) {
		pDetail->dXi[j] /= tmfrac;
	}
	for (int j = 0; j < 18; j++) {
		pDetail->adBcoef[j] = 0.0;
	}
	double k5p0 = 0.0, k2p5 = 0.0, u5p0 = 0.0, u2p5 = 0.0;
	pDetail->dW = 0.0;
	double q1p0 = 0.0;
	pDetail->dF = 0.0;
	ptNGPar->dMrx = 0.0;
	ptNGPar->dHhvMol = 0.0;
	ptNGPar->dLhvMol = 0.0;
	for (int i = 0; i < pDetail->iNCC; i++) {
		ptNGPar->dMrx += pDetail->dXi[i] * pDetail->dMri[i];

		k2p5 += pDetail->dXi[i] * pow(pDetail->dKi[i], 2.5);
		u2p5 += pDetail->dXi[i] * pow(pDetail->dEi[i], 2.5);
		pDetail->dW += pDetail->dXi[i] * pDetail->dGi[i];
		q1p0 += pDetail->dXi[i] * pDetail->dQi[i];
		pDetail->dF += pDetail->dXi[i] * pDetail->dXi[i] * pDetail->dFi[i];

		for (int j = i; j < pDetail->iNCC; j++) {
			const double Xij = (i == j) ? pDetail->dXi[i] * pDetail->dXi[j] : 2.0 * pDetail->dXi[i] * pDetail->dXi[j];
			if (pDetail->dKij[i][j] != 1.0) {
				const double term = pow(pDetail->dKi[i] * pDetail->dKi[j], 2.5);
				k5p0 += Xij * (pow(pDetail->dKij[i][j], 5.0) - 1.0) * term;
			}
			if (pDetail->dUij[i][j] != 1.0) {
				const double term = pow(pDetail->dEi[i] * pDetail->dEi[j], 2.5);
				u5p0 += Xij * (pow(pDetail->dUij[i][j], 5.0) - 1.0) * term;
			}
			if (pDetail->dGij[i][j] != 1.0) {
				const double avgG = (pDetail->dGi[i] + pDetail->dGi[j]) / 2.0;
				pDetail->dW += Xij * (pDetail->dGij[i][j] - 1.0) * avgG;
			}
			const double Eij = pDetail->dEij[i][j] * sqrt(pDetail->dEi[i] * pDetail->dEi[j]);
			const double Gij = pDetail->dGij[i][j] * (pDetail->dGi[i] + pDetail->dGi[j]) / 2.0;
			const double e0p5 = sqrt(Eij);
			const double e2p0 = Eij * Eij;
			const double e3p0 = Eij * e2p0;
			const double e3p5 = e3p0 * e0p5;
			const double e4p5 = Eij * e3p5;
			const double e6p0 = e3p0 * e3p0;
			const double e7p5 = e4p5 * Eij * e2p0;
			const double e9p5 = e7p5 * e2p0;
			const double e11p0 = e4p5 * e4p5 * e2p0;
			const double e12p0 = e11p0 * Eij;
			const double e12p5 = e12p0 * e0p5;
			const double s3 = Xij * pow(pow(pDetail->dKi[i], 3.0) * pow(pDetail->dKi[j], 3.0), 0.5);
			pDetail->adBcoef[0] += s3;
			pDetail->adBcoef[1] += s3 * e0p5;
			pDetail->adBcoef[2] += s3 * Eij;
			pDetail->adBcoef[3] += s3 * e3p5;
			pDetail->adBcoef[4] += s3 * Gij / e0p5;
			pDetail->adBcoef[5] += s3 * Gij * e4p5;
			pDetail->adBcoef[6] += s3 * pDetail->dQi[i] * pDetail->dQi[j] * e0p5;
			pDetail->adBcoef[7] += s3 * pDetail->dSi[i] * pDetail->dSi[j] * e7p5;
			pDetail->adBcoef[8] += s3 * pDetail->dSi[i] * pDetail->dSi[j] * e9p5;
			pDetail->adBcoef[9] += s3 * pDetail->dWi[i] * pDetail->dWi[j] * e6p0;
			pDetail->adBcoef[10] += s3 * pDetail->dWi[i] * pDetail->dWi[j] * e12p0;
			pDetail->adBcoef[11] += s3 * pDetail->dWi[i] * pDetail->dWi[j] * e12p5;
			pDetail->adBcoef[12] += s3 * pDetail->dFi[i] * pDetail->dFi[j] / e6p0;
			pDetail->adBcoef[13] += s3 * e2p0;
			pDetail->adBcoef[14] += s3 * e3p0;
			pDetail->adBcoef[15] += s3 * pDetail->dQi[i] * pDetail->dQi[j] * e2p0;
			pDetail->adBcoef[16] += s3 * e2p0;
			pDetail->adBcoef[17] += s3 * e11p0;
		}
	}


	for (int i = 0; i < 18; i++) {
		pDetail->adBcoef[i] *= pDetail->adAn[i];
	}
	pDetail->dKp3 = pow(k5p0 + pow(k2p5, 2.0), 0.6);
	pDetail->dU = pow(u5p0 + pow(u2p5, 2.0), 0.2);
	pDetail->dQp2 = q1p0 * q1p0;
}

void Detail_bvir(Detail *pDetail) {
	pDetail->dB = pDetail->ddBdT = pDetail->dd2BdT2 = 0.0;
	const double t = pDetail->dT;
	const double t0p5 = sqrt(t);
	const double t2p0 = t * t;
	const double t3p0 = t * t2p0;
	const double t3p5 = t3p0 * t0p5;
	const double t4p5 = t * t3p5;
	const double t6p0 = t3p0 * t3p0;
	const double t11p0 = t4p5 * t4p5 * t2p0;
	const double t7p5 = t6p0 * t * t0p5;
	const double t9p5 = t7p5 * t2p0;
	const double t12p0 = t9p5 * t0p5 * t2p0;
	const double t12p5 = t12p0 * t0p5;
	// double t1p5 = t * t0p5;
	// double t4p0 = t2p0 * t2p0;
	double Bx[18];
	Bx[0] =  pDetail->adBcoef[0];
	Bx[1] =  pDetail->adBcoef[1] / t0p5;
	Bx[2] =  pDetail->adBcoef[2] / t;
	Bx[3] =  pDetail->adBcoef[3] / t3p5;
	Bx[4] =  pDetail->adBcoef[4] * t0p5;
	Bx[5] =  pDetail->adBcoef[5] / t4p5;
	Bx[6] =  pDetail->adBcoef[6] / t0p5;
	Bx[7] =  pDetail->adBcoef[7] / t7p5;
	Bx[8] =  pDetail->adBcoef[8] / t9p5;
	Bx[9] =  pDetail->adBcoef[9] / t6p0;
	Bx[10] = pDetail-> adBcoef[10] / t12p0;
	Bx[11] = pDetail-> adBcoef[11] / t12p5;
	Bx[12] = pDetail-> adBcoef[12] * t6p0;
	Bx[13] = pDetail-> adBcoef[13] / t2p0;
	Bx[14] = pDetail-> adBcoef[14] / t3p0;
	Bx[15] = pDetail-> adBcoef[15] / t2p0;
	Bx[16] = pDetail-> adBcoef[16] / t2p0;
	Bx[17] = pDetail-> adBcoef[17] / t11p0;
	for (int i = 0; i < 18; i++) {
		pDetail->dB += Bx[i];
	}
	for (int i = 0; i < 18; i++) {
		if (pDetail->adUn[i] != 0.0) {
			Bx[i] *= pDetail->adUn[i] ;
		}
	}
	for (int i = 0; i < 18; i++) {
		if (pDetail->adUn[i] != 0.0) {
			pDetail->ddBdT += Bx[i]/t;
		}
	}
	pDetail->ddBdT = -pDetail->ddBdT;
	for (int i = 0; i < 18; i++) {
		if (pDetail->adUn[i] != 0.0 && pDetail->adUn[i] != -1.0) {
			Bx[i] *= (pDetail->adUn[i] + 1.0) ;
		}
	}
	for (int i = 0; i < 18; i++) {
		if (pDetail->adUn[i] != 0.0 && pDetail->adUn[i] != -1.0) {
			pDetail->dd2BdT2 += Bx[i]/ t2p0;
		}
	}
}

void Detail_temp(Detail *pDetail) {
	Detail_bvir(pDetail);
	const double tr = pDetail->dT / pDetail->dU;
	const double tr0p5 = sqrt(tr);
        const double tr1p5 = tr * tr0p5;
        const double tr2p0 = tr * tr;
        const double tr3p0 = tr * tr2p0;
        const double tr4p0 = tr * tr3p0;
        const double tr5p0 = tr * tr4p0;
        const double tr6p0 = tr * tr5p0;
        const double tr7p0 = tr * tr6p0;
        const double tr8p0 = tr * tr7p0;
        const double tr9p0 = tr * tr8p0;
        const double tr11p0 = tr6p0 * tr5p0;
        const double tr13p0 = tr6p0 * tr7p0;
        const double tr21p0 = tr9p0 * tr9p0 * tr3p0;
        const double tr22p0 = tr * tr21p0;
        const double tr23p0 = tr * tr22p0;

        pDetail->adFn[12] = pDetail->adAn[12] * pDetail->dF * tr6p0;
        pDetail->adFn[13] = pDetail->adAn[13] / tr2p0;
        pDetail->adFn[14] = pDetail->adAn[14] / tr3p0;
        pDetail->adFn[15] = pDetail->adAn[15] * pDetail->dQp2 / tr2p0;
        pDetail->adFn[16] = pDetail->adAn[16] / tr2p0;
        pDetail->adFn[17] = pDetail->adAn[17] / tr11p0;
        pDetail->adFn[18] = pDetail->adAn[18] * tr0p5;
        pDetail->adFn[19] = pDetail->adAn[19] / tr0p5;
        pDetail->adFn[20] = pDetail->adAn[20];

        pDetail->adFn[21] = pDetail->adAn[21] / tr4p0;
        pDetail->adFn[22] = pDetail->adAn[22] / tr6p0;
        pDetail->adFn[23] = pDetail->adAn[23] / tr21p0;
        pDetail->adFn[24] = pDetail->adAn[24] * pDetail->dW / tr23p0;
        pDetail->adFn[25] = pDetail->adAn[25] * pDetail->dQp2 / tr22p0;
        pDetail->adFn[26] = pDetail->adAn[26] * pDetail->dF * tr;
        pDetail->adFn[27] = pDetail->adAn[27] * pDetail->dQp2 * tr0p5;
        pDetail->adFn[28] = pDetail->adAn[28] * pDetail->dW / tr7p0;
        pDetail->adFn[29] = pDetail->adAn[29] * pDetail->dF * tr;
        pDetail->adFn[30] = pDetail->adAn[30] / tr6p0;
        pDetail->adFn[31] = pDetail->adAn[31] * pDetail->dW / tr4p0;
        pDetail->adFn[32] = pDetail->adAn[32] * pDetail->dW / tr;
        pDetail->adFn[33] = pDetail->adAn[33] * pDetail->dW / tr9p0;
        pDetail->adFn[34] = pDetail->adAn[34] * pDetail->dF * tr13p0;
        pDetail->adFn[35] = pDetail->adAn[35] / tr21p0;
        pDetail->adFn[36] = pDetail->adAn[36] * pDetail->dQp2 / tr8p0;
        pDetail->adFn[37] = pDetail->adAn[37] * tr0p5;
        pDetail->adFn[38] = pDetail->adAn[38];
        pDetail->adFn[39] = pDetail->adAn[39] / tr2p0;
        pDetail->adFn[40] = pDetail->adAn[40] / tr7p0;
        pDetail->adFn[41] = pDetail->adAn[41] * pDetail->dQp2 / tr9p0;
        pDetail->adFn[42] = pDetail->adAn[42] / tr22p0;
        pDetail->adFn[43] = pDetail->adAn[43] / tr23p0;
        pDetail->adFn[44] = pDetail->adAn[44] / tr;
        pDetail->adFn[45] = pDetail->adAn[45] / tr9p0;
        pDetail->adFn[46] = pDetail->adAn[46] * pDetail->dQp2 / tr3p0;
        pDetail->adFn[47] = pDetail->adAn[47] / tr8p0;
        pDetail->adFn[48] = pDetail->adAn[48] * pDetail->dQp2 / tr23p0;
        pDetail->adFn[49] = pDetail->adAn[49] / tr1p5;
        pDetail->adFn[50] = pDetail->adAn[50] * pDetail->dW / tr5p0;
        pDetail->adFn[51] = pDetail->adAn[51] * pDetail->dQp2 * tr0p5;
        pDetail->adFn[52] = pDetail->adAn[52] / tr4p0;
        pDetail->adFn[53] = pDetail->adAn[53] * pDetail->dW / tr7p0;
        pDetail->adFn[54] = pDetail->adAn[54] / tr3p0;
        pDetail->adFn[55] = pDetail->adAn[55] * pDetail->dW;
        pDetail->adFn[56] = pDetail->adAn[56] / tr;
        pDetail->adFn[57] = pDetail->adAn[57] * pDetail->dQp2;
}

void Detail_ddetail(Detail *pDetail, NGParSTRUCT *ptNGPar) {
	double xnumer, xdenom;
	const int imax = 150;
	pDetail->dRho = 0.0;
	Detail_braket(pDetail, ptNGPar);
	if (ptNGPar->lStatus == MAX_NUM_OF_ITERATIONS_EXCEEDED ||
	    ptNGPar->lStatus == NEGATIVE_DENSITY_DERIVATIVE) {
		return;
	}
	double x1 = pDetail->dRhoL;
	double x2 = pDetail->dRhoH;
	double y1 = pDetail->dPRhoL - pDetail->dP;
	double y2 = pDetail->dPRhoH - pDetail->dP;
	double delx = x1 - x2;
	double delprv = delx;
	double x3 = x1;
	double y3 = y1;
	for (int i = 0; i < imax; i++) {
		const double epsmin = 1.e-7;
		const double epsr = 1.e-6;
		const double epsp = 1.e-6;
		if (y2 * y3 > 0.0) {
			x3 = x1;
			y3 = y1;
			delx = x1 - x2;
			delprv = delx;
		}
		if (fabs(y3) < fabs(y2)) {
			x1 = x2;
			x2 = x3;
			x3 = x1;
			y1 = y2;
			y2 = y3;
			y3 = y1;
		}
		const double delmin = epsmin * fabs(x2);
		const double delbis = 0.5 * (x3 - x2);
		if (fabs(delprv) < delmin || fabs(y1) < fabs(y2)) {
			delx = delbis;
			delprv = delbis;
		} else {
			if (x3 != x1) {
				const double y2my3 = y2 - y3;
				const double y3my1 = y3 - y1;
				const double y1my2 = y1 - y2;
				xdenom = -(y1my2) * (y2my3) * (y3my1);
				xnumer = x1 * y2 * y3 * (y2my3)
				         + x2 * y3 * y1 * (y3my1)
				         + x3 * y1 * y2 * (y1my2) - x2 * xdenom;
			} else {
				xnumer = (x2 - x1) * y2;
				xdenom = y1 - y2;
			}
			if (2.0 * fabs(xnumer) < fabs(delprv * xdenom)) {
				delprv = delx;
				delx = xnumer / xdenom;
			} else {
				delx = delbis;
				delprv = delbis;
			}
		}
		if ((fabs(y2) < epsp * pDetail->dP) && (fabs(delx) < epsr * fabs(x2))) {
			pDetail->dRho = x2 + delx;
			return;
		}
		if (fabs(delx) < delmin) {
			const double sgndel = delbis / fabs(delbis);
			delx = 1.0000009 * sgndel * delmin;
			delprv = delx;
		}
		const double boundn = delx * (x2 + delx - x3);
		if (boundn > 0.0) {
			delx = delbis;
			delprv = delbis;
		}
		x1 = x2;
		y1 = y2;
		x2 = x2 + delx;
		Detail_pdetail(pDetail, x2);
		y2 = pDetail->dPCalc - pDetail->dP;
	}
	ptNGPar->lStatus = MAX_NUM_OF_ITERATIONS_EXCEEDED;
	pDetail->dRho = x2;
}

void Detail_braket(Detail *pDetail, NGParSTRUCT *ptNGPar) {
	double rho2;
	const int imax = 200;
	double rho1 = 0.0;
	double p1 = 0.0;
	double rhomax = 1.0 / pDetail->dKp3;
	if (pDetail->dT > 1.2593 * pDetail->dU)
		rhomax = 20.0 * rhomax;
	const double videal = RGASKJ * pDetail->dT / pDetail->dP;
	if (fabs(pDetail->dB) < (0.167 * videal)) {
		rho2 = 0.95 / (videal + pDetail->dB);
	} else {
		rho2 = 1.15 / videal;
	}
	double del = rho2 / 20.0;
	for (int it = 0; it < imax; it++) {
		if (rho2 > rhomax && ptNGPar->lStatus != MAX_DENSITY_IN_BRAKET_EXCEEDED) {
			ptNGPar->lStatus = MAX_DENSITY_IN_BRAKET_EXCEEDED;
			del = 0.01 * (rhomax - rho1) + (pDetail->dP / (RGASKJ * pDetail->dT)) / 20.0;
			rho2 = rho1 + del;
			continue;
		}
		Detail_pdetail(pDetail, rho2);
		const double p2 = pDetail->dPCalc;
		if (p2 > pDetail->dP) {
			pDetail->dRhoL = rho1;
			pDetail->dPRhoL = p1;
			pDetail->dRhoH = rho2;
			pDetail->dPRhoH = p2;
			ptNGPar->lStatus = NORMAL;
			return;
		} else if (p2 > p1) {
			if (ptNGPar->lStatus == MAX_DENSITY_IN_BRAKET_EXCEEDED)
				del *= 2.0;
			rho1 = rho2;
			p1 = p2;
			rho2 = rho1 + del;
			continue;
		} else {
			ptNGPar->lStatus = NEGATIVE_DENSITY_DERIVATIVE;
			pDetail->dRho = rho1;
			return;
		}
	}
	ptNGPar->lStatus = MAX_NUM_OF_ITERATIONS_EXCEEDED;
	pDetail->dRho = rho2;
}

void Detail_pdetail(Detail *pDetail, double dD) {
	pDetail->dPCalc = Detail_zdetail(pDetail, dD) * dD * RGASKJ * pDetail->dT;
}

double Detail_zdetail(Detail *pDetail, double d) {
	const double D1 = pDetail->dKp3 * d;
	const double D2 = D1 * D1;
	const double D3 = D2 * D1;
	const double D4 = D3 * D1;
	const double D5 = D4 * D1;
	const double D6 = D5 * D1;
	const double D7 = D6 * D1;
	const double D8 = D7 * D1;
	const double D9 = D8 * D1;
	const double exp1 = exp(-D1);
	const double exp2 = exp(-D2);
	const double exp3 = exp(-D3);
	const double exp4 = exp(-D4);
	pDetail->dZ = 1.0 + pDetail->dB * d
	              + pDetail->adFn[12] * D1 * (exp3 - 1.0 - 3.0 * D3 * exp3)
	              + (pDetail->adFn[13] + pDetail->adFn[14] + pDetail->adFn[15]) * D1 * (exp2 - 1.0 - 2.0 * D2 * exp2)
	              + (pDetail->adFn[16] + pDetail->adFn[17]) * D1 * (exp4 - 1.0 - 4.0 * D4 * exp4)
	              + (pDetail->adFn[18] + pDetail->adFn[19]) * D2 * 2.0
	              + (pDetail->adFn[20] + pDetail->adFn[21] + pDetail->adFn[22]) * D2 * (2.0 - 2.0 * D2) * exp2
	              + (pDetail->adFn[23] + pDetail->adFn[24] + pDetail->adFn[25]) * D2 * (2.0 - 4.0 * D4) * exp4
	              + pDetail->adFn[26] * D2 * (2.0 - 4.0 * D4) * exp4
	              + pDetail->adFn[27] * D3 * 3.0
	              + (pDetail->adFn[28] + pDetail->adFn[29]) * D3 * (3.0 - D1) * exp1
	              + (pDetail->adFn[30] + pDetail->adFn[31]) * D3 * (3.0 - 2.0 * D2) * exp2
	              + (pDetail->adFn[32] + pDetail->adFn[33]) * D3 * (3.0 - 3.0 * D3) * exp3
	              + (pDetail->adFn[34] + pDetail->adFn[35] + pDetail->adFn[36]) * D3 * (3.0 - 4.0 * D4) * exp4
	              + (pDetail->adFn[37] + pDetail->adFn[38]) * D4 * 4.0
	              + (pDetail->adFn[39] + pDetail->adFn[40] + pDetail->adFn[41]) * D4 * (4.0 - 2.0 * D2) * exp2
	              + (pDetail->adFn[42] + pDetail->adFn[43]) * D4 * (4.0 - 4.0 * D4) * exp4
	              + pDetail->adFn[44] * D5 * 5.0
	              + (pDetail->adFn[45] + pDetail->adFn[46]) * D5 * (5.0 - 2.0 * D2) * exp2
	              + (pDetail->adFn[47] + pDetail->adFn[48]) * D5 * (5.0 - 4.0 * D4) * exp4
	              + pDetail->adFn[49] * D6 * 6.0
	              + pDetail->adFn[50] * D6 * (6.0 - 2.0 * D2) * exp2
	              + pDetail->adFn[51] * D7 * 7.0
	              + pDetail->adFn[52] * D7 * (7.0 - 2.0 * D2) * exp2
	              + pDetail->adFn[53] * D8 * (8.0 - D1) * exp1
	              + (pDetail->adFn[54] + pDetail->adFn[55]) * D8 * (8.0 - 2.0 * D2) * exp2
	              + (pDetail->adFn[56] + pDetail->adFn[57]) * D9 * (9.0 - 2.0 * D2) * exp2;
	return pDetail->dZ;
}

double Detail_dZdT(Detail *pDetail, double d) {
	const double D1 = pDetail->dKp3 * d;
	const double D2 = D1 * D1;
	const double D3 = D2 * D1;
	const double D4 = D3 * D1;
	const double D5 = D4 * D1;
	const double D6 = D5 * D1;
	const double D7 = D6 * D1;
	const double D8 = D7 * D1;
	const double exp1 = exp(-D1);
	const double exp2 = exp(-D2);
	const double exp3 = exp(-D3);
	const double exp4 = exp(-D4);
	for (int i = 12; i < 58; i++) {
		if (pDetail->adUn[i] && pDetail->adFn[i]) {
			pDetail->fx[i] = (pDetail->adFn[i] * pDetail->adUn[i] * D1) / pDetail->dT;
		} else {
			pDetail->fx[i] = 0.0;
		}
	}
	pDetail->ddZdT = d * pDetail->ddBdT;
	if (pDetail->dF)
		pDetail->ddZdT += pDetail->fx[12] - (pDetail->fx[12] * (1.0 - 3.0 * D3) * exp3);
	double tmp = (1.0 - 2.0 * D2) * exp2;
	pDetail->ddZdT += (pDetail->fx[13] - (pDetail->fx[13] * tmp));
	pDetail->ddZdT += pDetail->fx[14] - (pDetail->fx[14] * tmp);
	pDetail->ddZdT += pDetail->fx[15] - (pDetail->fx[15] * tmp);
	tmp = (1.0 - 4.0 * D4) * exp4;
	pDetail->ddZdT += pDetail->fx[16] - (pDetail->fx[16] * tmp);
	pDetail->ddZdT += pDetail->fx[17] - (pDetail->fx[17] * tmp);
	pDetail->ddZdT = pDetail->ddZdT - (pDetail->fx[18] + pDetail->fx[19]) * D1 * 2.0
	                 - (pDetail->fx[21] + pDetail->fx[22]) * D1 * (2.0 - 2.0 * D2) * exp2
	                 - (pDetail->fx[23] + pDetail->fx[24] + pDetail->fx[25]) * D1 * (2.0 - 4.0 * D4) * exp4
	                 - pDetail->fx[26] * D1 * (2.0 - 4.0 * D4) * exp4
	                 - pDetail->fx[27] * D2 * 3.0
	                 - (pDetail->fx[28] + pDetail->fx[29]) * D2 * (3.0 - D1) * exp1
	                 - (pDetail->fx[30] + pDetail->fx[31]) * D2 * (3.0 - 2.0 * D2) * exp2
	                 - (pDetail->fx[32] + pDetail->fx[33]) * D2 * (3.0 - 3.0 * D3) * exp3
	                 - (pDetail->fx[34] + pDetail->fx[35] + pDetail->fx[36]) * D2 * (3.0 - 4.0 * D4) * exp4
	                 - pDetail->fx[37] * D3 * 4.0
	                 - (pDetail->fx[39] + pDetail->fx[40] + pDetail->fx[41]) * D3 * (4.0 - 2.0 * D2) * exp2
	                 - (pDetail->fx[42] + pDetail->fx[43]) * D3 * (4.0 - 4.0 * D4) * exp4
	                 - pDetail->fx[44] * D4 * 5.0
	                 - (pDetail->fx[45] + pDetail->fx[46]) * D4 * (5.0 - 2.0 * D2) * exp2
	                 - (pDetail->fx[47] + pDetail->fx[48]) * D4 * (5.0 - 4.0 * D4) * exp4
	                 - pDetail->fx[49] * D5 * 6.0
	                 - pDetail->fx[50] * D5 * (6.0 - 2.0 * D2) * exp2
	                 - pDetail->fx[51] * D6 * 7.0
	                 - pDetail->fx[52] * D6 * (7.0 - 2.0 * D2) * exp2
	                 - pDetail->fx[53] * D7 * (8.0 - D1) * exp1
	                 - pDetail->fx[54] * D7 * (8.0 - 2.0 * D2) * exp2
	                 - pDetail->fx[56] * D8 * (9.0 - 2.0 * D2) * exp2;
	return pDetail->ddZdT;
}

double Detail_d2ZdT2(Detail *pDetail, double d) {
	const double D1 = pDetail->dKp3 * d;
	const double D2 = D1 * D1;
	const double D3 = D2 * D1;
	const double D4 = D3 * D1;
	const double D5 = D4 * D1;
	const double D6 = D5 * D1;
	const double D7 = D6 * D1;
	const double D8 = D7 * D1;
	const double exp1 = exp(-D1);
	const double exp2 = exp(-D2);
	const double exp3 = exp(-D3);
	const double exp4 = exp(-D4);
	for (int i = 12; i < 58; i++) {
		if (pDetail->adUn[i] && pDetail->adFn[i]) {
			pDetail->fx[i] = (pDetail->adFn[i] * D1 * pDetail->adUn[i] * (pDetail->adUn[i] + 1.0)) / (
				                 pDetail->dT * pDetail->dT);
		} else {
			pDetail->fx[i] = 0.0;
		}
	}
	pDetail->dd2ZdT2 = d * pDetail->dd2BdT2;
	if (pDetail->dF)
		pDetail->dd2ZdT2 += pDetail->fx[12] - (pDetail->fx[12] * (1.0 - 3.0 * D3) * exp3);
	double tmp = (1.0 - 2.0 * D2) * exp2;
	pDetail->dd2ZdT2 += -pDetail->fx[13] + (pDetail->fx[13] * tmp);
	pDetail->dd2ZdT2 += -pDetail->fx[14] + (pDetail->fx[14] * tmp);
	pDetail->dd2ZdT2 += -pDetail->fx[15] + (pDetail->fx[15] * tmp);
	tmp = (1.0 - 4.0 * D4) * exp4;
	pDetail->dd2ZdT2 += -pDetail->fx[16] + (pDetail->fx[16] * tmp);
	pDetail->dd2ZdT2 += -pDetail->fx[17] + pDetail->fx[17] * tmp;
	pDetail->dd2ZdT2 = pDetail->dd2ZdT2 + (pDetail->fx[18] + pDetail->fx[19]) * D1 * 2.0
	                   + (pDetail->fx[21] + pDetail->fx[22]) * D1 * (2.0 - 2.0 * D2) * exp2
	                   + (pDetail->fx[23] + pDetail->fx[24] + pDetail->fx[25]) * D1 * (2.0 - 4.0 * D4) * exp4
	                   + pDetail->fx[26] * D1 * (2.0 - 4.0 * D4) * exp4
	                   + pDetail->fx[27] * D2 * 3.0
	                   + (pDetail->fx[28] + pDetail->fx[29]) * D2 * (3.0 - D1) * exp1
	                   + (pDetail->fx[30] + pDetail->fx[31]) * D2 * (3.0 - 2.0 * D2) * exp2
	                   + (pDetail->fx[32] + pDetail->fx[33]) * D2 * (3.0 - 3.0 * D3) * exp3
	                   + (pDetail->fx[34] + pDetail->fx[35] + pDetail->fx[36]) * D2 * (3.0 - 4.0 * D4) * exp4
	                   + pDetail->fx[37] * D3 * 4.0
	                   + (pDetail->fx[39] + pDetail->fx[40] + pDetail->fx[41]) * D3 * (4.0 - 2.0 * D2) * exp2
	                   + (pDetail->fx[42] + pDetail->fx[43]) * D3 * (4.0 - 4.0 * D4) * exp4
	                   + pDetail->fx[44] * D4 * 5.0
	                   + (pDetail->fx[45] + pDetail->fx[46]) * D4 * (5.0 - 2.0 * D2) * exp2
	                   + (pDetail->fx[47] + pDetail->fx[48]) * D4 * (5.0 - 4.0 * D4) * exp4
	                   + pDetail->fx[49] * D5 * 6.0
	                   + pDetail->fx[50] * D5 * (6.0 - 2.0 * D2) * exp2
	                   + pDetail->fx[51] * D6 * 7.0
	                   + pDetail->fx[52] * D6 * (7.0 - 2.0 * D2) * exp2
	                   + pDetail->fx[53] * D7 * (8.0 - D1) * exp1
	                   + pDetail->fx[54] * D7 * (8.0 - 2.0 * D2) * exp2
	                   + pDetail->fx[56] * D8 * (9.0 - 2.0 * D2) * exp2;
	return pDetail->dd2ZdT2;
}

double Detail_dZdD(Detail *pDetail, double d) {
	double temp, temp1, temp2, temp3;
	const double D1 = pDetail->dKp3 * d;
	const double D2 = D1 * D1;
	const double D3 = D2 * D1;
	const double D4 = D3 * D1;
	const double D5 = D4 * D1;
	const double D6 = D5 * D1;
	const double D7 = D6 * D1;
	const double D8 = D7 * D1;
	const double exp1 = exp(-D1);
	const double exp2 = exp(-D2);
	const double exp3 = exp(-D3);
	const double exp4 = exp(-D4);
	for (int i = 12; i < 58; i++) {
		pDetail->fx[i] = pDetail->adFn[i];
	}
	pDetail->ddZdD = pDetail->dB / pDetail->dKp3;
	if (pDetail->dF) {
		temp1 = -9.0 * D3 * exp3;
		temp2 = (1.0 - 3.0 * D3) * exp3;
		temp3 = -temp2 * 3.0 * D6;
		temp = temp1 + temp2 + temp3;
		pDetail->ddZdD += -pDetail->fx[12] + pDetail->fx[12] * temp;
	}
	temp1 = -4.0 * D2 * exp2;
	temp2 = (1.0 - 2.0 * D2) * exp2;
	temp3 = -temp2 * 2.0 * D2;
	temp = temp1 + temp2 + temp3;
	pDetail->ddZdD += -pDetail->fx[13] + pDetail->fx[13] * temp;
	pDetail->ddZdD += -pDetail->fx[14] + pDetail->fx[14] * temp;
	pDetail->ddZdD += -pDetail->fx[15] + pDetail->fx[15] * temp;
	temp1 = -16.0 * D4 * exp4;
	temp2 = (1.0 - 4.0 * D4) * exp4;
	temp3 = -temp2 * 4.0 * D4;
	temp = temp1 + temp2 + temp3;
	pDetail->ddZdD += -pDetail->fx[16] + pDetail->fx[16] * temp;
	pDetail->ddZdD += -pDetail->fx[17] + pDetail->fx[17] * temp;
	temp = 4.0 * D1;
	pDetail->ddZdD += pDetail->fx[18] * temp;
	pDetail->ddZdD += pDetail->fx[19] * temp;
	temp1 = -4.0 * D3 * exp2;
	temp2 = (2.0 - 2.0 * D2) * 2.0 * D1 * exp2;
	temp3 = -temp2 * D2;
	temp = temp1 + temp2 + temp3;
	pDetail->ddZdD += pDetail->fx[20] * temp;
	pDetail->ddZdD += pDetail->fx[21] * temp;
	pDetail->ddZdD += pDetail->fx[22] * temp;
	temp1 = -16.0 * D5 * exp4;
	temp2 = (2.0 - 4.0 * D4) * 2.0 * D1 * exp4;
	temp3 = -temp2 * 2.0 * D4;
	temp = temp1 + temp2 + temp3;
	pDetail->ddZdD += pDetail->fx[23] * temp;
	pDetail->ddZdD += pDetail->fx[24] * temp;
	pDetail->ddZdD += pDetail->fx[25] * temp;
	pDetail->ddZdD += pDetail->fx[26] * temp;
	temp = 9.0 * D2;
	pDetail->ddZdD += pDetail->fx[27] * temp;
	temp = -D3 * exp1 + (3.0 - D1) * 3.0 * D2 * exp1;
	temp -= (3.0 - D1) * D3 * exp1;
	pDetail->ddZdD += pDetail->fx[28] * temp;
	pDetail->ddZdD += pDetail->fx[29] * temp;
	temp1 = -4.0 * D4 * exp2;
	temp2 = (3.0 - 2.0 * D2) * 3.0 * D2 * exp2;
	temp3 = -(3.0 - 2.0 * D2) * 2.0 * D4 * exp2;
	temp = temp1 + temp2 + temp3;
	pDetail->ddZdD += pDetail->fx[30] * temp;
	pDetail->ddZdD += pDetail->fx[31] * temp;
	temp1 = -9.0 * D5 * exp3;
	temp2 = (3.0 - 3.0 * D3) * 3.0 * D2 * exp3;
	temp3 = -(3.0 - 3.0 * D3) * 3.0 * D5 * exp3;
	temp = temp1 + temp2 + temp3;
	pDetail->ddZdD += pDetail->fx[32] * temp;
	pDetail->ddZdD += pDetail->fx[33] * temp;
	temp1 = -16.0 * D6 * exp4;
	temp2 = (3.0 - 4.0 * D4) * 3.0 * D2 * exp4;
	temp3 = -(3.0 - 4.0 * D4) * D6 * 4.0 * exp4;
	temp = temp1 + temp2 + temp3;
	pDetail->ddZdD += pDetail->fx[34] * temp;
	pDetail->ddZdD += pDetail->fx[35] * temp;
	pDetail->ddZdD += pDetail->fx[36] * temp;
	temp = 16.0 * D3;
	pDetail->ddZdD += pDetail->fx[37] * temp;
	pDetail->ddZdD += pDetail->fx[38] * temp;
	temp1 = -4.0 * D5 * exp2;
	temp2 = (4.0 - 2.0 * D2) * 4.0 * D3 * exp2;
	temp3 = -(4.0 - 2.0 * D2) * 2.0 * D5 * exp2;
	temp = temp1 + temp2 + temp3;
	pDetail->ddZdD += pDetail->fx[39] * temp;
	pDetail->ddZdD += pDetail->fx[40] * temp;
	pDetail->ddZdD += pDetail->fx[41] * temp;
	temp = -16.0 * D7 * exp4 + (4.0 - 4.0 * D4) * 4.0 * D3 * exp4;
	temp -= (4.0 - 4.0 * D4) * D7 * 4.0 * exp4;
	pDetail->ddZdD += pDetail->fx[42] * temp;
	pDetail->ddZdD += pDetail->fx[43] * temp;
	temp = 25.0 * D4;
	pDetail->ddZdD += pDetail->fx[44] * temp;
	temp = -4.0 * D6 * exp2 + (5.0 - 2.0 * D2) * 5.0 * D4 * exp2;
	temp -= (5.0 - 2.0 * D2) * D6 * 2.0 * exp2;
	pDetail->ddZdD += pDetail->fx[45] * temp;
	pDetail->ddZdD += pDetail->fx[46] * temp;
	temp = -16.0 * D8 * exp4 + (5.0 - 4.0 * D4) * 5.0 * D4 * exp4;
	temp -= (5.0 - 4.0 * D4) * D8 * 4.0 * exp4;
	pDetail->ddZdD += pDetail->fx[47] * temp;
	pDetail->ddZdD += pDetail->fx[48] * temp;
	temp = 36.0 * D5;
	pDetail->ddZdD += pDetail->fx[49] * temp;
	temp = -4.0 * D7 * exp2 + (6.0 - 2.0 * D2) * 6.0 * D5 * exp2;
	temp -= (6.0 - 2.0 * D2) * D7 * 2.0 * exp2;
	pDetail->ddZdD += pDetail->fx[50] * temp;
	temp = 49.0 * D6;
	pDetail->ddZdD += pDetail->fx[51] * temp;
	temp = -4.0 * D8 * exp2 + (7.0 - 2.0 * D2) * 7.0 * D6 * exp2;
	temp -= (7.0 - 2.0 * D2) * D8 * 2.0 * exp2;
	pDetail->ddZdD += pDetail->fx[52] * temp;
	temp = -1.0 * D8 * exp1 + (8.0 - D1) * 8.0 * D7 * exp1;
	temp -= (8.0 - D1) * D8 * exp1;
	pDetail->ddZdD += pDetail->fx[53] * temp;
	temp = -4.0 * D1 * D8 * exp2 + (8.0 - 2.0 * D2) * 8.0 * D7 * exp2;
	temp -= (8.0 - 2.0 * D2) * D8 * 2.0 * D1 * exp2;
	pDetail->ddZdD += pDetail->fx[54] * temp;
	pDetail->ddZdD += pDetail->fx[55] * temp;
	temp = -4.0 * D2 * D8 * exp2 + (9.0 - 2.0 * D2) * 9.0 * D8 * exp2;
	temp -= (9.0 - 2.0 * D2) * D2 * D8 * 2.0 * exp2;
	pDetail->ddZdD += pDetail->fx[56] * temp;
	pDetail->ddZdD += pDetail->fx[57] * temp;
	pDetail->ddZdD *= pDetail->dKp3;
	return pDetail->ddZdD;
}

void Detail_relativedensity(const Detail *pDetail, NGParSTRUCT *ptNGPar) {
	const double dMWair = 28.96256;
	const double dBX = -0.12527 + 5.91e-4 * ptNGPar->dTb - 6.62e-7 * ptNGPar->dTb * ptNGPar->dTb;
	const double dZa = 1.0 + (dBX * pDetail->dP) / (RGASKJ * ptNGPar->dTb);
	ptNGPar->dRD_Ideal = ptNGPar->dMrx / dMWair;
	ptNGPar->dRD_Real = ptNGPar->dRD_Ideal * (dZa / ptNGPar->dZb);
}
