print(result)
summary(result)
plot(result)Getting started with rjsf
Introduction
rjsf provides an R interface to the Python jsf package for Jump-Switch-Flow simulation.
The main user-facing function is jsf_simulate(). It lets users:
Define a compartmental reaction model in R.
Pass the model to the Python
jsfbackend throughreticulate.Return the simulation output as either:
- a regular R
data.frame; or - a structured
JSFResultobject.
- a regular R
A JSFResult object supports standard methods such as:
Set up Python jsf
rjsf uses reticulate to communicate with Python. The Python jsf package must therefore already be installed in the Python environment used by reticulate.
Installation instructions for the Python dependencies are provided in the package README.
You can inspect the Python environment selected by reticulate with:
reticulate::py_config()Check Python jsf
Load rjsf and check whether the Python jsf module is available:
library(rjsf)
jsf_available()A correctly configured environment should return:
[1] TRUE
If it returns FALSE, check that:
- Python
jsfis installed; - it is installed in the environment currently used by
reticulate; and reticulate::py_config()reports the expected Python executable.
Lotka-Volterra predator-prey model
The Lotka-Volterra model describes interactions between two species:
prey;predator.
The model contains three reactions:
- Prey birth:
Prey -> 2 Prey - Predator death:
Predator -> NULL - Predation:
Prey + Predator -> 2 Predator
The state vector is:
x <- c(prey, predator)Define the rate function
The Python jsf backend expects the rate function to be a Python callable. We create one using reticulate::py_eval():
rates_lv <- reticulate::py_eval(
"lambda x, t: [2.0 * x[0], 1.5 * x[1], 0.05 * x[0] * x[1]]"
)The three rates correspond to:
2.0 * prey # prey birth
1.5 * predator # predator death
0.05 * prey * predator # predation
Define the stoichiometry
The reactant matrix describes what each reaction consumes:
reactant_lv <- matrix(
c(
1, 0,
0, 1,
1, 1
),
ncol = 2,
byrow = TRUE
)
reactant_lvThe product matrix describes what each reaction produces:
product_lv <- matrix(
c(
2, 0,
0, 0,
0, 2
),
ncol = 2,
byrow = TRUE
)
product_lvInternally, jsf_simulate() calculates the net stoichiometry matrix as:
nu = product - reactant
For this model, the net state changes are:
Prey -> 2 Prey [+1, 0]
Predator -> NULL [ 0, -1]
Prey + Predator -> 2 Predator [-1, +1]
Run the simulation
Run the model and request a JSFResult object:
result_lv <- jsf_simulate(
x0 = c(prey = 50, predator = 10),
rates = rates_lv,
reactant = reactant_lv,
product = product_lv,
do_disc = c(1, 1),
t_max = 10,
dt = 0.01,
switching_threshold = c(30, 30),
species_names = c("prey", "predator"),
return_type = "JSFResult"
)The important arguments are:
x0defines the initial number of prey and predators.do_disc = c(1, 1)allows both species to be treated discretely when required.switching_threshold = c(30, 30)defines the switching threshold for each species.return_type = "JSFResult"returns a structured result containing the simulation trajectory and associated metadata.
Inspect the result
Print the result:
result_lvCalculate a summary:
summary(result_lv)Plot the simulated trajectories:
plot(result_lv)SIR epidemic model
The SIR model describes the spread of an infectious disease through three compartments:
S: susceptible;I: infectious;R: recovered.
The model contains two reactions:
- Infection:
S + I -> 2 I - Recovery:
I -> R
The state vector is:
x <- c(S, I, R)Define the model parameters
Set the total population, infection rate, and recovery rate:
N <- 1000
beta <- 0.5
gamma <- 0.1Here:
N = total population
beta = infection rate
gamma = recovery rate
Define the rate function
Create a Python callable containing the infection and recovery rates:
rates_sir <- reticulate::py_eval(sprintf(
"lambda x, t: [%f * x[0] * x[1] / %f, %f * x[1]]",
beta,
N,
gamma
))The rates correspond to:
beta * S * I / N # infection
gamma * I # recovery
Define the stoichiometry
Define the reactant matrix:
reactant_sir <- matrix(
c(
1, 1, 0,
0, 1, 0
),
ncol = 3,
byrow = TRUE
)
reactant_sirDefine the product matrix:
product_sir <- matrix(
c(
0, 2, 0,
0, 0, 1
),
ncol = 3,
byrow = TRUE
)
product_sirThe net state changes are:
S + I -> 2 I [-1, +1, 0]
I -> R [ 0, -1, +1]
Run the simulation
result_sir <- jsf_simulate(
x0 = c(S = N - 10, I = 10, R = 0),
rates = rates_sir,
reactant = reactant_sir,
product = product_sir,
do_disc = c(0, 1, 0),
t_max = 60,
dt = 0.1,
switching_threshold = c(N, 10, N),
species_names = c("S", "I", "R"),
return_type = "JSFResult"
)In this example, do_disc = c(0, 1, 0) allows the infectious compartment to be treated discretely when required.
This is useful because stochastic effects can be particularly important when the number of infectious individuals is small.
Inspect the result
Print the result:
result_sirCalculate a summary:
summary(result_sir)Plot the simulated trajectories:
plot(result_sir)Return a data frame
The default output from jsf_simulate() is a regular R data.frame.
df_lv <- jsf_simulate(
x0 = c(prey = 50, predator = 10),
rates = rates_lv,
reactant = reactant_lv,
product = product_lv,
do_disc = c(1, 1),
t_max = 10,
dt = 0.01,
switching_threshold = c(30, 30),
species_names = c("prey", "predator"),
return_type = "data.frame"
)
head(df_lv)A data frame returned by jsf_simulate() contains:
- a
timecolumn; and - one column for each model species.
A data frame can later be converted into a JSFResult object:
result_from_df <- as_jsf_result(
df_lv,
method = "operator-splitting",
config = list(
model = "Lotka-Volterra",
dt = 0.01,
switching_threshold = c(30, 30)
)
)
result_from_dfSummary
The main rjsf workflow is:
Define the initial state
-> define the rate function
-> define the reactant and product matrices
-> call jsf_simulate()
-> return a data.frame or JSFResult
-> inspect the output with print(), summary(), and plot()
Use a data.frame when you primarily need the simulation values for further analysis.
Use a JSFResult when you want a structured object containing both the simulation trajectories and their associated metadata.