@@ -66,14 +66,51 @@ void Model::initialize(ScalarType dt)
6666 m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Recovered)] -
6767 m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Dead)];
6868 }
69- else {
69+ else if (m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Susceptible)] > 1e-12 ) {
70+ // Take initialized value for Susceptibles if value can't be calculated via the standard formula.
71+ m_initialization_method = 2 ;
72+ // Calculate other compartment sizes for t=0.
73+ other_compartments_current_timestep (dt);
7074
75+ // R; need an initial value for R, therefore do not calculate via compute_recovered()
76+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Recovered)] =
77+ m_N - m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Susceptible)] -
78+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Exposed)] -
79+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedNoSymptoms)] -
80+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedSymptoms)] -
81+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedSevere)] -
82+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedCritical)] -
83+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Dead)];
84+ }
85+ else if (m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Recovered)] > 1e-12 ) {
86+ // If value for Recovered is initialized and standard method is not applicable (i.e., no value for total infections
87+ // or suceptibles given directly), calculate Susceptibles via other compartments.
88+ // The calculation of other compartments' values is not dependent on Susceptibles at time 0, i.e., S(0), but only on the transitions of the past.
89+ m_initialization_method = 3 ;
90+ other_compartments_current_timestep (dt);
91+
92+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Susceptible)] =
93+ m_N - m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Exposed)] -
94+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedNoSymptoms)] -
95+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedSymptoms)] -
96+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedSevere)] -
97+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedCritical)] -
98+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Recovered)] -
99+ m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Dead)];
100+ }
101+ else {
71102 // compute Susceptibles at time 0 and m_forceofinfection at time -dt as initial values for discretization scheme
72103 // use m_forceofinfection at -dt to be consistent with further calculations of S (see compute_susceptibles()),
73104 // where also the value of m_forceofinfection for the previous timestep is used
74105 update_forceofinfection (dt, true );
75106 if (m_forceofinfection > 1e-12 ) {
76- m_initialization_method = 2 ;
107+ m_initialization_method = 4 ;
108+
109+ /* Attention: With an inappropriate combination of parameters and initial conditions, it can happen that S
110+ becomes greater than N when this formula is used. In this case, at least one compartment is initialized
111+ with a number less than zero, so that a log_error is thrown.
112+ However, this initialization method is consistent with the numerical solver of the model equations,
113+ so it may sometimes make sense to use this method. */
77114 m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Susceptible)] =
78115 m_transitions.get_last_value ()[Eigen::Index (InfectionTransition::SusceptibleToExposed)] /
79116 (dt * m_forceofinfection);
@@ -91,46 +128,27 @@ void Model::initialize(ScalarType dt)
91128 m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedCritical)] -
92129 m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Dead)];
93130 }
94- else if (m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Susceptible)] > 1e-12 ) {
95- // take initialized value for Susceptibles if value can't be calculated via the standard formula
96- m_initialization_method = 3 ;
97- // calculate other compartment sizes for t=0
98- other_compartments_current_timestep (dt);
99-
100- // R; need an initial value for R, therefore do not calculate via compute_recovered()
101- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Recovered)] =
102- m_N - m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Susceptible)] -
103- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Exposed)] -
104- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedNoSymptoms)] -
105- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedSymptoms)] -
106- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedSevere)] -
107- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedCritical)] -
108- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Dead)];
109- }
110- else if (m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Recovered)] > 1e-12 ) {
111- // if value for Recovered is initialized and standard method is not applicable, calculate Susceptibles via other compartments
112- // determining other compartment sizes is not dependent of Susceptibles(0), just of the transitions of the past.
113- // calculate other compartment sizes for t=0
114- m_initialization_method = 4 ;
115- other_compartments_current_timestep (dt);
116-
117- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Susceptible)] =
118- m_N - m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Exposed)] -
119- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedNoSymptoms)] -
120- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedSymptoms)] -
121- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedSevere)] -
122- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::InfectedCritical)] -
123- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Recovered)] -
124- m_populations[Eigen::Index (0 )][Eigen::Index (InfectionState::Dead)];
125- }
126131 else {
127132 m_initialization_method = -1 ;
128133 log_error (" Error occured while initializing compartments: Force of infection is evaluated to 0 and neither "
129134 " Susceptibles nor Recovered or total confirmed cases for time 0 were set. One of them should be "
130135 " larger 0." );
131136 }
132137 }
133- // compute m_forceofinfection at time 0 needed for further simulation
138+
139+ // Verify that the initialization produces an appropriate result.
140+ // Another check would be if the sum of the compartments is equal to N, but in all initialization methods one of the compartments is initialized via N - the others.
141+ // This also means that if a compartment is greater than N, we will always have one or more compartments less than zero.
142+ // Check if all compartments are non negative.
143+ for (int i = 0 ; i < (int )InfectionState::Count; i++) {
144+ if (m_populations[0 ][i] < 0 ) {
145+ m_initialization_method = -2 ;
146+ log_error (" Initialization failed. One or more initial values for populations are less than zero. It may "
147+ " help to use a different method for initialization." );
148+ }
149+ }
150+
151+ // Compute m_forceofinfection at time 0 needed for further simulation.
134152 update_forceofinfection (dt);
135153}
136154
0 commit comments