summaryrefslogblamecommitdiffstats
path: root/subsurface-core/gas-model.c
blob: b90467bbd7c07362e1a8faff002b5c57e06fcfde (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15













                                                                                                 
                                                                               









                                                                                           
                                                                                  


















                                                                                                                             
  



















                                                                    


















                                                               






                                           
 




































                                                                                               



                                                                 
                                                                 

                                                                 













                                                                      
 
/* gas-model.c */
/* gas compressibility model */
#include <stdio.h>
#include <stdlib.h>
#include "dive.h"

/*
 * This gives an interative solution of hte Redlich-Kwong equation for the compressibility factor
 * according to https://en.wikipedia.org/wiki/Redlich–Kwong_equation_of_state
 * in terms of the reduced temperature T/T_crit and pressure p/p_crit.
 *
 * Iterate this three times for good results in our pressur range.
 *
 */

static double redlich_kwong_equation(double t_red, double p_red, double z_init)
{
	return (1.0/(1.0 - 0.08664*p_red/(t_red * z_init)) -
		 0.42748/(sqrt(t_red * t_red * t_red) * ((t_red*z_init/p_red + 0.08664))));
}

/*
 * At high pressures air becomes less compressible, and
 * does not follow the ideal gas law any more.
 */
#define STANDARD_TEMPERATURE 293.0

static double redlich_kwong_compressibility_factor(struct gasmix *gas, double bar)
{
	/* Critical points according to https://en.wikipedia.org/wiki/Critical_point_(thermodynamics) */

	double tcn2 = 126.2;
	double tco2 = 154.6;
	double tche = 5.19;

	double pcn2 = 33.9;
	double pco2 = 50.5;
	double pche = 2.27;

	double tc, pc;

	tc = (tco2 * get_o2(gas) + tche * get_he(gas) + tcn2 * (1000 - get_o2(gas) - get_he(gas))) / 1000.0;
	pc = (pco2 * get_o2(gas) + pche * get_he(gas) + pcn2 * (1000 - get_o2(gas) - get_he(gas))) / 1000.0;

	return (redlich_kwong_equation(STANDARD_TEMPERATURE/tc, bar/pc,
				       redlich_kwong_equation(STANDARD_TEMPERATURE/tc, bar/pc,
							      redlich_kwong_equation(STANDARD_TEMPERATURE/tc, bar/pc,1.0))));
}

/*
 * Generic quintic polynomial
 */
static double quintic(double bar, const double coefficient[])
{
	double	x0 = 1.0,
		x1 = bar,
		x2 = x1*x1,
		x3 = x2*x1,
		x4 = x2*x2,
		x5 = x2*x3;

	return	x0 * coefficient[0] +
		x1 * coefficient[1] +
		x2 * coefficient[2] +
		x3 * coefficient[3] +
		x4 * coefficient[4] +
		x5 * coefficient[5];
}

/*
 * These are the quintic coefficients by Lubomir I. Ivanov that have
 * been optimized for the least-square error to the air
 * compressibility factor table (at 300K) taken from Wikipedia:
 *
 * bar  z_factor
 * ---  ------
 *   1: 0.9999
 *   5: 0.9987
 *  10: 0.9974
 *  20: 0.9950
 *  40: 0.9917
 *  60: 0.9901
 *  80: 0.9903
 * 100: 0.9930
 * 150: 1.0074
 * 200: 1.0326
 * 250: 1.0669
 * 300: 1.1089
 * 400: 1.2073
 * 500: 1.3163
 */
static const double air_coefficients[6] = {
	+1.0002556612420115,
	-0.0003115084635183305,
	+0.00000227808965401253,
	+1.91596422989e-9,
	-8.78421542e-12,
	+6.77746e-15
};

/*
 * Quintic least-square coefficients for O2/N2/He based on tables at
 *
 *    http://ww.baue.org/library/zfactor_table.php
 *
 * converted to bar and also done by Lubomir.
 */
static const double o2_coefficients[6] = {
	+1.0002231211532653,
	-0.0007471497056767194,
	+0.00000200444854807816,
	+2.91501995188e-9,
	-4.48294663e-12,
	-6.11529e-15
};

static const double n2_coefficients[6] = {
	+1.0001898816185364,
	-0.00030793319362077315,
	+0.00000327557417347714,
	-1.93872574476e-9,
	-2.7732353e-12,
	-2.8921e-16
};

static const double he_coefficients[6] = {
	+0.9998700261301693,
	+0.0005452130351730479,
	-2.7853712233619e-7,
	+5.5935404211e-10,
	-1.35114572e-12,
	+2.00476e-15
};

static double air_compressibility_factor(double bar) { return quintic(bar, air_coefficients); }
static double o2_compressibility_factor(double bar) { return quintic(bar, o2_coefficients); }
static double n2_compressibility_factor(double bar) { return quintic(bar, n2_coefficients); }
static double he_compressibility_factor(double bar) { return quintic(bar, he_coefficients); }

/*
 * We end up using specialized functions for known gases, because
 * we have special tables for them.
 *
 * For air we use our known-good table. For other mixes we use a
 * linear interpolation of the Z factors of the individual gases.
 */
double gas_compressibility_factor(struct gasmix *gas, double bar)
{
	double o2, n2, he;	// Z factors
	double of, nf, hf;	// gas fractions ("partial pressures")

	if (gasmix_is_air(gas))
		return air_compressibility_factor(bar);

	o2 = o2_compressibility_factor(bar);
	n2 = n2_compressibility_factor(bar);
	he = he_compressibility_factor(bar);

	of = gas->o2.permille / 1000.0;
	hf = gas->he.permille / 1000.0;
	nf = 1.0 - of - nf;

	return o2*of + n2*nf + he*hf;
}