Per pathogen health progression - #106
Conversation
…and mortality rates harvest every pathogen's embedded profiles into a (pathogen_id, progression_id) table instead of collapsing them into one DefaultHealthProgression; this drops the single-pathogen restriction, so two pathogens with identical severity stratification can differ in mortality by one parameter
every concrete HealthProgression was a router implementing only select_health_profile, which is why an explicit policy and embedded care conflicted. routing moves to a (pathogen_id, progression_id) index passed to calculate_health_progression!; PerPathogenHealthProgression, LegacyHealthProgression and select_health_profile are gone, DefaultHealthProgression is fieldless, and its tier profiles move to StandardOfCare
…o its progressions
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Issue #1 – StandardOfCare
--> StandardOfCare as described is not a standard if not applied to all categories equally
----> also does only work for pre-set categories has to be adapted when using new categories
--> StandardOfCare does not avoid multiple identical blocks when it still needs subsections for severe and critical
----> StandardOfCare as baseline across all progressions?
--> feels a bit like the old system with a new name
Requested Change:
--> StandardOfCare applies to all categories unless flagged otherwise agnostic of categories used
--> StandardOfCare can use subsets of categories to avoid multiple lines
Question #1 – _demand and _set_demand! assumes no additional care levels
--> is this intended?
Question #2 – order of application
--> Why is the newest the standard not the oldest? If provided with legacy and new version, new version is used (with warning).
Variable Naming
“CriticalHealthProfile” implies a connection to critical progression but can be assigned to other progressions
--> maybe rename to “ICUHealthProfile” or similar to avoid confusion
--> same is true for SevereHealthProfile
Some of these requests are hard to implement: a HealthProfile is anchored to a tier's onset field (SevereHealthProfile to severeness_onset, CriticalHealthProfile to critical_onset) and their parameters are disjoint, so one profile cannot apply to all categories. I removed StandardOfCare from the public API instead. Per-pathogen health now goes into a health block on each progression, and StandardOfCare is purely for backwards compatibility (to be removed when we update to 2.0)
Added ArgumentError throws to both. Additional care levels are not trivial and require extra fields on the individual, for example. We may implement this in the future.
The newest wins because otherwise adding the new form would do nothing until you delete the old one. determine_health_progression should be easier to read now.
Left as is. You are correct that they can be assigned to other progressions, but SevereHealthProfile is always anchored at severeness_onset and CriticalHealthProfile to critical_onset. ICUHealthProfile wouldn't be entirely accurate, because it ignores deaths and ward admissions. |
… (now on parity with SevereHealthProfile)
GEMS 1.2 made the simulation multipathogen but left host care and mortality global: one
DefaultHealthProgressionheld a singleSevereHealthProfileand a singleCriticalHealthProfilefor the whole run, so every pathogen shared one hospitalization and death rate (by default). This release moves those profiles onto the progression categories, where each pathogen carries its own, and leavesHealthProgressionresponsible only for combining a host's concurrent infections into one care timeline.A 1.2 config's
[HealthProgression]section is still read, with a deprecation warning, but twoCriticaltiming keys were renamed and have to be updated by hand; see Critical Timing. Simulations built from Julia may need further changes; see Breaking Changes.Per-Pathogen Health Profiles
Each progression category carries its own care and mortality. In Julia it takes a profile as
health, e.g.Critical(...; health = CriticalHealthProfile(hospital_probability = 0.95)). In a config file it takes ahealthsub-table, e.g.[Pathogens.Covid19.progressions.Critical.health], holding the keys that used to sit under[HealthProgression.parameters.critical]. Either form also accepts the parameters flat among the disease timings, but not both at once.Simulationcollects the profiles into aHealthProfileIndexkeyed by(pathogen_id, progression_id), available ashealth_profiles(sim). Built once at construction, it is what replacedselect_health_profile: aHealthProgressionis handed the index and looks up whatever an infection needs, instead of knowing which profile belongs to which pathogen. Because the key is the progression and not the tier, two categories that peak at the same tier can carry different profiles.Embedding previously worked only for single-pathogen runs, and was rejected alongside an explicit
health_progressionor a[HealthProgression]section. Those restrictions are gone.HealthProgression
HealthProgressionno longer routes infections to profiles:select_health_profileis gone,DefaultHealthProgressionis an empty struct, andcalculate_health_progression!takes theHealthProfileIndexas a new argument.LegacyHealthProgressiongoes with it: it wrapped a private copy of the same routing for the legacy categories, which the index now covers.GEMS._health_profile(index, infection)looks up an infection's profile, ornothingwhen its category carries no health, andcalculate_health_profiledraws the standard schedule from it, so a custom policy can reuse the default draw instead of reimplementing it.The
[HealthProgression]config section now names only the combination policy and itsparametersblock is optional, so the section is needed only for a custom policy.DefaultConf.tomlwas migrated accordingly, its two sub-tables moving onto the Covid19SevereandCriticalprogressions.Critical Timing
CriticalHealthProfilenow anchors the ward atsevereness_onsetand the ICU atcritical_onset, putting it on parity withSevereHealthProfile. Two keys change name accordingly, in both Julia and config files:critical_onset_to_hospital_admissionsevereness_onset_to_hospital_admissionhospital_admission_to_icu_admissioncritical_onset_to_icu_admissionThere is no fallback for the old names; they reach the constructor as unknown keywords and error.
Renaming alone does not reproduce 1.2 timings. Ward admissions now fall earlier, measured from severeness onset instead of critical onset. The ICU is scheduled from critical onset instead of from the ward admission, and if it lands first, the ward admission is moved to it.
LegacyCriticalis unaffected.Deprecations
severe/criticalsub-tables under[HealthProgression.parameters]are still read as tier-level defaults, filling in only the categories that embed no health of their own, with a deprecation warning.carekeyword onSevereandCriticalis deprecated in favour ofhealth.Breaking Changes
The renamed
Criticaltiming keys above affect config files as well as Julia. The rest affect simulations built from Julia only.CriticalHealthProfilekeywords were renamed and its ward and ICU admissions re-anchored; see Critical Timing.DefaultHealthProgression(severe = ..., critical = ...)no longer takes those keywords. Embed the profiles on the progressions instead.HealthProgressionmust implementcalculate_health_progression!for its own type, withindex::HealthProfileIndexadded afternew_infection.compute_health!takes theHealthProfileIndexafterhp.carefield onSevereandCriticalis now calledhealth.select_health_profileandLegacyHealthProgressionare removed.