Skip to content
Merged
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
Source for the [EpiAware](https://github.com/EpiAware) organisation website — the
meta-site for a composable Julia ecosystem for infectious disease modelling.

The site links out to the ecosystem's packages, wraps their documentation in a
single browser, and hosts org-level material (using Julia, FAQ, contributing,
developer, funding, getting involved) alongside a gallery and team page.
The site is the ecosystem's shared front door: an inventory of every package
linking out to its own documentation, the approaches that tie them together,
and org-level material (using Julia, FAQ, contributing, developer, funding,
getting involved) alongside a gallery and team page.

## Build

Expand All @@ -22,19 +23,23 @@ Pushes to `main` deploy it to GitHub Pages.

## Adding a package

Copy `packages/_template.qmd` to `packages/<yourpackage>.qmd`, fill in the front
matter and body, and open a pull request. The card on the
[Packages](https://epiaware.github.io/packages/) page is generated from the file,
and adding the package to the docs browser is a one-line entry in the
`EPIAWARE_DOCS` list in `docs.qmd`.
Add a row to the table in `packages/index.qmd`: package name linking to its
documentation, a GitHub icon linking to its source, a status pill, a
`data-category` (`modelling`, `distributions`, or `infrastructure`) so it
picks up the category filter, and a one-sentence description. Open a pull
request.

## Structure

- `index.qmd` — home
- `packages/` — one page per package, plus the generated listing and a template
- `docs.qmd` — unified documentation browser
- `tutorials.qmd`, `gallery.qmd`, `team.qmd`, `funding.qmd`, `get-involved.qmd`, `community.qmd`
- `packages/index.qmd` — the ecosystem inventory (one filterable table)
- `approaches/` — the modelling approaches (composed distributions, composable
Turing models) and their shared overview
- `tutorials/index.qmd` — a filterable listing of runnable tutorials, each
living in its own package's documentation
- `gallery.qmd`, `team.qmd`, `funding.qmd`, `get-involved.qmd`, `community.qmd`
- `using-julia.qmd`, `faq.qmd`, `contributing.qmd`, `developer.qmd` — org-level guides
- `news/` — blog posts
- `theme-light.scss`, `theme-dark.scss`, `styles.css` — theme
- `assets/img/logo.svg` — org logo

Expand Down
31 changes: 22 additions & 9 deletions approaches/composed-distributions.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ using ComposedDistributions, Distributions

# BDBV-inspired delay tree: parallel pathways
# with sequential, resolve, and compete nested together
tree = compose((
tree = @uncertain compose((
clinical = sequential(
:onset_admit => Gamma(1.2, 3.0),
:onset_admit => Gamma(Normal(1.2, 0.2), 3.0),
:admit_resolve => resolve(
:death => (Gamma(2.0, 3.5), 0.3),
:discharge => (Gamma(1.0, 8.0), 0.7))),
Expand Down Expand Up @@ -121,10 +121,10 @@ Both share one internal representation, so the model you build to simulate is th

The approach is built in four layers, each resting on the one before.

- **Leaves** are any Distributions.jl `UnivariateDistribution`, used directly as the per-event delays.
- **Leaves** are any Distributions.jl `UnivariateDistribution`, used directly as the per-event delays, including Distributions.jl's own `truncated(...)` and `censored(...)` wrappers — a leaf can be truncated or censored, but wrapping a whole tree the same way errors by design, since the composers read a wrapper's structure to peel through to the free delay underneath.
- **Composers** wire named leaves into an event tree.
- **Combination and lowering** join or collapse whole delays with `convolved`, `difference`, and `observed_distribution`.
- **Parameters and edits** read and reshape an assembled tree with `params_table`, `param_priors`, `update`, `prune`, and `splice`.
- **Parameters and edits** read and reshape an assembled tree with `params_table`, `param_priors`, `uncertain`, `update`, `prune`, and `splice`.

### Five composers

Expand All @@ -151,15 +151,17 @@ The model does not change, only the delays each case supplies.

Real line-list delays are rarely clean, and the corrections are part of the model rather than a preprocessing step.
[CensoredDistributions.jl](https://censoreddistributions.epiaware.org/) supplies censoring leaves for primary-event censoring, interval censoring, and truncation.
[ModifiedDistributions.jl](https://modifieddistributions.epiaware.org/) supplies modifier leaves that rescale, weight, or transform a delay.
[ModifiedDistributions.jl](https://modifieddistributions.epiaware.org/dev/) supplies modifier leaves that rescale, weight, or transform a delay.
Both are leaves like any other, so they slot into the tree and the composers peel through them to reach the free delay underneath.

### Uncertainty in the parameters themselves

A delay taken from the literature rarely comes with exact parameters.
`uncertain` wraps a leaf whose parameters are themselves distributions, nested to any depth.
`uncertain` wraps a leaf whose parameters are themselves distributions, nested to any depth, and the `@uncertain` macro reads a distribution passed as a constructor argument as that parameter's prior, so `@uncertain Gamma(Normal(2.0, 0.3), 1.0)` reads the same as writing it out by hand.
The result is still a univariate distribution, so it composes as a leaf everywhere, and `has_uncertain` guards against forgetting to pin it down before fitting.

`uncertain` is also the verb for promoting parameters on a tree already built: `uncertain(tree; onset_admit = (shape = prior,))` targets one parameter, and bare `uncertain(tree)` promotes every free parameter with a default prior in one call.

### One representation across the workflow

The tree is not tied to one package or one use.
Expand All @@ -169,7 +171,8 @@ There is no translation step between the delay model, the infection model, and t
### Read the posterior back through the same tree

After fitting, the posterior is read back by applying the parameter draws to the same tree.
`update(template, chain)` walks each draw through the tree and returns a distribution per draw, so every delay mean, convolution, or contrast comes from the fitted object itself.
`update(template, chain)` reduces the chain to a point summary and returns one fitted tree; `update(template, table)` does the same from a Tables.jl table of values or priors, for a bulk edit outside a sampling loop.
Reading every draw rather than a point summary maps `update` over `param_draws(template, chain)`, so every delay mean, convolution, or contrast still comes from the fitted object itself, one draw at a time.
Nothing is recomputed in separate post-processing that could drift from the model.

## Where next
Expand All @@ -179,13 +182,23 @@ Nothing is recomputed in separate post-processing that could drift from the mode
[composing distributions](https://composeddistributions.epiaware.org/dev/getting-started/tutorials/composing-distributions).
- The [ComposedDistributions.jl documentation](https://composeddistributions.epiaware.org/dev/)
covers the full API and worked examples.
- [ConvolvedDistributions.jl](https://convolveddistributions.epiaware.org/) handles
- [ConvolvedDistributions.jl](https://convolveddistributions.epiaware.org/dev/) handles
the convolutions (sums) of delays that arise naturally in event trees.
- [ModifiedDistributions.jl](https://modifieddistributions.epiaware.org/) lets you
- [ModifiedDistributions.jl](https://modifieddistributions.epiaware.org/dev/) lets you
rescale, weight, or otherwise transform individual leaves without changing the
tree structure.
- [CensoredDistributions.jl](https://censoreddistributions.epiaware.org/) adds
the censoring layer for real line-list data.
- [LoweredDistributions.jl](https://lowereddistributions.epiaware.org/dev/) lowers
the same tree onto a phase-type chain or a CTMC, the bridge to compartmental
models.
- Fitting outside Turing, or fitting a plain struct alongside a tree?
[DistributionsInference.jl](https://github.com/EpiAware/DistributionsInference.jl)
hosts the PPL-neutral log-density and readback that `as_logdensity` and
`as_turing` build on: `distribution_priors` assembles priors the same way
`param_priors` does for a tree, and `distribution_params` reads a fitted
chain back to the estimated values by name, whatever fittable object it
came from.
- Ready to fit a full model with infection dynamics? See the
[composable Turing models approach](composable-turing-models.qmd).

Expand Down
2 changes: 1 addition & 1 deletion developer.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Packages run a consistent set of quality tools:
- [JET.jl](https://github.com/aviatesk/JET.jl) for static analysis (`@report_opt`, `@report_package`)
- Doctests and formatting checks

[EpiAwarePackageTools.jl](https://epiawarepackagetools.epiaware.org/) provides the shared
[EpiAwarePackageTools.jl](https://epiawarepackagetools.epiaware.org/dev/) provides the shared
harnesses, including automatic-differentiation tests across backends.

## Checking performance
Expand Down
2 changes: 1 addition & 1 deletion faq.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ version. Package-specific citation details live in each package's documentation.

## Where do I get help or report a bug?

- Questions: the [epinowcast forum](https://community.epinowcast.org/) or a package's GitHub Discussions
- Questions: the [epinowcast forum](https://community.epinowcast.org/)
- Bugs and feature requests: open an issue on the relevant GitHub repository
- General Julia help: [Julia Discourse](https://discourse.julialang.org/) and [Slack](https://julialang.org/slack/)

Expand Down
3 changes: 2 additions & 1 deletion get-involved.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ ecosystem, there is a place for you here.
- **Discuss.** Join the [epinowcast forum](https://community.epinowcast.org/) to
ask questions and talk through ideas — the best first step.
- **Try the packages.** Use them on a real problem and tell us what worked and
what didn't, via a package's GitHub Discussions or issues.
what didn't, via the [forum](https://community.epinowcast.org/) or a
package's GitHub issues.
- **Contribute.** Fix a bug, improve documentation, or add a feature. See the
[Contributing](contributing.qmd) guide.
- **Bring a use case.** If you have a modelling problem that composable tools
Expand Down
4 changes: 2 additions & 2 deletions index.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ using ComposedDistributions, Distributions

# BDBV-inspired delay tree: parallel pathways
# with sequential, resolve, and compete nested together
tree = compose((
tree = @uncertain compose((
clinical = sequential(
:onset_admit => Gamma(1.2, 3.0),
:onset_admit => Gamma(Normal(1.2, 0.2), 3.0),
:admit_resolve => resolve(
:death => (Gamma(2.0, 3.5), 0.3),
:discharge => (Gamma(1.0, 8.0), 0.7))),
Expand Down
22 changes: 15 additions & 7 deletions packages/index.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Status reflects where a package sits in its release cycle rather than a judgemen
<td class="data-name">
<a href="https://convolveddistributions.epiaware.org/dev/">ConvolvedDistributions.jl</a>
<a class="data-gh" href="https://github.com/EpiAware/ConvolvedDistributions.jl" aria-label="ConvolvedDistributions.jl on GitHub"><i class="bi bi-github"></i></a>
<span class="status-pill status-experimental">experimental</span>
<span class="status-pill status-maturing">maturing</span>
</td>
<td>Convolve probability distributions, with shared numerical quadrature.</td>
</tr>
Expand All @@ -74,25 +74,33 @@ Status reflects where a package sits in its release cycle rather than a judgemen
</tr>
<tr data-category="distributions">
<td class="data-name">
<a href="https://github.com/EpiAware/LoweredDistributions.jl">LoweredDistributions.jl</a>
<a href="https://lowereddistributions.epiaware.org/dev/">LoweredDistributions.jl</a>
<a class="data-gh" href="https://github.com/EpiAware/LoweredDistributions.jl" aria-label="LoweredDistributions.jl on GitHub"><i class="bi bi-github"></i></a>
<span class="status-pill status-experimental">in development</span>
<span class="status-pill status-experimental">experimental</span>
</td>
<td>Lower a distribution, or a whole composed event tree, onto a backend-agnostic dynamical-systems representation (a phase-type chain or a CTMC), then hand it to Catalyst, SciML, AlgebraicPetri, or JumpProcesses.</td>
</tr>
<tr data-category="distributions">
<td class="data-name">
<a href="https://github.com/EpiAware/DistributionsInference.jl">DistributionsInference.jl</a>
<a class="data-gh" href="https://github.com/EpiAware/DistributionsInference.jl" aria-label="DistributionsInference.jl on GitHub"><i class="bi bi-github"></i></a>
<span class="status-pill status-experimental">experimental</span>
</td>
<td>Common components for differential equation infectious disease models. In development, so there is nothing to install yet.</td>
<td>A PPL-neutral fit protocol and log-density engine: any object that names its own parameters becomes fittable, with Turing.jl, Bijectors, and FlexiChains readback layered on as extensions rather than requirements.</td>
</tr>
<tr data-category="infrastructure">
<td class="data-name">
<a href="https://epiawarepackagetools.epiaware.org/">EpiAwarePackageTools.jl</a>
<a href="https://epiawarepackagetools.epiaware.org/dev/">EpiAwarePackageTools.jl</a>
<a class="data-gh" href="https://github.com/EpiAware/EpiAwarePackageTools.jl" aria-label="EpiAwarePackageTools.jl on GitHub"><i class="bi bi-github"></i></a>
<span class="status-pill status-experimental">experimental</span>
</td>
<td>Shared scaffolding, quality checks, and test utilities used across the ecosystem.</td>
</tr>
<tr data-category="infrastructure">
<td class="data-name">
<a href="https://github.com/EpiAware/EpiAwareADTools.jl">EpiAwareADTools.jl</a>
<a href="https://epiawareadtools.epiaware.org/dev/">EpiAwareADTools.jl</a>
<a class="data-gh" href="https://github.com/EpiAware/EpiAwareADTools.jl" aria-label="EpiAwareADTools.jl on GitHub"><i class="bi bi-github"></i></a>
<span class="status-pill status-experimental">experimental</span>
<span class="status-pill status-maturing">maturing</span>
</td>
<td>Automatic differentiation safety machinery for the stack, tested across ForwardDiff, ReverseDiff, Mooncake, and Enzyme. Deliberately framed as fixes we host while we try to fix things upstream.</td>
</tr>
Expand Down
8 changes: 4 additions & 4 deletions tutorials/index.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -109,25 +109,25 @@ If you are new to an approach, start with the tutorial marked *start here*.
</tr>
<tr data-category="delays">
<td class="data-name">
<a href="https://censoreddistributions.epiaware.org/dev/getting-started/tutorials/fitting-with-turing">Fitting with Turing</a>
<a href="https://censoreddistributions.epiaware.org/stable/getting-started/tutorials/fitting-with-turing">Fitting with Turing</a>
</td>
<td>Estimating a delay distribution from censored, truncated line-list data. <em>CensoredDistributions</em></td>
</tr>
<tr data-category="delays">
<td class="data-name">
<a href="https://censoreddistributions.epiaware.org/dev/getting-started/tutorials/analytical-primarycensored-cdfs">Analytical primary-censored CDFs</a>
<a href="https://censoreddistributions.epiaware.org/stable/getting-started/tutorials/analytical-primarycensored-cdfs">Analytical primary-censored CDFs</a>
</td>
<td>Closed-form primary-event censoring, and when it beats numerical integration. <em>CensoredDistributions</em></td>
</tr>
<tr data-category="delays">
<td class="data-name">
<a href="https://censoreddistributions.epiaware.org/dev/getting-started/tutorials/exponentially-tilted-primary-events">Exponentially tilted primary events</a>
<a href="https://censoreddistributions.epiaware.org/stable/getting-started/tutorials/exponentially-tilted-primary-events">Exponentially tilted primary events</a>
</td>
<td>Primary events that are not uniform within their window, as in a growing epidemic. <em>CensoredDistributions</em></td>
</tr>
<tr data-category="delays">
<td class="data-name">
<a href="https://censoreddistributions.epiaware.org/dev/getting-started/tutorials/ad-backends">Automatic differentiation backends</a>
<a href="https://censoreddistributions.epiaware.org/stable/getting-started/tutorials/ad-backends">Automatic differentiation backends</a>
</td>
<td>Which AD backend to use for censored delay likelihoods, and what it costs. <em>CensoredDistributions</em></td>
</tr>
Expand Down
Loading