emod-api 3.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- emod_api/__init__.py +1 -0
- emod_api/campaign.py +170 -0
- emod_api/channelreports/__init__.py +0 -0
- emod_api/channelreports/channels.py +433 -0
- emod_api/channelreports/icj_to_csv.py +65 -0
- emod_api/channelreports/plot_icj_means.py +149 -0
- emod_api/channelreports/plot_prop_report.py +205 -0
- emod_api/channelreports/utils.py +326 -0
- emod_api/config/__init__.py +0 -0
- emod_api/config/default_from_schema.py +16 -0
- emod_api/config/default_from_schema_no_validation.py +177 -0
- emod_api/config/from_overrides.py +135 -0
- emod_api/demographics/__init__.py +0 -0
- emod_api/demographics/age_distribution.py +163 -0
- emod_api/demographics/base_input_file.py +28 -0
- emod_api/demographics/calculators.py +159 -0
- emod_api/demographics/demographic_exceptions.py +54 -0
- emod_api/demographics/demographics.py +249 -0
- emod_api/demographics/demographics_base.py +752 -0
- emod_api/demographics/demographics_overlay.py +41 -0
- emod_api/demographics/fertility_distribution.py +235 -0
- emod_api/demographics/implicit_functions.py +112 -0
- emod_api/demographics/mortality_distribution.py +227 -0
- emod_api/demographics/node.py +456 -0
- emod_api/demographics/overlay_node.py +16 -0
- emod_api/demographics/properties_and_attributes.py +737 -0
- emod_api/demographics/service/__init__.py +0 -0
- emod_api/demographics/service/grid_construction.py +143 -0
- emod_api/demographics/service/service.py +55 -0
- emod_api/demographics/susceptibility_distribution.py +170 -0
- emod_api/demographics/updateable.py +58 -0
- emod_api/legacy/__init__.py +0 -0
- emod_api/legacy/plotAllCharts.py +230 -0
- emod_api/migration/__init__.py +0 -0
- emod_api/migration/__main__.py +22 -0
- emod_api/migration/migration.py +782 -0
- emod_api/multidim_plotter.py +80 -0
- emod_api/schema_to_class.py +440 -0
- emod_api/serialization/__init__.py +0 -0
- emod_api/serialization/census_and_mod_pop.py +48 -0
- emod_api/serialization/dtk_file_support.py +61 -0
- emod_api/serialization/dtk_file_tools.py +1378 -0
- emod_api/serialization/dtk_file_utility.py +141 -0
- emod_api/serialization/serialized_population.py +205 -0
- emod_api/spatialreports/__init__.py +0 -0
- emod_api/spatialreports/__main__.py +67 -0
- emod_api/spatialreports/plot_spat_means.py +99 -0
- emod_api/spatialreports/spatial.py +210 -0
- emod_api/utils/__init__.py +26 -0
- emod_api/utils/distributions/__init__.py +0 -0
- emod_api/utils/distributions/base_distribution.py +38 -0
- emod_api/utils/distributions/bimodal_distribution.py +64 -0
- emod_api/utils/distributions/constant_distribution.py +58 -0
- emod_api/utils/distributions/demographic_distribution_flag.py +16 -0
- emod_api/utils/distributions/distribution_type.py +15 -0
- emod_api/utils/distributions/dual_constant_distribution.py +68 -0
- emod_api/utils/distributions/dual_exponential_distribution.py +75 -0
- emod_api/utils/distributions/exponential_distribution.py +63 -0
- emod_api/utils/distributions/gaussian_distribution.py +69 -0
- emod_api/utils/distributions/log_normal_distribution.py +61 -0
- emod_api/utils/distributions/poisson_distribution.py +59 -0
- emod_api/utils/distributions/uniform_distribution.py +70 -0
- emod_api/utils/distributions/weibull_distribution.py +69 -0
- emod_api/utils/str_enum.py +6 -0
- emod_api/weather/__init__.py +0 -0
- emod_api/weather/weather.py +428 -0
- emod_api-3.0.2.dist-info/METADATA +131 -0
- emod_api-3.0.2.dist-info/RECORD +71 -0
- emod_api-3.0.2.dist-info/WHEEL +5 -0
- emod_api-3.0.2.dist-info/licenses/LICENSE +21 -0
- emod_api-3.0.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from typing import Callable, List, Tuple
|
|
3
|
+
|
|
4
|
+
from emod_api.demographics.age_distribution import AgeDistribution
|
|
5
|
+
from emod_api.demographics.fertility_distribution import FertilityDistribution
|
|
6
|
+
from emod_api.demographics.mortality_distribution import MortalityDistribution
|
|
7
|
+
from emod_api.demographics.susceptibility_distribution import SusceptibilityDistribution
|
|
8
|
+
from emod_api.demographics.updateable import Updateable
|
|
9
|
+
from emod_api.demographics.properties_and_attributes import IndividualAttributes, IndividualProperty, IndividualProperties, NodeAttributes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Node(Updateable):
|
|
13
|
+
# ability to resolve between Nodes
|
|
14
|
+
res_in_degrees = 2.5 / 60
|
|
15
|
+
|
|
16
|
+
def __init__(self,
|
|
17
|
+
lat: float,
|
|
18
|
+
lon: float,
|
|
19
|
+
pop: float,
|
|
20
|
+
name: str = None,
|
|
21
|
+
area: float = None,
|
|
22
|
+
# TODO: consider deprecating 'forced_id' as an argument and renaming it to simply 'id' for clarity and
|
|
23
|
+
# brevity.
|
|
24
|
+
forced_id: int = None,
|
|
25
|
+
individual_attributes: IndividualAttributes = None,
|
|
26
|
+
individual_properties: IndividualProperties = None,
|
|
27
|
+
node_attributes: NodeAttributes = None,
|
|
28
|
+
meta: dict = None):
|
|
29
|
+
"""
|
|
30
|
+
A Node in EMOD is synonymous with a group of people (model agents). A node typically represents a spatial
|
|
31
|
+
geography (for example, a city, province, or country), but does not have to. Arguments to Node construction
|
|
32
|
+
define states of the agents (individual_properties), their initial attributes and distributions
|
|
33
|
+
(initial_attributes), and attributes of the node (group) as a whole (node_attributes).
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
lat (float): Latitude of the node in degrees.
|
|
37
|
+
lon (float): Longitude of the node in degrees.
|
|
38
|
+
pop (int): Initial population of the node.
|
|
39
|
+
name (str): Name of the node.
|
|
40
|
+
area (float): Area of the node. # TODO: units unknown
|
|
41
|
+
forced_id (int): ID of the node
|
|
42
|
+
individual_attributes (IndividualAttributes): Specifies initial distributions of various agent attributes,
|
|
43
|
+
such as age, fertility, and mortality.
|
|
44
|
+
individual_properties (IndividualProperties): Specifies the utilized IndividualProperty objects for the
|
|
45
|
+
node, which define properties of individual model agents.
|
|
46
|
+
node_attributes (NodeAttributes): Specifies node-specific attributes.
|
|
47
|
+
meta (dict): A metadata dictionary for a Node. Entries in here are effectively comments as EMOD
|
|
48
|
+
binaries do not recognize node-level metadata.
|
|
49
|
+
"""
|
|
50
|
+
super().__init__()
|
|
51
|
+
self.forced_id = forced_id
|
|
52
|
+
self.meta = meta if meta else {}
|
|
53
|
+
self.individual_attributes = individual_attributes if individual_attributes else IndividualAttributes()
|
|
54
|
+
self.individual_properties = individual_properties if individual_properties else IndividualProperties()
|
|
55
|
+
|
|
56
|
+
self.node_attributes = NodeAttributes(latitude=lat, longitude=lon, initial_population=pop, area=area)
|
|
57
|
+
if node_attributes is not None:
|
|
58
|
+
self.node_attributes.update(node_attributes)
|
|
59
|
+
|
|
60
|
+
if name is None:
|
|
61
|
+
# if no node name was explicitly provided, we need to figure out how to name the node
|
|
62
|
+
if node_attributes is None or node_attributes.name is None:
|
|
63
|
+
# if no node_attributes object was provided with a name, use a standard default name
|
|
64
|
+
name = f"node{str(self.id)}"
|
|
65
|
+
else:
|
|
66
|
+
# if a name was specified for use via the node_attributes parameter, use it
|
|
67
|
+
name = node_attributes.name
|
|
68
|
+
self.name = name
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def name(self):
|
|
72
|
+
return self.node_attributes.name
|
|
73
|
+
|
|
74
|
+
@name.setter
|
|
75
|
+
def name(self, value):
|
|
76
|
+
self.node_attributes.name = value
|
|
77
|
+
|
|
78
|
+
def __repr__(self):
|
|
79
|
+
return f"{self.node_attributes.name} - ({self.node_attributes.latitude},{self.node_attributes.longitude})"
|
|
80
|
+
|
|
81
|
+
def has_individual_property(self, property_key: str) -> bool:
|
|
82
|
+
return self.individual_properties.has_individual_property(property_key=property_key)
|
|
83
|
+
|
|
84
|
+
def get_individual_property(self, property_key: str) -> IndividualProperty:
|
|
85
|
+
if not self.has_individual_property(property_key=property_key):
|
|
86
|
+
raise Exception(f"No such individual property {property_key} exists in node: {self.id}")
|
|
87
|
+
ip_by_name = {ip.property: ip for ip in self.individual_properties}
|
|
88
|
+
return ip_by_name[property_key]
|
|
89
|
+
|
|
90
|
+
def to_dict(self) -> dict:
|
|
91
|
+
"""
|
|
92
|
+
Translate node structure to a dictionary for EMOD
|
|
93
|
+
"""
|
|
94
|
+
d = {"NodeID": self.id,
|
|
95
|
+
"NodeAttributes": self.node_attributes.to_dict()}
|
|
96
|
+
|
|
97
|
+
if self.individual_attributes:
|
|
98
|
+
d["IndividualAttributes"] = self.individual_attributes.to_dict()
|
|
99
|
+
|
|
100
|
+
if self.individual_properties:
|
|
101
|
+
ip_dict = {"IndividualProperties": []}
|
|
102
|
+
for ip in self.individual_properties:
|
|
103
|
+
ip_dict["IndividualProperties"].append(ip.to_dict())
|
|
104
|
+
d.update(ip_dict)
|
|
105
|
+
|
|
106
|
+
d.update(self.meta)
|
|
107
|
+
return d
|
|
108
|
+
|
|
109
|
+
def to_tuple(self):
|
|
110
|
+
"""
|
|
111
|
+
Returns a tuple of (latitude, longitude, and initial population)
|
|
112
|
+
"""
|
|
113
|
+
return self.node_attributes.latitude, self.node_attributes.longitude, self.node_attributes.initial_population
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def id(self):
|
|
117
|
+
""" Returns the node ID"""
|
|
118
|
+
return (
|
|
119
|
+
self.forced_id
|
|
120
|
+
if self.forced_id is not None
|
|
121
|
+
else nodeid_from_lat_lon(self.node_attributes.latitude, self.node_attributes.longitude, self.res_in_degrees)
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
@classmethod
|
|
125
|
+
def init_resolution_from_file(cls, fn):
|
|
126
|
+
if "30arcsec" in fn:
|
|
127
|
+
cls.res_in_degrees = 30 / 3600.0
|
|
128
|
+
elif "2_5arcmin" in fn:
|
|
129
|
+
cls.res_in_degrees = 2.5 / 30
|
|
130
|
+
else:
|
|
131
|
+
raise Exception("Don't recognize resolution from demographics filename")
|
|
132
|
+
|
|
133
|
+
@classmethod
|
|
134
|
+
def from_data(cls,
|
|
135
|
+
data: dict) -> Tuple["Node", List[Callable]]:
|
|
136
|
+
"""
|
|
137
|
+
Function used to create the node object from data (most likely coming from a demographics file)
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
data (dict): Contains the node definitions
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
A New Node object and a list of known implicit functions needed for config compatibility.
|
|
144
|
+
"""
|
|
145
|
+
implicit_functions = []
|
|
146
|
+
|
|
147
|
+
nodeid = data["NodeID"]
|
|
148
|
+
node_attributes_dict = dict(data.get("NodeAttributes"))
|
|
149
|
+
attributes = data["NodeAttributes"]
|
|
150
|
+
name = attributes.pop("FacilityName", nodeid)
|
|
151
|
+
individual_attributes_dict = data.get("IndividualAttributes")
|
|
152
|
+
individual_properties_dict = data.get("IndividualProperties")
|
|
153
|
+
|
|
154
|
+
individual_properties = IndividualProperties()
|
|
155
|
+
if individual_properties_dict:
|
|
156
|
+
for ip in individual_properties_dict:
|
|
157
|
+
individual_properties.add(IndividualProperty(property=ip["Property"],
|
|
158
|
+
values=ip["Values"],
|
|
159
|
+
transitions=ip["Transitions"],
|
|
160
|
+
initial_distribution=ip["Initial_Distribution"]))
|
|
161
|
+
individual_attributes = None
|
|
162
|
+
if individual_attributes_dict:
|
|
163
|
+
individual_attributes, implicit_functions = IndividualAttributes().from_dict(individual_attributes_dict)
|
|
164
|
+
|
|
165
|
+
node_attributes = None
|
|
166
|
+
if node_attributes_dict:
|
|
167
|
+
node_attributes = NodeAttributes().from_dict(node_attributes_dict)
|
|
168
|
+
|
|
169
|
+
# Create the node and return plus any known necessary implicit functions
|
|
170
|
+
node = cls(node_attributes.latitude, node_attributes.longitude, node_attributes.initial_population,
|
|
171
|
+
name=name, forced_id=nodeid, individual_attributes=individual_attributes,
|
|
172
|
+
individual_properties=individual_properties, node_attributes=node_attributes)
|
|
173
|
+
return node, implicit_functions
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def pop(self):
|
|
177
|
+
""" initial population """
|
|
178
|
+
return self.node_attributes.initial_population
|
|
179
|
+
|
|
180
|
+
@pop.setter
|
|
181
|
+
def pop(self, value):
|
|
182
|
+
self.node_attributes.initial_population = value
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def lon(self):
|
|
186
|
+
""" longitude """
|
|
187
|
+
return self.node_attributes.longitude
|
|
188
|
+
|
|
189
|
+
@lon.setter
|
|
190
|
+
def lon(self, value):
|
|
191
|
+
self.node_attributes.longitude = value
|
|
192
|
+
|
|
193
|
+
@property
|
|
194
|
+
def lat(self):
|
|
195
|
+
""" latitude """
|
|
196
|
+
return self.node_attributes.latitude
|
|
197
|
+
|
|
198
|
+
@lat.setter
|
|
199
|
+
def lat(self, value):
|
|
200
|
+
self.node_attributes.latitude = value
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def birth_rate(self):
|
|
204
|
+
""" birth rate in births per person per day"""
|
|
205
|
+
return self.node_attributes.birth_rate
|
|
206
|
+
|
|
207
|
+
@birth_rate.setter
|
|
208
|
+
def birth_rate(self, value):
|
|
209
|
+
self.node_attributes.birth_rate = value
|
|
210
|
+
|
|
211
|
+
def _set_individual_attributes(self, ind_attribute: IndividualAttributes):
|
|
212
|
+
self.individual_attributes = ind_attribute
|
|
213
|
+
|
|
214
|
+
def _set_individual_properties(self, ind_properties: IndividualProperties):
|
|
215
|
+
self.individual_properties = ind_properties
|
|
216
|
+
|
|
217
|
+
def _add_individual_property(self, ind_property: IndividualProperty):
|
|
218
|
+
self.individual_properties.add(ind_property)
|
|
219
|
+
|
|
220
|
+
def _set_node_attributes(self, node_attributes: NodeAttributes):
|
|
221
|
+
self.node_attributes = node_attributes
|
|
222
|
+
|
|
223
|
+
#
|
|
224
|
+
# Any of the following _set_*() functions that appear to be missing are not valid (e.g. prevalence complex dist)
|
|
225
|
+
#
|
|
226
|
+
|
|
227
|
+
def _set_age_complex_distribution(self, distribution: AgeDistribution):
|
|
228
|
+
"""
|
|
229
|
+
Properly sets a complex age distribution and unsets a simple one for consistency (just in case one was set).
|
|
230
|
+
For details on complex distributions, see:
|
|
231
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#complex-distributions
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
distribution: The complex age distribution to set
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
Nothing
|
|
238
|
+
"""
|
|
239
|
+
self.individual_attributes.age_distribution_flag = None
|
|
240
|
+
self.individual_attributes.age_distribution1 = None
|
|
241
|
+
self.individual_attributes.age_distribution2 = None
|
|
242
|
+
self.individual_attributes.age_distribution = distribution
|
|
243
|
+
|
|
244
|
+
def _set_age_simple_distribution(self, flag: int, value1: float, value2: float):
|
|
245
|
+
"""
|
|
246
|
+
Properly sets a simple age distribution and unsets a complex one for consistency (just in case one was set).
|
|
247
|
+
For details on the simple distribution flag and value meanings, see:
|
|
248
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#simple-distributions
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
flag: simple distribution flag determines the type of simple distribution to use
|
|
252
|
+
value1: simple distribution type-dependent parameter number 1
|
|
253
|
+
value2: simple distribution type-dependent parameter number 2
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
Nothing
|
|
257
|
+
"""
|
|
258
|
+
self.individual_attributes.age_distribution_flag = flag
|
|
259
|
+
self.individual_attributes.age_distribution1 = value1
|
|
260
|
+
self.individual_attributes.age_distribution2 = value2
|
|
261
|
+
self.individual_attributes.age_distribution = None
|
|
262
|
+
|
|
263
|
+
def _set_susceptibility_complex_distribution(self, distribution: SusceptibilityDistribution):
|
|
264
|
+
"""
|
|
265
|
+
Properly sets a complex susceptibility distribution and unsets a simple one for consistency (just in case one
|
|
266
|
+
was set). For details on complex distributions, see:
|
|
267
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#complex-distributions
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
distribution: The complex susceptibility distribution to set
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
Nothing
|
|
274
|
+
"""
|
|
275
|
+
self.individual_attributes.susceptibility_distribution_flag = None
|
|
276
|
+
self.individual_attributes.susceptibility_distribution1 = None
|
|
277
|
+
self.individual_attributes.susceptibility_distribution2 = None
|
|
278
|
+
self.individual_attributes.susceptibility_distribution = distribution
|
|
279
|
+
|
|
280
|
+
def _set_susceptibility_simple_distribution(self, flag: int, value1: float, value2: float):
|
|
281
|
+
"""
|
|
282
|
+
Properly sets a simple susceptibility distribution and unsets a complex one for consistency (just in case one
|
|
283
|
+
was set). For details on the simple distribution flag and value meanings, see:
|
|
284
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#simple-distributions
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
flag: simple distribution flag determines the type of simple distribution to use
|
|
288
|
+
value1: simple distribution type-dependent parameter number 1
|
|
289
|
+
value2: simple distribution type-dependent parameter number 2
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
Nothing
|
|
293
|
+
"""
|
|
294
|
+
self.individual_attributes.susceptibility_distribution_flag = flag
|
|
295
|
+
self.individual_attributes.susceptibility_distribution1 = value1
|
|
296
|
+
self.individual_attributes.susceptibility_distribution2 = value2
|
|
297
|
+
self.individual_attributes.susceptibility_distribution = None
|
|
298
|
+
|
|
299
|
+
def _set_prevalence_simple_distribution(self, flag: int, value1: float, value2: float):
|
|
300
|
+
"""
|
|
301
|
+
Properly sets a simple prevalence distribution. For details on the simple distribution flag and value meanings,
|
|
302
|
+
see:
|
|
303
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#simple-distributions
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
flag: simple distribution flag determines the type of simple distribution to use
|
|
307
|
+
value1: simple distribution type-dependent parameter number 1
|
|
308
|
+
value2: simple distribution type-dependent parameter number 2
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
Nothing
|
|
312
|
+
"""
|
|
313
|
+
self.individual_attributes.prevalence_distribution_flag = flag
|
|
314
|
+
self.individual_attributes.prevalence_distribution1 = value1
|
|
315
|
+
self.individual_attributes.prevalence_distribution2 = value2
|
|
316
|
+
|
|
317
|
+
def _set_migration_heterogeneity_simple_distribution(self, flag: int, value1: float, value2: float):
|
|
318
|
+
"""
|
|
319
|
+
Properly sets a simple migration heterogeneity distribution. For details on the simple distribution flag and
|
|
320
|
+
value meanings, see:
|
|
321
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#simple-distributions
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
flag: simple distribution flag determines the type of simple distribution to use
|
|
325
|
+
value1: simple distribution type-dependent parameter number 1
|
|
326
|
+
value2: simple distribution type-dependent parameter number 2
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
Nothing
|
|
330
|
+
"""
|
|
331
|
+
self.individual_attributes.migration_heterogeneity_distribution_flag = flag
|
|
332
|
+
self.individual_attributes.migration_heterogeneity_distribution1 = value1
|
|
333
|
+
self.individual_attributes.migration_heterogeneity_distribution2 = value2
|
|
334
|
+
|
|
335
|
+
def _set_mortality_complex_distribution(self, distribution: MortalityDistribution):
|
|
336
|
+
"""
|
|
337
|
+
Properly sets a complex mortality distribution. For details on complex distributions, see:
|
|
338
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#complex-distributions
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
distribution: The complex mortality distribution to set
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
Nothing
|
|
345
|
+
"""
|
|
346
|
+
self.individual_attributes.mortality_distribution = distribution
|
|
347
|
+
|
|
348
|
+
def _set_mortality_female_complex_distribution(self, distribution: MortalityDistribution):
|
|
349
|
+
"""
|
|
350
|
+
Properly sets a complex female mortality distribution. For details on complex distributions, see:
|
|
351
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#complex-distributions
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
distribution: The complex female mortality distribution to set
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
Nothing
|
|
358
|
+
"""
|
|
359
|
+
self.individual_attributes.mortality_distribution_female = distribution
|
|
360
|
+
|
|
361
|
+
def _set_mortality_male_complex_distribution(self, distribution: MortalityDistribution):
|
|
362
|
+
"""
|
|
363
|
+
Properly sets a complex male mortality distribution. For details on complex distributions, see:
|
|
364
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#complex-distributions
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
distribution: The complex male mortality distribution to set
|
|
368
|
+
|
|
369
|
+
Returns:
|
|
370
|
+
Nothing
|
|
371
|
+
"""
|
|
372
|
+
self.individual_attributes.mortality_distribution_male = distribution
|
|
373
|
+
|
|
374
|
+
# malaria only
|
|
375
|
+
# TODO: Move to emodpy-malaria?
|
|
376
|
+
# https://github.com/InstituteforDiseaseModeling/emodpy-malaria-old/issues/707
|
|
377
|
+
def _set_innate_immune_simple_distribution(self, flag: int, value1: float, value2: float):
|
|
378
|
+
"""
|
|
379
|
+
Properly sets a simple innate immune distribution. For details on the simple distribution flag and value
|
|
380
|
+
meanings, see:
|
|
381
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#simple-distributions
|
|
382
|
+
|
|
383
|
+
Args:
|
|
384
|
+
flag: simple distribution flag determines the type of simple distribution to use
|
|
385
|
+
value1: simple distribution type-dependent parameter number 1
|
|
386
|
+
value2: simple distribution type-dependent parameter number 2
|
|
387
|
+
|
|
388
|
+
Returns:
|
|
389
|
+
Nothing
|
|
390
|
+
"""
|
|
391
|
+
self.individual_attributes.innate_immune_distribution_flag = flag
|
|
392
|
+
self.individual_attributes.innate_immune_distribution1 = value1
|
|
393
|
+
self.individual_attributes.innate_immune_distribution2 = value2
|
|
394
|
+
|
|
395
|
+
# malaria only
|
|
396
|
+
# TODO: Move to emodpy-malaria?
|
|
397
|
+
# https://github.com/InstituteforDiseaseModeling/emodpy-malaria-old/issues/707
|
|
398
|
+
def _set_risk_simple_distribution(self, flag: int, value1: float, value2: float):
|
|
399
|
+
"""
|
|
400
|
+
Properly sets a simple risk distribution. For details on the simple distribution flag and value meanings, see:
|
|
401
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#simple-distributions
|
|
402
|
+
|
|
403
|
+
Args:
|
|
404
|
+
flag: simple distribution flag determines the type of simple distribution to use
|
|
405
|
+
value1: simple distribution type-dependent parameter number 1
|
|
406
|
+
value2: simple distribution type-dependent parameter number 2
|
|
407
|
+
|
|
408
|
+
Returns:
|
|
409
|
+
Nothing
|
|
410
|
+
"""
|
|
411
|
+
self.individual_attributes.risk_distribution_flag = flag
|
|
412
|
+
self.individual_attributes.risk_distribution1 = value1
|
|
413
|
+
self.individual_attributes.risk_distribution2 = value2
|
|
414
|
+
|
|
415
|
+
# HIV only
|
|
416
|
+
def _set_fertility_complex_distribution(self, distribution: FertilityDistribution):
|
|
417
|
+
"""
|
|
418
|
+
Properly sets a complex fertility distribution. For details on complex distributions, see:
|
|
419
|
+
https://docs.idmod.org/projects/emod-generic/en/latest/parameter-demographics.html#complex-distributions
|
|
420
|
+
|
|
421
|
+
Args:
|
|
422
|
+
distribution: The complex fertility distribution to set
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
Nothing
|
|
426
|
+
"""
|
|
427
|
+
self.individual_attributes.fertility_distribution = distribution
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def get_xpix_ypix(nodeid):
|
|
431
|
+
""" Get pixel position from nodid. Inverse of :py:func:`nodeid_from_lat_lon` """
|
|
432
|
+
ypix = (nodeid - 1) & 2 ** 16 - 1
|
|
433
|
+
xpix = (nodeid - 1) >> 16 # shift bits to the right
|
|
434
|
+
return (xpix, ypix)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def lat_lon_from_nodeid(nodeid, res_in_deg=Node.res_in_degrees):
|
|
438
|
+
""" Inverse of :py:func:`nodeid_from_lat_lon` """
|
|
439
|
+
xpix, ypix = get_xpix_ypix(nodeid)
|
|
440
|
+
lat = (0.5 + ypix) * res_in_deg - 90.0
|
|
441
|
+
lon = (0.5 + xpix) * res_in_deg - 180.0
|
|
442
|
+
return (lat, lon)
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def xpix_ypix_from_lat_lon(lat, lon, res_in_deg=Node.res_in_degrees):
|
|
446
|
+
""" Pixel position (origin is -90°N and -180°E). No modular arithmentic is done."""
|
|
447
|
+
xpix = int(math.floor((lon + 180.0) / res_in_deg))
|
|
448
|
+
ypix = int(math.floor((lat + 90.0) / res_in_deg))
|
|
449
|
+
return xpix, ypix
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def nodeid_from_lat_lon(lat, lon, res_in_deg=Node.res_in_degrees):
|
|
453
|
+
""" Generate unique identifier from lat, lon. Inverse of :py:func:`lat_lon_from_nodeid` """
|
|
454
|
+
xpix, ypix = xpix_ypix_from_lat_lon(lat, lon, res_in_deg)
|
|
455
|
+
nodeid = (xpix << 16) + ypix + 1
|
|
456
|
+
return nodeid
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from emod_api.demographics.node import Node
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class OverlayNode(Node):
|
|
5
|
+
"""
|
|
6
|
+
Node that only requires an ID. Use to overlay a Node.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
def __init__(self,
|
|
10
|
+
node_id: int,
|
|
11
|
+
latitude: float = None,
|
|
12
|
+
longitude: float = None,
|
|
13
|
+
initial_population: int = None,
|
|
14
|
+
**kwargs
|
|
15
|
+
):
|
|
16
|
+
super().__init__(lat=latitude, lon=longitude, pop=initial_population, forced_id=node_id, **kwargs)
|