Skip to content

1268 Vaccination data reporting expired #1269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions cpp/memilio/io/epi_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,21 @@ class DiviEntry
inline bool is_divi_data_available(const Date& date)
{
static const Date divi_data_start(2020, 4, 23);
static const Date divi_data_end(2024, 7, 21);
return date >= divi_data_start && date <= divi_data_end;
return date >= divi_data_start;
}

/**
* @brief Checks if vaccination data is available for any day within the given date interval.
* @param start_date The start date of the interval to check.
* @param end_date The end date of the interval to check.
* @return True if there is any overlap between the given date range and the vaccination data
* availability period, false otherwise.
*/
inline bool is_vaccination_data_available(const Date& start_date, const Date& end_date)
{
static const Date vaccination_data_start(2020, 12, 27);
static const Date vaccination_data_end(2024, 7, 9);
return !(end_date < vaccination_data_start || start_date > vaccination_data_end);
}

/**
Expand Down
21 changes: 21 additions & 0 deletions cpp/models/ode_secirts/parameters_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,27 @@ template <typename FP = double>
IOResult<void> set_vaccination_data(std::vector<Model<FP>>& model, const std::string& path, Date date,
const std::vector<int>& vregion, int num_days)
{
// Check if vaccination data is available for the given date range
auto end_date = offset_date_by_days(date, num_days);
if (!is_vaccination_data_available(date, end_date)) {
log_warning("No vaccination data available in range from {} to {}. "
"Vaccination data will be set to 0.",
date, end_date);
// Set vaccination data to 0 for all models
for (auto& m : model) {
m.parameters.template get<DailyPartialVaccinations<FP>>().resize(SimulationDay(num_days + 1));
m.parameters.template get<DailyFullVaccinations<FP>>().resize(SimulationDay(num_days + 1));
m.parameters.template get<DailyBoosterVaccinations<FP>>().resize(SimulationDay(num_days + 1));
for (auto d = SimulationDay(0); d < SimulationDay(num_days + 1); ++d) {
for (auto a = AgeGroup(0); a < m.parameters.get_num_groups(); ++a) {
m.parameters.template get<DailyPartialVaccinations<FP>>()[{a, d}] = 0.0;
m.parameters.template get<DailyFullVaccinations<FP>>()[{a, d}] = 0.0;
m.parameters.template get<DailyBoosterVaccinations<FP>>()[{a, d}] = 0.0;
}
}
}
return success();
}
BOOST_OUTCOME_TRY(auto&& vacc_data, read_vaccination_data(path));
BOOST_OUTCOME_TRY(set_vaccination_data(model, vacc_data, date, vregion, num_days));
return success();
Expand Down
20 changes: 20 additions & 0 deletions cpp/models/ode_secirvvs/parameters_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,26 @@ template <typename FP = double>
IOResult<void> set_vaccination_data(std::vector<Model<FP>>& model, const std::string& path, Date date,
const std::vector<int>& vregion, int num_days)
{
// Check if vaccination data is available for the given date range
auto end_date = offset_date_by_days(date, num_days);
if (!is_vaccination_data_available(date, end_date)) {
log_warning("No vaccination data available in range from {} to {}. "
"Vaccination data will be set to 0.",
date, end_date);
// Set vaccination data to 0 for all models
for (auto& m : model) {
m.parameters.template get<DailyPartialVaccinations<FP>>().resize(SimulationDay(num_days + 1));
m.parameters.template get<DailyFullVaccinations<FP>>().resize(SimulationDay(num_days + 1));

for (auto d = SimulationDay(0); d < SimulationDay(num_days + 1); ++d) {
for (auto a = AgeGroup(0); a < m.parameters.get_num_groups(); ++a) {
m.parameters.template get<DailyPartialVaccinations<FP>>()[{a, d}] = 0.0;
m.parameters.template get<DailyFullVaccinations<FP>>()[{a, d}] = 0.0;
}
}
}
return success();
}
BOOST_OUTCOME_TRY(auto&& vacc_data, read_vaccination_data(path));
BOOST_OUTCOME_TRY(set_vaccination_data(model, vacc_data, date, vregion, num_days));
return success();
Expand Down
24 changes: 21 additions & 3 deletions cpp/tests/test_epi_data_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,28 @@ TEST(TestEpiDataIo, read_divi_data)
TEST(TestEpiDataIo, is_divi_data_available)
{
EXPECT_FALSE(mio::is_divi_data_available(mio::Date(2020, 4, 22))); // Before start
EXPECT_FALSE(mio::is_divi_data_available(mio::Date(2024, 7, 22))); // After end
EXPECT_TRUE(mio::is_divi_data_available(mio::Date(2020, 4, 23))); // Start date
EXPECT_TRUE(mio::is_divi_data_available(mio::Date(2022, 1, 1))); // Inside range
EXPECT_TRUE(mio::is_divi_data_available(mio::Date(2024, 7, 21))); // End date
EXPECT_TRUE(mio::is_divi_data_available(mio::Date(2022, 1, 1))); // Day after start
}

TEST(TestEpiDataIo, is_vaccination_data_available)
{
// Single date tests
EXPECT_FALSE(mio::is_vaccination_data_available(mio::Date(2020, 12, 26), mio::Date(2020, 12, 26))); // Before start
EXPECT_TRUE(mio::is_vaccination_data_available(mio::Date(2020, 12, 27), mio::Date(2020, 12, 27))); // Start date
EXPECT_TRUE(mio::is_vaccination_data_available(mio::Date(2024, 7, 9), mio::Date(2024, 7, 9))); // End date
EXPECT_FALSE(mio::is_vaccination_data_available(mio::Date(2024, 7, 10), mio::Date(2024, 7, 10))); // After end

// Date range tests
EXPECT_TRUE(
mio::is_vaccination_data_available(mio::Date(2020, 12, 20), mio::Date(2020, 12, 28))); // Overlap with start
EXPECT_TRUE(mio::is_vaccination_data_available(mio::Date(2024, 7, 5), mio::Date(2024, 7, 15))); // Overlap with end
EXPECT_TRUE(
mio::is_vaccination_data_available(mio::Date(2021, 1, 1), mio::Date(2021, 12, 31))); // Completely within range
EXPECT_TRUE(
mio::is_vaccination_data_available(mio::Date(2020, 1, 1), mio::Date(2025, 1, 1))); // Contains entire range
EXPECT_FALSE(mio::is_vaccination_data_available(mio::Date(2019, 1, 1), mio::Date(2020, 12, 26))); // Before start
EXPECT_FALSE(mio::is_vaccination_data_available(mio::Date(2024, 7, 10), mio::Date(2025, 1, 1))); // After end
}

TEST(TestEpiDataIo, read_confirmed_cases_data)
Expand Down
7 changes: 1 addition & 6 deletions cpp/tests/test_odesecir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1453,11 +1453,6 @@ TEST(TestOdeSecir, set_divi_data_invalid_dates)
EXPECT_THAT(print_wrap(model_vector[0].populations.array().cast<double>()),
MatrixNear(print_wrap(model.populations.array().cast<double>()), 1e-10, 1e-10));

// Test with data after DIVI dataset was no longer updated.
EXPECT_THAT(mio::osecir::details::set_divi_data(model_vector, "", {1001}, {2025, 12, 01}, 1.0), IsSuccess());
EXPECT_THAT(print_wrap(model_vector[0].populations.array().cast<double>()),
MatrixNear(print_wrap(model.populations.array().cast<double>()), 1e-10, 1e-10));

mio::set_log_level(mio::LogLevel::warn);
}

Expand All @@ -1478,7 +1473,7 @@ TEST_F(ModelTestOdeSecir, set_confirmed_cases_data_with_ICU)

// Change dates of the case data so that no ICU data is available at that time.
// Also, increase the number of confirmed cases by 1 each day.
const auto t0 = mio::Date(2025, 1, 1);
const auto t0 = mio::Date(2000, 1, 1);
auto day_add = 0;
for (auto& entry : case_data) {
entry.date = offset_date_by_days(t0, day_add);
Expand Down
56 changes: 49 additions & 7 deletions cpp/tests/test_odesecirts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -768,12 +768,6 @@ TEST(TestOdeSECIRTS, set_divi_data_invalid_dates)
// Assure that populations is the same as before.
EXPECT_THAT(print_wrap(model_vector[0].populations.array().cast<double>()),
MatrixNear(print_wrap(model.populations.array().cast<double>()), 1e-10, 1e-10));

// Test with data after DIVI dataset was no longer updated.
EXPECT_THAT(mio::osecirts::details::set_divi_data(model_vector, "", {1001}, {2025, 12, 01}, 1.0), IsSuccess());
EXPECT_THAT(print_wrap(model_vector[0].populations.array().cast<double>()),
MatrixNear(print_wrap(model.populations.array().cast<double>()), 1e-10, 1e-10));

mio::set_log_level(mio::LogLevel::warn);
}

Expand Down Expand Up @@ -802,7 +796,7 @@ TEST(TestOdeSECIRTS, set_confirmed_cases_data_with_ICU)

// Change dates of the case data so that no ICU data is available at that time.
// Also, increase the number of confirmed cases by 1 each day.
const auto t0 = mio::Date(2025, 1, 1);
const auto t0 = mio::Date(2000, 1, 1);
auto day_add = 0;
for (auto& entry : case_data) {
entry.date = offset_date_by_days(t0, day_add);
Expand Down Expand Up @@ -1079,6 +1073,54 @@ TEST(TestOdeSECIRTS, model_initialization)
MatrixNear(print_wrap(expected_values), 1e-5, 1e-5));
}

TEST(TestOdeSECIRTS, set_vaccination_data_not_avail)
{
const auto num_age_groups = 2;
const auto num_days = 5;
mio::osecirts::Model<double> model(num_age_groups);
std::vector<mio::osecirts::Model<double>> model_vector = {model};

// Setup initial non-zero vaccination data
auto& params = model_vector[0].parameters;
params.get<mio::osecirts::DailyPartialVaccinations<double>>().resize(mio::SimulationDay(num_days + 1));
params.get<mio::osecirts::DailyFullVaccinations<double>>().resize(mio::SimulationDay(num_days + 1));
params.get<mio::osecirts::DailyBoosterVaccinations<double>>().resize(mio::SimulationDay(num_days + 1));

const double initial_partial_vacc_val = 10.0;
const double initial_full_vacc_val = 5.0;
const double initial_booster_vacc_val = 2.0;

for (auto g = mio::AgeGroup(0); g < mio::AgeGroup(num_age_groups); ++g) {
for (auto d = mio::SimulationDay(0); d < mio::SimulationDay(num_days + 1); ++d) {
params.get<mio::osecirts::DailyPartialVaccinations<double>>()[{g, d}] = initial_partial_vacc_val;
params.get<mio::osecirts::DailyFullVaccinations<double>>()[{g, d}] = initial_full_vacc_val;
params.get<mio::osecirts::DailyBoosterVaccinations<double>>()[{g, d}] = initial_booster_vacc_val;
}
}

// call set_vaccination_data with an unavailable date
mio::Date unavailable_date(2019, 1, 1); // Date before vaccinations started
std::vector<int> region = {1001};
std::string any_path = "dummy_vacc_path.json";

auto result =
mio::osecirts::details::set_vaccination_data(model_vector, any_path, unavailable_date, region, num_days);

ASSERT_THAT(result, IsSuccess());

// Check that vaccinations are set to zero for all days and age groups
for (auto d = mio::SimulationDay(0); d < mio::SimulationDay(num_days + 1); ++d) {
for (auto a = mio::AgeGroup(0); a < mio::AgeGroup(num_age_groups); ++a) {
auto partial_vacc = params.get<mio::osecirts::DailyPartialVaccinations<double>>()[{a, d}];
auto full_vacc = params.get<mio::osecirts::DailyFullVaccinations<double>>()[{a, d}];
auto booster_vacc = params.get<mio::osecirts::DailyBoosterVaccinations<double>>()[{a, d}];
EXPECT_NEAR(partial_vacc, 0.0, 1e-10);
EXPECT_NEAR(full_vacc, 0.0, 1e-10);
EXPECT_NEAR(booster_vacc, 0.0, 1e-10);
}
}
}

#endif

TEST(TestOdeSECIRTS, parameter_percentiles)
Expand Down
57 changes: 47 additions & 10 deletions cpp/tests/test_odesecirvvs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,11 +583,6 @@ TEST(TestOdeSECIRVVS, set_divi_data_invalid_dates)
EXPECT_THAT(print_wrap(model_vector[0].populations.array().cast<double>()),
MatrixNear(print_wrap(model.populations.array().cast<double>()), 1e-10, 1e-10));

// Test with data after DIVI dataset was no longer updated.
EXPECT_THAT(mio::osecirvvs::details::set_divi_data(model_vector, "", {1001}, {2025, 12, 01}, 1.0), IsSuccess());
EXPECT_THAT(print_wrap(model_vector[0].populations.array().cast<double>()),
MatrixNear(print_wrap(model.populations.array().cast<double>()), 1e-10, 1e-10));

mio::set_log_level(mio::LogLevel::warn);
}

Expand All @@ -612,7 +607,7 @@ TEST(TestOdeSECIRVVS, set_confirmed_cases_data_with_ICU)

// Change dates of the case data so that no ICU data is available at that time.
// Also, increase the number of confirmed cases by 1 each day.
const auto t0 = mio::Date(2025, 1, 1);
const auto t0 = mio::Date(2000, 1, 1);
auto day_add = 0;
for (auto& entry : case_data) {
entry.date = offset_date_by_days(t0, day_add);
Expand Down Expand Up @@ -666,14 +661,14 @@ TEST(TestOdeSECIRVVS, read_data)

auto read_result1 = mio::osecirvvs::read_input_data_county(model1, {2020, 12, 01}, {1002},
std::vector<double>(size_t(num_age_groups), 1.0), 1.0,
TEST_GERMANY_PYDATA_DIR, 10);
TEST_GERMANY_PYDATA_DIR, 30);

auto read_result2 = mio::osecirvvs::read_input_data(model2, {2020, 12, 01}, {1002},
std::vector<double>(size_t(num_age_groups), 1.0), 1.0,
TEST_GERMANY_PYDATA_DIR, 10);
TEST_GERMANY_PYDATA_DIR, 30);

auto read_result_district = mio::osecirvvs::read_input_data(
model3, {2020, 12, 01}, {1002}, std::vector<double>(size_t(num_age_groups), 1.0), 1.0, pydata_dir_District, 10);
model3, {2020, 12, 01}, {1002}, std::vector<double>(size_t(num_age_groups), 1.0), 1.0, pydata_dir_District, 30);

ASSERT_THAT(read_result1, IsSuccess());
ASSERT_THAT(read_result2, IsSuccess());
Expand Down Expand Up @@ -903,7 +898,7 @@ TEST(TestOdeSECIRVVS, model_initialization)

ASSERT_THAT(mio::osecirvvs::read_input_data_county(model_vector, {2020, 12, 01}, {0},
std::vector<double>(size_t(num_age_groups), 1.0), 1.0,
TEST_GERMANY_PYDATA_DIR, 2, false),
TEST_GERMANY_PYDATA_DIR, 30, false),
IsSuccess());

// Values from data/export_time_series_init_osecirvvs.h5, for reading in comparison
Expand Down Expand Up @@ -1088,6 +1083,48 @@ TEST(TestOdeSECIRVVS, run_simulation)
ASSERT_THAT(print_wrap(result.matrix()), MatrixNear(print_wrap(expected_result.matrix()), 1e-5, 1e-5));
}

TEST(TestOdeSECIRVVS, set_vaccination_data_not_avail)
{
const auto num_age_groups = 2;
const auto num_days = 5;
mio::osecirvvs::Model<double> model(num_age_groups);
std::vector<mio::osecirvvs::Model<double>> model_vector = {model};

// Setup initial non-zero vaccination data
auto& params = model_vector[0].parameters;
params.get<mio::osecirvvs::DailyPartialVaccinations<double>>().resize(mio::SimulationDay(num_days + 1));
params.get<mio::osecirvvs::DailyFullVaccinations<double>>().resize(mio::SimulationDay(num_days + 1));

const double initial_partial_vacc_val = 10.0;
const double initial_full_vacc_val = 5.0;

for (auto g = mio::AgeGroup(0); g < mio::AgeGroup(num_age_groups); ++g) {
for (auto d = mio::SimulationDay(0); d < mio::SimulationDay(num_days + 1); ++d) {
params.get<mio::osecirvvs::DailyPartialVaccinations<double>>()[{g, d}] = initial_partial_vacc_val;
params.get<mio::osecirvvs::DailyFullVaccinations<double>>()[{g, d}] = initial_full_vacc_val;
}
}

// call set_vaccination_data with an unavailable date
mio::Date unavailable_date(2019, 1, 1); // Date before vaccinations started
std::vector<int> region = {1001};
std::string any_path = "dummy_vacc_path.json";
auto result =
mio::osecirvvs::details::set_vaccination_data(model_vector, any_path, unavailable_date, region, num_days);

ASSERT_THAT(result, IsSuccess());

// Check that vaccinations are set to zero for all days and age groups
for (auto d = mio::SimulationDay(0); d < mio::SimulationDay(num_days + 1); ++d) {
for (auto a = mio::AgeGroup(0); a < mio::AgeGroup(num_age_groups); ++a) {
auto partial_vacc = params.get<mio::osecirvvs::DailyPartialVaccinations<double>>()[{a, d}];
auto full_vacc = params.get<mio::osecirvvs::DailyFullVaccinations<double>>()[{a, d}];
EXPECT_NEAR(partial_vacc, 0.0, 1e-10);
EXPECT_NEAR(full_vacc, 0.0, 1e-10);
}
}
}

#endif

TEST(TestOdeSECIRVVS, parameter_percentiles)
Expand Down