model.h Source File

CPP API: model.h Source File
ode_secirvvs/model.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2020-2026 MEmilio
3 *
4 * Authors: Wadim Koslow, Daniel Abele, Martin J. Kühn
5 *
6 * Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20 #ifndef MIO_ODE_SECIRVVS_MODEL_H
21 #define MIO_ODE_SECIRVVS_MODEL_H
22 
30 #include "memilio/math/smoother.h"
32 
33 #include <numbers>
34 
35 namespace mio
36 {
37 namespace osecirvvs
38 {
39 // clang-format off
40 using Flows = TypeList<
41  //naive
57  //partial immunity
73  //improved immunity
89 // clang-format on
90 
91 template <typename FP>
92 class Model
93  : public FlowModel<FP, InfectionState, mio::Populations<FP, AgeGroup, InfectionState>, Parameters<FP>, Flows>
94 {
96 
97 public:
98  using typename Base::ParameterSet;
99  using typename Base::Populations;
100 
101  Model(const Populations& pop, const ParameterSet& params)
102  : Base(pop, params)
103  {
104  }
105 
106  Model(int num_agegroups)
107  : Model(Populations({AgeGroup(num_agegroups), InfectionState::Count}), ParameterSet(AgeGroup(num_agegroups)))
108  {
109  }
110 
111  void get_flows(Eigen::Ref<const Eigen::VectorX<FP>> pop, Eigen::Ref<const Eigen::VectorX<FP>> y, FP t,
112  Eigen::Ref<Eigen::VectorX<FP>> flows) const override
113  {
114  auto const& params = this->parameters;
115  AgeGroup n_agegroups = params.get_num_groups();
116 
117  ContactMatrixGroup<FP> const& contact_matrix = params.template get<ContactPatterns<FP>>();
118 
119  FP icu_occupancy = 0.0;
120  FP test_and_trace_required = 0.0;
121  for (auto i = AgeGroup(0); i < n_agegroups; ++i) {
122  test_and_trace_required +=
123  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]) /
124  params.template get<TimeInfectedNoSymptoms<FP>>()[i] *
128  this->populations.get_from(pop, {i, InfectionState::InfectedNoSymptomsNaiveConfirmed}) +
129  this->populations.get_from(pop, {i, InfectionState::InfectedNoSymptomsPartialImmunityConfirmed}) +
130  this->populations.get_from(pop, {i, InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed}));
131  icu_occupancy += this->populations.get_from(pop, {i, InfectionState::InfectedCriticalNaive}) +
132  this->populations.get_from(pop, {i, InfectionState::InfectedCriticalPartialImmunity}) +
133  this->populations.get_from(pop, {i, InfectionState::InfectedCriticalImprovedImmunity});
134  }
135 
136  for (auto i = AgeGroup(0); i < n_agegroups; i++) {
137 
138  size_t SNi = this->populations.get_flat_index({i, InfectionState::SusceptibleNaive});
139  size_t ENi = this->populations.get_flat_index({i, InfectionState::ExposedNaive});
140  size_t INSNi = this->populations.get_flat_index({i, InfectionState::InfectedNoSymptomsNaive});
141  size_t ISyNi = this->populations.get_flat_index({i, InfectionState::InfectedSymptomsNaive});
142  size_t ISevNi = this->populations.get_flat_index({i, InfectionState::InfectedSevereNaive});
143  size_t ICrNi = this->populations.get_flat_index({i, InfectionState::InfectedCriticalNaive});
144 
145  size_t INSNCi = this->populations.get_flat_index({i, InfectionState::InfectedNoSymptomsNaiveConfirmed});
146  size_t ISyNCi = this->populations.get_flat_index({i, InfectionState::InfectedSymptomsNaiveConfirmed});
147 
148  size_t SPIi = this->populations.get_flat_index({i, InfectionState::SusceptiblePartialImmunity});
149  size_t EPIi = this->populations.get_flat_index({i, InfectionState::ExposedPartialImmunity});
150  size_t INSPIi = this->populations.get_flat_index({i, InfectionState::InfectedNoSymptomsPartialImmunity});
151  size_t ISyPIi = this->populations.get_flat_index({i, InfectionState::InfectedSymptomsPartialImmunity});
152  size_t ISevPIi = this->populations.get_flat_index({i, InfectionState::InfectedSeverePartialImmunity});
153  size_t ICrPIi = this->populations.get_flat_index({i, InfectionState::InfectedCriticalPartialImmunity});
154 
155  size_t INSPICi =
156  this->populations.get_flat_index({i, InfectionState::InfectedNoSymptomsPartialImmunityConfirmed});
157  size_t ISyPICi =
158  this->populations.get_flat_index({i, InfectionState::InfectedSymptomsPartialImmunityConfirmed});
159 
160  size_t EIIi = this->populations.get_flat_index({i, InfectionState::ExposedImprovedImmunity});
161  size_t INSIIi = this->populations.get_flat_index({i, InfectionState::InfectedNoSymptomsImprovedImmunity});
162  size_t ISyIIi = this->populations.get_flat_index({i, InfectionState::InfectedSymptomsImprovedImmunity});
163  size_t ISevIIi = this->populations.get_flat_index({i, InfectionState::InfectedSevereImprovedImmunity});
164  size_t ICrIIi = this->populations.get_flat_index({i, InfectionState::InfectedCriticalImprovedImmunity});
165 
166  size_t INSIICi =
167  this->populations.get_flat_index({i, InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed});
168  size_t ISyIICi =
169  this->populations.get_flat_index({i, InfectionState::InfectedSymptomsImprovedImmunityConfirmed});
170 
171  size_t SIIi = this->populations.get_flat_index({i, InfectionState::SusceptibleImprovedImmunity});
172 
173  FP reducExposedPartialImmunity = params.template get<ReducExposedPartialImmunity<FP>>()[i];
174  FP reducExposedImprovedImmunity = params.template get<ReducExposedImprovedImmunity<FP>>()[i];
175  FP reducInfectedSymptomsPartialImmunity =
176  params.template get<ReducInfectedSymptomsPartialImmunity<FP>>()[i];
177  FP reducInfectedSymptomsImprovedImmunity =
178  params.template get<ReducInfectedSymptomsImprovedImmunity<FP>>()[i];
179  FP reducInfectedSevereCriticalDeadPartialImmunity =
180  params.template get<ReducInfectedSevereCriticalDeadPartialImmunity<FP>>()[i];
181  FP reducInfectedSevereCriticalDeadImprovedImmunity =
182  params.template get<ReducInfectedSevereCriticalDeadImprovedImmunity<FP>>()[i];
183  FP reducTimeInfectedMild = params.template get<ReducTimeInfectedMild<FP>>()[i];
184 
185  //symptomatic are less well quarantined when testing and tracing is overwhelmed so they infect more people
186  auto riskFromInfectedSymptomatic =
187  smoother_cosine<FP>(test_and_trace_required, params.template get<TestAndTraceCapacity<FP>>(),
188  params.template get<TestAndTraceCapacity<FP>>() *
189  params.template get<TestAndTraceCapacityMaxRiskSymptoms<FP>>(),
190  params.template get<RiskOfInfectionFromSymptomatic<FP>>()[i],
191  params.template get<MaxRiskOfInfectionFromSymptomatic<FP>>()[i]);
192 
193  auto riskFromInfectedNoSymptoms =
194  smoother_cosine<FP>(test_and_trace_required, params.template get<TestAndTraceCapacity<FP>>(),
195  params.template get<TestAndTraceCapacity<FP>>() *
196  params.template get<TestAndTraceCapacityMaxRiskNoSymptoms<FP>>(),
197  params.template get<RelativeTransmissionNoSymptoms<FP>>()[i], 1.0);
198 
199  for (auto j = AgeGroup(0); j < n_agegroups; j++) {
200  size_t SNj = this->populations.get_flat_index({j, InfectionState::SusceptibleNaive});
201  size_t ENj = this->populations.get_flat_index({j, InfectionState::ExposedNaive});
202  size_t INSNj = this->populations.get_flat_index({j, InfectionState::InfectedNoSymptomsNaive});
203  size_t ISyNj = this->populations.get_flat_index({j, InfectionState::InfectedSymptomsNaive});
204  size_t ISevNj = this->populations.get_flat_index({j, InfectionState::InfectedSevereNaive});
205  size_t ICrNj = this->populations.get_flat_index({j, InfectionState::InfectedCriticalNaive});
206  size_t SIIj = this->populations.get_flat_index({j, InfectionState::SusceptibleImprovedImmunity});
207 
208  size_t INSNCj = this->populations.get_flat_index({j, InfectionState::InfectedNoSymptomsNaiveConfirmed});
209  size_t ISyNCj = this->populations.get_flat_index({j, InfectionState::InfectedSymptomsNaiveConfirmed});
210 
211  size_t SPIj = this->populations.get_flat_index({j, InfectionState::SusceptiblePartialImmunity});
212  size_t EPIj = this->populations.get_flat_index({j, InfectionState::ExposedPartialImmunity});
213  size_t INSPIj =
214  this->populations.get_flat_index({j, InfectionState::InfectedNoSymptomsPartialImmunity});
215  size_t ISyPIj = this->populations.get_flat_index({j, InfectionState::InfectedSymptomsPartialImmunity});
216  size_t ISevPIj = this->populations.get_flat_index({j, InfectionState::InfectedSeverePartialImmunity});
217  size_t ICrPIj = this->populations.get_flat_index({j, InfectionState::InfectedCriticalPartialImmunity});
218 
219  size_t INSPICj =
220  this->populations.get_flat_index({j, InfectionState::InfectedNoSymptomsPartialImmunityConfirmed});
221  size_t ISyPICj =
222  this->populations.get_flat_index({j, InfectionState::InfectedSymptomsPartialImmunityConfirmed});
223 
224  size_t EIIj = this->populations.get_flat_index({j, InfectionState::ExposedImprovedImmunity});
225  size_t INSIIj =
226  this->populations.get_flat_index({j, InfectionState::InfectedNoSymptomsImprovedImmunity});
227  size_t ISyIIj = this->populations.get_flat_index({j, InfectionState::InfectedSymptomsImprovedImmunity});
228  size_t ISevIIj = this->populations.get_flat_index({j, InfectionState::InfectedSevereImprovedImmunity});
229  size_t ICrIIj = this->populations.get_flat_index({j, InfectionState::InfectedCriticalImprovedImmunity});
230 
231  size_t INSIICj =
232  this->populations.get_flat_index({j, InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed});
233  size_t ISyIICj =
234  this->populations.get_flat_index({j, InfectionState::InfectedSymptomsImprovedImmunityConfirmed});
235 
236  // effective contact rate by contact rate between groups i and j and damping j
237  FP season_val = (1 + params.template get<Seasonality<FP>>() *
238  sin(std::numbers::pi_v<ScalarType> *
239  ((params.template get<StartDay<FP>>() + t) / 182.5 + 0.5)));
240  FP cont_freq_eff =
241  season_val * contact_matrix.get_matrix_at(SimulationTime<FP>(t))(
242  static_cast<Eigen::Index>((size_t)i), static_cast<Eigen::Index>((size_t)j));
243  // without died people
244  FP Nj = pop[SNj] + pop[ENj] + pop[INSNj] + pop[ISyNj] + pop[ISevNj] + pop[ICrNj] + pop[INSNCj] +
245  pop[ISyNCj] + pop[SPIj] + pop[EPIj] + pop[INSPIj] + pop[ISyPIj] + pop[ISevPIj] + pop[ICrPIj] +
246  pop[INSPICj] + pop[ISyPICj] + pop[SIIj] + pop[EIIj] + pop[INSIIj] + pop[ISyIIj] + pop[ISevIIj] +
247  pop[ICrIIj] + pop[INSIICj] + pop[ISyIICj];
248  const FP divNj = (Nj < Limits<FP>::zero_tolerance()) ? FP(0.0) : FP(1.0 / Nj);
249 
250  FP ext_inf_force_dummy = cont_freq_eff * divNj *
251  params.template get<TransmissionProbabilityOnContact<FP>>()[(AgeGroup)i] *
252  (riskFromInfectedNoSymptoms * (pop[INSNj] + pop[INSPIj] + pop[INSIIj]) +
253  riskFromInfectedSymptomatic * (pop[ISyNj] + pop[ISyPIj] + pop[ISyIIj]));
254 
255  FP dummy_SN = y[SNi] * ext_inf_force_dummy;
256 
257  FP dummy_SPI = y[SPIi] * reducExposedPartialImmunity * ext_inf_force_dummy;
258 
259  FP dummy_SII = y[SIIi] * reducExposedImprovedImmunity * ext_inf_force_dummy;
260 
261  flows[this->template get_flat_flow_index<InfectionState::SusceptibleNaive,
262  InfectionState::ExposedNaive>({i})] += dummy_SN;
263  flows[this->template get_flat_flow_index<InfectionState::SusceptiblePartialImmunity,
264  InfectionState::ExposedPartialImmunity>({i})] += dummy_SPI;
265  flows[this->template get_flat_flow_index<InfectionState::SusceptibleImprovedImmunity,
266  InfectionState::ExposedImprovedImmunity>({i})] += dummy_SII;
267  }
268 
269  // ICU capacity shortage is close
270  // TODO: if this is used with vaccination model, it has to be adapted if CriticalPerSevere
271  // is different for different vaccination status. This is not the case here and in addition, ICUCapacity
272  // is set to infinity and this functionality is deactivated, so this is OK for the moment.
273  FP criticalPerSevereAdjusted = smoother_cosine<FP>(
274  icu_occupancy, 0.90 * params.template get<ICUCapacity<FP>>(), params.template get<ICUCapacity<FP>>(),
275  params.template get<CriticalPerSevere<FP>>()[i], 0);
276 
277  FP deathsPerSevereAdjusted = params.template get<CriticalPerSevere<FP>>()[i] - criticalPerSevereAdjusted;
278 
279  /**** path of immune-naive ***/
280  // Exposed
281  flows[this->template get_flat_flow_index<InfectionState::ExposedNaive,
282  InfectionState::InfectedNoSymptomsNaive>({i})] +=
283  y[ENi] / params.template get<TimeExposed<FP>>()[i];
284 
285  // InfectedNoSymptoms
286  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsNaive,
287  InfectionState::SusceptibleImprovedImmunity>({i})] =
288  params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i] /
289  params.template get<TimeInfectedNoSymptoms<FP>>()[i] * y[INSNi];
290  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsNaive,
291  InfectionState::InfectedSymptomsNaive>({i})] =
292  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]) /
293  params.template get<TimeInfectedNoSymptoms<FP>>()[i] * y[INSNi];
294  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsNaiveConfirmed,
295  InfectionState::InfectedSymptomsNaiveConfirmed>({i})] =
296  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]) /
297  params.template get<TimeInfectedNoSymptoms<FP>>()[i] * y[INSNCi];
298  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsNaiveConfirmed,
299  InfectionState::SusceptibleImprovedImmunity>({i})] =
300  params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i] /
301  params.template get<TimeInfectedNoSymptoms<FP>>()[i] * y[INSNCi];
302 
303  // InfectedSymptoms
304  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsNaive,
305  InfectionState::InfectedSevereNaive>({i})] =
306  params.template get<SeverePerInfectedSymptoms<FP>>()[i] /
307  params.template get<TimeInfectedSymptoms<FP>>()[i] * y[ISyNi];
308 
309  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsNaive,
310  InfectionState::SusceptibleImprovedImmunity>({i})] =
311  (1 - params.template get<SeverePerInfectedSymptoms<FP>>()[i]) /
312  params.template get<TimeInfectedSymptoms<FP>>()[i] * y[ISyNi];
313 
314  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsNaiveConfirmed,
315  InfectionState::InfectedSevereNaive>({i})] =
316  params.template get<SeverePerInfectedSymptoms<FP>>()[i] /
317  params.template get<TimeInfectedSymptoms<FP>>()[i] * y[ISyNCi];
318 
319  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsNaiveConfirmed,
320  InfectionState::SusceptibleImprovedImmunity>({i})] =
321  (1 - params.template get<SeverePerInfectedSymptoms<FP>>()[i]) /
322  params.template get<TimeInfectedSymptoms<FP>>()[i] * y[ISyNCi];
323 
324  // InfectedSevere
325  flows[this->template get_flat_flow_index<InfectionState::InfectedSevereNaive,
326  InfectionState::InfectedCriticalNaive>({i})] =
327  criticalPerSevereAdjusted / params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevNi];
328 
329  flows[this->template get_flat_flow_index<InfectionState::InfectedSevereNaive,
330  InfectionState::SusceptibleImprovedImmunity>({i})] =
331  (1 - params.template get<CriticalPerSevere<FP>>()[i]) /
332  params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevNi];
333 
334  flows[this->template get_flat_flow_index<InfectionState::InfectedSevereNaive, InfectionState::DeadNaive>(
335  {i})] = deathsPerSevereAdjusted / params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevNi];
336 
337  // InfectedCritical
338  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalNaive, InfectionState::DeadNaive>(
339  {i})] = params.template get<DeathsPerCritical<FP>>()[i] /
340  params.template get<TimeInfectedCritical<FP>>()[i] * y[ICrNi];
341 
342  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalNaive,
343  InfectionState::SusceptibleImprovedImmunity>({i})] =
344  (1 - params.template get<DeathsPerCritical<FP>>()[i]) /
345  params.template get<TimeInfectedCritical<FP>>()[i] * y[ICrNi];
346 
347  // /**** path of partially immune (e.g., one dose of vaccination) ***/
348  // Exposed
349  flows[this->template get_flat_flow_index<InfectionState::ExposedPartialImmunity,
350  InfectionState::InfectedNoSymptomsPartialImmunity>({i})] +=
351  y[EPIi] / params.template get<TimeExposed<FP>>()[i];
352 
353  // InfectedNoSymptoms
354  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsPartialImmunity,
355  InfectionState::SusceptibleImprovedImmunity>({i})] =
356  (1 - (reducInfectedSymptomsPartialImmunity / reducExposedPartialImmunity) *
357  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i])) /
358  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSPIi];
359  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsPartialImmunity,
360  InfectionState::InfectedSymptomsPartialImmunity>({i})] =
361  (reducInfectedSymptomsPartialImmunity / reducExposedPartialImmunity) *
362  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]) /
363  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSPIi];
364  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsPartialImmunityConfirmed,
365  InfectionState::InfectedSymptomsPartialImmunityConfirmed>({i})] =
366  (reducInfectedSymptomsPartialImmunity / reducExposedPartialImmunity) *
367  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]) /
368  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSPICi];
369  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsPartialImmunityConfirmed,
370  InfectionState::SusceptibleImprovedImmunity>({i})] =
371  (1 - (reducInfectedSymptomsPartialImmunity / reducExposedPartialImmunity) *
372  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i])) /
373  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSPICi];
374 
375  // InfectedSymptoms
376  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsPartialImmunity,
377  InfectionState::InfectedSeverePartialImmunity>({i})] =
378  reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSymptomsPartialImmunity *
379  params.template get<SeverePerInfectedSymptoms<FP>>()[i] /
380  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyPIi];
381 
382  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsPartialImmunity,
383  InfectionState::SusceptibleImprovedImmunity>({i})] =
384  (1 - (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSymptomsPartialImmunity) *
385  params.template get<SeverePerInfectedSymptoms<FP>>()[i]) /
386  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyPIi];
387 
388  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsPartialImmunityConfirmed,
389  InfectionState::InfectedSeverePartialImmunity>({i})] =
390  reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSymptomsPartialImmunity *
391  params.template get<SeverePerInfectedSymptoms<FP>>()[i] /
392  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyPICi];
393 
394  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsPartialImmunityConfirmed,
395  InfectionState::SusceptibleImprovedImmunity>({i})] =
396  (1 - (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSymptomsPartialImmunity) *
397  params.template get<SeverePerInfectedSymptoms<FP>>()[i]) /
398  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyPICi];
399 
400  // InfectedSevere
401  flows[this->template get_flat_flow_index<InfectionState::InfectedSeverePartialImmunity,
402  InfectionState::InfectedCriticalPartialImmunity>({i})] =
403  reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSevereCriticalDeadPartialImmunity *
404  criticalPerSevereAdjusted / params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevPIi];
405 
406  flows[this->template get_flat_flow_index<InfectionState::InfectedSeverePartialImmunity,
407  InfectionState::SusceptibleImprovedImmunity>({i})] =
408  (1 - (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSevereCriticalDeadPartialImmunity) *
409  params.template get<CriticalPerSevere<FP>>()[i]) /
410  params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevPIi];
411 
412  flows[this->template get_flat_flow_index<InfectionState::InfectedSeverePartialImmunity,
413  InfectionState::DeadPartialImmunity>({i})] =
414  (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSevereCriticalDeadPartialImmunity) *
415  deathsPerSevereAdjusted / params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevPIi];
416 
417  // InfectedCritical
418  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalPartialImmunity,
419  InfectionState::DeadPartialImmunity>({i})] =
420  (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSevereCriticalDeadPartialImmunity) *
421  params.template get<DeathsPerCritical<FP>>()[i] / params.template get<TimeInfectedCritical<FP>>()[i] *
422  y[ICrPIi];
423 
424  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalPartialImmunity,
425  InfectionState::SusceptibleImprovedImmunity>({i})] =
426  (1 - (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSevereCriticalDeadPartialImmunity) *
427  params.template get<DeathsPerCritical<FP>>()[i]) /
428  params.template get<TimeInfectedCritical<FP>>()[i] * y[ICrPIi];
429 
430  // /**** path of twice vaccinated, here called immune although reinfection is possible now ***/
431  // Exposed
432  flows[this->template get_flat_flow_index<InfectionState::ExposedImprovedImmunity,
433  InfectionState::InfectedNoSymptomsImprovedImmunity>({i})] +=
434  y[EIIi] / params.template get<TimeExposed<FP>>()[i];
435 
436  // InfectedNoSymptoms
437  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsImprovedImmunity,
438  InfectionState::SusceptibleImprovedImmunity>({i})] =
439  (1 - (reducInfectedSymptomsImprovedImmunity / reducExposedImprovedImmunity) *
440  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i])) /
441  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSIIi];
442  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsImprovedImmunity,
443  InfectionState::InfectedSymptomsImprovedImmunity>({i})] =
444  (reducInfectedSymptomsImprovedImmunity / reducExposedImprovedImmunity) *
445  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]) /
446  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSIIi];
447  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed,
448  InfectionState::InfectedSymptomsImprovedImmunityConfirmed>({i})] =
449  (reducInfectedSymptomsImprovedImmunity / reducExposedImprovedImmunity) *
450  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]) /
451  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSIICi];
452  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed,
453  InfectionState::SusceptibleImprovedImmunity>({i})] =
454  (1 - (reducInfectedSymptomsImprovedImmunity / reducExposedImprovedImmunity) *
455  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i])) /
456  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSIICi];
457 
458  // InfectedSymptoms
459  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsImprovedImmunity,
460  InfectionState::InfectedSevereImprovedImmunity>({i})] =
461  reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSymptomsImprovedImmunity *
462  params.template get<SeverePerInfectedSymptoms<FP>>()[i] /
463  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyIIi];
464 
465  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsImprovedImmunity,
466  InfectionState::SusceptibleImprovedImmunity>({i})] =
467  (1 - (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSymptomsImprovedImmunity) *
468  params.template get<SeverePerInfectedSymptoms<FP>>()[i]) /
469  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyIIi];
470 
471  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsImprovedImmunityConfirmed,
472  InfectionState::InfectedSevereImprovedImmunity>({i})] =
473  reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSymptomsImprovedImmunity *
474  params.template get<SeverePerInfectedSymptoms<FP>>()[i] /
475  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyIICi];
476 
477  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsImprovedImmunityConfirmed,
478  InfectionState::SusceptibleImprovedImmunity>({i})] =
479  (1 - (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSymptomsImprovedImmunity) *
480  params.template get<SeverePerInfectedSymptoms<FP>>()[i]) /
481  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyIICi];
482 
483  // InfectedSevere
484  flows[this->template get_flat_flow_index<InfectionState::InfectedSevereImprovedImmunity,
485  InfectionState::InfectedCriticalImprovedImmunity>({i})] =
486  reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSevereCriticalDeadImprovedImmunity *
487  criticalPerSevereAdjusted / params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevIIi];
488 
489  flows[this->template get_flat_flow_index<InfectionState::InfectedSevereImprovedImmunity,
490  InfectionState::SusceptibleImprovedImmunity>({i})] =
491  (1 -
492  (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSevereCriticalDeadImprovedImmunity) *
493  params.template get<CriticalPerSevere<FP>>()[i]) /
494  params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevIIi];
495 
496  flows[this->template get_flat_flow_index<InfectionState::InfectedSevereImprovedImmunity,
497  InfectionState::DeadImprovedImmunity>({i})] =
498  (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSevereCriticalDeadImprovedImmunity) *
499  deathsPerSevereAdjusted / params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevIIi];
500 
501  // InfectedCritical
502  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalImprovedImmunity,
503  InfectionState::DeadImprovedImmunity>({i})] =
504  (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSevereCriticalDeadImprovedImmunity) *
505  params.template get<DeathsPerCritical<FP>>()[i] / params.template get<TimeInfectedCritical<FP>>()[i] *
506  y[ICrIIi];
507 
508  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalImprovedImmunity,
509  InfectionState::SusceptibleImprovedImmunity>({i})] =
510  (1 -
511  (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSevereCriticalDeadImprovedImmunity) *
512  params.template get<DeathsPerCritical<FP>>()[i]) /
513  params.template get<TimeInfectedCritical<FP>>()[i] * y[ICrIIi];
514  }
515  }
516 
521  template <class IOContext>
522  void serialize(IOContext& io) const
523  {
524  auto obj = io.create_object("Model");
525  obj.add_element("Parameters", this->parameters);
526  obj.add_element("Populations", this->populations);
527  }
528 
533  template <class IOContext>
534  static IOResult<Model> deserialize(IOContext& io)
535  {
536  auto obj = io.expect_object("Model");
537  auto par = obj.expect_element("Parameters", Tag<ParameterSet>{});
538  auto pop = obj.expect_element("Populations", Tag<Populations>{});
539  return apply(
540  io,
541  [](auto&& par_, auto&& pop_) {
542  return Model{pop_, par_};
543  },
544  par, pop);
545  }
546 };
547 
548 //forward declaration, see below.
549 template <typename FP, class Base = mio::Simulation<FP, Model<FP>>>
550 class Simulation;
551 
559 template <typename FP, class Base = mio::Simulation<FP, Model<FP>>>
560 FP get_infections_relative(const Simulation<FP, Base>& model, FP t, const Eigen::Ref<const Eigen::VectorX<FP>>& y);
561 
567 template <typename FP, class BaseT>
568 class Simulation : public BaseT
569 {
570 public:
577  Simulation(mio::osecirvvs::Model<FP> const& model, FP t0 = 0., FP dt = 0.1)
578  : BaseT(model, t0, dt)
579  , m_t_last_npi_check(t0)
580  {
581  }
582 
595  void apply_variant(const FP t, const CustomIndexArray<UncertainValue<FP>, AgeGroup> base_infectiousness)
596  {
597  using std::min;
598  using std::pow;
599 
600  auto start_day = this->get_model().parameters.template get<StartDay<FP>>();
601  auto start_day_new_variant = this->get_model().parameters.template get<StartDayNewVariant<FP>>();
602 
603  if (start_day + t >= start_day_new_variant - 1e-10) {
604  const FP days_variant = t - (start_day_new_variant - start_day);
605  const FP share_new_variant = min<FP>(1.0, 0.01 * pow(2, (1. / 7) * days_variant));
606  const auto num_groups = this->get_model().parameters.get_num_groups();
607  for (auto i = AgeGroup(0); i < num_groups; ++i) {
608  FP new_transmission = (1 - share_new_variant) * base_infectiousness[i] +
609  share_new_variant * base_infectiousness[i] *
610  this->get_model().parameters.template get<InfectiousnessNewVariant<FP>>()[i];
611  this->get_model().parameters.template get<TransmissionProbabilityOnContact<FP>>()[i] = new_transmission;
612  }
613  }
614  }
615 
616  void apply_vaccination(FP t)
617  {
618  using std::floor;
619  auto t_idx = SimulationDay(size_t(floor(t)));
620  auto& params = this->get_model().parameters;
621  size_t num_groups = (size_t)params.get_num_groups();
622  auto last_value = this->get_result().get_last_value();
623 
624  auto count = (size_t)InfectionState::Count;
625  auto S = (size_t)InfectionState::SusceptibleNaive;
626  auto SV = (size_t)InfectionState::SusceptiblePartialImmunity;
627  auto R = (size_t)InfectionState::SusceptibleImprovedImmunity;
628 
629  for (size_t i = 0; i < num_groups; ++i) {
630 
631  FP first_vacc;
632  FP full_vacc;
633  if (t_idx == SimulationDay(0)) {
634  first_vacc = params.template get<DailyPartialVaccinations<FP>>()[{(AgeGroup)i, t_idx}];
635  full_vacc = params.template get<DailyFullVaccinations<FP>>()[{(AgeGroup)i, t_idx}];
636  }
637  else {
638  first_vacc =
639  params.template get<DailyPartialVaccinations<FP>>()[{(AgeGroup)i, t_idx}] -
640  params.template get<DailyPartialVaccinations<FP>>()[{(AgeGroup)i, t_idx - SimulationDay(1)}];
641  full_vacc = params.template get<DailyFullVaccinations<FP>>()[{(AgeGroup)i, t_idx}] -
642  params.template get<DailyFullVaccinations<FP>>()[{(AgeGroup)i, t_idx - SimulationDay(1)}];
643  }
644 
645  if (last_value(count * i + S) - first_vacc < 0) {
646  FP corrected = 0.99 * last_value(count * i + S);
647  log_warning("too many first vaccinated at time {}: setting first_vacc from {} to {}", t, first_vacc,
648  corrected);
649  first_vacc = corrected;
650  }
651 
652  last_value(count * i + S) -= first_vacc;
653  last_value(count * i + SV) += first_vacc;
654 
655  if (last_value(count * i + SV) - full_vacc < 0) {
656  FP corrected = 0.99 * last_value(count * i + SV);
657  log_warning("too many fully vaccinated at time {}: setting full_vacc from {} to {}", t, full_vacc,
658  corrected);
659  full_vacc = corrected;
660  }
661 
662  last_value(count * i + SV) -= full_vacc;
663  last_value(count * i + R) += full_vacc;
664  }
665  }
666 
674  Eigen::Ref<Eigen::VectorX<FP>> advance(FP tmax)
675  {
676  using std::floor;
677  using std::min;
678 
679  auto& t_end_dyn_npis = this->get_model().parameters.get_end_dynamic_npis();
680  auto& dyn_npis = this->get_model().parameters.template get<DynamicNPIsInfectedSymptoms<FP>>();
681  auto& contact_patterns = this->get_model().parameters.template get<ContactPatterns<FP>>();
682  // const size_t num_groups = (size_t)this->get_model().parameters.get_num_groups();
683 
684  // in the apply_variant function, we adjust the TransmissionProbabilityOnContact parameter. We need to store
685  // the base value to use it in the apply_variant function and also to reset the parameter after the simulation.
686  auto base_infectiousness = this->get_model().parameters.template get<TransmissionProbabilityOnContact<FP>>();
687 
688  FP delay_npi_implementation;
689  FP t = BaseT::get_result().get_last_time();
690  const FP dt = dyn_npis.get_thresholds().size() > 0 ? dyn_npis.get_interval().get() : tmax;
691  while (t < tmax) {
692 
693  FP dt_eff = min<FP>(dt, tmax - t);
694  dt_eff = min<FP>(dt_eff, m_t_last_npi_check + dt - t);
695 
696  if (dt_eff >= 1.0) {
697  dt_eff = 1.0;
698  }
699 
700  if (t == 0) {
701  //this->apply_vaccination(t); // done in init now?
702  this->apply_variant(t, base_infectiousness);
703  }
704  BaseT::advance(t + dt_eff);
705  if (t + 0.5 + dt_eff - floor(t + 0.5) >= 1) {
706  this->apply_vaccination(t + 0.5 + dt_eff);
707  this->apply_variant(t, base_infectiousness);
708  }
709 
710  if (t > 0) {
711  delay_npi_implementation =
712  this->get_model().parameters.template get<DynamicNPIsImplementationDelay<FP>>();
713  }
714  else { // DynamicNPIs for t=0 are 'misused' to be from-start NPIs. I.e., do not enforce delay.
715  delay_npi_implementation = 0;
716  }
717  t = t + dt_eff;
718 
719  if (dyn_npis.get_thresholds().size() > 0) {
720  if (floating_point_greater_equal<FP>(t, m_t_last_npi_check + dt)) {
721  if (t < t_end_dyn_npis) {
722  auto inf_rel = get_infections_relative<FP>(*this, t, this->get_result().get_last_value()) *
723  dyn_npis.get_base_value();
724  auto exceeded_threshold = dyn_npis.get_max_exceeded_threshold(inf_rel);
725  if (exceeded_threshold != dyn_npis.get_thresholds().end() &&
726  (exceeded_threshold->first > m_dynamic_npi.first ||
727  t > FP(m_dynamic_npi.second))) { //old npi was weaker or is expired
728 
729  auto t_start = SimulationTime<FP>(t + delay_npi_implementation);
730  auto t_end = t_start + SimulationTime<FP>(dyn_npis.get_duration());
731  this->get_model().parameters.get_start_commuter_detection() = t_start.get();
732  this->get_model().parameters.get_end_commuter_detection() = t_end.get();
733  m_dynamic_npi = std::make_pair(exceeded_threshold->first, t_end);
734  implement_dynamic_npis(contact_patterns.get_cont_freq_mat(), exceeded_threshold->second,
735  t_start, t_end, [](auto& g) {
736  return make_contact_damping_matrix(g);
737  });
738  }
739  }
740  m_t_last_npi_check = t;
741  }
742  }
743  else {
744  m_t_last_npi_check = t;
745  }
746  }
747  // reset TransmissionProbabilityOnContact. This is important for the graph simulation where the advance
748  // function is called multiple times for the same model.
749  this->get_model().parameters.template get<TransmissionProbabilityOnContact<FP>>() = base_infectiousness;
750 
751  return this->get_result().get_last_value();
752  }
753 
754 private:
756  std::pair<FP, SimulationTime<FP>> m_dynamic_npi = {-std::numeric_limits<FP>::max(), SimulationTime<FP>(0)};
757 };
758 
771 template <typename FP>
772 inline auto simulate(FP t0, FP tmax, FP dt, const Model<FP>& model,
773  std::unique_ptr<OdeIntegratorCore<FP>>&& integrator_core = nullptr)
774 {
775  return mio::simulate<FP, Model<FP>, Simulation<FP>>(t0, tmax, dt, model, std::move(integrator_core));
776 }
777 
790 template <typename FP>
791 inline auto simulate_flows(FP t0, FP tmax, FP dt, const Model<FP>& model,
792  std::unique_ptr<OdeIntegratorCore<FP>>&& integrator_core = nullptr)
793 {
794  return mio::simulate_flows<FP, Model<FP>, Simulation<FP, mio::FlowSimulation<FP, Model<FP>>>>(
795  t0, tmax, dt, model, std::move(integrator_core));
796 }
797 
798 //see declaration above.
799 template <typename FP, class Base>
800 FP get_infections_relative(const Simulation<FP, Base>& sim, FP /*t*/, const Eigen::Ref<const Eigen::VectorX<FP>>& y)
801 {
802  FP sum_inf = 0;
803  for (auto i = AgeGroup(0); i < sim.get_model().parameters.get_num_groups(); ++i) {
804  sum_inf += sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsNaive});
805  sum_inf += sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsNaiveConfirmed});
806  sum_inf += sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsPartialImmunity});
807  sum_inf += sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsImprovedImmunity});
808  sum_inf +=
809  sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsPartialImmunityConfirmed});
810  sum_inf +=
811  sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsImprovedImmunityConfirmed});
812  }
813  auto inf_rel = sum_inf / sim.get_model().populations.get_total();
814 
815  return inf_rel;
816 }
817 
828 template <typename FP, class Base = mio::Simulation<FP, Model<FP>>>
829 auto get_mobility_factors(const Simulation<Base>& sim, FP /*t*/, const Eigen::Ref<const Eigen::VectorX<FP>>& y)
830 
831 {
832  auto& params = sim.get_model().parameters;
833  //parameters as arrays
834  auto& p_asymp = params.template get<RecoveredPerInfectedNoSymptoms<FP>>().array().template cast<FP>();
835  auto& p_inf = params.template get<RiskOfInfectionFromSymptomatic<FP>>().array().template cast<FP>();
836  auto& p_inf_max = params.template get<MaxRiskOfInfectionFromSymptomatic<FP>>().array().template cast<FP>();
837  //slice of InfectedNoSymptoms
838  auto y_INS = slice(y, {Eigen::Index(InfectionState::InfectedNoSymptomsNaive),
839  Eigen::Index(size_t(params.get_num_groups())), Eigen::Index(InfectionState::Count)}) +
840  slice(y, {Eigen::Index(InfectionState::InfectedNoSymptomsPartialImmunity),
841  Eigen::Index(size_t(params.get_num_groups())), Eigen::Index(InfectionState::Count)}) +
842  slice(y, {Eigen::Index(InfectionState::InfectedNoSymptomsImprovedImmunity),
843  Eigen::Index(size_t(params.get_num_groups())), Eigen::Index(InfectionState::Count)});
844 
845  //compute isolation, same as infection risk from main model
846  auto test_and_trace_required =
847  ((1 - p_asymp) / params.template get<TimeInfectedNoSymptoms<FP>>().array().template cast<FP>() * y_INS.array())
848  .sum();
849  auto riskFromInfectedSymptomatic =
850  smoother_cosine<FP>(test_and_trace_required, FP(params.template get<TestAndTraceCapacity<FP>>()),
851  params.template get<TestAndTraceCapacity<FP>>() *
852  params.template get<TestAndTraceCapacityMaxRiskSymptoms<FP>>(),
853  p_inf.matrix(), p_inf_max.matrix());
854 
855  //set factor for infected
856  auto factors = Eigen::VectorX<FP>::Ones(y.rows()).eval();
857  slice(factors, {Eigen::Index(InfectionState::InfectedSymptomsNaive), Eigen::Index(size_t(params.get_num_groups())),
858  Eigen::Index(InfectionState::Count)})
859  .array() = riskFromInfectedSymptomatic;
860  slice(factors, {Eigen::Index(InfectionState::InfectedSymptomsPartialImmunity),
861  Eigen::Index(size_t(params.get_num_groups())), Eigen::Index(InfectionState::Count)})
862  .array() = riskFromInfectedSymptomatic;
863  slice(factors, {Eigen::Index(InfectionState::InfectedSymptomsImprovedImmunity),
864  Eigen::Index(size_t(params.get_num_groups())), Eigen::Index(InfectionState::Count)})
865  .array() = riskFromInfectedSymptomatic;
866  return factors;
867 }
868 
869 template <typename FP, class Base = mio::Simulation<FP, Model<FP>>>
870 auto test_commuters(Simulation<FP, Base>& sim, Eigen::Ref<Eigen::VectorX<FP>> mobile_population, FP time)
871 {
872  auto& model = sim.get_model();
873  FP nondetection = 1.0;
874  if (time >= model.parameters.get_start_commuter_detection() &&
875  time < model.parameters.get_end_commuter_detection()) {
876  nondetection = (FP)model.parameters.get_commuter_nondetection();
877  }
878  for (auto i = AgeGroup(0); i < model.parameters.get_num_groups(); ++i) {
879  auto ISyNi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsNaive});
880  auto ISyNCi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsNaiveConfirmed});
881  auto INSNi = model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsNaive});
882  auto INSNCi = model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsNaiveConfirmed});
883 
884  auto ISPIi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsPartialImmunity});
885  auto ISPICi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsPartialImmunityConfirmed});
886  auto INSPIi = model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsPartialImmunity});
887  auto INSPICi =
888  model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsPartialImmunityConfirmed});
889 
890  auto ISyIIi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsImprovedImmunity});
891  auto ISyIICi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsImprovedImmunityConfirmed});
892  auto INSIIi = model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsImprovedImmunity});
893  auto INSIICi =
894  model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed});
895 
896  //put detected commuters in their own compartment so they don't contribute to infections in their home node
897  sim.get_result().get_last_value()[ISyNi] -= mobile_population[ISyNi] * (1 - nondetection);
898  sim.get_result().get_last_value()[ISyNCi] += mobile_population[ISyNi] * (1 - nondetection);
899  sim.get_result().get_last_value()[INSNi] -= mobile_population[INSNi] * (1 - nondetection);
900  sim.get_result().get_last_value()[INSNCi] += mobile_population[INSNi] * (1 - nondetection);
901 
902  sim.get_result().get_last_value()[ISPIi] -= mobile_population[ISPIi] * (1 - nondetection);
903  sim.get_result().get_last_value()[ISPICi] += mobile_population[ISPIi] * (1 - nondetection);
904  sim.get_result().get_last_value()[INSPIi] -= mobile_population[INSPIi] * (1 - nondetection);
905  sim.get_result().get_last_value()[INSPICi] += mobile_population[INSPIi] * (1 - nondetection);
906 
907  sim.get_result().get_last_value()[ISyIIi] -= mobile_population[ISyIIi] * (1 - nondetection);
908  sim.get_result().get_last_value()[ISyIICi] += mobile_population[ISyIIi] * (1 - nondetection);
909  sim.get_result().get_last_value()[INSIIi] -= mobile_population[INSIIi] * (1 - nondetection);
910  sim.get_result().get_last_value()[INSIICi] += mobile_population[INSIIi] * (1 - nondetection);
911 
912  //reduce the number of commuters
913  mobile_population[ISyNi] *= nondetection;
914  mobile_population[INSNi] *= nondetection;
915 
916  mobile_population[ISPIi] *= nondetection;
917  mobile_population[INSPIi] *= nondetection;
918 
919  mobile_population[ISyIIi] *= nondetection;
920  mobile_population[INSIIi] *= nondetection;
921  }
922 }
923 
924 } // namespace osecirvvs
925 } // namespace mio
926 
927 #endif //MIO_ODE_SECIRVVS_MODEL_H
represents a collection of contact frequency matrices that whose sum is the total number of contacts.
Definition: contact_matrix.h:536
A class template for an array with custom indices.
Definition: custom_index_array.h:136
A FlowModel is a CompartmentalModel defined by the flows between compartments.
Definition: flow_model.h:74
Interface class defining the integration step used in a SystemIntegrator.
Definition: integrator.h:48
A class template for compartment populations.
Definition: populations.h:55
decltype(auto) get_from(Arr &&y, Index const &cats) const
get_from returns the value of a flat container at the flat index corresponding to set of enum values.
Definition: populations.h:123
Represents the simulation time as an integer index.
Definition: simulation_day.h:32
double simulation time.
Definition: damping.h:58
Parameters of the simulation that are the same everywhere within the Model.
Definition: abm/parameters.h:764
Run the Simulation in discrete steps, evolve the Model and report results.
Definition: models/abm/simulation.h:37
Definition: ode_secirvvs/model.h:94
void serialize(IOContext &io) const
serialize this.
Definition: ode_secirvvs/model.h:522
Model(const Populations &pop, const ParameterSet &params)
Definition: ode_secirvvs/model.h:101
static IOResult< Model > deserialize(IOContext &io)
deserialize an object of this class.
Definition: ode_secirvvs/model.h:534
void get_flows(Eigen::Ref< const Eigen::VectorX< FP >> pop, Eigen::Ref< const Eigen::VectorX< FP >> y, FP t, Eigen::Ref< Eigen::VectorX< FP >> flows) const override
Definition: ode_secirvvs/model.h:111
Model(int num_agegroups)
Definition: ode_secirvvs/model.h:106
Parameters of an age-resolved SECIR/SECIHURD model with paths for partial and improved immunity throu...
Definition: ode_secirvvs/parameters.h:645
specialization of compartment model simulation for the SECIRVVS model.
Definition: ode_secirvvs/model.h:569
FP m_t_last_npi_check
Definition: ode_secirvvs/model.h:755
void apply_vaccination(FP t)
Definition: ode_secirvvs/model.h:616
Eigen::Ref< Eigen::VectorX< FP > > advance(FP tmax)
advance simulation to tmax.
Definition: ode_secirvvs/model.h:674
Simulation(mio::osecirvvs::Model< FP > const &model, FP t0=0., FP dt=0.1)
construct a simulation.
Definition: ode_secirvvs/model.h:577
void apply_variant(const FP t, const CustomIndexArray< UncertainValue< FP >, AgeGroup > base_infectiousness)
Applies the effect of a new variant of a disease to the transmission probability of the model.
Definition: ode_secirvvs/model.h:595
ad::internal::unary_intermediate< AD_TAPE_REAL, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::operations::ad_sin< AD_TAPE_REAL > > sin(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x1)
Definition: ad.hpp:913
static double floor(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x)
Definition: ad.hpp:2451
static min_max_return_type< ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > >::type min(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &a, const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &b)
Definition: ad.hpp:2599
ad::internal::binary_intermediate_aa< AD_TAPE_REAL, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::operations::ad_pow_aa< AD_TAPE_REAL > > pow(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x1, const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x2)
Definition: ad.hpp:1610
static min_max_return_type< ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > >::type max(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &a, const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &b)
Definition: ad.hpp:2596
auto get_mobility_factors(const Simulation< Base > &sim, FP, const Eigen::Ref< const Eigen::VectorX< FP >> &y)
Get mobility factors.
Definition: ode_secirvvs/model.h:829
auto test_commuters(Simulation< FP, Base > &sim, Eigen::Ref< Eigen::VectorX< FP >> mobile_population, FP time)
Definition: ode_secirvvs/model.h:870
FP get_infections_relative(const Simulation< FP, Base > &model, FP t, const Eigen::Ref< const Eigen::VectorX< FP >> &y)
get percentage of infections per total population.
Definition: ode_secirvvs/model.h:800
auto simulate(FP t0, FP tmax, FP dt, const Model< FP > &model, std::unique_ptr< OdeIntegratorCore< FP >> &&integrator_core=nullptr)
Specialization of simulate for SECIRVVS models using Simulation.
Definition: ode_secirvvs/model.h:772
auto simulate_flows(FP t0, FP tmax, FP dt, const Model< FP > &model, std::unique_ptr< OdeIntegratorCore< FP >> &&integrator_core=nullptr)
Specialization of simulate for SECIRVVS models using the FlowSimulation.
Definition: ode_secirvvs/model.h:791
A collection of classes to simplify handling of matrix shapes in meta programming.
Definition: models/abm/analyze_result.h:30
boost::outcome_v2::in_place_type_t< T > Tag
Type that is used for overload resolution.
Definition: io.h:407
auto i
Definition: io.h:809
void log_warning(spdlog::string_view_t fmt, const Args &... args)
Definition: logging.h:112
details::ApplyResultT< F, T... > apply(IOContext &io, F f, const IOResult< T > &... rs)
Evaluate a function with zero or more unpacked IOResults as arguments.
Definition: io.h:481
auto slice(V &&v, Seq< Eigen::Index > elems)
take a regular slice of a row or column vector.
Definition: eigen_util.h:107
void implement_dynamic_npis(DampingExprGroup &damping_expr_group, const std::vector< DampingSampling< FP >> &npis, SimulationTime< FP > begin, SimulationTime< FP > end, MakeMatrix &&make_matrix)
implement dynamic NPIs for a time span.
Definition: dynamic_npis.h:279
constexpr std::tuple_element< I, std::tuple< Index< CategoryTags >... > >::type & get(Index< CategoryTags... > &i) noexcept
Retrieves the Index (by reference) at the Ith position of a MultiIndex.
Definition: index.h:294
boost::outcome_v2::unchecked< T, IOStatus > IOResult
Value-or-error type for operations that return a value but can fail.
Definition: io.h:353
The AgeGroup struct is used as a dynamically sized tag for all age dependent categories.
Definition: age_group.h:32
mio::Populations< FP, AgeGroup, InfectionState > Populations
Definition: compartmental_model.h:62
A Flow defines a possible transition between two Compartments in a FlowModel.
Definition: flow.h:33
Collection of types. Each type is mapped to an index of type size_t.
Definition: type_list.h:32
Multiplier for the test and trace capacity to determine when it is considered overloaded by symptomat...
Definition: ode_secirvvs/parameters.h:144
capacity to test and trace contacts of infected for quarantine per day.
Definition: ode_secirvvs/parameters.h:112
the (mean) time in day unit for asymptomatic cases that are infected but have not yet developed sympt...
Definition: ode_secirvvs/parameters.h:225