B-Simulant LibraryDomain Packs

Domain Packs

Pre-built BioModules for specific scientific domains.

Neuroscience Pack

bsim.packs.neuro - Computational neuroscience modules for spiking neural networks.

Installation

from bsim.packs.neuro import (
    # Inputs
    PoissonInput,
    StepCurrent,
 
    # Populations
    IzhikevichPopulation,
 
    # Synapses
    ExpSynapseCurrent,
 
    # Monitors
    SpikeMonitor,
    RateMonitor,
    StateMonitor,
    NeuroMetrics
)

Input Modules

PoissonInput

Generate Poisson-distributed spike trains:

input = PoissonInput(
    rate_hz=100.0, # Firing rate (Hz)
    n=10           # Number of spike trains
)

Outputs:

  • spikes - Spike times array

StepCurrent

Inject current into neurons:

# Constant current
current = StepCurrent(I=10.0)  # 10 pA
 
# Scheduled current (start_t, end_t, I_value)
current = StepCurrent(
    I=10.0,
    schedule=[(0.1, 0.5, 15.0)]
)

Outputs:

  • current - Current value

Neuron Populations

IzhikevichPopulation

Spiking neuron population with various presets:

# Regular spiking (default cortical neurons)
pop = IzhikevichPopulation(n=100, preset="RS")
 
# Fast spiking (interneurons)
pop = IzhikevichPopulation(n=50, preset="FS")
 
# Intrinsically bursting
pop = IzhikevichPopulation(n=25, preset="Bursting")

Presets:

PresetabcdBehavior
RS0.020.2-658Regular spiking
FS0.10.2-652Fast spiking
Bursting0.020.2-554Intrinsically bursting
Chattering0.020.2-502Chattering
LTS0.020.25-652Low-threshold spiking

Custom parameters:

pop = IzhikevichPopulation(
    n=100,
    a=0.02, b=0.2, c=-65, d=8,  # Izhikevich parameters
    v_init=-70.0,               # Initial membrane potential
    u_init=-14.0                # Initial recovery variable
)

Inputs:

  • current - External current injection

Outputs:

  • spikes - Output spike times
  • state - Sampled membrane state traces

Synapses

ExpSynapseCurrent

Exponentially decaying synaptic current:

synapse = ExpSynapseCurrent(
    n_pre=100,    # Pre-synaptic population size
    n_post=100,   # Post-synaptic population size
    p_connect=0.1,# Connection probability
    weight=1.0,   # Synaptic weight
    tau=0.01,     # Decay time constant (s)
    delay_steps=0 # Step delay
)

Inputs:

  • spikes - Presynaptic spike times

Outputs:

  • current - Postsynaptic current

Monitors

SpikeMonitor

Record and visualize spike rasters:

monitor = SpikeMonitor(
    width=800,    # Raster plot width
    height=400    # Raster plot height
)

Inputs:

  • spikes - Spike times to record

Visualization:

  • Raster plot image

RateMonitor

Population firing rate over time:

monitor = RateMonitor(
    window_size=0.05,  # Window in seconds
    n_neurons=100      # Population size
)

Visualization:

  • Firing rate timeseries

StateMonitor

Record membrane voltage traces:

monitor = StateMonitor(
    max_points=5000
)

Visualization:

  • Voltage traces timeseries

NeuroMetrics

Summary statistics:

metrics = NeuroMetrics()

Visualization:

  • Table with spike counts, mean rates, CV ISI, etc.

Complete Example

import bsim
from bsim.packs.neuro import (
    PoissonInput, IzhikevichPopulation,
    ExpSynapseCurrent, SpikeMonitor, RateMonitor
)
 
world = bsim.BioWorld(solver=bsim.FixedStepSolver())
wb = bsim.WiringBuilder(world)
 
# Input spikes
wb.add("input", PoissonInput(n=100, rate_hz=50.0))
wb.add("input_syn", ExpSynapseCurrent(n_pre=100, n_post=800, weight=0.5, tau=0.01))
 
# Excitatory population
wb.add("exc", IzhikevichPopulation(n=800, preset="RS"))
 
# Inhibitory population
wb.add("inh", IzhikevichPopulation(n=200, preset="FS"))
 
# Synapses
wb.add("e2i_syn", ExpSynapseCurrent(n_pre=800, n_post=200, weight=0.5, tau=0.01))
wb.add("i2e_syn", ExpSynapseCurrent(n_pre=200, n_post=800, weight=-1.0, tau=0.01))
 
# Monitors
wb.add("spike_mon", SpikeMonitor())
wb.add("rate_mon", RateMonitor(window_size=0.05, n_neurons=1000))
 
# Wiring
wb.connect("input.out.spikes", ["input_syn.in.spikes"])
wb.connect("input_syn.out.current", ["exc.in.current"])
wb.connect("exc.out.spikes", ["e2i_syn.in.spikes", "spike_mon.in.spikes", "rate_mon.in.spikes"])
wb.connect("e2i_syn.out.current", ["inh.in.current"])
wb.connect("inh.out.spikes", ["i2e_syn.in.spikes"])
wb.connect("i2e_syn.out.current", ["exc.in.current"])
 
wb.apply()
 
# Simulate 1 second
result = world.simulate(steps=10000, dt=0.001)

Ecology Pack

bsim.packs.ecology - Population dynamics and ecosystem simulations.

Installation

from bsim.packs.ecology import (
    # Environment
    Environment,
 
    # Populations
    OrganismPopulation,
    Prey,
    Predator,
 
    # Interactions
    PredatorPreyInteraction,
    CompetitionInteraction,
    MutualismInteraction,
 
    # Monitors
    PopulationMonitor,
    EcologyMetrics,
    PhaseSpaceMonitor,
 
    # Presets
    PRESET_RABBIT, PRESET_FOX,
    PRESET_DEER, PRESET_WOLF,
    PRESET_BACTERIA
)

Environment

Broadcast environmental conditions:

env = Environment(
    temperature=25.0,    # Celsius
    water=100.0,         # Arbitrary units
    food_availability=1.0,  # 0-2 scale
    sunlight=1.0
)

Outputs:

  • conditions - Combined environmental state

Populations

OrganismPopulation

Generic population with birth/death dynamics:

pop = OrganismPopulation(
    name="Species",
    initial_count=100,  # Initial population
    birth_rate=0.1,     # Per-capita birth rate
    death_rate=0.02,    # Per-capita death rate
    carrying_capacity=1000  # Optional K
)

Using presets:

rabbits = OrganismPopulation(name="Rabbits", initial_count=100, preset="rabbit")
foxes = OrganismPopulation(name="Foxes", initial_count=10, preset="fox")

Presets:

Presetbirth_ratedeath_rateNotes
PRESET_RABBIT0.20.05Fast reproduction
PRESET_FOX0.050.08Predator-leaning
PRESET_DEER0.10.04Moderate
PRESET_WOLF0.040.06Slow, apex predator
PRESET_BACTERIA0.80.7Very fast

Inputs:

  • conditions - Environment conditions payload
  • predation - Predation events (kills)
  • competition - Competition pressure
  • food_gained - Food from predation

Outputs:

  • population_state - Current population state payload

Interactions

PredatorPreyInteraction

Lotka-Volterra style predation:

interaction = PredatorPreyInteraction(
    predation_rate=0.01,       # Attack rate
    conversion_efficiency=0.1  # Prey -> Predator conversion
)

Inputs:

  • prey_state - Prey population state
  • predator_state - Predator population state

Outputs:

  • predation - Predation events sent to prey
  • food_gained - Food gain sent to predators

CompetitionInteraction

Resource competition between species:

competition = CompetitionInteraction(
    competition_coefficient=0.5,
    resource_type="food"
)

MutualismInteraction

Beneficial relationships:

mutualism = MutualismInteraction(
    benefit_rate=0.05,
    benefit_type="food"
)

Monitors

PopulationMonitor

Track populations over time:

monitor = PopulationMonitor()

Inputs:

  • population_state - Population state signals

Visualization:

  • Dual timeseries plot

EcologyMetrics

Summary statistics:

metrics = EcologyMetrics()

Visualization:

  • Table with diversity indices, extinction events, etc.

PhaseSpaceMonitor

2D phase space trajectory:

monitor = PhaseSpaceMonitor(
    x_species="Prey",
    y_species="Predator"
)

Visualization:

  • Phase space plot

Complete Example

import bsim
from bsim.packs.ecology import (
    Environment, OrganismPopulation,
    PredatorPreyInteraction, PopulationMonitor, PhaseSpaceMonitor
)
 
world = bsim.BioWorld(solver=bsim.FixedStepSolver())
wb = bsim.WiringBuilder(world)
 
# Environment
wb.add("env", Environment(temperature=20.0))
 
# Populations
wb.add("rabbits", OrganismPopulation(name="Rabbits", initial_count=100, preset="rabbit"))
wb.add("foxes", OrganismPopulation(name="Foxes", initial_count=10, preset="fox"))
 
# Interaction
wb.add("predation", PredatorPreyInteraction(
    predation_rate=0.01,
    conversion_efficiency=0.1
))
 
# Monitors
pop_mon = PopulationMonitor()
phase_mon = PhaseSpaceMonitor(x_species="Rabbits", y_species="Foxes")
wb.add("pop_mon", pop_mon)
wb.add("phase_mon", phase_mon)
 
# Wiring
wb.connect("env.out.conditions", ["rabbits.in.conditions", "foxes.in.conditions"])
wb.connect("rabbits.out.population_state", [
    "predation.in.prey_state",
    "pop_mon.in.population_state",
    "phase_mon.in.population_state"
])
wb.connect("foxes.out.population_state", [
    "predation.in.predator_state",
    "pop_mon.in.population_state",
    "phase_mon.in.population_state"
])
wb.connect("predation.out.predation", ["rabbits.in.predation"])
wb.connect("predation.out.food_gained", ["foxes.in.food_gained"])
 
wb.apply()
 
# Simulate 100 time units
result = world.simulate(steps=10000, dt=0.01)
 
# Get visualizations
pop_vis = pop_mon.visualize()
phase_vis = phase_mon.visualize()

Creating Custom Packs

Structure a new domain pack:

bsim/packs/mypack/
├── __init__.py      # Export all modules
├── inputs.py        # Input modules
├── populations.py   # Core entities
├── interactions.py  # Interactions between entities
├── monitors.py      # Visualization modules
└── presets.py       # Parameter presets

Example module:

# mypack/populations.py
from bsim import BioModule
 
class CellPopulation(BioModule):
    def __init__(self, n: int, division_rate: float):
        super().__init__()
        self.n = n
        self.division_rate = division_rate
 
    def inputs(self):
        return {"nutrients", "signals"}
 
    def outputs(self):
        return {"population", "waste"}
 
    # ... implement on_event, on_signal, visualize, reset