Natural Gas Properties with ISO6976.2016

Overview

ISO6976.2016 implements the calculation method of ISO 6976:2016 “Natural Gas — Calculation of calorific values, density, relative density and Wobbe indices from composition”. Given a gas composition as mole fractions, it returns all combustion and volumetric properties together with their standard uncertainties, propagated according to Annex B of the standard.

Properties returned

Symbol Description Unit
M Molar mass kg/kmol
Z Compression factor
G_o, D_o Ideal-gas relative density and density —, kg/m³
G, u_G Real-gas relative density
D, u_D Real-gas density kg/m³
Hcg, u_Hcg Molar gross calorific value kJ/mol
Hcn, u_Hcn Molar net calorific value kJ/mol
Hmg, u_Hmg Mass-basis gross calorific value MJ/kg
Hmn, u_Hmn Mass-basis net calorific value MJ/kg
Hvg, u_Hvg Volumetric gross calorific value (real gas) MJ/m³
Hvn, u_Hvn Volumetric net calorific value (real gas) MJ/m³
Hvg_o, Hvn_o Ideal-gas volumetric calorific values MJ/m³
Wg, u_Wg Gross Wobbe index MJ/m³
Wn, u_Wn Net Wobbe index MJ/m³
Wg_o, Wn_o Ideal-gas Wobbe indices MJ/m³

Properties with a u_ prefix are standard uncertainties (k = 1) unless the coverage argument is set to a value other than 1.

Application limits

The calculation is valid only within the limits defined in ISO 6976:2016 §5:

Quick start

The simplest way to provide a composition is to construct a numeric vector of length 60 in the component order of ISO 6976:2016 Table A.2 (use componentNames() to see the full list):

x   <- numeric(60)   # all zeros
u_x <- numeric(60)   # all zero uncertainties
r_x <- diag(60)      # identity correlation matrix (no correlations)

# Fill in a simple two-component mixture: 95 % methane, 5 % nitrogen
x[componentIndex("methane")]  <- 0.95
x[componentIndex("nitrogen")] <- 0.05

# Assign standard uncertainties (0.05 mol/mol each)
u_x[componentIndex("methane")]  <- 0.0005
u_x[componentIndex("nitrogen")] <- 0.0005

res <- calculateProperties(x, u_x, r_x,
                           combustionTemperature = 25,
                           volumeTemperature     = 15)

cat("Molar mass              :", round(res$M,   4), "kg/kmol\n")
#> Molar mass              : 16.641 kg/kmol
cat("Compression factor Z    :", round(res$Z,   6), "\n")
#> Compression factor Z    : 0.998139
cat("Gross CV (volumetric)   :", round(res$Hvg, 4), "MJ/m³\n")
#> Gross CV (volumetric)   : 35.8484 MJ/m³
cat("  standard uncertainty  :", round(res$u_Hvg, 6), "MJ/m³\n")
#>   standard uncertainty  : 0.020476 MJ/m³
cat("Gross Wobbe index       :", round(res$Wg,  4), "MJ/m³\n")
#> Gross Wobbe index       : 47.261 MJ/m³
cat("  standard uncertainty  :", round(res$u_Wg, 6), "MJ/m³\n")
#>   standard uncertainty  : 0.026097 MJ/m³

Using the GasComponents class

For applications that build a composition incrementally — for example when reading chromatograph results component by component — the GasComponents R6 class provides named getters and setters:

gc <- GasComponents$new()

# Set fractions by name or by index
gc$setFraction("methane",  0.9234)
gc$setFraction("ethane",   0.0254)
gc$setFraction("propane",  0.0152)
gc$setFraction("nitrogen", 0.0103)
gc$setFraction("carbon dioxide", 0.0154)
gc$setFraction(1L, 0.9234)   # same as "methane"

# Set uncertainties
gc$setUncertainty("methane",        0.000332)
gc$setUncertainty("ethane",         0.000243)
gc$setUncertainty("propane",        0.000148)
gc$setUncertainty("nitrogen",       0.000195)
gc$setUncertainty("carbon dioxide", 0.000111)

# Retrieve a value
gc$getFraction("methane")
#> [1] 0.9234

# Pass directly to calculateProperties
res <- calculateProperties(gc$fractions, gc$uncertainties, gc$correlations,
                           combustionTemperature = 15,
                           volumeTemperature     = 15)
round(res$Hvg, 4)   # real-gas vol. gross CV [MJ/m³]
#> [1] 38.0053

Setting correlations

When a GC calibration provides a full covariance matrix, use setCorrelationMatrix() or setCorrelation() for individual pairs:

gc2 <- GasComponents$new()
gc2$setFractionArray(gc$fractions)
gc2$setUncertaintyArray(gc$uncertainties)

# Negative correlation between methane and ethane (typical for GC)
gc2$setCorrelation("methane", "ethane", -0.65)
gc2$getCorrelation("methane", "ethane")
#> [1] -0.65
gc2$getCorrelation("ethane", "methane")   # automatically symmetric
#> [1] -0.65

Reference conditions

ISO 6976:2016 defines properties at specified reference temperatures and a reference pressure. The package supports all temperature combinations in the standard:

data("example3", envir = environment())

# German/European standard: 25 °C combustion, 0 °C metering
r25_0 <- calculateProperties(example3$fractionArray, example3$uncertaintyArray,
                             example3$correlationMatrix,
                             combustionTemperature = 25,
                             volumeTemperature     = 0)

# UK/legacy standard: 15 °C / 15 °C
r15_15 <- calculateProperties(example3$fractionArray, example3$uncertaintyArray,
                              example3$correlationMatrix,
                              combustionTemperature = 15,
                              volumeTemperature     = 15)

cat("Hvg at 25/0 °C  :", round(r25_0$Hvg,  5), "MJ/m³\n")
#> Hvg at 25/0 °C  : 41.8936 MJ/m³
cat("Hvg at 15/15 °C :", round(r15_15$Hvg, 5), "MJ/m³\n")
#> Hvg at 15/15 °C : 39.73351 MJ/m³

Uncertainty and coverage factor

All u_ outputs are standard uncertainties (k = 1) by default. For expanded uncertainties at a given confidence level, set coverage = 2 (approximately 95 % for a normal distribution):

data("example1", envir = environment())

r_k1 <- calculateProperties(example1$fractionArray, example1$uncertaintyArray,
                             example1$correlationMatrix,
                             combustionTemperature = 15, volumeTemperature = 15,
                             coverage = 1)
r_k2 <- calculateProperties(example1$fractionArray, example1$uncertaintyArray,
                             example1$correlationMatrix,
                             combustionTemperature = 15, volumeTemperature = 15,
                             coverage = 2)

cat("Gross Wobbe index :", round(r_k1$Wg, 5), "MJ/m³\n")
#> Gross Wobbe index : 49.52936 MJ/m³
cat("  u (k=1)         :", round(r_k1$u_Wg, 6), "MJ/m³\n")
#>   u (k=1)         : 0.021675 MJ/m³
cat("  U (k=2, ~95%)   :", round(r_k2$u_Wg, 6), "MJ/m³\n")
#>   U (k=2, ~95%)   : 0.04335 MJ/m³

Verification against ISO 6976:2016 Annex D

The package ships with the four reference datasets from Annex D of the standard. The results below reproduce Table D.2 of ISO 6976:2016.

data("example1", envir = environment())
res <- calculateProperties(example1$fractionArray, example1$uncertaintyArray,
                           example1$correlationMatrix,
                           combustionTemperature = 15,
                           volumeTemperature     = 15,
                           coverage              = 1)

tab <- data.frame(
  Property = c("M [kg/kmol]", "Z", "Hcg [kJ/mol]", "u(Hcg)",
               "Hmg [MJ/kg]", "u(Hmg)", "Hvg [MJ/m\u00b3]", "u(Hvg)"),
  Computed = round(c(res$M,     res$Z,     res$Hcg,   res$u_Hcg,
                     res$Hmg,   res$u_Hmg, res$Hvg,   res$u_Hvg), 7),
  ISO_6976 = c(17.3884301, 0.99776224, 906.1799588, 0.615609872,
               52.113961,  0.024301,   38.410611,   0.026267)
)
knitr::kable(tab, align = "lrr")
Property Computed ISO_6976
M [kg/kmol] 17.3884301 17.3884301
Z 0.9977622 0.9977622
Hcg [kJ/mol] 906.1799588 906.1799588
u(Hcg) 0.6156099 0.6156099
Hmg [MJ/kg] 52.1139605 52.1139610
u(Hmg) 0.0243009 0.0243010
Hvg [MJ/m³] 38.4106112 38.4106110
u(Hvg) 0.0262668 0.0262670

Component reference

# All 60 components in table order
nms <- componentNames()
cat(paste(sprintf("%2d  %s", seq_along(nms), nms), collapse = "\n"), "\n")
#>  1  methane
#>  2  ethane
#>  3  propane
#>  4  n-butane
#>  5  isobutane
#>  6  n-pentane
#>  7  isopentane
#>  8  neopentane
#>  9  n-hexane
#> 10  2-methylpentane
#> 11  3-methylpentane
#> 12  2,2-dimethylbutane
#> 13  2,3-dimethylbutane
#> 14  n-heptane
#> 15  n-octane
#> 16  n-nonane
#> 17  n-decane
#> 18  ethylene
#> 19  propylene
#> 20  1-butene
#> 21  cis-2-butene
#> 22  trans-2-butene
#> 23  isobutylene
#> 24  1-pentene
#> 25  propadiene
#> 26  1,2-butadiene
#> 27  1,3-butadiene
#> 28  acetylene
#> 29  cyclopentane
#> 30  methylcyclopentane
#> 31  ethylcyclopentane
#> 32  cyclohexane
#> 33  methylcyclohexane
#> 34  ethylcyclohexane
#> 35  benzene
#> 36  toluene
#> 37  ethylbenzene
#> 38  o-xylene
#> 39  methanol
#> 40  methanethiol
#> 41  hydrogen
#> 42  water
#> 43  hydrogen sulphide
#> 44  ammonia
#> 45  hydrogen cyanide
#> 46  carbon monoxide
#> 47  carbonyl sulphide
#> 48  carbon disulphide
#> 49  helium
#> 50  neon
#> 51  argon
#> 52  nitrogen
#> 53  oxygen
#> 54  carbon dioxide
#> 55  sulphur dioxide
#> 56  n-undecane
#> 57  n-dodecane
#> 58  n-tridecane
#> 59  n-tetradecane
#> 60  n-pentadecane

Further reading