-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSimulation.py
158 lines (113 loc) · 4.94 KB
/
Simulation.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# package imports
# external libraries which need to be installed separately
import numpy as np
# internal python libraries
from pprint import pformat
from InfectionChain import InfectionChain
"""
This is the heart of the whole application. This is where the simulation happens.
"""
class Simulation:
"""
Contact per person will be calculated depending of the extended circle of friends.
Args:
_config: includes all the configurations of the simulation.
"""
def __init__(self, _config: {str: str}):
self._config = _config
# we document our virus chain
self._infection_history = []
# we document the infection counts
self._viruses = []
# we assume that a person meets every friend two times per year
# a person meets another person after 'contact_per_person'-days
self.contact_per_person = 1.75 * round(365 / (2 * self._config['extended_circle_of_friends']))
# representation of simulation will be printed in the terminal so it looks pretty sick
print(self)
"""
String representation of the object.
If we override the __repr__-method, we can decide what will be printed.
Returns:
str. the configuration
"""
def __repr__(self) -> str:
return '\nConfiguration of the simulation:\n' + pformat(vars(self), indent=2, width=1) + '\n'
"""
Simulates every day until the time is over.
Every day needs to be simulated seperately for every infection chain. So we iterate over every day and every
chain and let a day pass with virus.day_ends(). When we create a new infection chain, we put that one into our
numpy array which is used like a database. At the end we return the infection history and all viruses as numpy
arrays which can then be further processed.
Returns:
np.ndarray: infection history.
np.ndarray: all virus chains.
"""
def simulate(self) -> (np.ndarray, np.ndarray):
# we add the time of the duration of the infection so we let the virus die at the rest of the time
for day in range(0, int(self._config['simulation_duration'])):
# initiate virus
if day % self.contact_per_person == 0:
if day == 0:
self._viruses.append(
InfectionChain(int(day // self.contact_per_person), self._config,
int(self._config['infection_count_start'])))
else:
self._viruses.append(
InfectionChain(int(day // self.contact_per_person), self._config,
self._viruses[-1].infection_count))
for idx, virus in enumerate(self._viruses):
virus.day_ends()
self._infection_history.append(self.get_total_active_infections_count())
return self.spread_infection_history(), np.array(self._viruses)
"""
Indicates how many people are infected in total.
Returns:
int. amount infections in total.
"""
def get_total_active_infections_count(self) -> int:
return sum([virus.infection_count for virus in self._viruses if virus.lifetime > 0])
"""
Indicates how many people are infected right now.
Returns:
int. amount active infections.
"""
def get_total_infections_count(self) -> int:
return sum([virus.infection_count for virus in self._viruses])
"""
Indicates the the incidence-value depending on population and active infections.
Returns:
np.ndarray. incidence values
"""
def get_incidence_values(self) -> np.ndarray:
return np.array([(virus.infection_count * 100000) / self._config['population'] for virus in self._viruses])
"""
Indicates how many people have passed away through the virus.
Returns:
int. mortality.
"""
def get_mortality(self) -> int:
return int(sum([virus.infection_count for virus in self._viruses]) * self._config['death_rate'])
"""
Indicates the 7-day incidence-value.
Returns:
int. incidence value.
"""
def get_seven_day_incidence(self) -> int:
return (self._viruses[-1].infection_count * 100000) / self._config['population']
"""
Indicates the amount of infections in the last seven days.
Returns:
int. amount of total infections.
"""
def get_seven_days_total_infections_count(self) -> int:
return self._viruses[-1].infection_count
"""
Distributes the infection numbers realistically over the days so as not to show a linear development.
Returns:
np.ndarray. distribution.
"""
def spread_infection_history(self) -> np.ndarray:
spread = np.zeros(len(self._infection_history) * 7)
for i, infection_count in enumerate(self._infection_history):
spread[i * 7:(i + 1) * 7] = infection_count / 7
return spread