Stoichiometric Matrix
Get Stoichiometric Matrix from a list of species
Let's imagine that we want to form the stochiometric matrix of a list of solid and water species. For that, we need to read the database from which these species originate and retrieve the list of primary species from that database.
using ChemistryLab
using PrettyTables
df_elements, df_substances, df_reactions = read_thermofun("../../../data/cemdata18-merged.json")
df_primaries = extract_primary_species("../../../data/CEMDATA18-31-03-2022-phaseVol.dat")
See ChemistryLab.read_thermofun
and ChemistryLab.extract_primary_species
It is then necessary to identify the list of secondary species likely to appear during the reactions.
given_species = filter(row -> row.symbol ∈ split("C3S Portlandite Jennite H2O@"), df_substances)
secondaries = filter(row->row.aggregate_state == "AS_AQUEOUS"
&& all(k->first(k) ∈ union_atoms(atoms.(given_species.species)), atoms(row.species))
&& row.symbol ∉ split("H2@ O2@"),
df_substances)
We can then deduce the primary species concerned by the reaction.
all_species = unique(vcat(given_species, secondaries), :symbol)
species = [Species(f; symbol = phreeqc_to_unicode(n)) for (f, n) in zip(all_species.formula, all_species.symbol)]
candidate_primaries = [Species(f; symbol = phreeqc_to_unicode(n)) for (f, n) in zip(df_primaries.formula, df_primaries.symbol)]
And construct the stoichiometric matrix
A, indep_comp, dep_comp = stoich_matrix(species, candidate_primaries)
┌───────┬──────┬─────────┬─────┬─────────────┬─────────┬────────┬──────────┬────
│ │ H₂O@ │ Jennite │ C₃S │ Portlandite │ CaSiO₃@ │ SiO₃²⁻ │ Si₄O₁₀⁴⁻ │ S ⋯
├───────┼──────┼─────────┼─────┼─────────────┼─────────┼────────┼──────────┼────
│ Ca²⁺ │ 0 │ 5//3 │ 3 │ 1 │ 1 │ 0 │ 0 │ ⋯
│ H₂O@ │ 1 │ 3.76667 │ 3 │ 2 │ 1 │ 1 │ 2 │ ⋯
│ H⁺ │ 0 │ -10//3 │ -6 │ -2 │ -2 │ -2 │ -4 │ ⋯
│ SiO₂@ │ 0 │ 1 │ 1 │ 0 │ 1 │ 1 │ 4 │ ⋯
└───────┴──────┴─────────┴─────┴─────────────┴─────────┴────────┴──────────┴────
7 columns omitted
Get Stoichiometric Matrix from a database file
using ChemistryLab
using PrettyTables
df_elements, df_substances, df_reactions = read_thermofun("../../../data/cemdata18-merged.json")
df_primaries = extract_primary_species("../../../data/CEMDATA18-31-03-2022-phaseVol.dat")
aqueous_species = filter(row->row.aggregate_state == "AS_AQUEOUS", df_substances)
species = [Species(f; symbol=phreeqc_to_unicode(n)) for (f,n) in zip(aqueous_species.formula, aqueous_species.symbol)]
candidate_primaries = [Species(f; symbol=phreeqc_to_unicode(n)) for (f,n) in zip(df_primaries.formula, df_primaries.symbol)]
A, indep_comp, dep_comp = stoich_matrix(species, candidate_primaries) ;
┌───────┬──────┬─────────┬────────┬─────────┬──────┬──────┬──────────┬──────────
│ │ H₂O@ │ CaSiO₃@ │ SiO₃²⁻ │ SrSiO₃@ │ HCN@ │ SCN⁻ │ AlSiO₅³⁻ │ Si₄O₁₀⁴ ⋯
├───────┼──────┼─────────┼────────┼─────────┼──────┼──────┼──────────┼──────────
│ AlO₂⁻ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 1 │ ⋯
│ Ca²⁺ │ 0 │ 1 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ Cl⁻ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ CO₃²⁻ │ 0 │ 0 │ 0 │ 0 │ 1 │ 1 │ 0 │ ⋯
│ FeO₂⁻ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ H₂O@ │ 1 │ 1 │ 1 │ 1 │ -6 │ -10 │ 1 │ ⋯
│ H⁺ │ 0 │ -2 │ -2 │ -2 │ 13 │ 20 │ -2 │ - ⋯
│ K⁺ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ Mg²⁺ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ Na⁺ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ NO₃⁻ │ 0 │ 0 │ 0 │ 0 │ 1 │ 1 │ 0 │ ⋯
│ SiO₂@ │ 0 │ 1 │ 1 │ 1 │ 0 │ 0 │ 1 │ ⋯
│ SO₄²⁻ │ 0 │ 0 │ 0 │ 0 │ 0 │ 1 │ 0 │ ⋯
│ Sr²⁺ │ 0 │ 0 │ 0 │ 1 │ 0 │ 0 │ 0 │ ⋯
│ Zz │ 0 │ 0 │ 0 │ 0 │ -10 │ -15 │ 0 │ ⋯
└───────┴──────┴─────────┴────────┴─────────┴──────┴──────┴──────────┴──────────
74 columns omitted
All the reactions of the species contained in the database can thus be reconstructed. Here, only ionic species are listed given the choice to only read ionic species in the database ("AS_AQUEOUS").
stoich_matrix_to_reactions(A, indep_comp, dep_comp) ;
67-element Vector{Reaction}:
Ca²⁺ + H₂O@ + SiO₂@ = CaSiO₃@ + 2H⁺
H₂O@ + SiO₂@ = SiO₃²⁻ + 2H⁺
H₂O@ + SiO₂@ + Sr²⁺ = SrSiO₃@ + 2H⁺
CO₃²⁻ + 13H⁺ + NO₃⁻ + 10e⁻ = HCN@ + 6H₂O@
CO₃²⁻ + 20H⁺ + NO₃⁻ + SO₄²⁻ + 15e⁻ = SCN⁻ + 10H₂O@
AlO₂⁻ + H₂O@ + SiO₂@ = AlSiO₅³⁻ + 2H⁺
2H₂O@ + 4SiO₂@ = Si₄O₁₀⁴⁻ + 4H⁺
3Cl⁻ + FeO₂⁻ + 4H⁺ = FeCl₃@ + 2H₂O@
AlO₂⁻ + 4H⁺ + 2SO₄²⁻ = Al(SO₄)₂⁻ + 2H₂O@
FeO₂⁻ + 4H⁺ + SO₄²⁻ + e⁻ = Fe(SO₄)@ + 2H₂O@
⋮
2H₂O@ = O₂@ + 4H⁺ + 4e⁻
9H⁺ + NO₃⁻ + 8e⁻ = NH₃@ + 3H₂O@
Ca²⁺ + CO₃²⁻ = CaCO₃@
Ca²⁺ + SO₄²⁻ = CaSO₄@
H₂O@ + SiO₂@ = HSiO₃⁻ + H⁺
Cl⁻ + FeO₂⁻ + 4H⁺ = FeCl²⁺ + 2H₂O@
Cl⁻ + FeO₂⁻ + 4H⁺ + e⁻ = FeCl⁺ + 2H₂O@
K⁺ + SO₄²⁻ = KSO₄⁻
CO₃²⁻ + Sr²⁺ = Sr(CO₃)@
The exercise can also be done on solid species. In this case, the data filter is carried out using the keyword "AS_CRYSTAL", in accordance with the terminology adopted in Thermofun.
┌───────┬─────────────┬───────────┬───────┬───────┬──────────┬───────────┬──────
│ │ zeoliteP_Ca │ chabazite │ M₇₅SH │ M₁₅SH │ zeoliteX │ natrolite │ zeo ⋯
├───────┼─────────────┼───────────┼───────┼───────┼──────────┼───────────┼──────
│ AlO₂⁻ │ 2 │ 2 │ 0 │ 0 │ 2 │ 2 │ ⋯
│ Ca²⁺ │ 1 │ 1 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ Cl⁻ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ CO₃²⁻ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ FeO₂⁻ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ H₂O@ │ 9//2 │ 6 │ 4 │ 4 │ 31//5 │ 2 │ ⋯
│ H⁺ │ 0 │ 0 │ -3 │ -3 │ 0 │ 0 │ ⋯
│ K⁺ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ Mg²⁺ │ 0 │ 0 │ 3//2 │ 3//2 │ 0 │ 0 │ ⋯
│ Na⁺ │ 0 │ 0 │ 0 │ 0 │ 2 │ 2 │ ⋯
│ NO₃⁻ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ Qtz │ 2 │ 4 │ 2 │ 1 │ 5//2 │ 3 │ ⋯
│ SO₄²⁻ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ Sr²⁺ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
│ Zz │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ⋯
└───────┴─────────────┴───────────┴───────┴───────┴──────────┴───────────┴──────
134 columns omitted
138-element Vector{Reaction}:
2AlO₂⁻ + Ca²⁺ + 9//2H₂O@ + 2SiO₂ = Ca(Al₂Si₂)O₈(H₂O)₉//₂
2AlO₂⁻ + Ca²⁺ + 6H₂O@ + 4SiO₂ = Ca(Al₂Si₄)O₁₂(H₂O)₆
4H₂O@ + 3//2Mg²⁺ + 2SiO₂ = Mg₃//₂Si₂O₁₁//₂(H₂O)₅//₂ + 3H⁺
4H₂O@ + 3//2Mg²⁺ + SiO₂ = Mg₃//₂SiO₇//₂(H₂O)₅//₂ + 3H⁺
2AlO₂⁻ + 31//5H₂O@ + 2Na⁺ + 5//2SiO₂ = Na₂(Al₂Si₅//₂)O₉(H₂O)₃₁//₅
2AlO₂⁻ + 2H₂O@ + 2Na⁺ + 3SiO₂ = Na₂(Al₂Si₃)O₁₀(H₂O)₂
2AlO₂⁻ + 8H₂O@ + 2Na⁺ + 4SiO₂ = Na₂(Al₂Si₄)O₁₂(H₂O)₈
14AlO₂⁻ + 12Ca²⁺ + 5H₂O@ = (CaO)₁₂(Al₂O₃)₇ + 10H⁺
4AlO₂⁻ + Ca²⁺ + 2H⁺ = CaO(Al₂O₃)₂ + H₂O@
2AlO₂⁻ + Ca²⁺ = CaOAl₂O₃
⋮
FeO₂⁻ + 20H⁺ + 2SO₄²⁻ + 15e⁻ = FeSS + 10H₂O@
2H₂O@ + Mg²⁺ = Mg(OH)₂ + 2H⁺
CO₃²⁻ + Mg²⁺ = MgCO₃
CO₃²⁻ + Sr²⁺ = SrCO₃
SO₄²⁻ + Sr²⁺ = SrSO₄
H₂O@ + SiO₂ = (SiO₂H₂O)₁
Ca²⁺ + H₂O@ = CaO + 2H⁺
H₂O@ + 2K⁺ = K₂O + 2H⁺
H₂O@ + 2Na⁺ = Na₂O + 2H⁺
Or with gases ("AS_GAS")
┌───────┬────┬─────┬─────┬─────┬────┬─────┬─────┐
│ │ O₂ │ N₂ │ CH₄ │ CO₂ │ H₂ │ H₂S │ H₂O │
├───────┼────┼─────┼─────┼─────┼────┼─────┼─────┤
│ H₂O │ 2 │ -6 │ -3 │ -1 │ 0 │ -4 │ 1 │
│ CO₃²⁻ │ 0 │ 0 │ 1 │ 1 │ 0 │ 0 │ 0 │
│ H⁺ │ -4 │ 12 │ 10 │ 2 │ 2 │ 10 │ 0 │
│ NO₃⁻ │ 0 │ 2 │ 0 │ 0 │ 0 │ 0 │ 0 │
│ SO₄²⁻ │ 0 │ 0 │ 0 │ 0 │ 0 │ 1 │ 0 │
│ Zz │ 4 │ -10 │ -8 │ 0 │ -2 │ -8 │ 0 │
└───────┴────┴─────┴─────┴─────┴────┴─────┴─────┘
6-element Vector{Reaction}:
2H₂O = O₂ + 4H⁺ + 4e⁻
12H⁺ + 2NO₃⁻ + 10e⁻ = N₂ + 6H₂O
CO₃²⁻ + 10H⁺ + 8e⁻ = CH₄ + 3H₂O
CO₃²⁻ + 2H⁺ = CO₂ + H₂O
2H⁺ + 2e⁻ = H₂
10H⁺ + SO₄²⁻ + 8e⁻ = H₂S + 4H₂O