Getting Started with B-Simulant
This guide walks you through installing and using the B-Simulant library for local simulations.
Installation
Basic Installation
pip install bsimWith Adapters
# SBML support (tellurium/libroadrunner)
pip install bsim[tellurium]
# ONNX/ML model support
pip install bsim[ml]
# All adapter extras (tellurium + ml)
pip install bsim[adapters]
# SimUI extras
pip install bsim[ui]From Source
git clone https://github.com/biosimulant/B-Simulant.git
cd B-Simulant
pip install -e ".[dev]"Your First Simulation
1. Import the Library
import bsim
from bsim import BioWorld, WiringBuilder, FixedStepSolver2. Create a World
The BioWorld is the central orchestrator:
world = BioWorld(solver=FixedStepSolver())3. Add Modules
Use WiringBuilder for declarative composition:
from bsim.packs.neuro import StepCurrent, IzhikevichPopulation, SpikeMonitor
wb = WiringBuilder(world)
input_current = StepCurrent(I=10.0, schedule=[(0.1, 0.8, 15.0)])
neurons = IzhikevichPopulation(n=100, preset="RS")
monitor = SpikeMonitor()
wb.add("input", input_current)
wb.add("neurons", neurons)
wb.add("monitor", monitor)4. Connect Modules
Wire outputs to inputs:
wb.connect("input.out.current", ["neurons.in.current"])
wb.connect("neurons.out.spikes", ["monitor.in.spikes"])
wb.apply()5. Run the Simulation
result = world.simulate(steps=1000, dt=0.001)
print(f"Simulated {result['steps']} steps (t={result['time']:.2f})")6. Visualize Results
# Get visualization data from monitors
visuals = monitor.visualize()
# Returns:
# {
# "render": "image",
# "data": { "src": "data:image/svg+xml;base64,...", "width": 600, "height": 300 }
# }Complete Example: Predator-Prey
import bsim
from bsim.packs.ecology import (
Environment,
OrganismPopulation,
PredatorPreyInteraction,
PopulationMonitor
)
# Create world with fixed time stepping
world = bsim.BioWorld(solver=bsim.FixedStepSolver())
# Build the composition
wb = bsim.WiringBuilder(world)
# Environment
wb.add("env", Environment(temperature=20.0))
# Add populations with species presets
wb.add("rabbits", OrganismPopulation(name="Rabbits", initial_count=100, preset="rabbit"))
wb.add("foxes", OrganismPopulation(name="Foxes", initial_count=10, preset="fox"))
# Add interaction dynamics
wb.add("predation", PredatorPreyInteraction(
predation_rate=0.01,
conversion_efficiency=0.1
))
# Add monitoring
monitor = PopulationMonitor()
wb.add("monitor", monitor)
# Wire the ecosystem
wb.connect("env.out.conditions", ["rabbits.in.conditions", "foxes.in.conditions"])
wb.connect("rabbits.out.population_state", ["predation.in.prey_state", "monitor.in.population_state"])
wb.connect("foxes.out.population_state", ["predation.in.predator_state", "monitor.in.population_state"])
wb.connect("predation.out.predation", ["rabbits.in.predation"])
wb.connect("predation.out.food_gained", ["foxes.in.food_gained"])
# Apply wiring
wb.apply()
# Simulate 100 time units with dt=0.01
result = world.simulate(steps=10000, dt=0.01)
# Get population time series
vis = monitor.visualize()
print(vis["data"]["title"])Using Adapters
SBML Model
from bsim.adapters import TelluriumAdapter
# Load SBML model
adapter = TelluriumAdapter(model_path="glycolysis.xml", expose=["S1", "S2"])
adapter.setup({})
# Or from string
adapter = TelluriumAdapter(sbml_string=sbml_string, expose=["S1", "S2"])
adapter.setup({})
# Advance and read outputs
adapter.advance_to(10.0)
outputs = adapter.get_outputs()
print(outputs["S1"].value)ONNX Model
from bsim.adapters import MLAdapter, BioSignal
# Load ONNX model (input/output names default to the model's I/O names)
adapter = MLAdapter(model_path="model.onnx")
adapter.setup({})
adapter.set_inputs({
"input_1": BioSignal(source="client", name="input_1", value=[1.0, 2.0, 3.0], time=0.0),
"input_2": BioSignal(source="client", name="input_2", value=[4.0, 5.0, 6.0], time=0.0),
})
adapter.advance_to(0.0)
outputs = adapter.get_outputs()
print(outputs)Hybrid Composition
from bsim.adapters import TelluriumAdapter, MLAdapter, TimeBroker
# Adapters run under the TimeBroker runtime (separate from BioWorld module wiring).
sbml = TelluriumAdapter(
model_path="pathway.xml",
expose=["ATP", "glucose"],
)
ml = MLAdapter(
model_path="response.onnx",
inputs={"ATP": "x1", "glucose": "x2"},
outputs={"y": "efficacy"},
)
broker = TimeBroker()
broker.register("metabolism", sbml, time_scale="seconds")
broker.register("predictor", ml, time_scale="seconds")
broker.connect("metabolism.ATP", "predictor.ATP")
broker.connect("metabolism.glucose", "predictor.glucose")
broker.setup()
for _t in broker.run(duration=100.0, dt=1.0):
pass
efficacy = ml.get_outputs()["efficacy"].value
print("efficacy:", efficacy)Configuration Files
YAML Configuration
# composition.yaml
modules:
prey:
class: bsim.packs.ecology.OrganismPopulation
args:
name: Prey
initial_count: 100
preset: rabbit
predator:
class: bsim.packs.ecology.OrganismPopulation
args:
name: Predator
initial_count: 10
preset: fox
interaction:
class: bsim.packs.ecology.PredatorPreyInteraction
args:
predation_rate: 0.01
wiring:
- from: prey.out.population_state
to: [interaction.in.prey_state]
- from: predator.out.population_state
to: [interaction.in.predator_state]
- from: interaction.out.predation
to: [prey.in.predation]
- from: interaction.out.food_gained
to: [predator.in.food_gained]Load and run:
import bsim
world = bsim.BioWorld(solver=bsim.FixedStepSolver())
world.load_wiring("composition.yaml")
result = world.simulate(steps=1000, dt=0.1)Note: YAML loading requires pyyaml (included in bsim[dev]).
SimUI: Web Interface
Launch a local web interface for your simulation:
from bsim.simui import Interface, Number, Button, EventLog, VisualsPanel
ui = Interface(
world,
controls=[
Number("steps", 1000, minimum=100, maximum=10000, step=100),
Number("dt", 0.01, minimum=0.001, maximum=0.1, step=0.001),
Button("Run")
],
outputs=[
EventLog(),
VisualsPanel()
]
)
# Launch in browser
ui.launch(port=8080)Access at http://localhost:8080/ui/.
Next Steps
- BioWorld & Modules - Deep dive into the core
- Adapters - SBML, ONNX, NeuroML integration
- Domain Packs - Pre-built neuroscience and ecology modules
- SimUI - Build web interfaces