viva-munk 0.0.2__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.
- viva_munk-0.0.2/LICENSE +21 -0
- viva_munk-0.0.2/PKG-INFO +153 -0
- viva_munk-0.0.2/README.md +120 -0
- viva_munk-0.0.2/pyproject.toml +81 -0
- viva_munk-0.0.2/setup.cfg +4 -0
- viva_munk-0.0.2/viva_munk/__init__.py +174 -0
- viva_munk-0.0.2/viva_munk/composites/__init__.py +104 -0
- viva_munk-0.0.2/viva_munk/core.py +5 -0
- viva_munk-0.0.2/viva_munk/experiments/cli.py +105 -0
- viva_munk-0.0.2/viva_munk/experiments/documents/__init__.py +27 -0
- viva_munk-0.0.2/viva_munk/experiments/documents/attachment.py +122 -0
- viva_munk-0.0.2/viva_munk/experiments/documents/bending_pressure.py +119 -0
- viva_munk-0.0.2/viva_munk/experiments/documents/biofilm.py +86 -0
- viva_munk-0.0.2/viva_munk/experiments/documents/chemotaxis.py +174 -0
- viva_munk-0.0.2/viva_munk/experiments/documents/daughter_machine.py +92 -0
- viva_munk-0.0.2/viva_munk/experiments/documents/glucose_growth.py +143 -0
- viva_munk-0.0.2/viva_munk/experiments/documents/inclusion_bodies.py +143 -0
- viva_munk-0.0.2/viva_munk/experiments/documents/mother_machine.py +132 -0
- viva_munk-0.0.2/viva_munk/experiments/documents/quorum_sensing.py +241 -0
- viva_munk-0.0.2/viva_munk/experiments/registry.py +373 -0
- viva_munk-0.0.2/viva_munk/experiments/replay.py +107 -0
- viva_munk-0.0.2/viva_munk/experiments/report.py +429 -0
- viva_munk-0.0.2/viva_munk/experiments/runner.py +488 -0
- viva_munk-0.0.2/viva_munk/experiments/test_suite.py +58 -0
- viva_munk-0.0.2/viva_munk/plots/__init__.py +0 -0
- viva_munk-0.0.2/viva_munk/plots/multibody_plots.py +874 -0
- viva_munk-0.0.2/viva_munk/processes/__init__.py +0 -0
- viva_munk-0.0.2/viva_munk/processes/cell_field_exchange.py +201 -0
- viva_munk-0.0.2/viva_munk/processes/chemotaxis.py +204 -0
- viva_munk-0.0.2/viva_munk/processes/diffusion_advection.py +412 -0
- viva_munk-0.0.2/viva_munk/processes/field_decay.py +61 -0
- viva_munk-0.0.2/viva_munk/processes/grow_divide.py +533 -0
- viva_munk-0.0.2/viva_munk/processes/inclusion_body.py +267 -0
- viva_munk-0.0.2/viva_munk/processes/multibody.py +1163 -0
- viva_munk-0.0.2/viva_munk/processes/pressure.py +125 -0
- viva_munk-0.0.2/viva_munk/processes/quorum_sensing.py +137 -0
- viva_munk-0.0.2/viva_munk/processes/remove_crossing.py +99 -0
- viva_munk-0.0.2/viva_munk/processes/secrete_eps.py +169 -0
- viva_munk-0.0.2/viva_munk/pymunk_agent_type.py +286 -0
- viva_munk-0.0.2/viva_munk/types/__init__.py +16 -0
- viva_munk-0.0.2/viva_munk/types/positive.py +139 -0
- viva_munk-0.0.2/viva_munk/visualizations/__init__.py +412 -0
- viva_munk-0.0.2/viva_munk/visualizations/cell_mass_traces.py +172 -0
- viva_munk-0.0.2/viva_munk.egg-info/PKG-INFO +153 -0
- viva_munk-0.0.2/viva_munk.egg-info/SOURCES.txt +46 -0
- viva_munk-0.0.2/viva_munk.egg-info/dependency_links.txt +1 -0
- viva_munk-0.0.2/viva_munk.egg-info/requires.txt +15 -0
- viva_munk-0.0.2/viva_munk.egg-info/top_level.txt +1 -0
viva_munk-0.0.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eran Agmon, Ryan Spangler
|
|
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.
|
viva_munk-0.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: viva-munk
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: multi-cell simulations with pymunk 2d physics
|
|
5
|
+
Author: Ryan Spangler
|
|
6
|
+
Author-email: Eran Agmon <agmon.eran@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/vivarium-collective/Viva-munk
|
|
9
|
+
Project-URL: Repository, https://github.com/vivarium-collective/Viva-munk
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: process-bigraph
|
|
19
|
+
Requires-Dist: bigraph-schema>=0.0.60
|
|
20
|
+
Requires-Dist: bigraph-viz
|
|
21
|
+
Requires-Dist: pymunk
|
|
22
|
+
Requires-Dist: numpy
|
|
23
|
+
Requires-Dist: matplotlib
|
|
24
|
+
Requires-Dist: Pillow
|
|
25
|
+
Requires-Dist: plum-dispatch
|
|
26
|
+
Requires-Dist: pbg-superpowers
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest; extra == "dev"
|
|
29
|
+
Requires-Dist: ipdb; extra == "dev"
|
|
30
|
+
Requires-Dist: build; extra == "dev"
|
|
31
|
+
Requires-Dist: twine>=4.0.2; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# viva-munk
|
|
35
|
+
|
|
36
|
+
[](https://pypi.org/project/viva-munk/)
|
|
37
|
+
[](https://pypi.org/project/viva-munk/)
|
|
38
|
+
[](LICENSE)
|
|
39
|
+
|
|
40
|
+
Multi-cell simulations with 2D physics, built on [process-bigraph](https://github.com/vivarium-collective/process-bigraph) and [pymunk](https://www.pymunk.org/).
|
|
41
|
+
|
|
42
|
+
### **[Demos](https://vivarium-collective.github.io/Viva-munk/)**
|
|
43
|
+
|
|
44
|
+
## Goal
|
|
45
|
+
|
|
46
|
+
Provide a composable framework for simulating populations of growing, dividing cells with realistic 2D physics and shared chemical environments. Cells are modeled as capsule-shaped rigid bodies (pymunk segments) — or as multi-segment compound bodies that can flex and bend — that grow, divide, secrete particles, attach to surfaces, and interact physically through collisions and confinement. Concentration fields are modeled with a finite-difference diffusion process and coupled to cells through a per-tick exchange step. The framework uses the bigraph process architecture, making it easy to compose new cell behaviors, environmental structures, and analysis pipelines.
|
|
47
|
+
|
|
48
|
+
Default parameters are calibrated to *E. coli* proportions (~1 μm wide, ~2 μm at birth, ~4 μm at division, ~30–40 min doubling time).
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
Requires Python 3.11+.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install viva-munk
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
To use as a library:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from viva_munk import core_import
|
|
62
|
+
from process_bigraph import Composite
|
|
63
|
+
|
|
64
|
+
core = core_import() # registers viva_munk types and processes
|
|
65
|
+
# ... build a spec dict and run: Composite(spec, core=core)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Quick Start
|
|
69
|
+
|
|
70
|
+
Run the full experiment suite and generate the HTML report:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone https://github.com/vivarium-collective/Viva-munk.git
|
|
74
|
+
cd Viva-munk
|
|
75
|
+
pip install -e .[dev]
|
|
76
|
+
|
|
77
|
+
# Run all experiments and open the HTML report
|
|
78
|
+
python -m viva_munk.experiments.test_suite
|
|
79
|
+
|
|
80
|
+
# Run without auto-opening the browser
|
|
81
|
+
python -m viva_munk.experiments.test_suite --no-open
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Architecture
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
viva_munk/
|
|
88
|
+
pymunk_agent_type.py # Custom PymunkAgent type with optimized dispatch
|
|
89
|
+
types/
|
|
90
|
+
positive.py # PositiveFloat / PositiveArray / Concentration / SetFloat
|
|
91
|
+
processes/
|
|
92
|
+
multibody.py # PymunkProcess — 2D physics (rigid + bending cells)
|
|
93
|
+
grow_divide.py # GrowDivide — exponential growth, division, mutation
|
|
94
|
+
pressure.py # Pressure — vectorized per-cell mechanical pressure
|
|
95
|
+
diffusion_advection.py # DiffusionAdvection — 2D field diffusion + advection
|
|
96
|
+
cell_field_exchange.py # CellFieldExchange — cell ↔ field uptake/secretion
|
|
97
|
+
secrete_eps.py # SecreteEPS — EPS particle secretion
|
|
98
|
+
remove_crossing.py # RemoveCrossing — remove cells past a boundary
|
|
99
|
+
plots/
|
|
100
|
+
multibody_plots.py # GIF rendering with phylogeny / pressure coloring
|
|
101
|
+
# and concentration-field heatmap overlays
|
|
102
|
+
experiments/
|
|
103
|
+
test_suite.py # Experiment registry, runner, HTML report generator
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Processes
|
|
107
|
+
|
|
108
|
+
- **PymunkProcess** (Process): Manages the pymunk 2D physics space. Handles three kinds of agents — rigid segment cells, multi-segment bending cells (compound bodies linked by pivot joints + damped rotary springs), and circular particles. Syncs state to bodies, steps the physics with sub-stepping, applies damping/jitter, optionally enforces adhesion to a wall, and emits position/velocity/polyline deltas.
|
|
109
|
+
- **GrowDivide** (Process): Per-cell exponential mass growth. Optionally gated by a Monod factor on a local nutrient (`local[nutrient_key]`) and inhibited by mechanical pressure (`exp(-pressure / pressure_k)`). When mass exceeds a threshold, the cell divides into two daughters along its axis; daughters can inherit mutated parameters and (for bending cells) a fresh straight polyline so they don't inherit the mother's pose.
|
|
110
|
+
- **Pressure** (Step): Computes a per-cell mechanical pressure proxy from cell-cell and cell-wall overlap depths (vectorized via numpy). Written back to each cell's `pressure` field for downstream consumers.
|
|
111
|
+
- **DiffusionAdvection** (Process): Explicit FTCS diffusion + upwind advection on a 2D `map[mol_id → array]` field, with ghost-layer boundary conditions (periodic / neumann / dirichlet / dirichlet_ghost).
|
|
112
|
+
- **CellFieldExchange** (Process): Couples `pymunk_agent` cells to a 2D field map. Each tick it samples each cell's local field concentration into `cell.local`, and applies each cell's `cell.exchange` amounts back into the corresponding field bin (Δconcentration = Δamount / bin_volume).
|
|
113
|
+
- **SecreteEPS** (Process): Per-cell EPS particle secretion at a rate proportional to cell mass. Particles are placed on the cell surface and added to the environment. Optionally gated to attached cells only.
|
|
114
|
+
- **RemoveCrossing** (Step): Removes any cell whose position exceeds a configurable x/y boundary. Used to model the flow channel in mother-machine experiments.
|
|
115
|
+
|
|
116
|
+
### Custom types
|
|
117
|
+
|
|
118
|
+
`pymunk_agent` is a `Node`-subclass type with hand-optimized `apply`/`reconcile`/`realize`/`check` dispatch (no per-field plum dispatch on the hot path). It carries the geometric and physical state of one cell (mass, radius, length, location, velocity, …) plus optional fields used by downstream processes (`polyline`, `attached`, `pressure`, `local`, `exchange`).
|
|
119
|
+
|
|
120
|
+
The `viva_munk.types.positive` module provides minimal `PositiveFloat`, `PositiveArray`, `Concentration`, and `SetFloat` types for the field state, accumulator-with-clamp semantics adapted from [spatio-flux](https://github.com/vivarium-collective/spatio-flux).
|
|
121
|
+
|
|
122
|
+
## Experiments
|
|
123
|
+
|
|
124
|
+
The current registry (`viva_munk/experiments/test_suite.py`):
|
|
125
|
+
|
|
126
|
+
- **daughter_machine** — single cell grows in an open chamber with an absorbing right wall.
|
|
127
|
+
- **mother_machine** — narrow dead-end channels (~1.5 μm wide); cells grow vertically and are removed when they reach the flow channel.
|
|
128
|
+
- **with_particles** — cells grow in a chamber seeded with passive particles; cells push and rearrange them.
|
|
129
|
+
- **attachment** — adhesin-bearing cells attach to the bottom surface via PivotJoints; adhesins split between daughters at division.
|
|
130
|
+
- **glucose_growth** — cells on a 2D glucose field. `DiffusionAdvection` spreads glucose, `CellFieldExchange` applies cell consumption every tick, and `GrowDivide` gates rate by Monod kinetics. Cells stop dividing once their local patch is depleted.
|
|
131
|
+
- **bending_pressure** — multi-segment bending capsules grow into a colony. `Pressure` computes mechanical pressure from neighbor / wall contacts and `GrowDivide` applies `exp(-pressure / pressure_k)` inhibition. Cells visibly bend AND slow.
|
|
132
|
+
- **chemotaxis** — twelve non-growing cells run/tumble up a static exponential ligand gradient in a long chamber. Each cell maintains a memory of its local concentration and modulates tumble rate as `λ = λ₀ · exp(-k · dc/dt)`.
|
|
133
|
+
- **inclusion_bodies** — a colony grows while each cell accumulates an inclusion-body aggregate (size in nm, logistic growth toward an 800 nm plateau). Aggregation inhibits growth; at division the IB is transferred entirely to one daughter so the IB-free sibling out-grows the laden one. Cells are soft bending capsules and a `Pressure` step adds a second slowdown as the colony packs. Colored by IB size.
|
|
134
|
+
|
|
135
|
+
`test_suite.py` runs each one, captures a GIF, a bigraph composition viz, and a serialized state JSON, and generates an HTML report (`out/report.html`) with timing, cell counts, descriptions, and embedded media.
|
|
136
|
+
|
|
137
|
+
## Dependencies
|
|
138
|
+
|
|
139
|
+
- [process-bigraph](https://github.com/vivarium-collective/process-bigraph) — bigraph process framework
|
|
140
|
+
- [bigraph-schema](https://github.com/vivarium-collective/bigraph-schema) — typed schemas (via process-bigraph)
|
|
141
|
+
- [bigraph-viz](https://github.com/vivarium-collective/bigraph-viz) — bigraph visualization
|
|
142
|
+
- [pymunk](https://www.pymunk.org/) — 2D physics engine
|
|
143
|
+
- numpy, matplotlib, Pillow, plum-dispatch
|
|
144
|
+
|
|
145
|
+
## Releasing
|
|
146
|
+
|
|
147
|
+
Releases are cut from `main` via `./release.sh`, which bumps the patch
|
|
148
|
+
version in `pyproject.toml`, commits + tags `vX.Y.Z`, pushes the tag, builds
|
|
149
|
+
sdist + wheel, and publishes to PyPI (token at `~/.pypi-token`).
|
|
150
|
+
|
|
151
|
+
## License
|
|
152
|
+
|
|
153
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# viva-munk
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/viva-munk/)
|
|
4
|
+
[](https://pypi.org/project/viva-munk/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Multi-cell simulations with 2D physics, built on [process-bigraph](https://github.com/vivarium-collective/process-bigraph) and [pymunk](https://www.pymunk.org/).
|
|
8
|
+
|
|
9
|
+
### **[Demos](https://vivarium-collective.github.io/Viva-munk/)**
|
|
10
|
+
|
|
11
|
+
## Goal
|
|
12
|
+
|
|
13
|
+
Provide a composable framework for simulating populations of growing, dividing cells with realistic 2D physics and shared chemical environments. Cells are modeled as capsule-shaped rigid bodies (pymunk segments) — or as multi-segment compound bodies that can flex and bend — that grow, divide, secrete particles, attach to surfaces, and interact physically through collisions and confinement. Concentration fields are modeled with a finite-difference diffusion process and coupled to cells through a per-tick exchange step. The framework uses the bigraph process architecture, making it easy to compose new cell behaviors, environmental structures, and analysis pipelines.
|
|
14
|
+
|
|
15
|
+
Default parameters are calibrated to *E. coli* proportions (~1 μm wide, ~2 μm at birth, ~4 μm at division, ~30–40 min doubling time).
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Requires Python 3.11+.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install viva-munk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
To use as a library:
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from viva_munk import core_import
|
|
29
|
+
from process_bigraph import Composite
|
|
30
|
+
|
|
31
|
+
core = core_import() # registers viva_munk types and processes
|
|
32
|
+
# ... build a spec dict and run: Composite(spec, core=core)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
Run the full experiment suite and generate the HTML report:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/vivarium-collective/Viva-munk.git
|
|
41
|
+
cd Viva-munk
|
|
42
|
+
pip install -e .[dev]
|
|
43
|
+
|
|
44
|
+
# Run all experiments and open the HTML report
|
|
45
|
+
python -m viva_munk.experiments.test_suite
|
|
46
|
+
|
|
47
|
+
# Run without auto-opening the browser
|
|
48
|
+
python -m viva_munk.experiments.test_suite --no-open
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Architecture
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
viva_munk/
|
|
55
|
+
pymunk_agent_type.py # Custom PymunkAgent type with optimized dispatch
|
|
56
|
+
types/
|
|
57
|
+
positive.py # PositiveFloat / PositiveArray / Concentration / SetFloat
|
|
58
|
+
processes/
|
|
59
|
+
multibody.py # PymunkProcess — 2D physics (rigid + bending cells)
|
|
60
|
+
grow_divide.py # GrowDivide — exponential growth, division, mutation
|
|
61
|
+
pressure.py # Pressure — vectorized per-cell mechanical pressure
|
|
62
|
+
diffusion_advection.py # DiffusionAdvection — 2D field diffusion + advection
|
|
63
|
+
cell_field_exchange.py # CellFieldExchange — cell ↔ field uptake/secretion
|
|
64
|
+
secrete_eps.py # SecreteEPS — EPS particle secretion
|
|
65
|
+
remove_crossing.py # RemoveCrossing — remove cells past a boundary
|
|
66
|
+
plots/
|
|
67
|
+
multibody_plots.py # GIF rendering with phylogeny / pressure coloring
|
|
68
|
+
# and concentration-field heatmap overlays
|
|
69
|
+
experiments/
|
|
70
|
+
test_suite.py # Experiment registry, runner, HTML report generator
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Processes
|
|
74
|
+
|
|
75
|
+
- **PymunkProcess** (Process): Manages the pymunk 2D physics space. Handles three kinds of agents — rigid segment cells, multi-segment bending cells (compound bodies linked by pivot joints + damped rotary springs), and circular particles. Syncs state to bodies, steps the physics with sub-stepping, applies damping/jitter, optionally enforces adhesion to a wall, and emits position/velocity/polyline deltas.
|
|
76
|
+
- **GrowDivide** (Process): Per-cell exponential mass growth. Optionally gated by a Monod factor on a local nutrient (`local[nutrient_key]`) and inhibited by mechanical pressure (`exp(-pressure / pressure_k)`). When mass exceeds a threshold, the cell divides into two daughters along its axis; daughters can inherit mutated parameters and (for bending cells) a fresh straight polyline so they don't inherit the mother's pose.
|
|
77
|
+
- **Pressure** (Step): Computes a per-cell mechanical pressure proxy from cell-cell and cell-wall overlap depths (vectorized via numpy). Written back to each cell's `pressure` field for downstream consumers.
|
|
78
|
+
- **DiffusionAdvection** (Process): Explicit FTCS diffusion + upwind advection on a 2D `map[mol_id → array]` field, with ghost-layer boundary conditions (periodic / neumann / dirichlet / dirichlet_ghost).
|
|
79
|
+
- **CellFieldExchange** (Process): Couples `pymunk_agent` cells to a 2D field map. Each tick it samples each cell's local field concentration into `cell.local`, and applies each cell's `cell.exchange` amounts back into the corresponding field bin (Δconcentration = Δamount / bin_volume).
|
|
80
|
+
- **SecreteEPS** (Process): Per-cell EPS particle secretion at a rate proportional to cell mass. Particles are placed on the cell surface and added to the environment. Optionally gated to attached cells only.
|
|
81
|
+
- **RemoveCrossing** (Step): Removes any cell whose position exceeds a configurable x/y boundary. Used to model the flow channel in mother-machine experiments.
|
|
82
|
+
|
|
83
|
+
### Custom types
|
|
84
|
+
|
|
85
|
+
`pymunk_agent` is a `Node`-subclass type with hand-optimized `apply`/`reconcile`/`realize`/`check` dispatch (no per-field plum dispatch on the hot path). It carries the geometric and physical state of one cell (mass, radius, length, location, velocity, …) plus optional fields used by downstream processes (`polyline`, `attached`, `pressure`, `local`, `exchange`).
|
|
86
|
+
|
|
87
|
+
The `viva_munk.types.positive` module provides minimal `PositiveFloat`, `PositiveArray`, `Concentration`, and `SetFloat` types for the field state, accumulator-with-clamp semantics adapted from [spatio-flux](https://github.com/vivarium-collective/spatio-flux).
|
|
88
|
+
|
|
89
|
+
## Experiments
|
|
90
|
+
|
|
91
|
+
The current registry (`viva_munk/experiments/test_suite.py`):
|
|
92
|
+
|
|
93
|
+
- **daughter_machine** — single cell grows in an open chamber with an absorbing right wall.
|
|
94
|
+
- **mother_machine** — narrow dead-end channels (~1.5 μm wide); cells grow vertically and are removed when they reach the flow channel.
|
|
95
|
+
- **with_particles** — cells grow in a chamber seeded with passive particles; cells push and rearrange them.
|
|
96
|
+
- **attachment** — adhesin-bearing cells attach to the bottom surface via PivotJoints; adhesins split between daughters at division.
|
|
97
|
+
- **glucose_growth** — cells on a 2D glucose field. `DiffusionAdvection` spreads glucose, `CellFieldExchange` applies cell consumption every tick, and `GrowDivide` gates rate by Monod kinetics. Cells stop dividing once their local patch is depleted.
|
|
98
|
+
- **bending_pressure** — multi-segment bending capsules grow into a colony. `Pressure` computes mechanical pressure from neighbor / wall contacts and `GrowDivide` applies `exp(-pressure / pressure_k)` inhibition. Cells visibly bend AND slow.
|
|
99
|
+
- **chemotaxis** — twelve non-growing cells run/tumble up a static exponential ligand gradient in a long chamber. Each cell maintains a memory of its local concentration and modulates tumble rate as `λ = λ₀ · exp(-k · dc/dt)`.
|
|
100
|
+
- **inclusion_bodies** — a colony grows while each cell accumulates an inclusion-body aggregate (size in nm, logistic growth toward an 800 nm plateau). Aggregation inhibits growth; at division the IB is transferred entirely to one daughter so the IB-free sibling out-grows the laden one. Cells are soft bending capsules and a `Pressure` step adds a second slowdown as the colony packs. Colored by IB size.
|
|
101
|
+
|
|
102
|
+
`test_suite.py` runs each one, captures a GIF, a bigraph composition viz, and a serialized state JSON, and generates an HTML report (`out/report.html`) with timing, cell counts, descriptions, and embedded media.
|
|
103
|
+
|
|
104
|
+
## Dependencies
|
|
105
|
+
|
|
106
|
+
- [process-bigraph](https://github.com/vivarium-collective/process-bigraph) — bigraph process framework
|
|
107
|
+
- [bigraph-schema](https://github.com/vivarium-collective/bigraph-schema) — typed schemas (via process-bigraph)
|
|
108
|
+
- [bigraph-viz](https://github.com/vivarium-collective/bigraph-viz) — bigraph visualization
|
|
109
|
+
- [pymunk](https://www.pymunk.org/) — 2D physics engine
|
|
110
|
+
- numpy, matplotlib, Pillow, plum-dispatch
|
|
111
|
+
|
|
112
|
+
## Releasing
|
|
113
|
+
|
|
114
|
+
Releases are cut from `main` via `./release.sh`, which bumps the patch
|
|
115
|
+
version in `pyproject.toml`, commits + tags `vX.Y.Z`, pushes the tag, builds
|
|
116
|
+
sdist + wheel, and publishes to PyPI (token at `~/.pypi-token`).
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "viva-munk"
|
|
7
|
+
version = "0.0.2"
|
|
8
|
+
description = "multi-cell simulations with pymunk 2d physics"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Eran Agmon", email = "agmon.eran@gmail.com"},
|
|
14
|
+
{name = "Ryan Spangler"},
|
|
15
|
+
]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"process-bigraph",
|
|
25
|
+
"bigraph-schema>=0.0.60",
|
|
26
|
+
"bigraph-viz",
|
|
27
|
+
"pymunk",
|
|
28
|
+
"numpy",
|
|
29
|
+
"matplotlib",
|
|
30
|
+
"Pillow",
|
|
31
|
+
"plum-dispatch",
|
|
32
|
+
# viva_munk/visualizations/* subclass pbg_superpowers.visualization.Visualization.
|
|
33
|
+
"pbg-superpowers",
|
|
34
|
+
# NOTE on spatio-flux: viva_munk/__init__.py imports
|
|
35
|
+
# `from spatio_flux.visualizations import (...)` at module-import
|
|
36
|
+
# time, but no PyPI-published spatio-flux release ships a
|
|
37
|
+
# `visualizations/` submodule (it was dropped in 1.4 in favour of
|
|
38
|
+
# `plots/`; the dev 1.0.0 still has it but is not on PyPI). Listing
|
|
39
|
+
# `spatio-flux` here would let pip install succeed but the import
|
|
40
|
+
# would still fail. Tracked separately: either refactor viva_munk's
|
|
41
|
+
# __init__ to use spatio_flux.plots, vendor what we need, or
|
|
42
|
+
# publish a 1.0.x patch with the legacy visualizations layout.
|
|
43
|
+
# Until then, viva-munk is installable only against a local
|
|
44
|
+
# editable spatio-flux checkout that has visualizations/.
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.optional-dependencies]
|
|
48
|
+
dev = [
|
|
49
|
+
"pytest",
|
|
50
|
+
"ipdb",
|
|
51
|
+
"build",
|
|
52
|
+
"twine>=4.0.2",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[project.urls]
|
|
56
|
+
Homepage = "https://github.com/vivarium-collective/Viva-munk"
|
|
57
|
+
Repository = "https://github.com/vivarium-collective/Viva-munk"
|
|
58
|
+
|
|
59
|
+
# Auto-discover every viva_munk subpackage at build time. The hand-
|
|
60
|
+
# maintained list previously skipped `viva_munk.composites` AND
|
|
61
|
+
# `viva_munk.visualizations`, so the published wheel didn't include
|
|
62
|
+
# those directories at all and `import viva_munk` broke on any clean
|
|
63
|
+
# install (the package's own __init__.py imports them). The
|
|
64
|
+
# auto-discovery pattern matches what spatio-flux does.
|
|
65
|
+
[tool.setuptools.packages.find]
|
|
66
|
+
where = ["."]
|
|
67
|
+
include = ["viva_munk*"]
|
|
68
|
+
exclude = ["tests*", "docs*", "studies*"]
|
|
69
|
+
|
|
70
|
+
# NOTE: this package previously declared a [tool.uv.sources] override
|
|
71
|
+
# pointing process-bigraph at `../process-bigraph` (editable). That
|
|
72
|
+
# section is dev-only convenience for working in a sibling checkout
|
|
73
|
+
# layout — but it leaks into downstream consumers when viva-munk is
|
|
74
|
+
# pulled as a git dependency, because uv resolves the transitive
|
|
75
|
+
# source path as `subdirectory=../process-bigraph` of the git URL,
|
|
76
|
+
# which doesn't exist. Removed for now; if you need the local
|
|
77
|
+
# editable checkout, install it explicitly:
|
|
78
|
+
#
|
|
79
|
+
# pip install -e ../process-bigraph
|
|
80
|
+
#
|
|
81
|
+
# or add the override in YOUR project's pyproject.toml (not here).
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Registration-related functions
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
__version__ = "0.0.1"
|
|
6
|
+
|
|
7
|
+
from process_bigraph import register_types as pb_register_types
|
|
8
|
+
from process_bigraph.types.process import register_types as pb_types_register
|
|
9
|
+
from process_bigraph.composite import Composite
|
|
10
|
+
from process_bigraph.emitter import RAMEmitter, SQLiteEmitter
|
|
11
|
+
from bigraph_schema.core import Core, BASE_TYPES
|
|
12
|
+
from bigraph_viz import register_types as viz_register_types
|
|
13
|
+
|
|
14
|
+
from viva_munk.processes.multibody import PymunkProcess
|
|
15
|
+
from viva_munk.processes.grow_divide import GrowDivide, AdderGrowDivide
|
|
16
|
+
from viva_munk.processes.remove_crossing import RemoveCrossing
|
|
17
|
+
from viva_munk.processes.secrete_eps import SecreteEPS
|
|
18
|
+
from viva_munk.processes.pressure import Pressure
|
|
19
|
+
from viva_munk.processes.diffusion_advection import DiffusionAdvection
|
|
20
|
+
from viva_munk.processes.cell_field_exchange import CellFieldExchange
|
|
21
|
+
from viva_munk.processes.chemotaxis import Chemotaxis
|
|
22
|
+
from viva_munk.processes.inclusion_body import InclusionBody, IBColony
|
|
23
|
+
from viva_munk.processes.quorum_sensing import QuorumSensing
|
|
24
|
+
from viva_munk.processes.field_decay import FieldDecay
|
|
25
|
+
# Spatio-flux processes referenced by spatio_flux.composites.particles.* —
|
|
26
|
+
# brownian_particles needs both BrownianMovement and ManageBoundaries to
|
|
27
|
+
# resolve their `local:` addresses at run time.
|
|
28
|
+
from spatio_flux.processes.particles import BrownianMovement, ManageBoundaries
|
|
29
|
+
# Spatio-flux Visualization Steps — heatmaps, GIFs, snapshot grids, and
|
|
30
|
+
# emitter-driven timeseries. Registered so dashboard users can attach them
|
|
31
|
+
# to any composite via the Visualizations tab.
|
|
32
|
+
from spatio_flux.visualizations import (
|
|
33
|
+
FieldHeatmap,
|
|
34
|
+
FieldAnimationGif,
|
|
35
|
+
FieldSnapshotsGrid,
|
|
36
|
+
ParticleTraces,
|
|
37
|
+
TestSuiteTimeSeries,
|
|
38
|
+
)
|
|
39
|
+
from viva_munk.pymunk_agent_type import PymunkAgent, register_pymunk_agent_dispatches
|
|
40
|
+
from viva_munk.types import positive_types
|
|
41
|
+
from viva_munk.visualizations import MultibodyVizStep, CellMassTraces
|
|
42
|
+
|
|
43
|
+
# Register custom dispatches once at module import
|
|
44
|
+
register_pymunk_agent_dispatches()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _patch_composite_realize_on_sentinels():
|
|
48
|
+
"""Ensure Composite re-realizes newly-added subtrees on `_add`/`_remove`.
|
|
49
|
+
|
|
50
|
+
`Map.apply` drops `_add` entries straight into state without calling
|
|
51
|
+
the value type's realize path, and `Composite.apply_updates` only
|
|
52
|
+
triggers `core.realize` on schema-level merges — not on structural
|
|
53
|
+
sentinels. So embedded process specs (e.g. `grow_divide` on a freshly
|
|
54
|
+
divided daughter) are never instantiated: the spec is visible in
|
|
55
|
+
state but its `'instance'` slot stays unset and the Process class
|
|
56
|
+
never runs on that cell. Result: lineages freeze after the first
|
|
57
|
+
division in every experiment that uses per-cell embedded processes.
|
|
58
|
+
|
|
59
|
+
The fix is a one-line amend: when structural sentinels are detected,
|
|
60
|
+
run `core.realize` (which follows `Link`/process specs and creates
|
|
61
|
+
instances via `realize_link`) before `find_instance_paths` scans
|
|
62
|
+
state for them.
|
|
63
|
+
"""
|
|
64
|
+
_original_apply_updates = Composite.apply_updates
|
|
65
|
+
|
|
66
|
+
def apply_updates_with_realize(self, updates):
|
|
67
|
+
update_paths = _original_apply_updates(self, updates)
|
|
68
|
+
if getattr(self, '_last_apply_structural', False):
|
|
69
|
+
# bigraph_schema.core.realize now returns a 3-tuple
|
|
70
|
+
# (schema, state, escape_merges). At top-level realize there
|
|
71
|
+
# is nothing above us for merges to escape to, so discard.
|
|
72
|
+
self.schema, self.state, _escape_merges = self.core.realize(
|
|
73
|
+
self.schema, self.state)
|
|
74
|
+
self.find_instance_paths(self.state)
|
|
75
|
+
self._build_view_project_cache()
|
|
76
|
+
return update_paths
|
|
77
|
+
|
|
78
|
+
Composite.apply_updates = apply_updates_with_realize
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
_patch_composite_realize_on_sentinels()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _patch_list_apply_tuple_update():
|
|
85
|
+
"""Make ``apply(schema: List, state: list, update: tuple)`` do
|
|
86
|
+
element-wise add when shape + numeric content match.
|
|
87
|
+
|
|
88
|
+
JSON serialization drops the tuple type, so a state that started as a
|
|
89
|
+
``(x, y)`` tuple becomes a ``[x, y]`` list and schema inference picks
|
|
90
|
+
``List(_element=Float)`` instead of ``Tuple(_values=[Float, Float])``.
|
|
91
|
+
The default ``apply(List)`` then does ``state + update`` — concat, not
|
|
92
|
+
element-wise — and crashes on the ``list + tuple`` type mismatch the
|
|
93
|
+
moment a process emits a tuple delta (``PymunkProcess`` does this for
|
|
94
|
+
``location``/``velocity`` every tick). Pin element-wise behavior for
|
|
95
|
+
the JSON-roundtripped case so the dashboard's subprocess flow works.
|
|
96
|
+
"""
|
|
97
|
+
from plum import dispatch
|
|
98
|
+
from bigraph_schema.schema import List
|
|
99
|
+
from bigraph_schema.methods.apply import apply as _apply
|
|
100
|
+
|
|
101
|
+
@_apply.dispatch
|
|
102
|
+
def apply_list_with_tuple_update(schema: List, state: list, update: tuple, path):
|
|
103
|
+
if len(state) == len(update) and all(
|
|
104
|
+
isinstance(s, (int, float)) for s in state
|
|
105
|
+
):
|
|
106
|
+
return [s + u for s, u in zip(state, update)], []
|
|
107
|
+
# Length mismatch or non-numeric: fall back to concat (matches
|
|
108
|
+
# the default ``state + list(update)`` semantics).
|
|
109
|
+
return list(state) + list(update), []
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
_patch_list_apply_tuple_update()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
from viva_munk import composites as _composites # noqa: E402,F401 — fires @composite_generator side-effects
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def register_pymunk_types(core):
|
|
119
|
+
# Use the optimized PymunkAgent Node subclass instead of a dict schema.
|
|
120
|
+
# This eliminates per-field dispatch overhead in apply/reconcile/realize.
|
|
121
|
+
core.register_type('pymunk_agent', PymunkAgent())
|
|
122
|
+
# NOTE: viva_munk.types.positive_types overlaps with spatio_flux's on
|
|
123
|
+
# ('positive_float', 'positive_array', 'concentration', 'set_float') —
|
|
124
|
+
# viva_munk uses instances (PositiveFloat()), spatio_flux uses classes
|
|
125
|
+
# (PositiveFloat). Registering both forms triggers a resolve conflict in
|
|
126
|
+
# bigraph_schema. spatio_flux's set is a strict superset (adds count,
|
|
127
|
+
# mass, delta_conc), so we let spatio_flux_register_types own these
|
|
128
|
+
# types in core_import() and skip the duplicate loop here.
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def register_processes(core):
|
|
132
|
+
core.register_link('PymunkProcess', PymunkProcess)
|
|
133
|
+
core.register_link('GrowDivide', GrowDivide)
|
|
134
|
+
core.register_link('AdderGrowDivide', AdderGrowDivide)
|
|
135
|
+
core.register_link('RemoveCrossing', RemoveCrossing)
|
|
136
|
+
core.register_link('SecreteEPS', SecreteEPS)
|
|
137
|
+
core.register_link('Pressure', Pressure)
|
|
138
|
+
core.register_link('DiffusionAdvection', DiffusionAdvection)
|
|
139
|
+
core.register_link('CellFieldExchange', CellFieldExchange)
|
|
140
|
+
core.register_link('Chemotaxis', Chemotaxis)
|
|
141
|
+
core.register_link('InclusionBody', InclusionBody)
|
|
142
|
+
core.register_link('IBColony', IBColony)
|
|
143
|
+
core.register_link('QuorumSensing', QuorumSensing)
|
|
144
|
+
core.register_link('FieldDecay', FieldDecay)
|
|
145
|
+
core.register_link('BrownianMovement', BrownianMovement)
|
|
146
|
+
core.register_link('ManageBoundaries', ManageBoundaries)
|
|
147
|
+
core.register_link('MultibodyVizStep', MultibodyVizStep)
|
|
148
|
+
core.register_link('CellMassTraces', CellMassTraces)
|
|
149
|
+
# Spatio-flux Visualization Steps
|
|
150
|
+
core.register_link('FieldHeatmap', FieldHeatmap)
|
|
151
|
+
core.register_link('FieldAnimationGif', FieldAnimationGif)
|
|
152
|
+
core.register_link('FieldSnapshotsGrid', FieldSnapshotsGrid)
|
|
153
|
+
core.register_link('ParticleTraces', ParticleTraces)
|
|
154
|
+
core.register_link('TestSuiteTimeSeries', TestSuiteTimeSeries)
|
|
155
|
+
core.register_link('Composite', Composite)
|
|
156
|
+
core.register_link('RAMEmitter', RAMEmitter)
|
|
157
|
+
core.register_link('SQLiteEmitter', SQLiteEmitter)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def core_import(core=None, config=None):
|
|
161
|
+
if not core:
|
|
162
|
+
core = Core(BASE_TYPES)
|
|
163
|
+
pb_types_register(core)
|
|
164
|
+
pb_register_types(core)
|
|
165
|
+
viz_register_types(core)
|
|
166
|
+
# Spatio-flux types (particle, position, bounds, fields, ...) are
|
|
167
|
+
# referenced by spatio_flux.composites.particles.* and other composites
|
|
168
|
+
# used in this workspace. Their Process classes (registered below) declare
|
|
169
|
+
# ports like 'map[particle]' that won't resolve without these types.
|
|
170
|
+
from spatio_flux import register_types as spatio_flux_register_types
|
|
171
|
+
spatio_flux_register_types(core)
|
|
172
|
+
register_pymunk_types(core)
|
|
173
|
+
register_processes(core)
|
|
174
|
+
return core
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Composite-generator registrations for viva-munk's experiment documents.
|
|
2
|
+
|
|
3
|
+
Each function here is a thin `@composite_generator`-decorated wrapper around
|
|
4
|
+
the corresponding `*_document(config=None)` builder in
|
|
5
|
+
`viva_munk.experiments.documents`. The decorator side-effect (registering
|
|
6
|
+
into pbg-superpowers' `_REGISTRY`) is what makes these visible to the
|
|
7
|
+
vivarium-dashboard's composite browser.
|
|
8
|
+
|
|
9
|
+
Parameters intentionally left unexposed for now — call sites get the
|
|
10
|
+
builder's default config. Per-composite kwargs can be surfaced later by
|
|
11
|
+
filling in `parameters=` on the decorator.
|
|
12
|
+
"""
|
|
13
|
+
from pbg_superpowers.composite_generator import composite_generator
|
|
14
|
+
|
|
15
|
+
from viva_munk.experiments.documents.attachment import attachment_document
|
|
16
|
+
from viva_munk.experiments.documents.bending_pressure import bending_pressure_document
|
|
17
|
+
from viva_munk.experiments.documents.biofilm import biofilm_document
|
|
18
|
+
from viva_munk.experiments.documents.chemotaxis import chemotaxis_document
|
|
19
|
+
from viva_munk.experiments.documents.daughter_machine import daughter_machine_document
|
|
20
|
+
from viva_munk.experiments.documents.glucose_growth import glucose_growth_document
|
|
21
|
+
from viva_munk.experiments.documents.inclusion_bodies import inclusion_bodies_document
|
|
22
|
+
from viva_munk.experiments.documents.mother_machine import mother_machine_document
|
|
23
|
+
from viva_munk.experiments.documents.quorum_sensing import quorum_sensing_document
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@composite_generator(
|
|
27
|
+
name="attachment",
|
|
28
|
+
description="Cells settling/attaching on a surface.",
|
|
29
|
+
default_n_steps=200,
|
|
30
|
+
)
|
|
31
|
+
def attachment(core=None) -> dict:
|
|
32
|
+
return attachment_document()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@composite_generator(
|
|
36
|
+
name="bending_pressure",
|
|
37
|
+
description="Bending-pressure rod-like cells.",
|
|
38
|
+
default_n_steps=200,
|
|
39
|
+
)
|
|
40
|
+
def bending_pressure(core=None) -> dict:
|
|
41
|
+
return bending_pressure_document()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@composite_generator(
|
|
45
|
+
name="biofilm",
|
|
46
|
+
description="Growing biofilm with EPS secretion + pressure dynamics.",
|
|
47
|
+
default_n_steps=500,
|
|
48
|
+
)
|
|
49
|
+
def biofilm(core=None) -> dict:
|
|
50
|
+
return biofilm_document()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@composite_generator(
|
|
54
|
+
name="chemotaxis",
|
|
55
|
+
description="Run/tumble chemotaxis up a static 2D ligand gradient.",
|
|
56
|
+
default_n_steps=200,
|
|
57
|
+
)
|
|
58
|
+
def chemotaxis(core=None) -> dict:
|
|
59
|
+
return chemotaxis_document()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@composite_generator(
|
|
63
|
+
name="daughter_machine",
|
|
64
|
+
description="Daughter-machine geometry: tracking daughter cells.",
|
|
65
|
+
default_n_steps=300,
|
|
66
|
+
)
|
|
67
|
+
def daughter_machine(core=None) -> dict:
|
|
68
|
+
return daughter_machine_document()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@composite_generator(
|
|
72
|
+
name="glucose_growth",
|
|
73
|
+
description="Glucose-driven growth and division.",
|
|
74
|
+
default_n_steps=300,
|
|
75
|
+
)
|
|
76
|
+
def glucose_growth(core=None) -> dict:
|
|
77
|
+
return glucose_growth_document()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@composite_generator(
|
|
81
|
+
name="inclusion_bodies",
|
|
82
|
+
description="Inclusion-body accumulation across a growing colony.",
|
|
83
|
+
default_n_steps=500,
|
|
84
|
+
)
|
|
85
|
+
def inclusion_bodies(core=None) -> dict:
|
|
86
|
+
return inclusion_bodies_document()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@composite_generator(
|
|
90
|
+
name="mother_machine",
|
|
91
|
+
description="Mother-machine geometry: single-channel cell trapping.",
|
|
92
|
+
default_n_steps=300,
|
|
93
|
+
)
|
|
94
|
+
def mother_machine(core=None) -> dict:
|
|
95
|
+
return mother_machine_document()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@composite_generator(
|
|
99
|
+
name="quorum_sensing",
|
|
100
|
+
description="Quorum-sensing autoinducer feedback in a growing colony.",
|
|
101
|
+
default_n_steps=300,
|
|
102
|
+
)
|
|
103
|
+
def quorum_sensing(core=None) -> dict:
|
|
104
|
+
return quorum_sensing_document()
|