flood-adapt 0.3.8__py3-none-any.whl → 0.3.10__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.
- flood_adapt/__init__.py +26 -22
- flood_adapt/adapter/__init__.py +9 -9
- flood_adapt/adapter/fiat_adapter.py +1541 -1536
- flood_adapt/adapter/interface/hazard_adapter.py +70 -70
- flood_adapt/adapter/interface/impact_adapter.py +36 -36
- flood_adapt/adapter/interface/model_adapter.py +89 -89
- flood_adapt/adapter/interface/offshore.py +19 -19
- flood_adapt/adapter/sfincs_adapter.py +1848 -1846
- flood_adapt/adapter/sfincs_offshore.py +193 -193
- flood_adapt/config/config.py +248 -290
- flood_adapt/config/fiat.py +219 -219
- flood_adapt/config/gui.py +331 -331
- flood_adapt/config/sfincs.py +481 -336
- flood_adapt/config/site.py +129 -129
- flood_adapt/database_builder/database_builder.py +2210 -2210
- flood_adapt/database_builder/templates/default_units/imperial.toml +9 -9
- flood_adapt/database_builder/templates/default_units/metric.toml +9 -9
- flood_adapt/database_builder/templates/green_infra_table/green_infra_lookup_table.csv +10 -10
- flood_adapt/database_builder/templates/infographics/OSM/config_charts.toml +90 -90
- flood_adapt/database_builder/templates/infographics/OSM/config_people.toml +57 -57
- flood_adapt/database_builder/templates/infographics/OSM/config_risk_charts.toml +121 -121
- flood_adapt/database_builder/templates/infographics/OSM/config_roads.toml +65 -65
- flood_adapt/database_builder/templates/infographics/OSM/styles.css +45 -45
- flood_adapt/database_builder/templates/infographics/US_NSI/config_charts.toml +126 -126
- flood_adapt/database_builder/templates/infographics/US_NSI/config_people.toml +60 -60
- flood_adapt/database_builder/templates/infographics/US_NSI/config_risk_charts.toml +121 -121
- flood_adapt/database_builder/templates/infographics/US_NSI/config_roads.toml +65 -65
- flood_adapt/database_builder/templates/infographics/US_NSI/styles.css +45 -45
- flood_adapt/database_builder/templates/infometrics/OSM/metrics_additional_risk_configs.toml +4 -4
- flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config.toml +143 -143
- flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config_risk.toml +153 -153
- flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config.toml +127 -127
- flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config_risk.toml +57 -57
- flood_adapt/database_builder/templates/infometrics/US_NSI/metrics_additional_risk_configs.toml +4 -4
- flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config.toml +191 -191
- flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config_risk.toml +153 -153
- flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config.toml +178 -178
- flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config_risk.toml +57 -57
- flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config.toml +9 -9
- flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config_risk.toml +65 -65
- flood_adapt/database_builder/templates/output_layers/bin_colors.toml +5 -5
- flood_adapt/database_builder.py +16 -16
- flood_adapt/dbs_classes/__init__.py +21 -21
- flood_adapt/dbs_classes/database.py +495 -688
- flood_adapt/dbs_classes/dbs_benefit.py +77 -76
- flood_adapt/dbs_classes/dbs_event.py +61 -59
- flood_adapt/dbs_classes/dbs_measure.py +112 -111
- flood_adapt/dbs_classes/dbs_projection.py +34 -34
- flood_adapt/dbs_classes/dbs_scenario.py +137 -137
- flood_adapt/dbs_classes/dbs_static.py +274 -273
- flood_adapt/dbs_classes/dbs_strategy.py +130 -129
- flood_adapt/dbs_classes/dbs_template.py +279 -278
- flood_adapt/dbs_classes/interface/database.py +107 -139
- flood_adapt/dbs_classes/interface/element.py +121 -121
- flood_adapt/dbs_classes/interface/static.py +47 -47
- flood_adapt/flood_adapt.py +1207 -1178
- flood_adapt/misc/database_user.py +16 -16
- flood_adapt/misc/exceptions.py +22 -0
- flood_adapt/misc/log.py +183 -183
- flood_adapt/misc/path_builder.py +54 -54
- flood_adapt/misc/utils.py +185 -185
- flood_adapt/objects/__init__.py +82 -82
- flood_adapt/objects/benefits/benefits.py +61 -61
- flood_adapt/objects/events/event_factory.py +135 -135
- flood_adapt/objects/events/event_set.py +88 -84
- flood_adapt/objects/events/events.py +234 -234
- flood_adapt/objects/events/historical.py +58 -58
- flood_adapt/objects/events/hurricane.py +68 -67
- flood_adapt/objects/events/synthetic.py +46 -50
- flood_adapt/objects/forcing/__init__.py +92 -92
- flood_adapt/objects/forcing/csv.py +68 -68
- flood_adapt/objects/forcing/discharge.py +66 -66
- flood_adapt/objects/forcing/forcing.py +150 -150
- flood_adapt/objects/forcing/forcing_factory.py +182 -182
- flood_adapt/objects/forcing/meteo_handler.py +93 -93
- flood_adapt/objects/forcing/netcdf.py +40 -40
- flood_adapt/objects/forcing/plotting.py +453 -429
- flood_adapt/objects/forcing/rainfall.py +98 -98
- flood_adapt/objects/forcing/tide_gauge.py +191 -191
- flood_adapt/objects/forcing/time_frame.py +90 -90
- flood_adapt/objects/forcing/timeseries.py +564 -564
- flood_adapt/objects/forcing/unit_system.py +580 -580
- flood_adapt/objects/forcing/waterlevels.py +108 -108
- flood_adapt/objects/forcing/wind.py +124 -124
- flood_adapt/objects/measures/measure_factory.py +92 -92
- flood_adapt/objects/measures/measures.py +529 -529
- flood_adapt/objects/object_model.py +74 -68
- flood_adapt/objects/projections/projections.py +103 -89
- flood_adapt/objects/scenarios/scenarios.py +22 -22
- flood_adapt/objects/strategies/strategies.py +89 -89
- flood_adapt/workflows/benefit_runner.py +579 -544
- flood_adapt/workflows/floodmap.py +85 -85
- flood_adapt/workflows/impacts_integrator.py +85 -82
- flood_adapt/workflows/scenario_runner.py +70 -70
- {flood_adapt-0.3.8.dist-info → flood_adapt-0.3.10.dist-info}/LICENSE +674 -674
- {flood_adapt-0.3.8.dist-info → flood_adapt-0.3.10.dist-info}/METADATA +866 -860
- flood_adapt-0.3.10.dist-info/RECORD +140 -0
- flood_adapt-0.3.8.dist-info/RECORD +0 -139
- {flood_adapt-0.3.8.dist-info → flood_adapt-0.3.10.dist-info}/WHEEL +0 -0
- {flood_adapt-0.3.8.dist-info → flood_adapt-0.3.10.dist-info}/top_level.txt +0 -0
|
@@ -1,529 +1,529 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from enum import Enum
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import Any, Optional
|
|
5
|
-
|
|
6
|
-
import geopandas as gpd
|
|
7
|
-
import pyproj
|
|
8
|
-
from pydantic import Field, field_validator, model_validator
|
|
9
|
-
|
|
10
|
-
from flood_adapt.config.site import Site
|
|
11
|
-
from flood_adapt.misc.utils import resolve_filepath, save_file_to_database
|
|
12
|
-
from flood_adapt.objects.forcing import unit_system as us
|
|
13
|
-
from flood_adapt.objects.object_model import Object
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class MeasureCategory(str, Enum):
|
|
17
|
-
"""Class describing the accepted input for the variable 'type' in Measure."""
|
|
18
|
-
|
|
19
|
-
impact = "impact"
|
|
20
|
-
hazard = "hazard"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class MeasureType(str, Enum):
|
|
24
|
-
"""Class describing the accepted input for the variable 'type' in Measure.
|
|
25
|
-
|
|
26
|
-
Each type of measure is associated with a category (hazard or impact) and can be used to determine the type of measure.
|
|
27
|
-
|
|
28
|
-
Attributes
|
|
29
|
-
----------
|
|
30
|
-
floodwall : A floodwall measure.
|
|
31
|
-
thin_dam : A thin dam measure.
|
|
32
|
-
levee : A levee measure.
|
|
33
|
-
pump : A pump measure.
|
|
34
|
-
culvert : A culvert measure.
|
|
35
|
-
water_square : A water square measure.
|
|
36
|
-
greening : A greening measure.
|
|
37
|
-
total_storage : A total storage measure.
|
|
38
|
-
elevate_properties : An elevate properties measure.
|
|
39
|
-
buyout_properties : A buyout properties measure.
|
|
40
|
-
floodproof_properties : A floodproof properties measure.
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
# Hazard measures
|
|
44
|
-
floodwall = "floodwall"
|
|
45
|
-
thin_dam = "thin_dam" # For now, same functionality as floodwall TODO: Add thin dam functionality
|
|
46
|
-
levee = "levee" # For now, same functionality as floodwall TODO: Add levee functionality
|
|
47
|
-
pump = "pump"
|
|
48
|
-
culvert = (
|
|
49
|
-
"culvert" # For now, same functionality as pump TODO: Add culvert functionality
|
|
50
|
-
)
|
|
51
|
-
water_square = "water_square"
|
|
52
|
-
greening = "greening"
|
|
53
|
-
total_storage = "total_storage"
|
|
54
|
-
|
|
55
|
-
# Impact measures
|
|
56
|
-
elevate_properties = "elevate_properties"
|
|
57
|
-
buyout_properties = "buyout_properties"
|
|
58
|
-
floodproof_properties = "floodproof_properties"
|
|
59
|
-
|
|
60
|
-
@classmethod
|
|
61
|
-
def is_hazard(cls, measure_type: str) -> bool:
|
|
62
|
-
return measure_type in [
|
|
63
|
-
cls.floodwall,
|
|
64
|
-
cls.thin_dam,
|
|
65
|
-
cls.levee,
|
|
66
|
-
cls.pump,
|
|
67
|
-
cls.culvert,
|
|
68
|
-
cls.water_square,
|
|
69
|
-
cls.greening,
|
|
70
|
-
cls.total_storage,
|
|
71
|
-
]
|
|
72
|
-
|
|
73
|
-
@classmethod
|
|
74
|
-
def is_impact(cls, measure_type: str) -> bool:
|
|
75
|
-
return measure_type in [
|
|
76
|
-
cls.elevate_properties,
|
|
77
|
-
cls.buyout_properties,
|
|
78
|
-
cls.floodproof_properties,
|
|
79
|
-
]
|
|
80
|
-
|
|
81
|
-
@classmethod
|
|
82
|
-
def get_measure_category(cls, measure_type: str) -> MeasureCategory:
|
|
83
|
-
if cls.is_hazard(measure_type):
|
|
84
|
-
return MeasureCategory.hazard
|
|
85
|
-
elif cls.is_impact(measure_type):
|
|
86
|
-
return MeasureCategory.impact
|
|
87
|
-
else:
|
|
88
|
-
raise ValueError(f"Invalid measure type: {measure_type}")
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
class SelectionType(str, Enum):
|
|
92
|
-
"""Class describing the accepted input for the variable 'selection_type' in Measures.
|
|
93
|
-
|
|
94
|
-
It is used to determine where to apply the measure to a model.
|
|
95
|
-
|
|
96
|
-
Attributes
|
|
97
|
-
----------
|
|
98
|
-
aggregation_area : Use aggregation area as geometry for the measure.
|
|
99
|
-
polygon : Use polygon as geometry for the measure.
|
|
100
|
-
polyline : Use polyline as geometry for the measure.
|
|
101
|
-
all : Apply the measure to all geometries in the database.
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
aggregation_area = "aggregation_area"
|
|
105
|
-
polygon = "polygon"
|
|
106
|
-
polyline = "polyline"
|
|
107
|
-
all = "all"
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
class Measure(Object):
|
|
111
|
-
"""The expected variables and data types of attributes common to all measures.
|
|
112
|
-
|
|
113
|
-
A measure is a collection of attributes that can be applied to a model.
|
|
114
|
-
|
|
115
|
-
Attributes
|
|
116
|
-
----------
|
|
117
|
-
name: str
|
|
118
|
-
Name of the measure.
|
|
119
|
-
description: str
|
|
120
|
-
Description of the measure.
|
|
121
|
-
type: MeasureType
|
|
122
|
-
Type of measure. Should be one of the MeasureType enum values.
|
|
123
|
-
"""
|
|
124
|
-
|
|
125
|
-
type: MeasureType
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
class HazardMeasure(Measure):
|
|
129
|
-
"""The expected variables and data types of attributes common to all hazard measures.
|
|
130
|
-
|
|
131
|
-
Attributes
|
|
132
|
-
----------
|
|
133
|
-
name: str
|
|
134
|
-
Name of the measure.
|
|
135
|
-
description: str
|
|
136
|
-
Description of the measure.
|
|
137
|
-
type: MeasureType
|
|
138
|
-
Type of measure. Should be one of the MeasureType enum values and is_hazard.
|
|
139
|
-
selection_type: SelectionType
|
|
140
|
-
Type of selection. Should be one of the SelectionType enum values.
|
|
141
|
-
polygon_file: str, Optional, default = None
|
|
142
|
-
Path to a polygon file, either absolute or relative to the measure path in the database.
|
|
143
|
-
|
|
144
|
-
"""
|
|
145
|
-
|
|
146
|
-
selection_type: SelectionType
|
|
147
|
-
polygon_file: Optional[str] = Field(
|
|
148
|
-
default=None,
|
|
149
|
-
min_length=1,
|
|
150
|
-
description="Path to a polygon file, either absolute or relative to the measure path.",
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
@field_validator("type")
|
|
154
|
-
def validate_type(cls, value):
|
|
155
|
-
if not MeasureType.is_hazard(value):
|
|
156
|
-
raise ValueError(f"Invalid hazard type: {value}")
|
|
157
|
-
return value
|
|
158
|
-
|
|
159
|
-
@model_validator(mode="after")
|
|
160
|
-
def validate_selection_type(self) -> "HazardMeasure":
|
|
161
|
-
if (
|
|
162
|
-
self.selection_type
|
|
163
|
-
not in [SelectionType.aggregation_area, SelectionType.all]
|
|
164
|
-
and self.polygon_file is None
|
|
165
|
-
):
|
|
166
|
-
raise ValueError(
|
|
167
|
-
"If `selection_type` is not 'aggregation_area' or 'all', then `polygon_file` needs to be set."
|
|
168
|
-
)
|
|
169
|
-
return self
|
|
170
|
-
|
|
171
|
-
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
172
|
-
if self.polygon_file:
|
|
173
|
-
Path(output_dir).mkdir(parents=True, exist_ok=True)
|
|
174
|
-
src_path = resolve_filepath("measures", self.name, self.polygon_file)
|
|
175
|
-
path = save_file_to_database(src_path, Path(output_dir))
|
|
176
|
-
# Update the shapefile path in the object so it is saved in the toml file as well
|
|
177
|
-
self.polygon_file = path.name
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
class ImpactMeasure(Measure):
|
|
181
|
-
"""The expected variables and data types of attributes common to all impact measures.
|
|
182
|
-
|
|
183
|
-
Attributes
|
|
184
|
-
----------
|
|
185
|
-
name: str
|
|
186
|
-
Name of the measure.
|
|
187
|
-
description: str
|
|
188
|
-
Description of the measure.
|
|
189
|
-
type: MeasureType
|
|
190
|
-
Type of measure. Should be one of the MeasureType enum values and is_hazard.
|
|
191
|
-
selection_type: SelectionType
|
|
192
|
-
Type of selection. Should be one of the SelectionType enum values.
|
|
193
|
-
polygon_file: str, Optional, default = None
|
|
194
|
-
Path to a polygon file, either absolute or relative to the measure path in the database.
|
|
195
|
-
property_type: str
|
|
196
|
-
Type of property. Should be one of the PropertyType enum values.
|
|
197
|
-
aggregation_area_type: str, Optional, default = None
|
|
198
|
-
Type of aggregation area. Should be one of the SelectionType enum values.
|
|
199
|
-
aggregation_area_name: str, Optional, default = None
|
|
200
|
-
Name of the aggregation area.
|
|
201
|
-
"""
|
|
202
|
-
|
|
203
|
-
type: MeasureType
|
|
204
|
-
selection_type: SelectionType
|
|
205
|
-
aggregation_area_type: Optional[str] = None
|
|
206
|
-
aggregation_area_name: Optional[str] = None
|
|
207
|
-
polygon_file: Optional[str] = Field(
|
|
208
|
-
default=None,
|
|
209
|
-
min_length=1,
|
|
210
|
-
description="Path to a polygon file, relative to the database path.",
|
|
211
|
-
)
|
|
212
|
-
property_type: str # TODO make enum
|
|
213
|
-
|
|
214
|
-
@field_validator("type")
|
|
215
|
-
def validate_type(cls, value):
|
|
216
|
-
if not MeasureType.is_impact(value):
|
|
217
|
-
raise ValueError(f"Invalid impact type: {value}")
|
|
218
|
-
return value
|
|
219
|
-
|
|
220
|
-
@model_validator(mode="after")
|
|
221
|
-
def validate_aggregation_area_name(self):
|
|
222
|
-
if (
|
|
223
|
-
self.selection_type == SelectionType.aggregation_area
|
|
224
|
-
and self.aggregation_area_name is None
|
|
225
|
-
):
|
|
226
|
-
raise ValueError(
|
|
227
|
-
"If `selection_type` is 'aggregation_area', then `aggregation_area_name` needs to be set."
|
|
228
|
-
)
|
|
229
|
-
return self
|
|
230
|
-
|
|
231
|
-
@model_validator(mode="after")
|
|
232
|
-
def validate_polygon_file(self):
|
|
233
|
-
if self.selection_type == SelectionType.polygon and self.polygon_file is None:
|
|
234
|
-
raise ValueError(
|
|
235
|
-
"If `selection_type` is 'polygon', then `polygon_file` needs to be set."
|
|
236
|
-
)
|
|
237
|
-
|
|
238
|
-
return self
|
|
239
|
-
|
|
240
|
-
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
241
|
-
"""Save the additional files to the database."""
|
|
242
|
-
if self.polygon_file:
|
|
243
|
-
src_path = resolve_filepath("measures", self.name, self.polygon_file)
|
|
244
|
-
path = save_file_to_database(src_path, Path(output_dir))
|
|
245
|
-
# Update the shapefile path in the object so it is saved in the toml file as well
|
|
246
|
-
self.polygon_file = path.name
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
class Elevate(ImpactMeasure):
|
|
250
|
-
"""The expected variables and data types of the "elevate" impact measure.
|
|
251
|
-
|
|
252
|
-
Attributes
|
|
253
|
-
----------
|
|
254
|
-
name: str
|
|
255
|
-
Name of the measure.
|
|
256
|
-
description: str
|
|
257
|
-
Description of the measure.
|
|
258
|
-
type : MeasureType
|
|
259
|
-
Type of measure. Should be "elevate_properties".
|
|
260
|
-
selection_type : SelectionType
|
|
261
|
-
Type of selection. Should be "polygon" or "aggregation_area".
|
|
262
|
-
polygon_file : str, Optional
|
|
263
|
-
Path to a polygon file, either absolute or relative to the measure path.
|
|
264
|
-
aggregation_area_type : str, Optional
|
|
265
|
-
Type of aggregation area. Should be "aggregation_area" or "all".
|
|
266
|
-
aggregation_area_name : str, Optional
|
|
267
|
-
Name of the aggregation area.
|
|
268
|
-
property_type : str
|
|
269
|
-
Type of property. Should be "residential" or "commercial".
|
|
270
|
-
elevation : us.UnitfulLengthRefValue
|
|
271
|
-
Elevation of the properties.
|
|
272
|
-
"""
|
|
273
|
-
|
|
274
|
-
type: MeasureType = MeasureType.elevate_properties
|
|
275
|
-
elevation: us.UnitfulLengthRefValue
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
class Buyout(ImpactMeasure):
|
|
279
|
-
"""The expected variables and data types of the "buyout" impact measure.
|
|
280
|
-
|
|
281
|
-
Attributes
|
|
282
|
-
----------
|
|
283
|
-
name: str
|
|
284
|
-
Name of the measure.
|
|
285
|
-
description: str, default ""
|
|
286
|
-
Description of the measure.
|
|
287
|
-
type : MeasureType, default MeasureType.buyout_properties
|
|
288
|
-
Type of measure.
|
|
289
|
-
selection_type : SelectionType
|
|
290
|
-
Type of selection. Should be "polygon" or "aggregation_area".
|
|
291
|
-
polygon_file : str, Optional
|
|
292
|
-
Path to a polygon file, either absolute or relative to the measure path.
|
|
293
|
-
aggregation_area_type : str, Optional
|
|
294
|
-
Type of aggregation area. Should be "aggregation_area" or "all".
|
|
295
|
-
aggregation_area_name : str, Optional
|
|
296
|
-
Name of the aggregation area.
|
|
297
|
-
property_type : str
|
|
298
|
-
Type of property. Should be "residential" or "commercial".
|
|
299
|
-
elevation : us.UnitfulLengthRefValue
|
|
300
|
-
Elevation of the properties.
|
|
301
|
-
|
|
302
|
-
"""
|
|
303
|
-
|
|
304
|
-
# Buyout has only the basic impact measure attributes
|
|
305
|
-
type: MeasureType = MeasureType.buyout_properties
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
class FloodProof(ImpactMeasure):
|
|
309
|
-
"""The expected variables and data types of the "floodproof" impact measure.
|
|
310
|
-
|
|
311
|
-
Attributes
|
|
312
|
-
----------
|
|
313
|
-
name: str
|
|
314
|
-
Name of the measure.
|
|
315
|
-
description: str
|
|
316
|
-
Description of the measure.
|
|
317
|
-
type : MeasureType
|
|
318
|
-
Type of measure. Should be "floodproof_properties".
|
|
319
|
-
selection_type : SelectionType
|
|
320
|
-
Type of selection. Should be "polygon" or "aggregation_area".
|
|
321
|
-
polygon_file : str, Optional
|
|
322
|
-
Path to a polygon file, either absolute or relative to the measure path.
|
|
323
|
-
aggregation_area_type : str, Optional
|
|
324
|
-
Type of aggregation area. Should be "aggregation_area" or "all".
|
|
325
|
-
aggregation_area_name : str, Optional
|
|
326
|
-
Name of the aggregation area.
|
|
327
|
-
property_type : str
|
|
328
|
-
Type of property. Should be "residential" or "commercial".
|
|
329
|
-
elevation : us.UnitfulLengthRefValue
|
|
330
|
-
Elevation of the properties.
|
|
331
|
-
"""
|
|
332
|
-
|
|
333
|
-
type: MeasureType = MeasureType.floodproof_properties
|
|
334
|
-
elevation: us.UnitfulLength
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
class FloodWall(HazardMeasure):
|
|
338
|
-
"""
|
|
339
|
-
The expected variables and data types of the "floodwall" hazard measure.
|
|
340
|
-
|
|
341
|
-
Attributes
|
|
342
|
-
----------
|
|
343
|
-
name: str
|
|
344
|
-
Name of the measure.
|
|
345
|
-
description: str
|
|
346
|
-
Description of the measure.
|
|
347
|
-
type : MeasureType
|
|
348
|
-
Type of measure. Should be "MeasureType.floodwall"
|
|
349
|
-
selection_type : SelectionType
|
|
350
|
-
Type of selection. Should be "SelectionType.polygon" or "SelectionType.aggregation_area".
|
|
351
|
-
polygon_file : Optional[str]
|
|
352
|
-
Path to a polygon file, either absolute or relative to the measure path.
|
|
353
|
-
elevation : us.UnitfulLength
|
|
354
|
-
Height of the floodwall.
|
|
355
|
-
absolute_elevation : bool
|
|
356
|
-
TODO remove?
|
|
357
|
-
"""
|
|
358
|
-
|
|
359
|
-
type: MeasureType = MeasureType.floodwall
|
|
360
|
-
elevation: us.UnitfulLength
|
|
361
|
-
absolute_elevation: Optional[bool] = False
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
class Pump(HazardMeasure):
|
|
365
|
-
"""
|
|
366
|
-
The expected variables and data types of the "pump" hazard measure.
|
|
367
|
-
|
|
368
|
-
Attributes
|
|
369
|
-
----------
|
|
370
|
-
name: str
|
|
371
|
-
Name of the measure.
|
|
372
|
-
description: str
|
|
373
|
-
Description of the measure.
|
|
374
|
-
type : MeasureType
|
|
375
|
-
Type of measure. Should be "pump"
|
|
376
|
-
selection_type : SelectionType
|
|
377
|
-
Type of selection. Should be "polyline".
|
|
378
|
-
polygon_file : str, Optional
|
|
379
|
-
Path to a polygon file, either absolute or relative to the measure path.
|
|
380
|
-
elevation : us.UnitfulLength
|
|
381
|
-
Height of the floodwall.
|
|
382
|
-
absolute_elevation : bool
|
|
383
|
-
TODO remove?
|
|
384
|
-
"""
|
|
385
|
-
|
|
386
|
-
type: MeasureType = MeasureType.pump
|
|
387
|
-
discharge: us.UnitfulDischarge
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
class GreenInfrastructure(HazardMeasure):
|
|
391
|
-
"""The expected variables and data types of the "green infrastructure" hazard measure.
|
|
392
|
-
|
|
393
|
-
Attributes
|
|
394
|
-
----------
|
|
395
|
-
name: str
|
|
396
|
-
Name of the measure.
|
|
397
|
-
description: str
|
|
398
|
-
Description of the measure.
|
|
399
|
-
type : MeasureType
|
|
400
|
-
Type of measure. Should be "greening"
|
|
401
|
-
selection_type : SelectionType
|
|
402
|
-
Type of selection. Should be "polygon" or "aggregation_area".
|
|
403
|
-
height : us.UnitfulHeight, Optional
|
|
404
|
-
Height of the green infrastructure.
|
|
405
|
-
volume : us.UnitfulVolume, Optional
|
|
406
|
-
Volume of the green infrastructure.
|
|
407
|
-
polygon_file : str, Optional
|
|
408
|
-
Path to a polygon file, either absolute or relative to the measure path.
|
|
409
|
-
aggregation_area_type : str, Optional
|
|
410
|
-
Type of aggregation area. Should be "aggregation_area".
|
|
411
|
-
aggregation_area_name : str, Optional
|
|
412
|
-
Name of the aggregation area.
|
|
413
|
-
percent_area : float, Optional
|
|
414
|
-
Percentage of the area that is green infrastructure.
|
|
415
|
-
"""
|
|
416
|
-
|
|
417
|
-
type: MeasureType = MeasureType.greening
|
|
418
|
-
volume: us.UnitfulVolume
|
|
419
|
-
height: Optional[us.UnitfulHeight] = None
|
|
420
|
-
aggregation_area_type: Optional[str] = None
|
|
421
|
-
aggregation_area_name: Optional[str] = None
|
|
422
|
-
percent_area: Optional[float] = Field(default=None, ge=0, le=100)
|
|
423
|
-
|
|
424
|
-
@field_validator("height", mode="before", check_fields=False)
|
|
425
|
-
def height_from_length(value: Any) -> Any:
|
|
426
|
-
if isinstance(value, us.UnitfulLength):
|
|
427
|
-
return us.UnitfulHeight(value=value.value, units=value.units)
|
|
428
|
-
return value
|
|
429
|
-
|
|
430
|
-
@model_validator(mode="after")
|
|
431
|
-
def validate_hazard_type_values(self) -> "GreenInfrastructure":
|
|
432
|
-
e_msg = f"Error parsing GreenInfrastructure: {self.name}"
|
|
433
|
-
|
|
434
|
-
if self.type == MeasureType.total_storage:
|
|
435
|
-
if self.height is not None or self.percent_area is not None:
|
|
436
|
-
raise ValueError(
|
|
437
|
-
f"{e_msg}\nHeight and percent_area cannot be set for total storage type measures"
|
|
438
|
-
)
|
|
439
|
-
return self
|
|
440
|
-
elif self.type == MeasureType.water_square:
|
|
441
|
-
if self.percent_area is not None:
|
|
442
|
-
raise ValueError(
|
|
443
|
-
f"{e_msg}\nPercentage_area cannot be set for water square type measures"
|
|
444
|
-
)
|
|
445
|
-
elif not isinstance(self.height, us.UnitfulHeight):
|
|
446
|
-
raise ValueError(
|
|
447
|
-
f"{e_msg}\nHeight needs to be set for water square type measures"
|
|
448
|
-
)
|
|
449
|
-
return self
|
|
450
|
-
elif self.type == MeasureType.greening:
|
|
451
|
-
if not isinstance(self.height, us.UnitfulHeight) or not isinstance(
|
|
452
|
-
self.percent_area, float
|
|
453
|
-
):
|
|
454
|
-
raise ValueError(
|
|
455
|
-
f"{e_msg}\nHeight and percent_area needs to be set for greening type measures"
|
|
456
|
-
)
|
|
457
|
-
else:
|
|
458
|
-
raise ValueError(
|
|
459
|
-
f"{e_msg}\nType must be one of 'water_square', 'greening', or 'total_storage'"
|
|
460
|
-
)
|
|
461
|
-
return self
|
|
462
|
-
|
|
463
|
-
@model_validator(mode="after")
|
|
464
|
-
def validate_selection_type_values(self) -> "GreenInfrastructure":
|
|
465
|
-
if self.selection_type == SelectionType.aggregation_area:
|
|
466
|
-
if self.aggregation_area_name is None:
|
|
467
|
-
raise ValueError(
|
|
468
|
-
"If `selection_type` is 'aggregation_area', then `aggregation_area_name` needs to be set."
|
|
469
|
-
)
|
|
470
|
-
if self.aggregation_area_type is None:
|
|
471
|
-
raise ValueError(
|
|
472
|
-
"If `selection_type` is 'aggregation_area', then `aggregation_area_type` needs to be set."
|
|
473
|
-
)
|
|
474
|
-
return self
|
|
475
|
-
|
|
476
|
-
@staticmethod
|
|
477
|
-
def calculate_volume(
|
|
478
|
-
area: us.UnitfulArea,
|
|
479
|
-
height: us.UnitfulHeight,
|
|
480
|
-
percent_area: float = 100.0,
|
|
481
|
-
) -> float:
|
|
482
|
-
"""Determine volume from area of the polygon and infiltration height.
|
|
483
|
-
|
|
484
|
-
Parameters
|
|
485
|
-
----------
|
|
486
|
-
area : us.UnitfulArea
|
|
487
|
-
Area of polygon with units (calculated using calculate_polygon_area)
|
|
488
|
-
height : us.UnitfulHeight
|
|
489
|
-
Water height with units
|
|
490
|
-
percent_area : float, optional
|
|
491
|
-
Percentage area covered by green infrastructure [%], by default 100.0
|
|
492
|
-
|
|
493
|
-
Returns
|
|
494
|
-
-------
|
|
495
|
-
float
|
|
496
|
-
Volume [m3]
|
|
497
|
-
"""
|
|
498
|
-
volume = (
|
|
499
|
-
area.convert(us.UnitTypesArea.m2)
|
|
500
|
-
* height.convert(us.UnitTypesLength.meters)
|
|
501
|
-
* (percent_area / 100.0)
|
|
502
|
-
)
|
|
503
|
-
return volume
|
|
504
|
-
|
|
505
|
-
@staticmethod
|
|
506
|
-
def calculate_polygon_area(gdf: gpd.GeoDataFrame, site: Site) -> float:
|
|
507
|
-
"""Calculate area of a GeoDataFrame Polygon.
|
|
508
|
-
|
|
509
|
-
Parameters
|
|
510
|
-
----------
|
|
511
|
-
gdf : gpd.GeoDataFrame
|
|
512
|
-
Polygon object
|
|
513
|
-
site : Site
|
|
514
|
-
site config (used for CRS)
|
|
515
|
-
|
|
516
|
-
Returns
|
|
517
|
-
-------
|
|
518
|
-
area : float
|
|
519
|
-
Area of the given polygon
|
|
520
|
-
"""
|
|
521
|
-
# Determine local CRS
|
|
522
|
-
crs = pyproj.CRS.from_string(site.sfincs.config.csname)
|
|
523
|
-
gdf = gdf.to_crs(crs)
|
|
524
|
-
|
|
525
|
-
# The GeoJSON file can contain multiple polygons
|
|
526
|
-
polygon = gdf.geometry
|
|
527
|
-
# Calculate the area of all polygons
|
|
528
|
-
area = polygon.area.sum()
|
|
529
|
-
return area
|
|
1
|
+
import os
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
import geopandas as gpd
|
|
7
|
+
import pyproj
|
|
8
|
+
from pydantic import Field, field_validator, model_validator
|
|
9
|
+
|
|
10
|
+
from flood_adapt.config.site import Site
|
|
11
|
+
from flood_adapt.misc.utils import resolve_filepath, save_file_to_database
|
|
12
|
+
from flood_adapt.objects.forcing import unit_system as us
|
|
13
|
+
from flood_adapt.objects.object_model import Object
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MeasureCategory(str, Enum):
|
|
17
|
+
"""Class describing the accepted input for the variable 'type' in Measure."""
|
|
18
|
+
|
|
19
|
+
impact = "impact"
|
|
20
|
+
hazard = "hazard"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MeasureType(str, Enum):
|
|
24
|
+
"""Class describing the accepted input for the variable 'type' in Measure.
|
|
25
|
+
|
|
26
|
+
Each type of measure is associated with a category (hazard or impact) and can be used to determine the type of measure.
|
|
27
|
+
|
|
28
|
+
Attributes
|
|
29
|
+
----------
|
|
30
|
+
floodwall : A floodwall measure.
|
|
31
|
+
thin_dam : A thin dam measure.
|
|
32
|
+
levee : A levee measure.
|
|
33
|
+
pump : A pump measure.
|
|
34
|
+
culvert : A culvert measure.
|
|
35
|
+
water_square : A water square measure.
|
|
36
|
+
greening : A greening measure.
|
|
37
|
+
total_storage : A total storage measure.
|
|
38
|
+
elevate_properties : An elevate properties measure.
|
|
39
|
+
buyout_properties : A buyout properties measure.
|
|
40
|
+
floodproof_properties : A floodproof properties measure.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
# Hazard measures
|
|
44
|
+
floodwall = "floodwall"
|
|
45
|
+
thin_dam = "thin_dam" # For now, same functionality as floodwall TODO: Add thin dam functionality
|
|
46
|
+
levee = "levee" # For now, same functionality as floodwall TODO: Add levee functionality
|
|
47
|
+
pump = "pump"
|
|
48
|
+
culvert = (
|
|
49
|
+
"culvert" # For now, same functionality as pump TODO: Add culvert functionality
|
|
50
|
+
)
|
|
51
|
+
water_square = "water_square"
|
|
52
|
+
greening = "greening"
|
|
53
|
+
total_storage = "total_storage"
|
|
54
|
+
|
|
55
|
+
# Impact measures
|
|
56
|
+
elevate_properties = "elevate_properties"
|
|
57
|
+
buyout_properties = "buyout_properties"
|
|
58
|
+
floodproof_properties = "floodproof_properties"
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def is_hazard(cls, measure_type: str) -> bool:
|
|
62
|
+
return measure_type in [
|
|
63
|
+
cls.floodwall,
|
|
64
|
+
cls.thin_dam,
|
|
65
|
+
cls.levee,
|
|
66
|
+
cls.pump,
|
|
67
|
+
cls.culvert,
|
|
68
|
+
cls.water_square,
|
|
69
|
+
cls.greening,
|
|
70
|
+
cls.total_storage,
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def is_impact(cls, measure_type: str) -> bool:
|
|
75
|
+
return measure_type in [
|
|
76
|
+
cls.elevate_properties,
|
|
77
|
+
cls.buyout_properties,
|
|
78
|
+
cls.floodproof_properties,
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
def get_measure_category(cls, measure_type: str) -> MeasureCategory:
|
|
83
|
+
if cls.is_hazard(measure_type):
|
|
84
|
+
return MeasureCategory.hazard
|
|
85
|
+
elif cls.is_impact(measure_type):
|
|
86
|
+
return MeasureCategory.impact
|
|
87
|
+
else:
|
|
88
|
+
raise ValueError(f"Invalid measure type: {measure_type}")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class SelectionType(str, Enum):
|
|
92
|
+
"""Class describing the accepted input for the variable 'selection_type' in Measures.
|
|
93
|
+
|
|
94
|
+
It is used to determine where to apply the measure to a model.
|
|
95
|
+
|
|
96
|
+
Attributes
|
|
97
|
+
----------
|
|
98
|
+
aggregation_area : Use aggregation area as geometry for the measure.
|
|
99
|
+
polygon : Use polygon as geometry for the measure.
|
|
100
|
+
polyline : Use polyline as geometry for the measure.
|
|
101
|
+
all : Apply the measure to all geometries in the database.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
aggregation_area = "aggregation_area"
|
|
105
|
+
polygon = "polygon"
|
|
106
|
+
polyline = "polyline"
|
|
107
|
+
all = "all"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class Measure(Object):
|
|
111
|
+
"""The expected variables and data types of attributes common to all measures.
|
|
112
|
+
|
|
113
|
+
A measure is a collection of attributes that can be applied to a model.
|
|
114
|
+
|
|
115
|
+
Attributes
|
|
116
|
+
----------
|
|
117
|
+
name: str
|
|
118
|
+
Name of the measure.
|
|
119
|
+
description: str
|
|
120
|
+
Description of the measure.
|
|
121
|
+
type: MeasureType
|
|
122
|
+
Type of measure. Should be one of the MeasureType enum values.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
type: MeasureType
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class HazardMeasure(Measure):
|
|
129
|
+
"""The expected variables and data types of attributes common to all hazard measures.
|
|
130
|
+
|
|
131
|
+
Attributes
|
|
132
|
+
----------
|
|
133
|
+
name: str
|
|
134
|
+
Name of the measure.
|
|
135
|
+
description: str
|
|
136
|
+
Description of the measure.
|
|
137
|
+
type: MeasureType
|
|
138
|
+
Type of measure. Should be one of the MeasureType enum values and is_hazard.
|
|
139
|
+
selection_type: SelectionType
|
|
140
|
+
Type of selection. Should be one of the SelectionType enum values.
|
|
141
|
+
polygon_file: str, Optional, default = None
|
|
142
|
+
Path to a polygon file, either absolute or relative to the measure path in the database.
|
|
143
|
+
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
selection_type: SelectionType
|
|
147
|
+
polygon_file: Optional[str] = Field(
|
|
148
|
+
default=None,
|
|
149
|
+
min_length=1,
|
|
150
|
+
description="Path to a polygon file, either absolute or relative to the measure path.",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
@field_validator("type")
|
|
154
|
+
def validate_type(cls, value):
|
|
155
|
+
if not MeasureType.is_hazard(value):
|
|
156
|
+
raise ValueError(f"Invalid hazard type: {value}")
|
|
157
|
+
return value
|
|
158
|
+
|
|
159
|
+
@model_validator(mode="after")
|
|
160
|
+
def validate_selection_type(self) -> "HazardMeasure":
|
|
161
|
+
if (
|
|
162
|
+
self.selection_type
|
|
163
|
+
not in [SelectionType.aggregation_area, SelectionType.all]
|
|
164
|
+
and self.polygon_file is None
|
|
165
|
+
):
|
|
166
|
+
raise ValueError(
|
|
167
|
+
"If `selection_type` is not 'aggregation_area' or 'all', then `polygon_file` needs to be set."
|
|
168
|
+
)
|
|
169
|
+
return self
|
|
170
|
+
|
|
171
|
+
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
172
|
+
if self.polygon_file:
|
|
173
|
+
Path(output_dir).mkdir(parents=True, exist_ok=True)
|
|
174
|
+
src_path = resolve_filepath("measures", self.name, self.polygon_file)
|
|
175
|
+
path = save_file_to_database(src_path, Path(output_dir))
|
|
176
|
+
# Update the shapefile path in the object so it is saved in the toml file as well
|
|
177
|
+
self.polygon_file = path.name
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class ImpactMeasure(Measure):
|
|
181
|
+
"""The expected variables and data types of attributes common to all impact measures.
|
|
182
|
+
|
|
183
|
+
Attributes
|
|
184
|
+
----------
|
|
185
|
+
name: str
|
|
186
|
+
Name of the measure.
|
|
187
|
+
description: str
|
|
188
|
+
Description of the measure.
|
|
189
|
+
type: MeasureType
|
|
190
|
+
Type of measure. Should be one of the MeasureType enum values and is_hazard.
|
|
191
|
+
selection_type: SelectionType
|
|
192
|
+
Type of selection. Should be one of the SelectionType enum values.
|
|
193
|
+
polygon_file: str, Optional, default = None
|
|
194
|
+
Path to a polygon file, either absolute or relative to the measure path in the database.
|
|
195
|
+
property_type: str
|
|
196
|
+
Type of property. Should be one of the PropertyType enum values.
|
|
197
|
+
aggregation_area_type: str, Optional, default = None
|
|
198
|
+
Type of aggregation area. Should be one of the SelectionType enum values.
|
|
199
|
+
aggregation_area_name: str, Optional, default = None
|
|
200
|
+
Name of the aggregation area.
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
type: MeasureType
|
|
204
|
+
selection_type: SelectionType
|
|
205
|
+
aggregation_area_type: Optional[str] = None
|
|
206
|
+
aggregation_area_name: Optional[str] = None
|
|
207
|
+
polygon_file: Optional[str] = Field(
|
|
208
|
+
default=None,
|
|
209
|
+
min_length=1,
|
|
210
|
+
description="Path to a polygon file, relative to the database path.",
|
|
211
|
+
)
|
|
212
|
+
property_type: str # TODO make enum
|
|
213
|
+
|
|
214
|
+
@field_validator("type")
|
|
215
|
+
def validate_type(cls, value):
|
|
216
|
+
if not MeasureType.is_impact(value):
|
|
217
|
+
raise ValueError(f"Invalid impact type: {value}")
|
|
218
|
+
return value
|
|
219
|
+
|
|
220
|
+
@model_validator(mode="after")
|
|
221
|
+
def validate_aggregation_area_name(self):
|
|
222
|
+
if (
|
|
223
|
+
self.selection_type == SelectionType.aggregation_area
|
|
224
|
+
and self.aggregation_area_name is None
|
|
225
|
+
):
|
|
226
|
+
raise ValueError(
|
|
227
|
+
"If `selection_type` is 'aggregation_area', then `aggregation_area_name` needs to be set."
|
|
228
|
+
)
|
|
229
|
+
return self
|
|
230
|
+
|
|
231
|
+
@model_validator(mode="after")
|
|
232
|
+
def validate_polygon_file(self):
|
|
233
|
+
if self.selection_type == SelectionType.polygon and self.polygon_file is None:
|
|
234
|
+
raise ValueError(
|
|
235
|
+
"If `selection_type` is 'polygon', then `polygon_file` needs to be set."
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
return self
|
|
239
|
+
|
|
240
|
+
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
241
|
+
"""Save the additional files to the database."""
|
|
242
|
+
if self.polygon_file:
|
|
243
|
+
src_path = resolve_filepath("measures", self.name, self.polygon_file)
|
|
244
|
+
path = save_file_to_database(src_path, Path(output_dir))
|
|
245
|
+
# Update the shapefile path in the object so it is saved in the toml file as well
|
|
246
|
+
self.polygon_file = path.name
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class Elevate(ImpactMeasure):
|
|
250
|
+
"""The expected variables and data types of the "elevate" impact measure.
|
|
251
|
+
|
|
252
|
+
Attributes
|
|
253
|
+
----------
|
|
254
|
+
name: str
|
|
255
|
+
Name of the measure.
|
|
256
|
+
description: str
|
|
257
|
+
Description of the measure.
|
|
258
|
+
type : MeasureType
|
|
259
|
+
Type of measure. Should be "elevate_properties".
|
|
260
|
+
selection_type : SelectionType
|
|
261
|
+
Type of selection. Should be "polygon" or "aggregation_area".
|
|
262
|
+
polygon_file : str, Optional
|
|
263
|
+
Path to a polygon file, either absolute or relative to the measure path.
|
|
264
|
+
aggregation_area_type : str, Optional
|
|
265
|
+
Type of aggregation area. Should be "aggregation_area" or "all".
|
|
266
|
+
aggregation_area_name : str, Optional
|
|
267
|
+
Name of the aggregation area.
|
|
268
|
+
property_type : str
|
|
269
|
+
Type of property. Should be "residential" or "commercial".
|
|
270
|
+
elevation : us.UnitfulLengthRefValue
|
|
271
|
+
Elevation of the properties.
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
type: MeasureType = MeasureType.elevate_properties
|
|
275
|
+
elevation: us.UnitfulLengthRefValue
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class Buyout(ImpactMeasure):
|
|
279
|
+
"""The expected variables and data types of the "buyout" impact measure.
|
|
280
|
+
|
|
281
|
+
Attributes
|
|
282
|
+
----------
|
|
283
|
+
name: str
|
|
284
|
+
Name of the measure.
|
|
285
|
+
description: str, default ""
|
|
286
|
+
Description of the measure.
|
|
287
|
+
type : MeasureType, default MeasureType.buyout_properties
|
|
288
|
+
Type of measure.
|
|
289
|
+
selection_type : SelectionType
|
|
290
|
+
Type of selection. Should be "polygon" or "aggregation_area".
|
|
291
|
+
polygon_file : str, Optional
|
|
292
|
+
Path to a polygon file, either absolute or relative to the measure path.
|
|
293
|
+
aggregation_area_type : str, Optional
|
|
294
|
+
Type of aggregation area. Should be "aggregation_area" or "all".
|
|
295
|
+
aggregation_area_name : str, Optional
|
|
296
|
+
Name of the aggregation area.
|
|
297
|
+
property_type : str
|
|
298
|
+
Type of property. Should be "residential" or "commercial".
|
|
299
|
+
elevation : us.UnitfulLengthRefValue
|
|
300
|
+
Elevation of the properties.
|
|
301
|
+
|
|
302
|
+
"""
|
|
303
|
+
|
|
304
|
+
# Buyout has only the basic impact measure attributes
|
|
305
|
+
type: MeasureType = MeasureType.buyout_properties
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
class FloodProof(ImpactMeasure):
|
|
309
|
+
"""The expected variables and data types of the "floodproof" impact measure.
|
|
310
|
+
|
|
311
|
+
Attributes
|
|
312
|
+
----------
|
|
313
|
+
name: str
|
|
314
|
+
Name of the measure.
|
|
315
|
+
description: str
|
|
316
|
+
Description of the measure.
|
|
317
|
+
type : MeasureType
|
|
318
|
+
Type of measure. Should be "floodproof_properties".
|
|
319
|
+
selection_type : SelectionType
|
|
320
|
+
Type of selection. Should be "polygon" or "aggregation_area".
|
|
321
|
+
polygon_file : str, Optional
|
|
322
|
+
Path to a polygon file, either absolute or relative to the measure path.
|
|
323
|
+
aggregation_area_type : str, Optional
|
|
324
|
+
Type of aggregation area. Should be "aggregation_area" or "all".
|
|
325
|
+
aggregation_area_name : str, Optional
|
|
326
|
+
Name of the aggregation area.
|
|
327
|
+
property_type : str
|
|
328
|
+
Type of property. Should be "residential" or "commercial".
|
|
329
|
+
elevation : us.UnitfulLengthRefValue
|
|
330
|
+
Elevation of the properties.
|
|
331
|
+
"""
|
|
332
|
+
|
|
333
|
+
type: MeasureType = MeasureType.floodproof_properties
|
|
334
|
+
elevation: us.UnitfulLength
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
class FloodWall(HazardMeasure):
|
|
338
|
+
"""
|
|
339
|
+
The expected variables and data types of the "floodwall" hazard measure.
|
|
340
|
+
|
|
341
|
+
Attributes
|
|
342
|
+
----------
|
|
343
|
+
name: str
|
|
344
|
+
Name of the measure.
|
|
345
|
+
description: str
|
|
346
|
+
Description of the measure.
|
|
347
|
+
type : MeasureType
|
|
348
|
+
Type of measure. Should be "MeasureType.floodwall"
|
|
349
|
+
selection_type : SelectionType
|
|
350
|
+
Type of selection. Should be "SelectionType.polygon" or "SelectionType.aggregation_area".
|
|
351
|
+
polygon_file : Optional[str]
|
|
352
|
+
Path to a polygon file, either absolute or relative to the measure path.
|
|
353
|
+
elevation : us.UnitfulLength
|
|
354
|
+
Height of the floodwall.
|
|
355
|
+
absolute_elevation : bool
|
|
356
|
+
TODO remove?
|
|
357
|
+
"""
|
|
358
|
+
|
|
359
|
+
type: MeasureType = MeasureType.floodwall
|
|
360
|
+
elevation: us.UnitfulLength
|
|
361
|
+
absolute_elevation: Optional[bool] = False
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
class Pump(HazardMeasure):
|
|
365
|
+
"""
|
|
366
|
+
The expected variables and data types of the "pump" hazard measure.
|
|
367
|
+
|
|
368
|
+
Attributes
|
|
369
|
+
----------
|
|
370
|
+
name: str
|
|
371
|
+
Name of the measure.
|
|
372
|
+
description: str
|
|
373
|
+
Description of the measure.
|
|
374
|
+
type : MeasureType
|
|
375
|
+
Type of measure. Should be "pump"
|
|
376
|
+
selection_type : SelectionType
|
|
377
|
+
Type of selection. Should be "polyline".
|
|
378
|
+
polygon_file : str, Optional
|
|
379
|
+
Path to a polygon file, either absolute or relative to the measure path.
|
|
380
|
+
elevation : us.UnitfulLength
|
|
381
|
+
Height of the floodwall.
|
|
382
|
+
absolute_elevation : bool
|
|
383
|
+
TODO remove?
|
|
384
|
+
"""
|
|
385
|
+
|
|
386
|
+
type: MeasureType = MeasureType.pump
|
|
387
|
+
discharge: us.UnitfulDischarge
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
class GreenInfrastructure(HazardMeasure):
|
|
391
|
+
"""The expected variables and data types of the "green infrastructure" hazard measure.
|
|
392
|
+
|
|
393
|
+
Attributes
|
|
394
|
+
----------
|
|
395
|
+
name: str
|
|
396
|
+
Name of the measure.
|
|
397
|
+
description: str
|
|
398
|
+
Description of the measure.
|
|
399
|
+
type : MeasureType
|
|
400
|
+
Type of measure. Should be "greening"
|
|
401
|
+
selection_type : SelectionType
|
|
402
|
+
Type of selection. Should be "polygon" or "aggregation_area".
|
|
403
|
+
height : us.UnitfulHeight, Optional
|
|
404
|
+
Height of the green infrastructure.
|
|
405
|
+
volume : us.UnitfulVolume, Optional
|
|
406
|
+
Volume of the green infrastructure.
|
|
407
|
+
polygon_file : str, Optional
|
|
408
|
+
Path to a polygon file, either absolute or relative to the measure path.
|
|
409
|
+
aggregation_area_type : str, Optional
|
|
410
|
+
Type of aggregation area. Should be "aggregation_area".
|
|
411
|
+
aggregation_area_name : str, Optional
|
|
412
|
+
Name of the aggregation area.
|
|
413
|
+
percent_area : float, Optional
|
|
414
|
+
Percentage of the area that is green infrastructure.
|
|
415
|
+
"""
|
|
416
|
+
|
|
417
|
+
type: MeasureType = MeasureType.greening
|
|
418
|
+
volume: us.UnitfulVolume
|
|
419
|
+
height: Optional[us.UnitfulHeight] = None
|
|
420
|
+
aggregation_area_type: Optional[str] = None
|
|
421
|
+
aggregation_area_name: Optional[str] = None
|
|
422
|
+
percent_area: Optional[float] = Field(default=None, ge=0, le=100)
|
|
423
|
+
|
|
424
|
+
@field_validator("height", mode="before", check_fields=False)
|
|
425
|
+
def height_from_length(value: Any) -> Any:
|
|
426
|
+
if isinstance(value, us.UnitfulLength):
|
|
427
|
+
return us.UnitfulHeight(value=value.value, units=value.units)
|
|
428
|
+
return value
|
|
429
|
+
|
|
430
|
+
@model_validator(mode="after")
|
|
431
|
+
def validate_hazard_type_values(self) -> "GreenInfrastructure":
|
|
432
|
+
e_msg = f"Error parsing GreenInfrastructure: {self.name}"
|
|
433
|
+
|
|
434
|
+
if self.type == MeasureType.total_storage:
|
|
435
|
+
if self.height is not None or self.percent_area is not None:
|
|
436
|
+
raise ValueError(
|
|
437
|
+
f"{e_msg}\nHeight and percent_area cannot be set for total storage type measures"
|
|
438
|
+
)
|
|
439
|
+
return self
|
|
440
|
+
elif self.type == MeasureType.water_square:
|
|
441
|
+
if self.percent_area is not None:
|
|
442
|
+
raise ValueError(
|
|
443
|
+
f"{e_msg}\nPercentage_area cannot be set for water square type measures"
|
|
444
|
+
)
|
|
445
|
+
elif not isinstance(self.height, us.UnitfulHeight):
|
|
446
|
+
raise ValueError(
|
|
447
|
+
f"{e_msg}\nHeight needs to be set for water square type measures"
|
|
448
|
+
)
|
|
449
|
+
return self
|
|
450
|
+
elif self.type == MeasureType.greening:
|
|
451
|
+
if not isinstance(self.height, us.UnitfulHeight) or not isinstance(
|
|
452
|
+
self.percent_area, float
|
|
453
|
+
):
|
|
454
|
+
raise ValueError(
|
|
455
|
+
f"{e_msg}\nHeight and percent_area needs to be set for greening type measures"
|
|
456
|
+
)
|
|
457
|
+
else:
|
|
458
|
+
raise ValueError(
|
|
459
|
+
f"{e_msg}\nType must be one of 'water_square', 'greening', or 'total_storage'"
|
|
460
|
+
)
|
|
461
|
+
return self
|
|
462
|
+
|
|
463
|
+
@model_validator(mode="after")
|
|
464
|
+
def validate_selection_type_values(self) -> "GreenInfrastructure":
|
|
465
|
+
if self.selection_type == SelectionType.aggregation_area:
|
|
466
|
+
if self.aggregation_area_name is None:
|
|
467
|
+
raise ValueError(
|
|
468
|
+
"If `selection_type` is 'aggregation_area', then `aggregation_area_name` needs to be set."
|
|
469
|
+
)
|
|
470
|
+
if self.aggregation_area_type is None:
|
|
471
|
+
raise ValueError(
|
|
472
|
+
"If `selection_type` is 'aggregation_area', then `aggregation_area_type` needs to be set."
|
|
473
|
+
)
|
|
474
|
+
return self
|
|
475
|
+
|
|
476
|
+
@staticmethod
|
|
477
|
+
def calculate_volume(
|
|
478
|
+
area: us.UnitfulArea,
|
|
479
|
+
height: us.UnitfulHeight,
|
|
480
|
+
percent_area: float = 100.0,
|
|
481
|
+
) -> float:
|
|
482
|
+
"""Determine volume from area of the polygon and infiltration height.
|
|
483
|
+
|
|
484
|
+
Parameters
|
|
485
|
+
----------
|
|
486
|
+
area : us.UnitfulArea
|
|
487
|
+
Area of polygon with units (calculated using calculate_polygon_area)
|
|
488
|
+
height : us.UnitfulHeight
|
|
489
|
+
Water height with units
|
|
490
|
+
percent_area : float, optional
|
|
491
|
+
Percentage area covered by green infrastructure [%], by default 100.0
|
|
492
|
+
|
|
493
|
+
Returns
|
|
494
|
+
-------
|
|
495
|
+
float
|
|
496
|
+
Volume [m3]
|
|
497
|
+
"""
|
|
498
|
+
volume = (
|
|
499
|
+
area.convert(us.UnitTypesArea.m2)
|
|
500
|
+
* height.convert(us.UnitTypesLength.meters)
|
|
501
|
+
* (percent_area / 100.0)
|
|
502
|
+
)
|
|
503
|
+
return volume
|
|
504
|
+
|
|
505
|
+
@staticmethod
|
|
506
|
+
def calculate_polygon_area(gdf: gpd.GeoDataFrame, site: Site) -> float:
|
|
507
|
+
"""Calculate area of a GeoDataFrame Polygon.
|
|
508
|
+
|
|
509
|
+
Parameters
|
|
510
|
+
----------
|
|
511
|
+
gdf : gpd.GeoDataFrame
|
|
512
|
+
Polygon object
|
|
513
|
+
site : Site
|
|
514
|
+
site config (used for CRS)
|
|
515
|
+
|
|
516
|
+
Returns
|
|
517
|
+
-------
|
|
518
|
+
area : float
|
|
519
|
+
Area of the given polygon
|
|
520
|
+
"""
|
|
521
|
+
# Determine local CRS
|
|
522
|
+
crs = pyproj.CRS.from_string(site.sfincs.config.csname)
|
|
523
|
+
gdf = gdf.to_crs(crs)
|
|
524
|
+
|
|
525
|
+
# The GeoJSON file can contain multiple polygons
|
|
526
|
+
polygon = gdf.geometry
|
|
527
|
+
# Calculate the area of all polygons
|
|
528
|
+
area = polygon.area.sum()
|
|
529
|
+
return area
|