Skip to content

Commit 470a7e7

Browse files
committed
backward consistency test
1 parent 7f36b26 commit 470a7e7

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

0 Bytes
Binary file not shown.

cpp/tests/test_dynamic_npis.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,51 @@ TEST(DynamicNPIs, secir_implementation_with_directives)
631631
EXPECT_EQ(contact_matrix_sim_5.get_matrix_at(mio::SimulationTime<double>(5.0))(0, 0), 1.0); // lifted at t_end+1=5
632632
}
633633

634+
TEST(DynamicNPIs, secir_backward_consistency_with_predefined)
635+
{
636+
// Verify the core reproducibility guarantee of the +1 offset:
637+
// A simulation with dynamic NPIs (threshold exceeded at t=1, delay=2 -> t_start=3)
638+
// must produce the same contact matrix as a simulation with predefined dampings
639+
// placed at t_start_damping = t_start+1 = 4 and t_end_damping = t_end+1 = 9.
640+
mio::osecir::Model<double> model(1);
641+
model.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::InfectedSymptoms}] = 10;
642+
model.populations.set_difference_from_total({mio::AgeGroup(0), mio::osecir::InfectionState::Susceptible}, 100);
643+
644+
mio::ContactMatrixGroup<double>& cm = model.parameters.get<mio::osecir::ContactPatterns<double>>();
645+
cm[0] = mio::ContactMatrix<double>(Eigen::MatrixXd::Constant(1, 1, 1.0));
646+
647+
mio::DynamicNPIs<double> npis;
648+
npis.set_threshold(0.05 * 50'000, {mio::DampingSampling<double>{0.5,
649+
mio::DampingLevel(0),
650+
mio::DampingType(0),
651+
mio::SimulationTime<double>(0),
652+
{0},
653+
Eigen::VectorXd::Ones(1)}});
654+
npis.set_duration(mio::SimulationTime<double>(5.0));
655+
npis.set_base_value(50'000);
656+
npis.set_implementation_delay(mio::SimulationTime<double>(2.0));
657+
model.parameters.get<mio::osecir::DynamicNPIsInfectedSymptoms<double>>() = npis;
658+
659+
// t0=1: threshold exceeded at t=1, delay=2 -> t_start=3, t_start_damping=4,
660+
// duration=5 -> t_end=8, t_end_damping=9
661+
mio::osecir::Simulation<double, mio_test::MockSimulation<mio::osecir::Model>> sim(model, 1.0);
662+
sim.advance(10.0);
663+
664+
// Equivalent predefined dampings: place damping at t_start_damping=4 and restore at t_end_damping=9.
665+
// smoother_cosine uses window [t-1, t], so damping at t=4 gives window [3,4].
666+
mio::ContactMatrixGroup<double> cm_expected(1, 1);
667+
cm_expected[0] = mio::ContactMatrix<double>(Eigen::MatrixXd::Constant(1, 1, 1.0));
668+
cm_expected[0].add_damping(0.5, mio::DampingLevel(0), mio::DampingType(0), mio::SimulationTime<double>(4.0));
669+
cm_expected[0].add_damping(0.0, mio::DampingLevel(0), mio::DampingType(0), mio::SimulationTime<double>(9.0));
670+
671+
auto const& cm_dynamic = sim.get_model().parameters.get<mio::osecir::ContactPatterns<double>>().get_cont_freq_mat();
672+
for (double t : {1.0, 2.0, 3.0, 3.5, 4.0, 5.0, 7.0, 8.0, 8.5, 9.0, 10.0}) {
673+
EXPECT_DOUBLE_EQ(cm_dynamic.get_matrix_at(mio::SimulationTime<double>(t))(0, 0),
674+
cm_expected.get_matrix_at(mio::SimulationTime<double>(t))(0, 0))
675+
<< "Mismatch at t=" << t;
676+
}
677+
}
678+
634679
TEST(DynamicNPIs, secirvvs_threshold_safe)
635680
{
636681
mio::osecirvvs::Model<double> model(1);

0 commit comments

Comments
 (0)