ReferencesHow Biosimulant Works

How Biosimulant Works

Biosimulant is an open-source Python engine for composing biological simulators and finite computations from modules with explicit typed ports. BioWorld drains before/after computation and advances temporal modules through atomic communication windows.

If you want a runnable introduction, start with the Library Quickstart (Python). This page explains the architecture behind that example.

The five core primitives

PrimitiveRoleReference
BioModuleA runnable temporal or finite-computation componentBioModule API
BioWorldThe communication-step orchestratorBioWorld API
SignalSpecA declared port contractBioSignal & SignalSpec
Typed BioSignal subclassesRuntime payloads crossing module boundariesBioSignal & SignalSpec
WiringBuilderA validated graph builder for named module portsWiringBuilder API

BioWorld: communication windows

Create a world with a required communication step:

world = biosim.BioWorld(communication_step=0.1)

ONCE_BEFORE_RUN modules run first, in dependency order. Then, for each window [t, t + communication_step]:

  1. the world reads committed signals at t
  2. it delivers those inputs to every connected target module
  3. every EACH_WINDOW module advances or executes across the same positive window
  4. the world commits all outputs atomically at t + communication_step

After the final window commits, ONCE_AFTER_RUN modules run in dependency order.

This means:

  • signal exchange is synchronized at shared communication boundaries
  • state signals use hold-last-value semantics until replaced
  • event signals are delivered once per connection per source timestamp
  • stale reads are checked from the consuming port’s SignalSpec

The kernel does not expose an execution-order scheduling contract, a global external tick parameter, rollback, or algebraic-loop solving.

A module sees another module’s output on the communication turn after it is committed. Final outputs are committed at the last boundary, so a downstream module that needs them should use ONCE_AFTER_RUN. Older temporal modules that implement advance_window() can use settle_steps / world.settle() instead.