How to Create a Domain Pack
A domain pack is a normal Python package that exports a coherent family of BioModule implementations, presets, and monitors.
Suggested structure
mypack/
__init__.py
inputs.py
populations.py
interactions.py
monitors.py
presets.pyExample input module
import biosimulant as biosim
class DrugDose(biosim.BioModule):
def __init__(self, dose_mg: float, schedule: list[float]):
self.dose_mg = float(dose_mg)
self.schedule = list(schedule)
self._outputs = {}
def outputs(self):
return {
"drug_concentration": biosim.SignalSpec.scalar(
dtype="float64",
emitted_unit="mg/L",
)
}
def advance_window(self, start: float, end: float) -> None:
active = any(abs(t - end) < 1e-9 for t in self.schedule)
self._outputs = {
"drug_concentration": biosim.ScalarSignal(
source="drug",
name="drug_concentration",
value=self.dose_mg if active else 0.0,
emitted_at=end,
spec=self.outputs()["drug_concentration"],
)
}
def get_outputs(self):
return dict(self._outputs)
def snapshot(self):
return {}Example population module
class CellPopulation(biosim.BioModule):
def __init__(self, n: int, division_rate: float = 0.1):
self.n = int(n)
self.division_rate = float(division_rate)
def inputs(self):
return {"drug_concentration": biosim.SignalSpec.scalar(dtype="float64")}
def outputs(self):
return {
"population_state": biosim.SignalSpec.record(
schema={"count": "int64"},
)
}Export your public surface
from .inputs import DrugDose
from .populations import CellPopulation
from .monitors import GrowthMonitor
__all__ = ["DrugDose", "CellPopulation", "GrowthMonitor"]Use the pack
import biosimulant as biosim
from mypack import DrugDose, CellPopulation, GrowthMonitor
world = biosim.BioWorld(communication_step=1.0)
builder = biosim.WiringBuilder(world)
builder.add("drug", DrugDose(dose_mg=100, schedule=[0, 24, 48]))
builder.add("cells", CellPopulation(n=1000))
builder.add("monitor", GrowthMonitor())
builder.connect("drug.drug_concentration", ["cells.drug_concentration"])
builder.connect("cells.population_state", ["monitor.population_state"])
builder.apply()
world.run(duration=72.0)Domain packs do not need to live under a biosimulant.* namespace. Stable import paths matter more than namespace conventions.