Thermochemistry

Composition manipulation

The core functionality is provided through the Stoichiometry structure:

WallyToolbox.StoichiometryType

Compound stoichiometry for ease of data manipulation.

This type provide a simple interface for declaring chemical compounds from stable ELEMENTS and computing molecular masses. Its main use is intended for compound creation during parsing of thermodynamic databases. Below we illustrate the creation of compounds and the algebra of creation of derived compounds.

julia> al2o3 = Stoichiometry(Al=2, O=3)
Stoichiometry(Pair{Symbol, <:Number}[:Al => 2, :O => 3])

julia> molecularmass(al2o3)
0.1019600768

julia> ca1o1 = Stoichiometry(Ca=1, O=1)
Stoichiometry(Pair{Symbol, <:Number}[:Ca => 1, :O => 1])

julia> c1a2 = ca1o1 + 2 * al2o3
Stoichiometry(Pair{Symbol, <:Number}[:Al => 4, :Ca => 1, :O => 7])

julia> molecularmass(c1a2)
0.25999715360000003

Please notice that ChemicalCompound creation should be done as early as possible as Stoichiometry has no state other than the number of atoms. Its recurrent use may lead to high computational cost for the evaluation of molecular masses.

source

Once the composition of a compound has been set with Stoichiometry, the preferred method of working is through the creation of a ChemicalCompound, as follows:

WallyToolbox.ChemicalCompoundType

A chemical compound with internal values pre-computed for recurrent use.

julia> al2o3 = Stoichiometry(Al=2, O=3);

julia> ca1o1 = Stoichiometry(Ca=1, O=1);

julia> CA = ChemicalCompound(ca1o1 + al2o3);

julia> molecularmass(CA)
0.1580370768
source

The following methods and types are available for operation over compositions and elements.

Hard-coded substances

Thermodynamic properties

Materials properties are often reported according to the formalism of MaierKelley1932 [1] or Shomate1954 [2]. To be able to handle data under these formats, the following structures are provided.

Empirical fuels

In industrial practice of CFD one is often confronted with simulating empirical fuels. This is how one generally calls a fuel provided in elemental mass fractions of elements and is the most common reporting format for heavy-fuel oil. Using EmpiricalFuel one can quickly perform conversions and find out the required air flow rate for setting up a process simulation or furnace operation.

WallyToolbox.EmpiricalFuelType

Provides description of an empirical fuel based on elemental mass fractions.

Fields

  • elements::Vector{Symbol}: Chemical elements reported in fuel.

  • Y::Vector{Float64}: Array of provided masses per kilogram of fuel.

  • X::Vector{Float64}: Array of computed moles per kilogram of fuel.

Examples

Below we illustrate how to create a fuel with the approximate mass fractions of carbon and hydrogen in naphtalene; next we check its string representation.

julia> fuel = EmpiricalFuel([0.937, 0.063, 0.0]; scaler=:C=>10.0);

julia> fuel.X
3-element Vector{Float64}:
 10.0
  8.011606189967983
  0.0

julia> String(fuel)
"C(10.000000)H(8.011606)O(0.000000)"
source

A simple empirical fuel complete combustion can be represented by the following chemical equation:

\[1\:\mathrm{C}_x\mathrm{H}_y\mathrm{O}_z + a\:\mathrm{O}_2 + b\:\mathrm{N}_2 \rightarrow x\:\mathrm{CO}_2 + \dfrac{y}{2}\:\mathrm{H}_2\mathrm{O} + b\:\mathrm{N}_2\]

Because for HFO representation will generally provide sulfur and nitrogen, the oxidation of these elements may be included in the balance and the previous reaction can be modified to:

\[1\:\mathrm{C}_x\mathrm{H}_y\mathrm{O}_z\mathrm{N}_n\mathrm{S}_s + a\:\mathrm{O}_2 + b\:\mathrm{N}_2 % \rightarrow % x\:\mathrm{CO}_2 + s\:\mathrm{SO}_2 + n\:\mathrm{NO} + \dfrac{y}{2}\:\mathrm{H}_2\mathrm{O} + b\:\mathrm{N}_2\]

Each element in carbon, hydrogen, sulfur, and nitrogen is present in a single oxide (here we assume $\mathrm{N}_2$ does not participate in oxidation, what would require equilibrium calculations with an enthalpy of formation of the empirical fuel that is generally unavailable - otherwise we would use the actual molecular representation of the substance), and balancing the right-hand side of the equation is trivial; one can derive the value of $a$ that remains compatible with oxygen content in fuel as:

\[a = \dfrac{1}{2}\left(2x+2s+n+\dfrac{y}{2}-z\right)\]

With this value it is trivial to find out the required mass flow rate of oxidizer. This is implemented in oxidizer_mass_flow_rate as documented below. Notice that this function will fail if one of the required elements in the above equation is missing. The presence of nitrogen oxides and sulfur is fuel is neglected in this calculations and one must assess whether they should be considered in a certain analysis prior to using this function.

WallyToolbox.oxidizer_mass_flow_rateFunction
oxidizer_mass_flow_rate(
    f::EmpiricalFuel; 
    y_o2 = 0.23, 
    burn_nitrogen = false
)

Computes the required amount of oxidizer to perform complete combustion of 1 kg provided empirical fuel. The value of y_o2 represents the mass fraction of oxygen in oxidizer; default value is typical for air.

julia> fuel = EmpiricalFuel([0.937, 0.063, 0.0]; scaler=:C=>10);

julia> oxidizer_mass_flow_rate(fuel; burn_nitrogen = true)
13.02691759229764

For simple compositions (in relative molar quantities) one can use the more straightforward interface illustrated below:

julia> oxidizer_mass_flow_rate(C=1, H=4, y_o2=1.0)
3.989029483263729
source

Heavy fuel-oils

Combustion of heavy-fuel oils (HFO) is discussed in detail by Lawn1987 [3]. Some relations that might be useful for the industrial combustion specialist are under implementation here to be integrated in larger models e.g. using flowsheets, or simple calculations.

WallyToolbox.hfo_empirical_formulaFunction
hfo_empirical_formula(Y; scaler = nothing)

Wrapper for EmpiricalFuel ensuring all HFO instances are created with all typical elements, say C, H, O, N, and S, provided in this same order.

source
WallyToolbox.hfo_specific_heatFunction
hfo_specific_heat(T::Float64, S::Float64)::Float64

Heavy fuel-oil specific heat estimation in terms of relative density $S$ as provided by Cragoe (1929). Temperature in kelvin.

source
WallyToolbox.hfo_enthalpy_net_bs2869Function
hfo_enthalpy_net_bs2869(;
    ρ::Float64,
    x::Float64,
    y::Float64,
    s::Float64
)::Float64

Heavy fuel-oil net energy capacity accordinto to BS2869:1983. Value is computed in [MJ/kg]. Parameters are given as:

  • ρ: HFO density at 15 °C, [kg/m³].
  • water: Mass percentage of water, [%].
  • ash: Mass percentage of ashes, [%].
  • sulphur: Mass percentage of sulphur, [%].
julia> hfo_enthalpy_net_bs2869(; ρ = 1020.0, water = 0.1, ash = 0.05, sulphur = 1.0)
40.13509836320001
source

Discrete phase model

WallyToolbox.RosinRammlerDropletType

Evaluate practical values for using Rosin-Rammler distribution in CFD.

Fields

  • vavg::Float64: Droplet average size [μm].

  • vmin::Float64: Droplet minimum size [μm].

  • vmax::Float64: Droplet maximum size [μm].

  • m::Float64: Distribution spread characteristic exponent.

  • θ::Float64: Distribution characteristic droplet size [μm].

Examples

Upcoming...

source
WallyToolbox.fit_rosinrammlerFunction
fit_rosinrammler(d₀, P₀; m=3.5)

Find parameter for particle size distribution with Weibull distribution, often called after Rosin-Rammler in the field of particles - based on characteristic size and associated cumulative density function (CDF) value. Parameter d₀ is the droplet size at which Weibull CDF evaluates to probability P₀. The value of m is generally recommended for a certain technology; a common value is provided by default.

source