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