Chemical systems and states
ChemistryLab.ChemicalStateChemistryLab.ChemicalStateChemistryLab.ChemicalStateChemistryLab.ChemicalSystemChemistryLab.ChemicalSystemChemistryLab.ChemicalSystemChemistryLab.PhaseQuantitiesBase.:*Base.:*Base.:+Base.:/Base.copyBase.getindexBase.getindexBase.mergeBase.mergeBase.showBase.showBase.sizeChemistryLab._auto_seed_neutral_pH!ChemistryLab._compute_V_phasesChemistryLab._compute_m_phasesChemistryLab._compute_n_phasesChemistryLab._compute_pHChemistryLab._compute_pKwChemistryLab._compute_pOHChemistryLab._compute_porosityChemistryLab._compute_saturationChemistryLab._entry_to_molesChemistryLab._has_molar_volumeChemistryLab._molar_volumeChemistryLab._update_derived!ChemistryLab.aqueousChemistryLab.componentsChemistryLab.crystalChemistryLab.gasChemistryLab.gasfluidChemistryLab.get_reactionChemistryLab.kinetic_speciesChemistryLab.massChemistryLab.massChemistryLab.massChemistryLab.molesChemistryLab.molesChemistryLab.molesChemistryLab.pHChemistryLab.pOHChemistryLab.porosityChemistryLab.pressureChemistryLab.rescale!ChemistryLab.saturationChemistryLab.set_neutral_pH!ChemistryLab.set_pressure!ChemistryLab.set_quantity!ChemistryLab.set_quantity!ChemistryLab.set_temperature!ChemistryLab.solid_solutionsChemistryLab.solutesChemistryLab.solventChemistryLab.temperatureChemistryLab.volumeChemistryLab.volumeChemistryLab.volume
ChemicalSystem
ChemistryLab.ChemicalSystem — Type
struct ChemicalSystem{T<:AbstractSpecies, R<:AbstractReaction, C, S, SS} <: 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.solid_solutions:Nothingwhen no solid solutions are present, or a concreteVector{<:AbstractSolidSolutionPhase}describing each solid-solution phase and its end-members. Populated via thesolid_solutionskeyword constructor.ss_groups: for each solid solution, the indices of its end-members inspecies.idx_ssendmembers: union of all end-member indices (flattenedss_groups).idx_kinetic: indices of kinetic species (empty when none declared).
ChemistryLab.ChemicalSystem — Method
ChemicalSystem(species, primaries=species; kinetic_species, solid_solutions) -> ChemicalSystemConstruct a fully typed ChemicalSystem from a vector of species, an optional vector of primary species, optional kinetic species with rates, and optional solid-solution phases.
All derived fields are computed once at construction time and remain consistent for the lifetime of the object.
Arguments
species: vector ofAbstractSpecies.primaries: subset used as independent components (default: all species).kinetic_species:nothing(default) or a dictionary / vector of pairs mapping each kinetic species (by nameStringorSpeciesobject) to its rate function. Rate functions must be callable as(T, P, t, n, lna, n_initial) → Real [mol/s](seeKineticFunc). The rate is given per mole of kinetic species (stoichiometric coefficient = 1); the constructor corrects by1/|νₖ|automatically. When provided, the nullspace N of the stoichiometric matrix is diagonalised so that each kinetic species appears in exactly one reaction. Those reactions are stored in thereactionsfield with their rate attached viarxn[:rate].solid_solutions: vector ofSolidSolutionPhase(default:nothing). When provided, end-members must already appear inspecies(matched by symbol) and must carryaggregate_state = AS_CRYSTALandclass = SC_SSENDMEMBER.
Examples
julia> sp = [
Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT),
Species("Na+"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLUTE),
];
julia> cs = ChemicalSystem(sp);
julia> length(cs)
2
julia> cs["H2O"] == sp[1]
truejulia> em1 = Species("AFm1"; aggregate_state=AS_CRYSTAL, class=SC_SSENDMEMBER);
julia> em2 = Species("AFm2"; aggregate_state=AS_CRYSTAL, class=SC_SSENDMEMBER);
julia> ss = SolidSolutionPhase("AFm", [em1, em2]);
julia> cs = ChemicalSystem([em1, em2]; solid_solutions=[ss]);
julia> cs.ss_groups
1-element Vector{Vector{Int64}}:
[1, 2]
julia> cs.idx_ssendmembers
2-element Vector{Int64}:
1
2ChemistryLab.ChemicalSystem — Method
ChemicalSystem(species, primaries::AbstractVector{<:AbstractString}; kinetic_species, solid_solutions) -> ChemicalSystemConvenience constructor that resolves primary species from their symbol strings.
Examples
julia> sp = [
Species("H2O"; aggregate_state=AS_AQUEOUS),
Species("NaCl"; aggregate_state=AS_CRYSTAL),
];
julia> cs = ChemicalSystem(sp, ["H2O"]);
julia> symbol.(cs.SM.primaries)
1-element Vector{String}:
"H2O"Base.getindex — Method
Base.getindex(cs::ChemicalSystem, i::AbstractString) -> AbstractSpeciesReturn the species whose symbol matches i. Runs in O(1) via dict_species.
Examples
julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS)]);
julia> cs["H2O"] == Species("H2O"; aggregate_state=AS_AQUEOUS)
trueBase.getindex — Method
Base.getindex(cs::ChemicalSystem, i::Int) -> AbstractSpeciesReturn the species at position i.
Examples
julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS)]);
julia> cs[1] == Species("H2O"; aggregate_state=AS_AQUEOUS)
trueBase.merge — Method
Base.merge(cs1::ChemicalSystem, cs2::ChemicalSystem) -> ChemicalSystemConstruct a new ChemicalSystem from the union of two systems.
Species and reactions are unioned by symbol — duplicates from cs2 are discarded. CSM and SM are built from scratch from the full species list. Primaries are taken as the union of both systems' primaries, filtered to those actually present in the merged species list.
In case of symbol conflict (species or reactions), cs1 takes priority over cs2. The return type is inferred from the merged collections and may differ from typeof(cs1) or typeof(cs2) if they contain different concrete types.
Examples
julia> cs1 = ChemicalSystem(
[Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT),
Species("H+"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLUTE)],
);
julia> cs2 = ChemicalSystem(
[Species("OH-"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLUTE),
Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)],
);
julia> cs = merge(cs1, cs2);
julia> length(cs)
3Base.merge — Method
Base.merge(css::ChemicalSystem...) -> ChemicalSystemConstruct a new ChemicalSystem from the union of an arbitrary number of systems, processed left-to-right. Earlier systems take priority over later ones in case of symbol conflicts.
Examples
julia> cs1 = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);
julia> cs2 = ChemicalSystem([Species("H+"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLUTE)]);
julia> cs3 = ChemicalSystem([Species("OH-"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLUTE)]);
julia> cs = merge(cs1, cs2, cs3);
julia> length(cs)
3ChemistryLab.aqueous — Method
aqueous(cs::ChemicalSystem) -> SubArrayReturn 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
trueChemistryLab.components — Method
components(cs::ChemicalSystem) -> SubArrayReturn 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
trueChemistryLab.crystal — Method
crystal(cs::ChemicalSystem) -> SubArrayReturn 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
trueChemistryLab.gas — Method
gas(cs::ChemicalSystem) -> SubArrayReturn 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
trueChemistryLab.gasfluid — Method
gasfluid(cs::ChemicalSystem) -> SubArrayReturn 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
trueChemistryLab.get_reaction — Method
get_reaction(cs::ChemicalSystem, sym::AbstractString) -> AbstractReactionReturn the reaction identified by symbol sym. Runs in O(1) via dict_reactions.
Examples
cs = ChemicalSystem(
[Species("H2O"; aggregate_state=AS_AQUEOUS)];
);
get_reaction(cs, "some_rxn") # returns the Reaction with that symbolChemistryLab.kinetic_species — Method
kinetic_species(cs::ChemicalSystem) -> SubArrayReturn a view of the kinetic species declared at construction time. Empty when no kinetic species were declared.
ChemistryLab.solid_solutions — Method
solid_solutions(cs::ChemicalSystem) -> Nothing | Vector{<:AbstractSolidSolutionPhase}Return the registered solid-solution phases, or nothing if none were declared.
Examples
julia> em1 = Species("Em1"; aggregate_state=AS_CRYSTAL, class=SC_SSENDMEMBER);
julia> em2 = Species("Em2"; aggregate_state=AS_CRYSTAL, class=SC_SSENDMEMBER);
julia> cs = ChemicalSystem(
[em1, em2];
solid_solutions=[SolidSolutionPhase("SS", [em1, em2])],
);
julia> solid_solutions(cs) isa Vector
true
julia> length(solid_solutions(cs))
1ChemistryLab.solutes — Method
solutes(cs::ChemicalSystem) -> SubArrayReturn 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
trueChemistryLab.solvent — Method
solvent(cs::ChemicalSystem) -> AbstractSpeciesReturn 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
trueChemicalState
ChemistryLab.ChemicalState — Type
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 underlyingChemicalSystem.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)—PhaseQuantities{Q}.m_phases: mass per phase(liquid, solid, gas, total)—PhaseQuantities{Q}.V_phases: volume per phase(liquid, solid, gas, total)—PhaseQuantities{Q}.pH: pH of the liquid phase, ornothingif H⁺ is absent —Float64 | Nothing.pOH: pOH of the liquid phase, ornothingif OH⁻ is absent —Float64 | Nothing.porosity:(V_liquid + V_gas) / V_total, orNaNif volumes unavailable —Float64.saturation:V_liquid / (V_liquid + V_gas), orNaNif pore volume is zero —Float64.
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.15ChemistryLab.ChemicalState — Method
ChemicalState(system::ChemicalSystem, values::AbstractVector; T, P) -> ChemicalStateConstruct a ChemicalState with explicit initial amounts or masses. Each entry is converted to moles independently — mixed units allowed.
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", 5.844u"g"]);
julia> ustrip(moles(state, "H2O"))
55.5
julia> isapprox(ustrip(moles(state, "NaCl")), 0.1; rtol=1e-4)
trueChemistryLab.ChemicalState — Method
ChemicalState(system::ChemicalSystem; T, P, n) -> ChemicalStateConstruct a ChemicalState from a ChemicalSystem with optional initial temperature, pressure, and molar amounts (default: all zero).
Arguments
system: theChemicalSystemdescribing the species.T: temperature in K (default:298.15u"K").P: pressure (default:1u"bar").n: molar amounts in mol (default: zeros).
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> ustrip(state.T[])
298.15
julia> ustrip(state.P[]) ≈ 1e5
true
julia> all(iszero.(ustrip.(state.n)))
trueChemistryLab.PhaseQuantities — Type
PhaseQuantities{Q}Named tuple type alias (liquid::Q, solid::Q, gas::Q, total::Q) for phase-aggregated quantities (moles, mass, or volume).
Each field holds the total of the corresponding thermodynamic phase. Q is typically an AbstractQuantity carrying SI units (mol, kg, or m³).
Base.:* — Method
Base.:*(state::ChemicalState, α::Real) -> ChemicalStateReturn a new ChemicalState with all molar amounts scaled by α. Temperature, pressure, and the underlying ChemicalSystem are unchanged. The operation is non-mutating — a copy is returned.
Examples
julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);
julia> state = ChemicalState(cs, [2.0u"mol"]);
julia> s2 = state * 3.0;
julia> ustrip(moles(s2, "H2O"))
6.0
julia> ustrip(moles(state, "H2O")) # original unchanged
2.0Base.:+ — Method
Base.:+(s1::ChemicalState, s2::ChemicalState) -> ChemicalStateCombine two chemical states by adding their species amounts.
- Same system (
s1.system === s2.system): the result shares the system reference. - Different systems: a merged system is created via
merge(s1.system, s2.system)(union of species,s1takes priority for duplicates). - T, P: taken from
s1. A warning is emitted ifs2has different T or P. - Derived quantities (pH, volumes, …) are recomputed from the summed moles.
Examples
julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);
julia> s1 = ChemicalState(cs, [2.0u"mol"]);
julia> s2 = ChemicalState(cs, [3.0u"mol"]);
julia> ustrip(moles(s1 + s2, "H2O"))
5.0Base.:/ — Method
Base.:/(state::ChemicalState, α::Real) -> ChemicalStateReturn a new ChemicalState with all molar amounts divided by α. The operation is non-mutating — a copy is returned.
Examples
julia> cs = ChemicalSystem([Species("H2O"; aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)]);
julia> state = ChemicalState(cs, [4.0u"mol"]);
julia> s = state / 2.0;
julia> ustrip(moles(s, "H2O"))
2.0Base.copy — Method
Base.copy(state::ChemicalState) -> ChemicalStateCreate a clone of a ChemicalState that shares the same ChemicalSystem reference but owns independent copies of all mutable fields.
Modifying the clone does not affect the original, and vice versa. The underlying ChemicalSystem is not duplicated.
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, [55.5u"mol", 0.1u"mol"]);
julia> clone = copy(state);
julia> set_quantity!(clone, "Na+", 0.5u"mol");
julia> ustrip(moles(state, "Na+"))
0.1
julia> ustrip(moles(clone, "Na+"))
0.5
julia> clone.system === state.system
trueChemistryLab._auto_seed_neutral_pH! — Method
_auto_seed_neutral_pH!(state::ChemicalState)When the aqueous solvent (H₂O@) is present with non-zero amount and both H⁺ and OH⁻ are in the system at zero/negligible concentration, seed them at the neutral pH concentration $c = 10^{-pK_w/2}$ [mol/L] using the T- and P-dependent water autoprotolysis constant.
Does nothing if any of the three species is absent, if H⁺ or OH⁻ already have non-negligible amounts (i.e. the user set them explicitly), or if pKw cannot be computed.
ChemistryLab._compute_V_phases — Method
_compute_V_phases(system, n, T, P) -> NamedTupleCompute volume per phase from n, T, P and standard molar volumes V⁰. Gas phase falls back to ideal gas law if V⁰ is not available for all gas species.
ChemistryLab._compute_m_phases — Method
_compute_m_phases(system, n) -> NamedTupleCompute mass per phase from species vector n and molar masses.
ChemistryLab._compute_n_phases — Method
_compute_n_phases(system, n) -> NamedTupleCompute moles per phase from species vector n.
ChemistryLab._compute_pH — Method
_compute_pH(system, n, V_liquid) -> Union{Float64, Nothing}Compute pH using the most reliable species between H⁺ and OH⁻.
- If cH⁺ ≥ cOH⁻: pH = -log10(c_H⁺)
- If cOH⁻ > cH⁺: pOH = -log10(c_OH⁻), then pH = pKw(T) - pOH
pKw(T) is retrieved from the reaction H2O = H+ + OH- in the system's reaction dictionary, evaluated at the current T and P. Returns nothing if neither H⁺ nor OH⁻ is present, or if liquid volume is zero.
ChemistryLab._compute_pKw — Method
_compute_pKw(system::ChemicalSystem, T, P) -> Union{Float64, Nothing}Compute pKw = -logK⁰(T, P) for the water dissociation reaction H2O@ = H+ + OH- reconstructed on the fly from the species present in system.
Returns nothing if any of H2O@, H+, or OH- is absent from the system.
ChemistryLab._compute_pOH — Method
_compute_pOH(system, n, T, P, V_liquid) -> Union{Float64, Nothing}Compute pOH symmetrically to _compute_pH:
- If cOH⁻ ≥ cH⁺: pOH = -log10(c_OH⁻)
- If cH⁺ > cOH⁻: pH = -log10(c_H⁺), then pOH = pKw(T) - pH
Returns nothing if neither species is present or volume is zero.
ChemistryLab._compute_porosity — Method
_compute_porosity(V_phases) -> Float64Compute porosity = (Vliquid + Vgas) / V_total. Returns NaN if total volume is zero.
ChemistryLab._compute_saturation — Method
_compute_saturation(V_phases) -> Float64Compute saturation = Vliquid / (Vliquid + V_gas). Returns NaN if pore volume is zero.
ChemistryLab._entry_to_moles — Method
_entry_to_moles(v::AbstractQuantity, s::AbstractSpecies) -> AbstractQuantityConvert a single value v to moles for species s. If v has amount dimension (mol), it is returned as-is. If v has mass dimension, it is divided by the molar mass M of s. Otherwise an error is raised.
ChemistryLab._has_molar_volume — Method
_has_molar_volume(s::AbstractSpecies) -> BoolReturn true if species s has a standard molar volume V⁰ available.
ChemistryLab._molar_volume — Method
_molar_volume(s::AbstractSpecies) -> SymbolicFuncReturn the standard molar volume SymbolicFunc of species s. Must be called as _molar_volume(s)(T=T, P=P; unit=true) to get a quantity.
ChemistryLab._update_derived! — Method
_update_derived!(state::ChemicalState)Recompute and update in place all derived quantities after any mutation of n, T, or P. Called automatically by set_quantity!, set_temperature!, and set_pressure!.
ChemistryLab.mass — Method
mass(state::ChemicalState, s::AbstractSpecies) -> AbstractQuantityReturn 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
trueChemistryLab.mass — Method
mass(state::ChemicalState, sym::AbstractString) -> AbstractQuantityReturn 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
trueChemistryLab.mass — Method
mass(state::ChemicalState) -> NamedTupleReturn 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
trueChemistryLab.moles — Method
moles(state::ChemicalState, s::AbstractSpecies) -> AbstractQuantityReturn 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.5ChemistryLab.moles — Method
moles(state::ChemicalState, sym::AbstractString) -> AbstractQuantityReturn 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.5ChemistryLab.moles — Method
moles(state::ChemicalState) -> NamedTupleReturn 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.5ChemistryLab.pH — Method
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}
trueChemistryLab.pOH — Method
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}
trueChemistryLab.porosity — Method
porosity(state::ChemicalState) -> Float64Return the porosity (V_liquid + V_gas) / V_total, or NaN if total volume is zero (no molar volumes available).
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 Float64
trueChemistryLab.pressure — Method
pressure(state::ChemicalState) -> AbstractQuantityReturn 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)
trueChemistryLab.rescale! — Method
rescale!(state::ChemicalState, target::AbstractQuantity) -> ChemicalStateScale all molar amounts in-place so that the total quantity of the matching physical dimension equals target.
target dimension | Quantity brought to target |
|---|---|
| mol | moles(state).total |
| kg (mass) | mass(state).total |
| m³ (volume) | volume(state).total |
All derived quantities (pH, volume, porosity, …) are recomputed after scaling. Returns state for chaining.
Examples
rescale!(state, 1.0u"mol") # total moles → 1 mol
rescale!(state, 1.0u"kg") # total mass → 1 kg
rescale!(state, 1.0u"m^3") # total volume → 1 m³
rescale!(state, 500u"g") # total mass → 500 gChemistryLab.saturation — Method
saturation(state::ChemicalState) -> Float64Return the saturation V_liquid / (V_liquid + V_gas), or NaN 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 Float64
trueChemistryLab.set_neutral_pH! — Method
set_neutral_pH!(state::ChemicalState) -> ChemicalStateSet H⁺ and OH⁻ concentrations to neutral pH at the current temperature and pressure, using the water autoprotolysis constant $K_w(T, P)$:
\[[\text{H}^+] = [\text{OH}^-] = 10^{-pK_w/2} \quad [\text{mol/L}]\]
Requires the system to contain H2O@ (solvent), H+, and OH-. The liquid volume is estimated from the current water amount.
Unlike _auto_seed_neutral_pH! (which only triggers when H⁺/OH⁻ are zero), this function always overwrites the current values — useful inside loops where the state is reused across iterations.
Examples
set_quantity!(s, "H2O@", 1.0u"kg")
set_neutral_pH!(s) # H⁺ and OH⁻ at neutral, T/P-dependentChemistryLab.set_pressure! — Method
set_pressure!(state::ChemicalState, P::AbstractQuantity) -> ChemicalStateSet 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)
trueChemistryLab.set_quantity! — Method
set_quantity!(state::ChemicalState, s::AbstractSpecies, n::AbstractQuantity) -> ChemicalStateSet 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.0ChemistryLab.set_quantity! — Method
set_quantity!(state::ChemicalState, sym::AbstractString, n::AbstractQuantity) -> ChemicalStateSet 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.0ChemistryLab.set_temperature! — Method
set_temperature!(state::ChemicalState, T::AbstractQuantity) -> ChemicalStateSet 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.0ChemistryLab.temperature — Method
temperature(state::ChemicalState) -> AbstractQuantityReturn 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.15ChemistryLab.volume — Method
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}
trueChemistryLab.volume — Method
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}
trueChemistryLab.volume — Method
volume(state::ChemicalState) -> NamedTupleReturn 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