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] - params.template get<DeathsPerSevere<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})] = (params.template get<DeathsPerSevere<FP>>()[i] + deathsPerSevereAdjusted) /
336  params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevNi];
337 
338  // InfectedCritical
339  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalNaive, InfectionState::DeadNaive>(
340  {i})] = params.template get<DeathsPerCritical<FP>>()[i] /
341  params.template get<TimeInfectedCritical<FP>>()[i] * y[ICrNi];
342 
343  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalNaive,
344  InfectionState::SusceptibleImprovedImmunity>({i})] =
345  (1 - params.template get<DeathsPerCritical<FP>>()[i]) /
346  params.template get<TimeInfectedCritical<FP>>()[i] * y[ICrNi];
347 
348  // /**** path of partially immune (e.g., one dose of vaccination) ***/
349  // Exposed
350  flows[this->template get_flat_flow_index<InfectionState::ExposedPartialImmunity,
351  InfectionState::InfectedNoSymptomsPartialImmunity>({i})] +=
352  y[EPIi] / params.template get<TimeExposed<FP>>()[i];
353 
354  // InfectedNoSymptoms
355  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsPartialImmunity,
356  InfectionState::SusceptibleImprovedImmunity>({i})] =
357  (1 - (reducInfectedSymptomsPartialImmunity / reducExposedPartialImmunity) *
358  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i])) /
359  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSPIi];
360  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsPartialImmunity,
361  InfectionState::InfectedSymptomsPartialImmunity>({i})] =
362  (reducInfectedSymptomsPartialImmunity / reducExposedPartialImmunity) *
363  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]) /
364  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSPIi];
365  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsPartialImmunityConfirmed,
366  InfectionState::InfectedSymptomsPartialImmunityConfirmed>({i})] =
367  (reducInfectedSymptomsPartialImmunity / reducExposedPartialImmunity) *
368  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]) /
369  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSPICi];
370  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsPartialImmunityConfirmed,
371  InfectionState::SusceptibleImprovedImmunity>({i})] =
372  (1 - (reducInfectedSymptomsPartialImmunity / reducExposedPartialImmunity) *
373  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i])) /
374  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSPICi];
375 
376  // InfectedSymptoms
377  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsPartialImmunity,
378  InfectionState::InfectedSeverePartialImmunity>({i})] =
379  reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSymptomsPartialImmunity *
380  params.template get<SeverePerInfectedSymptoms<FP>>()[i] /
381  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyPIi];
382 
383  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsPartialImmunity,
384  InfectionState::SusceptibleImprovedImmunity>({i})] =
385  (1 - (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSymptomsPartialImmunity) *
386  params.template get<SeverePerInfectedSymptoms<FP>>()[i]) /
387  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyPIi];
388 
389  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsPartialImmunityConfirmed,
390  InfectionState::InfectedSeverePartialImmunity>({i})] =
391  reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSymptomsPartialImmunity *
392  params.template get<SeverePerInfectedSymptoms<FP>>()[i] /
393  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyPICi];
394 
395  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsPartialImmunityConfirmed,
396  InfectionState::SusceptibleImprovedImmunity>({i})] =
397  (1 - (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSymptomsPartialImmunity) *
398  params.template get<SeverePerInfectedSymptoms<FP>>()[i]) /
399  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyPICi];
400 
401  // InfectedSevere
402  flows[this->template get_flat_flow_index<InfectionState::InfectedSeverePartialImmunity,
403  InfectionState::InfectedCriticalPartialImmunity>({i})] =
404  reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSevereCriticalDeadPartialImmunity *
405  criticalPerSevereAdjusted / params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevPIi];
406 
407  flows[this->template get_flat_flow_index<InfectionState::InfectedSeverePartialImmunity,
408  InfectionState::SusceptibleImprovedImmunity>({i})] =
409  (1 - (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSevereCriticalDeadPartialImmunity) *
410  (params.template get<CriticalPerSevere<FP>>()[i] +
411  params.template get<DeathsPerSevere<FP>>()[i])) /
412  params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevPIi];
413 
414  flows[this->template get_flat_flow_index<InfectionState::InfectedSeverePartialImmunity,
415  InfectionState::DeadPartialImmunity>({i})] =
416  (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSevereCriticalDeadPartialImmunity) *
417  (params.template get<DeathsPerSevere<FP>>()[i] + deathsPerSevereAdjusted) /
418  params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevPIi];
419 
420  // InfectedCritical
421  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalPartialImmunity,
422  InfectionState::DeadPartialImmunity>({i})] =
423  (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSevereCriticalDeadPartialImmunity) *
424  params.template get<DeathsPerCritical<FP>>()[i] / params.template get<TimeInfectedCritical<FP>>()[i] *
425  y[ICrPIi];
426 
427  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalPartialImmunity,
428  InfectionState::SusceptibleImprovedImmunity>({i})] =
429  (1 - (reducInfectedSevereCriticalDeadPartialImmunity / reducInfectedSevereCriticalDeadPartialImmunity) *
430  params.template get<DeathsPerCritical<FP>>()[i]) /
431  params.template get<TimeInfectedCritical<FP>>()[i] * y[ICrPIi];
432 
433  // /**** path of twice vaccinated, here called immune although reinfection is possible now ***/
434  // Exposed
435  flows[this->template get_flat_flow_index<InfectionState::ExposedImprovedImmunity,
436  InfectionState::InfectedNoSymptomsImprovedImmunity>({i})] +=
437  y[EIIi] / params.template get<TimeExposed<FP>>()[i];
438 
439  // InfectedNoSymptoms
440  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsImprovedImmunity,
441  InfectionState::SusceptibleImprovedImmunity>({i})] =
442  (1 - (reducInfectedSymptomsImprovedImmunity / reducExposedImprovedImmunity) *
443  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i])) /
444  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSIIi];
445  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsImprovedImmunity,
446  InfectionState::InfectedSymptomsImprovedImmunity>({i})] =
447  (reducInfectedSymptomsImprovedImmunity / reducExposedImprovedImmunity) *
448  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]) /
449  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSIIi];
450  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed,
451  InfectionState::InfectedSymptomsImprovedImmunityConfirmed>({i})] =
452  (reducInfectedSymptomsImprovedImmunity / reducExposedImprovedImmunity) *
453  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]) /
454  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSIICi];
455  flows[this->template get_flat_flow_index<InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed,
456  InfectionState::SusceptibleImprovedImmunity>({i})] =
457  (1 - (reducInfectedSymptomsImprovedImmunity / reducExposedImprovedImmunity) *
458  (1 - params.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i])) /
459  (params.template get<TimeInfectedNoSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[INSIICi];
460 
461  // InfectedSymptoms
462  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsImprovedImmunity,
463  InfectionState::InfectedSevereImprovedImmunity>({i})] =
464  reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSymptomsImprovedImmunity *
465  params.template get<SeverePerInfectedSymptoms<FP>>()[i] /
466  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyIIi];
467 
468  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsImprovedImmunity,
469  InfectionState::SusceptibleImprovedImmunity>({i})] =
470  (1 - (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSymptomsImprovedImmunity) *
471  params.template get<SeverePerInfectedSymptoms<FP>>()[i]) /
472  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyIIi];
473 
474  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsImprovedImmunityConfirmed,
475  InfectionState::InfectedSevereImprovedImmunity>({i})] =
476  reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSymptomsImprovedImmunity *
477  params.template get<SeverePerInfectedSymptoms<FP>>()[i] /
478  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyIICi];
479 
480  flows[this->template get_flat_flow_index<InfectionState::InfectedSymptomsImprovedImmunityConfirmed,
481  InfectionState::SusceptibleImprovedImmunity>({i})] =
482  (1 - (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSymptomsImprovedImmunity) *
483  params.template get<SeverePerInfectedSymptoms<FP>>()[i]) /
484  (params.template get<TimeInfectedSymptoms<FP>>()[i] * reducTimeInfectedMild) * y[ISyIICi];
485 
486  // InfectedSevere
487  flows[this->template get_flat_flow_index<InfectionState::InfectedSevereImprovedImmunity,
488  InfectionState::InfectedCriticalImprovedImmunity>({i})] =
489  reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSevereCriticalDeadImprovedImmunity *
490  criticalPerSevereAdjusted / params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevIIi];
491 
492  flows[this->template get_flat_flow_index<InfectionState::InfectedSevereImprovedImmunity,
493  InfectionState::SusceptibleImprovedImmunity>({i})] =
494  (1 -
495  (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSevereCriticalDeadImprovedImmunity) *
496  (params.template get<CriticalPerSevere<FP>>()[i] +
497  params.template get<DeathsPerSevere<FP>>()[i])) /
498  params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevIIi];
499 
500  flows[this->template get_flat_flow_index<InfectionState::InfectedSevereImprovedImmunity,
501  InfectionState::DeadImprovedImmunity>({i})] =
502  (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSevereCriticalDeadImprovedImmunity) *
503  (params.template get<DeathsPerSevere<FP>>()[i] + deathsPerSevereAdjusted) /
504  params.template get<TimeInfectedSevere<FP>>()[i] * y[ISevIIi];
505 
506  // InfectedCritical
507  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalImprovedImmunity,
508  InfectionState::DeadImprovedImmunity>({i})] =
509  (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSevereCriticalDeadImprovedImmunity) *
510  params.template get<DeathsPerCritical<FP>>()[i] / params.template get<TimeInfectedCritical<FP>>()[i] *
511  y[ICrIIi];
512 
513  flows[this->template get_flat_flow_index<InfectionState::InfectedCriticalImprovedImmunity,
514  InfectionState::SusceptibleImprovedImmunity>({i})] =
515  (1 -
516  (reducInfectedSevereCriticalDeadImprovedImmunity / reducInfectedSevereCriticalDeadImprovedImmunity) *
517  params.template get<DeathsPerCritical<FP>>()[i]) /
518  params.template get<TimeInfectedCritical<FP>>()[i] * y[ICrIIi];
519  }
520  }
521 
526  template <class IOContext>
527  void serialize(IOContext& io) const
528  {
529  auto obj = io.create_object("Model");
530  obj.add_element("Parameters", this->parameters);
531  obj.add_element("Populations", this->populations);
532  }
533 
538  template <class IOContext>
539  static IOResult<Model> deserialize(IOContext& io)
540  {
541  auto obj = io.expect_object("Model");
542  auto par = obj.expect_element("Parameters", Tag<ParameterSet>{});
543  auto pop = obj.expect_element("Populations", Tag<Populations>{});
544  return apply(
545  io,
546  [](auto&& par_, auto&& pop_) {
547  return Model{pop_, par_};
548  },
549  par, pop);
550  }
551 };
552 
553 //forward declaration, see below.
554 template <typename FP, class Base = mio::Simulation<FP, Model<FP>>>
555 class Simulation;
556 
564 template <typename FP, class Base = mio::Simulation<FP, Model<FP>>>
565 FP get_infections_relative(const Simulation<FP, Base>& model, FP t, const Eigen::Ref<const Eigen::VectorX<FP>>& y);
566 
572 template <typename FP, class BaseT>
573 class Simulation : public BaseT
574 {
575 public:
582  Simulation(mio::osecirvvs::Model<FP> const& model, FP t0 = 0., FP dt = 0.1)
583  : BaseT(model, t0, dt)
584  , m_t_last_npi_check(t0)
585  {
586  }
587 
600  void apply_variant(const FP t, const CustomIndexArray<UncertainValue<FP>, AgeGroup> base_infectiousness)
601  {
602  using std::min;
603  using std::pow;
604 
605  auto start_day = this->get_model().parameters.template get<StartDay<FP>>();
606  auto start_day_new_variant = this->get_model().parameters.template get<StartDayNewVariant<FP>>();
607 
608  if (start_day + t >= start_day_new_variant - 1e-10) {
609  const FP days_variant = t - (start_day_new_variant - start_day);
610  const FP share_new_variant = min<FP>(1.0, 0.01 * pow(2, (1. / 7) * days_variant));
611  const auto num_groups = this->get_model().parameters.get_num_groups();
612  for (auto i = AgeGroup(0); i < num_groups; ++i) {
613  FP new_transmission = (1 - share_new_variant) * base_infectiousness[i] +
614  share_new_variant * base_infectiousness[i] *
615  this->get_model().parameters.template get<InfectiousnessNewVariant<FP>>()[i];
616  this->get_model().parameters.template get<TransmissionProbabilityOnContact<FP>>()[i] = new_transmission;
617  }
618  }
619  }
620 
621  void apply_vaccination(FP t)
622  {
623  using std::floor;
624  auto t_idx = SimulationDay(size_t(floor(t)));
625  auto& params = this->get_model().parameters;
626  size_t num_groups = (size_t)params.get_num_groups();
627  auto last_value = this->get_result().get_last_value();
628 
629  auto count = (size_t)InfectionState::Count;
630  auto S = (size_t)InfectionState::SusceptibleNaive;
631  auto SV = (size_t)InfectionState::SusceptiblePartialImmunity;
632  auto R = (size_t)InfectionState::SusceptibleImprovedImmunity;
633 
634  for (size_t i = 0; i < num_groups; ++i) {
635 
636  FP first_vacc;
637  FP full_vacc;
638  if (t_idx == SimulationDay(0)) {
639  first_vacc = params.template get<DailyPartialVaccinations<FP>>()[{(AgeGroup)i, t_idx}];
640  full_vacc = params.template get<DailyFullVaccinations<FP>>()[{(AgeGroup)i, t_idx}];
641  }
642  else {
643  first_vacc =
644  params.template get<DailyPartialVaccinations<FP>>()[{(AgeGroup)i, t_idx}] -
645  params.template get<DailyPartialVaccinations<FP>>()[{(AgeGroup)i, t_idx - SimulationDay(1)}];
646  full_vacc = params.template get<DailyFullVaccinations<FP>>()[{(AgeGroup)i, t_idx}] -
647  params.template get<DailyFullVaccinations<FP>>()[{(AgeGroup)i, t_idx - SimulationDay(1)}];
648  }
649 
650  if (last_value(count * i + S) - first_vacc < 0) {
651  FP corrected = 0.99 * last_value(count * i + S);
652  log_warning("too many first vaccinated at time {}: setting first_vacc from {} to {}", t, first_vacc,
653  corrected);
654  first_vacc = corrected;
655  }
656 
657  last_value(count * i + S) -= first_vacc;
658  last_value(count * i + SV) += first_vacc;
659 
660  if (last_value(count * i + SV) - full_vacc < 0) {
661  FP corrected = 0.99 * last_value(count * i + SV);
662  log_warning("too many fully vaccinated at time {}: setting full_vacc from {} to {}", t, full_vacc,
663  corrected);
664  full_vacc = corrected;
665  }
666 
667  last_value(count * i + SV) -= full_vacc;
668  last_value(count * i + R) += full_vacc;
669  }
670  }
671 
679  Eigen::Ref<Eigen::VectorX<FP>> advance(FP tmax)
680  {
681  using std::floor;
682  using std::min;
683 
684  auto& t_end_dyn_npis = this->get_model().parameters.get_end_dynamic_npis();
685  auto& dyn_npis = this->get_model().parameters.template get<DynamicNPIsInfectedSymptoms<FP>>();
686  auto& contact_patterns = this->get_model().parameters.template get<ContactPatterns<FP>>();
687  // const size_t num_groups = (size_t)this->get_model().parameters.get_num_groups();
688 
689  // in the apply_variant function, we adjust the TransmissionProbabilityOnContact parameter. We need to store
690  // the base value to use it in the apply_variant function and also to reset the parameter after the simulation.
691  auto base_infectiousness = this->get_model().parameters.template get<TransmissionProbabilityOnContact<FP>>();
692 
693  FP delay_npi_implementation;
694  FP t = BaseT::get_result().get_last_time();
695  const FP dt = dyn_npis.get_thresholds().size() > 0 ? dyn_npis.get_interval().get() : tmax;
696  while (t < tmax) {
697 
698  FP dt_eff = min<FP>(dt, tmax - t);
699  dt_eff = min<FP>(dt_eff, m_t_last_npi_check + dt - t);
700 
701  if (dt_eff >= 1.0) {
702  dt_eff = 1.0;
703  }
704 
705  if (t == 0) {
706  //this->apply_vaccination(t); // done in init now?
707  this->apply_variant(t, base_infectiousness);
708  }
709  BaseT::advance(t + dt_eff);
710  if (t + 0.5 + dt_eff - floor(t + 0.5) >= 1) {
711  this->apply_vaccination(t + 0.5 + dt_eff);
712  this->apply_variant(t, base_infectiousness);
713  }
714 
715  if (t > 0) {
716  delay_npi_implementation =
717  this->get_model().parameters.template get<DynamicNPIsImplementationDelay<FP>>();
718  }
719  else { // DynamicNPIs for t=0 are 'misused' to be from-start NPIs. I.e., do not enforce delay.
720  delay_npi_implementation = 0;
721  }
722  t = t + dt_eff;
723 
724  if (dyn_npis.get_thresholds().size() > 0) {
725  if (floating_point_greater_equal<FP>(t, m_t_last_npi_check + dt)) {
726  if (t < t_end_dyn_npis) {
727  auto inf_rel = get_infections_relative<FP>(*this, t, this->get_result().get_last_value()) *
728  dyn_npis.get_base_value();
729  auto exceeded_threshold = dyn_npis.get_max_exceeded_threshold(inf_rel);
730  if (exceeded_threshold != dyn_npis.get_thresholds().end() &&
731  (exceeded_threshold->first > m_dynamic_npi.first ||
732  t > FP(m_dynamic_npi.second))) { //old npi was weaker or is expired
733 
734  auto t_start = SimulationTime<FP>(t + delay_npi_implementation);
735  auto t_end = t_start + SimulationTime<FP>(dyn_npis.get_duration());
736  this->get_model().parameters.get_start_commuter_detection() = t_start.get();
737  this->get_model().parameters.get_end_commuter_detection() = t_end.get();
738  m_dynamic_npi = std::make_pair(exceeded_threshold->first, t_end);
739  implement_dynamic_npis(contact_patterns.get_cont_freq_mat(), exceeded_threshold->second,
740  t_start, t_end, [](auto& g) {
741  return make_contact_damping_matrix(g);
742  });
743  }
744  }
745  m_t_last_npi_check = t;
746  }
747  }
748  else {
749  m_t_last_npi_check = t;
750  }
751  }
752  // reset TransmissionProbabilityOnContact. This is important for the graph simulation where the advance
753  // function is called multiple times for the same model.
754  this->get_model().parameters.template get<TransmissionProbabilityOnContact<FP>>() = base_infectiousness;
755 
756  return this->get_result().get_last_value();
757  }
758 
759 private:
761  std::pair<FP, SimulationTime<FP>> m_dynamic_npi = {-std::numeric_limits<FP>::max(), SimulationTime<FP>(0)};
762 };
763 
776 template <typename FP>
777 inline auto simulate(FP t0, FP tmax, FP dt, const Model<FP>& model,
778  std::unique_ptr<OdeIntegratorCore<FP>>&& integrator_core = nullptr)
779 {
780  return mio::simulate<FP, Model<FP>, Simulation<FP>>(t0, tmax, dt, model, std::move(integrator_core));
781 }
782 
795 template <typename FP>
796 inline auto simulate_flows(FP t0, FP tmax, FP dt, const Model<FP>& model,
797  std::unique_ptr<OdeIntegratorCore<FP>>&& integrator_core = nullptr)
798 {
799  return mio::simulate_flows<FP, Model<FP>, Simulation<FP, mio::FlowSimulation<FP, Model<FP>>>>(
800  t0, tmax, dt, model, std::move(integrator_core));
801 }
802 
803 //see declaration above.
804 template <typename FP, class Base>
805 FP get_infections_relative(const Simulation<FP, Base>& sim, FP /*t*/, const Eigen::Ref<const Eigen::VectorX<FP>>& y)
806 {
807  FP sum_inf = 0;
808  for (auto i = AgeGroup(0); i < sim.get_model().parameters.get_num_groups(); ++i) {
809  sum_inf += sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsNaive});
810  sum_inf += sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsNaiveConfirmed});
811  sum_inf += sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsPartialImmunity});
812  sum_inf += sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsImprovedImmunity});
813  sum_inf +=
814  sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsPartialImmunityConfirmed});
815  sum_inf +=
816  sim.get_model().populations.get_from(y, {i, InfectionState::InfectedSymptomsImprovedImmunityConfirmed});
817  }
818  auto inf_rel = sum_inf / sim.get_model().populations.get_total();
819 
820  return inf_rel;
821 }
822 
833 template <typename FP, class Base = mio::Simulation<FP, Model<FP>>>
834 auto get_mobility_factors(const Simulation<Base>& sim, FP /*t*/, const Eigen::Ref<const Eigen::VectorX<FP>>& y)
835 
836 {
837  auto& params = sim.get_model().parameters;
838  //parameters as arrays
839  auto& p_asymp = params.template get<RecoveredPerInfectedNoSymptoms<FP>>().array().template cast<FP>();
840  auto& p_inf = params.template get<RiskOfInfectionFromSymptomatic<FP>>().array().template cast<FP>();
841  auto& p_inf_max = params.template get<MaxRiskOfInfectionFromSymptomatic<FP>>().array().template cast<FP>();
842  //slice of InfectedNoSymptoms
843  auto y_INS = slice(y, {Eigen::Index(InfectionState::InfectedNoSymptomsNaive),
844  Eigen::Index(size_t(params.get_num_groups())), Eigen::Index(InfectionState::Count)}) +
845  slice(y, {Eigen::Index(InfectionState::InfectedNoSymptomsPartialImmunity),
846  Eigen::Index(size_t(params.get_num_groups())), Eigen::Index(InfectionState::Count)}) +
847  slice(y, {Eigen::Index(InfectionState::InfectedNoSymptomsImprovedImmunity),
848  Eigen::Index(size_t(params.get_num_groups())), Eigen::Index(InfectionState::Count)});
849 
850  //compute isolation, same as infection risk from main model
851  auto test_and_trace_required =
852  ((1 - p_asymp) / params.template get<TimeInfectedNoSymptoms<FP>>().array().template cast<FP>() * y_INS.array())
853  .sum();
854  auto riskFromInfectedSymptomatic =
855  smoother_cosine<FP>(test_and_trace_required, FP(params.template get<TestAndTraceCapacity<FP>>()),
856  params.template get<TestAndTraceCapacity<FP>>() *
857  params.template get<TestAndTraceCapacityMaxRiskSymptoms<FP>>(),
858  p_inf.matrix(), p_inf_max.matrix());
859 
860  //set factor for infected
861  auto factors = Eigen::VectorX<FP>::Ones(y.rows()).eval();
862  slice(factors, {Eigen::Index(InfectionState::InfectedSymptomsNaive), Eigen::Index(size_t(params.get_num_groups())),
863  Eigen::Index(InfectionState::Count)})
864  .array() = riskFromInfectedSymptomatic;
865  slice(factors, {Eigen::Index(InfectionState::InfectedSymptomsPartialImmunity),
866  Eigen::Index(size_t(params.get_num_groups())), Eigen::Index(InfectionState::Count)})
867  .array() = riskFromInfectedSymptomatic;
868  slice(factors, {Eigen::Index(InfectionState::InfectedSymptomsImprovedImmunity),
869  Eigen::Index(size_t(params.get_num_groups())), Eigen::Index(InfectionState::Count)})
870  .array() = riskFromInfectedSymptomatic;
871  return factors;
872 }
873 
874 template <typename FP, class Base = mio::Simulation<FP, Model<FP>>>
875 auto test_commuters(Simulation<FP, Base>& sim, Eigen::Ref<Eigen::VectorX<FP>> mobile_population, FP time)
876 {
877  auto& model = sim.get_model();
878  FP nondetection = 1.0;
879  if (time >= model.parameters.get_start_commuter_detection() &&
880  time < model.parameters.get_end_commuter_detection()) {
881  nondetection = (FP)model.parameters.get_commuter_nondetection();
882  }
883  for (auto i = AgeGroup(0); i < model.parameters.get_num_groups(); ++i) {
884  auto ISyNi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsNaive});
885  auto ISyNCi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsNaiveConfirmed});
886  auto INSNi = model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsNaive});
887  auto INSNCi = model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsNaiveConfirmed});
888 
889  auto ISPIi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsPartialImmunity});
890  auto ISPICi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsPartialImmunityConfirmed});
891  auto INSPIi = model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsPartialImmunity});
892  auto INSPICi =
893  model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsPartialImmunityConfirmed});
894 
895  auto ISyIIi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsImprovedImmunity});
896  auto ISyIICi = model.populations.get_flat_index({i, InfectionState::InfectedSymptomsImprovedImmunityConfirmed});
897  auto INSIIi = model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsImprovedImmunity});
898  auto INSIICi =
899  model.populations.get_flat_index({i, InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed});
900 
901  //put detected commuters in their own compartment so they don't contribute to infections in their home node
902  sim.get_result().get_last_value()[ISyNi] -= mobile_population[ISyNi] * (1 - nondetection);
903  sim.get_result().get_last_value()[ISyNCi] += mobile_population[ISyNi] * (1 - nondetection);
904  sim.get_result().get_last_value()[INSNi] -= mobile_population[INSNi] * (1 - nondetection);
905  sim.get_result().get_last_value()[INSNCi] += mobile_population[INSNi] * (1 - nondetection);
906 
907  sim.get_result().get_last_value()[ISPIi] -= mobile_population[ISPIi] * (1 - nondetection);
908  sim.get_result().get_last_value()[ISPICi] += mobile_population[ISPIi] * (1 - nondetection);
909  sim.get_result().get_last_value()[INSPIi] -= mobile_population[INSPIi] * (1 - nondetection);
910  sim.get_result().get_last_value()[INSPICi] += mobile_population[INSPIi] * (1 - nondetection);
911 
912  sim.get_result().get_last_value()[ISyIIi] -= mobile_population[ISyIIi] * (1 - nondetection);
913  sim.get_result().get_last_value()[ISyIICi] += mobile_population[ISyIIi] * (1 - nondetection);
914  sim.get_result().get_last_value()[INSIIi] -= mobile_population[INSIIi] * (1 - nondetection);
915  sim.get_result().get_last_value()[INSIICi] += mobile_population[INSIIi] * (1 - nondetection);
916 
917  //reduce the number of commuters
918  mobile_population[ISyNi] *= nondetection;
919  mobile_population[INSNi] *= nondetection;
920 
921  mobile_population[ISPIi] *= nondetection;
922  mobile_population[INSPIi] *= nondetection;
923 
924  mobile_population[ISyIIi] *= nondetection;
925  mobile_population[INSIIi] *= nondetection;
926  }
927 }
928 
929 } // namespace osecirvvs
930 } // namespace mio
931 
932 #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
Typesafe wrapper for a floating-point simulation time value (in days).
Definition: damping.h:78
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:527
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:539
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:663
specialization of compartment model simulation for the SECIRVVS model.
Definition: ode_secirvvs/model.h:574
FP m_t_last_npi_check
Definition: ode_secirvvs/model.h:760
void apply_vaccination(FP t)
Definition: ode_secirvvs/model.h:621
Eigen::Ref< Eigen::VectorX< FP > > advance(FP tmax)
advance simulation to tmax.
Definition: ode_secirvvs/model.h:679
Simulation(mio::osecirvvs::Model< FP > const &model, FP t0=0., FP dt=0.1)
construct a simulation.
Definition: ode_secirvvs/model.h:582
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:600
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:834
auto test_commuters(Simulation< FP, Base > &sim, Eigen::Ref< Eigen::VectorX< FP >> mobile_population, FP time)
Definition: ode_secirvvs/model.h:875
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:805
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:777
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:796
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:304
boost::outcome_v2::unchecked< T, IOStatus > IOResult
Value-or-error type for operations that return a value but can fail.
Definition: io.h:353
Typesafe index representing an age group.
Definition: age_group.h:40
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