Skip to contents

RsNLME package logo

Introduction

A metamodel (file with a .mmdl extension) simplifies the integration of RsNLME with Pirana. It acts like a container for all the information needed to run a Pharmacometric Modeling Language (PML) model. PML is the language that powers both Phoenix NLME and RsNLME. Think of a metamodel as similar to a NONMEM control file.

This guide explains metamodels and demonstrates how they can be used for conveniently storing, fitting, and exploring PML models. To understand this, we need to first look at how PML models are run in Phoenix NLME and RsNLME.

Assumptions:

  • Both your input data and PML model files are in your current working directory.
  • The directory containing the NLME Engine is specified in the INSTALLDIR environment variable. You can verify this with the following R commands:
  # Load the RsNLME package
  library(Certara.RsNLME)
  # check if the env.variable is set correctly
  Sys.getenv("INSTALLDIR")

These assumptions will hold throughout this document.

PML Models in Phoenix NLME

If you’ve used Phoenix NLME before, you’ll recognize that PML models in Phoenix are saved as .mdl files. These files contain the model’s statements, equations, and assignments. But they don’t specify things like the dataset to use, how columns should be mapped to model variables, or what tables should be generated as output (see the example below, which follows the syntax described in the linked documentation).


    test(){
        cfMicro(A1, Cl / V)
        dosepoint(A1)
        C = A1 / V
        error(CEps = 0.1)
        observe(CObs = C * (1 + CEps))
        stparm(V = tvV * exp(nV))
        stparm(Cl = tvCl * exp(nCl))
        fixef(tvV = c(, 5, ))
        fixef(tvCl = c(, 1, ))
        ranef(diag(nV, nCl) = c(1, 1))
    }

Phoenix stores all this information (model, data, mappings) within the project itself. The NLME executables only access this information during the model run. However, if you want to run PML models from the command line, you need to provide separate files for data, column definitions (linking data columns to model variables), and any additional input options (like ADDL and SS) along with the engine arguments:

%INSTALLDIR%\runNLME.bat 5 100 OneCpt_IVInfusion.mdl columnMapping.txt OneCpt_IVInfusionData.csv

PML Models in RsNLME

Certara.RsNLME also allows you to run PML models from the command line. You’ll need to provide the input data and PML model files to create a model object. If column mappings aren’t automatically detected, you’ll need to specify them. You can also provide additional input options (like ADDL, SS, Reset, MDV, and infusion). Here’s an example:

PMLModelCodeOutput  <-" 
    test(){
        cfMicro(A1, Cl / V)
        dosepoint(A1)
        C = A1 / V
        error(CEps = 0.1)
        observe(CObs = C * (1 + CEps))
        stparm(V = tvV * exp(nV))
        stparm(Cl = tvCl * exp(nCl))
        fixef(tvV = c(, 5, ))
        fixef(tvCl = c(, 1, ))
        ranef(diag(nV, nCl) = c(1, 1))
    } "
  PMLModelCodeFile <- file.path(tempdir(TRUE), "OneCpt_IVInfusion.mdl")
  writeLines(PMLModelCodeOutput, PMLModelCodeFile)
  # for the input data description please refer to ?OneCpt_IVInfusionData
  # Create the model object
  model <- textualmodel(modelName = "OneCpt_IVInfusion",
                        mdl = PMLModelCodeFile,
                        data = OneCpt_IVInfusionData)

  # Manually map the un-mapped model variables
  model <- colMapping(model, mappings = c(id = "Subject", A1 = "Dose"))
  
  # Add infusion information for dosing compartment A1
  model <- addInfusion(model, "A1", isDuration = TRUE, colName = "Duration")

As you can see, the model object (an instance of the NlmePmlModel class) holds information about the model code, column mappings, and data — all in a binary format. Metamodels simplify this by combining these elements into a single, human-readable text file.

Metamodel Overview

Metamodels are structured with different blocks, each starting with a double number sign (##) followed by the block name. Comments within metamodels use the same syntax as PML models: # or // for single-line comments and /* ... */ for multi-line comments.

Metamodel Blocks:

  • Author:
    • Specifies the metamodel’s author (e.g., ##Author: User).
    • This block is optional and not used during model estimation.
  • Description:
    • Used by Pirana to display a description of the metamodel’s purpose (e.g., ##Description: PK model for Drug X).
    • This block is optional and not used during model estimation.
  • Based on:
    • Indicates the name of a reference metamodel, used by Pirana for building reference trees (e.g., ##Based on: BasePKModel.mmdl).
    • This block is optional and not used during model estimation.
  • DATA:
    • Required: Specifies the path to the input data file. Both absolute and relative paths are allowed.
    • The data.table::fread() function (with default settings) is used to load the data (e.g., ##DATA ./data.csv).
  • MAP:
    • Defines mappings between model variables and data columns using the = sign (e.g., variableName=columnName).
    • If a mapping isn’t provided for a model variable, it’s assumed that the variable name and column name are the same (e.g., CObs is equivalent to CObs=CObs).
    • Special Variables: This block can also map special variables not explicitly present in the model:
      • id: Required for population models. Maps up to five data columns (separated by commas) to identify individual subject profiles. If not mapped, the model is treated as individual.
      • time: Required for time-based models. Maps the time variable.
      • dosingCompartmentName_Rate: Indicates that the specified dosing compartment involves infusion, with rate information provided in the mapped column.
      • dosingCompartmentName_Duration: Indicates that the specified dosing compartment involves infusion, with duration information provided in the mapped column.
      • SS: Indicates that the mapped column contains a steady-state flag. Translated to the sscol statement in the column definition file.
      • SSOffSet: Indicates that the mapped column contains the SS offset. Only applicable if SS is also mapped. Translated to the ssoffcol statement.
      • ADDL: Indicates that the mapped column contains an additional identical dose flag. Translated to the addlcol statement.
      • II: Represents the inter-dose interval. Must be mapped if either SS or ADDL is used. Translated to the iicol statement.
      • MDV: Indicates that the mapped column contains missing data values (MDV). Rows with non-zero numeric values in this column will be ignored.
      • Reset: Indicates that the mapped column contains a reset flag. If the value in the reset column is not zero, time is allowed to be reset on that row.
    • Categorical Covariates: For categorical covariates (defined using fcovariate or covariate with an empty parenthesis), you can define label names for each category value if the mapped data column is of character type. Label names are specified in round brackets after the column name (e.g., Sex = Gender(Male = 0, Female = 1)).
  • DOSING CYCLE:
    • Provides an alternative way to define ADDL or SS dosing cycles for specific dosing compartments. The syntax is:
      • For SS: SS = [COL] Dosepoint = [CMT] Amount = [NUM/COL] Delta = [NUM/COL] Duration = [NUM/COL] Rate = [NUM/COL]
      • For ADDL: ADDL = [COL] Delta = [NUM/COL] Dosepoint = [CMT] Amount = [NUM/COL] Duration = [NUM/COL] Rate = [NUM/COL]
    • Where:
      • [COL] is the column name containing the ADDL/SS flag.
      • [CMT] is the dosing compartment name from the model.
      • [NUM/COL] is either a column name or a numeric value.
      • Delta represents the inter-dose interval.
  • COLDEF:
    • Defines column definitions using the syntax described here.
    • Useful when column definitions can’t be defined through ##MAP or ##DOSING CYCLE.
    • You can use both ##MAP and ##COLDEF; definitions from both blocks will be combined.
    • Example (defining all column definitions):
        ##COLDEF 
        id("id")
        time("time")
        dose(A1<-"dose")
        covr(sex<-"sex"("male" = 0, "female" = 1))
        covr(wt<-"wt")
        obs(CObs<-"conc") 
  • MODEL:
    • Required: Contains the PML model code. Refer to the “Modeling Syntax” documentation for details.
  • ESTARGS:
    • Specifies engine arguments using the syntax of the engineParams() function in the Certara.RsNLME package. Arguments are separated by commas or spaces.
    • If not provided, default values are used.
    • Example:
        ##ESTARGS
        method = "QRPEM", 
        iSample = 1200,
        maxStepsODE = 50000000, 
        mapAssist = 1,
        ODE = "AutoDetect",
        numIterations = 0
    • You can define multiple ESTARGS blocks; they will be executed sequentially, with each run using the final estimates from the previous run.
  • SIMARGS:
    • Specifies arguments for model simulation:
      • numReplicates: Number of simulation replicates (default: 100).
      • seed: Random number generator seed (default: 1234).
      • sort, ODE, rtolODE, atolODE, maxStepsODE: See the engineParams() documentation.
    • Multiple ESTARGS and SIMARGS blocks are supported and applied sequentially (all ESTARGS runs first, followed by all SIMARGS runs).
  • TABLES:
    • Defines additional output tables (note: a posthoc.csv table with structural parameters and covariates at each data row is created by default).
    • Use the table statement syntax documented here.
    • Example:
        ##TABLES
        table(file="table01.csv", time(0,10,seq(2,8,0.1)), 
              dose(A1), covr(BW), obs(Conc), BW, C, cObs, V, Ke) 
    • Tables can also be defined in the ##COLDEF block. If defined in both, all tables will be included in the column definition file.

Metamodel Example

Let’s create a simple metamodel called OneCpt_IVInfusion.mmdl.

## Description: A one-compartment model with IV infusion

# The model is fitted using the default FOCE-ELS engine.
# Note: the default values for the relevant NLME engine arguments are chosen based on the model, type ?engineParams for details.

## DATA OneCpt_IVInfusion.csv
## MAP id = Subject time = Time A1 = Dose A1_Rate = Rate CObs

## MODEL
test(){
    cfMicro(A1, Cl / V)
    dosepoint(A1)
    C = A1 / V
    error(CEps = 0.1)
    observe(CObs = C * (1 + CEps))
    stparm(V = tvV * exp(nV))
    stparm(Cl = tvCl * exp(nCl))
    fixef(tvV = c(, 5, ))
    fixef(tvCl = c(, 1, ))
    ranef(diag(nV, nCl) = c(1, 1))
}

## ESTARGS
numIterations = 1 # one iteration only
stdErr = "None" # no standard error estimation requested

Explanation of Blocks:

  • Description: Provides a brief description of the model.
  • DATA: Specifies that the input data is in the OneCpt_IVInfusion.csv file (in the current directory).
  • MAP: Maps model variables to data columns:
    • id = Subject: Maps the individual identifier to the Subject column.
    • time = Time: Maps the time variable to the Time column.
    • A1 = Dose: Maps the amount administered to dosing compartment A1 to the Dose column.
    • A1_Rate = Rate: Maps the infusion rate for dosing compartment A1 to the Rate column (if rate is zero or missing, a bolus dose is assumed).
    • CObs: Maps the observed concentration to the CObs column (this is shorthand for CObs = CObs).
  • MODEL: Defines a one-compartment population model with clearance parameterization.
  • ESTARGS: Sets specific engine arguments:
    • numIterations = 1: Limits the optimization to a single iteration.
    • stdErr = "None": Disables standard error calculation.

Running a Metamodel

You can run a metamodel using the run_metamodel() function. Here’s how to run the example metamodel locally without parallelization (if you don’t specify a host and MPI is available, it will automatically parallelize over 4 threads; otherwise, it will run on a single core).

Note: We’ll use the directoryToRun argument to create a new subfolder named OneCpt_IVInfusion in your working directory, where the model output files will be stored.

  host <- hostParams(parallelMethod = "None",
                     hostName = "local",
                     numCores = 1)
  
  OneCpt_IVInfusionFile <-
    system.file("vignettesdata/OneCpt_IVInfusion.mmdl",
                package = "Certara.RsNLME",
                mustWork = TRUE)
  
  OneCpt_IVInfusionResults <-
    run_metamodel(mmdlfile = OneCpt_IVInfusionFile,
                  directoryToRun = "OneCpt_IVInfusion",
                  host = host)
  print(OneCpt_IVInfusionResults$Overall)
#>    Scenario RetCode    LogLik     -2LL      AIC      BIC nParm nObs nSub
#> 1: WorkFlow       4 -1085.769 2171.538 2181.538 2204.294     5  700  100
#>    EpsShrinkage Condition
#> 1:      0.12159        NA

Loading a Metamodel for Other Run Modes

If you want to perform a different type of run (e.g., bootstrap), you need to load the metamodel into R using the create_model_from_metamodel() function. This function returns a list containing the model object and engine parameters (if specified in the metamodel). You can then pass these to the appropriate model execution function.

Example (Bootstrap Run):

  ModelParamsList <- 
    create_model_from_metamodel(mmdlfile = OneCpt_IVInfusionFile)
  bootParams <- BootstrapParams(numReplicates = 5,
                                randomNumSeed = 1234)
  
  bootResults <-
    bootstrap(model = ModelParamsList$model,
              params = ModelParamsList$params,
              bootParams = bootParams)
  print(bootResults$BootTheta)
#>    Scenario Parameter      Mean      Stderr      CV%    Median      2.5%
#> 1:      (B)       tvV 4.7780358 0.010690711 0.223747 4.7720495 4.7682849
#> 2:      (B)      tvCl 0.8549129 0.010439461 1.221114 0.8508297 0.8473296
#> 3:      (B)      CEps 0.0941178 0.007253549 7.706883 0.0912145 0.0849065
#>        97.5%
#> 1: 4.7949070
#> 2: 0.8731682
#> 3: 0.1038233