CHNOSZ website | vignettes

Customizing the thermodynamic database

Jeffrey M. Dick

This vignette was compiled on 2022-03-27 with CHNOSZ version 1.9.9-9.

This vignette will cover some topics about using custom thermodynamic data in CHNOSZ. The two main functions to remember are add.OBIGT() to add data from a CSV file and mod.OBIGT() to add or modify data through a function interface. A third function, logB_to_OBIGT(), is provided to fit thermodynamic parameters to experimental formation constants (log β).

Before describing the methods to add or modify data, some notes on the basic structure of the database and data entry conventions are given. Column names (or parts thereof) are formatted in blue (e.g. formula), and important notes are highlighted in yellow (NOTE). Function names in CHNOSZ are colored red for functions that have side effects (including those that modify the database; e.g. add.OBIGT()) and green for functions that don’t have side effects (e.g. subcrt()).

Basic structure of OBIGT

OBIGT is the name of the thermodynamic database in CHNOSZ. The data are distributed in CSV files files in the inst/extdata/OBIGT directory of the CHNOSZ package. When the package is installed, the files are copied to the exdata/OBIGT directory of the installed package location. To see where this is on your computer, run the following command.

system.file("extdata/OBIGT", package = "CHNOSZ")
## [1] "/tmp/RtmpgP3H2E/Rinst4bdb3040e14b/CHNOSZ/extdata/OBIGT"

The directory path on your computer will be different. Although possible, it is recommended NOT to edit the data files at that location. This is because they will be overwritten by any package updates; also, it is good practice to keep all the files needed for your project in a project directory.

This lists the files in that directory:

dir(system.file("extdata/OBIGT", package = "CHNOSZ"))
##  [1] "AD.csv"            "AS04.csv"          "Berman_cr.csv"    
##  [4] "DEW.csv"           "GEMSFIT.csv"       "H2O_aq.csv"       
##  [7] "SLOP98.csv"        "SUPCRT92.csv"      "biotic_aq.csv"    
## [10] "inorganic_aq.csv"  "inorganic_cr.csv"  "inorganic_gas.csv"
## [13] "organic_aq.csv"    "organic_cr.csv"    "organic_gas.csv"  
## [16] "organic_liq.csv"   "refs.csv"

Some of these files are used to build the default OBIGT database that is created when CHNOSZ starts up. There are also a number of optional data files that have additional non-default datasets. The OBIGT vignette summarizes the contents of the default and optional data files. The files can also be opened by a spreadsheet program and used as templates for adding data yourself.

OBIGT is a data frame that is populated with default CSV data files when CHNOSZ starts up or by using the reset() or OBIGT() functions. The OBIGT data frame is stored in an environment named CHNOSZ that is part of the namespace of the CHNOSZ package. More specifically, it is part of a list named thermo, which has the OBIGT database and other parameters and settings used by CHNOSZ. reset() restores the entire thermo object to default values; OBIGT() restores just the OBIGT data frame. The latter is useful for situations where you are calculating chemical affinities (with affinity()) and want to see the effects of changing the thermodynamic database.

OBIGT can be changed during an R session; if it couldn’t, this vignette would not be possible! R has the capability of saving your workspace when quitting R and loading it when R is restarted. (This is not a feature I use; my preference is to load data into a fresh session every time I start R.) This “load saved workspace” feature means that the content of OBIGT might not be the default database, even if R has just been started. To ensure that this vignette is run using the default database, we will use reset() to reset OBIGT and the other settings used by CHNOSZ.

reset()
## reset: resetting "thermo" object
## OBIGT: loading default database with 1904 aqueous, 3445 total species

thermo() is a convenience function to access or modify parts of the thermo list object. To see the first few entries in OBIGT, do this:

head(thermo()$OBIGT)
##    name abbrv formula state     ref1  ref2       date E_units      G      H
## 1 water  <NA>     H2O   liq    HGK84 JOH92 2006-10-25     cal     NA     NA
## 2    e-  <NA>   (Z-1)    aq electron  <NA> 2006-10-28     cal      0      0
## 3    H+    H+      H+    aq   proton  <NA> 1997-11-06     cal      0      0
## 4   Li+   Li+     Li+    aq     SH88  <NA> 1997-11-06     cal -69933 -66552
## 5   Na+   Na+     Na+    aq     SH88  <NA> 1997-11-06     cal -62591 -57433
## 6    K+    K+      K+    aq     SH88  <NA> 1997-11-06     cal -67510 -60270
##         S    Cp     V    a1.a   a2.b   a3.c    a4.d  c1.e   c2.f omega.lambda
## 1      NA    NA    NA      NA     NA     NA      NA    NA     NA           NA
## 2 15.6166  0.00  0.00  0.0000  0.000  0.000  0.0000  0.00  0.000       0.0000
## 3  0.0000  0.00  0.00  0.0000  0.000  0.000  0.0000  0.00  0.000       0.0000
## 4  2.7000 14.20 -0.87 -0.0237 -0.069 11.580 -2.7761 19.20 -0.240       0.4862
## 5 13.9600  9.06 -1.11  1.8390 -2.285  3.256 -2.7260 18.18 -2.981       0.3306
## 6 24.1500  1.98  9.06  3.5590 -1.473  5.435 -2.7120  7.40 -1.791       0.1927
##   z.T
## 1  NA
## 2   0
## 3   0
## 4   1
## 5   1
## 6   1

Conventions for data entry in OBIGT

Types of data, required and optional data, order-of-magnitude scaling and info().

The format of OBIGT is described in the CHNOSZ manual: see ?thermo. Next, we point out some special conventions. Here are the numbered column names for reference:

##  [1] "1 name"          "2 abbrv"         "3 formula"       "4 state"        
##  [5] "5 ref1"          "6 ref2"          "7 date"          "8 E_units"      
##  [9] "9 G"             "10 H"            "11 S"            "12 Cp"          
## [13] "13 V"            "14 a1.a"         "15 a2.b"         "16 a3.c"        
## [17] "17 a4.d"         "18 c1.e"         "19 c2.f"         "20 omega.lambda"
## [21] "21 z.T"

Types of data

Ranges of HKF and CGL models

To a first approximation, the revised HKF equations of state are applicable within the stability region of liquid water or the supercritical fluid with a density greater than 0.35 g/cm3, and not exceeding the ranges of 0 to 1000 °C and 1 to 5000 bar (see Shock et al., 1992 for details). There are two ways in which these limits are enforced in CHNOSZ:

The first three terms in the CGL heat capacity equation correspond to the Maier-Kelley equation for heat capacity (Maier and Kelley, 1932); the additional terms are useful for representing heat capacities of minerals (Robie and Hemingway, 1995) and organic gases and liquids (Helgeson et al., 1998). The upper temperature limit for applicability of the CGL heat-capacity equation corresponds to the temperature of phase transition or to a temperature beyond which extrapolations from experimental data becomes highly uncertain. A maximum temperature can be stored in the final column of OBIGT, and is used by subcrt() to replace computed values with NA above the maximum.

Required and optional data

REQUIRED:

OPTIONAL: Everything else. Really, it depends on what you need. For instance, if you just want to use subcrt() to calculate log K of a reaction from ΔG° of species at 25 °C, then G is the only parameter that is needed.

OPTIONAL but useful:

NOTE: Other functions in CHNOSZ do not depend on date, ref1, and ref2, so you can put anything there that is convenient for you.

NA or 0?

If a character value or thermodynamic parameter (Columns 1-13) is unknown, use NA. Note that a missing (blank) value in the file is treated as NA.

If an “equation-of-state” or heat capacity coefficient (Columns 14-20) is unknown, use 0.

More detail on the inner working of the functions: For both HKF and CGL, if at least one parameter for a species is provided, any NA values of the other parameters are taken to be zero. If all EOS parameters are NA, but values of Cp and/or V are present, they are assumed to be constants for extrapolating thermodynamic properties (e.g. ΔG°) as a function of temperature and pressure.

OOM scaling and info()

To make data entry easier, some values in the the CSV files and OBIGT data frame are scaled by order-of-magnitude (OOM) factors. This is particularly applicable to HKF parameters, for which OOM scaling is nearly always used in published data tables. OOM scaling is also applied to the CGL parameters. See ?thermo for details of the OOM scaling.

info() provides a simple user interface to the OBIGT database and is called by other functions in CHNOSZ to retrieve unscaled values from the database. This is a summary of its main features:

NOTE: info() does NOT change the units; the values it displays (including possibly calculated ones) correspond to the E.units() for that species. On the other hand, subcrt() outputs values in the units selected with E.units().

Case study: NA and 0 in the default database

Use the info() function to look at the database and subcrt() to calculate thermodynamic properties.

Let’s look at some minerals first. First use info() to get the species indices (i.e. rownumbers) in OBIGT, then pull out the “raw” data (including OOM scaling and any NA values).

icr <- info(c("orpiment,amorphous", "arsenic,alpha", "tin"))
thermo()$OBIGT[icr, ]
##                    name abbrv formula state ref1     ref2       date E_units
## 2031 orpiment,amorphous  <NA>   As2S3    cr NA03     <NA> 2017-10-16       J
## 2024      arsenic,alpha  <NA>      As    cr NA03 ZZL+16.1 2017-10-16       J
## 1973                tin    Sn      Sn    cr JH85     <NA> 1985-08-00     cal
##           G      H      S    Cp      V a1.a a2.b a3.c a4.d c1.e c2.f
## 2031 -76800 -66900 200.00    NA     NA   NA   NA   NA   NA   NA   NA
## 2024      0      0  35.63 24.43 12.960   NA   NA   NA   NA   NA   NA
## 1973      0      0  12.24    NA 16.289 4.42  6.3    0    0    0    0
##      omega.lambda    z.T
## 2031           NA     NA
## 2024           NA     NA
## 1973            0 505.06

Based on the values in the Cp column, would you predict that thermodynamic properties at T > 25 °C could be calculated for all of these minerals? Let’s see …

For conciseness we’ll consider a relatively small temperature range and display only the out part of the subcrt() output.

subcrt("orpiment,amorphous", T = c(25, 50, 75))$out[[1]]
## subcrt: 1 species at 3 values of T (ºC) and P (bar) [energy units: J]
##    T P    logK      G      H   S  V Cp
## 1 25 1 13.4548 -76800 -66900 200 NA NA
## 2 50 1      NA     NA     NA  NA NA NA
## 3 75 1      NA     NA     NA  NA NA NA

That makes sense; integrating NA Cp to calculate Gibbs energy and other thermodynamic properties would propagate NA, and that is what appears in the output. Now let’s run the calculation for the alpha phase of arsenic.

subcrt("arsenic,alpha", T = c(25, 50, 75))$out[[1]]
## subcrt: 1 species at 3 values of T (ºC) and P (bar) [energy units: J]
##    T P     logK         G       H       S     V    Cp
## 1 25 1 0.000000     0.000    0.00 35.6300 12.96 24.43
## 2 50 1 0.148008  -915.669  610.75 37.5971 12.96 24.43
## 3 75 1 0.281856 -1878.634 1221.50 39.4175 12.96 24.43

What happened here? Even though there are no heat capacity coefficients (see above), there is a non-NA value of Cp, and that value is used together with the entropy for calculating Gibbs energy at T > 25 °C. Note that zero for the 25 °C values of G and H is not a mistake or a placeholder for unknown values (unknown values should be represented by NA). This is the reference state for the element, for which G and H are by convention equal to zero.

Let’s look at another element in its reference state, tin:

subcrt("tin", T = c(25, 50, 75))$out[[1]]
## info.character: found tin(cr) with 1 phase transition
## subcrt: 1 species at 3 values of T (ºC) and P (bar) [energy units: J]
## subcrt: 2 phases for tin ... phase 1 is stable
##    T P     logK        G        H       S      V      Cp polymorph
## 1 25 1 0.000000     0.00    0.000 51.2122 16.289 26.3523         1
## 2 50 1 0.211328 -1307.40  667.044 53.3602 16.289 27.0113         1
## 3 75 1 0.400149 -2667.09 1350.563 55.3973 16.289 27.6702         1

Are you surprised? You might be if you only noticed the NA value for Cp in OBIGT. However, there are non-NA values for the heat capacity coefficients, which are used to calculate Cp° as a function of temperature. When supplied with a numeric argument (species index), info() actually does this to fill in missing 25 °C values of Cp, V, and G, H, or S if possible, in addition to removing OOM scaling and simplifying column names:

info(info("tin"))
## info.character: found tin(cr) with 1 phase transition
## info.numeric: Cp of tin(cr) is NA; set by EOS parameters to 6.3 cal K-1 mol-1
##      name abbrv formula state ref1 ref2       date E_units G H     S      Cp
## 1973  tin    Sn      Sn    cr JH85 <NA> 1985-08-00     cal 0 0 12.24 6.29834
##           V    a      b c d e f lambda      T
## 1973 16.289 4.42 0.0063 0 0 0 0      0 505.06

Examples of adding data from a file

Using add.OBIGT() to add data from optional data files for OBIGT or CSV files you make yourself.

add.OBIGT() with optional data files

TODO

add.OBIGT() with other CSV files

add.OBIGT() can also be used to add data from a user-specified file to the OBIGT database. The file must be a CSV (comma separated value) file with column headers that match those in the main database. As an example, here are the contents of BZA10.csv, which has parameters taken from Bazarkina et al. (2010). Missing values are indicated by NA:

file <- system.file("extdata/adds/BZA10.csv", package = "CHNOSZ")
read.csv(file, as.is = TRUE)
##      name abbrv formula state  ref1 ref2       date       G  H     S     Cp
## 1   CdCl+    NA   CdCl+    aq BZA10   NA 2010-07-03  -52629 NA  7.06  11.12
## 2   CdCl2    NA   CdCl2    aq BZA10   NA 2010-07-03  -84883 NA 25.72 116.01
## 3  CdCl3-    NA  CdCl3-    aq BZA10   NA 2010-07-03 -115399 NA 45.15  97.78
## 4 CdCl4-2    NA CdCl4-2    aq BZA10   NA 2010-07-03 -145583 NA 50.61  42.52
##       V    a1.a    a2.b    a3.c    a4.d    c1.e    c2.f omega.lambda z.T
## 1  2.20  2.2303 -2.3357  6.6681 -2.6824 16.6723 -0.7693       0.4372   1
## 2 42.21  7.5221 10.5852  1.5895 -3.2166 73.7023 20.5956      -0.0495   0
## 3 63.47 10.8045 18.5994 -1.5605 -3.5479 72.0244 16.8832       0.9378  -1
## 4 81.35 13.8329 25.9938 -4.4669 -3.8536 53.6766  5.6267       2.4766  -2

Loading the data with add.OBIGT() produces a message that the new data replace existing species. We can then use subcrt() to calculate the equilibrium constant for a reaction involving the new species. Note the decrease in the stepwise stability constant for the second cadmium chloride complex with increasing pressure (Bazarkina et al., 2010, Fig. 4).

iCd <- add.OBIGT(file)
## add.OBIGT: read 4 rows; made 4 replacements, 0 additions [energy units: cal]
subcrt(c("CdCl+", "Cl-", "CdCl2"), c(-1, -1, 1), T = 25, P = c(1, 2000))
## subcrt: 3 species at 2 values of T (ºC) and P (bar) (wet) [energy units: J]
## $reaction
##     coeff  name formula state ispecies
## 392    -1 CdCl+   CdCl+    aq      392
## 29     -1   Cl-     Cl-    aq       29
## 393     1 CdCl2   CdCl2    aq      393
## 
## $out
##    T    P      rho      logK         G       H       S       V      Cp
## 1 25    1 0.997061 0.6413808 -3661.000 2669.61 21.3384 22.6816 561.306
## 2 25 2000 1.071783 0.0618531  -353.058 2732.39 10.4541 12.2632 539.264

After running reset() we can look up the source of data in the default OBIGT database (Sverjensky et al., 1997). Running the reaction now with the default values, we see that the equilibrium constant is not as sensitive to pressure:

reset()
## reset: resetting "thermo" object
## OBIGT: loading default database with 1904 aqueous, 3445 total species
thermo.refs(iCd)[, 1:3]
##      key                                           author year
## 86 SSH97 D. A. Sverjensky, E. L. Shock and H. C. Helgeson 1997
subcrt(c("CdCl+", "Cl-", "CdCl2"), c(-1, -1, 1), T = 25, P = c(1, 2000))
## subcrt: 3 species at 2 values of T (ºC) and P (bar) (wet) [energy units: J]
## $reaction
##     coeff  name formula state ispecies
## 392    -1 CdCl+   CdCl+    aq      392
## 29     -1   Cl-     Cl-    aq       29
## 393     1 CdCl2   CdCl2    aq      393
## 
## $out
##    T    P      rho     logK        G        H        S        V      Cp
## 1 25    1 0.997061 0.619391 -3535.48 -8522.81 -16.7360 10.04043 214.488
## 2 25 2000 1.071783 0.425897 -2431.02 -9603.90 -24.0664  2.34196 191.416

Examples of adding and modifying data with a function

Use mod.OBIGT() to add or modify the database in the current session. The function requires the name of a species and one or more properties to change.

mod.OBIGT() for aqueous species

Let’s add data for CoCl4-2 from Liu et al. (2011). The values are taken from Table 5 of that paper; as is common for parameters in the HKF model, they are reported in caloric units, and some of the values have multipliers, which are kept when entering the data. The entry includes the date in ISO 8601 extended format (e.g. 2020-08-16); Sys.Date() is used in this example to get the current date.

mod.OBIGT("CoCl4-2", formula = "CoCl4-2", state = "aq", ref1 = "LBT+11", E_units = "cal",
  date = as.character(Sys.Date()), G = -134150, H = -171558, S = 19.55, Cp = 72.09, V = 27.74)
## mod.OBIGT: updated CoCl4-2(aq)
## [1] 845

The function prints a message saying that the species was added, and returns the species index of the new species. Now let’s modify the new species by adding the HKF coefficients. The z at the end refers to the charge of the species, and is used only for calculating the “g function” in the revised HKF model, not for balancing reactions.

mod.OBIGT("CoCl4-2", a1 = 6.5467, a2 = 8.2069, a3 = 2.0130, a4 = -3.1183,
  c1 = 76.3357, c2 = 11.6389, omega = 2.9159, z = -2)
## mod.OBIGT: no change for CoCl4-2(aq)
## [1] 845

Let us now calculate the equilibrium constant for the formation of CoCl4-2 from Co+2 and Cl-.

T <- c(25, seq(50, 350, 50))
sres <- subcrt(c("Co+2", "Cl-", "CoCl4-2"), c(-1, -4, 1), T = T)
round(sres$out$logK, 2)
## [1] -3.20 -2.96 -2.02 -0.74  0.77  2.50  4.57  7.29

The calculated values of logK are identical to those in Table 9 of Liu et al. (2011), which provides a good indication that the thermodynamic parameters were entered correctly. Nevertheless, this isn’t a guarantee that the thermodynamic parameters are consistent with the provided values of CP° and V°. We can see this by running info() to cross-check the parameters for the new CoCl4-2 species:

inew <- info("CoCl4-2")
info(inew)
## checkEOS: Cp of CoCl4-2(aq) differs by 1.33 cal K-1 mol-1 from tabulated value
## checkEOS: V of CoCl4-2(aq) differs by -1.19 cm3 mol-1 from tabulated value

The messages indicate that the given values of CP° and V° differ slightly from those calculated using the HKF parameters.

mod.OBIGT() for minerals

Let’s add data for magnesiochromite from Klemme et al. (2000). The parameters in this paper are reported in Joules, so we set the E.units() to J. The value for volume, in cm3 mol-1, is from Robie and Hemingway (1995).

H <- -1762000
S <- 119.6
V <- 43.56
mod.OBIGT("magnesiochromite", formula = "MgCr2O4", state = "cr", ref1 = "KOSG00",
          date = as.character(Sys.Date()), E_units = "J", H = H, S = S, V = V)
## mod.OBIGT: added magnesiochromite(cr) with energy units of J
## [1] 3446

Here are the heat capacity parameters for the “Haas-Fisher” polynomial equation (Cp = a + bT + cT − 2 + dT − 0.5 + eT2). Order-of-magnitude multipliers are required for the values of b and c (and also e if it is present; see the description for columns 14-21 of the OBIGT data frame in ?thermo). Note that an additional f term is available, which can have any exponent given by lambda, but it is not needed here. 1500 K is a generic value for the high-temperature limit; experimental heat capacities were only reported up to 340 K (Klemme et al., 2000).

a <- 221.4
b <- -0.00102030 * 1e3
c <- -1757210 * 1e-5
d <- -1247.9
mod.OBIGT("magnesiochromite", E_units = "J", a = a, b = b, c = c, d = d,
          e = 0, f = 0, lambda = 0, T = 1500)
## mod.OBIGT: updated magnesiochromite(cr)
## [1] 3446

Now we can use subcrt() to calculate the heat capacity of magnesiochromite. For this calculation, we set the temperature units to Kelvin. We also specify a pressure of 1 bar to prevent an error in the calculation of Psat below the freezing temperature of water.

T.units("K")
## changed temperature units to K
subcrt("magnesiochromite", property = "Cp", T = c(250, 300, 340), P = 1)
## subcrt: 1 species at 3 values of T (K) and P (bar) [energy units: J]
## $species
##                  name formula state ispecies
## 3446 magnesiochromite MgCr2O4    cr     3446
## 
## $out
## $out$magnesiochromite
##     T P      Cp
## 1 250 1 114.105
## 2 300 1 129.522
## 3 340 1 138.175

The calculated values are with 0.1 J K-1 mol-1 of those shown in Fig. 1 of Klemme et al. (2000).

Finally, let’s restore the units setting for later calculations with subcrt(). (Another way would be to run reset(), which also resets the OBIGT database.)

T.units("C")
## changed temperature units to C

Other models

Here we’ll look at how to add minerals that use the Berman equations and aqueous nonelectrolytes that use the Akinfiev-Diamond model.

Akinfiev-Diamond model

The Akinfiev-Diamond model for aqueous species (Akinfiev and Diamond, 2003) is activated by setting in thermo() for a given aqueous species. The database must also include a corresponding gasesous species with the same name or chemical formula.

TODO

TODO: Add van’t Hoff example?

Case study: Formation constants for aqueous tungsten species

Here we use logB_to_OBIGT() to fit formation constants to thermodynamic parameters using a constant heat capacity. Some additional steps are shown to refine a thermodynamic model to generate a speciation diagram as a function of pH.

Fitting formation constants

logB_to_OBIGT() requires three things:

logB_to_OBIGT() does three things:

First we set the pressure for all log β data.

P <- "Psat"

Add first species: HWO4- (Wang et al., 2019).

T <- c(250, 300, 350)
logB <- c(5.58, 6.51, 7.99)
species <- c("WO4-2", "H+", "HWO4-")
coeff <- c(-1, -1, 1)
logB_to_OBIGT(logB, species, coeff, T, P)
## mod.OBIGT: updated HWO4-(aq)
## logB_to_OBIGT: mean absolute difference between logB (experimental) and logK (calculated) is 0.0199
## [1] 442

Add second species: H3WO4F2- (Wang et al., 2021).

T <- seq(100, 250, 25)
logB <- c(17.00, 17.11, 17.46, 17.75, 18.17, 18.71, 19.23)
# Species and coefficients in the formation reaction
species <- c("H+", "WO4-2", "F-", "H3WO4F2-")
coeff <- c(-3, -1, -2, 1)
logB_to_OBIGT(logB, species, coeff, T, P)
## mod.OBIGT: updated H3WO4F2-(aq)
## logB_to_OBIGT: mean absolute difference between logB (experimental) and logK (calculated) is 0.0307
## [1] 3447

Add third species: H2WO4 (Wang et al., 2021). We have to increase the tolerance because there is considerable scatter in the experimental values.

logB <- c(7.12, 7.82, 7.07, 7.76, 7.59, 7.98, 8.28)
species <- c("H+", "WO4-2", "H2WO4")
coeff <- c(-2, -1, 1)
logB_to_OBIGT(logB, species, coeff, T, P, tolerance = 0.3)
## mod.OBIGT: updated H2WO4(aq)
## logB_to_OBIGT: mean absolute difference between logB (experimental) and logK (calculated) is 0.2035
## [1] 884

We can tell from the low species indices of HWO4- (442) and H2WO4 (884) that logB_to_OBIGT() replaced parameters for these species that were already present in OBIGT.

Diagram 1: Constant molality of F-

Now we’re ready to make a speciation diagram. Our target is to reproduce Fig. 7b of Wang et al. (2021), which is made for 300 °C. A constant molality of F- is based on the assumption of complete dissociation of 0.1 m NaF (we’ll change this later). An ionic strength of 1.2 mol/kg is estimated for a solution with 1.8 m NaCl (use NaCl(300, m_tot = 1.8)). NOTE: because the ionic strength is non-zero, the calculations here refer to molality instead of activity of species (see An Introduction to CHNOSZ).

basis(c("H+", "WO4-2", "F-", "H2O", "O2"))
basis("F-", log10(0.1))
iaq <- retrieve("W", c("O", "H", "F"), "aq")
species(iaq)
a <- affinity(pH = c(2, 7), T = 300, IS = 1.2)
e <- equilibrate(a)
col <- c(1, 4, 5, 2)
diagram(e, alpha = TRUE, col = col, lty = 1, lwd = 2, ylab = "Fraction total W")

This isn’t quite the diagram we were looking for. The published diagram shows a broad region of coexistence of H3WO4F2- and HWO4- at pH < 5 and increasing abundance of H2WO4 at lower pH.

Diagram 2: Variable molality of F-

In reality, the molality of F- depends strongly on pH according to the reaction H+ + F- = HF. With a little algebra, we can calculate the molality of F- (a_F in the code below) from the equilbrium constant of this reaction for a given total F concentration (F_tot). NOTE: It is important to call subcrt() with a non-zero IS so that it returns effective equilibrium constants corrected for ionic strength (see what hapens to the diagram if you set IS = 0).

T <- 300
pH <- seq(2, 7, 0.1)
logK_HF <- subcrt(c("H+", "F-", "HF"), c(-1, -1, 1), T = T, IS = 1.2)$out$logK
## info.character: found HF(aq); also available in gas
## subcrt: 3 species at 300 ºC and 85.84 bar (wet) [energy units: J]
## nonideal: calculations for F- (Bdot equation)
## nonideal: calculations for HF (Setchenow equation)
F_tot <- 0.1
a_F <- F_tot / (1 + 10^(logK_HF - pH))

Now that we have the molality of F- as a function of pH, we can provide it in the call to affinity().

basis(c("H+", "WO4-2", "F-", "H2O", "O2"))
iaq <- retrieve("W", c("O", "H", "F"), "aq")
species(iaq)
a <- affinity(pH = pH, "F-" = log10(a_F), T = T, IS = 1.2)
e <- equilibrate(a)
diagram(e, alpha = TRUE, col = col, lty = 1, lwd = 2, ylab = "Fraction total W")

That’s more like it. We have captured the basic geometry of Fig. 7b in Wang et al. (2021). For instance, in accord with the published diagram, HWO4- plateaus at around 40% of total W, and H2WO4 and H3WO4F2- are nearly equally abundant at pH = 2.

The highest experimental temperature for the formation constants of H2WO4 and H3WO4F2- is 250 °C, but this diagram is drawn for 300 °C. Wang et al. (2021) used the modified Ryzhenko-Bryzgalin (MRB) model to extrapolate to 300 °C. In contrast, we used a different model but obtained quite similar results.

NOTE: The coefficients in the model used by logB_to_OBIGT() are 25 °C values of G, S, and Cp. In a conservative interpretation, these should be regarded only as fitting parameters, and should not be used to compute thermodynamic properties close to 25 °C unless they were fit to experimental data in that temperature range.

References

Akinfiev NN, Diamond LW. 2003. Thermodynamic description of aqueous nonelectrolytes at infinite dilution over a wide range of state parameters. Geochimica et Cosmochimica Acta 67(4): 613–629. doi: 10.1016/S0016-7037(02)01141-9

Bazarkina EF, Zotov AV, Akinfiev NN. 2010. Pressure-dependent stability of cadmium chloride complexes: Potentiometric measurements at 1-1000 bar and 25°C. Geology of Ore Deposits 52(2): 167–178. doi: 10.1134/S1075701510020054

Helgeson HC, Owens CE, Knox AM, Richard L. 1998. Calculation of the standard molal thermodynamic properties of crystalline, liquid, and gas organic molecules at high temperatures and pressures. Geochimica et Cosmochimica Acta 62(6): 985–1081. doi: 10.1016/S0016-7037(97)00219-6

Klemme S, O’Neill HS, Schnelle W, Gmelin E. 2000. The heat capacity of MgCr2O4, FeCr2O4, and Cr2O3 at low temperatures and derived thermodynamic properties. American Mineralogist 85(11-12): 1686–1693. doi: 10.2138/am-2000-11-1212

Liu W, Borg SJ, Testemale D, Etschmann B, Hazemann J-L, Brugger J. 2011. Speciation and thermodynamic properties for cobalt chloride complexes in hydrothermal fluids at 35–440 °C and 600 bar: An in-situ XAS study. Geochimica et Cosmochimica Acta 75(5): 1227–1248. doi: 10.1016/j.gca.2010.12.002

Maier CG, Kelley KK. 1932. An equation for the representation of high-temperature heat content data. Journal of the American Chemical Society 54(8): 3243–3246. doi: 10.1021/ja01347a029

Robie RA, Hemingway BS. 1995. Thermodynamic Properties of Minerals and Related Substances at 298.15 K and 1 Bar (105 Pascals) Pressure and at Higher Temperatures. Washington, D.C.: U.S. Geological Survey. (Bulletin 2131). doi: 10.3133/b2131

Shock EL, Oelkers EH, Johnson JW, Sverjensky DA, Helgeson HC. 1992. Calculation of the thermodynamic properties of aqueous species at high pressures and temperatures: Effective electrostatic radii, dissociation constants, and standard partial molal properties to 1000 °C and 5 kbar. Journal of the Chemical Society, Faraday Transactions 88(6): 803–826. doi: 10.1039/FT9928800803

Sverjensky DA, Harrison B, Azzolini D. 2014. Water in the deep Earth: The dielectric constant and the solubilities of quartz and corundum to 60 kb and 1,200 °C. Geochimica et Cosmochimica Acta 129: 125–145. doi: 10.1016/j.gca.2013.12.019

Sverjensky DA, Shock EL, Helgeson HC. 1997. Prediction of the thermodynamic properties of aqueous metal complexes to 1000°C and 5 kb. Geochimica et Cosmochimica Acta 61(7): 1359–1412. doi: 10.1016/S0016-7037(97)00009-4

Wang X-S, Timofeev A, Williams-Jones AE, Shang L-B, Bi X-W. 2019. An experimental study of the solubility and speciation of tungsten in NaCl-bearing aqueous solutions at 250, 300, and 350 °C. Geochimica et Cosmochimica Acta 265: 313–329. doi: 10.1016/j.gca.2019.09.013

Wang X-S, Williams-Jones AE, Hu R-Z, Shang L-B, Bi X-W. 2021. The role of fluorine in granite-related hydrothermal tungsten ore genesis: Results of experiments and modeling. Geochimica et Cosmochimica Acta 292: 170–187. doi: 10.1016/j.gca.2020.09.032