QSPC 2026

Workshop

Engineering-Style QSP Modeling with Heta

Evgeny Metelkin, Ivan Borisov
2026-04-07

QSPC 2026 | InSysBio Workshop

About the workshop

Practical tools and workflows for developing and maintaining QSP models

I. Heta language. heta-compiler

II. Modularity in QSP

III. HetaSimulator.jl

width:
QSPC 2026 | InSysBio Workshop

Heta project

https://hetalang.github.io

  • Documentation
  • Tutorials
  • GitHub repositories
  • Examples
width:
QSPC 2026 | InSysBio Workshop

🛠 What we will need today

  • Text editor (VSCode/Sublime/Notepad)
    + console
  • heta-compiler (command line tool)
QSPC 2026 | InSysBio Workshop

Challenges in QSP modeling

  • Editable models — models must remain readable and revisable
  • Structure — large models need decomposition into reusable parts

  • Tool interoperability — no single environment covers the full workflow

  • Versioned teamwork — projects need text-based collaboration and diffs

QSPC 2026 | InSysBio Workshop

Part I

Heta language. heta-compiler

ODE-based vs process-based modeling. Heta syntax. heta-compiler. Export formats. QSP project structure.

QSPC 2026 | InSysBio Workshop

Example 1a: ODE-based

[ODE]
A_amt ~ -r1;
B_amt ~ r1 - r2;
C_amt ~ r2;
[rules]
A = A_amt / c1;
B = B_amt / c1;
C = C_amt / c1;
r1 = k1 * A * c1;
r2 = k2 * B * c1;
[parameters]
c1 = 5.5;
k1 = 0.1;
k2 = 0.05;
[initials]
A = 2.0;
B = 0.0;
C = 0.0;
QSPC 2026 | InSysBio Workshop

Example 1b: ODE-based

[ODE]
A_amt ~ -r1 - r3;     ⟵
B_amt ~ r1 - r2;
C_amt ~ r2;
D_amt ~ r3;           ⟵
[rules]
A = A_amt / c1;
B = B_amt / c1;
C = C_amt / c1;
D = D_amt / c1;       ⟵
r1 = k1 * A * c1;
r2 = k2 * B * c1;
r3 = k3 * A * c1;     ⟵
[parameters]
c1 = 5.5;
k1 = 0.1;
k2 = 0.05;
k3 = 0.02;            ⟵
[initials]
A = 2.0;
B = 0.0;
C = 0.0;
D = 0.0;              ⟵
QSPC 2026 | InSysBio Workshop

Example 1a: process-based

c1 @Compartment .= 5.5;
A @Species { compartment: c1 } .= 2.0;
B @Species { compartment: c1 } .= 0.0;
C @Species { compartment: c1 } .= 0.0;

r1 @Reaction { actors: A => B } := k1 * A * c1;
r2 @Reaction { actors: B => C } := k2 * B * c1;

k1 @Const = 0.1;
k2 @Const = 0.05;
QSPC 2026 | InSysBio Workshop

Example 1b: process-based

c1 @Compartment .= 5.5;
A @Species { compartment: c1 } .= 2.0;
B @Species { compartment: c1 } .= 0.0;
C @Species { compartment: c1 } .= 0.0;

r1 @Reaction { actors: A => B } := k1 * A * c1;
r2 @Reaction { actors: B => C } := k2 * B * c1;

k1 @Const = 0.1;
k2 @Const = 0.05;

// new part
D @Species { compartment: c1 } .= 0.0;
r3 @Reaction { actors: A => D } := k3 * A * c1;
k3 @Const = 0.02;
QSPC 2026 | InSysBio Workshop

Why process-based is better?

  • Readability — more intuitive and closer to the way we think about biology
  • Flexibility — easier to extend and update, more freedom in syntax

  • Modularity — easier to decompose into reusable parts, less global changes

👉 The difference becomes important when the model grows.

QSPC 2026 | InSysBio Workshop

Process-based modeling

  • Abstract layer. Process-based languages do not replace ODE models.
    Instead, they provide a higher-level way to describe the system.
    The compiler automatically generates the system of differential equations.
  • Other process-based systems:
    • SBML
    • CellML
    • Antimony/Tellurium
    • SimBiology
    • CellDesigner, COPASI, etc.
QSPC 2026 | InSysBio Workshop

Syntax: Component Declaration

fig

QSPC 2026 | InSysBio Workshop

Multiple versions of the same code

Version 1:

r1 @Reaction { actors: A => B, units: umole/second } := k1 * A * c1;

Version 2:

r1 @Reaction { actors: A => B };  // insert
r1 { units: umole/second };       // update
r1 := k1 * A * c1;                // update
QSPC 2026 | InSysBio Workshop

Syntax: Base Classes

k1 @Const = 1.2e-1; fixed values
p1 @Record := x * y; values which vary over time
c1 @Compartment .= 5.5; physical volumes
A @Species {compartment: c1} .= 2.0; concentrations or amounts
r1 @Reaction {actors: A => B} := k1*A*c1; reactions and transport
QSPC 2026 | InSysBio Workshop

Syntax: Switcher Classes

To create events triggered at specific time points:

sw1 @TimeSwitcher { start: 10, period: 6 };

To create events triggered when an expression crosses zero from negative to positive:

sw2 @CSwitcher { trigger: 5 - x };
QSPC 2026 | InSysBio Workshop

Syntax: Assignments

= assign number, for Const, numbers only
:= rule assignment, calculate value at each time step, for Record, Process, Compartment, Species, Reaction
.= initial assignment, calculate value at time 0, for Record, Compartment, Species
[sw1]= assignment when switcher sw1 is active, for Record, Compartment, Species
QSPC 2026 | InSysBio Workshop

Example 1с: use events

c1 @Compartment .= 5.5;
A @Species { compartment: c1 } .= 2.0;
B @Species { compartment: c1 } .= 0.0;
C @Species { compartment: c1 } .= 0.0;

r1 @Reaction { actors: A => B } := k1 * A * c1;
r2 @Reaction { actors: B => C } := k2 * B * c1;

k1 @Const = 0.1;
k2 @Const = 0.05;

// new part
D @Species { compartment: c1 } .= 0.0;
r3 @Reaction { actors: A => D } := k3 * A * c1;
k3 @Const = 0.02;

// event
sw1 @TimeSwitcher { start: 12, period: 24 };
dose @Const = 1.5;
A [sw1]= A + dose / c1;
QSPC 2026 | InSysBio Workshop

heta-compiler

  1. Reads Heta model files
  2. Checks for errors
  3. Builds internal structure
  4. Exports to various formats
QSPC 2026 | InSysBio Workshop

💡 Task 1: Compile first model in heta-compiler

Compile the model we just created and generate simulation-ready outputs:
SBML, DBSolve, Dot.

Steps

  1. Create a directory task-1 and open the directory with VSCode.

  2. Create a file index.heta with the code from the previous example.

  3. Open the terminal Ctrl + ` and run the command
    heta build --export=SBML,DBSolve,Dot

  4. Check the generated files in the dist directory.
    (Graphviz plugin is required for Dot file)

QSPC 2026 | InSysBio Workshop

💡 Task 1: Compile the same model in heta-online

Steps

  1. Open https://heta-online.insysbio.com in your browser.
  2. Copy the code from the previous example and paste it into the editor.
  3. Click the "Compile" button and check the generated outputs.
QSPC 2026 | InSysBio Workshop

heta-compiler commands

heta -v check installation and version
heta build compile the model from index.heta
heta build --export=SBML,Simbio compile and export to SBML, SimBiology
heta build --source=model.heta compile from a specific file
heta build --units-check check for unit consistency

👉 See documentation for additional options and export formats

QSPC 2026 | InSysBio Workshop

Console VS Declaration file

console command - need to run every time

heta build --source=src/index.heta --export=SBML,DBSolve --units-check

platform.yml - one-time declaration + heta build every time

{
  options: {
    unitsCheck: true
  },
  importModule: {
    source: src/index.heta
  },
  export: [
    { format: SBML },
    { format: DBSolve }
  ]
}
QSPC 2026 | InSysBio Workshop

Modeling platform example

qsp-project/
  |-- src/            ⟵ model source
  |  |-- index.heta
  |  |-- module1.heta
  |  |-- module2.xml
  |-- dist/           ⟵ compiled outputs (if required)
  |-- data/           ⟵ experimental data
  |-- scenarios/      ⟵ conditions and simulation scenarios
  |-- docs/           ⟵ documentation, reports
  |-- results/        ⟵ outputs, logs
  |-- julia/          ⟵ Julia code
  |-- R/              ⟵ R code
  |-- platform.yml     ⟵ top-level metadata, configurations
  |-- README.txt      ⟵ human-readable overview

👉 Project structures may vary, but they should follow clear conventions so that all team members can easily understand and navigate them.

QSPC 2026 | InSysBio Workshop

Project structure tips (not for Heta only)

Good practices

✅ Store everything in a single directory - repository
✅ Keep the repository clean
✅ Separate model code, data, documentation, and scripts
✅ Use clear naming conventions for files and directories

Bad practices

❌ Store important files outside the repository
❌ Mix code, data, and models in the same file
❌ Mix source and generated files
❌ Store multiple versioned copies of the same files: model_2026-04-07.heta.

QSPC 2026 | InSysBio Workshop

How to create a new Heta project

heta init

is a command that creates a new project with a minimal structure and example files.

QSPC 2026 | InSysBio Workshop

platform.yml - project configuration

{
  builderVersion: ^0.10.0,
  id: template,
  notes: platform notes,
  version: v0.1.0,
  license: UNLICENSED,
  options: {},
  importModule: {
    type: heta,
    source: src/index.heta
  },
  export: [
    { format: JSON, omit: [], useUnitsExpr: false },
    #{ format: YAML, omit: [], useUnitsExpr: false },
    #{ format: DBSolve, powTransform: keep, version: 26 },
    #{ format: SLV, eventsOff: false, powTransform: keep, version: 26 },
    #{ format: SBML, version: L2V4 },
    #{ format: Simbio },
    #{ format: Mrgsolve },
    #{ format: Table, omitRows: 0, omit: [], bookType: csv, splitByClass: false },
    #{ format: XLSX, omitRows: 0, omit: [], splitByClass: true },
    #{ format: Julia },
    #{ format: Matlab },
    #{ format: Dot },
    #{ format: Summary }
  ]
}
QSPC 2026 | InSysBio Workshop

Part II

Modularity in QSP

Decomposition. Multiple model formats. Table format. SBML integration.

QSPC 2026 | InSysBio Workshop

The problem of monolithic models

  • Difficult to understand
  • Difficult to modify
  • Difficult to reuse

👉 Decomposing a large system into smaller, manageable parts is a common engineering practice.

QSPC 2026 | InSysBio Workshop

Including modules

Example project structure:

qsp-project/
  |-- src/
     |-- index.heta
     |-- qsp-units.heta
     |-- module1.heta
     |-- module2.heta

index.heta:

/* Main module */
include module1.heta;
include module2.heta;
include qsp-units.heta;
...

bottom:10%
QSPC 2026 | InSysBio Workshop

💡 Task 2: Split model

// cell-dynamics
blood @Compartment .= 5.3;
cell_count @Species { compartment: blood } .= 1;
v_prol @Reaction { actors: => cell_count };
v_prol := k_prol * cell_count;

k_prol @Const = 1e-3;

// intracellular-processes
cell_vol @Compartment := 1e-6 * cell_count;
m1 @Species { compartment: cell_vol } .= 0;
m2 @Species { compartment: cell_vol } .= 0;
m3 @Species { compartment: blood } .= 0;

vsyn_m1 @Reaction { actors: => m1 };
vsyn_m1 := ksyn * cell_vol;
v_m1_m2 @Reaction { actors: m1 => m2 };
v_m1_m2 := kcat_m1 * m1 / (Km1 + m1) * cell_vol;
vtr_m2 @Reaction { actors: m2 => m3 };
vtr_m2 := P * S * m2;

ksyn @Const = 1e-2;
kcat_m1 @Const = 1e-1;
Km1 @Const = 12;
P @Const = 1.2;
S @Const = 1e-8;
QSPC 2026 | InSysBio Workshop

💡 Task 2: Split model

Split the model into modules and verify that it still works

Steps

  1. Create a directory task-2 and open the directory with VSCode.
  2. Create project structure with heta init.
  3. Replace the content of src/index.heta with the code from the previous slide.
  4. Review platform.yml uncomment the desired export formats: SBML, Dot.
  5. Build the model with heta build.
  6. Split the code into three files: cell-dynamics.heta, intracellular-processes.heta, index.heta.
  7. Build to check that everything works after the split.
QSPC 2026 | InSysBio Workshop

How to decompose to modules?

  • Ad-hoc split: old-part.heta | new-part.heta | newest-part.heta | third-party.heta

  • By component types: species.heta | reactions.heta | constants.heta

  • By biological subsystems: pk.heta | tumor.heta | immune.heta | drug-action.heta

👉 There is no single correct structure. However, in practice, organizing modules by subsystems, usually works best.

QSPC 2026 | InSysBio Workshop

🎬 Demo 1: FAAH inhibitor

Modular decomposition

https://doi.org/10.1038/psp.2013.72
https://github.com/insysbio/faah-inhibitor


alt text

QSPC 2026 | InSysBio Workshop

Tables as modules (CSV / Excel)

Heta code is not the only way to create modules.

/* index.heta */

include mod2.csv type table;                  // from CSV
include mod3.xlsx type table with {sheet: 0}; // from XLSX (first sheet)
include mod3.xlsx type table with {sheet: 1}; // from XLSX (second sheet)
QSPC 2026 | InSysBio Workshop

Example of Heta table format

reactions.csv - Heta code:

r1 @Reaction { actors: A => B } := k1 * A * comp1;
r2 @Reaction { actors: B => C } := k2 * B * comp1;
//r3 @Reaction { actors: C => A } := k3 * C * comp1;

reactions.csv - Table format:

on id class actors assignments.ode_
1 r1 Reaction A => B k1 * A * comp1
1 r2 Reaction B => C k2 * B * comp1
0 r3 Reaction C => A k3 * C * comp1
width:
QSPC 2026 | InSysBio Workshop

💡 Task 3: Build model from tables

Modify an existing table-based model.

Steps

  1. Create a directory task-3
  2. Init project with heta init
    (? Select file types: heta+xlsx).
  3. Download table-based model from https://hetalang.github.io/qspc2026/table.xlsx to /src/table.xlsx.
  4. Build the model with
    heta build.
width:
QSPC 2026 | InSysBio Workshop

💡 Task 3: Build model from tables

Modify an existing table-based model.

Steps

  1. Open the file src/table.xlsx and modify the model to add a new reaction.
  2. Build the model again and check that the changes are reflected in the outputs.
QSPC 2026 | InSysBio Workshop

Table format: pros and cons

Pros:

  • Easy to create and edit in Excel if you are not comfortable with code
  • Does not require learning Heta syntax
  • Provides a structured, tabular view of model components

Cons:

  • Limited expressiveness compared to Heta code
  • Harder to navigate in large models
  • Difficult to track changes and compare versions
  • Less flexible for modular decomposition (often leads to splitting by component types)

👉 Table format is convenient, but not always scalable

QSPC 2026 | InSysBio Workshop

Other module types

include json_file.json type json;
include yaml_file.yml type yaml;

include sbml_file.xml type sbml;   // !!!

👉 heta-compiler can integrate SBML models as modules.

QSPC 2026 | InSysBio Workshop

🎬 Demo 2: Insulin signaling in diabetes type 2

SBML integration

https://doi.org/10.1074/jbc.M112.432062
https://biomodels.org/BIOMD0000000448
https://github.com/insysbio/insulin-signaling-t2d

alt text

QSPC 2026 | InSysBio Workshop

Heta modules: summary

  • Split large models into manageable parts
  • Support reuse and model extension
  • Combine multiple formats: Heta code, tables, JSON, YAML
  • Integrate external models (e.g. SBML)
/* index.heta */
include mod1.heta;                  // Heta
include mod2.csv type table;        // Table
include mod3.xlsx type table with {sheet: 0, omitRows: 0};
include mod3.xlsx type table with {sheet: 1, omitRows: 0};
include mod4.json type json;        // JSON
include mod5.yml type yaml;         // YAML
include mod6.xml type sbml;         // SBML
QSPC 2026 | InSysBio Workshop

Part III

HetaSimulator.jl

Intro. Simulations. Scenarios. Visualization. Workflow.

QSPC 2026 | InSysBio Workshop

HetaSimulator.jl intro

  • Julia simulation package for Heta platforms
  • Runs models directly without conversion
  • Easy to visualize results
  • Can be extended for advanced analysis

👉 A natural and integrated way to work with Heta models.

QSPC 2026 | InSysBio Workshop

🎬 Demo 3: example 1c

#= julia/run.jl =#
using HetaSimulator, Plots

# Load the model
platform = load_platform(".")
model = models(platform)[:nameless] # get default model

# Define a simulation scenario and run
scn1 = Scenario(
    model, (0., 100.); 
    observables = [:A, :B]
)
results = sim(scn1)

# plot results
plot(results)
QSPC 2026 | InSysBio Workshop

HetaSimulator.jl: capabilities

  • Flexible ODE solvers (DiffEq.jl)
  • Visualization and plotting
  • Simulation scenarios inline or from files
  • Experimental data integration, parameter estimation, identifiability analysis
  • Monte-Carlo simulations, Virtual Populations, sensitivity analysis
  • High-performance computing with SLURM integration
QSPC 2026 | InSysBio Workshop

Heta workflow: from model to simulation

  1. heta init → create project
  2. Edit platform.yml → configure build
  3. Edit index.heta / modules → define model
  4. load_platform(".") → check model in HetaSimulator
  5. Run simulations → analyze results
  6. ↺ Repeat steps 3–5
  7. Export model → share or reuse
QSPC 2026 | InSysBio Workshop

The idea behind Heta project

👉 We put the model at the center.

👉 Treat models as code: editable, versioned, modular.

👉 Engineering principles: structure, separation, reproducibility.

QSPC 2026 | InSysBio Workshop

https://hetalang.github.io

Thank you!