## FCSys.Utilities.Chemistry

Functions to support chemistry

### Information

Extends from Modelica.Icons.Package (Icon for standard packages).

### Package Content

Name | Description
--- | ---
charge | Return the charge of a species given its chemical formula
countElements | Return the number of elements in a chemical formula
readElement | Return the symbol, coefficient, and charge of an element in a chemical formula
readSpecies | Return the symbols and coefficients of the elements in a chemical formula
stoich | Return stoichiometric coefficients of a reaction based on chemical formulas of reacting species

## FCSys.Utilities.Chemistry.charge

Return the charge of a species given its chemical formula

### Information

This function returns the net electrical charge associated with a species represented by a chemical formula (`formula`). If the charge number is not given explicitly in the formula, then it is assumed to be zero. A "+" or "-" without any immediately following digits is interpreted as a charge of +1 or -1, respectively. If there is an error in the chemical formula, then 0 is returned.

Example:
`charge("Hg2+2")` returns 2.

Extends from Modelica.Icons.Function (Icon for functions).

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
String | formula |  | Chemical formula

### Outputs

Type | Name | Description
--- | --- | ---
Integer | z | Charge number

### Modelica definition

    function charge
      "Return the charge of a species given its chemical formula"
      extends Modelica.Icons.Function;
      input String formula "Chemical formula";
      output Integer z "Charge number";

    external"C";

    end charge;

## FCSys.Utilities.Chemistry.countElements

Return the number of elements in a chemical formula

### Information

This function returns the number of elements in a chemical formula. Electrons are counted as a present element (or rather particle) if the net charge is nonzero.

Examples:
`countElements("C19HF37O5S-")` returns 5 and `countElements("H+")` returns 2.

Please see the readElement function for details about the format of the chemical formula.

Extends from Modelica.Icons.Function (Icon for functions).

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
String | formula |  | Chemical formula

### Outputs

Type | Name | Description
--- | --- | ---
Integer | n | Number of elements

### Modelica definition

    function countElements
      "Return the number of elements in a chemical formula"
      extends Modelica.Icons.Function;
      input String formula "Chemical formula";
      output Integer n "Number of elements";

    external"C";

    end countElements;

## FCSys.Utilities.Chemistry.readElement

Return the symbol, coefficient, and charge of an element in a chemical formula

### Information

This function returns the symbol (`symbol`), stoichiometric coefficient (n), and electrical charge (z) associated with an element as it appears in a chemical formula (`formula`). After any initial whitespace in the `formula` string, which is ignored, the symbol must begin with a letter and may continue with lowercase letters. The symbol may be followed by a positive integer and then a charge number (both independently optional). If present, the charge number must begin with "+" or "-" and may be followed by optional digits. The `remainder` output gives the remainder of the `formula` string after the symbol, coefficient, and charge have been extracted.

If the coefficient is not explicitly given, then it is assumed to be one. If the charge number is not given, then it is assumed to be zero. A "+" or "-" without following digits is interpreted as a charge of +1 or -1, respectively. If there is an error, then `symbol` will be an empty string.

Example:
`(symbol, n, z, remainder) = readElement("Hg2+2")` returns `symbol="Hg"`, `n=2`, `z=2`, and `remainder=""`.

Extends from Modelica.Icons.Function (Icon for functions).

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
String | formula |  | Chemical formula

### Outputs

Type | Name | Description
--- | --- | ---
String | symbol | Name of element (empty if error)
Integer | n | Stoichiometric coefficient
Integer | z | Charge number
String | remainder | Remainder of the chemical formula

### Modelica definition

    function readElement
      "Return the symbol, coefficient, and charge of an element in a chemical formula"
      extends Modelica.Icons.Function;
      input String formula "Chemical formula";
      output String symbol "Name of element (empty if error)";
      output Integer n "Stoichiometric coefficient";
      output Integer z "Charge number";
      output String remainder "Remainder of the chemical formula";

    external"C" readElement(
        formula,
        symbol,
        n,
        z,
        remainder);

    end readElement;

## FCSys.Utilities.Chemistry.readSpecies

Return the symbols and coefficients of the elements in a chemical formula

### Information

This function reads a chemical formula (`formula`) and returns the symbols (`symbols`) and coefficients (`coeffs`). Each element is interpreted according to the rules in the readElement function. Currently, `formula` may not contain parentheses or brackets.

The symbols correspond to chemical/physical elements or electrons ("e-"). Electrons are listed if the charge is nonzero.

Example:
`(symbols, coeffs) = readSpecies("C19HF37O5S-")` returns `symbols={"C", "H", "F", "O", "S", "e-"}` and `coeffs={19, 1, 37, 5, 1, 1}`.

Extends from Modelica.Icons.Function (Icon for functions).

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
String | formula |  | Chemical formula

### Outputs

Type | Name | Description
--- | --- | ---
String | symbols[countElements(formula)] | Symbols of the elements
Integer | coeffs[countElements(formula)] | Coefficients of the elements

### Modelica definition

    function readSpecies
      "Return the symbols and coefficients of the elements in a chemical formula"
      extends Modelica.Icons.Function;
      input String formula "Chemical formula";
      output String symbols[countElements(formula)] "Symbols of the elements";
      output Integer coeffs[countElements(formula)] "Coefficients of the elements";
      // Note:  coeffs[size(symbols, 1)] would save computation but fails
      // in Dymola 2014.

    protected
      Integer z "Charge number";
      Integer z_net=0 "Net charge";
      Integer i=1 "Index of element";
      String f=formula "Working copy of formula";

    algorithm
      // Read the elements.
      while f <> "" loop
        (symbols[i],coeffs[i],z,f) := readElement(f);
        assert(symbols[i] <> "", "The formula (" + formula + ") is invalid.");
        z_net := z_net + z;
        if symbols[i] <> "e" then
          i := i + 1;
          // Electrons are counted below.
        end if;
      end while;

      // Add electrons according to the charge.
      if z_net <> 0 then
        symbols[i] := "e-";
        coeffs[i] := -z_net;
      end if;
    end readSpecies;

## FCSys.Utilities.Chemistry.stoich

Return stoichiometric coefficients of a reaction based on chemical formulas of reacting species

### Information

This function returns a vector of stoichiometric coefficients (n) that balance a chemical reaction among the species given by a vector of chemical formulas (`formulas`). If the reaction is ill-posed or non-unique, then the function will fail with a message. Each formula is interpreted according to the rules in the readElement function.

Example:
`stoich({"e-","H+","O2","H2O"})` returns `{-4,-4,-1,2}`, which indicates the reaction 4e- + 4H+ + O2 ⇌ 2H2O.

Extends from Modelica.Icons.Function (Icon for functions).

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
String | formulas[:] |  | Chemical formulas of the species

### Outputs

Type | Name | Description
--- | --- | ---
Integer | n[size(formulas, 1)] | Stoichiometric coefficients

### Modelica definition

    function stoich
      "Return stoichiometric coefficients of a reaction based on chemical formulas of reacting species"
      import Modelica.Math.Matrices.singularValues;
      extends Modelica.Icons.Function;
      input String formulas[:] "Chemical formulas of the species";
      output Integer n[size(formulas, 1)] "Stoichiometric coefficients";

    protected
      Integer n_species=size(formulas, 1) "Number of species";
      Integer n_elements[n_species]=countElements(formulas)
        "Number of elements within each species";
      Integer n_tot=sum(n_elements) "Total number of elements";
      String allSymbols[n_tot] "Symbols of all the elementary components";
      String symbols[n_species, max(n_elements)]
        "Symbols of the elements of each species";
      Integer coeffs[n_species, max(n_elements)]
        "Coefficients of the elements of each species";
      Integer i "Index";
      Integer j=1 "Index";
      Real d[n_species] "Diagonal entries of SVD";
      Real u[n_species, n_species] "1st unitary matrix of SVD";
      Real v[n_species, n_species] "2nd unitary matrix of SVD";
      Real minabs
        "Minimum magnitude of the unnormalized stoichiometric coefficients";
      Real elementCoeffs[n_species, n_tot] "Elementary coefficients";

    algorithm
      // Generate a list of all the symbols.
      for i in 1:n_species loop
        (symbols[i, 1:n_elements[i]],coeffs[i, 1:n_elements[i]]) := readSpecies(
          formulas[i]);
        allSymbols[j:j + n_elements[i] - 1] := symbols[i, 1:n_elements[i]];
        j := j + n_elements[i];
      end for;
      // Reduce the list to a (unique) set.
      i := 1;
      while i < n_tot loop
        j := i + 1;
        while j <= n_tot loop
          if allSymbols[i] == allSymbols[j] then
            allSymbols[j] := allSymbols[n_tot];
            n_tot := n_tot - 1;
          else
            j := j + 1;
          end if;
        end while;
        i := i + 1;
      end while;
      // Note:  While loops are used since the upper bound changes.
      // Find the elementary coefficients for each species in terms of the
      // unique list of symbols.
      elementCoeffs[:, 1:n_tot] := zeros(n_species, n_tot);
      for i in 1:n_species loop
        for j in 1:n_elements[i] loop
          for k in 1:n_tot loop
            if allSymbols[k] == symbols[i, j] then
              elementCoeffs[i, k] := coeffs[i, j];
              break;
            end if;
          end for;
        end for;
      end for;
      // Perform singular value decomposition (SVD).
      assert(n_species == n_tot + 1, "The reaction is ill-posed.
    " + (if n_species > n_tot + 1 then "A species may be included more than once."
         else "A species may be missing or the wrong one has been entered."));
      (d,u,v) := singularValues(cat(
        2,
        elementCoeffs[:, 1:n_tot],
        zeros(n_species, 1)));
      // This approach is based on [Reichert2010].
      // Extract the stoichiometric coefficients and normalize them.
      minabs := min(abs(u[:, end]));
      assert(minabs > 0, "The reaction is ill-posed.
    An unrelated species may be included.");
      n := round(u[:, end]/minabs);
    end stoich;