package com.ng.ngtools.modules;

  public class Therm
  {
	// member data
	//double dT;// current temperature, in Kelvins
	//double dP;// current pressure, in Pascals
	//double dD;// molar density, in moles/dm3
	//double dRho;// mass density, in kg/m3
	private double dPdD; // partial deriv of P wrt D
	private double dPdT; // partial deriv of P wrt T
	private double dSi; // ideal gas specific entropy, kJ/kg.K
	private double dTold; // temperature previously used
	private double dMrxold; // mixture molar mass previously used
	private final double[] GK_root = new double[] {0.14887433898163121088, 0.43339539412924719080, 0.67940956829902440263, 0.86506336668898451073, 0.97390652851717172008};
	private final double[] GK_weight = new double[] {0.29552422471475286217, 0.26926671930999634918, 0.21908636251598204295, 0.14945134915058059038, 0.066671344308688137179};
	//set the number of points for quadrature 
	private final int GK_points = 5;
	//equation constants for ideal gas heat capacity, enthalpy and entropy 
	private final double[][] ThermConstants = new double[][]
	{
		{-29776.4, 7.95454, 43.9417, 1037.09, 1.56373, 813.205, -24.9027, 1019.98, -10.1601, 1070.14, -20.0615},
		{-3495.34, 6.95587, 0.272892, 662.738, -0.291318, -680.562, 1.78980, 1740.06, 0.0, 100.0, 4.49823},
		{20.7307, 6.96237, 2.68645, 500.371, -2.56429, -530.443, 3.91921, 500.198, 2.13290, 2197.22, 5.81381},
		{-37524.4, 7.98139, 24.3668, 752.320, 3.53990, 272.846, 8.44724, 1020.13, -13.2732, 869.510, -22.4010},
		{-56072.1, 8.14319, 37.0629, 735.402, 9.38159, 247.190, 13.4556, 1454.78, -11.7342, 984.518, -24.0426},
		{-13773.1, 7.97183, 6.27078, 2572.63, 2.05010, 1156.72, 0.0, 100.0, 0.0, 100.0, -3.24989},
		{-10085.4, 7.94680, -0.08380, 433.801, 2.85539, 843.792, 6.31595, 1481.43, -2.88457, 1102.23, -0.51551},
		{-5565.60, 6.66789, 2.33458, 2584.98, .749019, 559.656, 0.0, 100.0, 0.0, 100.0, -7.94821},
		{-2753.49, 6.95854, 2.02441, 1541.22, .096774, 3674.81, 0.0, 100.0, 0.0, 100.0, 6.23387},
		{-3497.45, 6.96302, 2.40013, 2522.05, 2.21752, 1154.15, 0.0, 100.0, 0.0, 100.0, 9.19749},
		{-72387.0, 17.8143, 58.2062, 1787.39, 40.7621, 808.645, 0.0, 100.0, 0.0, 100.0, -44.1341},
		{-72674.8, 18.6383, 57.4178, 1792.73, 38.6599, 814.151, 0.0, 100.0, 0.0, 100.0, -46.1938},
		{-91505.5, 21.3861, 74.3410, 1701.58, 47.0587, 775.899, 0.0, 100.0, 0.0, 100.0, -60.2474},
		{-83845.2, 22.5012, 69.5789, 1719.58, 46.2164, 802.174, 0.0, 100.0, 0.0, 100.0, -62.2197},
		{-94982.5, 26.6225, 80.3819, 1718.49, 55.6598, 802.069, 0.0, 100.0, 0.0, 100.0, -77.5366},
		{-103353.0, 30.4029, 90.6941, 1669.32, 63.2028, 786.001, 0.0, 100.0, 0.0, 100.0, -92.0164},
		{-109674.0, 34.0847, 100.253, 1611.55, 69.7675, 768.847, 0.0, 100.0, 0.0, 100.0, -106.149},
		{-122599.0, 38.5014, 111.446, 1646.48, 80.5015, 781.588, 0.0, 100.0, 0.0, 100.0, -122.444},
		{-133564.0, 42.7143, 122.173, 1654.85, 90.2255, 785.564, 0.0, 100.0, 0.0, 100.0, -138.006},
		{0.0, 4.9680, 0.0, 100.0, 0.0, 100.0, 0.0, 100.0, 0.0, 100.0, 0.0},
		{0.0, 4.9680, 0.0, 100.0, 0.0, 100.0, 0.0, 100.0, 0.0, 100.0, 0.0}
	};
	// enumerations for indexing of coefficients
	//public enum CoefficientList { coefA = 0, coefB, coefC, coefD, coefE, coefF, coefG, coefH, coefI, coefJ, coefK } ;
	public int coefA = 0;
	public int coefB = 1;
	public int coefC = 2;
	public int coefD = 3;
	public int coefE = 4;
	public int coefF = 5;
	public int coefG = 6;
	public int coefH = 7;
	public int coefI = 8;
	public int coefJ = 9;
	public int coefK = 10;
	// conversion constant for thermochemical calories to Joules: 1 cal(IT) = 4.1840 J
	private static final double CalTH = 4.1840;
	public Therm()
	{
	  // initialize 3 history-sensitive variables 
	  dSi = 0.0;
	  dTold = 0.0;
	  dMrxold = 0.0;
	} //Therm()
	/**************************************************************************
	*Function:Math.Coth()
	*Arguments:double
	*Returns:double
	*Purpose:calculate hyperbolic cotangent; used in Ho calculations
	*Revisions:
	*Notes:Not a Therm object class member, just a utility for this
	*file. The C++ language has no intrinsic support for
	*hyperbolic cotangent
	**************************************************************************/
	private double coth(double x)
	{
	  return Math.cosh(x) / Math.sinh(x);
	} // Math.Coth()
	/**************************************************************************
	*Function:Run()
	*Arguments:ref AGA10.GasPropsSTRUCT , Detail *
	*Returns:void
	*Purpose:overall execution control; top level math for SOS and k
	*Revisions:
	**************************************************************************/
	public final void Run(com.ng.ngtools.tangible.RefObject<NG_Cal.GasPropsSTRUCT> ptAGA10, com.ng.ngtools.tangible.RefObject<Detail> ptD)
	{
	  //local variables
	  double c, x, y, z;
	  //first run basic set of functions within AGA 8 (1994) Detail Method 
	  ptD.argValue.Run(ptAGA10);
	  //find first partial derivative of Z wrt D
	  ptD.argValue.dZdD(ptAGA10.argValue.dDf);
	  //find real gas cv, cp, specific enthalpy and entropy
	  CprCvrHS(ptAGA10, ptD);
	  //ratio of real gas specific heats
	  ptAGA10.argValue.dk = ptAGA10.argValue.dCp / ptAGA10.argValue.dCv;
	  //solve c in three steps, for clarity and ease of debugging 
	  x = ptAGA10.argValue.dk * NG_Cal.RGAS * 1000.0 * ptAGA10.argValue.dTf;
	  y = ptAGA10.argValue.dMrx;
	  z = ptAGA10.argValue.dZf + ptAGA10.argValue.dDf * ptD.argValue.ddZdD;
	  //calculate c, which is SOS^2
	  c = (x / y) * z;
	  //speed of sound 
	  ptAGA10.argValue.dSOS = Math.sqrt(c);
	  //calculate the real gas isentropic exponent
	  //using expression functionally equivalent to Equation 3.2
	  ptAGA10.argValue.dKappa = (c * ptAGA10.argValue.dRhof) / ptAGA10.argValue.dPf;
    } //Run()
	/**************************************************************************
	*Function:CpiMolar()
	*Arguments:ref AGA10.GasPropsSTRUCT 
	*Returns:double
	*Purpose:Calculate constant pressure ideal gas molar heat capacity
	*in (J/mol-K), applying eqns from Aly, Lee, McFall
	*Notes:For continuity, the original constants and eqn's have been
	*retained. Conversion from thermochemical calories(th) to
	*Joules is applied after the primary calculations are complete.
	*Revisions:
	**************************************************************************/
	private double CpiMolar(com.ng.ngtools.tangible.RefObject<NG_Cal.GasPropsSTRUCT> ptAGA10)
	{
	  double Cp = 0.0;
	  double Cpx;
	  double DT, FT, HT, JT;
	  double Dx, Fx, Hx, Jx;
	  double T;
	  int i;
	  //to maximize readability of this section, use intermediate variable T 
	  T = ptAGA10.argValue.dTf;
	  //calculate heat capacity for each component
	  for (i = 0; i < NG_Cal.NUMBEROFCOMPONENTS; i++)
	  {
		//skip species whose concentration is zero
		if (ptAGA10.argValue.adMixture[i] <= 0.0)
		{
			continue;
		}
		//initialize Cp of species to zero
		Cpx = 0.0;
		// calculate species intermediate terms
		DT = ThermConstants[i][coefD] / T;
		FT = ThermConstants[i][coefF] / T;
		HT = ThermConstants[i][coefH] / T;
		JT = ThermConstants[i][coefJ] / T;
		// use intermediate terms to avoid redundant calcs
		Dx = DT / Math.sinh(DT);
		Fx = FT / Math.cosh(FT);
		Hx = HT / Math.sinh(HT);
		Jx = JT / Math.cosh(JT);
		Cpx += ThermConstants[i][coefB];
		Cpx += ThermConstants[i][coefC] * Dx * Dx;
		Cpx += ThermConstants[i][coefE] * Fx * Fx;
		Cpx += ThermConstants[i][coefG] * Hx * Hx;
		Cpx += ThermConstants[i][coefI] * Jx * Jx;
		//use current mole fraction to weight the contribution 
		Cpx *= ptAGA10.argValue.adMixture[i];
		//add this contribution to the sum
		Cp += Cpx;
	  }
	  // convert from cal(th)/mol-K to J/mol-K 
	  Cp *= CalTH;
	  return Cp;
	} //CpiMolar()
	/**************************************************************************
	*Function:Ho()
	*Arguments:ref AGA10.GasPropsSTRUCT 
	*Returns:double
	*Purpose:Calculate ideal gas specific enthalpy (J/kg)
	*Notes:For continuity, the original constants and eqn's have been
	*retained. Conversion from thermochemical calories(th) to
	*Joules is applied after the primary calculations are complete.
	*Revisions:
	**************************************************************************/
	private double Ho(com.ng.ngtools.tangible.RefObject<NG_Cal.GasPropsSTRUCT> ptAGA10)
	{
	  double H = 0.0;
	  double Hx;
	  double DT, FT, HT, JT;
	  double cothDT, tanhFT, cothHT, tanhJT;
	  double T;
	  int i;
	  // to maximize readability of this section, use intermediate variable T
	  T = ptAGA10.argValue.dTf;
	  for (i = 0; i < NG_Cal.NUMBEROFCOMPONENTS; i++)
	  {
		// skip species whose concentration is zero 
		if (ptAGA10.argValue.adMixture[i] <= 0.0)
		{
			continue;
		}
		Hx = 0.0;
		// calculate species intermediate terms 
		DT = ThermConstants[i][coefD] / T;
		FT = ThermConstants[i][coefF] / T;
		HT = ThermConstants[i][coefH] / T;
		JT = ThermConstants[i][coefJ] / T;
		cothDT = coth(DT);
		tanhFT = Math.tanh(FT);
		cothHT = coth(HT);
		tanhJT = Math.tanh(JT);
		Hx += ThermConstants[i][coefA];
		Hx += ThermConstants[i][coefB] * T;
		Hx += ThermConstants[i][coefC] * ThermConstants[i][coefD] * cothDT;
		Hx -= ThermConstants[i][coefE] * ThermConstants[i][coefF] * tanhFT;
		Hx += ThermConstants[i][coefG] * ThermConstants[i][coefH] * cothHT;
		Hx -= ThermConstants[i][coefI] * ThermConstants[i][coefJ] * tanhJT;
		//use current mole fraction to weight the contribution 
		Hx *= ptAGA10.argValue.adMixture[i];
		//add this contribution to the sum
		H += Hx;
	  }
	  //convert from cal(th)/g-mol to kJ/kg-mol 
	  H *= CalTH;
	  //convert from kJ/kg-mol to J/kg
	  H /= ptAGA10.argValue.dMrx;
	  // return in J/kg 
	  return H * 1.0e3;
	}
	//  Ho()
	/**************************************************************************
	*Function:So()
	*Arguments:ref AGA10.GasPropsSTRUCT 
	*Returns:double
	*Purpose:ideal gas specific entropy (J/kg-K)
	*Notes:For continuity, the original constants and eqn's have been
	*retained. Conversion from thermochemical calories(th) to
	*Joules is applied after the primary calculations are complete.
	*Revisions:
	**************************************************************************/
	private double So(com.ng.ngtools.tangible.RefObject<NG_Cal.GasPropsSTRUCT> ptAGA10)
	{
	  double S = 0.0;
	  double Sx;
	  double DT, FT, HT, JT;
	  double cothDT, tanhFT, cothHT, tanhJT;
	  double sinhDT, coshFT, sinhHT, coshJT;
	  double T;
	  int i;
	  // to improve readability of this section, use intermediate variable T 
	  T = ptAGA10.argValue.dTf;
	  for (i = 0; i < NG_Cal.NUMBEROFCOMPONENTS; i++)
	  {
		// skip species whose concentration is zero
		if (ptAGA10.argValue.adMixture[i] <= 0.0)
		{
			continue;
		}
		Sx = 0.0;
		// calculate species intermediate terms
		DT = ThermConstants[i][coefD] / T;
		FT = ThermConstants[i][coefF] / T;
		HT = ThermConstants[i][coefH] / T;
		JT = ThermConstants[i][coefJ] / T;
		cothDT = coth(DT);
		tanhFT = Math.tanh(FT);
		cothHT = coth(HT);
		tanhJT = Math.tanh(JT);
		sinhDT = Math.sinh(DT);
		coshFT = Math.cosh(FT);
		sinhHT = Math.sinh(HT);
		coshJT = Math.cosh(JT);
		Sx += ThermConstants[i][coefK];
		Sx += ThermConstants[i][coefB] * Math.log(T);
		Sx += ThermConstants[i][coefC] * (DT * cothDT - Math.log(sinhDT));
		Sx -= ThermConstants[i][coefE] * (FT * tanhFT - Math.log(coshFT));
		Sx += ThermConstants[i][coefG] * (HT * cothHT - Math.log(sinhHT));
		Sx -= ThermConstants[i][coefI] * (JT * tanhJT - Math.log(coshJT));
		//use current mole fraction to weight the contribution
		Sx *= ptAGA10.argValue.adMixture[i];
		//add this contribution to the sum
		S += Sx;
	  }
	  //convert cal(th)/mol-K basis to to kJ/kg mol-K
	  S *= CalTH;
	  //convert from kJ/kg mol-K to kJ/kg-K
	  S /= ptAGA10.argValue.dMrx;
	  // return in J/kg-K
	  return S * 1.0e3;
	} //So()
	/**************************************************************************
	*Function:CprCvrHS()
	*Arguments:ref AGA10.GasPropsSTRUCT , Detail *
	*Returns:void
	*Purpose:reasonably efficient group calculation of Cp, Cv, H and S
	*Revisions:
	**************************************************************************/
	private void CprCvrHS(com.ng.ngtools.tangible.RefObject<NG_Cal.GasPropsSTRUCT> ptAGA10, com.ng.ngtools.tangible.RefObject<Detail> ptD)
	{
	  double Cvinc, Cvr, Cpr;
	  double Hinc;
	  double Sinc;
	  double Smixing;
	  double Cp, Si;
	  double a, b, x;
	  int i;
	  //initialize integrals to zero
	  Cvinc = 0.0;
	  Hinc = 0.0;
	  Sinc = 0.0;
	  //initialize entropy of mixing
	  Smixing = 0.0;
	  //find ideal gas Cp
	  Cp = CpiMolar(ptAGA10);
	  //find ideal gas enthalpy 
	  ptAGA10.argValue.dHo = Ho(ptAGA10);
	  //find ideal gas entropy
	  Si = So(ptAGA10);
	  //calculate ideal gas specific heat capacity at constant pressure in J/kgK 
	  ptAGA10.argValue.dCpi = (Cp * 1000.0) / ptAGA10.argValue.dMrx;
	  //integrate partial derivatives from D=0 to D=D, applying Gauss-Kronrod quadrature
	  for (i = 0; i < GK_points; i++)
	  {
		// set calculation point at + abscissa
		x = ptAGA10.argValue.dDf * (1.0 + GK_root[i]) / 2.0;
		//get Z at D 
		ptD.argValue.zdetail(x);
		ptD.argValue.dZdT(x);
		ptD.argValue.d2ZdT2(x);
		//gather contributions at + abscissa; applying weighting factor 
		Hinc += GK_weight[i] * ptD.argValue.ddZdT / x;
		Cvinc += GK_weight[i] * (2.0 * ptD.argValue.ddZdT + ptAGA10.argValue.dTf * ptD.argValue.dd2ZdT2) / x;
		Sinc += GK_weight[i] * (ptD.argValue.dZ + ptAGA10.argValue.dTf * ptD.argValue.ddZdT - 1.0) / x;
		//set calculation point at - abscissa
		x = ptAGA10.argValue.dDf * (1.0 - GK_root[i]) / 2.0;
		//get Z at D 
		ptD.argValue.zdetail(x);
		//calculate 1st and 2nd partial derivatives of Z wrt T
		ptD.argValue.dZdT(x);
		ptD.argValue.d2ZdT2(x);
		//gather contributions at - abscissa; applying weighting factor
		Hinc += GK_weight[i] * ptD.argValue.ddZdT / x;
		Cvinc += GK_weight[i] * (2.0 * ptD.argValue.ddZdT + ptAGA10.argValue.dTf * ptD.argValue.dd2ZdT2) / x;
		Sinc += GK_weight[i] * (ptD.argValue.dZ + ptAGA10.argValue.dTf * ptD.argValue.ddZdT - 1.0) / x;
	  }
	  //return Z and partial derivatives to full molar density
	  ptD.argValue.zdetail(ptAGA10.argValue.dDf);
	  ptD.argValue.dZdT(ptAGA10.argValue.dDf);
	  ptD.argValue.d2ZdT2(ptAGA10.argValue.dDf);
	  //complete Cv molar
	  Cvr = Cp - NG_Cal.RGAS * (1.0 + ptAGA10.argValue.dTf * Cvinc * 0.5 * ptAGA10.argValue.dDf);
	  //intermediate values for Cp, containing 2 partial derivatives
	  a = (ptAGA10.argValue.dZf + ptAGA10.argValue.dTf * ptD.argValue.ddZdT);
	  b = (ptAGA10.argValue.dZf + ptAGA10.argValue.dDf * ptD.argValue.ddZdD);
	  //calculate dPdT, the partial derivative of P wrt T, at D
	  dPdT = NG_Cal.RGAS * ptAGA10.argValue.dDf * a;
	  //calculate dPdD, the partial derivative of P wrt D, at T
	  dPdD = NG_Cal.RGAS * ptAGA10.argValue.dTf * b;
	  //equation completing molar Cp, cancelling appropriate terms
	  Cpr = Cvr + NG_Cal.RGAS * ((a * a) / b);
	  //change from molar to mass basis
	  Cpr /= ptAGA10.argValue.dMrx;
	  Cvr /= ptAGA10.argValue.dMrx;
	  // write to the data stucture
	  ptAGA10.argValue.dCv = Cvr * 1000.0; // convert from joules/kgK to kilojoules/kgK
	  ptAGA10.argValue.dCp = Cpr * 1000.0;
	  // calculate specific enthalpy
	  ptAGA10.argValue.dH = ptAGA10.argValue.dHo + 1000.0 * NG_Cal.RGAS * ptAGA10.argValue.dTf * (ptAGA10.argValue.dZf - 1.0 - ptAGA10.argValue.dTf * Hinc * 0.5 * ptAGA10.argValue.dDf) / ptAGA10.argValue.dMrx;
	  // calculate entropy of mixing
	  for (i = 0; i < NG_Cal.NUMBEROFCOMPONENTS; i++)
	  {
		if (ptAGA10.argValue.adMixture[i] != 0)
		{
			Smixing += ptAGA10.argValue.adMixture[i] * Math.log(ptAGA10.argValue.adMixture[i]);
		}
	  }
	  Smixing *= NG_Cal.RGAS;
	  // calculate specific entropy
	  ptAGA10.argValue.dS = Si - Smixing - 1000.0 * NG_Cal.RGAS * (Math.log(ptAGA10.argValue.dPf / 101325.0) - Math.log(ptAGA10.argValue.dZf) + Sinc * 0.5 * ptAGA10.argValue.dDf) / ptAGA10.argValue.dMrx;
    } //CprCvrHS()
	/**************************************************************************
	*Function:HS_Mode()
	*Arguments:ref AGA10.GasPropsSTRUCT , Detail *, double, double, bool
	*Returns:void
	*Purpose:Calculates a pressure & temperature from known enthalpy & entropy,
	*with or without prior estimates.This function has a role in the
	*calculation of C*.
	*Solution based on a doubly-nested trial & error algorithm and Newton's
	*method.
	*
	*For illustrative purpose, two approaches are supported by this example.
	*If you are starting without advance knowledge of P & T, set the input parm
	*bGuess to false, thus specifying a conservative search approach.
	*If, however, you have a basis for guessing P & T (plenum conditions of a
	*critical flow nozzle, for example) set P & T via GasPropsSTRUCT and set
	*bGuess = true. The initial guess allows the search function to be more
	*aggressive and, typically, faster.
	*
	*Revisions:
	**************************************************************************/
	public final void HS_Mode(com.ng.ngtools.tangible.RefObject<NG_Cal.GasPropsSTRUCT> ptAGA10, com.ng.ngtools.tangible.RefObject<Detail> ptD, double H, double S, boolean bGuess)
	{
	  double s0, s1, s2, t0, t1, t2, tmin, tmax;
	  double h0, h1, h2, p0, p1, p2, px, pmin, pmax;
	  double delta1, delta2;
	  double tolerance = 0.001; // convergence tolerance (used for both H and S searches)
	  int i, j;
	  //s0and h0 are our real gas reference points 
	  s0 = S;
	  h0 = H;
	  //calling function specifies whether search parameters are supplied thru ptAGA10 or unknown 
	  if (bGuess)
	  {
		t1 = ptAGA10.argValue.dTf;
		px = ptAGA10.argValue.dPf;
		pmax = px * 2.0;
		pmin = px * 0.1;
		tmax = t1 * 1.5;
		tmin = t1 * 0.67;
	  }
	  else // use arbitrary, generic limits
	  {
		t1 = 273.15;
		px = 1013250.0; // 10 atmospheres
		pmax = NG_Cal.P_MAX;
		pmin = 10000.0; // 10 kPa
		tmax = NG_Cal.T_MAX;
		tmin = NG_Cal.T_MIN;
	  }
	  // set the temperature differential
	  t2 = t1 + 10.0;
	  ///////////////////////////////////////////
	  //begin double trial-and-error, searching for T & P
	  //run the calculation with initial guesses
	  ptD.argValue.Run(ptAGA10);
	  //h1 is difference between h given and h@Tf, Pf
	  h1 = this.H(ptAGA10, ptD) - h0;
	  //outer loop: search for a t2 which will satisfy constant enthalpy 
	  for (i = 0; i < NG_Cal.MAX_NUM_OF_ITERATIONS; i++)
	  {
		ptAGA10.argValue.dTf = t2;
		p1 = px; // reset one bracket
		p2 = px * 0.1; // set other bracket to 0.1x the upper bracket
		ptAGA10.argValue.dPf = p1;
		ptD.argValue.Run(ptAGA10);
		s1 = this.S(ptAGA10, ptD) - s0;
		//inside loop: search for a p2 which will satisfy constant entropy
		for (j = 0; j < NG_Cal.MAX_NUM_OF_ITERATIONS; j++)
		{
		  ptAGA10.argValue.dPf = p2;
		  ptD.argValue.Run(ptAGA10);
		  s2 = this.S(ptAGA10, ptD) - s0;
		  //calculate our proportional change
		  delta2 = Math.abs(s1 - s2) / s0; // close enough?
		  if (delta2 < tolerance)
		  {
			  break;
		  }
		  //revise our estimate to p2
		  p0 = p2;
		  p2 = (p1 * s2 - p2 * s1) / (s2 - s1);
		  //check for negative pressure and clamp to pmin for safety
		  if (p2 <= pmin)
		  {
			p2 = pmin;
		  }
		  //check if we've created an unrealistic pressure
		  if (p2 >= pmax)
		  {
			  p2 = pmax; // swap values
		  }
		  p1 = p0;
		  s1 = s2;
		}
		// check for failure to converge
		if (j >= NG_Cal.MAX_NUM_OF_ITERATIONS)
		{
			ptAGA10.argValue.lStatus = NG_Cal.MAX_NUM_OF_ITERATIONS_EXCEEDED;
		}
		//calc enthalpy at guessed P & current iter T 
		h2 = this.H(ptAGA10, ptD) - h0;
		//calculate our proportional change
		delta1 = Math.abs(h1 - h2) / h0;
		// close enough?
		if (delta1 < tolerance && i > 0)
		{
			break;
		}
		//revise our estimate to t2 
		t0 = t2;
		t2 = (t1 * h2 - t2 * h1) / (h2 - h1);
		//check if we've created an unrealistic temperature 
		if (t2 >= tmax)
		{
			t2 = tmax;
		}
		//revise t2, if necessary
		if (t2 <= tmin)
		{
		  t2 = t0 + 10.0;
		  ptAGA10.argValue.dTf = t2;
		  ptD.argValue.Run(ptAGA10);
		  h2 = this.H(ptAGA10, ptD) - h0;
		}
		t1 = t0;
		h1 = h2;
	  }
	  // check for failure to converge
	  if (i >= NG_Cal.MAX_NUM_OF_ITERATIONS)
	  {
		  ptAGA10.argValue.lStatus = NG_Cal.MAX_NUM_OF_ITERATIONS_EXCEEDED;
	  }
	} //HS_Mode()
	/**************************************************************************
	*Function:H()
	*Arguments:ref AGA10.GasPropsSTRUCT , Detail *
	*Returns:double
	*Purpose:real gas specific enthalpy
	*Revisions:
	**************************************************************************/
	private double H(com.ng.ngtools.tangible.RefObject<NG_Cal.GasPropsSTRUCT> ptAGA10, com.ng.ngtools.tangible.RefObject<Detail> ptD)
	{
	  double Hinc;
	  double x;
	  int i;
	  //initialize integral 
	  Hinc = 0.0;
	  //find ideal gas enthalpy 
	  ptAGA10.argValue.dHo = Ho(ptAGA10);
	  //integrate partial derivatives from D=0 to D=D, applying Gauss-Kronrod quadrature 
	  for (i = 0; i < GK_points; i++)
	  {
		//calculate 1st and 2nd partial derivatives of Z wrt T
		x = ptAGA10.argValue.dDf * (1.0 + GK_root[i]) / 2.0;
		ptD.argValue.zdetail(x);
		ptD.argValue.dZdT(x);
		ptD.argValue.d2ZdT2(x);
		Hinc += GK_weight[i] * ptD.argValue.ddZdT / x;
		if (i == 10)
		{
			break;
		}
		x = ptAGA10.argValue.dDf * (1.0 - GK_root[i]) / 2.0;
		ptD.argValue.zdetail(x);
		ptD.argValue.dZdT(x);
		ptD.argValue.d2ZdT2(x);
		Hinc += GK_weight[i] * ptD.argValue.ddZdT / x;
	  }
	  ptD.argValue.zdetail(ptAGA10.argValue.dDf);
	  ptD.argValue.dZdT(ptAGA10.argValue.dDf);
	  ptD.argValue.d2ZdT2(ptAGA10.argValue.dDf);
	  // calculate specific enthalpy
	  ptAGA10.argValue.dH = ptAGA10.argValue.dHo + 1000.0 * NG_Cal.RGAS * ptAGA10.argValue.dTf * (ptAGA10.argValue.dZf - 1.0 - ptAGA10.argValue.dTf * Hinc * 0.5 * ptAGA10.argValue.dDf) / ptAGA10.argValue.dMrx;
	  return (ptAGA10.argValue.dH);
	} // H()
	/**************************************************************************
	*Function:S()
	*Arguments:ref AGA10.GasPropsSTRUCT , Detail *
	*Returns:double
	*Purpose:real gas specific entropy
	*Revisions:
	**************************************************************************/
	private double S(com.ng.ngtools.tangible.RefObject<NG_Cal.GasPropsSTRUCT> ptAGA10, com.ng.ngtools.tangible.RefObject<Detail> ptD)
	{
	  double Sinc;
	  double Smixing;
	  double x;
	  int i;
	  //initialize integral 
	  Sinc = 0.0;
	  //initialize entropy of mixing 
	  Smixing = 0.0;
	  //integrate partial derivatives from D=0 to D=D, applying Gauss-Kronrod quadrature
	  for (i = 0; i < GK_points; i++)
	  {
		//calculate 1st and 2nd partial derivatives of Z wrt T
		x = ptAGA10.argValue.dDf * (1.0 + GK_root[i]) / 2.0;
		ptD.argValue.zdetail(x);
		ptD.argValue.dZdT(x);
		ptD.argValue.d2ZdT2(x);
		Sinc += GK_weight[i] * (ptD.argValue.dZ + ptAGA10.argValue.dTf * ptD.argValue.ddZdT - 1.0) / x;
		if (i == 10)
		{
			break;
		}
		x = ptAGA10.argValue.dDf * (1.0 - GK_root[i]) / 2.0;
		ptD.argValue.zdetail(x);
		ptD.argValue.dZdT(x);
		ptD.argValue.d2ZdT2(x);
		Sinc += GK_weight[i] * (ptD.argValue.dZ + ptAGA10.argValue.dTf * ptD.argValue.ddZdT - 1.0) / x;
	  }
	  //reset Z and partial deivatives dZdT and d2ZdT2
	  ptD.argValue.zdetail(ptAGA10.argValue.dDf);
	  ptD.argValue.dZdT(ptAGA10.argValue.dDf);
	  ptD.argValue.d2ZdT2(ptAGA10.argValue.dDf);
	  //find ideal gas entropy, but only if temperature or composition have changed
	  if (ptAGA10.argValue.dTf != dTold || ptAGA10.argValue.dMrx != dMrxold)
	  {
		dSi = So(ptAGA10);
		dTold = ptAGA10.argValue.dTf;
		dMrxold = ptAGA10.argValue.dMrx;
	  }
	  //calculate entropy of mixing
	  for (i = 0; i < NG_Cal.NUMBEROFCOMPONENTS; i++)
	  {
		if (ptAGA10.argValue.adMixture[i] != 0)
		{
			Smixing += ptAGA10.argValue.adMixture[i] * Math.log(ptAGA10.argValue.adMixture[i]);
		}
	  }
	  Smixing *= NG_Cal.RGAS;
	  // calculate specific entropy
	  ptAGA10.argValue.dS = dSi - Smixing - 1000.0 * NG_Cal.RGAS * (Math.log(ptAGA10.argValue.dPf / 101325.0) - Math.log(ptAGA10.argValue.dZf) + Sinc * 0.5 * ptAGA10.argValue.dDf) / ptAGA10.argValue.dMrx;
	  return (ptAGA10.argValue.dS);
	} // S()
  }