# CHNOSZ/demo/Pourbaix.R # Eh-pH diagram for Fe-O-H with equisolubility lines # After Pourbaix (1974, p. 312) # 20210301 jmd first version library(CHNOSZ) # Load OBIGT database without organic species # (speeds up and reduces memory needed for C diagram) OBIGT(no.organics = TRUE) ### PARAMETERS (to be changed by the user) ### # Choose an element # Some mostly working ones: Fe, Cu, Au, Rh, Mn, C # Incomplete: Al (no native metal), Ni, ... # Not working: Cr, ... # (Cr has no solids in OBIGT) element <- "Fe" # Set temperature and pressure T <- 25 # Can use "Psat" for T >= 100 degC P <- 1 # Ionic strength (mol/kg) IS <- 0 # Set plot limits and resolution pH <- c(-2, 16) Eh <- c(-2, 2) res <- 700 # Assign levels for equisolubility lines levels <- seq(-6, 0, 2) # Switches for using colors color.fields <- TRUE color.water <- TRUE color.lines <- TRUE color.names <- TRUE # Names of aqueous species to move down # (to avoid conflict with water lines or mineral names) namesdown <- c("MnOH+", "MnO", "Cu+2", "CuO") # Names of aqueous species to move down even more namesdown2 <- c("Fe+3", "FeOH+2", "FeO+", "HFeO2", "FeO2-", "HMnO2-", "MnO2-2") ### SCRIPT (can also be changed by the user if wanted!) ### # Find a species with this element # (to be used as a basis species) elem_basis <- element if(is.na(suppressMessages(info(elem_basis)))) { elem_basis <- paste0(element, "+") if(is.na(suppressMessages(info(elem_basis)))) { elem_basis <- paste0(element, "+2") if(is.na(suppressMessages(info(elem_basis)))) { elem_basis <- paste0(element, "+3") } } } # Define system basis(c(elem_basis, "H2O", "H+", "e-")) # Find species icr <- retrieve(element, c("O", "H"), "cr", T = T, P = P) iaq <- retrieve(element, c("O", "H"), "aq", T = T, P = P) # Add solids with unit activity species(icr, 0) # Add aqueous species with activity for first equisolubility line species(iaq, levels[1], add = TRUE) # Calculate affinities of formation of species # from basis species as a function of Eh and pH a_all <- affinity(pH = c(pH, res), Eh = c(Eh, res), T = T, P = P, IS = IS) # Plot diagram (LAYER 1: colors for all fields) limit.water <- fill <- NULL if(!color.water) limit.water <- FALSE if(!color.fields) fill <- NA d_all <- diagram(a_all, names = FALSE, lty = 0, min.area = 0.1, limit.water = limit.water, fill = fill) # Calculate affinities for minerals species(icr) # Calculate overall solubility (i.e. minimum solubility given all candidate minerals) s <- solubility(iaq, pH = c(pH, res), Eh = c(Eh, res), T = T, P = P, IS = IS, in.terms.of = element) # Plot diagram (LAYER 2: equisolubility lines) diagram(s, levels = levels, contour.method = "flattest", add = TRUE, lwd = 1.5) # Calculate affinities for aqueous species # FIXME: should be able to remove cr species from previous affinity object species(iaq, 0) a_aq <- affinity(pH = c(pH, res), Eh = c(Eh, res), T = T, P = P, IS = IS) # Plot diagram (LAYER 3: equal-activity lines for aqueous species) col <- ifelse(color.lines, 4, 1) # Use a white background to improve contrast # (so the line remains visible if it coincides with an equisolubility contour) diagram(a_aq, add = TRUE, col = "white", lwd = 1.3, names = FALSE) # Plot diagram (LAYER 4: labels for aqueous species fields) # Apply y offset for specified names dy <- rep(0, nrow(a_aq$species)) dy[a_aq$species$name %in% namesdown] <- -0.3 dy[a_aq$species$name %in% namesdown2] <- -0.5 # Use a white background for names rx <- diff(par("usr")[1:2]) for(ddx in c(-rx/700, rx/700)) diagram(a_aq, add = TRUE, lty = 2, lwd = 0.6, col = col, dx = ddx, dy = dy, col.names = "white", bold = TRUE) ry <- diff(par("usr")[3:4]) for(ddy in c(-ry/700, ry/700)) diagram(a_aq, add = TRUE, lty = 2, lwd = 0.6, col = col, dy = dy + ddy, col.names = "white", bold = TRUE) col.names <- ifelse(color.names, 4, 1) diagram(a_aq, add = TRUE, lty = 0, col = col, dy = dy, col.names = col.names) # Add solids with unit activity species(icr, 0) # Add aqueous species with activity for last equisolubility line # (i.e. unit activity) species(iaq, levels[length(levels)], add = TRUE) # Calculate affinities of formation of species # from basis species as a function of Eh and pH a_all_0 <- affinity(pH = c(pH, res), Eh = c(Eh, res), T = T, P = P, IS = IS) # Plot diagram (LAYER 5: mineral stability boundaries and water lines) d_all_0 <- diagram(a_all_0, fill = NA, names = FALSE, lty = 0, lty.cr = 1, lwd = 3, add = TRUE) water.lines(d_all_0, lty = 5, lwd = 1.3) # Plot diagram (LAYER 6: large bold labels for all mineral fields) # (this is the last layer, so names are above equal-activity lines, # but we use positions calculated with the first equisolubility line # so that names are within the shrunken parts of the mineral fields) # Create labels using chemical formulas instead of name of minerals formulas <- info(a_all$species$ispecies, check.it = FALSE)$formula formulas[a_all$species$state == "aq"] <- "" diagram(a_all, fill = NA, names = formulas, bold = TRUE, cex.names = 1.2, lty = 0, add = TRUE) # Add title Texpr <- lT(T) Pexpr <- lP(P) main <- bquote(.(element)*"-O-H at "*.(Texpr)*" and "*.(Pexpr)) title(main = main) # Reset OBIGT database to run other demos reset()