Skip to content

Conversation

@cdc-mitzimorris
Copy link
Collaborator

This PR adds work that was done in https://github.com/cdcent/cfa-pyrenew-hierarchical/pull/4 to PyRenew.

It adds the base observation process class, concrete implementations for Count processes and the abstract base class for Measurement processes, together with unit tests and two new tutorials for count and measurement observation processes respectively.

Once this PR and the work done in https://github.com/cdcent/cfa-pyrenew-hierarchical/pull/5 have been added to PyRenew, subsequent PRs will deprecate unused features and harmonize the documentation and tutorials.

@codecov
Copy link

codecov bot commented Dec 23, 2025

Codecov Report

❌ Patch coverage is 98.36957% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.26%. Comparing base (02446c5) to head (edd6573).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
pyrenew/observation/count_observations.py 96.66% 2 Missing ⚠️
pyrenew/observation/noise.py 98.38% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #644      +/-   ##
==========================================
+ Coverage   96.98%   97.26%   +0.27%     
==========================================
  Files          42       47       +5     
  Lines        1094     1278     +184     
==========================================
+ Hits         1061     1243     +182     
- Misses         33       35       +2     
Flag Coverage Δ
unittests 97.26% <98.36%> (+0.27%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link

github-actions bot commented Dec 23, 2025

Thank you for your contribution @cdc-mitzimorris 🚀! Your github-pages is ready for download 👉 here 👈!
(The artifact expires on 2026-01-22T15:26:51Z. You can re-generate it by re-running the workflow here.)

@cdc-mitzimorris
Copy link
Collaborator Author

ready for re-review - high-level concerns addressed:

  • changed expected to predicted
  • standardized calls to sample w/ arg obs
  • revised measurement observations tutorial
  • removed helper class for hierarchical models; use NumPyro's TruncatedNormalDistribution directly.

@cdc-mitzimorris
Copy link
Collaborator Author

In preparing to add the model_builder class for component composition, it became clear that the noise model shouldn't manage the plates directly - this is the responsibility of the RV.
The utility class VectorizedRV wraps simple distributions in a plate, while hierarchical priors (e.g., HierarchicalNormalPrior) use internal plates with partial pooling. The noise model works with either because it only depends on the interface, not the implementation.
Updated file observation/noise.py and the corresponding notebook.

expected_counts_safe = jnp.nan_to_num(expected_counts, nan=0.0)
predicted_counts = self._predicted_obs(infections)
self._deterministic("predicted_counts", predicted_counts)
predicted_counts_safe = jnp.nan_to_num(predicted_counts, nan=0.0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ This feels dangerous to do automatically and without warning. I think I would rather force the user to do it themself in _predicted_obs, where appropriate. Is there a good reason not to?

"""
predicted_values = self._predicted_obs(infections)

self._deterministic("predicted_log_conc", predicted_values)
Copy link
Collaborator

@dylanhmorris dylanhmorris Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Site name should be configurable and/or dynamically generated based on a higher-level configurable name.

predicted_obs = predicted_values[times, subpop_indices]

observed = self.noise.sample(
name="concentrations",
Copy link
Collaborator

@dylanhmorris dylanhmorris Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be configurable and/or dynamically generated based on a higher-level configurable name.

Copy link
Collaborator

@dylanhmorris dylanhmorris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @cdc-mitzimorris! A few things to address and then I can re-review.

cdc-mitzimorris and others added 2 commits January 15, 2026 10:20
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Co-authored-by: Dylan H. Morris <dylanhmorris@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants