nmrec is an R package for reading records from a NONMEM control stream, parsing and modifying records of interest, and writing the result.
read_ctl()
reads the NONMEM control stream from the
specified path. Or, if you’ve already read in the lines as a character
vector, you can use parse_ctl()
.
lines <- nmrec::nmrec_examples[["bayes1"]]
head(lines, 4)
#> [1] ";Model Desc: Two compartment Model, Using ADVAN3, TRANS4"
#> [2] ";Project Name: nm7examples"
#> [3] ""
#> [4] "$PROB RUN# Example 1 (from samp5l)"
ctl <- nmrec::parse_ctl(lines)
The result is an ?nmrec_ctl_records
list of two items,
“frontmatter” (any lines before the first record) and “records”.
ctl$frontmatter
#> [1] ";Model Desc: Two compartment Model, Using ADVAN3, TRANS4"
#> [2] ";Project Name: nm7examples"
#> [3] ""
length(ctl$records)
#> [1] 25
head(ctl$records, 3)
#> [[1]]
#> $PROB RUN# Example 1 (from samp5l)
#>
#>
#> [[2]]
#> $INPUT C SET ID JID TIME DV=CONC AMT=DOSE RATE EVID MDV CMT CLX
#> V1X QX V2X SDIX SDSX
#>
#>
#> [[3]]
#> $DATA example1.csv IGNORE=C
The list of records contains ?nmrec_record
objects.
purrr::map_chr(ctl$records, "name")
#> [1] "problem" "input" "data" "subroutines" "pk"
#> [6] "error" "theta" "omega" "sigma" "prior"
#> [11] "thetap" "thetapv" "omegap" "omegapd" "sigmap"
#> [16] "sigmapd" "estimation" "estimation" "estimation" "estimation"
#> [21] "estimation" "covariance" "table" "table" "table"
unique(purrr::map_chr(ctl$records, is))
#> [1] "nmrec_record_problem" "nmrec_record_input"
#> [3] "nmrec_record_data" "nmrec_record_raw"
#> [5] "nmrec_record_theta" "nmrec_record_omega"
#> [7] "nmrec_record_sigma" "nmrec_record_prior"
#> [9] "nmrec_record_estimation" "nmrec_record_table"
class(ctl$records[[17]])
#> [1] "nmrec_record_estimation" "nmrec_record"
#> [3] "R6"
If nmrec doesn’t support parsing within a given record type,
the record type will be nmrec_record_raw
. Otherwise, the
record type will be nmrec_record_{name}
, where
name
is the standardized record name in lower case.
You can use select_records()
to extract records of a
given type. This is a simple wrapper around purrr::keep()
that standardizes the input name (e.g., “est” to “estimation”).
ests <- nmrec::select_records(ctl, "est")
head(ests, 2)
#> [[1]]
#> $EST METHOD=ITS MAPITER=0 INTERACTION FILE=example1.ext NITER=500
#> PRINT=5 NOABORT SIGL=4 CTYPE=3 CITER=10
#> CALPHA=0.05 NOPRIOR=1 NSIG=2
#>
#>
#>
#> [[2]]
#> $EST METHOD=SAEM INTERACTION NBURN=3000 NITER=500 PRINT=100
#> SEED=1556678 ISAMPLE=2
The ?record
object is an R6 object.
est1 <- ests[[1]]
ls(est1)
#> [1] "clone" "format" "get_lines" "get_options" "initialize"
#> [6] "name" "parse" "values"
The primary method of interest is $parse()
, which parses
the record lines and populates the $values
field. This
field is a list of elements (things like spaces and new lines) and
?nmrec_option
objects. Once a record is parsed, the
$values
field fully controls how it will be rendered.
You can grab an option of interest from a record with
get_record_option()
.
est1_meth <- nmrec::get_record_option(est1, "meth")
ls(est1_meth)
#> [1] "clone" "format" "initialize" "name" "name_raw"
#> [6] "sep" "value"
?nmrec_option
objects, like ?nmrec_record
objects, are R6 objects. The fields
of interest depend on the option type. Here are the important fields for
the selected method option of the first estimation record:
est1_meth$name
#> [1] "method"
est1_meth$name_raw
#> [1] "METHOD"
est1_meth$value
#> [1] "ITS"
est1_meth$sep
#> [1] "="
A key feature of option and records objects is that, as R6 objects, they have reference
semantics (see vignette("Introduction", "R6")
).
For example, you could mutate NSIG=2
to NSIG=3
in the est1
record like so:
est1_nsig <- nmrec::get_record_option(est1, "sig")
est1_nsig$name
#> [1] "sigdigits"
est1_nsig$value
#> [1] "2"
est1_nsig$value <- 3
est1_nsig
#> NSIG=3
est1
#> $EST METHOD=ITS MAPITER=0 INTERACTION FILE=example1.ext NITER=500
#> PRINT=5 NOABORT SIGL=4 CTYPE=3 CITER=10
#> CALPHA=0.05 NOPRIOR=1 NSIG=3
If you print ctl
(the original
nmrec_ctl_records
object), you’ll notice that the
NSIG
change is reflected there.
Alternatively, you can also modify or append new options with
set_record_option()
, which covers the more common cases of
setting flag/value options.
est1
#> $EST METHOD=ITS MAPITER=0 INTERACTION FILE=example1.ext NITER=500
#> PRINT=5 NOABORT SIGL=4 CTYPE=3 CITER=10
#> CALPHA=0.05 NOPRIOR=1 NSIG=3
nmrec::set_record_option(est1, "CITER", value = 15) # Update CITER to 15
est1
#> $EST METHOD=ITS MAPITER=0 INTERACTION FILE=example1.ext NITER=500
#> PRINT=5 NOABORT SIGL=4 CTYPE=3 CITER=15
#> CALPHA=0.05 NOPRIOR=1 NSIG=3
nmrec::set_record_option(est1, "NOABORT", NULL) # Remove NOABORT
est1
#> $EST METHOD=ITS MAPITER=0 INTERACTION FILE=example1.ext NITER=500
#> PRINT=5 SIGL=4 CTYPE=3 CITER=15
#> CALPHA=0.05 NOPRIOR=1 NSIG=3
nmrec::set_record_option(est1, "MAXEVAL", 10) # Add option MAXEVAL=10
est1
#> $EST METHOD=ITS MAPITER=0 INTERACTION FILE=example1.ext NITER=500
#> PRINT=5 SIGL=4 CTYPE=3 CITER=15
#> CALPHA=0.05 NOPRIOR=1 NSIG=3 MAXEVAL=10
You can write the modified result to a file with
write_ctl()
.
write_ctl(ctl, "modified.ctl")