From noreply at r-forge.r-project.org Thu Jul 27 02:01:57 2017 From: noreply at r-forge.r-project.org (noreply at r-forge.r-project.org) Date: Thu, 27 Jul 2017 02:01:57 +0200 (CEST) Subject: [CHNOSZ-commits] r205 - in pkg/CHNOSZ: . R data demo inst inst/extdata/OBIGT man tests/testthat vignettes Message-ID: <20170727000157.A0CD0188E7B@r-forge.r-project.org> 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 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 a1--a4 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;?"????)~)??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