Thermochemistry
Composition manipulation
The core functionality is provided through the Stoichiometry
structure:
WallyToolbox.Stoichiometry
— TypeCompound 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.
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.ChemicalCompound
— TypeA 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
The following methods and types are available for operation over compositions and elements.
WallyToolbox.element
— FunctionRetrieve an element by name.
WallyToolbox.atomicmass
— FunctionAtomic mass of element [kg/mol].
WallyToolbox.molecularmass
— FunctionMolecular mass of compound [kg/mol].
WallyToolbox.ElementData
— TypeRepresents a chemical element.
WallyToolbox.ElementalQuantity
— TypeRepresents a pair of element symbol and associated amount.
WallyToolbox.density
— FunctionEvaluates the density of material [kg/m³].
WallyToolbox.specific_heat
— FunctionEvaluates the specific heat of materials [J/(kg.K)].
WallyToolbox.enthalpy
— FunctionEvaluates the enthalpy of material [J/kg].
WallyToolbox.entropy
— FunctionEvaluates the entropy of material [J/K].
Hard-coded substances
WallyToolbox.PureAir
— TypeSimple implementation of pure air for illustration purposes.
WallyToolbox.PureMineral
— TypeSimple solid mineral material for illustration purposes.
WallyToolbox.PureWater
— TypeSimple implementation of liquid water for illustration purposes.
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.
WallyToolbox.LaurentPolynomialProperties
— TypeThermodynamic properties represeted by Laurent polynomials.
WallyToolbox.MaierKelleyThermo
— TypeThermodynamic properties represeted in Maier-Kelley formalism.
This is a special case of LaurentPolynomialProperties
.
WallyToolbox.ShomateThermo
— TypeThermodynamic properties represeted in Shomate formalism.
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.EmpiricalFuel
— TypeProvides 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)"
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_rate
— Functionoxidizer_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
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_formula
— Functionhfo_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.
WallyToolbox.hfo_specific_heat
— Functionhfo_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.
WallyToolbox.hfo_enthalpy_net_bs2869
— Functionhfo_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
Discrete phase model
WallyToolbox.RosinRammlerDroplet
— TypeEvaluate 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...
WallyToolbox.fit_rosinrammler
— Functionfit_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.
WallyToolbox.plot_rosinrammler
— FunctionDisplay Rosin-Rammler distribution and optionally reference data.