|
29 | 29 | #include "memilio/io/parameters_io.h" |
30 | 30 | #include "memilio/data/analyze_result.h" |
31 | 31 | #include "memilio/math/adapt_rk.h" |
| 32 | +#include "memilio/geography/regions.h" |
32 | 33 |
|
33 | 34 | #include <gtest/gtest.h> |
34 | 35 |
|
@@ -1516,5 +1517,184 @@ TEST(TestOdeSecir, read_population_data_failure) |
1516 | 1517 | EXPECT_EQ(result.error().message(), "File with county population expected."); |
1517 | 1518 | } |
1518 | 1519 |
|
| 1520 | +TEST(TestOdeSecirIO, read_input_data_county_aggregates_one_group) |
| 1521 | +{ |
| 1522 | + // Set up two models with different number of age groups. |
| 1523 | + const size_t num_age_groups = 6; |
| 1524 | + std::vector<mio::osecir::Model<double>> models6{mio::osecir::Model<double>((int)num_age_groups)}; |
| 1525 | + std::vector<mio::osecir::Model<double>> models1{mio::osecir::Model<double>(1)}; |
| 1526 | + |
| 1527 | + // Relevant parameters for model with 6 age groups |
| 1528 | + for (auto i = mio::AgeGroup(0); i < (mio::AgeGroup)num_age_groups; ++i) { |
| 1529 | + models6[0].parameters.get<mio::osecir::SeverePerInfectedSymptoms<double>>()[i] = 0.2; |
| 1530 | + models6[0].parameters.get<mio::osecir::CriticalPerSevere<double>>()[i] = 0.25; |
| 1531 | + } |
| 1532 | + |
| 1533 | + // Relevant parameters for model with 1 age group |
| 1534 | + models1[0].parameters.get<mio::osecir::SeverePerInfectedSymptoms<double>>()[mio::AgeGroup(0)] = 0.2; |
| 1535 | + models1[0].parameters.get<mio::osecir::CriticalPerSevere<double>>()[mio::AgeGroup(0)] = 0.25; |
| 1536 | + |
| 1537 | + const auto pydata_dir_Germany = mio::path_join(TEST_DATA_DIR, "Germany", "pydata"); |
| 1538 | + const std::vector<int> counties{1002}; |
| 1539 | + const auto date = mio::Date(2020, 12, 1); |
| 1540 | + |
| 1541 | + std::vector<double> scale6(num_age_groups, 1.0); |
| 1542 | + std::vector<double> scale1{1.0}; |
| 1543 | + |
| 1544 | + // Initialize both models |
| 1545 | + ASSERT_THAT(mio::osecir::read_input_data_county(models6, date, counties, scale6, 1.0, pydata_dir_Germany), |
| 1546 | + IsSuccess()); |
| 1547 | + ASSERT_THAT(mio::osecir::read_input_data_county(models1, date, counties, scale1, 1.0, pydata_dir_Germany), |
| 1548 | + IsSuccess()); |
| 1549 | + |
| 1550 | + // Aggreagate the results from the model with 6 age groups and compare with the model with 1 age group |
| 1551 | + const auto& m6 = models6[0]; |
| 1552 | + const auto& m1 = models1[0]; |
| 1553 | + const double tol = 1e-10; |
| 1554 | + for (int s = 0; s < (int)mio::osecir::InfectionState::Count; ++s) { |
| 1555 | + double sum6 = 0.0; |
| 1556 | + for (size_t ag = 0; ag < num_age_groups; ++ag) { |
| 1557 | + sum6 += m6.populations[{mio::AgeGroup(ag), (mio::osecir::InfectionState)s}].value(); |
| 1558 | + } |
| 1559 | + const double v1 = m1.populations[{mio::AgeGroup(0), (mio::osecir::InfectionState)s}].value(); |
| 1560 | + EXPECT_NEAR(sum6, v1, tol); |
| 1561 | + } |
| 1562 | + |
| 1563 | + // Total population |
| 1564 | + EXPECT_NEAR(m6.populations.get_total(), m1.populations.get_total(), tol); |
| 1565 | +} |
| 1566 | + |
| 1567 | +TEST(TestOdeSecirIO, set_population_data_single_age_group) |
| 1568 | +{ |
| 1569 | + const size_t num_age_groups = 6; |
| 1570 | + |
| 1571 | + // Create two models: one with 6 age groups, one with 1 age group |
| 1572 | + std::vector<mio::osecir::Model<double>> models6{mio::osecir::Model<double>((int)num_age_groups)}; |
| 1573 | + std::vector<mio::osecir::Model<double>> models1{mio::osecir::Model<double>(1)}; |
| 1574 | + |
| 1575 | + // Test population data with 6 different values for age groups |
| 1576 | + std::vector<std::vector<double>> population_data6 = {{10000.0, 20000.0, 30000.0, 25000.0, 15000.0, 8000.0}}; |
| 1577 | + std::vector<std::vector<double>> population_data1 = {{108000.0}}; // sum of all age groups |
| 1578 | + std::vector<int> regions = {1002}; |
| 1579 | + |
| 1580 | + // Set population data for both models |
| 1581 | + EXPECT_THAT(mio::osecir::details::set_population_data(models6, population_data6, regions), IsSuccess()); |
| 1582 | + EXPECT_THAT(mio::osecir::details::set_population_data(models1, population_data1, regions), IsSuccess()); |
| 1583 | + |
| 1584 | + // Sum all compartments across age groups in 6-group model and compare 1-group model |
| 1585 | + const double tol = 1e-10; |
| 1586 | + for (int s = 0; s < (int)mio::osecir::InfectionState::Count; ++s) { |
| 1587 | + double sum6 = 0.0; |
| 1588 | + for (size_t ag = 0; ag < num_age_groups; ++ag) { |
| 1589 | + sum6 += models6[0].populations[{mio::AgeGroup(ag), (mio::osecir::InfectionState)s}].value(); |
| 1590 | + } |
| 1591 | + double val1 = models1[0].populations[{mio::AgeGroup(0), (mio::osecir::InfectionState)s}].value(); |
| 1592 | + |
| 1593 | + EXPECT_NEAR(sum6, val1, tol); |
| 1594 | + } |
| 1595 | + |
| 1596 | + // Total population should also match |
| 1597 | + EXPECT_NEAR(models6[0].populations.get_total(), models1[0].populations.get_total(), tol); |
| 1598 | +} |
| 1599 | + |
| 1600 | +TEST(TestOdeSecirIO, set_confirmed_cases_data_single_age_group) |
| 1601 | +{ |
| 1602 | + const size_t num_age_groups = 6; |
| 1603 | + |
| 1604 | + // Create two models: one with 6 age groups, one with 1 age group |
| 1605 | + std::vector<mio::osecir::Model<double>> models6{mio::osecir::Model<double>((int)num_age_groups)}; |
| 1606 | + std::vector<mio::osecir::Model<double>> models1{mio::osecir::Model<double>(1)}; |
| 1607 | + |
| 1608 | + // Create case data for all 6 age groups over multiple days (current day + 6 days back) |
| 1609 | + std::vector<mio::ConfirmedCasesDataEntry> case_data; |
| 1610 | + |
| 1611 | + for (int day_offset = -6; day_offset <= 0; ++day_offset) { |
| 1612 | + mio::Date current_date = mio::offset_date_by_days(mio::Date(2020, 12, 1), day_offset); |
| 1613 | + |
| 1614 | + for (int age_group = 0; age_group < 6; ++age_group) { |
| 1615 | + double base_confirmed = 80.0 + age_group * 8.0 + (day_offset + 6) * 5.0; |
| 1616 | + double base_recovered = 40.0 + age_group * 4.0 + (day_offset + 6) * 3.0; |
| 1617 | + double base_deaths = 3.0 + age_group * 0.5 + (day_offset + 6) * 0.5; |
| 1618 | + |
| 1619 | + mio::ConfirmedCasesDataEntry entry{base_confirmed, |
| 1620 | + base_recovered, |
| 1621 | + base_deaths, |
| 1622 | + current_date, |
| 1623 | + mio::AgeGroup(age_group), |
| 1624 | + {}, |
| 1625 | + mio::regions::CountyId(1002), |
| 1626 | + {}}; |
| 1627 | + case_data.push_back(entry); |
| 1628 | + } |
| 1629 | + } |
| 1630 | + |
| 1631 | + std::vector<int> regions = {1002}; |
| 1632 | + std::vector<double> scaling_factors = {1.0}; |
| 1633 | + |
| 1634 | + // Set confirmed cases data for both models |
| 1635 | + EXPECT_THAT(mio::osecir::details::set_confirmed_cases_data(models6, case_data, regions, mio::Date(2020, 12, 1), |
| 1636 | + scaling_factors), |
| 1637 | + IsSuccess()); |
| 1638 | + EXPECT_THAT(mio::osecir::details::set_confirmed_cases_data(models1, case_data, regions, mio::Date(2020, 12, 1), |
| 1639 | + scaling_factors), |
| 1640 | + IsSuccess()); |
| 1641 | + |
| 1642 | + // Sum all compartments across age groups in 6-group model should be equal to 1-group model |
| 1643 | + for (int s = 0; s < (int)mio::osecir::InfectionState::Count; ++s) { |
| 1644 | + double sum6 = 0.0; |
| 1645 | + for (size_t ag = 0; ag < num_age_groups; ++ag) { |
| 1646 | + sum6 += models6[0].populations[{mio::AgeGroup(ag), (mio::osecir::InfectionState)s}].value(); |
| 1647 | + } |
| 1648 | + |
| 1649 | + double val1 = models1[0].populations[{mio::AgeGroup(0), (mio::osecir::InfectionState)s}].value(); |
| 1650 | + |
| 1651 | + EXPECT_NEAR(sum6, val1, 1e-10); |
| 1652 | + } |
| 1653 | + |
| 1654 | + // Total population |
| 1655 | + EXPECT_NEAR(models6[0].populations.get_total(), models1[0].populations.get_total(), 1e-10); |
| 1656 | +} |
| 1657 | + |
| 1658 | +TEST(TestOdeSecirIO, set_divi_data_single_age_group) |
| 1659 | +{ |
| 1660 | + // Create models with 6 age groups and 1 age group |
| 1661 | + std::vector<mio::osecir::Model<double>> models_6_groups{mio::osecir::Model<double>(6)}; |
| 1662 | + std::vector<mio::osecir::Model<double>> models_1_group{mio::osecir::Model<double>(1)}; |
| 1663 | + |
| 1664 | + // Set relevant parameters for all age groups |
| 1665 | + for (int i = 0; i < 6; i++) { |
| 1666 | + models_6_groups[0].parameters.get<mio::osecir::SeverePerInfectedSymptoms<double>>()[mio::AgeGroup(i)] = 0.2; |
| 1667 | + models_6_groups[0].parameters.get<mio::osecir::CriticalPerSevere<double>>()[mio::AgeGroup(i)] = 0.25; |
| 1668 | + } |
| 1669 | + |
| 1670 | + // Set relevant parameters for 1 age group model |
| 1671 | + models_1_group[0].parameters.get<mio::osecir::SeverePerInfectedSymptoms<double>>()[mio::AgeGroup(0)] = 0.2; |
| 1672 | + models_1_group[0].parameters.get<mio::osecir::CriticalPerSevere<double>>()[mio::AgeGroup(0)] = 0.25; |
| 1673 | + |
| 1674 | + // Apply DIVI data to both models |
| 1675 | + std::vector<int> regions = {1002}; |
| 1676 | + double scaling_factor_icu = 1.0; |
| 1677 | + mio::Date date(2020, 12, 1); |
| 1678 | + std::string divi_data_path = mio::path_join(TEST_DATA_DIR, "Germany", "pydata", "county_divi_ma7.json"); |
| 1679 | + auto result_6_groups = |
| 1680 | + mio::osecir::details::set_divi_data(models_6_groups, divi_data_path, regions, date, scaling_factor_icu); |
| 1681 | + auto result_1_group = |
| 1682 | + mio::osecir::details::set_divi_data(models_1_group, divi_data_path, regions, date, scaling_factor_icu); |
| 1683 | + |
| 1684 | + EXPECT_THAT(result_6_groups, IsSuccess()); |
| 1685 | + EXPECT_THAT(result_1_group, IsSuccess()); |
| 1686 | + |
| 1687 | + // Calculate totals after applying DIVI data |
| 1688 | + double total_icu_6_groups_after = 0.0; |
| 1689 | + for (int i = 0; i < 6; i++) { |
| 1690 | + total_icu_6_groups_after += |
| 1691 | + models_6_groups[0].populations[{mio::AgeGroup(i), mio::osecir::InfectionState::InfectedCritical}].value(); |
| 1692 | + } |
| 1693 | + double icu_1_group_after = |
| 1694 | + models_1_group[0].populations[{mio::AgeGroup(0), mio::osecir::InfectionState::InfectedCritical}].value(); |
| 1695 | + |
| 1696 | + EXPECT_NEAR(total_icu_6_groups_after, icu_1_group_after, 1e-10); |
| 1697 | +} |
| 1698 | + |
1519 | 1699 | #endif |
1520 | 1700 | #endif |
0 commit comments