Running individual simulation and retrieving the results
Once the simulation is loaded (see Loading a
simulation and accessing entities), it can be run using
runSimulations()
to produce an object of the class
SimulationResults
. Keep in mind that
runSimulations()
produces a list of
SimulationResults
objects.
library(ospsuite)
#> Loading required package: rSharp
# Load the simulation
simFilePath <- system.file("extdata", "Aciclovir.pkml", package = "ospsuite")
sim <- loadSimulation(simFilePath)
simulationResults <- runSimulations(simulations = sim)
# Extract `SimulationResults` by simulation id
simulationResults <- simulationResults[[sim$id]]
print(simulationResults)
#> SimulationResults:
#> Number of individuals: 1
The advantage of storing the results in a object is the option to keep different results of the same simulation produced with different settings (e.g., model parameters).
Simulated time-value pairs for a specific output from the
SimulationResults
-object can be accessed with the method
getOutputValues
. The user can provide either the path(s) of
the output (which can be a molecule, a parameter, or an observer), or
the object(s) of the type Molecule
, Parameter
,
or Quantity
(for observers) with the argument
quantitiesOrPaths
. If no output is specified, all outputs
available in the simulation results are returned.
The paths of all available outputs can be accessed via
simulationResults$allQuantityPaths
#> [1] "Organism|PeripheralVenousBlood|Aciclovir|Plasma (Peripheral Venous Blood)"
getOutputValues
returns a list with two entries:
data
and metadata
:
-
data
is a dataframe with two predefined columns (IndividualId and Time) as well as one column for each requested output-
IndividualId
(not relevant for an individual simulation) -
Time
a vector with simulated time values (in minutes, equal for all outputs) - a vector with simulated entries for each output requested.
-
metaData
is a list containing one entry for each requested output. Each entry contains information pertinent to the output such as its dimension or the unit.
# Get simulated results by path
resultsPath <- simulationResults$allQuantityPaths[[1]]
print(resultsPath)
#> [1] "Organism|PeripheralVenousBlood|Aciclovir|Plasma (Peripheral Venous Blood)"
resultsData <- getOutputValues(simulationResults, quantitiesOrPaths = resultsPath)
resultsTime <- resultsData$data$Time
resultsValues <- resultsData$data$`Organism|PeripheralVenousBlood|Aciclovir|Plasma (Peripheral Venous Blood)`
plot(resultsTime, resultsValues, type = "l")
The results can be stored in and imported from a *.csv file with the
methods exportResultsToCSV
and
importResultsFromCSV
.
# Load and run the simulation
simFilePath <- system.file("extdata", "Aciclovir.pkml", package = "ospsuite")
sim <- loadSimulation(simFilePath)
# `runSimulations` returns a list of `SimulationResults`. For single simulation,
# we directly extract the first element, as only one object is created.
simulationResults <- runSimulations(simulations = sim)[[1]]
# Export to csv
csvResultsPath <- system.file("extdata", "SimResults.csv", package = "ospsuite")
exportResultsToCSV(results = simulationResults, filePath = csvResultsPath)
# Load from csv
resultsLoaded <- importResultsFromCSV(filePaths = csvResultsPath, simulation = sim)
print(resultsLoaded)
#> SimulationResults:
#> Number of individuals: 1
Running multiple individual simulations and retrieving the results
In some cases, the user might want to run multiple simulations in
parallel. This can be achieved easily by simply passing a list of
simulations to the runSimulations()
function. However, only
individual simulations (i.e., the population
argument must
remain empty) are supported.
By default, the simulations will be executed in parallel by using up to all cores available on the machine minus 1. So if there are 8 cores and the user simulates 4 simulations, 4 cores will be used. On the other hand, if the user simulates 10 simulations with only 8 cores available, 7 will be used and then the first 3 available.
# Load and run multiple simulations concurrently.
simFilePath <- system.file("extdata", "Aciclovir.pkml", package = "ospsuite")
# We load 3 times the same simulation for convenience. But in real life scenarios,
# they should be different simulations
sim1 <- loadSimulation(simFilePath)
sim2 <- loadSimulation(simFilePath)
sim3 <- loadSimulation(simFilePath)
simulationResults <- runSimulations(simulations = list(sim1, sim2, sim3))
The results in this case will be a named list of
SimulationResults
-object , i.e. one for each simulation.
The names of the entries of the list are the ids of the simulation to
which the results correspond. This way, it is easy to retrieve the
correct results for the specific simulation
Adding new outputs
By default, only outputs that were selected in PK-Sim or MoBi prior
to the export of the simulation to pkml
are generated. The
user can add new outputs to the simulation with the method
addOutputs
. The outputs can be provided either as objects
of the type(s) Molecule
, Parameter
, or
Quantity
, or as path strings. The output list is a property
of the simulation
. After adding or removing outputs, the
corresponding simulation needs to be re-run in order to generate updated
results.
# Clear the list of generated outputs
clearOutputs(sim)
# Add new outputs as objects
molecule <- getMolecule("Organism|Kidney|Intracellular|Aciclovir", sim)
observer <- getQuantity("Organism|Lumen|Aciclovir|Fraction dissolved", sim)
addOutputs(c(molecule, observer), simulation = sim)
# Add new outputs as path strings
addOutputs(
c(
"Organism|Lumen|Stomach|Aciclovir",
"Organism|PeripheralVenousBlood|Aciclovir|Whole Blood (Peripheral Venous Blood)"
),
simulation = sim
)
# Run simulation
simulationResults <- runSimulations(simulations = sim)
# Retrieve all generated outputs (e.g. omitting the quantitiesOrPaths property
# will return all available values)
resultsData <- getOutputValues(simulationResults)
# Note that "Organism|PeripheralVenousBlood|Aciclovir|Plasma (Peripheral Venous Blood)"
# is not in the list of generated results any more
names(resultsData$data)
#> NULL
clearOutputs()
and addOutputs()
can be
combined with the function setOutputs()
.
Changing simulation intervals
The simulation interval (i.e., the simulation times at which results
are stored) are stored as the property $outputSchema
of a
Simulation
object.
print(sim$outputSchema)
#> OutputSchema:
#> Interval:
#> Name: Simulation interval high resolution
#> Start time: 0.00e+00 [min]
#> End time: 15.00 [min]
#> Resolution: 1.00 [pts/min]
#> Interval:
#> Name: Simulation Interval 1
#> Start time: 15.00 [min]
#> End time: 1440.00 [min]
#> Resolution: 0.33 [pts/min]
#> Interval:
#> Name: Simulation Interval 2
#> Start time: 120.00 [min]
#> End time: 1440.00 [min]
#> Resolution: 0.07 [pts/min]
To change the simulation interval, the user can use one of the
functions clearOutputIntervals()
,
addOutputInterval()
, and
setOutputInterval()
.
# Remove all output intervals - simulation not possible!
clearOutputIntervals(simulation = sim)
runSimulations(simulations = sim)
#> Error in do.call(".External", c(list("r_call_method", self$pointer, methodName), : Type: OSPSuite.Utility.Exceptions.OSPSuiteException
#> Message: Time points output schema is empty
#> Method: Void EvaluateCppCallResult(Boolean, System.String)
#> Stack trace:
#> at OSPSuite.SimModel.PInvokeHelper.EvaluateCppCallResult(Boolean success, String errorMessage)
#> at OSPSuite.SimModel.Simulation.evaluateCppCallResult(Boolean success, String errorMessage)
#> at OSPSuite.SimModel.Simulation.RunSimulation()
#> at OSPSuite.Core.Domain.Services.SimModelManager.simulate()
#> at OSPSuite.Core.Domain.Services.SimModelManager.doIfNotCanceled(Action actionToExecute)
#> at OSPSuite.Core.Domain.Services.SimModelManager.RunSimulation(IModelCoreSimulation simulation, SimulationRunOptions simulationRunOptions)
#> at OSPSuite.R.Services.SimulationRunner.run(IModelCoreSimulation simulation, SimulationRunOptions simulationRunOptions)
#> at OSPSuite.R.Services.SimulationRunner.Run(SimulationRunArgs simulationRunArgs)
#> at InvokeStub_SimulationRunner.Run(Object, Span`1)
#> at System.Reflection.M
# Add an interval
addOutputInterval(simulation = sim, startTime = 0, endTime = 20, resolution = 60, intervalName = "highRes")
print(sim$outputSchema)
#> OutputSchema:
#> Interval:
#> Name: highRes
#> Start time: 0.00e+00 [min]
#> End time: 20.00 [min]
#> Resolution: 60.00 [pts/min]
# Add a second interval
addOutputInterval(simulation = sim, startTime = 30, endTime = 2000, resolution = 4, intervalName = "lowRes")
print(sim$outputSchema)
#> OutputSchema:
#> Interval:
#> Name: highRes
#> Start time: 0.00e+00 [min]
#> End time: 20.00 [min]
#> Resolution: 60.00 [pts/min]
#> Interval:
#> Name: lowRes
#> Start time: 30.00 [min]
#> End time: 2000.00 [min]
#> Resolution: 4.00 [pts/min]
# Replace the existing interval(s) with a new one
setOutputInterval(simulation = sim, startTime = 0, endTime = 2000, resolution = 4)
print(sim$outputSchema)
#> OutputSchema:
#> Interval:
#> Name: Output interval
#> Start time: 0.00e+00 [min]
#> End time: 2000.00 [min]
#> Resolution: 4.00 [pts/min]