Commit 7673975e authored by Marco De Lucia's avatar Marco De Lucia
Browse files

MDL: some fixes for CRAN submission

parent 199bd108
Package: RedModRphree
Title: Programmable interface to the phreeqc geochemical solver adding features such as surrogate models, reactive transport and Pourbaix diagrams
Version: 0.2
Authors@R: c(person("Marco", "De Lucia", email = "delucia@gfz-potsdam.de", role = c("aut", "cre"), comment=, comment = c(ORCID = "0000-0003-0918-3766")),
person("Janis", "Jatnieks", email = "deltaxzz@gmail.com", role = c("ctb")))
Author: Marco De Lucia [aut, cre],
Janis Jatnieks [ctb]
Maintainer: Marco De Lucia <delucia@gfz-potsdam.de>
Description: Programmable interface to the phreeqc geochemical solver adding features such as surrogate models, reactive transport and Pourbaix diagrams.
Title: Programmable Interface to the PHREEQC Geochemical Solver
Version: 0.3.1
Authors@R: c(person(given = "Marco",
family = "De Lucia",
email = "delucia@gfz-potsdam.de",
role = c("aut", "cre"),
comment = c(ORCID = "0000-0003-0918-3766")),
person(given = "Janis",
family = "Jatnieks",
email = "deltaxzz@gmail.com",
role = c("ctb")))
Description: Programmable interface to the phreeqc geochemical solver
adding features such as surrogate models, reactive transport and
Pourbaix diagrams.
Depends: R (>= 3.2.0), doParallel, phreeqc, mgcv, graphics, methods, stats, utils, plyr, foreach
License: LGPL-2.1
Encoding: UTF-8
LLazyData: true
RoxygenNote: 7.1.1
LazyData: true
......@@ -11,7 +11,6 @@ export(DistributeKin)
export(DistributeKinMatrix)
export(DistributeMatrix)
export(ElementalBalanceMin)
export(ExtractPphases)
export(ExtractSamples)
export(ExtractSpecies)
export(ExtractTotals)
......
## Functions for dealing with simulations with kinetics
### Marco De Lucia, delucia@gfz-potsdam.de, 2009-2021
### Time-stamp: "Last modified 2021-04-12 12:46:35 delucia"
### Time-stamp: "Last modified 2021-04-28 15:19:27 delucia"
##' This function runs the generated input buffer (or a list thereof)
##' through \code{phreeqc}, which has been already loaded as
##' dependency. Also the database must be previously and explicitely
##' loaded by the user using, e.g.,
##' \code{db <- RPhreeFile('/path/to/database.dat', is.db=TRUE)}
##' followed by
##' \code{phreeqc::phrLoadDatabaseString(db)}
##' or using one of the databases included in \code{phreeqc}, e.g.,
##' loaded by the user using, e.g., \code{db <-
##' RPhreeFile('/path/to/database.dat', is.db=TRUE)} followed by
##' \code{phreeqc::phrLoadDatabaseString(db)} or using one of the
##' databases included in \code{phreeqc}, e.g.,
##' \code{phreeqc::phrLoadDatabaseString(phreeqc.dat)}.
##'
##' Parallelization is achieved using \code{%dopar%} from package
......@@ -55,7 +54,6 @@ RunPQC <- function(input, procs=1, second=TRUE) {
## old one
## res <- parallel::mclapply(input, .runPQC, mc.silent=TRUE, mc.cores=procs)
## res <- parallel::parLapply(ThisRunCluster, input, .runPQC)
res <- foreach::foreach(i=seq_along(input), .combine=rbind) %dopar% .runPQC(input[[i]], onlysecond=second)
## ## a is the string containing the rbind of each element of the list
......@@ -79,7 +77,8 @@ RunPQC <- function(input, procs=1, second=TRUE) {
##' @param prop The property whose values need to be distributed.
##' @param values The numerical value(s) to distribute across the
##' SOLUTIONS/KINETICS blocks.
##' @param ident The identifier for the line where the actual values will be pasted, defaults to "-m"
##' @param ident The identifier for the line where the actual values
##' will be pasted, defaults to "-m"
##' @return A new input buffer
##' @author MDL
##' @export
......
## Functions for dealing with surrogate simulations
### Marco De Lucia, delucia@gfz-potsdam.de, 2009-2018
### Time-stamp: "Last modified 2021-04-12 13:05:02 delucia"
### Marco De Lucia, delucia@gfz-potsdam.de, 2009-2021
### Time-stamp: "Last modified 2021-04-28 15:30:47 delucia"
##' Todo
......@@ -203,17 +203,22 @@ ReduceState <- function(data)
##' occurences of a geochemical problem?
##' @param ebreak logical, defaults to FALSE. If TRUE, an early break
##' is invoked
##' @param writeout logical, defaults to FALSE.
##' @param writeout logical, defaults to FALSE. Should we write the
##' phreeqc output on disk?
##' @param surrogate logical, defaults to FALSE. Should we use
##' surrogates instead of phreeqc?
##' @param surrogate.FUN The function which calls the surrogate
##' @param model The list of surrogate models, one element per
##' variable
##' @param model a list containing all surrogate models, one element
##' per variable
##' @param baleq data structure containing the balance equations
##' @param tol absolute tolerance on the mass balance
##' @param tol absolute tolerance on the mass balance. If this is
##' trespassed, phreeqc is called instead
##' @param call_pqc logical, defaults to TRUE: if TRUE, calls phreeqc
##' on the surrogate simulations which trespass the tolerance
##' @return a list containing lots of stuff
##' @return a list containing lots of stuff. Each element of the list
##' represent an iteration and has two elements: $T
##' (concentrations after the transport) and $C, concentrations
##' after the chemistry
##' @author MDL
##' @export
ReactTranspBalanceEq <- function(setup, init, maxtime, step=c("time","iter","fix_dt"),
......@@ -243,9 +248,9 @@ ReactTranspBalanceEq <- function(setup, init, maxtime, step=c("time","iter","fix
if (procs > 1) {
if (Sys.info()[["sysname"]]=="Windows") {
ThisRunCluster <<- parallel::makePSOCKcluster(procs)
ThisRunCluster <- parallel::makePSOCKcluster(procs)
} else {
ThisRunCluster <<- parallel::makeForkCluster(procs)
ThisRunCluster <- parallel::makeForkCluster(procs)
}
doParallel::registerDoParallel(ThisRunCluster)
......@@ -480,7 +485,7 @@ ReactTranspBalanceEq <- function(setup, init, maxtime, step=c("time","iter","fix
on.exit()
if (procs > 1) {
stopCluster(ThisRunCluster)
parallel::stopCluster(ThisRunCluster)
msg("Parallelization cluster stopped")
}
......@@ -553,9 +558,9 @@ ReactTranspBalanceKin <- function(setup, init, maxtime, step=c("time","iter","fi
if (procs > 1) {
if (Sys.info()[["sysname"]]=="Windows") {
ThisRunCluster <<- parallel::makePSOCKcluster(procs)
ThisRunCluster <- parallel::makePSOCKcluster(procs)
} else {
ThisRunCluster <<- parallel::makeForkCluster(procs)
ThisRunCluster <- parallel::makeForkCluster(procs)
}
doParallel::registerDoParallel(ThisRunCluster)
......@@ -791,7 +796,7 @@ ReactTranspBalanceKin <- function(setup, init, maxtime, step=c("time","iter","fi
on.exit()
if (procs > 1) {
stopCluster(ThisRunCluster)
parallel::stopCluster(ThisRunCluster)
msg("Parallelization cluster stopped")
}
......
## Functions for dealing with surrogate simulations
### Marco De Lucia, delucia@gfz-potsdam.de, 2009-2021
### Time-stamp: "Last modified 2021-04-12 11:45:32 delucia"
### Time-stamp: "Last modified 2021-04-28 15:32:05 delucia"
##' Computes the average of absolute values of a vector
##' @title Average of absolute values
......@@ -90,13 +90,14 @@ ExtractSpecies <- function(flatlist, species) {
return(tmp)
}
##' @title Extract all phases from a flatted Rphree list
##' @title Extract all equilibrium phases from a flattened output list
##' @param flatlist the list as input to search in
##' @param totals vector containing the names of the phases to search
##' for
##' @return matix with one pphases per column
##' @param pphases character vector containing the names of the Pure
##' Phases whose values are to be extracted
##' @param species vector containing the names of the species to
##' search for
##' @return a matrix containing as many columns as specified pphases
##' @author MDL
##' @export
ExtractPphases <- function(flatlist, pphases) {
tmp <- matrix(NA, len <- length(flatlist), speclen <- length(pphases))
colnames(tmp) <- pphases
......
### Utility functions for RedModRphree
### Marco De Lucia, delucia@gfz-potsdam.de, 2009-2018
### Time-stamp: "Last modified 2021-04-12 12:58:36 delucia"
### Marco De Lucia, delucia@gfz-potsdam.de, 2009-2021
### Time-stamp: "Last modified 2021-04-28 14:50:36 delucia"
##' Replicates an input buffer containing only one SOLUTION, taking
##' care of SOLUTION/KINETICS/PURE identifiers. Eventually insert a
##' block (e.g: PUNCH) under the first SOLUTION.
##' block (e.g: PUNCH) just once under the first SOLUTION.
##'
##' Analogous to standard \code{rep} function.
##' @title Replicate a SOLUTION
##' @param sol The initial phreeqc buffer that needs to be replicated.
##' @param n Number of replicates to generate.
##' @param sol The initial phreeqc buffer that needs to be replicated
##' @param n Number of replicates to generate
##' @param first A new block which needs to be inserted only in the
##' first solution (typically, PUNCH and alike).
##' @return A buffer upon which Rphree can be called.
##' first solution (typically, PUNCH and alike)
##' @return A buffer upon which RunPQC can be called
##' @author MDL
##' @export
RepSol <- function(sol, n, first=NULL)
......@@ -62,8 +62,6 @@ RepSol <- function(sol, n, first=NULL)
##' Function that adds a new property (species, pure phase, ...) to an
##' input buffer.
##'
##' .. content for DETAILS ..
##' @title Add a new property (species, pure phase, ...) to an input
##' buffer
##' @param input The input buffer.
......@@ -72,14 +70,13 @@ RepSol <- function(sol, n, first=NULL)
##' @param values The value(s) of the property.
##' @param cat The category of the property. Must be one of
##' \code{c("tot","pphases","kin")}
##' @param kinpar Kinetics parameters for the KINETICS case.
##' @param kinpar Kinetics parameters for the KINETICS case
##' @param first A block to be added in the first SOLUTION, as in
##' \code{RepSol} and \code{Distribute}.
##' @return The new input buffer upon which Rphree can be called.
##' \code{RepSol} and \code{Distribute}
##' @return The new input buffer upon which RunPQC can be called
##' @author MDL
##' @export
AddProp <- function(input, name, values, cat, kinpar=NULL, first=NULL)
### Add a property (species, pure phase, ...) to an input buffer
{
cat <- match.arg(cat,c("tot","pphases","kin"))
......@@ -150,16 +147,18 @@ AddProp <- function(input, name, values, cat, kinpar=NULL, first=NULL)
##' replicated length(values) times by RepSol. For KINETICS use
##' \code{DistributeKin}.
##'
##' @title Distribute properties in an input buffer.
##' @param input The initial input buffer.
##' @param prop The property whose values need to be distributed.
##' @param values The numerical value(s) to distribute across the SOLUTIONS.
##' @title Distribute properties in an input buffer
##' @param input The initial input buffer
##' @param prop The property whose values need to be distributed
##' @param values The numerical value(s) to distribute across the
##' SOLUTIONS
##' @param newname Optional name of a property which is not initially
##' present in the input buffer.
##' present in the input buffer
##' @param first The \code{first} block which will be passed to
##' \code{\link{RepSol}} if needed
##' @param wholeline logical. if TRUE, comments after the properties (i.e. "as HCO3") get also distributed.
##' @return A new input buffer upon which Rphree can be run.
##' @param wholeline logical. if TRUE, comments after the properties
##' (i.e. "as HCO3") get also distributed.
##' @return A new input buffer upon which RunPQC can be run
##' @author MDL
##' @export
Distribute <- function(input, prop, values, newname=NULL, first=NULL, wholeline=TRUE)
......@@ -203,7 +202,6 @@ Distribute <- function(input, prop, values, newname=NULL, first=NULL, wholeline=
##' Erases the SOLUTION number n (label, not position) from an input
##' buffer containing many.
##'
##' @title Suppress a simulation from an input buffer
##' @param biginp The input buffer
##' @param n The number of the simulation to erase
......@@ -218,22 +216,22 @@ SuppressSim <- function(biginp, n=1L)
}
##' This functions extracts informations from calculated Rphree
##' formatted solutions.
##'
##' @title Extract specific values from an Rphree output
##' @param lin The list containg the Rphree solution(s)
##' This functions extracts informations extracted from standard
##' PHREEQC output files
##' @title Extract specific values from a phreeqc output
##' @param lin The list containg the parsed phreeqc solution(s)
##' @param cat A string indicating the category (or output block) to
##' search in, must be one of: "tot, desc, pphases, master, species,
##' kin, SI"
##' search in, must be one of:
##' "tot, desc, pphases, master, species, kin, SI"
##' @param prop The name of the inquired property (element, species,
##' mineral phase,\dots) whose value(s)
##' @param force Logical. If TRUE (default if left unspecified), a valid numeric value (0) is returned even if the property is not found
##' value is returned if the inquired property is not found in the
##' solution
##' @param force Logical. If TRUE (default if left unspecified), a
##' valid numeric value (0) is returned even if the property is
##' not found value is returned if the inquired property is not
##' found in the solution
##' @param flex Logical. If TRUE, expects no "ListInfo" in the
##' formatted solution list and performs heuristics to circumvent this
##' absence
##' formatted solution list and performs heuristics to circumvent
##' this absence
##' @return A numeric vector containing the inquired properties
##' @author MDL
##' @examples
......@@ -290,7 +288,6 @@ RPinfo <- function(lin, cat=c("tot","desc","pphases","master","species","kin","S
##' Workhorse function for extraction of results from a solution,
##' primarily intended to be used by \code{\link{RPinfo}}, where it is
##' called inside a \code{sapply} statement.
##'
##' @title Workhorse function for extraction of informations from a
##' solution
##' @param sol The solution outputted by Rphree
......@@ -311,7 +308,8 @@ RPhreeExt <- function(sol, cat, prop)
##' Workhorse function for extraction of results from a solution,
##' specifically equilibrium phases.
##'
##' @title Workhorse function for extraction of
##' @title Workhorse function for extraction of equilibrium phases
##' from a solution list
##' @param lin The solution outputted by Rphree
##' @param which String containing the name of the specific pphase to
##' look for. If omitted, all pphases are returned.
......@@ -336,10 +334,10 @@ RGetPhases <- function(lin, which=NULL, delta=TRUE)
##' Workhorse function for extraction of results from a solution,
##' specifically equilibrium phases. Variant.
##' specifically equilibrium phases.
##'
##' @title extract the phases from a Rphree solution
##' @param lin The solution outputted by Rphree
##' @title extract the phases from a PHREEQC output
##' @param lin The solution outputted by phree
##' @return A data.frame containing the results of equilibrium phases
##' @author MDL
##' @export
......
### RedModRphree, functions to perform basic visualization
### Licence: LGPL version 2.1
### Time-stamp: "Last modified 2018-05-06 19:30:10 delucia"
### Time-stamp: "Last modified 2021-04-28 15:16:50 delucia"
##' @title Display the profiles of some variables along a 1D reactive
##' transport simulation
......@@ -79,7 +79,7 @@ PlotModsInSample <- function(mod, res, des, sample=seq(1,nrow(res)), column=TRUE
else
par(mfrow=c(2,nr))
for (i in seq_along(mod)) {
plot(result[,i], predict(mod[[i]], design),"p",pch=3, main=names(mod)[i],
plot(result[,i], stats::predict(mod[[i]], design),"p",pch=3, main=names(mod)[i],
xlab="Full physics", ylab="Surrogate", ...)
abline(0,1,lty="dashed",col="grey")
}
......
## Time-stamp: "Last modified 2021-04-12 11:40:11 delucia"
## Time-stamp: "Last modified 2021-04-28 15:14:00 delucia"
##' @title Extracts input/output tables from a list of Reactive
##' Transport Simulations
##' @param simlist a list containing the simulations
......
......@@ -18,21 +18,18 @@ mineral,...)}
\item{cat}{The category of the property. Must be one of
\code{c("tot","pphases","kin")}}
\item{kinpar}{Kinetics parameters for the KINETICS case.}
\item{kinpar}{Kinetics parameters for the KINETICS case}
\item{first}{A block to be added in the first SOLUTION, as in
\code{RepSol} and \code{Distribute}.}
\code{RepSol} and \code{Distribute}}
}
\value{
The new input buffer upon which Rphree can be called.
The new input buffer upon which RunPQC can be called
}
\description{
Function that adds a new property (species, pure phase, ...) to an
input buffer.
}
\details{
.. content for DETAILS ..
}
\author{
MDL
}
......@@ -2,27 +2,29 @@
% Please edit documentation in R/Rphree_Utils.R
\name{Distribute}
\alias{Distribute}
\title{Distribute properties in an input buffer.}
\title{Distribute properties in an input buffer}
\usage{
Distribute(input, prop, values, newname = NULL, first = NULL, wholeline = TRUE)
}
\arguments{
\item{input}{The initial input buffer.}
\item{input}{The initial input buffer}
\item{prop}{The property whose values need to be distributed.}
\item{prop}{The property whose values need to be distributed}
\item{values}{The numerical value(s) to distribute across the SOLUTIONS.}
\item{values}{The numerical value(s) to distribute across the
SOLUTIONS}
\item{newname}{Optional name of a property which is not initially
present in the input buffer.}
present in the input buffer}
\item{first}{The \code{first} block which will be passed to
\code{\link{RepSol}} if needed}
\item{wholeline}{logical. if TRUE, comments after the properties (i.e. "as HCO3") get also distributed.}
\item{wholeline}{logical. if TRUE, comments after the properties
(i.e. "as HCO3") get also distributed.}
}
\value{
A new input buffer upon which Rphree can be run.
A new input buffer upon which RunPQC can be run
}
\description{
Function to distribute different values of one property
......
......@@ -14,7 +14,8 @@ DistributeKin(input, prop = NULL, values, ident = "-m0")
\item{values}{The numerical value(s) to distribute across the
SOLUTIONS/KINETICS blocks.}
\item{ident}{The identifier for the line where the actual values will be pasted, defaults to "-m"}
\item{ident}{The identifier for the line where the actual values
will be pasted, defaults to "-m"}
}
\value{
A new input buffer
......
......@@ -2,21 +2,24 @@
% Please edit documentation in R/Rphree_SurrogateUtils.R
\name{ExtractPphases}
\alias{ExtractPphases}
\title{Extract all phases from a flatted Rphree list}
\title{Extract all equilibrium phases from a flattened output list}
\usage{
ExtractPphases(flatlist, pphases)
}
\arguments{
\item{flatlist}{the list as input to search in}
\item{totals}{vector containing the names of the phases to search
for}
\item{pphases}{character vector containing the names of the Pure
Phases whose values are to be extracted}
\item{species}{vector containing the names of the species to
search for}
}
\value{
matix with one pphases per column
a matrix containing as many columns as specified pphases
}
\description{
Extract all phases from a flatted Rphree list
Extract all equilibrium phases from a flattened output list
}
\author{
MDL
......
......@@ -2,7 +2,8 @@
% Please edit documentation in R/Rphree_Utils.R
\name{RGetPhases}
\alias{RGetPhases}
\title{Workhorse function for extraction of}
\title{Workhorse function for extraction of equilibrium phases
from a solution list}
\usage{
RGetPhases(lin, which = NULL, delta = TRUE)
}
......
......@@ -3,7 +3,7 @@
\name{RPhreeExt}
\alias{RPhreeExt}
\title{Workhorse function for extraction of informations from a
solution}
solution}
\usage{
RPhreeExt(sol, cat, prop)
}
......
......@@ -2,7 +2,7 @@
% Please edit documentation in R/Rphree_Utils.R
\name{RPinfo}
\alias{RPinfo}
\title{Extract specific values from an Rphree output}
\title{Extract specific values from a phreeqc output}
\usage{
RPinfo(
lin,
......@@ -13,29 +13,30 @@ RPinfo(
)
}
\arguments{
\item{lin}{The list containg the Rphree solution(s)}
\item{lin}{The list containg the parsed phreeqc solution(s)}
\item{cat}{A string indicating the category (or output block) to
search in, must be one of: "tot, desc, pphases, master, species,
kin, SI"}
search in, must be one of:
"tot, desc, pphases, master, species, kin, SI"}
\item{prop}{The name of the inquired property (element, species,
mineral phase,\dots) whose value(s)}
\item{force}{Logical. If TRUE (default if left unspecified), a valid numeric value (0) is returned even if the property is not found
value is returned if the inquired property is not found in the
solution}
\item{force}{Logical. If TRUE (default if left unspecified), a
valid numeric value (0) is returned even if the property is
not found value is returned if the inquired property is not
found in the solution}
\item{flex}{Logical. If TRUE, expects no "ListInfo" in the
formatted solution list and performs heuristics to circumvent this
absence}
formatted solution list and performs heuristics to circumvent
this absence}
}
\value{
A numeric vector containing the inquired properties
}
\description{
This functions extracts informations from calculated Rphree
formatted solutions.
This functions extracts informations extracted from standard
PHREEQC output files
}
\examples{
\dontrun{
......
......@@ -2,19 +2,19 @@
% Please edit documentation in R/Rphree_Utils.R
\name{RReadPhases}
\alias{RReadPhases}
\title{extract the phases from a Rphree solution}
\title{extract the phases from a PHREEQC output}
\usage{
RReadPhases(lin)
}
\arguments{
\item{lin}{The solution outputted by Rphree}
\item{lin}{The solution outputted by phree}
}
\value{
A data.frame containing the results of equilibrium phases
}
\description{
Workhorse function for extraction of results from a solution,
specifically equilibrium phases. Variant.
specifically equilibrium phases.
}
\author{
MDL
......
......@@ -47,25 +47,30 @@ occurences of a geochemical problem?}
\item{ebreak}{logical, defaults to FALSE. If TRUE, an early break
is invoked}
\item{writeout}{logical, defaults to FALSE.}
\item{writeout}{logical, defaults to FALSE. Should we write the
phreeqc output on disk?}
\item{surrogate}{logical, defaults to FALSE. Should we use
surrogates instead of phreeqc?}
\item{surrogate.FUN}{The function which calls the surrogate}
\item{model}{The list of surrogate models, one element per
variable}
\item{model}{a list containing all surrogate models, one element
per variable}
\item{baleq}{data structure containing the balance equations}
\item{tol}{absolute tolerance on the mass balance}
\item{tol}{absolute tolerance on the mass balance. If this is
trespassed, phreeqc is called instead}
\item{call_pqc}{logical, defaults to TRUE: if TRUE, calls phreeqc
on the surrogate simulations which trespass the tolerance}
}
\value{
a list containing lots of stuff
a list containing lots of stuff. Each element of the list
represent an iteration and has two elements: $T
(concentrations after the transport) and $C, concentrations
after the chemistry
}
\description{
TODO
......
......@@ -7,20 +7,20 @@
RepSol(sol, n, first = NULL)
}
\arguments{
\item{sol}{The initial phreeqc buffer that needs to be replicated.}
\item{sol}{The initial phreeqc buffer that needs to be replicated}
\item{n}{Number of replicates to generate.}
\item{n}{Number of replicates to generate}
\item{first}{A new block which needs to be inserted only in the
first solution (typically, PUNCH and alike).}
first solution (typically, PUNCH and alike)}
}
\value{
A buffer upon which Rphree can be called.
A buffer upon which RunPQC can be called
}
\description{
Replicates an input buffer containing only one SOLUTION, taking
care of SOLUTION/KINETICS/PURE identifiers. Eventually insert a
block (e.g: PUNCH) under the first SOLUTION.
block (e.g: PUNCH) just once under the first SOLUTION.
}
\details{
Analogous to standard \code{rep} function.
......
......@@ -22,11 +22,10 @@ a data.frame containing the SELECTED_OUTPUT, ordered if
This function runs the generated input buffer (or a list thereof)
through \code{phreeqc}, which has been already loaded as
dependency. Also the database must be previously and explicitely
loaded by the user using, e.g.,
\code{db <- RPhreeFile('/path/to/database.dat', is.db=TRUE)}
followed by
\code{phreeqc::phrLoadDatabaseString(db)}
or using one of the databases included in \code{phreeqc}, e.g.,
loaded by the user using, e.g., \code{db <-
RPhreeFile('/path/to/database.dat', is.db=TRUE)} followed by
\code{phreeqc::phrLoadDatabaseString(db)} or using one of the
databases included in \code{phreeqc}, e.g.,
\code{phreeqc::phrLoadDatabaseString(phreeqc.dat)}.
}
\details{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment