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²⁺ + HO@ + SiO@ = CaSiO@ + 2H
 HO@ + SiO@ = SiO²⁻ + 2H
 HO@ + SiO@ + Sr²⁺ = SrSiO@ + 2H
 CO²⁻ + 13H + NO + 10e⁻ = HCN@ + 6HO@
 CO²⁻ + 20H + NO + SO²⁻ + 15e⁻ = SCN + 10HO@
 AlO + HO@ + SiO@ = AlSiO³⁻ + 2H
 2HO@ + 4SiO@ = SiO₁₀⁴⁻ + 4H
 3Cl + FeO + 4H = FeCl@ + 2HO@
 AlO + 4H + 2SO²⁻ = Al(SO) + 2HO@
 FeO + 4H + SO²⁻ + e⁻ = Fe(SO)@ + 2HO@2HO@ = O@ + 4H + 4e⁻
 9H + NO + 8e⁻ = NH@ + 3HO@
 Ca²⁺ + CO²⁻ = CaCO@
 Ca²⁺ + SO²⁻ = CaSO@
 HO@ + SiO@ = HSiO + H
 Cl + FeO + 4H = FeCl²⁺ + 2HO@
 Cl + FeO + 4H + e⁻ = FeCl + 2HO@
 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//2HO@ + 2SiO = Ca(AlSi)O(HO)₉//₂
 2AlO + Ca²⁺ + 6HO@ + 4SiO = Ca(AlSi)O₁₂(HO)
 4HO@ + 3//2Mg²⁺ + 2SiO = Mg₃//₂SiO₁₁//₂(HO)₅//₂ + 3H
 4HO@ + 3//2Mg²⁺ + SiO = Mg₃//₂SiO₇//₂(HO)₅//₂ + 3H
 2AlO + 31//5HO@ + 2Na + 5//2SiO = Na(AlSi₅//₂)O(HO)₃₁//₅
 2AlO + 2HO@ + 2Na + 3SiO = Na(AlSi)O₁₀(HO)
 2AlO + 8HO@ + 2Na + 4SiO = Na(AlSi)O₁₂(HO)
 14AlO + 12Ca²⁺ + 5HO@ = (CaO)₁₂(AlO) + 10H
 4AlO + Ca²⁺ + 2H = CaO(AlO) + HO@
 2AlO + Ca²⁺ = CaOAlO
 ⋮
 FeO + 20H + 2SO²⁻ + 15e⁻ = FeSS + 10HO@
 2HO@ + Mg²⁺ = Mg(OH) + 2H
 CO²⁻ + Mg²⁺ = MgCO
 CO²⁻ + Sr²⁺ = SrCO
 SO²⁻ + Sr²⁺ = SrSO
 HO@ + SiO = (SiOHO)
 Ca²⁺ + HO@ = CaO + 2H
 HO@ + 2K = KO + 2H
 HO@ + 2Na = NaO + 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}:
 2HO = O + 4H + 4e⁻
 12H + 2NO + 10e⁻ = N + 6HO
 CO²⁻ + 10H + 8e⁻ = CH + 3HO
 CO²⁻ + 2H = CO + HO
 2H + 2e⁻ = H
 10H + SO²⁻ + 8e⁻ = HS + 4HO