[CHNOSZ-commits] r205 - in pkg/CHNOSZ: . R data demo inst inst/extdata/OBIGT man tests/testthat vignettes

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Thu Jul 27 02:01:57 CEST 2017


Author: jedick
Date: 2017-07-27 02:01:56 +0200 (Thu, 27 Jul 2017)
New Revision: 205

Added:
   pkg/CHNOSZ/R/add.obigt.R
   pkg/CHNOSZ/demo/adenine.R
   pkg/CHNOSZ/inst/extdata/OBIGT/CHNOSZ_aq.csv
   pkg/CHNOSZ/man/add.obigt.Rd
Removed:
   pkg/CHNOSZ/inst/extdata/OBIGT/CHNOSZ_aq.csv.xz
Modified:
   pkg/CHNOSZ/DESCRIPTION
   pkg/CHNOSZ/R/examples.R
   pkg/CHNOSZ/R/transfer.R
   pkg/CHNOSZ/R/util.data.R
   pkg/CHNOSZ/data/refs.csv
   pkg/CHNOSZ/data/thermo.R
   pkg/CHNOSZ/demo/00Index
   pkg/CHNOSZ/demo/activity_ratios.R
   pkg/CHNOSZ/inst/NEWS
   pkg/CHNOSZ/man/EOSregress.Rd
   pkg/CHNOSZ/man/examples.Rd
   pkg/CHNOSZ/man/transfer.Rd
   pkg/CHNOSZ/man/util.data.Rd
   pkg/CHNOSZ/tests/testthat/test-util.data.R
   pkg/CHNOSZ/vignettes/anintro.Rmd
   pkg/CHNOSZ/vignettes/eos-regress.Rmd
   pkg/CHNOSZ/vignettes/obigt.Rmd
   pkg/CHNOSZ/vignettes/obigt.bib
   pkg/CHNOSZ/vignettes/vig.bib
Log:
add adenine (Lowe et al., 2017) to CHNOSZ_aq.csv


Modified: pkg/CHNOSZ/DESCRIPTION
===================================================================
--- pkg/CHNOSZ/DESCRIPTION	2017-06-06 14:35:05 UTC (rev 204)
+++ pkg/CHNOSZ/DESCRIPTION	2017-07-27 00:01:56 UTC (rev 205)
@@ -1,14 +1,14 @@
-Date: 2017-06-06
+Date: 2017-07-27
 Package: CHNOSZ
-Version: 1.1.0-3
+Version: 1.1.0-4
 Title: Chemical Thermodynamics and Activity Diagrams
 Author: Jeffrey Dick
 Maintainer: Jeffrey Dick <j3ffdick at gmail.com>
 Depends: R (>= 3.1.0)
 Suggests: limSolve, testthat, knitr, rmarkdown, tufte, RSVGTipsDevice
 Imports: grDevices, graphics, stats, utils, colorspace
-Description: An integrated set of tools for thermodynamic calculations in compositional
-  biology and geochemistry. Thermodynamic properties are taken from a database for minerals
+Description: An integrated set of tools for thermodynamic calculations in geochemistry and
+  compositional biology. Thermodynamic properties are taken from a database for minerals
   and inorganic and organic aqueous species including biomolecules, or from amino acid
   group additivity for proteins. High-temperature properties are calculated using the
   revised Helgeson-Kirkham-Flowers equations of state for aqueous species. Functions are

Added: pkg/CHNOSZ/R/add.obigt.R
===================================================================
--- pkg/CHNOSZ/R/add.obigt.R	                        (rev 0)
+++ pkg/CHNOSZ/R/add.obigt.R	2017-07-27 00:01:56 UTC (rev 205)
@@ -0,0 +1,162 @@
+# CHNOSZ/add.obigt.R
+# add or change entries in the thermodynamic database
+
+today <- function() {
+  # write today's date in the format used in SUPCRT data files
+  # e.g. 13.May.12 for 2012-05-13
+  t <- date()
+  tt <- unlist(strsplit(t, " "))
+  # for single-digit days there is an extra space
+  tt <- tt[!tt==""]
+  tday <- tt[3]
+  tmonth <- tt[2]
+  tyear <- substr(tt[5], start=3, stop=4)
+  return(paste(tday, tmonth, tyear, sep="."))
+}
+
+mod.obigt <- function(...) {
+  # add or modify species in thermo$obigt
+  thermo <- get("thermo")
+  # the names and values are in the arguments
+  # this works for providing arguments via do.call
+  args <- list(...)
+  # this is needed if we are called with a list as the actual argument
+  if(is.list(args[[1]])) args <- args[[1]]
+  if(length(args) < 2) stop("please supply at least a species name and a property to update")
+  if(is.null(names(args))) stop("please supply named arguments")
+  # if the first argument is numeric, it's the species index
+  if(is.numeric(args[[1]][1])) {
+    ispecies <- args[[1]]
+  } else {
+    # if the name of the first argument is missing, assume it's the species name
+    if(names(args)[1]=="") names(args)[1] <- "name"
+    # search for this species, use check.protein=FALSE to avoid infinite loop when adding proteins
+    # and suppressMessages to not show messages about matches of this name to other states
+    if("state" %in% names(args)) ispecies <- suppressMessages(mapply(info.character, 
+      species=args$name, state=args$state, check.protein=FALSE, SIMPLIFY=TRUE, USE.NAMES=FALSE))
+    else ispecies <- suppressMessages(mapply(info.character, 
+      species=args$name, check.protein=FALSE, SIMPLIFY=TRUE, USE.NAMES=FALSE))
+  }
+  # the column names of thermo$obigt, split at the "."
+  cnames <- c(do.call(rbind, strsplit(colnames(thermo$obigt), ".", fixed=TRUE)), colnames(thermo$obigt))
+  # the columns we are updating
+  icol <- match(names(args), cnames)
+  if(any(is.na(icol))) stop(paste("properties not in thermo$obigt:", paste(names(args)[is.na(icol)], collapse=" ")) )
+  # the column numbers for properties that matched after the split
+  icol[icol > 40] <- icol[icol > 40] - 40
+  icol[icol > 20] <- icol[icol > 20] - 20
+  # which species are new and which are old
+  inew <- which(is.na(ispecies))
+  iold <- which(!is.na(ispecies))
+  # the arguments as data frame
+  args <- data.frame(args, stringsAsFactors=FALSE)
+  if(length(inew) > 0) {
+    # the right number of blank rows of thermo$obigt
+    newrows <- thermo$obigt[1:length(inew), ]
+    # if we don't know something it's NA
+    newrows[] <- NA
+    # put in a default state
+    newrows$state <- thermo$opt$state
+    # the formula defaults to the name
+    newrows$formula <- args$name[inew]
+    # fill in the columns
+    newrows[, icol] <- args[inew, ]
+    # now check the formulas
+    e <- tryCatch(makeup(newrows$formula), error=function(e) e)
+    if(inherits(e, "error")) {
+      warning("please supply a valid chemical formula as the species name or in the 'formula' argument")
+      # transmit the error from makeup
+      stop(e)
+    }
+    # assign to thermo$obigt
+    thermo$obigt <- rbind(thermo$obigt, newrows)
+    rownames(thermo$obigt) <- NULL
+    assign("thermo", thermo, "CHNOSZ")
+    # update ispecies
+    ntotal <- nrow(thermo$obigt)
+    ispecies[inew] <- (ntotal-length(inew)+1):ntotal
+    # inform user
+    message(paste("mod.obigt: added ", newrows$name, "(", newrows$state, ")", sep="", collapse="\n"))
+  }
+  if(length(iold) > 0) {
+    # loop over species
+    for(i in 1:length(iold)) {
+      # the old values and the state
+      oldprop <- thermo$obigt[ispecies[iold[i]], icol]
+      state <- thermo$obigt$state[ispecies[iold[i]]]
+      # tell user if they're the same, otherwise update the data entry
+      if(isTRUE(all.equal(oldprop, args[iold[i], ], check.attributes=FALSE))) 
+        message("mod.obigt: no change for ", args$name[iold[i]], "(", state, ")")
+      else {
+        thermo$obigt[ispecies[iold[i]], icol] <- args[iold[i], ]
+        assign("thermo", thermo, "CHNOSZ")
+        message("mod.obigt: updated ", args$name[iold[i]], "(", state, ")")
+      }
+    }
+  }
+  return(ispecies)
+}
+
+add.obigt <- function(file, force=TRUE, E.units="cal") {
+  # add/replace entries in thermo$obigt from values saved in a file
+  # only replace if force==TRUE
+  thermo <- get("thermo")
+  to1 <- thermo$obigt
+  id1 <- paste(to1$name,to1$state)
+  # is the source the name of a species or a file?
+  CHNOSZfile <- system.file("extdata/OBIGT/CHNOSZ_aq.csv", package="CHNOSZ")
+  dat <- read.csv(CHNOSZfile, as.is=TRUE)
+  idat <- match(file, dat$name)
+  newdat <- dat[idat, ]
+  if(!all(is.na(newdat))) to2 <- newdat  # a species
+  else to2 <- read.csv(file,as.is=TRUE)  # a file
+  id2 <- paste(to2$name,to2$state)
+  # check if the data is compatible with thermo$obigt
+  tr <- try(rbind(to1,to2),silent=TRUE)
+  if(identical(class(tr),'try-error')) stop(paste(file,"is not compatible with thermo$obigt data table."))
+  # match the new species to existing ones
+  does.exist <- id2 %in% id1
+  ispecies.exist <- na.omit(match(id2, id1))
+  nexist <- sum(does.exist)
+  # convert from J if necessary
+  if(tolower(E.units)=="j") {
+    # loop over each row
+    for(i in 1:nrow(to2)) {
+      # GHS and EOS parameters
+      icol <- (8:18)
+      # if it's aqueous, also include omega
+      if(to2$state[i]=="aq") icol <-(8:19)
+      # don't touch volume (in column 12)
+      icol <- icol[icol!=12]
+      # convert to calories
+      to2[i,icol] <- convert(to2[i,icol],"cal")
+    }
+  }
+  # keep track of the species we've added
+  inew <- numeric()
+  if(force) {
+    # replace existing entries
+    if(nexist > 0) {
+      to1[ispecies.exist, ] <- to2[does.exist, ]
+      to2 <- to2[!does.exist, ]
+      inew <- c(inew, ispecies.exist)
+    }
+  } else {
+    # ignore any new entries that already exist
+    to2 <- to2[!does.exist, ]
+    nexist <- 0
+  }
+  # add new entries
+  if(nrow(to2) > 0) {
+    to1 <- rbind(to1, to2)
+    inew <- c(inew, (length(id1)+1):nrow(to1))
+  }
+  # commit the change
+  thermo$obigt <- to1
+  rownames(thermo$obigt) <- 1:nrow(thermo$obigt)
+  assign("thermo", thermo, "CHNOSZ")
+  message("add.obigt: read ", length(does.exist), " rows; made ", 
+    nexist, " replacements, ", nrow(to2), " additions, units = ", E.units)
+  message("add.obigt: use data(thermo) to restore default database")
+  return(invisible(inew))
+}

Modified: pkg/CHNOSZ/R/examples.R
===================================================================
--- pkg/CHNOSZ/R/examples.R	2017-06-06 14:35:05 UTC (rev 204)
+++ pkg/CHNOSZ/R/examples.R	2017-07-27 00:01:56 UTC (rev 205)
@@ -28,7 +28,8 @@
 
 demos <- function(which=c("sources", "protein.equil", "affinity", "NaCl", "density", 
   "ORP", "revisit", "findit", "ionize", "buffer", "protbuff", "yeastgfp", "mosaic",
-  "copper", "solubility", "wjd", "dehydration", "bugstab", "Shh", "activity_ratios"), to.file=FALSE) {
+  "copper", "solubility", "wjd", "dehydration", "bugstab", "Shh", "activity_ratios",
+  "adenine"), to.file=FALSE) {
   # run one or more demos from CHNOSZ with ask=FALSE, and return the value of the last one
   for(i in 1:length(which)) {
     # say something so the user sees where we are

Modified: pkg/CHNOSZ/R/transfer.R
===================================================================
--- pkg/CHNOSZ/R/transfer.R	2017-06-06 14:35:05 UTC (rev 204)
+++ pkg/CHNOSZ/R/transfer.R	2017-07-27 00:01:56 UTC (rev 205)
@@ -806,6 +806,8 @@
   # or feldspar("open")
   # setup conditions for feldspar reaction
   basis(delete=TRUE)
+  # make pseudo-H4SiO4 available
+  add.obigt("pseudo-H4SiO4")
   basis(c('Al+3','pseudo-H4SiO4','K+','H2O','H+','O2'))
   # some of SLS94's initial conditions
   basis(c('K+','H4SiO4'),c(-6,-6))

Modified: pkg/CHNOSZ/R/util.data.R
===================================================================
--- pkg/CHNOSZ/R/util.data.R	2017-06-06 14:35:05 UTC (rev 204)
+++ pkg/CHNOSZ/R/util.data.R	2017-07-27 00:01:56 UTC (rev 205)
@@ -1,165 +1,6 @@
 # CHNOSZ/util.data.R
-# add or change entries in the thermodynamic database
+# check entries in the thermodynamic database
 
-today <- function() {
-  # write today's date in the format used in SUPCRT data files
-  # e.g. 13.May.12 for 2012-05-13
-  t <- date()
-  tt <- unlist(strsplit(t, " "))
-  # for single-digit days there is an extra space
-  tt <- tt[!tt==""]
-  tday <- tt[3]
-  tmonth <- tt[2]
-  tyear <- substr(tt[5], start=3, stop=4)
-  return(paste(tday, tmonth, tyear, sep="."))
-}
-
-mod.obigt <- function(...) {
-  # add or modify species in thermo$obigt
-  thermo <- get("thermo")
-  # the names and values are in the arguments
-  # this works for providing arguments via do.call
-  args <- list(...)
-  # this is needed if we are called with a list as the actual argument
-  if(is.list(args[[1]])) args <- args[[1]]
-  if(length(args) < 2) stop("please supply at least a species name and a property to update")
-  if(is.null(names(args))) stop("please supply named arguments")
-  # if the first argument is numeric, it's the species index
-  if(is.numeric(args[[1]][1])) {
-    ispecies <- args[[1]]
-  } else {
-    # if the name of the first argument is missing, assume it's the species name
-    if(names(args)[1]=="") names(args)[1] <- "name"
-    # search for this species, use check.protein=FALSE to avoid infinite loop when adding proteins
-    # and suppressMessages to not show messages about matches of this name to other states
-    if("state" %in% names(args)) ispecies <- suppressMessages(mapply(info.character, 
-      species=args$name, state=args$state, check.protein=FALSE, SIMPLIFY=TRUE, USE.NAMES=FALSE))
-    else ispecies <- suppressMessages(mapply(info.character, 
-      species=args$name, check.protein=FALSE, SIMPLIFY=TRUE, USE.NAMES=FALSE))
-  }
-  # the column names of thermo$obigt, split at the "."
-  cnames <- c(do.call(rbind, strsplit(colnames(thermo$obigt), ".", fixed=TRUE)), colnames(thermo$obigt))
-  # the columns we are updating
-  icol <- match(names(args), cnames)
-  if(any(is.na(icol))) stop(paste("properties not in thermo$obigt:", paste(names(args)[is.na(icol)], collapse=" ")) )
-  # the column numbers for properties that matched after the split
-  icol[icol > 40] <- icol[icol > 40] - 40
-  icol[icol > 20] <- icol[icol > 20] - 20
-  # which species are new and which are old
-  inew <- which(is.na(ispecies))
-  iold <- which(!is.na(ispecies))
-  # the arguments as data frame
-  args <- data.frame(args, stringsAsFactors=FALSE)
-  if(length(inew) > 0) {
-    # the right number of blank rows of thermo$obigt
-    newrows <- thermo$obigt[1:length(inew), ]
-    # if we don't know something it's NA
-    newrows[] <- NA
-    # put in a default state
-    newrows$state <- thermo$opt$state
-    # the formula defaults to the name
-    newrows$formula <- args$name[inew]
-    # fill in the columns
-    newrows[, icol] <- args[inew, ]
-    # now check the formulas
-    e <- tryCatch(makeup(newrows$formula), error=function(e) e)
-    if(inherits(e, "error")) {
-      warning("please supply a valid chemical formula as the species name or in the 'formula' argument")
-      # transmit the error from makeup
-      stop(e)
-    }
-    # assign to thermo$obigt
-    thermo$obigt <- rbind(thermo$obigt, newrows)
-    rownames(thermo$obigt) <- NULL
-    assign("thermo", thermo, "CHNOSZ")
-    # update ispecies
-    ntotal <- nrow(thermo$obigt)
-    ispecies[inew] <- (ntotal-length(inew)+1):ntotal
-    # inform user
-    message(paste("mod.obigt: added ", newrows$name, "(", newrows$state, ")", sep="", collapse="\n"))
-  }
-  if(length(iold) > 0) {
-    # loop over species
-    for(i in 1:length(iold)) {
-      # the old values and the state
-      oldprop <- thermo$obigt[ispecies[iold[i]], icol]
-      state <- thermo$obigt$state[ispecies[iold[i]]]
-      # tell user if they're the same, otherwise update the data entry
-      if(isTRUE(all.equal(oldprop, args[iold[i], ], check.attributes=FALSE))) 
-        message("mod.obigt: no change for ", args$name[iold[i]], "(", state, ")")
-      else {
-        thermo$obigt[ispecies[iold[i]], icol] <- args[iold[i], ]
-        assign("thermo", thermo, "CHNOSZ")
-        message("mod.obigt: updated ", args$name[iold[i]], "(", state, ")")
-      }
-    }
-  }
-  return(ispecies)
-}
-
-add.obigt <- function(file, force=FALSE, E.units="cal") {
-  # add/replace entries in thermo$obigt from values saved in a file
-  # only replace if force==TRUE
-  thermo <- get("thermo")
-  to1 <- thermo$obigt
-  id1 <- paste(to1$name,to1$state)
-  to2 <- read.csv(file,as.is=TRUE)
-  id2 <- paste(to2$name,to2$state)
-  # check if the file is compatible with thermo$obigt
-  tr <- try(rbind(to1,to2),silent=TRUE)
-  if(identical(class(tr),'try-error')) stop(paste(file,"is not compatible with thermo$obigt data table."))
-  # match the new species to existing ones
-  does.exist <- id2 %in% id1
-  ispecies.exist <- na.omit(match(id2, id1))
-  nexist <- sum(does.exist)
-  # convert from J if necessary
-  if(tolower(E.units)=="j") {
-    # loop over each row
-    for(i in 1:nrow(to2)) {
-      # GHS and EOS parameters
-      icol <- (8:18)
-      # if it's aqueous, also include omega
-      if(to2$state[i]=="aq") icol <-(8:19)
-      # don't touch volume (in column 12)
-      icol <- icol[icol!=12]
-      # convert to calories
-      to2[i,icol] <- convert(to2[i,icol],"cal")
-    }
-  }
-  # keep track of the species we've added
-  inew <- numeric()
-  if(force) {
-    # replace existing entries
-    if(nexist > 0) {
-      to1[ispecies.exist, ] <- to2[does.exist, ]
-      to2 <- to2[!does.exist, ]
-      inew <- c(inew, ispecies.exist)
-    }
-  } else {
-    # ignore any new entries that already exist
-    to2 <- to2[!does.exist, ]
-    nexist <- 0
-  }
-  # add new entries
-  if(nrow(to2) > 0) {
-    to1 <- rbind(to1, to2)
-    inew <- c(inew, (length(id1)+1):nrow(to1))
-  }
-  # commit the change
-  thermo$obigt <- to1
-  rownames(thermo$obigt) <- 1:nrow(thermo$obigt)
-  assign("thermo", thermo, "CHNOSZ")
-  # message about file, if file argument is missing (default)
-  if(missing(file)) {
-    message("add.obigt: using default file:") 
-    message(file)
-  }
-  message("add.obigt: read ", length(does.exist), " rows; made ", 
-    nexist, " replacements, ", nrow(to2), " additions, units = ", E.units)
-  message("add.obigt: use data(thermo) to restore default database")
-  return(invisible(inew))
-}
-
 thermo.refs <- function(key=NULL) {
   ## return references for thermodynamic data.
   ## 20110615 browse.refs() first version

Modified: pkg/CHNOSZ/data/refs.csv
===================================================================
--- pkg/CHNOSZ/data/refs.csv	2017-06-06 14:35:05 UTC (rev 204)
+++ pkg/CHNOSZ/data/refs.csv	2017-07-27 00:01:56 UTC (rev 205)
@@ -116,3 +116,4 @@
 CHNOSZ.6,"J. M. Dick",2017,"CHNOSZ package documentation","dipeptides not included in slop files after slop98.dat",http://chnosz.net
 CHNOSZ.7,"J. M. Dick",2017,"CHNOSZ package documentation","charge of NpO2(Oxal), La(Succ)+, NH4(Succ)-, and NpO2(Succ) as listed by @PSK99",http://chnosz.net
 CHNOSZ.8,"J. M. Dick",2017,"CHNOSZ package documentation","Incorrect values of HKF a<sub>1</sub>--a<sub>4</sub> parameters for [-CH2NH2] were printed in Table 6 of @DLH06; corrected values are used here.",http://chnosz.net
+LCT17,"A. R. Lowe, J. S. Cox and P. R. Tremaine",2017,"J. Chem. Thermodynamics 112, 129-145","adenine Cp and V",https://doi.org/10.1016/j.jct.2017.04.005

Modified: pkg/CHNOSZ/data/thermo.R
===================================================================
--- pkg/CHNOSZ/data/thermo.R	2017-06-06 14:35:05 UTC (rev 204)
+++ pkg/CHNOSZ/data/thermo.R	2017-07-27 00:01:56 UTC (rev 205)
@@ -9,7 +9,7 @@
 
 local({
   # create obigt data frame
-  sources_aq <- paste0(c("H2O", "inorganic", "organic", "biotic", "CHNOSZ"), "_aq")
+  sources_aq <- paste0(c("H2O", "inorganic", "organic", "biotic"), "_aq")
   sources_cr <- paste0(c("inorganic", "organic"), "_cr")
   sources_liq <- paste0(c("organic"), "_liq")
   sources_gas <- paste0(c("inorganic", "organic"), "_gas")

Modified: pkg/CHNOSZ/demo/00Index
===================================================================
--- pkg/CHNOSZ/demo/00Index	2017-06-06 14:35:05 UTC (rev 204)
+++ pkg/CHNOSZ/demo/00Index	2017-07-27 00:01:56 UTC (rev 205)
@@ -18,3 +18,4 @@
 bugstab         formation potential of microbial proteins in colorectal cancer
 Shh             affinities of transcription factors relative to Sonic hedgehog
 activity_ratios mineral stability plots with activity ratios on the axes
+adenine         HKF parameters regressed from heat capacity and volume of aqueous adenine

Modified: pkg/CHNOSZ/demo/activity_ratios.R
===================================================================
--- pkg/CHNOSZ/demo/activity_ratios.R	2017-06-06 14:35:05 UTC (rev 204)
+++ pkg/CHNOSZ/demo/activity_ratios.R	2017-07-27 00:01:56 UTC (rev 205)
@@ -10,8 +10,8 @@
 ## Steinmann et al., 1994 (http://ccm.geoscienceworld.org/content/42/2/197)
 ## Garrels and Christ, p. 361 (http://www.worldcat.org/oclc/517586)
 ## https://wwwbrr.cr.usgs.gov/projects/GWC_coupled/phreeqc/html/final-75.html
-# the pseudospecies H4SiO4 is used as a basis species
-# (see the vignette "Regressing thermodynamic data")
+# make the pseudospecies H4SiO4 available for use as a basis species
+add.obigt("pseudo-H4SiO4")
 basis(c("Al+3", "pseudo-H4SiO4", "K+", "H2O", "H+", "O2"))
 species(c("gibbsite", "muscovite", "kaolinite", "pyrophyllite", "k-feldspar"))
 a <- affinity(H4SiO4 = c(-6, -2, res), `K+` = c(-3, 6, res))

Added: pkg/CHNOSZ/demo/adenine.R
===================================================================
--- pkg/CHNOSZ/demo/adenine.R	                        (rev 0)
+++ pkg/CHNOSZ/demo/adenine.R	2017-07-27 00:01:56 UTC (rev 205)
@@ -0,0 +1,117 @@
+# CHNOSZ/demos/adenine.R
+# plot thermodynamic data and model fits for aqueous adenine 20170725
+
+# notable functions in this demo:
+# EOSregress() - to regress HKF coefficients from Cp data
+# add.obigt() - to add thermodynamic data that are not in the default database
+
+# LCT17 = Lowe et al., 2017 (J. Chem. Thermodyn., doi:10.1016/j.jct.2017.04.005)
+# LH06 = LaRowe and Helgeson, 2006 (Geochim. Cosmochim. Acta, doi:10.1016/j.gca.2006.04.010)
+# HKF = Helgeson-Kirkham-Flowers equations (e.g. Am. J. Sci., doi:10.2475/ajs.281.10.1249)
+
+# adenine Cp0 and V0 from LCT17 Table 4
+AdH <- data.frame(
+  T = seq(288.15, 363.15, 5),
+  V = c(89.1, 89.9, 90.6, 91.3, 92, 92.7, 93.1, 93.6, 94.1, 94.9, 95.4, 95.9, 96.3, 96.9, 97.1, 97.8),
+  V_SD = c(1.1, 1.3, 1.1, 1, 1.1, 1, 0.9, 0.9, 0.8, 0.6, 0.7, 0.7, 0.7, 0.4, 1.1, 0.7),
+  Cp = c(207, 212, 216, 220, 224, 227, 230, 234, 237, 241, 243, 245, 248, 250, 252, 255),
+  Cp_SD = c(5, 7, 8, 7, 8, 7, 6, 7, 6, 5, 6, 6, 5, 4, 7, 5)
+)
+# functions to calculate V and Cp using density model (LCT17 Eq. 28)
+Vfun <- function(v1, v2, k, T) {
+  # gas constant (cm3 bar K-1 mol-1)
+  R <- 83.144598
+  # isothermal compressibility (bar-1)
+  beta <- water("beta", TK)$beta
+  v1 + v2 / (T - 228) - k * R * beta
+}
+Cpfun <- function(c1, c2, k, T) {
+  # gas constant (J K-1 mol-1)
+  R <- 8.3144598
+  # isobaric temperature derivative of expansivity (K-2)
+  daldT <- water("daldT", TK)$daldT
+  c1 + c2 / (T - 228) ^ 2 - k * R * T * daldT
+}
+# set up units (used for axis labels and HKF calculations)
+E.units("J")
+T.units("K")
+# temperature and pressure points for calculations
+TK <- seq(275, 425)
+P <- water("Psat", TK)$Psat
+# set up plots
+layout(matrix(1:3), heights=c(1, 8, 8))
+# title at top
+par(mar=c(0, 0, 0, 0), cex=1)
+plot.new()
+text(0.5, 0.5, "Heat capacity and volume of aqueous adenine\n(Lowe et al., 2017)", font=2)
+# settings for plot areas
+par(mar = c(4, 4, 0.5, 1), mgp = c(2.4, 0.5, 0))
+# location of x-axis tick marks
+xaxp <- c(275, 425, 6)
+
+### Cp plot (LCT17 Figures 4 and 12) ###
+plot(AdH$T, AdH$Cp, type = "p", xlim = range(TK), ylim = c(150, 350),
+     xlab = axis.label("T"), ylab = axis.label("Cp0"), 
+     pch = 5, tcl = 0.3, xaxs = "i", yaxs = "i", las = 1, xaxp = xaxp
+)
+# error bars (arrows trick from https://stackoverflow.com/questions/13032777/scatter-plot-with-error-bars)
+arrows(AdH$T, AdH$Cp - AdH$Cp_SD, AdH$T, AdH$Cp + AdH$Cp_SD, length = 0.05, angle = 90, code = 3)
+# get LH06 predictions using HKF model
+LH06 <- subcrt("adenine", T = TK)$out$adenine
+lines(TK, LH06$Cp, lty = 3)
+# density model (parameters from LCT17 Table 11)
+lines(TK, Cpfun(160.4, -653239, -7930.3, TK), lty = 2)
+
+# regress HKF parameters
+# specify the terms in the HKF equations
+var <- c("invTTheta2", "TXBorn")
+# build a data frame with T, P, and Cp columns
+Cpdat <- data.frame(T = AdH[, "T"], P = 1, Cp = AdH[, "Cp"])
+# convert Cp data from J to cal
+Cpdat$Cp <- convert(Cpdat$Cp, "cal")
+# regress HKF parameters from Cp data
+HKFcoeffs <- EOSregress(Cpdat, var)$coefficients
+# get predictions from the fitted model
+Cpfit <- EOScalc(HKFcoeffs, TK, P)
+# plot the fitted model
+lines(TK, convert(Cpfit, "J"), lwd = 2, col = "green3")
+# format coefficients for legend; use scientific notation for c2 and omega
+coeffs <- format(signif(HKFcoeffs, 4), scientific = TRUE)
+# keep c1 out of scientific notation
+coeffs[1] <- signif(HKFcoeffs[[1]], 4)
+ipos <- which(coeffs >= 0)
+coeffs[ipos] <- paste("+", coeffs[ipos], sep = "")
+fun.lab <- as.expression(lapply(1:length(coeffs), function(x) {
+  EOSlab(names(HKFcoeffs)[x], coeffs[x])
+}))
+# add legend: regressed HKF coefficients
+legend("topleft", legend = fun.lab, pt.cex = 0.1, box.col = "green3")
+# add legend: lines
+legend("bottomright", lty = c(3, 2, 1), lwd = c(1, 1, 2), col = c("black", "black", "green3"), bty = "n",
+  legend = c("HKF model (LaRowe and Helgeson, 2006)",
+  "density model (Lowe et al., 2017)", "HKF model (fit using CHNOSZ)")
+)
+
+### V plot (LCT17 Figures 3 and 11) ###
+plot(AdH$T, AdH$V, type = "p", xlim = range(TK), ylim = c(85, 105),
+     xlab = axis.label("T"), ylab = axis.label("V0"), 
+     pch = 5, tcl = 0.3, xaxs = "i", yaxs = "i", las = 1, xaxp = xaxp
+)
+axis(3, labels = FALSE, tcl = 0.3, xaxp = xaxp)
+axis(4, labels = FALSE, tcl = 0.3)
+arrows(AdH$T, AdH$V - AdH$V_SD, AdH$T, AdH$V + AdH$V_SD, length = 0.05, angle = 90, code = 3)
+# HKF model with coefficients from LH06
+lines(TK, LH06$V, lty = 3)
+# density model with coefficients from LCT17
+lines(TK, Vfun(73.9, -917.0, -7930.3, TK), lty = 2)
+# load HKF coefficients for adenine reported by LCT17
+# note that the Cp coefficients here are very close to those regressed above!
+add.obigt("adenine")
+LCT17 <- subcrt("adenine", T = TK)$out$adenine
+lines(TK, LCT17$V, lwd = 2, col = "royalblue")
+legend("bottomright", lty = c(3, 2, 1), lwd = c(1, 1, 2), col = c("black", "black", "royalblue"), bty = "n",
+  legend=c("HKF model (LaRowe and Helgeson, 2006)",
+  "density model (Lowe et al., 2017)", "HKF model (fit by Lowe et al., 2017 using CHNOSZ)")
+)
+# reset database
+data(thermo)

Modified: pkg/CHNOSZ/inst/NEWS
===================================================================
--- pkg/CHNOSZ/inst/NEWS	2017-06-06 14:35:05 UTC (rev 204)
+++ pkg/CHNOSZ/inst/NEWS	2017-07-27 00:01:56 UTC (rev 205)
@@ -1,10 +1,19 @@
-CHANGES IN CHNOSZ 1.1.0-3 (2017-06-06)
+CHANGES IN CHNOSZ 1.1.0-4 (2017-07-27)
 --------------------------------------
 
 - water.lines() now works for diagrams of Eh, pe, logfO2, logaO2,
   logfH2, or logaH2 vs pH, T, or P. It is possible to have T or P on
   either the x- or y-axis.
 
+- Data file CHNOSZ_aq.csv is no longer added to the database by default.
+  It is now intended to hold provisional updates. Updated heat capacity
+  and volume HKF parameters for adenine (Lowe et al., 2017) have been
+  added to this file.
+
+- Modify add.obigt() to search for species from CHNOSZ_aq.csv to add to
+  the current database. If the species is not found, add.obigt() treats
+  the argument as a file name, as before.
+
 CHANGES IN CHNOSZ 1.1.0 (2017-05-04)
 ------------------------------------
 

Copied: pkg/CHNOSZ/inst/extdata/OBIGT/CHNOSZ_aq.csv (from rev 204, pkg/CHNOSZ/inst/extdata/OBIGT/CHNOSZ_aq.csv.xz)
===================================================================
--- pkg/CHNOSZ/inst/extdata/OBIGT/CHNOSZ_aq.csv	                        (rev 0)
+++ pkg/CHNOSZ/inst/extdata/OBIGT/CHNOSZ_aq.csv	2017-07-27 00:01:56 UTC (rev 205)
@@ -0,0 +1,3 @@
+name,abbrv,formula,state,ref1,ref2,date,G,H,S,Cp,V,a1.a,a2.b,a3.c,a4.d,c1.e,c2.f,omega.lambda,z.T
+pseudo-H4SiO4,NA,H4SiO4,aq,CHNOSZ.4,NA,18.Feb.17,-312565,-346409,51.4246,-40.0964,52.1998,89.2031,-176.5071,-452.1431,101.36051,67.0854,-52.0776,0.1215745,0
+adenine,NA,C5H5N5,aq,LCT17,LH06a,26.Jul.17,74770,31235,53.41,51.63,90.6,23.53,0,-17.75,0,48.54,-3.318,-1.093,0

Deleted: pkg/CHNOSZ/inst/extdata/OBIGT/CHNOSZ_aq.csv.xz
===================================================================
--- pkg/CHNOSZ/inst/extdata/OBIGT/CHNOSZ_aq.csv.xz	2017-06-06 14:35:05 UTC (rev 204)
+++ pkg/CHNOSZ/inst/extdata/OBIGT/CHNOSZ_aq.csv.xz	2017-07-27 00:01:56 UTC (rev 205)
@@ -1 +0,0 @@
-ý7zXZ  æÖ´F !   t/å£à þ Í] 7Iýúb‹¿ñ9²¶Ë¦¨•TB;qý"½qù¦cL;ù"ß“<²ëbï¨gò;ø¥Kä‡¥Šfœ‘1Æw?oz†ÆCþ­aì]IØŽ¨Ý5i‡Rw¼lù¼ßgˆnÞÛ¿¡õö|É\¿ë%}Bèà>—œ)~)ÉÛMa=~ԍ+	@Ü,†è\²ëªZÜ"Ôþ”•edŠ­èí¦…È»C€C¡Ã4—È• ØÍ»å!ž-¹ÉT‡C%Ò:Ô®€     ’›UPÚUÖô éÿ  áÛ¹±Ägû    YZ
\ No newline at end of file

Modified: pkg/CHNOSZ/man/EOSregress.Rd
===================================================================
--- pkg/CHNOSZ/man/EOSregress.Rd	2017-06-06 14:35:05 UTC (rev 204)
+++ pkg/CHNOSZ/man/EOSregress.Rd	2017-07-27 00:01:56 UTC (rev 205)
@@ -49,6 +49,7 @@
 
 \details{
 \code{EOSregress} uses a linear model (\code{\link{lm}}) to regress the experimental heat capacity or volume data in \code{exptdata}, which is a data frame with columns \samp{T} (temperature in degrees Kelvin), \samp{P} (pressure in bars), and \samp{Cp} or \samp{V} (heat capacity in cal/mol.K or volume in cm3/mol).
+The \samp{Cp} or \samp{V} data must be in the third column.
 Only data below the temperature of \code{T.max} are included in the regression.
 The regression formula is specified by a vector of names in \code{var}.
 The names of the variables can be any combination of the following (listed in the order of search): variables listed in the following table, any available property of \code{\link{water}} (e.g. \samp{V}, \samp{alpha}, \samp{QBorn}), or the name of a function that can be found using \code{\link{get}} in the default environment.
@@ -130,6 +131,8 @@
 var <- c("invTTheta2", "TXBorn")
 # perform regression, with a temperature limit
 EOSlm <- EOSregress(d, var, T.max=600)
+# calculate the Cp at some temperature and pressure
+EOScalc(EOSlm$coefficients, 298.15, 1)
 # get the database values of c1, c2 and omega for CH4(aq)
 CH4coeffs <- EOScoeffs("CH4", "Cp")
 ## make plots comparing the regressions

Added: pkg/CHNOSZ/man/add.obigt.Rd
===================================================================
--- pkg/CHNOSZ/man/add.obigt.Rd	                        (rev 0)
+++ pkg/CHNOSZ/man/add.obigt.Rd	2017-07-27 00:01:56 UTC (rev 205)
@@ -0,0 +1,107 @@
+\encoding{UTF-8}
+\name{add.obigt}
+\alias{add.obigt}
+\alias{mod.obigt}
+\alias{today}
+\title{Functions to Work with the Thermodynamic Database}
+\description{
+Add or modify species in the thermodynamic database.
+}
+
+\usage{
+  add.obigt(file, force = TRUE, E.units = "cal")
+  mod.obigt(...)
+  today()
+}
+
+\arguments{
+  \item{file}{character, path to a file}
+  \item{force}{logical, force replacement of already existing species?}
+  \item{E.units}{character, units of energy, \samp{cal} or \samp{J}}
+  \item{...}{character or numeric, properties of species to modify in the thermodynamic database}
+}
+
+\details{
+
+\code{\link{add.obigt}} is available to update the thermodynamic database in use in the running session.
+If the \code{file} argument matches the name of a species in \code{extdata/OBIGT/CHNOSZ_aq.csv}, this species is added to the database (possibly replacing an existing species with the same name).
+Otherwise, \code{add.obigt} reads data from the specified \code{file} and adds it to \code{\link{thermo}$obigt}.
+
+The format of the file must be the same as the OBIGT files provided with CHNOSZ.
+Set \code{force} to FALSE to avoid replacing species that exist in the thermodynamic database (each unique combination of a name and a state in the database is considered to be a different species).
+Given the default setting of \code{E.units}, the function does not perform any unit conversions.
+If \code{E.units} is set to \samp{J}, then the thermodynamic parameters are converted from units of Joules to calories, as used in the CHNOSZ database. 
+
+When adding species, there is no attempt made to keep the order of physical states in the database (aq-cr-liq-gas); the function simply adds new rows to the end of \code{thermo}$obigt.
+As a result, retrieving the properties of an added aqueous species using \code{\link{info}} requires an explicit \code{state="aq"} argument to that function if a species with the same name is in one of the cr, liq or gas states.
+
+\code{mod.obigt} changes one or more of the properties of species or adds species to the thermodynamic database.
+These changes are lost if you reload the database by calling \code{\link{data}(thermo)} or if you quit the \R session without saving it.
+The name of the species to add or change must be supplied as the first argument of \code{...} or as a named argument (named \samp{name}).
+When adding new species, a chemical formula should be included along with the values of any of the thermodynamic properties.
+The formula is taken from the \samp{formula} argument, or if that is missing, is taken to be the same as the \samp{name} of the species.
+An error results if the formula is not valid (i.e. can not be parsed by\code{\link{makeup}}).
+Additional arguments refer to the name of the property(s) to be updated and are matched to any part of compound column names in \code{\link{thermo}$obigt}, such as \samp{z} or \samp{T} in \samp{z.T}.
+Unless \samp{state} is specified as one of the properties, its value is taken from \code{thermo$opt$state}.
+When adding species, properties that are not specified become NA (except for \samp{state}).
+The values provided should be in the units specifed in the documentation for the \code{thermo} data object, including any order-of-magnitude scaling factors.
+
+\code{today} returns the current date in the format adopted for \code{thermo$obigt} (inherited from SUPCRT-format data files) e.g. \samp{13.May.12} for May 13, 2012.
+}
+
+\value{
+The values returned (\code{\link{invisible}}-y) by \code{mod.obigt} are the rownumbers of the affected species.
+}
+
+\seealso{ \code{\link{thermo}}, \code{\link{util.data}}, \code{\link{mod.buffer}} }
+
+\examples{\dontshow{data(thermo)}
+## modify an existing species (example only)
+ialanine <- mod.obigt("alanine", state="cr", G=0, H=0, S=0)
+# we have made the values of G, H, and S inconsistent
+# with the elemental composition of alanine, so the following 
+# now produces a message about that
+info(ialanine)
+## add a species
+iCl2O <- mod.obigt("Cl2O", G=20970)
+info(iCl2O)
+# add a species with a name that is different from the formula
+mod.obigt("buckminsterfullerene", formula="C60", state="cr", date=today())
+# retrieve the species data (thermodynamic properties in this toy example are NA)
+info(info("C60"))
+# reset database
+data(thermo)
+
+# using add.obigt():
+# compare stepwise stability constants of cadmium chloride complexes
+# using data from Sverjensky et al., 1997 and Bazarkina et al., 2010
+Cdspecies <- c("Cd+2", "CdCl+", "CdCl2", "CdCl3-", "CdCl4-2")
+P <- c(1, seq(25, 1000, 25))
+SSH97 <- lapply(1:4, function(i) {
+  subcrt(c(Cdspecies[i], "Cl-", Cdspecies[i+1]),
+    c(-1, -1, 1), T=25, P=P)$out$logK
+})
[TRUNCATED]

To get the complete diff run:
    svnlook diff /svnroot/chnosz -r 205


More information about the CHNOSZ-commits mailing list