Add query_forecast_end function and integrate into job processing
- Introduced the `query_forecast_end` function in `incubations.py` to determine the end date for query-synthesis weather based on incubation status and treatment intervals. - Updated the `_run_job_inner` function in `job.py` to utilize `query_forecast_end`, enhancing the job's ability to handle future disease forecasting. - Added unit tests in `test_incubations.py` to validate the behavior of `query_forecast_end` under various scenarios, ensuring accurate forecasting logic. - Improved overall code clarity and maintainability with the new function integration.
This commit is contained in:
parent
ebc8ad26b6
commit
47b4300391
@ -46,6 +46,7 @@ from pipeline.stages.incubations import (
|
||||
forecast_has_risk,
|
||||
incubation_start_covered,
|
||||
parse_register,
|
||||
query_forecast_end,
|
||||
reconcile_register,
|
||||
register_payload,
|
||||
)
|
||||
@ -251,7 +252,7 @@ def _run_job_inner(resources: Resources, job: Job, as_of: date, dry_run: bool) -
|
||||
disease.disease_english,
|
||||
weather,
|
||||
phenology,
|
||||
future_disease,
|
||||
query_forecast_end(future_disease, incubation_register, as_of, interval_open),
|
||||
)
|
||||
|
||||
payload: dict[str, Any] = {
|
||||
|
||||
@ -214,6 +214,27 @@ def first_future_disease_date(
|
||||
return None
|
||||
|
||||
|
||||
def query_forecast_end(
|
||||
future_disease: date | None,
|
||||
register: dict[str, IncubationRecord],
|
||||
as_of: date,
|
||||
interval_open: bool,
|
||||
) -> date | None:
|
||||
"""End date for query-synthesis weather. None means today through as_of+5.
|
||||
|
||||
An uncovered incubation that has already started, with the treatment
|
||||
interval closed, uses the full forward window. Otherwise the window ends
|
||||
on the first future risk day.
|
||||
"""
|
||||
underway = any(
|
||||
not record.infection_covered and record.start_date <= as_of
|
||||
for record in register.values()
|
||||
)
|
||||
if underway and not interval_open:
|
||||
return None
|
||||
return future_disease
|
||||
|
||||
|
||||
def covered_by_key(register: dict[str, IncubationRecord]) -> dict[str, bool]:
|
||||
return {key: record.infection_covered for key, record in register.items()}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ from pipeline.stages.incubations import (
|
||||
forecast_has_risk,
|
||||
incubation_start_covered,
|
||||
parse_register,
|
||||
query_forecast_end,
|
||||
reconcile_register,
|
||||
)
|
||||
from pipeline.stages.products import ProductIndex, ProductRow
|
||||
@ -247,6 +248,45 @@ class RiskAndPrefilterTests(unittest.TestCase):
|
||||
register = {"incubazioneprimaria2": _record(_FUTURE, True)}
|
||||
self.assertEqual(first_future_disease_date(forecasts, register, _AS_OF), _FAR)
|
||||
|
||||
def test_underway_uncovered_incubation_uses_the_full_window(self) -> None:
|
||||
tomorrow = _AS_OF + timedelta(days=1)
|
||||
forecasts = {
|
||||
_PAST: ["INCUBAZPRIMARIA2_40"],
|
||||
tomorrow: ["INCUBAZPRIMARIA2_60"],
|
||||
_FAR: ["FASE5"],
|
||||
}
|
||||
register = {"incubazioneprimaria2": _record(_PAST, False)}
|
||||
future = first_future_disease_date(forecasts, register, _AS_OF)
|
||||
self.assertEqual(future, tomorrow)
|
||||
self.assertIsNone(query_forecast_end(future, register, _AS_OF, False))
|
||||
|
||||
def test_open_interval_keeps_the_first_future_day(self) -> None:
|
||||
tomorrow = _AS_OF + timedelta(days=1)
|
||||
forecasts = {tomorrow: ["INCUBAZPRIMARIA2_60"]}
|
||||
register = {"incubazioneprimaria2": _record(_PAST, False)}
|
||||
future = first_future_disease_date(forecasts, register, _AS_OF)
|
||||
self.assertEqual(query_forecast_end(future, register, _AS_OF, True), tomorrow)
|
||||
|
||||
def test_future_only_incubation_keeps_its_start_day(self) -> None:
|
||||
forecasts = {_FUTURE: ["INCUBAZPRIMARIA2_40"]}
|
||||
register = {"incubazioneprimaria2": _record(_FUTURE, False)}
|
||||
future = first_future_disease_date(forecasts, register, _AS_OF)
|
||||
self.assertEqual(query_forecast_end(future, register, _AS_OF, False), _FUTURE)
|
||||
|
||||
def test_covered_incubation_keeps_a_later_fase5(self) -> None:
|
||||
forecasts = {_PAST: ["INCUBAZPRIMARIA2_80"], _FAR: ["FASE5"]}
|
||||
register = {"incubazioneprimaria2": _record(_PAST, True)}
|
||||
future = first_future_disease_date(forecasts, register, _AS_OF)
|
||||
self.assertEqual(future, _FAR)
|
||||
self.assertEqual(query_forecast_end(future, register, _AS_OF, False), _FAR)
|
||||
|
||||
def test_incubation_starting_today_uses_the_full_window(self) -> None:
|
||||
tomorrow = _AS_OF + timedelta(days=1)
|
||||
forecasts = {_TODAY: ["INCUBAZPRIMARIA2_10"], tomorrow: ["INCUBAZPRIMARIA2_20"]}
|
||||
register = {"incubazioneprimaria2": _record(_TODAY, False)}
|
||||
future = first_future_disease_date(forecasts, register, _AS_OF)
|
||||
self.assertIsNone(query_forecast_end(future, register, _AS_OF, False))
|
||||
|
||||
def test_uncovered_past_incubation_selects_incubazprimaria(self) -> None:
|
||||
forecasts = {_PAST: ["INCUBAZPRIMARIA2_80.7", "FASE5"]}
|
||||
rule = select_prefilter_rule(forecasts, {}, _AS_OF, {"incubazioneprimaria2": False})
|
||||
|
||||
Loading…
Reference in New Issue
Block a user