You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
6.3 KiB
R
156 lines
6.3 KiB
R
#' Calculate required mass of substance to dissolve
|
|
#'
|
|
#' You want to prepare a solution of known molarity and volume of
|
|
#' a particular substance.
|
|
#' This function calculates the required mass to weigh up.
|
|
#'
|
|
#' @param formulamass of the substance (in grams per mole)
|
|
#' @param volume of the final solution (in liters)
|
|
#' @param molarity (in moles per liter)
|
|
#'
|
|
#' @return mass of substance (in grams)
|
|
#' @export
|
|
molarity2mass <- function(formulamass, volume, molarity) {
|
|
mass <- formulamass * volume * molarity
|
|
# Double-check units:
|
|
# [g * mol-1] * [liter] * [mole * liter-1] = [g]
|
|
return(mass)
|
|
}
|
|
|
|
|
|
|
|
#' Vapour pressure of water
|
|
#'
|
|
#' Vapour pressure of water as a function of temperature
|
|
#' This function returns the vapour pressure of water at the given
|
|
#' temperature(s) from the common::vapourwater dataset.
|
|
#'
|
|
#' @param temperature numeric vector, in degrees Celsius
|
|
#'
|
|
#' @return vapour pressure of water, in kilopascal
|
|
#' @export
|
|
#'
|
|
#' @examples
|
|
#' \dontrun{
|
|
#' VapourPressureWater(45)
|
|
#' VapourPressureWater(c(20, 25, 45, 60))
|
|
#' }
|
|
VapourPressureWater <- function(temperature) {
|
|
data <- common::vapourwater
|
|
# if T outside range in data, warn the user
|
|
if (any(temperature < min(data$temperature)) | any(temperature > max(data$temperature))) {
|
|
warning("At least one supplied temperature is outside the data range (",
|
|
paste(range(data$temperature), collapse=" - "),
|
|
" Celsius). Returning NAs for those values.")
|
|
}
|
|
# The vapourwater dataset only contains data for every degree celsius (or less),
|
|
# so we use the interpolation function to fill in the rest.
|
|
# Note that approx(rule = 1) returns NAs for input outside the data range.
|
|
pressure <-
|
|
stats::approx(x = data$temperature, y = data$pressure,
|
|
method = "linear", rule = 1,
|
|
xout = temperature)$y
|
|
return(pressure)
|
|
}
|
|
|
|
|
|
|
|
#' Oxygen solubility in water
|
|
#'
|
|
#' Oxygen solubility in water which is in contact with
|
|
#' air saturated with water vapour, as a function of
|
|
#' temperature and at a total pressure of 760 torr.
|
|
#'
|
|
#' Some background: as the temperature of a gasesous solution is raised the
|
|
#' gas is driven off until complete degassing occurs at the boiling point
|
|
#' of the solvent. This variation of solubility with temperature can be
|
|
#' derived from thermodynamic first principles.
|
|
#' But the variation of oxygen solubility in water cannot be represented by a
|
|
#' simple relationship (derived from thermodynamic first principles), and so
|
|
#' more complicated expressions which are fitted to empirical data have
|
|
#' to be used.
|
|
#'
|
|
#' Hitchman, Measurement of Dissolved Oxygen, 1978 reproduce a table by
|
|
#' Battino and Clever (1966) that presents experimental values of the
|
|
#' so-called Bunsen absorption coefficient (this is the volume of gas, at 0 C
|
|
#' and 760 torr, that, at the temperature of measurement, is dissolved in one
|
|
#' volume of the solvent when the partial pressure of the gas is 760 torr)
|
|
#' recorded by eleven research groups up until 1965. The standard error of the
|
|
#' mean value is never greater +-0.5%. The mean values from this table are
|
|
#' probably accurate enough for most applications.
|
|
#' Hitchman notes that the data in this table can be fitted by two forms of
|
|
#' equations: one form obtained from Henry's law (under the restriction that
|
|
#' the partial pressure of the gas remains constant), and another form by
|
|
#' describing the variation with temperature by fitting a general power series.
|
|
#' The latter approach is used in this function.
|
|
#'
|
|
#' Hitchman chooses to fit a fourth degree polynomial, and found that the
|
|
#' square of the correlation coefficient was 0.999996.
|
|
#'
|
|
#' For more background and detailed derivation of the formula used here,
|
|
#' see section 2.2 (pp. 11) in Hitchman.
|
|
#'
|
|
#' This formula is strictly speaking only valid for 0 < T < 50 celsius.
|
|
#' The function will return values outside this range, but with a warning.
|
|
#'
|
|
#' @param temperature numeric, vector. In degrees Celsius.
|
|
#'
|
|
#' @return a dataframe with the following columns:
|
|
#' + "temperature" same as the supplied temperature
|
|
#' + "g/cm-3" oxygen solubility expressed as gram per cubic cm
|
|
#' + "mg/L" ditto expressed as milligram per litre
|
|
#' + "mol/L" ditto expressed as moles per litre (molarity)
|
|
#' + "permoleculewater" number of O2 molecules per molecule of water
|
|
#' Note: mg/L is equivalent to ppm by weight (since water has approx
|
|
#' unit density in the temperature range 0-50 Celsius).
|
|
#' @export
|
|
#' @examples
|
|
#' \dontrun{
|
|
#' OxygenSolubilityWater(22)
|
|
#' OxygenSolubilityWater(c(2, 7, 12, 30))
|
|
#' }
|
|
OxygenSolubilityWater <- function(temperature) {
|
|
if (any(temperature < 0) | any(temperature > 50)) {
|
|
warning("This function is fitted to data within the range 0 - 50 Celsius. ",
|
|
"You are now extrapolating.")
|
|
}
|
|
# formula weight of oxygen
|
|
oxygen.fw <- 15.9994 # gram per mole
|
|
# formula weight of water
|
|
water.fw <- 18.02
|
|
# oxygen ratio in dry air (20.95%)
|
|
oxygen.dryair <- 20.95 / 100
|
|
# coefficients (from Hitchman)
|
|
A <- 4.9E1
|
|
B <- -1.335
|
|
C <- 2.759E-2
|
|
D <- -3.235E-4
|
|
E <- 1.614E-6
|
|
# conversion factor from Bunsen to g/cm-3
|
|
conv.factor <- (2 * oxygen.fw) / 22.414E3
|
|
# Bunsen absorption coefficient, commonly denoted as Greek alpha
|
|
alpha <-
|
|
1E-3 * (A + B * temperature + C * temperature^2 +
|
|
D * temperature^3 + E * temperature^4)
|
|
# solubility of oxygen, in gram per cm-3
|
|
oxygen.solubility <-
|
|
data.frame(temperature = temperature,
|
|
grampercm3 =
|
|
(conv.factor * oxygen.dryair / 760) * alpha *
|
|
# keep in mind that VapourPressureWater() returns values in kilopascal
|
|
(760 - pascal2torr(1E3 * common::VapourPressureWater(temperature))),
|
|
mgperlitre =
|
|
1E6 * (conv.factor * oxygen.dryair / 760) * alpha *
|
|
(760 - pascal2torr(1E3 * common::VapourPressureWater(temperature))),
|
|
molperlitre =
|
|
1E3 * (conv.factor * oxygen.dryair / 760) * alpha *
|
|
(760 - pascal2torr(1E3 * common::VapourPressureWater(temperature))) /
|
|
(2 * oxygen.fw))
|
|
# Number of O2 molecules per water molecule
|
|
oxygen.solubility$permoleculewater <-
|
|
# note: using a water density value that's approx the average in the
|
|
# temperature range 0 - 50 Celsius
|
|
((1E3 * oxygen.solubility$grampercm3) / oxygen.fw) / (995.00 / water.fw)
|
|
return(oxygen.solubility)
|
|
}
|