Moved reference electrode converter functions and data to their own package.
Also removed vapour water functions that are already part of the water package.master
parent
bee42f9fd9
commit
f96a3dc92e
@ -1,18 +0,0 @@
|
|||||||
#' @name vapourwater
|
|
||||||
#' @title Vapour pressure and other saturation properties of water
|
|
||||||
#' @description A dataset summarising vapour pressure, enthalpy of vapourisation,
|
|
||||||
#' and surface tension of water from 0.01 Celsius to 373.95 Celsius.
|
|
||||||
#' Data as accepted by the International Association for the Properties
|
|
||||||
#' of Water and Steam for general scientific use.
|
|
||||||
#' Source: CRC handbook, 94th ed., table 6-10-90, Eric W. Lemmon.
|
|
||||||
#' @docType data
|
|
||||||
#' @format A data frame with 189 rows and 4 variables:
|
|
||||||
#' \describe{
|
|
||||||
#' \item{temperature}{temperature/celsius}
|
|
||||||
#' \item{pressure}{pressure/kilopascal}
|
|
||||||
#' \item{enthalpy}{enthalpy of vapourisation/kilojoule per kilogram}
|
|
||||||
#' \item{surfacetension}{surface tension/millinewton per metre}
|
|
||||||
#' }
|
|
||||||
#' @source Handbook of Chemistry and Physics, 94th ed., 6-10-90, Eric W. Lemmon.
|
|
||||||
#' @author Taha Ahmed
|
|
||||||
NULL
|
|
@ -1,871 +0,0 @@
|
|||||||
#' AVS -> SHE
|
|
||||||
#'
|
|
||||||
#' Converts from absolute vacuum scale (AVS) to SHE scale
|
|
||||||
#'
|
|
||||||
#' @param avs Potential in AVS scale
|
|
||||||
#'
|
|
||||||
#' @return potential in SHE scale (numeric)
|
|
||||||
#' @export
|
|
||||||
AVS2SHE <- function(avs) {
|
|
||||||
.Deprecated("as.SHE")
|
|
||||||
she <- -(4.5 + avs)
|
|
||||||
return(she)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#' SHE -> AVS
|
|
||||||
#'
|
|
||||||
#' Converts from SHE scale to absolute vacuum (AVS) scale
|
|
||||||
#'
|
|
||||||
#' @param she Potential in SHE scale
|
|
||||||
#'
|
|
||||||
#' @return potential in AVS scale (numeric)
|
|
||||||
#' @export
|
|
||||||
SHE2AVS <- function(she) {
|
|
||||||
.Deprecated("as.SHE")
|
|
||||||
avs <- -(4.5 + she)
|
|
||||||
return(avs)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#' Get standardised name of reference electrode
|
|
||||||
#'
|
|
||||||
#' Given a reference electrode label, this function returns its canonical name
|
|
||||||
#' (as defined by this package).
|
|
||||||
#' This function tries to match against as many variations as possible for each
|
|
||||||
#' reference electrode.
|
|
||||||
#' The entire point of this function is to decrease the mental load on the user
|
|
||||||
#' by not requiring them to remember a particular label or name for each reference
|
|
||||||
#' electrode, instead almost any sufficiently distinct label or string will still
|
|
||||||
#' be correctly identified.
|
|
||||||
#'
|
|
||||||
#' @param refname string or a vector of strings
|
|
||||||
#'
|
|
||||||
#' @return vector with corresponding "canonical" name or empty string (if none found)
|
|
||||||
#' @export
|
|
||||||
RefCanonicalName <- function(refname) {
|
|
||||||
# scale names
|
|
||||||
electrode.system <- list()
|
|
||||||
electrode.system[["SHE"]] <-
|
|
||||||
c("SHE",
|
|
||||||
"Standard hydrogen",
|
|
||||||
"Standard hydrogen electrode")
|
|
||||||
electrode.system[["AgCl/Ag"]] <-
|
|
||||||
c("AgCl/Ag",
|
|
||||||
"Ag/AgCl",
|
|
||||||
"AgCl",
|
|
||||||
"Silver-Silver chloride",
|
|
||||||
"Silver chloride",
|
|
||||||
"SSC") # Sometimes used abbr. for Saturated Silver Chloride
|
|
||||||
electrode.system[["Hg2Cl2/Hg"]] <-
|
|
||||||
c("Hg2Cl2/Hg",
|
|
||||||
"Hg/Hg2Cl2",
|
|
||||||
"Hg2Cl2",
|
|
||||||
"Calomel-Mercury",
|
|
||||||
"Mercury-Calomel",
|
|
||||||
"Calomel",
|
|
||||||
"SCE")
|
|
||||||
electrode.system[["AVS"]] <-
|
|
||||||
c("AVS",
|
|
||||||
"Vacuum",
|
|
||||||
"Vacuum scale",
|
|
||||||
"Absolute",
|
|
||||||
"Absolute scale",
|
|
||||||
"Absolute vacuum scale")
|
|
||||||
electrode.system[["Li"]] <-
|
|
||||||
c("Li",
|
|
||||||
"Li/Li+",
|
|
||||||
"Li+/Li",
|
|
||||||
"Lithium")
|
|
||||||
electrode.system[["Na"]] <-
|
|
||||||
c("Na",
|
|
||||||
"Na+/Na",
|
|
||||||
"Na/Na+",
|
|
||||||
"Sodium")
|
|
||||||
electrode.system[["Mg"]] <-
|
|
||||||
c("Mg",
|
|
||||||
"Mg2+/Mg",
|
|
||||||
"Mg/Mg2+",
|
|
||||||
"Magnesium")
|
|
||||||
|
|
||||||
# if no argument or empty string supplied as arg, return the entire list as df
|
|
||||||
# to give the user a nice overview of all available options
|
|
||||||
if (missing(refname) || refname == "") {
|
|
||||||
max.row.length <- 0
|
|
||||||
for (i in 1:length(electrode.system)) {
|
|
||||||
# find the longest row and save its length
|
|
||||||
this.row.length <- length(electrode.system[[i]])
|
|
||||||
if (this.row.length > max.row.length) max.row.length <- this.row.length
|
|
||||||
}
|
|
||||||
# initialise an empty df with dimensions that fit electrode.system
|
|
||||||
overview.names <-
|
|
||||||
data.frame(
|
|
||||||
structure(dimnames =
|
|
||||||
list(
|
|
||||||
# rownames
|
|
||||||
seq(1, length(electrode.system)),
|
|
||||||
# colnames
|
|
||||||
c("canonical", paste0("option", seq(1, max.row.length - 1)))),
|
|
||||||
matrix("",
|
|
||||||
nrow = length(electrode.system),
|
|
||||||
ncol = max.row.length,
|
|
||||||
byrow = TRUE)),
|
|
||||||
stringsAsFactors = FALSE)
|
|
||||||
# now populate the df
|
|
||||||
for (i in 1:length(electrode.system)) {
|
|
||||||
this.row.length <- length(electrode.system[[i]])
|
|
||||||
overview.names[i,1:this.row.length] <- electrode.system[[i]]
|
|
||||||
}
|
|
||||||
message(paste0("You did not specify any reference electrode name.\n",
|
|
||||||
"Here are the options supported by this function (case-insensitive):"))
|
|
||||||
print(knitr::kable(overview.names))
|
|
||||||
}
|
|
||||||
|
|
||||||
# defining refname in this manner makes sure to get all possible combinations
|
|
||||||
# but there might be a number of duplicates, but those we can
|
|
||||||
# get rid of in the next step
|
|
||||||
electrode <-
|
|
||||||
data.frame(refname =
|
|
||||||
# here we create lower-case version of electrode.system,
|
|
||||||
# a version with symbols (-/) subbed with spaces,
|
|
||||||
# and a lower-case with symbols subbed with spaces
|
|
||||||
c(unname(unlist(electrode.system)),
|
|
||||||
tolower(unname(unlist(electrode.system))),
|
|
||||||
gsub("[-/]", " ", unname(unlist(electrode.system))),
|
|
||||||
gsub("[-/]", " ", tolower(unname(unlist(electrode.system))))),
|
|
||||||
refcanon =
|
|
||||||
rep(sub("[0-9]$", "", names(unlist(electrode.system))),
|
|
||||||
4), # this number needs to equal number of elements in c() above!
|
|
||||||
stringsAsFactors = FALSE)
|
|
||||||
# detect and remove duplicates
|
|
||||||
electrode <-
|
|
||||||
electrode[!duplicated(electrode$refname),]
|
|
||||||
# reset row numbering in dataframe just for good measure
|
|
||||||
row.names(electrode) <- 1:dim(electrode)[1]
|
|
||||||
|
|
||||||
# pre-allocate the return vector
|
|
||||||
refcanon <- rep("", length(refname))
|
|
||||||
# now all we have to do is check each user-submitted refname against
|
|
||||||
# electrode$refname and return the value on the same row but next column
|
|
||||||
for (i in 1:length(refname)) {
|
|
||||||
refcanon[i] <-
|
|
||||||
electrode$refcanon[which(electrode$refname == refname[i])]
|
|
||||||
}
|
|
||||||
|
|
||||||
return(refcanon)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#' Potentials as SHE
|
|
||||||
#'
|
|
||||||
#' This function just outputs a tidy dataframe with potential vs SHE for
|
|
||||||
#' different scales, electrolytes, concentrations, and temperatures.
|
|
||||||
#' Using data from literature.
|
|
||||||
#'
|
|
||||||
#' @return tidy dataframe with the following columns
|
|
||||||
#' \tabular{ll}{
|
|
||||||
#' \code{electrode} \tab reference electrode \cr
|
|
||||||
#' \code{electrolyte} \tab electrolyte \cr
|
|
||||||
#' \code{conc.num} \tab concentration of electrolyte, mol/L \cr
|
|
||||||
#' \code{conc.string} \tab concentration of electrolyte, as string, may also note temperature at which conc \cr
|
|
||||||
#' \code{temp} \tab temperature / degrees Celsius \cr
|
|
||||||
#' \code{SHE} \tab potential vs SHE / volt \cr
|
|
||||||
#' \code{sid} \tab set id, just for housekeeping inside this function \cr
|
|
||||||
#' \code{reference} \tab BibTeX reference \cr
|
|
||||||
#' \code{dEdT} \tab temperature coefficient / volt/kelvin \cr
|
|
||||||
#' }
|
|
||||||
#' @export
|
|
||||||
potentials.as.SHE <- function() {
|
|
||||||
# scale name should be one of canonical (see RefCanonicalName)
|
|
||||||
|
|
||||||
# follow the convention of "each row one observation" (at different temperatures)
|
|
||||||
# all potentials vs SHE
|
|
||||||
|
|
||||||
potentials <-
|
|
||||||
as.data.frame(
|
|
||||||
matrix(data =
|
|
||||||
# electrode # electrolyte # conc/M # conc label # temp # pot vs SHE # set id # ref
|
|
||||||
c("AgCl/Ag", "NaCl(aq)", "5.9", "saturated", "25", "0.2630", "9", "CRC 97th ed., 97-05-22",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "3.5", "3.5M at 25C", "10", "0.215", "1", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "3.5", "3.5M at 25C", "15", "0.212", "1", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "3.5", "3.5M at 25C", "20", "0.208", "1", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "3.5", "3.5M at 25C", "25", "0.205", "1", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "3.5", "3.5M at 25C", "30", "0.201", "1", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "3.5", "3.5M at 25C", "35", "0.197", "1", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "3.5", "3.5M at 25C", "40", "0.193", "1", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "4.2", "saturated", "10", "0.214", "2", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "4.2", "saturated", "15", "0.209", "2", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "4.2", "saturated", "20", "0.204", "2", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "4.2", "saturated", "25", "0.199", "2", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "4.2", "saturated", "30", "0.194", "2", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "4.2", "saturated", "35", "0.189", "2", "Sawyer1995",
|
|
||||||
"AgCl/Ag", "KCl(aq)", "4.2", "saturated", "40", "0.184", "2", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "0.1", "0.1M at 25C", "10", "0.336", "3", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "0.1", "0.1M at 25C", "15", "0.336", "3", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "0.1", "0.1M at 25C", "20", "0.336", "3", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "0.1", "0.1M at 25C", "25", "0.336", "3", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "0.1", "0.1M at 25C", "30", "0.335", "3", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "0.1", "0.1M at 25C", "35", "0.334", "3", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "0.1", "0.1M at 25C", "40", "0.334", "3", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "1.0", "1.0M at 25C", "10", "0.287", "4", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "1.0", "1.0M at 25C", "20", "0.284", "4", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "1.0", "1.0M at 25C", "25", "0.283", "4", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "1.0", "1.0M at 25C", "30", "0.282", "4", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "1.0", "1.0M at 25C", "40", "0.278", "4", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "3.5", "3.5M at 25C", "10", "0.256", "5", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "3.5", "3.5M at 25C", "15", "0.254", "5", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "3.5", "3.5M at 25C", "20", "0.252", "5", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "3.5", "3.5M at 25C", "25", "0.250", "5", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "3.5", "3.5M at 25C", "30", "0.248", "5", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "3.5", "3.5M at 25C", "35", "0.246", "5", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "3.5", "3.5M at 25C", "40", "0.244", "5", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "4.2", "saturated", "10", "0.254", "6", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "4.2", "saturated", "15", "0.251", "6", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "4.2", "saturated", "20", "0.248", "6", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "4.2", "saturated", "25", "0.244", "6", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "4.2", "saturated", "30", "0.241", "6", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "4.2", "saturated", "35", "0.238", "6", "Sawyer1995",
|
|
||||||
"Hg2Cl2/Hg", "KCl(aq)", "4.2", "saturated", "40", "0.234", "6", "Sawyer1995",
|
|
||||||
"AVS", "", "", "", "25", "-4.44", "7", "Trasatti1986",
|
|
||||||
"SHE", "", "", "", "-273.15", "0.00", "8", "Inzelt2013",
|
|
||||||
"SHE", "", "", "", "0", "0.00", "8", "Inzelt2013",
|
|
||||||
"SHE", "", "", "", "25", "0.00", "8", "Inzelt2013",
|
|
||||||
# arbitrary max T=580C (temp at which sodalime glass loses rigidity)
|
|
||||||
"SHE", "", "", "", "580", "0.00", "8", "Inzelt2013",
|
|
||||||
"Li", "", "1.0", "1.0M at 25C", "25", "-3.0401", "10", "CRC 97th ed., 97-05-22",
|
|
||||||
"Na", "", "1.0", "1.0M at 25C", "25", "-2.71", "11", "CRC 97th ed., 97-05-22",
|
|
||||||
"Mg", "", "1.0", "1.0M at 25C", "25", "-2.372", "12", "CRC 97th ed., 97-05-22"),
|
|
||||||
ncol = 8,
|
|
||||||
byrow = TRUE), stringsAsFactors = FALSE)
|
|
||||||
|
|
||||||
colnames(potentials) <-
|
|
||||||
c("electrode",
|
|
||||||
"electrolyte",
|
|
||||||
"conc.num",
|
|
||||||
"conc.string",
|
|
||||||
"temp",
|
|
||||||
"SHE",
|
|
||||||
"sid",
|
|
||||||
"reference")
|
|
||||||
|
|
||||||
# convert these columns to type numeric
|
|
||||||
potentials[, c("conc.num", "temp", "SHE")] <-
|
|
||||||
as.numeric(as.character(unlist(potentials[, c("conc.num", "temp", "SHE")])))
|
|
||||||
|
|
||||||
# make room for a dE/dT column
|
|
||||||
potentials$dEdT <- as.numeric(NA)
|
|
||||||
|
|
||||||
# calculate temperature coefficient (dE/dT) for each scale, concentration, and electrolyte (ie. set id)
|
|
||||||
for (s in 1:length(unique(potentials$sid))) {
|
|
||||||
# sid column eas added to data just to make this calculation here easier
|
|
||||||
subspot <- potentials[which(potentials$sid == unique(potentials$sid)[s]), ]
|
|
||||||
# a linear fit will give us temperature coefficient as slope
|
|
||||||
lm.subspot <- stats::lm(SHE ~ temp, data = subspot)
|
|
||||||
potentials[which(potentials$sid == unique(potentials$sid)[s]), "dEdT"] <-
|
|
||||||
lm.subspot$coefficients[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
return(potentials)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#' Convert from electrochemical or physical scale to SHE
|
|
||||||
#'
|
|
||||||
#' Convert an arbitrary number of potentials against any known electrochemical
|
|
||||||
#' scale (or the electronic vacuum scale) to potential vs SHE.
|
|
||||||
#'
|
|
||||||
#' @param potential potential in volt
|
|
||||||
#' @param scale name of the original scale
|
|
||||||
#' @param electrolyte optional, specify electrolyte solution, e.g., "KCl(aq)". Must match value in \code{as.SHE.data$electrolyte}.
|
|
||||||
#' @param concentration of electrolyte in mol/L, or as the string "saturated"
|
|
||||||
#' @param temperature of system in degrees Celsius
|
|
||||||
#' @param as.SHE.data dataframe with dataset
|
|
||||||
#'
|
|
||||||
#' @return potential in SHE scale
|
|
||||||
#' @export
|
|
||||||
as.SHE <- function(potential,
|
|
||||||
scale,
|
|
||||||
electrolyte = "",
|
|
||||||
concentration = "saturated",
|
|
||||||
temperature = 25,
|
|
||||||
as.SHE.data = potentials.as.SHE()) {
|
|
||||||
|
|
||||||
# if the supplied temperature does not exist in the data, this function will attempt to interpolate
|
|
||||||
# note that concentration has to match, no interpolation is attempted for conc
|
|
||||||
|
|
||||||
# potential and scale vectors supplied by user could have arbitrary length
|
|
||||||
# just make sure potential and scale args have the same length (or length(scale) == 1)
|
|
||||||
if (length(potential) == 0 | length(scale) == 0) {
|
|
||||||
stop("Potential or scale arguments cannot be empty!")
|
|
||||||
} else if (length(potential) != length(scale)) {
|
|
||||||
# stop, unless length(scale) == 1 where we will assume it should be recycled
|
|
||||||
if (length(scale) == 1) {
|
|
||||||
message("Arg <scale> has unit length. We'll recycle it to match length of <potential>.")
|
|
||||||
scale <- rep(scale, length(potential))
|
|
||||||
} else {
|
|
||||||
stop("Length of <potential> and <scale> must be equal OR <scale> may be unit length.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arglength <- length(potential)
|
|
||||||
# make the args concentration, temperature and electrolyte this same length,
|
|
||||||
# unless the user supplied them (only necessary for length > 1)
|
|
||||||
if (arglength > 1) {
|
|
||||||
# handle two cases:
|
|
||||||
# 1. user did not touch concentration, temperature and electrolyte args.
|
|
||||||
# Assume they forgot and reset their length and print a message
|
|
||||||
# 2. user did change concentration or temperature or electrolyte, but still failed to
|
|
||||||
# ensure length equal to arglength. In this case, abort.
|
|
||||||
# note: we can get the default value set in the function call using formals()
|
|
||||||
if (identical(concentration, formals(as.SHE)$concentration) &
|
|
||||||
identical(temperature, formals(as.SHE)$temperature) &
|
|
||||||
identical(electrolyte, formals(as.SHE)$electrolyte)) {
|
|
||||||
# case 1
|
|
||||||
# message("NOTE: default concentration and temperature values used for all potentials and scales.")
|
|
||||||
message(paste0("The default concentration (", formals(as.SHE)$concentration, ") and temperature (", formals(as.SHE)$temperature, "C) will be assumed for all your potential/scale values."))
|
|
||||||
concentration <- rep(concentration, arglength)
|
|
||||||
temperature <- rep(temperature, arglength)
|
|
||||||
electrolyte <- rep(electrolyte, arglength)
|
|
||||||
} else {
|
|
||||||
# case 2
|
|
||||||
stop("Concentration, temperature and electrolyte arguments must have the same number of elements as potential and scale!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## we can now safely assume that length(<args>) == arglength
|
|
||||||
# place args into a single dataframe
|
|
||||||
# this way, we can correlate columns to each other by row
|
|
||||||
dfargs <-
|
|
||||||
data.frame(potential = potential,
|
|
||||||
scale = common::RefCanonicalName(scale),
|
|
||||||
electrolyte = electrolyte,
|
|
||||||
concentration = concentration,
|
|
||||||
temperature = temperature,
|
|
||||||
stringsAsFactors = FALSE)
|
|
||||||
# add column to keep track of vacuum scale
|
|
||||||
# dfargs$vacuum <- as.logical(FALSE)
|
|
||||||
# add column to hold calc potential vs SHE
|
|
||||||
dfargs$SHE <- as.numeric(NA)
|
|
||||||
|
|
||||||
## From here on, ONLY access the arguments via this dataframe
|
|
||||||
## That is, use dfargs$electrolyte, NOT electrolyte
|
|
||||||
|
|
||||||
# SHE scale special considerations
|
|
||||||
# 1. concentration is constant for SHE
|
|
||||||
if (any(dfargs$scale == common::RefCanonicalName("SHE"))) {
|
|
||||||
dfargs$concentration[which(dfargs$scale == common::RefCanonicalName("SHE"))] <- ""
|
|
||||||
dfargs$electrolyte[which(dfargs$scale == common::RefCanonicalName("SHE"))] <- ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# AVS scale special considerations
|
|
||||||
# 1. concentration is meaningless for AVS
|
|
||||||
if (any(dfargs$scale == common::RefCanonicalName("AVS"))) {
|
|
||||||
# concentration is meaningless for AVS (no electrolyte) so for those rows, we'll reset it
|
|
||||||
dfargs$concentration[which(dfargs$scale == common::RefCanonicalName("AVS"))] <- ""
|
|
||||||
dfargs$electrolyte[which(dfargs$scale == common::RefCanonicalName("AVS"))] <- ""
|
|
||||||
# dfargs$vacuum[which(dfargs$scale == common::RefCanonicalName("AVS"))] <- TRUE
|
|
||||||
}
|
|
||||||
|
|
||||||
# now just work our way through dfargs, line-by-line to determine potential as SHE
|
|
||||||
# all necessary conditions should be recorded right here in dfargs
|
|
||||||
for (p in 1:dim(dfargs)[1]) {
|
|
||||||
## WE ARE NOW WORKING ROW-BY-ROW THROUGH THE SUPPLIED ARGUMENTS IN dfargs
|
|
||||||
# Step-wise matching:
|
|
||||||
# + first, we subset against electrode scale. If dataset only has one row, done. Else,
|
|
||||||
# + we subset against either conc.string or conc.num. Stop if zero rows in dataset (error), otherwise proceed.
|
|
||||||
# Our "dataset" is the literature data supplied via the argument as.SHE.data
|
|
||||||
this.data.scale <- subset(as.SHE.data, electrode == dfargs$scale[p])
|
|
||||||
# subset.scale <- subset(as.SHE.data, electrode == dfargs$scale[p])
|
|
||||||
if (dim(this.data.scale)[1] > 1) {
|
|
||||||
# continue matching, now against conc.string or conc.num
|
|
||||||
if (is.character(dfargs$concentration[p])) {
|
|
||||||
this.data.concentration <-
|
|
||||||
# subset.concentration <-
|
|
||||||
subset(this.data.scale, conc.string == dfargs$concentration[p])
|
|
||||||
} else {
|
|
||||||
this.data.concentration <-
|
|
||||||
# subset.concentration <-
|
|
||||||
subset(this.data.scale, conc.num == dfargs$concentration[p])
|
|
||||||
}
|
|
||||||
# stop if the resulting dataframe after matching contains no rows
|
|
||||||
if (dim(this.data.concentration)[1] == 0) {
|
|
||||||
stop(paste0("Failed to find any matching entries in dataset for ",
|
|
||||||
paste(dfargs[p, ], collapse = " ", sep = "")))
|
|
||||||
}
|
|
||||||
# Note: it's ok at this point if the resulting dataset contains more than one row as
|
|
||||||
# more matching will be done below
|
|
||||||
# If we haven't had reason to stop(), we should be good
|
|
||||||
# just housekeeping: rename the variable so we don't have to edit code below
|
|
||||||
this.SHE.data <- this.data.concentration
|
|
||||||
# subset.SHE.data <- subset.concentration
|
|
||||||
} else {
|
|
||||||
# just housekeeping again
|
|
||||||
this.SHE.data <- this.data.scale
|
|
||||||
# subset.SHE.data <- subset.scale
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
## Electrolyte
|
|
||||||
# == We would like to transparently handle the following scenario:
|
|
||||||
# || if the user did not specify electrolyte solution (which we can check by using formals())
|
|
||||||
# || but the dataset (after subsetting against scale and concentration above) still contains
|
|
||||||
# || more than one electrolyte
|
|
||||||
# >> Approach: we'll specify a "fallback" electrolyte, KCl (usually that's what the user wants)
|
|
||||||
# >> and inform/warn about it
|
|
||||||
|
|
||||||
# KCl is a good assumption, as we always have KCl
|
|
||||||
# for the cases where an electrode system has more than one electrolyte
|
|
||||||
fallback.electrolyte <- "KCl(aq)"
|
|
||||||
if (length(unique(this.SHE.data$electrolyte)) > 1) {
|
|
||||||
if (formals(as.SHE)$electrolyte == "") {
|
|
||||||
warning(paste0("More than one electrolyte ",
|
|
||||||
"available for E(", dfargs$scale[p], ") in dataset. ",
|
|
||||||
"I'll assume you want ", fallback.electrolyte, "."))
|
|
||||||
this.SHE.data <-
|
|
||||||
subset(this.SHE.data, electrolyte == fallback.electrolyte)
|
|
||||||
} else {
|
|
||||||
# else the user did change the electrolyte arg, use the user's value
|
|
||||||
this.SHE.data <-
|
|
||||||
subset(this.SHE.data, electrolyte == dfargs$electrolyte[p])
|
|
||||||
# but stop if the resulting dataframe contains no rows
|
|
||||||
if (dim(this.SHE.data)[1] == 0) stop("Your choice of electrolyte does not match any data!")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
# dataset contains only one unique electrolyte
|
|
||||||
# again, check if electrolyte in arg matches the one in dataset
|
|
||||||
# if it does, great, if it does not, print a message and use it anyway
|
|
||||||
if (unique(this.SHE.data$electrolyte) == dfargs$electrolyte[p]) {
|
|
||||||
this.SHE.data <-
|
|
||||||
subset(this.SHE.data, electrolyte == dfargs$electrolyte[p])
|
|
||||||
} else {
|
|
||||||
# whatever electrolyte the user supplied does not match what's left in the datasubset
|
|
||||||
# but at this point the user is probably better served by returning the electrolyte we have
|
|
||||||
# along with an informative message (that's the only reason for the if-else below)
|
|
||||||
electrolytes.in.subset <-
|
|
||||||
unique(subset(as.SHE.data, electrode == dfargs$scale[p])$electrolyte)
|
|
||||||
if (dfargs$electrolyte[p] == "") {
|
|
||||||
message(
|
|
||||||
paste0('Electrolyte "" (empty string) not in dataset for E(',
|
|
||||||
dfargs$scale[p], '). ',
|
|
||||||
'These electrolytes are: ',
|
|
||||||
paste(electrolytes.in.subset, collapse = ', or '), '.',
|
|
||||||
"I'll assume you want ", fallback.electrolyte, ".")
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
message(paste0("Electrolyte ", dfargs$electrolyte[p], " not in dataset for E(",
|
|
||||||
dfargs$scale[p], "). ",
|
|
||||||
"These electrolytes are: ",
|
|
||||||
paste(electrolytes.in.subset, collapse = ", or "), ".",
|
|
||||||
"I'll assume you want ", fallback.electrolyte, ".")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# temperature
|
|
||||||
# either happens to match a temperature in the dataset, or we interpolate
|
|
||||||
# (under the assumption that potential varies linearly with temperature)
|
|
||||||
if (!any(this.SHE.data$temp == dfargs$temperature[p])) {
|
|
||||||
# sought temperature was not available in dataset, check that it falls inside
|
|
||||||
# note: important to use less/more-than-or-equal in case data only contains one value
|
|
||||||
if ((dfargs$temperature[p] <= max(this.SHE.data$temp)) && (dfargs$temperature[p] >= min(this.SHE.data$temp))) {
|
|
||||||
# within dataset range, do linear interpolation
|
|
||||||
lm.subset <- stats::lm(SHE ~ temp, data = this.SHE.data)
|
|
||||||
# interpolated temperature, calculated based on linear regression
|
|
||||||
# (more accurate than simple linear interpolation with approx())
|
|
||||||
pot.interp <-
|
|
||||||
lm.subset$coefficients[2] * dfargs$temperature[p] + lm.subset$coefficients[1]
|
|
||||||
### CALC POTENTIAL vs SHE
|
|
||||||
dfargs$SHE[p] <-
|
|
||||||
ifelse(dfargs$scale[p] == "AVS",
|
|
||||||
pot.interp - dfargs$potential[p],
|
|
||||||
pot.interp + dfargs$potential[p])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
# requested temperature does exist in dataset
|
|
||||||
### CALC POTENTIAL vs SHE
|
|
||||||
dfargs$SHE[p] <-
|
|
||||||
ifelse(dfargs$scale[p] == "AVS",
|
|
||||||
subset(this.SHE.data, temp == dfargs$temperature[p])$SHE - dfargs$potential[p],
|
|
||||||
subset(this.SHE.data, temp == dfargs$temperature[p])$SHE + dfargs$potential[p])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(dfargs$SHE)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#' Convert from SHE scale to another electrochemical or physical scale
|
|
||||||
#'
|
|
||||||
#' Convert an arbitrary number of potentials vs SHE to another electrochemical
|
|
||||||
#' scale (or the vacuum scale).
|
|
||||||
#' The available target scales are those listed by \code{\link{potentials.as.SHE}}.
|
|
||||||
#'
|
|
||||||
#' @param potential potential in volt
|
|
||||||
#' @param scale name of the target scale
|
|
||||||
#' @param electrolyte optional, specify electrolyte solution, e.g., "KCl(aq)". Must match one of the values in \code{\link{potentials.as.SHE}$electrolyte}
|
|
||||||
#' @param concentration of electrolyte in mol/L, or as the string "saturated"
|
|
||||||
#' @param temperature of system in degrees Celsius
|
|
||||||
#' @param as.SHE.data by default this parameter reads the full dataset \code{\link{potentials.as.SHE}}
|
|
||||||
#'
|
|
||||||
#' @return potential in the specified target scale
|
|
||||||
#' @export
|
|
||||||
from.SHE <- function(potential,
|
|
||||||
scale,
|
|
||||||
electrolyte = "",
|
|
||||||
concentration = "saturated",
|
|
||||||
temperature = 25,
|
|
||||||
as.SHE.data = potentials.as.SHE()) {
|
|
||||||
|
|
||||||
# if the supplied temperature does not exist in the data, this function will attempt to interpolate
|
|
||||||
# note that concentration has to match, no interpolation is attempted for conc
|
|
||||||
|
|
||||||
# potential and scale vectors supplied by user could have arbitrary length
|
|
||||||
# just make sure potential and scale args have the same length (or length(scale) == 1)
|
|
||||||
if (length(potential) == 0 | length(scale) == 0) {
|
|
||||||
stop("Potential or scale arguments cannot be empty!")
|
|
||||||
} else if (length(potential) != length(scale)) {
|
|
||||||
# stop, unless length(scale) == 1 where we will assume it should be recycled
|
|
||||||
if (length(scale) == 1) {
|
|
||||||
message("Arg <scale> has unit length. We'll recycle it to match length of <potential>.")
|
|
||||||
scale <- rep(scale, length(potential))
|
|
||||||
} else {
|
|
||||||
stop("Length of <potential> and <scale> must be equal OR <scale> may be unit length.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arglength <- length(potential)
|
|
||||||
# make the args concentration, temperature and electrolyte this same length,
|
|
||||||
# unless the user supplied them (only necessary for length > 1)
|
|
||||||
if (arglength > 1) {
|
|
||||||
# handle two cases:
|
|
||||||
# 1. user did not touch concentration, temperature and electrolyte args.
|
|
||||||
# Assume they forgot and reset their length and print a message
|
|
||||||
# 2. user did change concentration or temperature or electrolyte, but still failed to
|
|
||||||
# ensure length equal to arglength. In this case, abort.
|
|
||||||
# note: we can get the default value set in the function call using formals()
|
|
||||||
if (identical(concentration, formals(from.SHE)$concentration) &
|
|
||||||
identical(temperature, formals(from.SHE)$temperature) &
|
|
||||||
identical(electrolyte, formals(from.SHE)$electrolyte)) {
|
|
||||||
# case 1
|
|
||||||
message(paste0("The default concentration (", formals(from.SHE)$concentration, ") and temperature (", formals(from.SHE)$temperature, "C) will be assumed for all your potential/scale values."))
|
|
||||||
concentration <- rep(concentration, arglength)
|
|
||||||
temperature <- rep(temperature, arglength)
|
|
||||||
electrolyte <- rep(electrolyte, arglength)
|
|
||||||
} else {
|
|
||||||
# case 2
|
|
||||||
stop("Concentration, temperature and electrolyte arguments must have the same number of elements as potential and scale!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## we can now safely assume that length(<args>) == arglength
|
|
||||||
# place args into a single dataframe
|
|
||||||
# this way, we can correlate columns to each other by row
|
|
||||||
dfargs <-
|
|
||||||
data.frame(potential = potential, # vs SHE
|
|
||||||
scale = common::RefCanonicalName(scale), # target scale
|
|
||||||
electrolyte = electrolyte,
|
|
||||||
concentration = concentration,
|
|
||||||
temperature = temperature,
|
|
||||||
stringsAsFactors = FALSE)
|
|
||||||
|
|
||||||
## From here on, ONLY access the arguments via this dataframe
|
|
||||||
## That is, use dfargs$electrolyte, NOT electrolyte (and so on)
|
|
||||||
|
|
||||||
# SHE scale special considerations
|
|
||||||
# 1. concentration is constant for SHE
|
|
||||||
if (any(dfargs$scale == common::RefCanonicalName("SHE"))) {
|
|
||||||
dfargs$concentration[which(dfargs$scale == common::RefCanonicalName("SHE"))] <- ""
|
|
||||||
dfargs$electrolyte[which(dfargs$scale == common::RefCanonicalName("SHE"))] <- ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# AVS scale special considerations
|
|
||||||
# 1. concentration is meaningless for AVS
|
|
||||||
if (any(dfargs$scale == common::RefCanonicalName("AVS"))) {
|
|
||||||
# concentration is meaningless for AVS (no electrolyte) so for those rows, we'll reset it
|
|
||||||
dfargs$concentration[which(dfargs$scale == common::RefCanonicalName("AVS"))] <- ""
|
|
||||||
dfargs$electrolyte[which(dfargs$scale == common::RefCanonicalName("AVS"))] <- ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# now just work our way through dfargs, line-by-line to determine potential as SHE
|
|
||||||
# all necessary conditions should be recorded right here in dfargs
|
|
||||||
for (p in 1:dim(dfargs)[1]) {
|
|
||||||
## WE ARE NOW WORKING ROW-BY-ROW THROUGH THE SUPPLIED ARGUMENTS IN dfargs
|
|
||||||
# Step-wise matching:
|
|
||||||
# + first, we subset against electrode scale. If dataset only has one row, done. Else,
|
|
||||||
# + we subset against either conc.string or conc.num. Stop if zero rows in dataset (error), otherwise proceed.
|
|
||||||
# Our "dataset" is the literature data supplied via the argument as.SHE.data
|
|
||||||
this.data.scale <- subset(as.SHE.data, electrode == dfargs$scale[p])
|
|
||||||
# subset.scale <- subset(as.SHE.data, electrode == dfargs$scale[p])
|
|
||||||
if (dim(this.data.scale)[1] > 1) {
|
|
||||||
# continue matching, now against conc.string or conc.num
|
|
||||||
if (is.character(dfargs$concentration[p])) {
|
|
||||||
this.data.concentration <-
|
|
||||||
subset(this.data.scale, conc.string == dfargs$concentration[p])
|
|
||||||
} else {
|
|
||||||
this.data.concentration <-
|
|
||||||
subset(this.data.scale, conc.num == dfargs$concentration[p])
|
|
||||||
}
|
|
||||||
# stop if the resulting dataframe after matching contains no rows
|
|
||||||
if (dim(this.data.concentration)[1] == 0) {
|
|
||||||
stop(paste0("Failed to find any matching entries in dataset for ",
|
|
||||||
paste(dfargs[p, ], collapse = " ", sep = "")))
|
|
||||||
}
|
|
||||||
# Note: it's ok at this point if the resulting dataset contains more than one row as
|
|
||||||
# more matching will be done below
|
|
||||||
# If we haven't had reason to stop(), we should be good
|
|
||||||
# just housekeeping: rename the variable so we don't have to edit code below
|
|
||||||
this.SHE.data <- this.data.concentration
|
|
||||||
} else {
|
|
||||||
# just housekeeping again
|
|
||||||
this.SHE.data <- this.data.scale
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
## Electrolyte
|
|
||||||
# == We would like to transparently handle the following scenario:
|
|
||||||
# || if the user did not specify electrolyte solution (which we can check by using formals())
|
|
||||||
# || but the dataset (after subsetting against scale and concentration above) still contains
|
|
||||||
# || more than one electrolyte
|
|
||||||
# >> Approach: we'll specify a "fallback" electrolyte, KCl (usually that's what the user wants)
|
|
||||||
# >> and inform/warn about it
|
|
||||||
|
|
||||||
# KCl is a good assumption, as we always have KCl for the cases where
|
|
||||||
# an electrode system has more than one electrolyte
|
|
||||||
fallback.electrolyte <- "KCl(aq)"
|
|
||||||
if (length(unique(this.SHE.data$electrolyte)) > 1) {
|
|
||||||
if (formals(as.SHE)$electrolyte == "") {
|
|
||||||
warning(paste0("More than one electrolyte ",
|
|
||||||
"available for E(", dfargs$scale[p], ") in dataset. ",
|
|
||||||
"I'll assume you want ", fallback.electrolyte, "."))
|
|
||||||
this.SHE.data <-
|
|
||||||
subset(this.SHE.data, electrolyte == fallback.electrolyte)
|
|
||||||
} else {
|
|
||||||
# else the user did change the electrolyte arg, use the user's value
|
|
||||||
this.SHE.data <-
|
|
||||||
subset(this.SHE.data, electrolyte == dfargs$electrolyte[p])
|
|
||||||
# but stop if the resulting dataframe contains no rows
|
|
||||||
if (dim(this.SHE.data)[1] == 0) stop("Your choice of electrolyte does not match any data!")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
# dataset contains only one unique electrolyte
|
|
||||||
# again, check if electrolyte in arg matches the one in dataset
|
|
||||||
# if it does, great, if it does not, print a message and use it anyway
|
|
||||||
if (unique(this.SHE.data$electrolyte) == dfargs$electrolyte[p]) {
|
|
||||||
this.SHE.data <-
|
|
||||||
subset(this.SHE.data, electrolyte == dfargs$electrolyte[p])
|
|
||||||
} else {
|
|
||||||
# whatever electrolyte the user supplied does not match what's left in the datasubset
|
|
||||||
# but at this point the user is probably better served by returning the electrolyte we have
|
|
||||||
# along with an informative message (that's the only reason for the if-else below)
|
|
||||||
electrolytes.in.subset <-
|
|
||||||
unique(subset(as.SHE.data, electrode == dfargs$scale[p])$electrolyte)
|
|
||||||
if (dfargs$electrolyte[p] == "") {
|
|
||||||
message(
|
|
||||||
paste0('Electrolyte "" (empty string) not in dataset for E(',
|
|
||||||
dfargs$scale[p], '). ',
|
|
||||||
'These electrolytes are: ',
|
|
||||||
paste(electrolytes.in.subset, collapse = ', or '), '.',
|
|
||||||
"I'll assume you want ", fallback.electrolyte, ".")
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
message(paste0("Electrolyte ", dfargs$electrolyte[p], " not in dataset for E(",
|
|
||||||
dfargs$scale[p], "). ",
|
|
||||||
"These electrolytes are: ",
|
|
||||||
paste(electrolytes.in.subset, collapse = ", or "), ".",
|
|
||||||
"I'll assume you want ", fallback.electrolyte, ".")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# temperature
|
|
||||||
# either happens to match a temperature in the dataset, or we interpolate
|
|
||||||
# (under the assumption that potential varies linearly with temperature)
|
|
||||||
if (!any(this.SHE.data$temp == dfargs$temperature[p])) {
|
|
||||||
# sought temperature was not available in dataset, check that it falls inside
|
|
||||||
# note: important to use less/more-than-or-equal in case data only contains one value
|
|
||||||
if ((dfargs$temperature[p] <= max(this.SHE.data$temp)) && (dfargs$temperature[p] >= min(this.SHE.data$temp))) {
|
|
||||||
# within dataset range, do linear interpolation
|
|
||||||
lm.subset <- stats::lm(SHE ~ temp, data = this.SHE.data)
|
|
||||||
# interpolated temperature, calculated based on linear regression
|
|
||||||
# (more accurate than simple linear interpolation with approx())
|
|
||||||
pot.interp <-
|
|
||||||
lm.subset$coefficients[2] * dfargs$temperature[p] + lm.subset$coefficients[1]
|
|
||||||
### CALC POTENTIAL vs requested scale
|
|
||||||
dfargs$potentialvsscale[p] <-
|
|
||||||
ifelse(dfargs$scale[p] == "AVS",
|
|
||||||
pot.interp - dfargs$potential[p],
|
|
||||||
dfargs$potential[p] - pot.interp)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
# requested temperature does exist in dataset
|
|
||||||
### CALC POTENTIAL vs requested scale
|
|
||||||
dfargs$potentialvsscale[p] <-
|
|
||||||
ifelse(dfargs$scale[p] == "AVS",
|
|
||||||
subset(this.SHE.data, temp == dfargs$temperature[p])$SHE - dfargs$potential[p],
|
|
||||||
dfargs$potential[p] - subset(this.SHE.data, temp == dfargs$temperature[p])$SHE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(dfargs$potentialvsscale)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#' ConvertRefPotEC
|
|
||||||
#'
|
|
||||||
#' This function does the heavy lifting.
|
|
||||||
#' Converts from an electrochemical reference scale into another.
|
|
||||||
#' SHE: standard hydrogen electrode
|
|
||||||
#' Ag/AgCl: silver silver-chloride electrode (3M KCl)
|
|
||||||
#' SCE: saturated calomel electrode
|
|
||||||
#'
|
|
||||||
#' @param argpotential potential (numeric)
|
|
||||||
#' @param argrefscale input reference scale (character string)
|
|
||||||
#' @param valuerefscale output reference scale (character string)
|
|
||||||
#'
|
|
||||||
#' @return potential in output reference scale (numeric)
|
|
||||||
ConvertRefPotEC <- function(argpotential, argrefscale, valuerefscale) {
|
|
||||||
.Deprecated("as.SHE")
|
|
||||||
##### Add more reference electrodes here >>
|
|
||||||
refpotatSHEzero <- c( 0, -0.21, -0.24, 3)
|
|
||||||
refrownames <- c( "SHE", "Ag/AgCl", "SCE", "Li/Li+")
|
|
||||||
refcolnames <- c("SHE0", "AgCl0", "SCE0", "Li0")
|
|
||||||
##### Add more reference electrodes here <<
|
|
||||||
#
|
|
||||||
SHE0 <-
|
|
||||||
data.frame(matrix(refpotatSHEzero,
|
|
||||||
ncol = length(refpotatSHEzero),
|
|
||||||
byrow = T))
|
|
||||||
refpotmtx <- matrix(NA, length(SHE0), length(SHE0))
|
|
||||||
refpotmtx[,1] <- matrix(as.matrix(SHE0), ncol = 1, byrow = T)
|
|
||||||
for (c in 2:length(SHE0)) {
|
|
||||||
# loop over columns (except the first)
|
|
||||||
for (r in 1:length(SHE0)) {
|
|
||||||
# loop over rows
|
|
||||||
refpotmtx[r, c] <- refpotmtx[r, 1] - refpotmtx[c, 1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
refpotdf <- as.data.frame(refpotmtx)
|
|
||||||
names(refpotdf) <- refcolnames
|
|
||||||
row.names(refpotdf) <- refrownames
|
|
||||||
## So far we have made a matrix of all the possible combinations,
|
|
||||||
## given the vector refpotatSHEzero. The matrix is not strictly necessary,
|
|
||||||
## but it may prove useful later. It does.
|
|
||||||
#
|
|
||||||
# Match argrefscale to the refrownames
|
|
||||||
argmatch <- match(argrefscale, refrownames, nomatch = 0)
|
|
||||||
# Match valuerefscale to the refrownames
|
|
||||||
valuematch <- match(valuerefscale, refrownames, nomatch = 0)
|
|
||||||
# We simply assume that the match was well-behaved
|
|
||||||
valuepotential <- argpotential + refpotdf[valuematch, argmatch]
|
|
||||||
# Check that arg and value electrodes are within bounds for a match
|
|
||||||
if (argmatch == 0 || valuematch == 0) {
|
|
||||||
# No match
|
|
||||||
# Perform suitable action
|
|
||||||
message("Arg out of bounds in call to ConvertRefPot")
|
|
||||||
valuepotential <- NA
|
|
||||||
}
|
|
||||||
return(valuepotential)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#' Convert from one electrochemical scale to another
|
|
||||||
#'
|
|
||||||
#' @param argpotential potential (numeric)
|
|
||||||
#' @param argrefscale input reference scale (char string)
|
|
||||||
#' @param valuerefscale output reference scale (char string)
|
|
||||||
#'
|
|
||||||
#' @return potential in output reference scale (numeric)
|
|
||||||
#' @export
|
|
||||||
ConvertRefPot <- function(argpotential, argrefscale, valuerefscale) {
|
|
||||||
.Deprecated("as.SHE")
|
|
||||||
# You should check that argpotential is valid numeric
|
|
||||||
|
|
||||||
# IDEA: make a matrix out of these (scale names and flags)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Valid scales
|
|
||||||
scale.names <- list()
|
|
||||||
scale.names[["SHE"]] <- c("SHE", "NHE", "she", "nhe")
|
|
||||||
scale.names[["AgCl"]] <- c("Ag/AgCl", "AgCl", "ag/agcl", "agcl")
|
|
||||||
scale.names[["SCE"]] <- c("SCE", "sce")
|
|
||||||
scale.names[["Li"]] <- c("Li/Li+", "Li", "Li+", "li", "li+", "li/li+")
|
|
||||||
scale.names[["AVS"]] <- c("AVS", "avs")
|
|
||||||
|
|
||||||
# Set flags
|
|
||||||
bool.flags <-
|
|
||||||
as.data.frame(matrix(0,
|
|
||||||
nrow = length(scale.names),
|
|
||||||
ncol = 2))
|
|
||||||
names(bool.flags) <- c("argref", "valueref")
|
|
||||||
row.names(bool.flags) <- names(scale.names)
|
|
||||||
|
|
||||||
# argrefscale
|
|
||||||
# Check that argrefscale is valid character mode
|
|
||||||
# ...
|
|
||||||
|
|
||||||
# steps through all scale names, "row-by-row",
|
|
||||||
# looking for any cell matching "argrefscale" string
|
|
||||||
# if found, save the position of that refelectrode (in scale.names) to
|
|
||||||
# that row and "argref" column of bool.flags
|
|
||||||
for (j in 1:length(row.names(bool.flags))) {
|
|
||||||
if (any(scale.names[[row.names(bool.flags)[j]]] == argrefscale)) {
|
|
||||||
bool.flags[row.names(bool.flags)[j], "argref"] <- j
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# valuerefscale
|
|
||||||
# Check that valuerefscale is valid character mode
|
|
||||||
# ...
|
|
||||||
|
|
||||||
for (k in 1:length(row.names(bool.flags))) {
|
|
||||||
if (any(scale.names[[row.names(bool.flags)[k]]] == valuerefscale)) {
|
|
||||||
bool.flags[row.names(bool.flags)[k], "valueref"] <- k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Depending on which flags are set, call the corresponding function
|
|
||||||
|
|
||||||
decision.vector <- colSums(bool.flags)
|
|
||||||
|
|
||||||
# Check if both scales are the same (no conversion needed). If so, abort gracefully.
|
|
||||||
# ...
|
|
||||||
|
|
||||||
if (decision.vector["argref"] == 5 || decision.vector["valueref"] == 5) {
|
|
||||||
# AVS is requested, deal with it it
|
|
||||||
if (decision.vector["argref"] == 5) {
|
|
||||||
# Conversion _from_ AVS
|
|
||||||
rnpotential <- ConvertRefPotEC(AVS2SHE(argpotential),
|
|
||||||
"SHE",
|
|
||||||
scale.names[[decision.vector["valueref"]]][1])
|
|
||||||
}
|
|
||||||
if (decision.vector["valueref"] == 5) {
|
|
||||||
# Conversion _to_ AVS
|
|
||||||
rnpotential <- SHE2AVS(ConvertRefPotEC(argpotential,
|
|
||||||
scale.names[[decision.vector["argref"]]][1],
|
|
||||||
"SHE"))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rnpotential <- ConvertRefPotEC(argpotential,
|
|
||||||
scale.names[[decision.vector["argref"]]][1],
|
|
||||||
scale.names[[decision.vector["valueref"]]][1])
|
|
||||||
}
|
|
||||||
return(rnpotential)
|
|
||||||
}
|
|
@ -1,4 +1,9 @@
|
|||||||
## A collection of general functions and data
|
# A collection of general functions and data
|
||||||
|
|
||||||
Includes common numerical functions, unit converters,
|
Includes common numerical functions and some LaTeX-specific functions.
|
||||||
some LaTeX-specific functions, as well as reference data.
|
|
||||||
|
|
||||||
|
|
||||||
|
## NOTE: the electrochemical reference electrode functions
|
||||||
|
|
||||||
|
have **moved** to the [`refelectrodes` package](https://github.com/chepec/refelectrodes)!
|
||||||
|
@ -1,190 +0,0 @@
|
|||||||
"T/degreeCelsius","P/kPa","dvapH/kJ kg-1","surface tension/mN m-1"
|
|
||||||
0.01,0.61165,2500.9,75.65
|
|
||||||
2,0.70599,2496.2,75.37
|
|
||||||
4,0.81355,2491.4,75.08
|
|
||||||
6,0.93536,2486.7,74.8
|
|
||||||
8,1.073,2481.9,74.51
|
|
||||||
10,1.2282,2477.2,74.22
|
|
||||||
12,1.4028,2472.5,73.93
|
|
||||||
14,1.599,2467.7,73.63
|
|
||||||
16,1.8188,2463,73.34
|
|
||||||
18,2.0647,2458.3,73.04
|
|
||||||
20,2.3393,2453.5,72.74
|
|
||||||
22,2.6453,2448.8,72.43
|
|
||||||
24,2.9858,2444,72.13
|
|
||||||
25,3.1699,2441.7,71.97
|
|
||||||
26,3.3639,2439.3,71.82
|
|
||||||
28,3.7831,2434.6,71.51
|
|
||||||
30,4.247,2429.8,71.19
|
|
||||||
32,4.7596,2425.1,70.88
|
|
||||||
34,5.3251,2420.3,70.56
|
|
||||||
36,5.9479,2415.5,70.24
|
|
||||||
38,6.6328,2410.8,69.92
|
|
||||||
40,7.3849,2406,69.6
|
|
||||||
42,8.2096,2401.2,69.27
|
|
||||||
44,9.1124,2396.4,68.94
|
|
||||||
46,10.099,2391.6,68.61
|
|
||||||
48,11.177,2386.8,68.28
|
|
||||||
50,12.352,2381.9,67.94
|
|
||||||
52,13.631,2377.1,67.61
|
|
||||||
54,15.022,2372.3,67.27
|
|
||||||
56,16.533,2367.4,66.93
|
|
||||||
58,18.171,2362.5,66.58
|
|
||||||
60,19.946,2357.7,66.24
|
|
||||||
62,21.867,2352.8,65.89
|
|
||||||
64,23.943,2347.8,65.54
|
|
||||||
66,26.183,2342.9,65.19
|
|
||||||
68,28.599,2338,64.84
|
|
||||||
70,31.201,2333,64.48
|
|
||||||
72,34,2328.1,64.12
|
|
||||||
74,37.009,2323.1,63.76
|
|
||||||
76,40.239,2318.1,63.4
|
|
||||||
78,43.703,2313,63.04
|
|
||||||
80,47.414,2308,62.67
|
|
||||||
82,51.387,2302.9,62.31
|
|
||||||
84,55.635,2297.9,61.94
|
|
||||||
86,60.173,2292.8,61.56
|
|
||||||
88,65.017,2287.6,61.19
|
|
||||||
90,70.182,2282.5,60.82
|
|
||||||
92,75.684,2277.3,60.44
|
|
||||||
94,81.541,2272.1,60.06
|
|
||||||
96,87.771,2266.9,59.68
|
|
||||||
98,94.39,2261.7,59.3
|
|
||||||
100,101.42,2256.4,58.91
|
|
||||||
102,108.87,2251.1,58.53
|
|
||||||
104,116.78,2245.8,58.14
|
|
||||||
106,125.15,2240.4,57.75
|
|
||||||
108,134.01,2235.1,57.36
|
|
||||||
110,143.38,2229.6,56.96
|
|
||||||
112,153.28,2224.2,56.57
|
|
||||||
114,163.74,2218.7,56.17
|
|
||||||
116,174.77,2213.2,55.77
|
|
||||||
118,186.41,2207.7,55.37
|
|
||||||
120,198.67,2202.1,54.97
|
|
||||||
122,211.59,2196.5,54.56
|
|
||||||
124,225.18,2190.9,54.16
|
|
||||||
126,239.47,2185.2,53.75
|
|
||||||
128,254.5,2179.5,53.34
|
|
||||||
130,270.28,2173.7,52.93
|
|
||||||
132,286.85,2167.9,52.52
|
|
||||||
134,304.23,2162.1,52.11
|
|
||||||
136,322.45,2156.2,51.69
|
|
||||||
138,341.54,2150.3,51.27
|
|
||||||
140,361.54,2144.3,50.86
|
|
||||||
142,382.47,2138.3,50.44
|
|
||||||
144,404.37,2132.2,50.01
|
|
||||||
146,427.26,2126.1,49.59
|
|
||||||
148,451.18,2119.9,49.17
|
|
||||||
150,476.16,2113.7,48.74
|
|
||||||
152,502.25,2107.5,48.31
|
|
||||||
154,529.46,2101.2,47.89
|
|
||||||
156,557.84,2094.8,47.46
|
|
||||||
158,587.42,2088.4,47.02
|
|
||||||
160,618.23,2082,46.59
|
|
||||||
162,650.33,2075.5,46.16
|
|
||||||
164,683.73,2068.9,45.72
|
|
||||||
166,718.48,2062.3,45.28
|
|
||||||
168,754.62,2055.6,44.85
|
|
||||||
170,792.19,2048.8,44.41
|
|
||||||
172,831.22,2042,43.97
|
|
||||||
174,871.76,2035.1,43.52
|
|
||||||
176,913.84,2028.2,43.08
|
|
||||||
178,957.51,2021.2,42.64
|
|
||||||
180,1002.8,2014.2,42.19
|
|
||||||
182,1049.8,2007,41.74
|
|
||||||
184,1098.5,1999.8,41.3
|
|
||||||
186,1148.9,1992.6,40.85
|
|
||||||
188,1201.1,1985.3,40.4
|
|
||||||
190,1255.2,1977.9,39.95
|
|
||||||
192,1311.2,1970.4,39.49
|
|
||||||
194,1369.1,1962.8,39.04
|
|
||||||
196,1429,1955.2,38.59
|
|
||||||
198,1490.9,1947.5,38.13
|
|
||||||
200,1554.9,1939.7,37.67
|
|
||||||
202,1621,1931.9,37.22
|
|
||||||
204,1689.3,1923.9,36.76
|
|
||||||
206,1759.8,1915.9,36.3
|
|
||||||
208,1832.6,1907.8,35.84
|
|
||||||
210,1907.7,1899.6,35.38
|
|
||||||
212,1985.1,1891.4,34.92
|
|
||||||
214,2065,1883,34.46
|
|
||||||
216,2147.3,1874.6,33.99
|
|
||||||
218,2232.2,1866,33.53
|
|
||||||
220,2319.6,1857.4,33.07
|
|
||||||
222,2409.6,1848.6,32.6
|
|
||||||
224,2502.3,1839.8,32.14
|
|
||||||
226,2597.8,1830.9,31.67
|
|
||||||
228,2696,1821.8,31.2
|
|
||||||
230,2797.1,1812.7,30.74
|
|
||||||
232,2901,1803.5,30.27
|
|
||||||
234,3008,1794.1,29.8
|
|
||||||
236,3117.9,1784.7,29.33
|
|
||||||
238,3230.8,1775.1,28.86
|
|
||||||
240,3346.9,1765.4,28.39
|
|
||||||
242,3466.2,1755.6,27.92
|
|
||||||
244,3588.7,1745.7,27.45
|
|
||||||
246,3714.5,1735.6,26.98
|
|
||||||
248,3843.6,1725.5,26.51
|
|
||||||
250,3976.2,1715.2,26.04
|
|
||||||
252,4112.2,1704.7,25.57
|
|
||||||
254,4251.8,1694.2,25.1
|
|
||||||
256,4394.9,1683.5,24.63
|
|
||||||
258,4541.7,1672.6,24.16
|
|
||||||
260,4692.3,1661.6,23.69
|
|
||||||
262,4846.6,1650.5,23.22
|
|
||||||
264,5004.7,1639.2,22.75
|
|
||||||
266,5166.8,1627.8,22.28
|
|
||||||
268,5332.9,1616.2,21.81
|
|
||||||
270,5503,1604.4,21.34
|
|
||||||
272,5677.2,1592.5,20.87
|
|
||||||
274,5855.6,1580.4,20.4
|
|
||||||
276,6038.3,1568.1,19.93
|
|
||||||
278,6225.2,1555.6,19.46
|
|
||||||
280,6416.6,1543,18.99
|
|
||||||
282,6612.4,1530.1,18.53
|
|
||||||
284,6812.8,1517.1,18.06
|
|
||||||
286,7017.7,1503.8,17.59
|
|
||||||
288,7227.4,1490.4,17.13
|
|
||||||
290,7441.8,1476.7,16.66
|
|
||||||
292,7661,1462.7,16.2
|
|
||||||
294,7885.2,1448.6,15.74
|
|
||||||
296,8114.3,1434.2,15.28
|
|
||||||
298,8348.5,1419.5,14.82
|
|
||||||
300,8587.9,1404.6,14.36
|
|
||||||
302,8832.5,1389.4,13.9
|
|
||||||
304,9082.4,1374,13.45
|
|
||||||
306,9337.8,1358.2,12.99
|
|
||||||
308,9598.6,1342.1,12.54
|
|
||||||
310,9865.1,1325.7,12.09
|
|
||||||
312,10137,1309,11.64
|
|
||||||
314,10415,1291.9,11.19
|
|
||||||
316,10699,1274.5,10.75
|
|
||||||
318,10989,1256.6,10.3
|
|
||||||
320,11284,1238.4,9.86
|
|
||||||
322,11586,1219.7,9.43
|
|
||||||
324,11895,1200.6,8.99
|
|
||||||
326,12209,1180.9,8.56
|
|
||||||
328,12530,1160.8,8.13
|
|
||||||
330,12858,1140.2,7.7
|
|
||||||
332,13193,1118.9,7.28
|
|
||||||
334,13534,1097.1,6.86
|
|
||||||
336,13882,1074.6,6.44
|
|
||||||
338,14238,1051.3,6.03
|
|
||||||
340,14601,1027.3,5.63
|
|
||||||
342,14971,1002.5,5.22
|
|
||||||
344,15349,976.7,4.83
|
|
||||||
346,15734,949.9,4.43
|
|
||||||
348,16128,922,4.05
|
|
||||||
350,16529,892.7,3.67
|
|
||||||
352,16939,862.1,3.29
|
|
||||||
354,17358,829.8,2.93
|
|
||||||
356,17785,795.5,2.57
|
|
||||||
358,18221,759,2.22
|
|
||||||
360,18666,719.8,1.88
|
|
||||||
362,19121,677.3,1.55
|
|
||||||
364,19585,630.5,1.23
|
|
||||||
366,20060,578.2,0.93
|
|
||||||
368,20546,517.8,0.65
|
|
||||||
370,21044,443.8,0.39
|
|
||||||
372,21554,340.3,0.16
|
|
||||||
373.95,22064,0,0
|
|
|
Binary file not shown.
Loading…
Reference in New Issue