PHIDS is a deterministic ecological simulation framework for analyzing how plant populations accumulate energy, respond to herbivore pressure, activate chemically mediated defenses, and propagate information across both airborne and mycorrhizal channels. The project integrates a data-oriented engine core, strict state invariants, and reproducible telemetry surfaces so that scenario outcomes can be interpreted as traceable computational experiments rather than opaque animation artifacts.
Current release line: v0.4.0.
Live documentation: https://foersben.github.io/PHIDS/
PHIDS is engineered for three overlapping groups:
- Research-oriented users who need transparent rule systems, deterministic phase ordering, and exportable telemetry for ecological analysis.
- Scenario authors and operators who construct and run simulations through a browser control center or API workflows.
- Contributors who extend engine behavior under explicit constraints (ECS locality, vectorization, bounded dimensions, and reproducible quality gates).
The core biological motifs currently represented include growth and reproduction dynamics, herbivore pressure, volatile signaling, local toxin defense, mycorrhizal relay, and population-level metabolic attrition.
PHIDS uses a deliberately layered runtime architecture centered on
src/phids/engine/loop.py (SimulationLoop).
Primary state owners:
src/phids/engine/core/ecs.py(ECSWorld) β discrete entities and O(1) spatial hash queriessrc/phids/engine/core/biotope.py(GridEnvironment) β vectorized field layers with read/write buffering for diffusion-sensitive statesrc/phids/telemetry/analytics.pyandsrc/phids/io/replay.pyβ per-tick analytical and replay outputs
Simulation tick phase order:
- flow field
- lifecycle
- interaction
- signaling
- telemetry / termination
This ordering is a semantic contract. Observable state at each phase boundary is defined by this sequence, not by ad-hoc update interleavings.
For the canonical architecture chapter, see
docs/architecture/index.md.
PHIDS is not implemented as an unconstrained object-graph simulation. The current implementation follows explicit structural rules:
- Data-oriented entities: runtime organisms and substances reside in
ECSWorldcomponents, not deep behavioral object hierarchies. - Vectorized fields: spatial state uses NumPy arrays; native Python multi-dimensional lists are not accepted for grid math.
- Buffered environmental updates: field-level read/write discipline is enforced where diffusion and field aggregation require deterministic visibility.
- Rule of 16 caps: flora, predators, and substances are bounded to pre-allocated maximum
dimensions (
src/phids/shared/constants.py). - O(1) locality checks: interaction and signaling must use spatial hash lookups rather than O(N^2) global scans.
- Hot-path optimization discipline: flow-field kernels remain Numba-oriented and benchmarked.
- Subnormal truncation policy: diffusion tails below
SIGNAL_EPSILONare zeroed to preserve sparse numeric behavior and runtime stability.
Project-level guidance is mirrored in AGENTS.md and
docs/engine/index.md.
PHIDS intentionally exposes two complementary interfaces.
- REST endpoints for scenario loading, simulation control, environmental updates, and export
- WebSocket streams for simulation-state transport and UI-oriented lightweight frames
See docs/interfaces/rest-and-websocket-surfaces.md.
- HTMX/Jinja control center for scenario drafting, matrix editing, and live diagnostics
- partial update routes for high-frequency operator interactions
Critical boundary: the UI does not mutate live runtime state directly. Configuration first changes
server-side DraftState (src/phids/api/ui_state.py), and only
POST /api/scenario/load-draft commits that draft into a live SimulationLoop.
See docs/ui/index.md.
The batch surface (/ui/batch) is designed for post-hoc statistical analysis rather than
live-grid rendering. The operational flow is:
- run
Nseeded trajectories from a validated draft; - persist aggregate outputs to
data/batches/{job_id}_summary.json; - inspect completed jobs in a chart/data-grid detail view;
- export decimated, publication-oriented aggregate artifacts.
The batch detail pane exposes:
Chartstab with meanΒ±sigma trajectory overlays and survival-probability curve;Data Gridtab with column projection and tick-stride decimation controls;- explicit
Apply Chart SettingsandApply Table Settingsactions for deterministic UI state transitions; - chart presets (
Balanced overview,Collapse risk focus,Predator pressure focus,Survival probability only) for rapid comparative evaluation; - export controls for
CSV,LaTeX table, andTikZwith metadata overrides (including survival-focused TikZ export when the survival preset is active).
Telemetry retention is intentionally bounded (MAX_TELEMETRY_TICKS = 10000) and table previews
show a decimated recent-tail window to keep both backend memory and browser DOM usage stable under
long-running observations.
Previously computed batches can be rehydrated into the in-memory ledger using the
Load Persisted Batches button (backed by POST /api/batch/load-persisted).
Reference chapter:
docs/ui/batch-runner-and-aggregate-analysis.md.
Scenarios encode bounded experimental setups: grid dimensions, species parameterization, trigger-rule matrices, initial placements, wind conditions, and termination constraints.
Curated examples are provided under examples/, including:
examples/dry_shrubland_cycles.jsonexamples/meadow_defense.jsonexamples/mixed_forest_understory.jsonexamples/root_network_alarm_chain.jsonexamples/wind_tunnel_orchard.json
Authoring references:
docs/scenarios/index.mddocs/scenarios/schema-and-curated-examples.mddocs/scenarios/scenario-authoring-and-trigger-semantics.md
uv sync --all-extras --devuv run uvicorn phids.api.main:app --reload --app-dir srcOpen:
- UI:
http://127.0.0.1:8000/ - OpenAPI docs:
http://127.0.0.1:8000/docs
uv run pytest tests/test_ui_routes.py -q
uv run pytest tests/test_systems_behavior.py tests/test_termination_and_loop.py -quv run ruff check .
uv run ruff format --check .
uv run mypy
uv run pytest
uv run mkdocs build --strictPHIDS uses a staged pre-commit regimen so that the commit boundary remains fast enough for
iterative work while the push boundary still rehearses the expensive integrity checks that protect
the engine, the documentation corpus, and the public contributor surface. The pre-commit stage
enforces repository hygiene, Ruff linting/formatting, YAML and TOML validity, merge-conflict
detection, secret scanning, and spelling review. The pre-push stage escalates to green,
repository-wide executable validation through strict source mypy, pytest, and
mkdocs build --strict, thereby
turning each push into a compact rehearsal of the same scientific reproducibility standards
expected from merge-ready work. The current type boundary checks src/phids.
Install both hook types once per clone:
uv run pre-commit install --hook-type pre-commit --hook-type pre-pushRehearse them manually when needed:
uv run pre-commit run --all-files
uv run pre-commit run --all-files --hook-stage pre-pushFor local containerized development:
docker compose up --buildThe compose workflow mounts src/ for iterative development. Optional cleanup:
docker rm -f phids-local
docker rmi -f phids:test phids:local
docker image prune -fRelease and packaging policy:
docs/development/containers-and-release-automation.md
Current verified state (local full-suite run):
196 passed- repository-wide coverage:
89.65% - all currently reported runtime modules in
src/phids/*are at>=80%coverage
Focused checks:
uv run pytest tests/test_ui_routes.py -q
uv run pytest tests/test_systems_behavior.py tests/test_termination_and_loop.py -q
uv run pytest tests/test_flow_field_benchmark.py tests/test_spatial_hash_benchmark.py -qCoverage-uplift regression checks (entrypoint + batch orchestration):
uv run pytest tests/test_cli_main.py tests/test_batch_runner.py -qIf you want to list only modules below 80% after a full run:
uv run pytest tests/ --no-header 2>&1 | awk '/^src\/phids\// {gsub("%","",$4); if (($4+0) < 80) print $0}'Representative route/system smoke slice:
uv run pytest -o addopts='' tests/test_api_routes.py tests/test_ui_routes.py tests/test_systems_behavior.py tests/test_example_scenarios.py -qFocused batch/UI smoke slice:
uv run pytest tests/test_ui_routes.py tests/test_api_routes.py -qScripted local CI:
./scripts/local_ci.sh allHook-only verification:
uv run pre-commit run --all-files
uv run pre-commit run --all-files --hook-stage pre-pushOptional workflow rehearsal:
./scripts/run_ci_with_act.sh --dryrunGitHub Actions policy summary:
- CI runs on pushes to
main, PRs targetingmain, and manual dispatch. developis intentionally not configured as an automatic CI trigger.- Container publishing is release-focused (main/tag boundaries).
References:
docs/development/github-actions-and-local-ci.mddocs/development/contribution-workflow-and-quality-gates.md
The repository includes:
Dockerfileanddocker-compose.ymlfor container workflows.github/workflows/docker-publish.ymlfor GHCR publication policy.github/workflows/release-binaries.ymlfor bundled Linux/Windows/macOS artifacts
- Engine thermodynamic invariants hardened in toxin lethality, starvation attrition, and reproduction-cost handling.
- API export routes remain async-safe under load via threadpool offloading of heavy serialization paths.
- Telemetry visualization now uses bounded in-place Chart.js updates, preventing long-run client memory growth.
- Batch summaries persist strict JSON payloads (non-finite values normalized) for robust browser parsing.
The canonical automated release flow is:
- merge
developintomainthrough a reviewed PR, - push a semantic tag from
main(for examplev0.4.0), - allow GitHub Actions to publish all release artifacts.
git checkout main
git pull --ff-only origin main
git tag v0.4.0
git push origin v0.4.0Expected automation outcomes:
Docs Pagesworkflow publishes updated documentation to GitHub Pages,Build and Publish Release Binariesworkflow attaches OS-specific bundles to the GitHub release,Build and Publish Docker Imageworkflow publishes multi-arch GHCR images for the release tag.
Start here for full subsystem detail:
- docs home:
docs/index.md - architecture:
docs/architecture/index.md - engine:
docs/engine/index.md - interfaces:
docs/interfaces/index.md - scenarios:
docs/scenarios/index.md - telemetry:
docs/telemetry/index.md - development:
docs/development/index.md - reference:
docs/reference/index.md
Published site: https://foersben.github.io/PHIDS/
Serve docs locally:
uv run mkdocs serve- simulation/math:
numpy,scipy,numba - API/runtime:
fastapi,uvicorn,websockets - validation/modeling boundary:
pydantic - telemetry/data processing:
polars - serialization:
msgpack - documentation:
mkdocs,mkdocs-material,mkdocstrings
src/phids/ canonical runtime package
tests/ unit, integration, and benchmark-sensitive coverage
examples/ curated scenario JSON files
docs/ MkDocs documentation corpus
scripts/ local CI and workflow rehearsal helpers
packaging/ PyInstaller configuration
- Want to understand phase semantics? Start at
docs/engine/index.md. - Want to build or edit scenarios? Start at
docs/scenarios/index.md. - Want route and WebSocket details? Start at
docs/interfaces/rest-and-websocket-surfaces.md. - Want contributor workflow and CI policy? Start at
docs/development/contribution-workflow-and-quality-gates.md.
MIT. See LICENSE.