Skip to content

Commit 7205b9d

Browse files
committed
Merge branch '917-improve-code-coverage-of-ide-secir' into 958-implement-a-check-for-the-results-of-the-initialization
2 parents 8569422 + 6c42373 commit 7205b9d

File tree

2 files changed

+103
-14
lines changed

2 files changed

+103
-14
lines changed

cpp/models/ide_secir/model.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,25 +53,24 @@ class Model
5353
const ParameterSet& Parameterset_init = ParameterSet());
5454

5555
/**
56-
* @brief Checks constraints on model parameters.
56+
* @brief Checks constraints on model parameters and initial data.
57+
* @return Returns true if one (or more) constraint(s) are not satisfied, otherwise false.
5758
*/
58-
void check_constraints(ScalarType dt) const
59+
bool check_constraints(ScalarType dt) const
5960
{
60-
if (!(m_populations.get_num_time_points() > 0)) {
61-
log_error("Model construction failed. No initial time point for populations.");
61+
if (!((int)m_transitions.get_num_elements() == (int)InfectionTransition::Count)) {
62+
log_error(
63+
"Initialization failed. Number of elements in transition vector does not match the required number.");
64+
return true;
6265
}
6366

6467
for (int i = 0; i < (int)InfectionState::Count; i++) {
6568
if (m_populations[0][i] < 0) {
6669
log_error("Initialization failed. Initial values for populations are less than zero.");
70+
return true;
6771
}
6872
}
6973

70-
if (!((int)m_transitions.get_num_elements() == (int)InfectionTransition::Count)) {
71-
log_error(
72-
"Initialization failed. Number of elements in transition vector does not match the required number.");
73-
}
74-
7574
ScalarType support_max = std::max(
7675
{parameters.get<TransitionDistributions>()[(int)InfectionTransition::ExposedToInfectedNoSymptoms]
7776
.get_support_max(dt, m_tol),
@@ -95,9 +94,10 @@ class Model
9594
if (m_transitions.get_num_time_points() < (Eigen::Index)std::ceil(support_max / dt)) {
9695
log_error(
9796
"Initialization failed. Not enough time points for transitions given before start of simulation.");
97+
return true;
9898
}
9999

100-
parameters.check_constraints();
100+
return parameters.check_constraints();
101101
}
102102

103103
/**

cpp/tests/test_ide_secir.cpp

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,97 @@ TEST(IdeSecir, checkInitializations)
348348
mio::set_log_level(mio::LogLevel::warn);
349349
}
350350

351-
// a) Test if check_constraints() function correctly reports wrongly set parameters.
352-
// b) Test if check_constraints() does not complain if parameters are set within correct ranges.
351+
// a) Test if the function check_constraints() of the class Model correctly reports errors in the model constraints.
352+
// b) Test if check_constraints() does not complain if the conditions are met.
353+
TEST(IdeSecir, testModelConstraints)
354+
{
355+
using Vec = mio::TimeSeries<ScalarType>::Vector;
356+
// Deactivate temporarily log output for next tests.
357+
mio::set_log_level(mio::LogLevel::off);
358+
359+
// Set wrong initial data and use check_constraints().
360+
// Follow the same order as in check_constraints().
361+
362+
// --- Test with wrong size of the initial value vector for the flows.
363+
ScalarType N = 10000;
364+
ScalarType deaths = 10;
365+
ScalarType dt = 1;
366+
367+
int num_transitions = (int)mio::isecir::InfectionTransition::Count;
368+
369+
// Create TimeSeries of the wrong size.
370+
mio::TimeSeries<ScalarType> init_wrong_size(num_transitions + 1);
371+
// Add time points with vectors of the wrong size.
372+
Vec vec_init_wrong_size = Vec::Constant(num_transitions + 1, 0.);
373+
vec_init_wrong_size[(int)mio::isecir::InfectionTransition::ExposedToInfectedNoSymptoms] = 10.0;
374+
init_wrong_size.add_time_point(-3, vec_init_wrong_size);
375+
while (init_wrong_size.get_last_time() < 0) {
376+
init_wrong_size.add_time_point(init_wrong_size.get_last_time() + dt, vec_init_wrong_size);
377+
}
378+
379+
// Initialize a model.
380+
mio::isecir::Model model_wrong_size(std::move(init_wrong_size), N, deaths);
381+
382+
// Return true for negative entry in m_populations.
383+
auto constraint_check = model_wrong_size.check_constraints(dt);
384+
EXPECT_TRUE(constraint_check);
385+
386+
// --- Test with negative number of deaths.
387+
deaths = -10;
388+
// Create TimeSeries with num_transitions elements.
389+
mio::TimeSeries<ScalarType> init(num_transitions);
390+
// Add time points for initialization of transitions.
391+
Vec vec_init = Vec::Constant(num_transitions, 0.);
392+
vec_init[(int)mio::isecir::InfectionTransition::ExposedToInfectedNoSymptoms] = 10.0;
393+
init.add_time_point(-3, vec_init);
394+
while (init.get_last_time() < 0) {
395+
init.add_time_point(init.get_last_time() + dt, vec_init);
396+
}
397+
398+
// Initialize a model.
399+
mio::TimeSeries<ScalarType> init_copy(init);
400+
mio::isecir::Model model_negative_deaths(std::move(init_copy), N, deaths);
401+
402+
// Return true for negative entry in m_populations.
403+
constraint_check = model_negative_deaths.check_constraints(dt);
404+
EXPECT_TRUE(constraint_check);
405+
406+
// --- Test with too few time points.
407+
deaths = 10;
408+
// Initialize a model.
409+
mio::isecir::Model model_few_timepoints(std::move(init), N, deaths);
410+
411+
mio::ExponentialDecay expdecay(4.0);
412+
mio::StateAgeFunctionWrapper delaydistribution(expdecay);
413+
std::vector<mio::StateAgeFunctionWrapper> vec_delaydistrib(num_transitions, delaydistribution);
414+
model_few_timepoints.parameters.set<mio::isecir::TransitionDistributions>(vec_delaydistrib);
415+
416+
constraint_check = model_few_timepoints.check_constraints(dt);
417+
EXPECT_TRUE(constraint_check);
418+
419+
// --- The check_constraints() function of parameters is tested in its own test below. ---
420+
421+
// --- Correct wrong setup so that next check can go through.
422+
mio::TimeSeries<ScalarType> init_enough_timepoints(num_transitions);
423+
init_enough_timepoints.add_time_point(-5, vec_init);
424+
while (init_enough_timepoints.get_last_time() < 0) {
425+
init_enough_timepoints.add_time_point(init_enough_timepoints.get_last_time() + dt, vec_init);
426+
}
427+
428+
// Initialize a model.
429+
mio::isecir::Model model(std::move(init_enough_timepoints), N, deaths);
430+
431+
model.parameters.set<mio::isecir::TransitionDistributions>(vec_delaydistrib);
432+
433+
constraint_check = model.check_constraints(dt);
434+
EXPECT_FALSE(constraint_check);
435+
436+
// Reactive log output.
437+
mio::set_log_level(mio::LogLevel::warn);
438+
}
439+
440+
// a) Test if check_constraints() function of Parameters correctly reports wrongly set parameters.
441+
// b) Test if check_constraints() function of Parameters does not complain if parameters are set within correct ranges.
353442
TEST(IdeSecir, testValueConstraints)
354443
{
355444
using Vec = mio::TimeSeries<ScalarType>::Vector;
@@ -442,8 +531,8 @@ TEST(IdeSecir, testValueConstraints)
442531
model.parameters
443532
.get<mio::isecir::TransitionProbabilities>()[(int)mio::isecir::InfectionTransition::SusceptibleToExposed] = 1.0;
444533
model.parameters.get<mio::isecir::TransitionProbabilities>()[(
445-
int)mio::isecir::InfectionTransition::ExposedToInfectedNoSymptoms] = -1.0;
446-
constraint_check = model.parameters.check_constraints();
534+
int)mio::isecir::InfectionTransition::ExposedToInfectedNoSymptoms] = 0.6;
535+
constraint_check = model.parameters.check_constraints();
447536
EXPECT_TRUE(constraint_check);
448537

449538
// Check sum InfectedNoSymptomsToInfectedSymptoms + InfectedNoSymptomsToRecovered.

0 commit comments

Comments
 (0)