biosim 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- biosim-0.0.1/.gitignore +25 -0
- biosim-0.0.1/LICENSE.txt +21 -0
- biosim-0.0.1/PKG-INFO +277 -0
- biosim-0.0.1/README.md +241 -0
- biosim-0.0.1/docs/PUBLIC_INTERNAL_BOUNDARY.md +20 -0
- biosim-0.0.1/docs/README.md +30 -0
- biosim-0.0.1/docs/biomodule.md +63 -0
- biosim-0.0.1/docs/bioworld.md +38 -0
- biosim-0.0.1/docs/book.md +49 -0
- biosim-0.0.1/docs/brain_pipeline.md +26 -0
- biosim-0.0.1/docs/config.md +42 -0
- biosim-0.0.1/docs/neuro.md +451 -0
- biosim-0.0.1/docs/overview.md +42 -0
- biosim-0.0.1/docs/plugin-development.md +178 -0
- biosim-0.0.1/docs/quickstart.md +89 -0
- biosim-0.0.1/docs/wiring.md +58 -0
- biosim-0.0.1/examples/README.md +43 -0
- biosim-0.0.1/examples/__init__.py +0 -0
- biosim-0.0.1/examples/basic_usage.py +33 -0
- biosim-0.0.1/examples/multi_module_ui_demo.py +161 -0
- biosim-0.0.1/examples/ui_demo.py +51 -0
- biosim-0.0.1/examples/visuals_demo.py +56 -0
- biosim-0.0.1/examples/wiring_builder_demo.py +86 -0
- biosim-0.0.1/examples/world_simulation.py +122 -0
- biosim-0.0.1/pyproject.toml +109 -0
- biosim-0.0.1/scripts/build_simui_frontend.sh +36 -0
- biosim-0.0.1/scripts/check_public_boundary.sh +19 -0
- biosim-0.0.1/scripts/release_pypi.sh +93 -0
- biosim-0.0.1/src/biosim/__about__.py +4 -0
- biosim-0.0.1/src/biosim/__init__.py +52 -0
- biosim-0.0.1/src/biosim/__main__.py +237 -0
- biosim-0.0.1/src/biosim/modules.py +73 -0
- biosim-0.0.1/src/biosim/signals.py +129 -0
- biosim-0.0.1/src/biosim/simui/__init__.py +18 -0
- biosim-0.0.1/src/biosim/simui/build.py +86 -0
- biosim-0.0.1/src/biosim/simui/editor_api.py +459 -0
- biosim-0.0.1/src/biosim/simui/graph.py +442 -0
- biosim-0.0.1/src/biosim/simui/interface.py +518 -0
- biosim-0.0.1/src/biosim/simui/registry.py +276 -0
- biosim-0.0.1/src/biosim/simui/runner.py +130 -0
- biosim-0.0.1/src/biosim/simui/static/app.css +1 -0
- biosim-0.0.1/src/biosim/simui/static/app.js +92 -0
- biosim-0.0.1/src/biosim/visuals.py +72 -0
- biosim-0.0.1/src/biosim/wiring.py +164 -0
- biosim-0.0.1/src/biosim/world.py +301 -0
- biosim-0.0.1/tests/__init__.py +3 -0
- biosim-0.0.1/tests/conftest.py +17 -0
- biosim-0.0.1/tests/test_api.py +5 -0
- biosim-0.0.1/tests/test_biomodules.py +40 -0
- biosim-0.0.1/tests/test_biosignals.py +116 -0
- biosim-0.0.1/tests/test_bioworld_flow.py +110 -0
- biosim-0.0.1/tests/test_errors.py +27 -0
- biosim-0.0.1/tests/test_listeners.py +25 -0
- biosim-0.0.1/tests/test_optional_deps.py +19 -0
- biosim-0.0.1/tests/test_ports_validation.py +150 -0
- biosim-0.0.1/tests/test_simui_spec.py +77 -0
- biosim-0.0.1/tests/test_visuals.py +148 -0
- biosim-0.0.1/tests/test_wiring_builder.py +70 -0
- biosim-0.0.1/tests/test_wiring_loader.py +65 -0
- biosim-0.0.1/tests/test_world_load_wiring.py +25 -0
- biosim-0.0.1/tests/test_world_load_wiring_yaml.py +19 -0
biosim-0.0.1/.gitignore
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Byte-compiled / cache
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.mypy_cache/
|
|
7
|
+
.ruff_cache/
|
|
8
|
+
.coverage
|
|
9
|
+
coverage.xml
|
|
10
|
+
htmlcov/
|
|
11
|
+
|
|
12
|
+
node_modules/
|
|
13
|
+
.venv/
|
|
14
|
+
dist/
|
|
15
|
+
build/
|
|
16
|
+
src/biosim/simui/_frontend/dist/
|
|
17
|
+
|
|
18
|
+
.DS_Store
|
|
19
|
+
|
|
20
|
+
# SimUI UI build outputs
|
|
21
|
+
packages/simui-ui/dist-static/
|
|
22
|
+
|
|
23
|
+
# Commit the built library artifacts so npm can install @biosim/simui-ui from a git SHA.
|
|
24
|
+
!packages/simui-ui/dist/
|
|
25
|
+
!packages/simui-ui/dist/**
|
biosim-0.0.1/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BioSimulant
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
biosim-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: biosim
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Core simulation library for Biosimulant
|
|
5
|
+
Project-URL: Documentation, https://github.com/Biosimulant/biosim#readme
|
|
6
|
+
Project-URL: Issues, https://github.com/Biosimulant/biosim/issues
|
|
7
|
+
Project-URL: Source, https://github.com/Biosimulant/biosim
|
|
8
|
+
Author-email: Demi <bjaiye1@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE.txt
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: numpy>=1.26
|
|
20
|
+
Provides-Extra: all
|
|
21
|
+
Requires-Dist: fastapi<1,>=0.110; extra == 'all'
|
|
22
|
+
Requires-Dist: pytest-cov>=4; extra == 'all'
|
|
23
|
+
Requires-Dist: pytest>=7; extra == 'all'
|
|
24
|
+
Requires-Dist: pyyaml>=6; extra == 'all'
|
|
25
|
+
Requires-Dist: tomli>=2; (python_version < '3.11') and extra == 'all'
|
|
26
|
+
Requires-Dist: uvicorn>=0.23; extra == 'all'
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest-cov>=4; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
30
|
+
Requires-Dist: pyyaml>=6; extra == 'dev'
|
|
31
|
+
Requires-Dist: tomli>=2; (python_version < '3.11') and extra == 'dev'
|
|
32
|
+
Provides-Extra: ui
|
|
33
|
+
Requires-Dist: fastapi<1,>=0.110; extra == 'ui'
|
|
34
|
+
Requires-Dist: uvicorn>=0.23; extra == 'ui'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# biosim
|
|
38
|
+
|
|
39
|
+
[](https://pypi.org/project/biosim)
|
|
40
|
+
[](https://pypi.org/project/biosim)
|
|
41
|
+
|
|
42
|
+
Composable simulation runtime + UI layer for orchestrating runnable biomodules.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Executive Summary & System Goals
|
|
47
|
+
|
|
48
|
+
### Vision
|
|
49
|
+
|
|
50
|
+
Provide a small, stable composition layer for simulations: wire reusable components ("biomodules") into a `BioWorld`, run them with a single orchestration contract, and visualize/debug runs via a lightweight web UI (SimUI). Biomodules are self-contained Python packages that can wrap external simulators internally (SBML/NeuroML/CellML/etc.) without a separate adapter layer.
|
|
51
|
+
|
|
52
|
+
### Core Mission
|
|
53
|
+
|
|
54
|
+
- Compose simulations from reusable, interoperable biomodules.
|
|
55
|
+
- Make "run + visualize + share a config" the default workflow (local-first; hosted later).
|
|
56
|
+
- Keep the runtime small and predictable while letting biomodules embed their own simulator/tooling.
|
|
57
|
+
|
|
58
|
+
### Primary Users
|
|
59
|
+
|
|
60
|
+
- Developers and researchers who need composable simulation workflows and fast iteration.
|
|
61
|
+
- Near-term beachhead: neuroscience demos (single neuron + small E/I microcircuits) with strong visuals and reproducible configs.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Installation
|
|
66
|
+
|
|
67
|
+
Preferred (pinned GitHub ref):
|
|
68
|
+
|
|
69
|
+
```console
|
|
70
|
+
pip install "biosim @ git+https://github.com/<org>/biosim.git@<ref>"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Alternative (package index):
|
|
74
|
+
|
|
75
|
+
```console
|
|
76
|
+
pip install biosim
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Publishing to PyPI
|
|
80
|
+
|
|
81
|
+
This repository publishes to PyPI using GitHub Trusted Publishing.
|
|
82
|
+
|
|
83
|
+
Release workflow:
|
|
84
|
+
|
|
85
|
+
1. Update `src/biosim/__about__.py` with a new version (example: `0.0.2`).
|
|
86
|
+
2. Commit and push the version bump to `main`.
|
|
87
|
+
3. Create and push a matching tag (`v0.0.2`).
|
|
88
|
+
4. Verify GitHub Actions `Publish to PyPI` finishes successfully.
|
|
89
|
+
|
|
90
|
+
Manual commands:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
git add src/biosim/__about__.py
|
|
94
|
+
git commit -m "Bump version to 0.0.2"
|
|
95
|
+
git push origin main
|
|
96
|
+
git tag v0.0.2
|
|
97
|
+
git push origin v0.0.2
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Automation script:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
bash scripts/release_pypi.sh
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- This reads the version from `src/biosim/__about__.py`, requires a clean git tree, pushes `main`, then creates and pushes `v<version>`.
|
|
107
|
+
- You can also pass an explicit version: `bash scripts/release_pypi.sh 0.0.2`.
|
|
108
|
+
- Use `--no-push` to only create the local tag: `bash scripts/release_pypi.sh --no-push`.
|
|
109
|
+
|
|
110
|
+
## Examples
|
|
111
|
+
|
|
112
|
+
- See `examples/` for quick-start scripts. Try:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
pip install -e .
|
|
116
|
+
python examples/basic_usage.py
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
For advanced curated demos (neuro/ecology), wiring configs, and model-pack templates, see the companion repo:
|
|
120
|
+
|
|
121
|
+
- https://github.com/Biosimulant/models
|
|
122
|
+
|
|
123
|
+
### Quick Start: BioWorld
|
|
124
|
+
|
|
125
|
+
Minimal usage:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
import biosim
|
|
129
|
+
from biosim import BioSignal, SignalMetadata
|
|
130
|
+
|
|
131
|
+
class Counter(biosim.BioModule):
|
|
132
|
+
min_dt = 0.1
|
|
133
|
+
|
|
134
|
+
def __init__(self):
|
|
135
|
+
self.value = 0
|
|
136
|
+
|
|
137
|
+
def reset(self) -> None:
|
|
138
|
+
self.value = 0
|
|
139
|
+
|
|
140
|
+
def advance_to(self, t: float) -> None:
|
|
141
|
+
self.value += 1
|
|
142
|
+
|
|
143
|
+
def get_outputs(self):
|
|
144
|
+
source = getattr(self, "_world_name", "counter")
|
|
145
|
+
return {
|
|
146
|
+
"count": BioSignal(
|
|
147
|
+
source=source,
|
|
148
|
+
name="count",
|
|
149
|
+
value=self.value,
|
|
150
|
+
time=0.0,
|
|
151
|
+
metadata=SignalMetadata(units="1", description="tick counter"),
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
world = biosim.BioWorld()
|
|
156
|
+
world.add_biomodule("counter", Counter())
|
|
157
|
+
world.run(duration=1.0, tick_dt=0.1)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Visuals from Modules
|
|
161
|
+
|
|
162
|
+
Modules may optionally expose web-native visuals via `visualize()`, returning a dict or list of dicts with keys `render` and `data`. The world can collect them without any transport layer:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
class MyModule(biosim.BioModule):
|
|
166
|
+
min_dt = 0.1
|
|
167
|
+
|
|
168
|
+
def advance_to(self, t: float) -> None:
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
def get_outputs(self):
|
|
172
|
+
return {}
|
|
173
|
+
|
|
174
|
+
def visualize(self):
|
|
175
|
+
return {
|
|
176
|
+
"render": "timeseries",
|
|
177
|
+
"data": {"series": [{"name": "s", "points": [[0.0, 1.0]]}]},
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
world = biosim.BioWorld()
|
|
181
|
+
world.add_biomodule("module", MyModule())
|
|
182
|
+
world.run(duration=0.1, tick_dt=0.1)
|
|
183
|
+
print(world.collect_visuals()) # [{"module": "module", "visuals": [...]}]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
See `examples/visuals_demo.py` for a minimal end-to-end example.
|
|
187
|
+
|
|
188
|
+
## SimUI (Python-Declared UI)
|
|
189
|
+
|
|
190
|
+
SimUI lets you build and launch a small web UI entirely from Python (similar to Gradio's ergonomics), backed by FastAPI and a prebuilt React SPA that renders visuals from JSON. The frontend uses Server-Sent Events (SSE) for real-time updates.
|
|
191
|
+
|
|
192
|
+
- User usage (no Node/npm required):
|
|
193
|
+
- Install UI extras: `pip install -e '.[ui]'`
|
|
194
|
+
- Try the demo: `python examples/ui_demo.py` then open `http://127.0.0.1:7860/ui/`.
|
|
195
|
+
- From your own code:
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
from biosim.simui import Interface, Number, Button, EventLog, VisualsPanel
|
|
199
|
+
world = biosim.BioWorld()
|
|
200
|
+
ui = Interface(
|
|
201
|
+
world,
|
|
202
|
+
controls=[Number("duration", 10), Number("tick_dt", 0.1), Button("Run")],
|
|
203
|
+
outputs=[EventLog(), VisualsPanel()],
|
|
204
|
+
)
|
|
205
|
+
ui.launch()
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
- The UI provides endpoints under `/ui/api/...`:
|
|
209
|
+
- `GET /api/spec` – UI layout (controls, outputs, modules)
|
|
210
|
+
- `POST /api/run` – Start a simulation run
|
|
211
|
+
- `GET /api/status` – Runner status (running/paused/error)
|
|
212
|
+
- `GET /api/state` – Full state (status + last step + modules)
|
|
213
|
+
- `GET /api/events` – Buffered world events (`?since_id=&limit=`)
|
|
214
|
+
- `GET /api/visuals` – Collected module visuals
|
|
215
|
+
- `GET /api/snapshot` – Full snapshot (status + visuals + events)
|
|
216
|
+
- `GET /api/stream` – SSE endpoint for real-time event streaming
|
|
217
|
+
- `POST /api/pause` – Pause running simulation
|
|
218
|
+
- `POST /api/resume` – Resume paused simulation
|
|
219
|
+
- `POST /api/reset` – Stop, reset, and clear buffers
|
|
220
|
+
- **Editor sub-API** (`/api/editor/...`): visual config editor for loading, saving, validating, and applying YAML wiring configs as node graphs. Endpoints include `modules`, `current`, `config`, `apply`, `validate`, `layout`, `to-yaml`, `from-yaml`, and `files`.
|
|
221
|
+
|
|
222
|
+
Per-run resets for clean visuals
|
|
223
|
+
- On each `Run`, the backend clears its event buffer and calls `reset()` on modules if they implement it.
|
|
224
|
+
- The frontend clears visuals/events before posting `/api/run`.
|
|
225
|
+
- To avoid overlapping charts across runs, add `reset()` to modules that accumulate history (e.g., time series points).
|
|
226
|
+
|
|
227
|
+
- Maintainer flow (building the frontend SPA):
|
|
228
|
+
- Edit the React/Vite app under `src/biosim/simui/_frontend/`.
|
|
229
|
+
- Build via Python: `python -m biosim.simui.build` (requires Node/npm). This writes `src/biosim/simui/static/app.js`.
|
|
230
|
+
- Alternatively: `bash scripts/build_simui_frontend.sh`.
|
|
231
|
+
- Packaging includes `src/biosim/simui/static/**`, so end users never need npm.
|
|
232
|
+
|
|
233
|
+
- CI packaging (recommended): run the frontend build before `python -m build` so wheels/sdists ship the bundled assets.
|
|
234
|
+
|
|
235
|
+
Troubleshooting:
|
|
236
|
+
- If you see `SimUI static bundle missing at .../static/app.js`, build the frontend with `python -m biosim.simui.build` (requires Node/npm) before launching. End users installing a release wheel won't see this.
|
|
237
|
+
|
|
238
|
+
### SimUI Design Notes
|
|
239
|
+
- Transport: SSE (Server-Sent Events). The SPA connects to `/api/stream` for real-time updates. Polling endpoints (`/api/status`, `/api/visuals`, `/api/events`) remain available for fallback/debugging.
|
|
240
|
+
- Events API: `/api/events?since_id=<int>&limit=<int>` returns `{ events, next_since_id }` where `events` are appended world events and `next_since_id` is the cursor for subsequent calls.
|
|
241
|
+
- VisualSpec types supported now:
|
|
242
|
+
- `timeseries`: `data = { "series": [{ "name": str, "points": [[x, y], ...] }, ...] }`
|
|
243
|
+
- `bar`: `data = { "items": [{ "label": str, "value": number }, ...] }`
|
|
244
|
+
- `table`: `data = { "columns": [..], "rows": [[..], ...] }` or `data = { "items": [{...}, ...] }`
|
|
245
|
+
- `image`: `data = { "src": str, "alt"?: str, "width"?: number, "height"?: number }`
|
|
246
|
+
- `scatter`: scatter plot data
|
|
247
|
+
- `heatmap`: matrix/heatmap data
|
|
248
|
+
- `graph`: placeholder renderer shows counts + JSON; richer graph lib can be added later
|
|
249
|
+
- `custom:<type>`: custom renderer namespace for user-defined types
|
|
250
|
+
- unknown types: rendered as JSON fallback
|
|
251
|
+
- VisualSpec may also include an optional `description` (string) for hover text or captions.
|
|
252
|
+
|
|
253
|
+
## Terminology
|
|
254
|
+
|
|
255
|
+
Understanding the core concepts is essential for working with biosim effectively.
|
|
256
|
+
|
|
257
|
+
| Term | Description |
|
|
258
|
+
|------|-------------|
|
|
259
|
+
| **BioWorld** | Runtime container that orchestrates multi-rate biomodules, routes signals, and publishes lifecycle events. |
|
|
260
|
+
| **BioModule** | Pluggable unit of behavior with local state. Implements the runnable contract (`setup/reset/advance_to/...`). |
|
|
261
|
+
| **BioSignal** | Typed, versioned data payload exchanged between modules via named ports. |
|
|
262
|
+
| **WorldEvent** | Runtime events emitted by the BioWorld (`STARTED`, `TICK`, `FINISHED`, etc.). |
|
|
263
|
+
| **Wiring** | Module connection graph. Defined programmatically, via `WiringBuilder`, or loaded from YAML/TOML configs. |
|
|
264
|
+
| **VisualSpec** | JSON structure returned by `module.visualize()` with `render` type and `data` payload. |
|
|
265
|
+
|
|
266
|
+
### Event Lifecycle
|
|
267
|
+
|
|
268
|
+
Every simulation follows this sequence:
|
|
269
|
+
```
|
|
270
|
+
STARTED -> TICK (xN) -> FINISHED
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
`PAUSED`, `RESUMED`, `STOPPED`, and `ERROR` may also be emitted depending on runtime control flow.
|
|
274
|
+
|
|
275
|
+
## License
|
|
276
|
+
|
|
277
|
+
MIT. See `LICENSE.txt`.
|
biosim-0.0.1/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# biosim
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/biosim)
|
|
4
|
+
[](https://pypi.org/project/biosim)
|
|
5
|
+
|
|
6
|
+
Composable simulation runtime + UI layer for orchestrating runnable biomodules.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Executive Summary & System Goals
|
|
11
|
+
|
|
12
|
+
### Vision
|
|
13
|
+
|
|
14
|
+
Provide a small, stable composition layer for simulations: wire reusable components ("biomodules") into a `BioWorld`, run them with a single orchestration contract, and visualize/debug runs via a lightweight web UI (SimUI). Biomodules are self-contained Python packages that can wrap external simulators internally (SBML/NeuroML/CellML/etc.) without a separate adapter layer.
|
|
15
|
+
|
|
16
|
+
### Core Mission
|
|
17
|
+
|
|
18
|
+
- Compose simulations from reusable, interoperable biomodules.
|
|
19
|
+
- Make "run + visualize + share a config" the default workflow (local-first; hosted later).
|
|
20
|
+
- Keep the runtime small and predictable while letting biomodules embed their own simulator/tooling.
|
|
21
|
+
|
|
22
|
+
### Primary Users
|
|
23
|
+
|
|
24
|
+
- Developers and researchers who need composable simulation workflows and fast iteration.
|
|
25
|
+
- Near-term beachhead: neuroscience demos (single neuron + small E/I microcircuits) with strong visuals and reproducible configs.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
Preferred (pinned GitHub ref):
|
|
32
|
+
|
|
33
|
+
```console
|
|
34
|
+
pip install "biosim @ git+https://github.com/<org>/biosim.git@<ref>"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Alternative (package index):
|
|
38
|
+
|
|
39
|
+
```console
|
|
40
|
+
pip install biosim
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Publishing to PyPI
|
|
44
|
+
|
|
45
|
+
This repository publishes to PyPI using GitHub Trusted Publishing.
|
|
46
|
+
|
|
47
|
+
Release workflow:
|
|
48
|
+
|
|
49
|
+
1. Update `src/biosim/__about__.py` with a new version (example: `0.0.2`).
|
|
50
|
+
2. Commit and push the version bump to `main`.
|
|
51
|
+
3. Create and push a matching tag (`v0.0.2`).
|
|
52
|
+
4. Verify GitHub Actions `Publish to PyPI` finishes successfully.
|
|
53
|
+
|
|
54
|
+
Manual commands:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
git add src/biosim/__about__.py
|
|
58
|
+
git commit -m "Bump version to 0.0.2"
|
|
59
|
+
git push origin main
|
|
60
|
+
git tag v0.0.2
|
|
61
|
+
git push origin v0.0.2
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Automation script:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
bash scripts/release_pypi.sh
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- This reads the version from `src/biosim/__about__.py`, requires a clean git tree, pushes `main`, then creates and pushes `v<version>`.
|
|
71
|
+
- You can also pass an explicit version: `bash scripts/release_pypi.sh 0.0.2`.
|
|
72
|
+
- Use `--no-push` to only create the local tag: `bash scripts/release_pypi.sh --no-push`.
|
|
73
|
+
|
|
74
|
+
## Examples
|
|
75
|
+
|
|
76
|
+
- See `examples/` for quick-start scripts. Try:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install -e .
|
|
80
|
+
python examples/basic_usage.py
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
For advanced curated demos (neuro/ecology), wiring configs, and model-pack templates, see the companion repo:
|
|
84
|
+
|
|
85
|
+
- https://github.com/Biosimulant/models
|
|
86
|
+
|
|
87
|
+
### Quick Start: BioWorld
|
|
88
|
+
|
|
89
|
+
Minimal usage:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
import biosim
|
|
93
|
+
from biosim import BioSignal, SignalMetadata
|
|
94
|
+
|
|
95
|
+
class Counter(biosim.BioModule):
|
|
96
|
+
min_dt = 0.1
|
|
97
|
+
|
|
98
|
+
def __init__(self):
|
|
99
|
+
self.value = 0
|
|
100
|
+
|
|
101
|
+
def reset(self) -> None:
|
|
102
|
+
self.value = 0
|
|
103
|
+
|
|
104
|
+
def advance_to(self, t: float) -> None:
|
|
105
|
+
self.value += 1
|
|
106
|
+
|
|
107
|
+
def get_outputs(self):
|
|
108
|
+
source = getattr(self, "_world_name", "counter")
|
|
109
|
+
return {
|
|
110
|
+
"count": BioSignal(
|
|
111
|
+
source=source,
|
|
112
|
+
name="count",
|
|
113
|
+
value=self.value,
|
|
114
|
+
time=0.0,
|
|
115
|
+
metadata=SignalMetadata(units="1", description="tick counter"),
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
world = biosim.BioWorld()
|
|
120
|
+
world.add_biomodule("counter", Counter())
|
|
121
|
+
world.run(duration=1.0, tick_dt=0.1)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Visuals from Modules
|
|
125
|
+
|
|
126
|
+
Modules may optionally expose web-native visuals via `visualize()`, returning a dict or list of dicts with keys `render` and `data`. The world can collect them without any transport layer:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
class MyModule(biosim.BioModule):
|
|
130
|
+
min_dt = 0.1
|
|
131
|
+
|
|
132
|
+
def advance_to(self, t: float) -> None:
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
def get_outputs(self):
|
|
136
|
+
return {}
|
|
137
|
+
|
|
138
|
+
def visualize(self):
|
|
139
|
+
return {
|
|
140
|
+
"render": "timeseries",
|
|
141
|
+
"data": {"series": [{"name": "s", "points": [[0.0, 1.0]]}]},
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
world = biosim.BioWorld()
|
|
145
|
+
world.add_biomodule("module", MyModule())
|
|
146
|
+
world.run(duration=0.1, tick_dt=0.1)
|
|
147
|
+
print(world.collect_visuals()) # [{"module": "module", "visuals": [...]}]
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
See `examples/visuals_demo.py` for a minimal end-to-end example.
|
|
151
|
+
|
|
152
|
+
## SimUI (Python-Declared UI)
|
|
153
|
+
|
|
154
|
+
SimUI lets you build and launch a small web UI entirely from Python (similar to Gradio's ergonomics), backed by FastAPI and a prebuilt React SPA that renders visuals from JSON. The frontend uses Server-Sent Events (SSE) for real-time updates.
|
|
155
|
+
|
|
156
|
+
- User usage (no Node/npm required):
|
|
157
|
+
- Install UI extras: `pip install -e '.[ui]'`
|
|
158
|
+
- Try the demo: `python examples/ui_demo.py` then open `http://127.0.0.1:7860/ui/`.
|
|
159
|
+
- From your own code:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from biosim.simui import Interface, Number, Button, EventLog, VisualsPanel
|
|
163
|
+
world = biosim.BioWorld()
|
|
164
|
+
ui = Interface(
|
|
165
|
+
world,
|
|
166
|
+
controls=[Number("duration", 10), Number("tick_dt", 0.1), Button("Run")],
|
|
167
|
+
outputs=[EventLog(), VisualsPanel()],
|
|
168
|
+
)
|
|
169
|
+
ui.launch()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
- The UI provides endpoints under `/ui/api/...`:
|
|
173
|
+
- `GET /api/spec` – UI layout (controls, outputs, modules)
|
|
174
|
+
- `POST /api/run` – Start a simulation run
|
|
175
|
+
- `GET /api/status` – Runner status (running/paused/error)
|
|
176
|
+
- `GET /api/state` – Full state (status + last step + modules)
|
|
177
|
+
- `GET /api/events` – Buffered world events (`?since_id=&limit=`)
|
|
178
|
+
- `GET /api/visuals` – Collected module visuals
|
|
179
|
+
- `GET /api/snapshot` – Full snapshot (status + visuals + events)
|
|
180
|
+
- `GET /api/stream` – SSE endpoint for real-time event streaming
|
|
181
|
+
- `POST /api/pause` – Pause running simulation
|
|
182
|
+
- `POST /api/resume` – Resume paused simulation
|
|
183
|
+
- `POST /api/reset` – Stop, reset, and clear buffers
|
|
184
|
+
- **Editor sub-API** (`/api/editor/...`): visual config editor for loading, saving, validating, and applying YAML wiring configs as node graphs. Endpoints include `modules`, `current`, `config`, `apply`, `validate`, `layout`, `to-yaml`, `from-yaml`, and `files`.
|
|
185
|
+
|
|
186
|
+
Per-run resets for clean visuals
|
|
187
|
+
- On each `Run`, the backend clears its event buffer and calls `reset()` on modules if they implement it.
|
|
188
|
+
- The frontend clears visuals/events before posting `/api/run`.
|
|
189
|
+
- To avoid overlapping charts across runs, add `reset()` to modules that accumulate history (e.g., time series points).
|
|
190
|
+
|
|
191
|
+
- Maintainer flow (building the frontend SPA):
|
|
192
|
+
- Edit the React/Vite app under `src/biosim/simui/_frontend/`.
|
|
193
|
+
- Build via Python: `python -m biosim.simui.build` (requires Node/npm). This writes `src/biosim/simui/static/app.js`.
|
|
194
|
+
- Alternatively: `bash scripts/build_simui_frontend.sh`.
|
|
195
|
+
- Packaging includes `src/biosim/simui/static/**`, so end users never need npm.
|
|
196
|
+
|
|
197
|
+
- CI packaging (recommended): run the frontend build before `python -m build` so wheels/sdists ship the bundled assets.
|
|
198
|
+
|
|
199
|
+
Troubleshooting:
|
|
200
|
+
- If you see `SimUI static bundle missing at .../static/app.js`, build the frontend with `python -m biosim.simui.build` (requires Node/npm) before launching. End users installing a release wheel won't see this.
|
|
201
|
+
|
|
202
|
+
### SimUI Design Notes
|
|
203
|
+
- Transport: SSE (Server-Sent Events). The SPA connects to `/api/stream` for real-time updates. Polling endpoints (`/api/status`, `/api/visuals`, `/api/events`) remain available for fallback/debugging.
|
|
204
|
+
- Events API: `/api/events?since_id=<int>&limit=<int>` returns `{ events, next_since_id }` where `events` are appended world events and `next_since_id` is the cursor for subsequent calls.
|
|
205
|
+
- VisualSpec types supported now:
|
|
206
|
+
- `timeseries`: `data = { "series": [{ "name": str, "points": [[x, y], ...] }, ...] }`
|
|
207
|
+
- `bar`: `data = { "items": [{ "label": str, "value": number }, ...] }`
|
|
208
|
+
- `table`: `data = { "columns": [..], "rows": [[..], ...] }` or `data = { "items": [{...}, ...] }`
|
|
209
|
+
- `image`: `data = { "src": str, "alt"?: str, "width"?: number, "height"?: number }`
|
|
210
|
+
- `scatter`: scatter plot data
|
|
211
|
+
- `heatmap`: matrix/heatmap data
|
|
212
|
+
- `graph`: placeholder renderer shows counts + JSON; richer graph lib can be added later
|
|
213
|
+
- `custom:<type>`: custom renderer namespace for user-defined types
|
|
214
|
+
- unknown types: rendered as JSON fallback
|
|
215
|
+
- VisualSpec may also include an optional `description` (string) for hover text or captions.
|
|
216
|
+
|
|
217
|
+
## Terminology
|
|
218
|
+
|
|
219
|
+
Understanding the core concepts is essential for working with biosim effectively.
|
|
220
|
+
|
|
221
|
+
| Term | Description |
|
|
222
|
+
|------|-------------|
|
|
223
|
+
| **BioWorld** | Runtime container that orchestrates multi-rate biomodules, routes signals, and publishes lifecycle events. |
|
|
224
|
+
| **BioModule** | Pluggable unit of behavior with local state. Implements the runnable contract (`setup/reset/advance_to/...`). |
|
|
225
|
+
| **BioSignal** | Typed, versioned data payload exchanged between modules via named ports. |
|
|
226
|
+
| **WorldEvent** | Runtime events emitted by the BioWorld (`STARTED`, `TICK`, `FINISHED`, etc.). |
|
|
227
|
+
| **Wiring** | Module connection graph. Defined programmatically, via `WiringBuilder`, or loaded from YAML/TOML configs. |
|
|
228
|
+
| **VisualSpec** | JSON structure returned by `module.visualize()` with `render` type and `data` payload. |
|
|
229
|
+
|
|
230
|
+
### Event Lifecycle
|
|
231
|
+
|
|
232
|
+
Every simulation follows this sequence:
|
|
233
|
+
```
|
|
234
|
+
STARTED -> TICK (xN) -> FINISHED
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
`PAUSED`, `RESUMED`, `STOPPED`, and `ERROR` may also be emitted depending on runtime control flow.
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT. See `LICENSE.txt`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Public/Internal Boundary
|
|
2
|
+
|
|
3
|
+
`bio-sim` is a public OSS repository.
|
|
4
|
+
|
|
5
|
+
## Allowed (public)
|
|
6
|
+
- Runtime/library source code
|
|
7
|
+
- Technical design docs and API contracts
|
|
8
|
+
- Testing strategy and quality docs
|
|
9
|
+
- Example models/templates intended for public use
|
|
10
|
+
|
|
11
|
+
## Not allowed (internal only)
|
|
12
|
+
- Business cases, pricing, GTM, investor/fundraising content
|
|
13
|
+
- Competitive strategy and commercial forecasts
|
|
14
|
+
- Internal operating procedures and non-public incident reports
|
|
15
|
+
- Secrets, service-account keys, credentials, tokens
|
|
16
|
+
|
|
17
|
+
## Enforcement
|
|
18
|
+
- CI blocks commits containing common business-sensitive terms in docs.
|
|
19
|
+
- CI blocks commits containing detected secrets.
|
|
20
|
+
- Internal planning docs are stored in `biosim-platform`.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# biosim Documentation
|
|
2
|
+
|
|
3
|
+
Welcome to the biosim documentation. This guide explains the core concepts, APIs, and practical wiring patterns for building modular biological simulations.
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- [Overview](overview.md): high-level architecture, core concepts (BioWorld, BioModule, BioSignal, SimUI)
|
|
8
|
+
- [Quickstart](quickstart.md): install, run, and explore
|
|
9
|
+
- API:
|
|
10
|
+
- [BioWorld](bioworld.md): orchestrator, events, run control (pause/resume/stop), signal routing
|
|
11
|
+
- [BioModule](biomodule.md): module interface, lifecycle, port metadata, visualization
|
|
12
|
+
- [Wiring](wiring.md): WiringBuilder, `build_from_spec`, and YAML/TOML loaders
|
|
13
|
+
- [Configuration](config.md): how to write wiring files
|
|
14
|
+
- [Example: Eye → LGN → SC pipeline](brain_pipeline.md)
|
|
15
|
+
- [Neuro packs](neuro.md): computational neuroscience modules (Izhikevich, Hodgkin-Huxley, Poisson input, synapses, monitors) — lives in the companion [`models`](https://github.com/Biosimulant/models) repo
|
|
16
|
+
- [Plugin Development](plugin-development.md): creating and distributing custom biomodules
|
|
17
|
+
|
|
18
|
+
See the files in this folder for a textbook-style walkthrough with code and concrete data examples.
|
|
19
|
+
|
|
20
|
+
## SimUI
|
|
21
|
+
|
|
22
|
+
The biosim core includes a lightweight web UI (SimUI) for running and visualizing simulations. See the [README](../README.md#simui-python-declared-ui) for:
|
|
23
|
+
- Python-declared interface API
|
|
24
|
+
- Full REST + SSE endpoint reference
|
|
25
|
+
- Config editor sub-API for visual wiring editing
|
|
26
|
+
- VisualSpec render types (timeseries, bar, table, image, scatter, heatmap, graph, custom)
|
|
27
|
+
|
|
28
|
+
## Building a single PDF
|
|
29
|
+
- Requirements: `pandoc` and a LaTeX engine (e.g., TeX Live)
|
|
30
|
+
- Status: planned (no `scripts/build_pdf.sh` in this repo yet)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# API: BioModule
|
|
2
|
+
|
|
3
|
+
BioModule encapsulates behavior with local state. It:
|
|
4
|
+
- Implements a runnable contract (`setup/reset/advance_to/...`).
|
|
5
|
+
- Receives inputs via `set_inputs(...)` and emits outputs via `get_outputs()`.
|
|
6
|
+
- Optionally declares connection ports for validation via `inputs()` and `outputs()`.
|
|
7
|
+
|
|
8
|
+
Signature (selected)
|
|
9
|
+
```python
|
|
10
|
+
class BioModule:
|
|
11
|
+
min_dt: float # required positive value (seconds by default), defaults to 0.0
|
|
12
|
+
|
|
13
|
+
def setup(self, config: Optional[Dict[str, Any]] = None) -> None: ...
|
|
14
|
+
def reset(self) -> None: ...
|
|
15
|
+
def advance_to(self, t: float) -> None: ... # abstract
|
|
16
|
+
def set_inputs(self, signals: Dict[str, BioSignal]) -> None: ...
|
|
17
|
+
def get_outputs(self) -> Dict[str, BioSignal]: ... # abstract
|
|
18
|
+
def get_state(self) -> Dict[str, Any]: ...
|
|
19
|
+
def next_due_time(self, now: float) -> float: ... # returns now + min_dt by default
|
|
20
|
+
def inputs(self) -> Set[str]: ...
|
|
21
|
+
def outputs(self) -> Set[str]: ...
|
|
22
|
+
def input_schemas(self) -> Dict[str, Any]: ... # optional, for future tooling
|
|
23
|
+
def output_schemas(self) -> Dict[str, Any]: ... # optional, for future tooling
|
|
24
|
+
def visualize(self) -> Optional[VisualSpec | List[VisualSpec]]: ...
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Notes:
|
|
28
|
+
- `advance_to` and `get_outputs` are abstract (must be implemented).
|
|
29
|
+
- `setup` receives an optional config dict (per-module section from the world config), not the BioWorld instance.
|
|
30
|
+
- `next_due_time` returns `float` (not Optional); default implementation is `now + min_dt`.
|
|
31
|
+
- `input_schemas`/`output_schemas` return port-name-to-schema mappings; currently unused but reserved for future validation.
|
|
32
|
+
- `visualize` returns a VisualSpec dict or list of dicts for browser rendering (see README VisualSpec types).
|
|
33
|
+
|
|
34
|
+
Example with local state
|
|
35
|
+
```python
|
|
36
|
+
class Eye(biosim.BioModule):
|
|
37
|
+
min_dt = 0.01
|
|
38
|
+
|
|
39
|
+
def __init__(self):
|
|
40
|
+
self.photons_seen = 0
|
|
41
|
+
|
|
42
|
+
def outputs(self):
|
|
43
|
+
return {"visual_stream"}
|
|
44
|
+
|
|
45
|
+
def advance_to(self, t: float) -> None:
|
|
46
|
+
self.photons_seen += 1
|
|
47
|
+
|
|
48
|
+
def get_outputs(self):
|
|
49
|
+
source = getattr(self, "_world_name", "eye")
|
|
50
|
+
return {
|
|
51
|
+
"visual_stream": biosim.BioSignal(
|
|
52
|
+
source=source,
|
|
53
|
+
name="visual_stream",
|
|
54
|
+
value={"count": self.photons_seen},
|
|
55
|
+
time=0.0,
|
|
56
|
+
metadata=biosim.SignalMetadata(units="1"),
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Typical values at runtime
|
|
62
|
+
- `t` -> current world time (float)
|
|
63
|
+
- `self.photons_seen` after two ticks -> `2`
|