Chemical systems and states

ChemicalSystem

ChemistryLab.ChemicalSystemType
struct ChemicalSystem{T<:AbstractSpecies, R<:AbstractReaction, C, S} <: AbstractVector{T}

An immutable, fully typed collection of chemical species and reactions with derived index structures and stoichiometric matrices.

Immutability guarantees that all derived fields (dict_species, dict_reactions, index vectors, CSM, SM) remain consistent with species and reactions throughout the lifetime of the object. To modify the system, use merge to construct a new ChemicalSystem.

Fields

  • species: ordered list of all species.
  • dict_species: fast O(1) lookup by species symbol.
  • idx_aqueous, idx_crystal, idx_gas: indices by aggregate state.
  • idx_solutes, idx_solvent, idx_components, idx_gasfluid: indices by class.
  • reactions: ordered list of all reactions.
  • dict_reactions: fast O(1) lookup by reaction symbol.
  • CSM: canonical stoichiometric matrix.
  • SM: stoichiometric matrix with respect to primaries.
source
ChemistryLab.aqueousFunction
aqueous(cs::ChemicalSystem) -> SubArray

Return a view of all aqueous species.

Examples

julia> cs = ChemicalSystem([
           Species("H2O";  aggregate_state=AS_AQUEOUS),
           Species("NaCl"; aggregate_state=AS_CRYSTAL),
       ]);

julia> length(aqueous(cs))
1

julia> aggregate_state(aqueous(cs)[1]) == AS_AQUEOUS
true
source
ChemistryLab.crystalFunction
crystal(cs::ChemicalSystem) -> SubArray

Return a view of all crystalline species.

Examples

julia> cs = ChemicalSystem([
           Species("H2O";  aggregate_state=AS_AQUEOUS),
           Species("NaCl"; aggregate_state=AS_CRYSTAL),
       ]);

julia> aggregate_state(crystal(cs)[1]) == AS_CRYSTAL
true
source
ChemistryLab.gasFunction
gas(cs::ChemicalSystem) -> SubArray

Return a view of all gas-phase species.

Examples

julia> cs = ChemicalSystem([Species("CO2"; aggregate_state=AS_GAS)]);

julia> aggregate_state(gas(cs)[1]) == AS_GAS
true
source
ChemistryLab.solutesFunction
solutes(cs::ChemicalSystem) -> SubArray

Return a view of all aqueous solute species.

Examples

julia> cs = ChemicalSystem([Species("Na+"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLUTE)]);

julia> class(solutes(cs)[1]) == SC_AQSOLUTE
true
source
ChemistryLab.solventFunction
solvent(cs::ChemicalSystem) -> AbstractSpecies

Return the unique solvent species directly (not a view), since a chemical system contains at most one solvent.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> class(solvent(cs)) == SC_AQSOLVENT
true
source
ChemistryLab.componentsFunction
components(s::Species) -> OrderedDict{Symbol,Number}

Return the components of a Species (atomic composition with charge).

source
components(s::CemSpecies) -> OrderedDict{Symbol,Number}

Return the components of a CemSpecies (oxide composition with charge).

source
components(cs::ChemicalSystem) -> SubArray

Return a view of all component species.

Examples

julia> cs = ChemicalSystem([Species("SiO2"; aggregate_state=AS_CRYSTAL, class=SC_COMPONENT)]);

julia> class(components(cs)[1]) == SC_COMPONENT
true
source
ChemistryLab.gasfluidFunction
gasfluid(cs::ChemicalSystem) -> SubArray

Return a view of all gas/fluid species.

Examples

julia> cs = ChemicalSystem([Species("CO2"; aggregate_state=AS_GAS, class=SC_GASFLUID)]);

julia> class(gasfluid(cs)[1]) == SC_GASFLUID
true
source
ChemistryLab.get_reactionFunction
get_reaction(cs::ChemicalSystem, sym::AbstractString) -> AbstractReaction

Return the reaction identified by symbol sym. Runs in O(1) via dict_reactions.

Examples

julia> cs = ChemicalSystem(
           [Species("H2O"; aggregate_state=AS_AQUEOUS)];
           reactions=[Reaction("H2O = H+ + OH-"; symbol="water_diss")],
       );

julia> symbol(get_reaction(cs, "water_diss"))
"water_diss"
source

ChemicalState

ChemistryLab.ChemicalStateType
struct ChemicalState{C, S, Q<:AbstractQuantity}

Immutable container holding the thermodynamic state of a ChemicalSystem.

Molar amounts are always stored internally in mol regardless of the input unit. Each species can be provided independently as a molar amount (mol) or as a mass (g, kg, etc.) — the constructor converts each entry individually using the molar mass M stored in the corresponding species.

The struct itself is immutable — fields cannot be reassigned. However, n, T, and P are stored as Vector to allow in-place mutation via set_quantity!, set_temperature!, and set_pressure!.

system is a shared reference: cloning via Base.copy does not duplicate the underlying ChemicalSystem.

Fields

  • system: reference to the underlying ChemicalSystem.
  • n: molar amounts (mol), one per species — mutable in place.
  • T: temperature (K) — 1-element Vector, mutable in place.
  • P: pressure (Pa) — 1-element Vector, mutable in place.
  • n_phases: moles per phase (liquid, solid, gas, total).
  • m_phases: mass per phase (liquid, solid, gas, total).
  • V_phases: volume per phase (liquid, solid, gas, total).
  • pH: pH of the liquid phase, or nothing if H⁺ is absent.
  • pOH: pOH of the liquid phase, or nothing if OH⁻ is absent.
  • porosity: (V_liquid + V_gas) / V_total, or nothing if volumes unavailable.
  • saturation: V_liquid / (V_liquid + V_gas), or nothing if pore volume is zero.

Examples

julia> cs = ChemicalSystem([
           Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT),
           Species("Na+"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLUTE),
       ]);

julia> state = ChemicalState(cs; T=298.15u"K", P=1u"bar");

julia> length(state.n)
2

julia> ustrip(state.T[])
298.15
source
ChemistryLab.temperatureFunction
temperature(state::ChemicalState) -> AbstractQuantity

Return the current temperature.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs; T=298.15u"K", P=1u"bar");

julia> ustrip(temperature(state))
298.15
source
ChemistryLab.pressureFunction
pressure(state::ChemicalState) -> AbstractQuantity

Return the current pressure.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs; T=298.15u"K", P=1u"bar");

julia> isapprox(ustrip(pressure(state)), 1e5; rtol=1e-4)
true
source
ChemistryLab.set_temperature!Function
set_temperature!(state::ChemicalState, T::AbstractQuantity) -> ChemicalState

Set the temperature in place and update all derived quantities.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs; T=298.15u"K", P=1u"bar");

julia> set_temperature!(state, 350.0u"K");

julia> ustrip(temperature(state))
350.0
source
ChemistryLab.set_pressure!Function
set_pressure!(state::ChemicalState, P::AbstractQuantity) -> ChemicalState

Set the pressure in place and update all derived quantities.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs; T=298.15u"K", P=1u"bar");

julia> set_pressure!(state, 2u"bar");

julia> isapprox(ustrip(pressure(state)), 2e5; rtol=1e-4)
true
source
ChemistryLab.molesFunction
moles(state::ChemicalState) -> NamedTuple

Return moles per phase (liquid, solid, gas, total).

Examples

julia> cs = ChemicalSystem([
           Species("H2O";  aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT),
           Species("NaCl"; aggregate_state=AS_CRYSTAL),
       ]);

julia> state = ChemicalState(cs, [55.5u"mol", 0.05u"mol"]);

julia> ustrip(moles(state).liquid)
55.5
source
moles(state::ChemicalState, s::AbstractSpecies) -> AbstractQuantity

Return the molar amount of species s in mol.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs, [55.5u"mol"]);

julia> ustrip(moles(state, cs[1]))
55.5
source
moles(state::ChemicalState, sym::AbstractString) -> AbstractQuantity

Return the molar amount of the species identified by symbol sym.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs, [55.5u"mol"]);

julia> ustrip(moles(state, "H2O"))
55.5
source
ChemistryLab.set_quantity!Function
set_quantity!(state::ChemicalState, s::AbstractSpecies, n::AbstractQuantity) -> ChemicalState

Set the molar amount of species s in place and update all derived quantities. If n has mass dimension, it is automatically converted to moles using M.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs, [55.5u"mol"]);

julia> set_quantity!(state, cs[1], 10.0u"mol");

julia> ustrip(moles(state, "H2O"))
10.0
source
set_quantity!(state::ChemicalState, sym::AbstractString, n::AbstractQuantity) -> ChemicalState

Set the molar amount of the species identified by symbol sym in place and update all derived quantities.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs, [55.5u"mol"]);

julia> set_quantity!(state, "H2O", 10.0u"mol");

julia> ustrip(moles(state, "H2O"))
10.0
source
ChemistryLab.massFunction
mass(state::ChemicalState) -> NamedTuple

Return mass per phase (liquid, solid, gas, total).

Examples

julia> cs = ChemicalSystem([
           Species("H2O";  aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT),
           Species("NaCl"; aggregate_state=AS_CRYSTAL),
       ]);

julia> state = ChemicalState(cs, [55.5u"mol", 0.05u"mol"]);

julia> mass(state).total isa AbstractQuantity
true
source
mass(state::ChemicalState, s::AbstractSpecies) -> AbstractQuantity

Return the mass of species s, computed as n × M.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs, [55.5u"mol"]);

julia> ustrip(uconvert(us"g", mass(state, cs[1]))) ≈ 55.5 * 18.015
true
source
mass(state::ChemicalState, sym::AbstractString) -> AbstractQuantity

Return the mass of the species identified by symbol sym.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs, [55.5u"mol"]);

julia> ustrip(uconvert(us"g", mass(state, "H2O"))) ≈ 55.5 * 18.015
true
source
ChemistryLab.volumeFunction
volume(state::ChemicalState) -> NamedTuple

Return volume per phase (liquid, solid, gas, total).

Examples

julia> cs = ChemicalSystem([
           Species("H2O";  aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT),
           Species("NaCl"; aggregate_state=AS_CRYSTAL),
       ]);

julia> state = ChemicalState(cs, [55.5u"mol", 0.05u"mol"]);

julia> volume(state).total isa AbstractQuantity
true
source
volume(state::ChemicalState, s::AbstractSpecies) -> Union{AbstractQuantity, Nothing}

Return the volume contribution of species s as n × V⁰(T,P). Returns nothing if V⁰ is not available for s.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs, [55.5u"mol"]);

julia> volume(state, cs[1]) isa Union{AbstractQuantity, Nothing}
true
source
volume(state::ChemicalState, sym::AbstractString) -> Union{AbstractQuantity, Nothing}

Return the volume contribution of the species identified by symbol sym. Returns nothing if V⁰ is not available.

Examples

julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);

julia> state = ChemicalState(cs, [55.5u"mol"]);

julia> volume(state, "H2O") isa Union{AbstractQuantity, Nothing}
true
source
ChemistryLab.pHFunction
pH(state::ChemicalState) -> Union{Float64, Nothing}

Return the pH of the liquid phase, or nothing if H⁺ is absent.

Examples

julia> cs = ChemicalSystem([
           Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT),
           Species("H+";  aggregate_state=AS_AQUEOUS, class=SC_AQSOLUTE),
       ]);

julia> state = ChemicalState(cs, [55.5u"mol", 1e-7u"mol"]);

julia> pH(state) isa Union{Float64, Nothing}
true
source
ChemistryLab.pOHFunction
pOH(state::ChemicalState) -> Union{Float64, Nothing}

Return the pOH of the liquid phase, or nothing if OH⁻ is absent.

Examples

julia> cs = ChemicalSystem([
           Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT),
           Species("OH-"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLUTE),
       ]);

julia> state = ChemicalState(cs, [55.5u"mol", 1e-7u"mol"]);

julia> pOH(state) isa Union{Float64, Nothing}
true
source
ChemistryLab.porosityFunction
porosity(state::ChemicalState) -> Union{Float64, Nothing}

Return the porosity (V_liquid + V_gas) / V_total, or nothing if total volume is zero.

Examples

julia> cs = ChemicalSystem([
           Species("H2O";  aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT),
           Species("NaCl"; aggregate_state=AS_CRYSTAL),
       ]);

julia> state = ChemicalState(cs, [55.5u"mol", 0.05u"mol"]);

julia> porosity(state) isa Union{Float64, Nothing}
true
source
ChemistryLab.saturationFunction
saturation(state::ChemicalState) -> Union{Float64, Nothing}

Return the saturation V_liquid / (V_liquid + V_gas), or nothing if pore volume is zero.

Examples

julia> cs = ChemicalSystem([
           Species("H2O";  aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT),
           Species("NaCl"; aggregate_state=AS_CRYSTAL),
       ]);

julia> state = ChemicalState(cs, [55.5u"mol", 0.05u"mol"]);

julia> saturation(state) isa Union{Float64, Nothing}
true
source