Species

Species is a composite type (introduced by the keyword struct) and is defined by a name, a symbol, a formula, an aggregate state, a class and properties. It creates chemical species for solution or solid phases:

struct Species{T<:Number} <: AbstractSpecies
    name::String
    symbol::String
    formula::Formula{T}
    aggregate_state::AggregateState
    class::Class
    properties::OrderedDict{Symbol,PropertyType}
end
Advanced description
  • aggregate_state denotes the state of the species (solid, liquid, gas) for which the possible keywords are ASAQUEOUS, ASCRYSTAL, ASGAS and ASUNDEF
  • class defines the role played by the species in the solution. The possible keywords are SCAQSOLVENT, SCAQSOLUTE, SCCOMPONENT, SCGASFLUID and SCUNDEF
  • properties refers to the set of properties intrinsic to the species. These properties are detailed below (Species properties).

Species construction

Species can be created from:

  • a Formula
fH2O = 2 * :H + :O
H2O = Species(fH2O)
Species{Int64}
           name: H2O
         symbol: H2O
        formula: H2O ◆ H₂O ◆ HO
          atoms: H => 2, O => 1
         charge: 0
aggregate_state: AS_UNDEF
          class: SC_UNDEF
     properties: molar_mass = 18.015 g mol^-1
  • a string
HSO4⁻ = Species("HSO₄⁻")
Species{Int64}
           name: HSO₄⁻
         symbol: HSO₄⁻
        formula: HSO₄⁻ ◆ HSO4- ◆ HSO
          atoms: H => 1, S => 1, O => 4
         charge: -1
aggregate_state: AS_UNDEF
          class: SC_UNDEF
     properties: molar_mass = 97.06400000000001 g mol^-1
  • a dictionary
CO2 = Species(Dict(:C => 1, :O => 2))
Species{Int64}
           name: CO₂
         symbol: CO₂
        formula: CO2 ◆ CO₂ ◆ CO
          atoms: O => 2, C => 1
         charge: 0
aggregate_state: AS_UNDEF
          class: SC_UNDEF
     properties: molar_mass = 44.009 g mol^-1
Adding charge

To add a charge when creating species with a dictionary, you must add, after the dictionary, the value of the charge (charge is considered an argument of the composite type).

CO2 = Species(Dict(:Si => 1, :O => 3),-2)
Species{Int64}
           name: SiO₃-2
         symbol: SiO₃-2
        formula: SiO3-2 ◆ SiO₃-2 ◆ SiO⁻²
          atoms: Si => 1, O => 3
         charge: -2
aggregate_state: AS_UNDEF
          class: SC_UNDEF
     properties: molar_mass = 76.082 g mol^-1

Keyword arguments such as name, symbol, aggregate_state, class can be added during construction.

fH₂O = 2*:H + :O
H₂O = Species(fH₂O; name="Water", symbol="H₂O@", aggregate_state=AS_AQUEOUS, class=SC_AQSOLVENT)
Species{Int64}
           name: Water
         symbol: H₂O@
        formula: H2O ◆ H₂O ◆ HO
          atoms: H => 2, O => 1
         charge: 0
aggregate_state: AS_AQUEOUS
          class: SC_AQSOLVENT
     properties: molar_mass = 18.015 g mol^-1

And symbol accept unicode characters.

CO₂ = Species(Dict(:C=>1, :O=>2); name="Carbon dioxide", symbol="CO₂⤴", aggregate_state=AS_GAS, class=SC_GAS_FLUID)
Species{Int64}
           name: Carbon dioxide
         symbol: CO₂⤴
        formula: CO2 ◆ CO₂ ◆ CO
          atoms: O => 2, C => 1
         charge: 0
aggregate_state: AS_GAS
          class: SC_GAS_FLUID
     properties: molar_mass = 44.009 g mol^-1
Comparison between species

Comparison between species are done by comparing atoms, aggregatestate and class. In the example below, vapour is not equal to H₂O since *aggregatestate* and class are different despite atoms are identical.

vapour = Species(2*:H + :O; name="Vapour", symbol="H₂O⤴", aggregate_state=AS_GAS, class=SC_GAS_FLUID)
vapour == H₂O
Remark

You will also have noticed that a calculation of the molar mass of the species is systematically carried out.


Cement Species

The manipulation of chemical formulas can also be done in cement notation. Here are examples of anhydrous phases:

C3S = CemSpecies("C3S")
C2S = CemSpecies("C2S")
C3A = CemSpecies("C3A")
C4AF = CemSpecies(Dict(:C => 4, :A => 1, :F => 1); name = "C4AF")
CemSpecies{Int64, Int64}
     cemformula: C4AF ◆ C₄AF ◆ CAF
         oxides: F => 1, A => 1, C => 4
        formula: Ca4Al2Fe2O10 ◆ Ca₄Al₂Fe₂O₁₀ ◆ CaAlFeO₁₀
          atoms: Fe => 2, O => 10, Al => 2, Ca => 4
         charge: 0
aggregate_state: AS_UNDEF
          class: SC_UNDEF
     properties: molar_mass = 485.95507680000003 g mol^-1
Warning

Not every molecule can be used to build a cement species. It is necessary for this molecule to decompose into a combination of the oxides present in the manufacturers' cement sheet (e.g. $CaO$, $SiO_2$, $Fe_2O_3$, $Al_2O_3$) and water. Thus, the following code will return an error.

CemSpecies(Species("Ca(OH)"))

Numeric and Symbolic CemSpecies

The previous species were constructed from integer values ​​of the number of chemical elements. However, other numerical value types ​​are possible (see species), such as fraction or Real values.

using ChemistryLab
ox = Dict(:C => 1.666667, :S => 1, :H => 2.1)
jennite = CemSpecies(ox)
CemSpecies{Real, Real}
           name: C₅//₃SH₂.₁
         symbol: C₅//₃SH₂.₁
     cemformula: C5//3SH2.1 ◆ C₅//₃SH₂.₁ ◆ C₅//₃SH₂.₁
         oxides: H => 2.1, S => 1, C => 1.666667
        formula: Ca5//3SiH21//5O5.76667 ◆ Ca₅//₃SiH₂₁//₅O₅.₇₆₆₆₇ ◆ Ca₅//₃SiH₂₁//₅O₅.₇₆₆₆₇
          atoms: H => 21//5, O => 5.76667, Si => 1, Ca => 5//3
         charge: 0
aggregate_state: AS_UNDEF
          class: SC_UNDEF
     properties: molar_mass = 191.3762199966667 g mol^-1

Symbolic values are also allowed. In this case, you need to use the SymPy library:

using ChemistryLab
using SymPy
â, ĝ = symbols("â ĝ", real = true)
ox = Dict(:C => â, :S => one(Sym), :H => ĝ)
CSH = CemSpecies(ox)
CemSpecies{SymPyCore.Sym{PyCall.PyObject}, SymPyCore.Sym{PyCall.PyObject}}
     cemformula: CâSHĝ ◆ CSH
         oxides: H => ĝ, S => 1, C => â
        formula: CaâSiH(2ĝ)O(â+ĝ+2) ◆ CaSiH(2ĝ)O(â+ĝ+2)
          atoms: H => 2*ĝ, O => â + ĝ + 2, Si => 1, Ca => â
         charge: 0
aggregate_state: AS_UNDEF
          class: SC_UNDEF
     properties: molar_mass = 56.077*â + 18.015*ĝ + 60.083 g mol^-1

The value of variables can be defined a posteriori.

jennite = CemSpecies(map(N, map(subs, cemformula(CSH), â => 1.666667, ĝ => 2.1)))
Remark

Conversion of coefficient types can also be done.

floatCSH = Species(convert(Float64, formula(numCSH)))

Conversion to Cement Notation

Convert species to cement notation and Unicode. Conversion can be done on simple species:

H2O = Species("H₂O")
cemH2O = CemSpecies(H2O)
CemSpecies{Int64, Int64}
           name: H₂O
         symbol: H₂O
     cemformula: H
         oxides: H => 1
        formula: H2O ◆ H₂O ◆ HO
          atoms: H => 2, O => 1
         charge: 0
aggregate_state: AS_UNDEF
          class: SC_UNDEF
     properties: molar_mass = 18.015 g mol^-1

Or more complex one:

CSH = Species("(SiO2)1(CaO)1.666667(H2O)2.1")
jennite = CemSpecies(CSH)
CemSpecies{Real, Real}
           name: (SiO2)1(CaO)1.666667(H2O)2.1
         symbol: (SiO2)1(CaO)1.666667(H2O)2.1
     cemformula: C5//3SH2.1 ◆ C₅//₃SH₂.₁ ◆ C₅//₃SH₂.₁
         oxides: C => 5//3, S => 1, H => 2.1
        formula: Ca5//3SiH21//5O5.76667 ◆ Ca₅//₃SiH₂₁//₅O₅.₇₆₆₆₇ ◆ Ca₅//₃SiH₂₁//₅O₅.₇₆₆₆₇
          atoms: Ca => 5//3, O => 5.76667, Si => 1, H => 21//5
         charge: 0
aggregate_state: AS_UNDEF
          class: SC_UNDEF
     properties: molar_mass = 191.3762199966667 g mol^-1

Species properties

Species properties are open and left to the discretion of users. Only the molar mass is systematically calculated and integrated into the species properties, for now. We can of course imagine that these properties could contain thermodynamic properties such as the Gibbs energy of formation, the heat capacity or even the entropy variation, these properties themselves being temperature dependent. These properties must nevertheless respect one of the following types: Number, AbstractVector{<:Number}, Function, AbstractString.

Imagine, for example, that we wanted to construct the jennite ($C_{1.67}SH_{2.1}$) molecule with some of its thermodynamic properties. The Gibbs energy of formation of this species is equal to -2480.81 KJ/mol. This property, intrinsic to the species, can be added simply as follows:

import Unitful: @u_str, K, J, mol, Quantity, uconvert, ustrip, unit, uparse
jennite.ΔfG⁰ = -2480.81*u"kJ/mol"
-2480.81 kJ mol^-1
function Cₚ(T, a)
    y= a[1] + a[2] * T + a[3] * T^(-2) + a[4] * T^(−0.5)
    return y
end
jennite.Cₚ = T -> Cₚ(T, [210.0*u"J/K/mol", 0.120*u"J/mol/K^2", -3.07e6*u"J*K/mol", 0.0*u"J/mol/K^(0.5)"]) #Todo unitful
jennite.Cₚ(273*u"K")
201.56798078600275 J K^-1 mol^-1