Repository navigation
Mem bugfix 903 subpop scaling - #904
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
The prerequisite #897 remains unmerged, and the stacked changes include unresolved numerical and documentation issues.
5 open findings
What changed in this PR
Fixes #903 by scaling subpopulation infections to their population sizes and routing per-capita infections to measurement observations. It also includes the still-unmerged #897 ascertainment work.
Changes:
- Corrects aggregate, subpopulation-count, and per-capita infection routing.
- Adds scalar and time-varying ascertainment after delay convolution.
- Expands unit, integration, and tutorial coverage.
| File | Description |
|---|---|
pyrenew/model/multisignal_model.py |
Corrects infection scaling and routing. |
pyrenew/model/pyrenew_builder.py |
Documents ascertainment registration. |
pyrenew/observation/base.py |
Adds delay-only convolution helper. |
pyrenew/observation/count_observations.py |
Applies ascertainment after delay. |
pyrenew/observation/measurement_observations.py |
Requests per-capita infections. |
pyrenew/observation/__init__.py |
Documents infection resolutions. |
pyrenew/convolve.py |
Adds delay-only convolution API. |
pyrenew/ascertainment/base.py |
Adds temporal ascertainment support. |
pyrenew/ascertainment/independent.py |
Adds independent ascertainment model. |
pyrenew/ascertainment/joint.py |
Supports temporal joint rates. |
pyrenew/ascertainment/linked.py |
Supports temporal ratio-linked rates. |
pyrenew/ascertainment/__init__.py |
Exports the new model. |
test/test_multisignal_infection_scaling.py |
Tests corrected infection routing. |
test/test_observation_counts.py |
Tests time-varying ascertainment. |
test/test_observation_validation.py |
Reuses shared test helper. |
test/test_interface_coverage.py |
Updates measurement resolution expectation. |
test/test_helpers.py |
Centralizes measurement test double. |
test/test_convolve.py |
Tests delay-only convolution. |
test/test_ascertainment.py |
Tests expanded ascertainment behavior. |
test/test_pyrenew_builder.py |
Tests builder integration. |
test/conftest.py |
Enforces 64-bit JAX tests. |
test/integration/conftest.py |
Adds integrated ascertainment fixtures. |
test/integration/test_subpopulation_counts_scaling.py |
Tests fitted subpopulation scaling. |
test/integration/test_population_infections_e_rtdaily_rw_timevary.py |
Tests time-varying ED ascertainment. |
test/integration/test_population_infections_he_weekly_joint_ascertainment.py |
Updates joint-site assertions. |
test/integration/test_population_infections_he_weekly_ratio_linked_ascertainment.py |
Updates ratio-site assertions. |
docs/tutorials/ascertainment.qmd |
Documents ascertainment models. |
docs/tutorials/building_multisignal_models.qmd |
Documents infection routing. |
docs/tutorials/observation_processes_counts.qmd |
Documents post-delay ascertainment. |
docs/tutorials/observation_processes_measurements.qmd |
Uses per-capita infections. |
docs/tutorials/latent_infections.qmd |
Applies formatting cleanup. |
panache.toml |
Removes Python lint configuration. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Thank you for your contribution @cdc-mitzimorris 🚀! Your github-pages is ready for download 👉 here 👈! |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #904 +/- ##
=======================================
Coverage 98.83% 98.84%
=======================================
Files 59 59
Lines 2241 2242 +1
=======================================
+ Hits 2215 2216 +1
Misses 26 26
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
6e213d1 to
39508f0
Compare
dylanhmorris
left a comment
There was a problem hiding this comment.
Throughout: replace "resident of subpopulation" with "member of subpopulation" since subpopulations are not necessarily spatial locations.
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
…Renew into mem_bugfix_903_subpop_scaling
|
@dylanhmorris requested changes made. |
|
Assert that PyRenew/test/test_interface_coverage.py Line 185 in cffa5dd |
dylanhmorris
left a comment
There was a problem hiding this comment.
Thanks @cdc-mitzimorris. Spotted a few small things reviewing the tests, but once those are addressed I think this is good to go.
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
…Renew into mem_bugfix_903_subpop_scaling
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
…Renew into mem_bugfix_903_subpop_scaling
Already covered in test_measurements_infection_resolution (test/test_interface_coverage.py:197): it asserts "subpop_per_capita" using a concrete subclass that inherits MeasurementObservation.infection_resolution() unchanged. |
|
@dylanhmorris - all changes made - thanks! |
dylanhmorris
left a comment
There was a problem hiding this comment.
Thanks @cdc-mitzimorris!



Closes #903
Problem
The latent process returns infections per resident of each subpopulation.
MultiSignalModel.sample()turned these into counts by multiplying bypopulation_sizealone, so each subpopulation was scaled as if it held the whole jurisdiction. As a result,"subpop"observations such asSubpopulationCountsreceived counts too large by a factor of1 / subpop_fractions[k]. The subpopulation counts did not sum to the aggregate count, and fitted Rt was biased by subpopulation size.Fix
In
MultiSignalModel.sample():"subpop"observations receiveall_subpops * population_size * subpop_fractions[k].latent_infections_by_subpoprecords the same values."subpop_per_capita", passesall_subpopsthrough unchanged.MeasurementObservation.infection_resolution()now returns it. A wastewater concentration does not depend on how many people live in the catchment, so measurement observations need infections per resident. Under the corrected"subpop", their predictions would have scaled withsubpop_fractions[k].Breaking change:
MeasurementObservationsubclasses now receive infections per resident instead of infections per resident timespopulation_size. Scale parameters such as genomes shed per infection must be set for the new input.Tutorials
building_multisignal_models.qmd: the Infection Resolution section now describes all three resolutions and how latent infections are converted for each.log10_genome_per_infchanges from 9.0 to 4.1, so predicted concentrations match the scale offake_nwss.csv.observation_processes_measurements.qmd: the example infections are now per resident.ascertainment.qmd,latent_subpopulation_infections.qmdandobservation_processes_counts.qmd.Tests
On the pre-fix code, 7 of the 9 new tests fail. All 9 pass with the fix.
test/test_multisignal_infection_scaling.py: traces the model and checks what each resolution receives. Subpopulation counts equal infections per resident times subpopulation population and sum to the aggregate. Measurement observations receive infections per resident.PopulationInfectionsis unchanged.test/integration/test_subpopulation_counts_scaling.py: fitsSubpopulationInfectionsto counts simulated for four subpopulations with fractions 0.5, 0.25, 0.15 and 0.10, all with the same true Rt. Before the fix, Rt in the smallest subpopulation was about 14% low over the first three weeks, and the subpopulation Rt deviations trended with subpopulation size (slope 0.032; the test requires below 0.01).test/conftest.pynow forces 64-bit floats and fails any test that runs without them.StubMeasurementObservationmoves totest/test_helpers.py.