# StoichTools: Tools for Doing Stoichiometry

StoichTools comprises a set of Matlab functions for doing stoichiometric analysis. These functions parse standard chemical notation for a variety of stoichiometric calculations including finding molecular weights, balancing reactions for atom and charge conservation, finding independent reactions, and displaying formulas in Hill notation. The functions account for both change and atomic balances so they can be used to balance ionic reactions and chemical half reactions.

StoichTools has extensive documentation including a set of worked homework problems demonstrating use of the functions.

These functions were developed to support introductory courses in Chemical Engineering.

    Jeff Kantor
    December 18, 2010

## Contents

- What is StoichTools?
- Parsing Chemical Formulas
- Additional Parsing Examples
- Chemical Abbreviations and Isotopes
- Non-stoichiometric Formulas
- From Atoms to Chemical Formulas
- Hill Notation & Canonical Representations
- Molecular Weight
- Creating Molecular Weight Tables
- Atomic Matrix
- Atomic Matrix for Ionic Species
- Balancing a Reaction
- Stoichiometric Matrix
- Mulitple Independent Reactions
- Further Examples of Complex Reactions
- Chemical Equations with Ionic Charges
- Chemical Half Equations
- Nested Formulas
- Version History

## What is StoichTools?

StoichTools works with two types of data:

1. Chemical formulas. Each chemical formula is a string written in a nearly universal chemical notation. For example, `H2SO4` represents Sulfuric Acid. Grouping is allowed (e.g., `CH3(CH2)6CH3` for octane) with either parentheses '()' or brackets '[]'. Charge is indicated by a trailing + or - followed by an optional number (e.g., `Fe+3` or `HSO4-`). Phase information may be included as a terminal (aq), (l), (g), or (s). Cell arrays can be used in most places to work with multiple formulas at one time (e.g., {'H2SO4','H+','SO4-2'}).
2. Atomic representation. Many calculations require knowledge of the charge, and of number of atoms of each type in a chemical species. This is maintained in a Matlab structure where r.C, for example, is the number of carbon atoms. The symbol after the dot is the standard 1 or 2 character symbol for an element. The symbol `Q` is reserved to indicated charge. A Matlab structure array is used to store multiple atomic reprentations in a single variable.

StoichTools provides functions for the following types of chemical calculations:

Working with Chemical Formulas

- `r = parse_formula(s)` processes a chemical formula to produce an atomic representation. This function is mainly used by other functions to process chemical formulas.
- `hillformula` processes a chemical formula or atomic reprentation to produce a chemical formula in standard Hill notation. The Hill notation widely used to represent species in chemical databases, such as the NIST Chemistry Webbook.

Calculating Molecular Weights

- `mw = molweight(s)` computes the molecular weights of chemical compounds. Input can be a chemical formula, a cell array of chemical formulas, or an array of atomic representations. If no output is indicated, then a table of molecular weights is printed.

Stoichiometry

- `[A,atoms,species] = atomic(s)` constructs the atomic matrix for a set of chemical compounds. Element `A(i,j)` is the number of `atoms{i}` in `species{j}`. Inputs may be chemical formula, a cell array of chemical formulas, If there are ionic species, then a special atom 'Q' is indicates the charge of the species. If no output is indicated, then the atomic matrix is displayed in tabular form.
- `V = stoich(s)` computes the stoichiometric matrix for a set of chemical compounds. The input is a cell array of chemical formulas, or an array of atomic representations. The columns of `V` correspond to independent chemical reactions satisfying atomic and charge balances. Element `V(j,k)` is the stoichiometric coefficient for species `j` in reaction `k`. A negative value denotes a reactant, a positive value denotes a product. If no output is indicated, then `disp_reaction` is used to display all independent reactions.
- `Vout = disp_reaction(V,s)` If no output is indicated, then format and displays the chemical reactions denoted by stoichiometric matrix `V` and the array of species `s`. The species may be cell array of formulas or an array of atomic representations. If feasible, the coefficients are scaled to integers. It integer coefficients are too long, then either rational or floating point coefficients are displayed. If an output is indicated, then `Vout` is a stoichiometric matrix with rescaled coefficients, and the reactions are not displayed.

Homework Problems with Solutions

The StoichTools folder includes a number of worked homework problems. These are Matlab scripts with titles in the pattern `HW_xx.m`. Each script begins with a cell containing the problem statement. Subsequent cells demonstrate solution to the problem. The homework files can be sviewed by using the Matlab publishing function.

## Parsing Chemical Formulas

Given a set of chemical species, `r = parse_formula(s)` parses a cell array of chemical formulas to produce a structure array r. The value is the number of atoms of that element present in the corresponding formula. The structure array includes a field for each atomic element in the set of species. We call this the atomic represenation of the species.

    % Parsing methane

    parse_formula('CH4')

    ans =

        C: 1
        H: 4

## Additional Parsing Examples

    ex{1} = 'NaHCO3';
    ex{2} = 'KFe3(SO4)2(OH)6';     % Jorosite
    ex{3} = 'KFe3(AsO4)2(HAsO4)2'; % Potassium-Iron-Arsenate
    ex{4} = '(CH4)8(H2O)46';       % Methane Clathrate
    ex{4} = 'HSO4-(aq)';

    for k = 1:length(ex)
        disp(ex{k});
        parse_formula(ex{k})
    end

    NaHCO3

    ans =

        Na: 1
         H: 1
         C: 1
         O: 3

    KFe3(SO4)2(OH)6

    ans =

         K: 1
        Fe: 3
         S: 2
         O: 14
         H: 6

    KFe3(AsO4)2(HAsO4)2

    ans =

         K: 1
        Fe: 3
        As: 4
         O: 16
         H: 2

    HSO4-(aq)

    ans =

        H: 1
        S: 1
        O: 4
        Q: -1

## Chemical Abbreviations and Isotopes

- Formulas may include D (Deuterium) or T (Tritium). These are treated as elements and included as distinct species in any atom balances.
- The common organic chemistry abbreviations Me (Methyl, CH3), Et (Ethyl, C2H5), Bu (Butyl, C4H9), Ph (Phenol, C6H5) may be included in formulas. These are replaced by their atomic formulas during the parsing process.
- The symbols M (any metal) and X (any halogen) may be used in formulas. Formulas containing the symbol M or X have unknown molecular weight.

    parse_formula('D2O')
    parse_formula('EtOH')
    molweight({'H2O','D2O','T2O','EtOH','PhOH','TiO2','MO2'});

    ans =

        D: 2
        O: 1

    ans =

        C: 2
        H: 6
        O: 1

    Species                    Mol. Wt.
    -------                    --------
    H2O                           18.02
    D2O                           20.03
    T2O                           22.03
    EtOH                          46.07
    PhOH                          94.11
    TiO2                          79.88
    MO2                             NaN

## Non-stoichiometric Formulas

Some applications of stoichiometry involve complex chemical compounds not easily described by simple chemical fomulas. So-called 'non-stoichiometric' compounds can be also be parsed.

    bacteria = 'CH1.8N0.24O0.36';
    parse_formula(bacteria);

## From Atoms to Chemical Formulas

Given a structure array of atomic representations, |s = hillformula(r)} constructs a cell array of corresponding chemical formulas.

    % Formula for octane

    octane.C = 8;
    octane.H = 18;
    hillformula(octane)

    ans =

        'C8H18'

## Hill Notation & Canonical Representations

The Hill notation is a commonly used system for writing chemical formulas in a standard form. % `hillformula(r)` produces a simple canonical representation of a chemical species. Note, however, that there may be many isomers for a given formula.

    s = {'Zr3B2','HBr','HCl','CH3(CH2)6CH3','NaCO3','CaC2','CH3OH', ...
         'CH3COOH','HNO3','H2SO4','NH3','SnH4','CH3HgCH3','(CH3CH2)4Pb', ...
         '[Co(NH3)6]+3','[B12H12]-2'};

    fprintf('\n%-15s %-15s\n----------      ----------\n', ...
        'Formula','Hill Notation');
    for k = 1:length(s)
        fprintf('%-15s %-15s\n',s{k},char(hillformula(s{k})));
    end

    Formula         Hill Notation
    ----------      ----------
    Zr3B2           B2Zr3
    HBr             BrH
    HCl             ClH
    CH3(CH2)6CH3    C8H18
    NaCO3           CNaO3
    CaC2            C2Ca
    CH3OH           CH4O
    CH3COOH         C2H4O2
    HNO3            HNO3
    H2SO4           H2O4S
    NH3             H3N
    SnH4            H4Sn
    CH3HgCH3        C2H6Hg
    (CH3CH2)4Pb     C8H20Pb
    [Co(NH3)6]+3    CoH18N6+3
    [B12H12]-2      B12H12-2

## Molecular Weight

    mw = molweight(s)
    mw = molweight(r)

Given a cell array of chemical formulas, or a structure array of atomic representations, `molweight` computes a corresponding vector of molecular weights.

    % Molecular Mass of Dimethyl Mercury

    s = 'CH3HgCH3';
    mw = molweight('CH3HgCH3');
    fprintf('Molecular Weight of Dimethyl Mercury (%s) = %g\n',s,mw);

    Molecular Weight of Dimethyl Mercury (CH3HgCH3) = 230.66

## Creating Molecular Weight Tables

If molweight as no output, then it prints a table of molecular weights.

    molweight(s);

    Species                    Mol. Wt.
    -------                    --------
    CH3HgCH3                     230.66

## Atomic Matrix

    [A,atoms,species] = atomic(s)
    [A,atoms,species] = atomic(r)

Given a cell array of chemical formulas `s`, or a structure array of atomic representations `r`, `atomic` computes the atomic matrix A. `atoms` is a a cell array of the atomic elements, `species` is a cell array of species. A(i,j) is the number of atoms of element atoms{i} in species species{j}. % When called without an output argument, `atomic` displays the atomic matrix.

    s = {'CH4','O2','H2O','CO2'};

    atomic(s);
    A = atomic(s);
    disp(' ');
    disp('A = ');
    disp(A);

             CH4       O2      H2O      CO2
     C:        1        0        0        1
     H:        4        0        2        0
     O:        0        2        1        2

    A =
         1     0     0     1
         4     0     2     0
         0     2     1     2

## Atomic Matrix for Ionic Species

For ionic species an additional row is added, labeled by 'Q', indicating the net charge on each of the species included in the matrix.

    s = {'Fe+3','SO4-2','H+','OH-','H2O','Fe2(SO4)3'};
    atomic(s);

            Fe+3    SO4-2       H+      OH-      H2O Fe2(SO4)3
    Fe:        1        0        0        0        0        2
     H:        0        0        1        1        2        0
     O:        0        4        0        1        1       12
     S:        0        1        0        0        0        3
     Q:        3       -2        1       -1        0        0

## Balancing a Reaction

Given a cell array of chemical formulas, or an array of atomic representations, `stoich(s)` computes stoichiometric coefficients that satisfy charge and atom balances. If no output is specified, then balanced reactions are displayed.

    stoich({'NaPb','CH3CH2Cl','(CH3CH2)4Pb','NaCl','Pb'});
    stoich({'H+(aq)','OH-(aq)','H2O(l)'});

    4 NaPb + 4 CH3CH2Cl <=> (CH3CH2)4Pb + 4 NaCl + 3 Pb

    H+(aq) + OH-(aq) <=> H2O(l)

## Stoichiometric Matrix

Given a cell array of chemical formulas, or a structure array of atomic representations, `V = stoich(s)` computes the stoichiometric matrix `V`. `V(n,r)` is the stoichiometric coeffient of species `n` in reaction `r`. The atomic and stoichiometric matrices satisfies the relationship `A*V = 0`.

    s = {'C8H18','O2','C','CO','CO2','H2O'};
    V = stoich(s);
    disp('Stoichiometric Matrix V = ');
    disp(V);

    Stoichiometric Matrix V =
        -1     0     0
         0    -1     0
         0     0    -1
        25    -2     2
       -17     2    -1
         9     0     0

## Mulitple Independent Reactions

    V = stoich(s)
    disp_reaction(V,s)

The columns of the stoichiometric matrix `V` represent independent reactions. The function `disp_reaction(V,s)` displays the reactions in a conventional human readable form.

    s = {'C8H18','O2','C','CO','CO2','H2O'};
    V = stoich(s);
    disp_reaction(V,s);

    C8H18 + 17 CO2 <=> 25 CO + 9 H2O
    O2 + 2 CO <=> 2 CO2
    C + CO2 <=> 2 CO

## Further Examples of Complex Reactions

Examples from http://www.chemistryhelp.net/chemistry-calculator/chemical-equation-balancer

    stoich({'P2I4','P4','H2O','H3PO4','PH4I'});

    stoich({'[Cr(N2H4CO)6]4[Cr(CN)6]3','KMnO4','H2SO4','K2Cr2O7', ...
         'MnSO4','CO2','KNO3','K2SO4','H2O'});

    stoich({'Cu(s)','HNO3(aq)','Cu(NO3)2(aq)','NO(g)','H2O(l)'});

    stoich({'Cu','HNO3','H2O','Cu(NO3)2','NO'});

    stoich({'KMnO4','C3H5(OH)3','K2CO3','Mn2O3','CO2','H2O'});

    stoich({'K2Cr2O7','FeCl2','HCl','KCl', ...
        'CrCl3','FeCl3','H2O'});

    stoich({'Bi(NO3)3(H2O)5','NaOH','H2O2','RuCl3', ...
         'NaNO3','NaCl','Bi2Ru2O7','H2O'});

    stoich({'(NH4)2MoO4','NH4NO3','Na3PO4','H2O', ...
        '(NH4)3[P(Mo3O10)4]','NaNO3','NH3'});

    stoich({'H2','Ca(CN)2','NaAlF4','FeSO4','MgSiO3','KI','H3PO4', ...
        'PbCrO4','BrCl','CF2Cl2','SO2','PbBr2','CrCl3','MgCO3', ...
        'KAl(OH)4','Fe(SCN)3','PI3','Na2SiO3','CaF2','H2O'});

    stoich({'NH4ClO4','NaY(OH)4','Ru(SCN)3','PBr5','TiCl2CrI4','BeCO3', ...
        'Rb2ZrO3','ZnAt2','CAt2I2','Rb0.998YAt4','RuS2','BeZrO3','Zn(CN)2', ...
        'NaHBr1.997','H3PO4','TiCrO4','ClI','H2SO4','H2O'});

    10 P2I4 + 13 P4 + 128 H2O <=> 32 H3PO4 + 40 PH4I

    10 [Cr(N2H4CO)6]4[Cr(CN)6]3 + 1176 KMnO4 + 1399 H2SO4
      <=> 35 K2Cr2O7 + 1176 MnSO4 + 420 CO2 + 660 KNO3 + 223 K2SO4
       + 1879 H2O

    3 Cu(s) + 8 HNO3(aq) <=> 3 Cu(NO3)2(aq) + 2 NO(g) + 4 H2O(l)

    3 Cu + 8 HNO3 <=> 4 H2O + 3 Cu(NO3)2 + 2 NO

    14 KMnO4 + 4 C3H5(OH)3 <=> 7 K2CO3 + 7 Mn2O3 + 5 CO2 + 16 H2O

    K2Cr2O7 + 6 FeCl2 + 14 HCl <=> 2 KCl + 2 CrCl3 + 6 FeCl3 + 7 H2O

    2 Bi(NO3)3(H2O)5 + 12 NaOH + H2O2 + 2 RuCl3
      <=> 6 NaNO3 + 6 NaCl + Bi2Ru2O7 + 17 H2O

    12 (NH4)2MoO4 + 3 NH4NO3 + Na3PO4 <=> 12 H2O + (NH4)3[P(Mo3O10)4]
       + 3 NaNO3 + 24 NH3

    88 H2 + 15 Ca(CN)2 + 6 NaAlF4 + 10 FeSO4 + 3 MgSiO3 + 6 KI + 2 H3PO4
       + 6 PbCrO4 + 12 BrCl + 3 CF2Cl2 + 20 SO2
      <=> 6 PbBr2 + 6 CrCl3 + 3 MgCO3 + 6 KAl(OH)4 + 10 Fe(SCN)3 + 2 PI3
       + 3 Na2SiO3 + 15 CaF2 + 79 H2O

    NH4ClO4 + 1.752 NaY(OH)4 + 1.9188 Ru(SCN)3 + 0.69974 PBr5
       + 0.37423 TiCl2CrI4 + 0.87425 BeCO3 + 0.87425 Rb2ZrO3
       + 3.3782 ZnAt2 + 0.12575 CAt2I2 <=> 1.752 Rb0.998YAt4 + 1.9188 RuS2
       + 0.87425 BeZrO3 + 3.3782 Zn(CN)2 + 1.752 NaHBr1.997
       + 0.69974 H3PO4 + 0.37423 TiCrO4 + 1.7485 ClI + 1.9188 H2SO4
       + 1.6596 H2O

## Chemical Equations with Ionic Charges

The charge on ionic species is indicated by + or - followed by an optional digit indicating the amount of charge. If ionic species are present, then a charge balance is include in the computation of the stoichiometric coefficients.

    stoich({'ClO2+(aq)','H3O+(aq)','Cl2(g)','H2O(l)','ClO3-(aq)','ClO2(aq)'});
    stoich({'Bi+3(aq)','HSnO2-(aq)','OH-(aq)','Bi(s)','H2O','SnO3-2(aq)'});
    stoich({'CH3CH2OH','Cr2O7-2','H+','CH3COOH','Cr+3','H2O'});
    stoich({'I-','I2','Mn+2','MnO4-','H+','H2O'});
    stoich({'Cl2','Cl-','Fe+2','Fe+3'});
    stoich({'Mn+2','BiO-3','H+','MnO4-','Bi3+','H2O'});
    stoich({'NpO2+2','NpO2(OH)H2C2O4+','NpO2+','CO2','H+','O2'});
    stoich({'H3PO4','(NH4)6Mo7O24','H+','(NH4)3PO4(MoO3)12','NH4+','H2O'});

    4 ClO2+(aq) + Cl2(g) + 4 ClO3-(aq) <=> 10 ClO2(aq)
    8 H3O+(aq) + Cl2(g) + 8 ClO3-(aq) <=> 12 H2O(l) + 10 ClO2(aq)

    2 Bi+3(aq) + 3 HSnO2-(aq) + 9 OH-(aq) <=> 2 Bi(s) + 6 H2O
       + 3 SnO3-2(aq)

    3 CH3CH2OH + 2 Cr2O7-2 + 16 H+ <=> 3 CH3COOH + 4 Cr+3 + 11 H2O

    10 I- + 2 MnO4- + 16 H+ <=> 5 I2 + 2 Mn+2 + 8 H2O

    Cl2 + 2 Fe+2 <=> 2 Cl- + 2 Fe+3

    4 Mn+2 + 5 Bi3+ + 31 H2O <=> 15 BiO-3 + 62 H+ + 4 MnO4-

    6 NpO2+2 + 2 NpO2(OH)H2C2O4+ <=> 8 NpO2+ + 4 CO2 + 6 H+ + O2

    7 H3PO4 + 12 (NH4)6Mo7O24 + 51 H+ <=> 7 (NH4)3PO4(MoO3)12 + 51 NH4+
       + 36 H2O

## Chemical Half Equations

Include the bare electron 'e-' to balance chemical half reactions. In acidic solutions, if one of the main reactants contains oxygen, add 'H+' and 'H2O'. In basic solutions, if one of the main reactants contains oxygen then add 'OH-' and 'H2O'.

    stoich({'Al+3(aq)','Al(s)','e-'});
    stoich({'Cl-(aq)','Cl2(g)','e-'});

    % Acidic Solutions

    stoich({'MnO4-(aq)','Mn+2(aq)','H2O(l)','H+(aq)','e-'});
    stoich({'O2(g)','H2O(l)','H+(aq)','e-'});
    stoich({'Ag2O3','Ag+','H2O','H+','e-'});
    stoich({'S2O3-2(aq)','S(s)','H2O(l)','H+(aq)','e-'});
    stoich({'HOOCCOOH(aq)','CO2(g)','H2O(l)','H+(aq)','e-'});

    % Alkali Solutions

    stoich({'MnO4-(aq)','Mn+2(aq)','H2O(l)','OH-(aq)','e-'});
    stoich({'Cr(OH)6-2','CrO4-2','H2O','OH-','e-'});
    stoich({'NH3OH(aq)','N2(g)','H2O(l)','OH-(aq)','e-'});
    stoich({'Al(OH)4-(aq)','Al(s)','H2O(l)','OH-(aq)','e-'});
    stoich({'ZrO(OH)2','Zr','H2O','OH-','e-'});

    Al+3(aq) + 3 e- <=> Al(s)

    2 Cl-(aq) <=> Cl2(g) + 2 e-

    MnO4-(aq) + 8 H+(aq) + 5 e- <=> Mn+2(aq) + 4 H2O(l)

    O2(g) + 4 H+(aq) + 4 e- <=> 2 H2O(l)

    Ag2O3 + 6 H+ + 4 e- <=> 2 Ag+ + 3 H2O

    S2O3-2(aq) + 6 H+(aq) + 4 e- <=> 2 S(s) + 3 H2O(l)

    HOOCCOOH(aq) <=> 2 CO2(g) + 2 H+(aq) + 2 e-

    MnO4-(aq) + 4 H2O(l) + 5 e- <=> Mn+2(aq) + 8 OH-(aq)

    Cr(OH)6-2 + 2 OH- <=> CrO4-2 + 4 H2O + 2 e-

    2 NH3OH(aq) + 4 OH-(aq) <=> N2(g) + 6 H2O(l) + 4 e-

    Al(OH)4-(aq) + 3 e- <=> Al(s) + 4 OH-(aq)

    ZrO(OH)2 + H2O + 4 e- <=> Zr + 4 OH-

## Nested Formulas

Matlab regular expressions capabilities are used to parse chemical formulas. While this keeps StoichTools simple and fast, one of the drawbacks of regular expressions is the difficulty of matching nested expressions. Thus nesting is limited to bracketed expressions inside of parentheses, or parentheses inside of brackets. By this rule, [Fe2(SO4)3] and (Fe2[SO4]3) are allowed, but (Fe2(SO4)3) and [Fe2[SO4]3] are not. In practice, chemical formula rarely need more than two levels of nesting.

    disp('These work fine.');
    molweight({'[Fe2(SO4)3]','(Fe2[SO4]3)'});

    fprintf('\n\n');
    try
        molweight({'(Fe2(SO4)3)','[Fe2[SO4]3]'})
    catch exception
        disp('But this does not.');
        disp(exception.message);
    end

    These work fine.

    Species                    Mol. Wt.
    -------                    --------
    [Fe2(SO4)3]                  399.88
    (Fe2[SO4]3)                  399.88

    But this does not.
    Could not parse formula:
        (Fe2(SO4)3)
                  ^

## Version History

- 2010/12/18 Submitted to Matlab Central
- 2010/12/19 Updated documentation, added solved homeworks
- 2010/12/19 Put rows of the atomic matrix in Hill order
- 2010/12/19 Expanded regular expression parsing to include phases
- 2010/12/20 Enhanced parser to accept non-stoichiometric formulas
- 2010/12/20 Enhanced disp_reaction for better coefficient formatting
- 2010/12/21 Parser to include common symbols D, T, Et, Me, Bu, Ph
- 2010/12/30 Fixed all mlint messages, reduced McCabe complexity
- 2010/12/30 Update to Matlab Central
- 2010/12/30 Further improvements to error handling (assert's)
- 2010/12/31 Fixed bug with NaN in molweight
- 2010/12/31 Renamed homework files so it makes more sense on MC
- 2010/12/31 Update to Matlab Central

To Do's

- Add Generation/Consumption Analysis
- Add Extent of Reaction Analysis
- Include an electrochemistry howework example (battery?)
- Add a display feature for stoich
- Add webbook lookup for chemical property data