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,302 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, TypeVar
|
|
5
|
+
|
|
6
|
+
import tomli_w
|
|
7
|
+
|
|
8
|
+
from flood_adapt.dbs_classes.interface.database import IDatabase
|
|
9
|
+
from flood_adapt.dbs_classes.interface.element import AbstractDatabaseElement
|
|
10
|
+
from flood_adapt.objects.object_model import Object
|
|
11
|
+
|
|
12
|
+
T_OBJECTMODEL = TypeVar("T_OBJECTMODEL", bound=Object)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DbsTemplate(AbstractDatabaseElement[T_OBJECTMODEL]):
|
|
16
|
+
display_name: str
|
|
17
|
+
dir_name: str
|
|
18
|
+
_object_class: type[T_OBJECTMODEL]
|
|
19
|
+
|
|
20
|
+
def __init__(self, database: IDatabase):
|
|
21
|
+
"""Initialize any necessary attributes."""
|
|
22
|
+
self._database = database
|
|
23
|
+
self.input_path = database.input_path / self.dir_name
|
|
24
|
+
self.output_path = database.output_path / self.dir_name
|
|
25
|
+
self.standard_objects = []
|
|
26
|
+
|
|
27
|
+
def get(self, name: str) -> T_OBJECTMODEL:
|
|
28
|
+
"""Return an object of the type of the database with the given name.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
name : str
|
|
33
|
+
name of the object to be returned
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
Object
|
|
38
|
+
object of the type of the specified object model
|
|
39
|
+
"""
|
|
40
|
+
# Make the full path to the object
|
|
41
|
+
full_path = self.input_path / name / f"{name}.toml"
|
|
42
|
+
|
|
43
|
+
# Check if the object exists
|
|
44
|
+
if not Path(full_path).is_file():
|
|
45
|
+
raise ValueError(f"{self.display_name}: '{name}' does not exist.")
|
|
46
|
+
|
|
47
|
+
# Load and return the object
|
|
48
|
+
return self._object_class.load_file(full_path)
|
|
49
|
+
|
|
50
|
+
def list_objects(self) -> dict[str, list[Any]]:
|
|
51
|
+
"""Return a dictionary with info on the objects that currently exist in the database.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
dict[str, list[Any]]
|
|
56
|
+
A dictionary that contains the keys: `name`, 'path', 'last_modification_date', 'description', 'objects'
|
|
57
|
+
Each key has a list of the corresponding values, where the index of the values corresponds to the same object.
|
|
58
|
+
"""
|
|
59
|
+
# Check if all objects exist
|
|
60
|
+
object_list = self._get_object_list()
|
|
61
|
+
|
|
62
|
+
# Load all objects
|
|
63
|
+
objects = [self._object_class.load_file(path) for path in object_list["path"]]
|
|
64
|
+
|
|
65
|
+
# From the loaded objects, get the name and description and add them to the object_list
|
|
66
|
+
object_list["name"] = [obj.name for obj in objects]
|
|
67
|
+
object_list["description"] = [obj.description for obj in objects]
|
|
68
|
+
object_list["objects"] = objects
|
|
69
|
+
return object_list
|
|
70
|
+
|
|
71
|
+
def copy(self, old_name: str, new_name: str, new_description: str):
|
|
72
|
+
"""Copy (duplicate) an existing object, and give it a new name.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
old_name : str
|
|
77
|
+
name of the existing measure
|
|
78
|
+
new_name : str
|
|
79
|
+
name of the new measure
|
|
80
|
+
new_description : str
|
|
81
|
+
description of the new measure
|
|
82
|
+
"""
|
|
83
|
+
copy_object = self.get(old_name)
|
|
84
|
+
copy_object.name = new_name
|
|
85
|
+
copy_object.description = new_description
|
|
86
|
+
|
|
87
|
+
# After changing the name and description, re-trigger the validators
|
|
88
|
+
copy_object.model_validate(copy_object)
|
|
89
|
+
|
|
90
|
+
# Checking whether the new name is already in use
|
|
91
|
+
self._validate_to_save(copy_object, overwrite=False)
|
|
92
|
+
|
|
93
|
+
# Write only the toml file
|
|
94
|
+
toml_path = self.input_path / new_name / f"{new_name}.toml"
|
|
95
|
+
toml_path.parent.mkdir(parents=True)
|
|
96
|
+
with open(toml_path, "wb") as f:
|
|
97
|
+
tomli_w.dump(copy_object.model_dump(exclude_none=True), f)
|
|
98
|
+
|
|
99
|
+
# Then copy all the accompanied files
|
|
100
|
+
src = self.input_path / old_name
|
|
101
|
+
dest = self.input_path / new_name
|
|
102
|
+
|
|
103
|
+
EXCLUDE = [".spw", ".toml"]
|
|
104
|
+
for file in src.glob("*"):
|
|
105
|
+
if file.suffix in EXCLUDE:
|
|
106
|
+
continue
|
|
107
|
+
if file.is_dir():
|
|
108
|
+
shutil.copytree(file, dest / file.name, dirs_exist_ok=True)
|
|
109
|
+
else:
|
|
110
|
+
shutil.copy2(file, dest / file.name)
|
|
111
|
+
|
|
112
|
+
def save(
|
|
113
|
+
self,
|
|
114
|
+
object_model: T_OBJECTMODEL,
|
|
115
|
+
overwrite: bool = False,
|
|
116
|
+
):
|
|
117
|
+
"""Save an object in the database and all associated files.
|
|
118
|
+
|
|
119
|
+
This saves the toml file and any additional files attached to the object.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
object_model : Object
|
|
124
|
+
object to be saved in the database
|
|
125
|
+
overwrite : bool, optional
|
|
126
|
+
whether to overwrite the object if it already exists in the
|
|
127
|
+
database, by default False
|
|
128
|
+
|
|
129
|
+
Raises
|
|
130
|
+
------
|
|
131
|
+
ValueError
|
|
132
|
+
Raise error if name is already in use.
|
|
133
|
+
"""
|
|
134
|
+
self._validate_to_save(object_model, overwrite=overwrite)
|
|
135
|
+
|
|
136
|
+
# If the folder doesnt exist yet, make the folder and save the object
|
|
137
|
+
if not (self.input_path / object_model.name).exists():
|
|
138
|
+
(self.input_path / object_model.name).mkdir()
|
|
139
|
+
|
|
140
|
+
# Save the object and any additional files
|
|
141
|
+
object_model.save(
|
|
142
|
+
self.input_path / object_model.name / f"{object_model.name}.toml",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
def edit(self, object_model: T_OBJECTMODEL):
|
|
146
|
+
"""Edit an already existing object in the database.
|
|
147
|
+
|
|
148
|
+
Parameters
|
|
149
|
+
----------
|
|
150
|
+
object_model : Object
|
|
151
|
+
object to be edited in the database
|
|
152
|
+
|
|
153
|
+
Raises
|
|
154
|
+
------
|
|
155
|
+
ValueError
|
|
156
|
+
Raise error if name is already in use.
|
|
157
|
+
"""
|
|
158
|
+
# Check if the object exists
|
|
159
|
+
if object_model.name not in self.list_objects()["name"]:
|
|
160
|
+
raise ValueError(
|
|
161
|
+
f"{self.display_name}: '{object_model.name}' does not exist. You cannot edit an {self.display_name.lower()} that does not exist."
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Check if it is possible to delete the object by saving with overwrite. This then
|
|
165
|
+
# also covers checking whether the object is a standard object, is already used in
|
|
166
|
+
# a higher level object. If any of these are the case, it cannot be deleted.
|
|
167
|
+
self.save(object_model, overwrite=True)
|
|
168
|
+
|
|
169
|
+
def delete(self, name: str, toml_only: bool = False):
|
|
170
|
+
"""Delete an already existing object in the database.
|
|
171
|
+
|
|
172
|
+
Parameters
|
|
173
|
+
----------
|
|
174
|
+
name : str
|
|
175
|
+
name of the object to be deleted
|
|
176
|
+
toml_only : bool, optional
|
|
177
|
+
whether to only delete the toml file or the entire folder. If the folder is empty after deleting the toml,
|
|
178
|
+
it will always be deleted. By default False
|
|
179
|
+
|
|
180
|
+
Raises
|
|
181
|
+
------
|
|
182
|
+
ValueError
|
|
183
|
+
Raise error if object to be deleted is already in use.
|
|
184
|
+
"""
|
|
185
|
+
# Check if the object is a standard object. If it is, raise an error
|
|
186
|
+
if self._check_standard_objects(name):
|
|
187
|
+
raise ValueError(
|
|
188
|
+
f"'{name}' cannot be deleted/modified since it is a standard {self.display_name}."
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
# Check if object is used in a higher level object. If it is, raise an error
|
|
192
|
+
if used_in := self.check_higher_level_usage(name):
|
|
193
|
+
raise ValueError(
|
|
194
|
+
f"{self.display_name}: '{name}' cannot be deleted/modified since it is already used in: {', '.join(used_in)}"
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
# Once all checks are passed, delete the object
|
|
198
|
+
toml_path = self.input_path / name / f"{name}.toml"
|
|
199
|
+
if toml_only:
|
|
200
|
+
# Only delete the toml file
|
|
201
|
+
toml_path.unlink(missing_ok=True)
|
|
202
|
+
# If the folder is empty, delete the folder
|
|
203
|
+
if not list(toml_path.parent.iterdir()):
|
|
204
|
+
toml_path.parent.rmdir()
|
|
205
|
+
else:
|
|
206
|
+
# Delete the entire folder
|
|
207
|
+
shutil.rmtree(toml_path.parent, ignore_errors=True)
|
|
208
|
+
if (self.output_path / name).exists():
|
|
209
|
+
shutil.rmtree(self.output_path / name, ignore_errors=True)
|
|
210
|
+
|
|
211
|
+
def _check_standard_objects(self, name: str) -> bool:
|
|
212
|
+
"""Check if an object is a standard object.
|
|
213
|
+
|
|
214
|
+
Parameters
|
|
215
|
+
----------
|
|
216
|
+
name : str
|
|
217
|
+
name of the object to be checked
|
|
218
|
+
|
|
219
|
+
Returns
|
|
220
|
+
-------
|
|
221
|
+
bool
|
|
222
|
+
True if the object is a standard object, False otherwise
|
|
223
|
+
"""
|
|
224
|
+
# If this function is not implemented for the object type, it cannot be a standard object.
|
|
225
|
+
# By default, it is not a standard object.
|
|
226
|
+
return False
|
|
227
|
+
|
|
228
|
+
def check_higher_level_usage(self, name: str) -> list[str]:
|
|
229
|
+
"""Check if an object is used in a higher level object.
|
|
230
|
+
|
|
231
|
+
Parameters
|
|
232
|
+
----------
|
|
233
|
+
name : str
|
|
234
|
+
name of the object to be checked
|
|
235
|
+
|
|
236
|
+
Returns
|
|
237
|
+
-------
|
|
238
|
+
list[str]
|
|
239
|
+
list of higher level objects that use the object
|
|
240
|
+
"""
|
|
241
|
+
# If this function is not implemented for the object type, it cannot be used in a higher
|
|
242
|
+
# level object. By default, return an empty list
|
|
243
|
+
return []
|
|
244
|
+
|
|
245
|
+
def _get_object_list(self) -> dict[str, list[Any]]:
|
|
246
|
+
"""Get a dictionary with all the toml paths and last modification dates that exist in the database of the given object_type.
|
|
247
|
+
|
|
248
|
+
Returns
|
|
249
|
+
-------
|
|
250
|
+
dict[str, Any]
|
|
251
|
+
A dictionary that contains the keys: `name` to 'path' and 'last_modification_date'
|
|
252
|
+
Each key has a list of the corresponding values, where the index of the values corresponds to the same object.
|
|
253
|
+
"""
|
|
254
|
+
# If the toml doesnt exist, we might be in the middle of saving a new object or could be a broken object.
|
|
255
|
+
# In any case, we should not list it in the database
|
|
256
|
+
directories = [
|
|
257
|
+
dir
|
|
258
|
+
for dir in self.input_path.iterdir()
|
|
259
|
+
if (dir / f"{dir.name}.toml").is_file()
|
|
260
|
+
]
|
|
261
|
+
paths = [Path(dir / f"{dir.name}.toml") for dir in directories]
|
|
262
|
+
names = [dir.name for dir in directories]
|
|
263
|
+
last_modification_date = [
|
|
264
|
+
datetime.fromtimestamp(file.stat().st_mtime) for file in paths
|
|
265
|
+
]
|
|
266
|
+
|
|
267
|
+
objects = {
|
|
268
|
+
"name": names,
|
|
269
|
+
"path": paths,
|
|
270
|
+
"last_modification_date": last_modification_date,
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return objects
|
|
274
|
+
|
|
275
|
+
def _validate_to_save(self, object_model: T_OBJECTMODEL, overwrite: bool) -> None:
|
|
276
|
+
"""Validate if the object can be saved.
|
|
277
|
+
|
|
278
|
+
Parameters
|
|
279
|
+
----------
|
|
280
|
+
object_model : Object
|
|
281
|
+
object to be validated
|
|
282
|
+
|
|
283
|
+
Raises
|
|
284
|
+
------
|
|
285
|
+
ValueError
|
|
286
|
+
Raise error if name is already in use.
|
|
287
|
+
"""
|
|
288
|
+
# Check if the object exists
|
|
289
|
+
if object_model.name in self.list_objects()["name"]:
|
|
290
|
+
raise ValueError(
|
|
291
|
+
f"{self.display_name}: '{object_model.name}' already exists. Choose a different name."
|
|
292
|
+
)
|
|
293
|
+
object_exists = object_model.name in self.list_objects()["name"]
|
|
294
|
+
|
|
295
|
+
# If you want to overwrite the object, and the object already exists, first delete it. If it exists and you
|
|
296
|
+
# don't want to overwrite, raise an error.
|
|
297
|
+
if overwrite and object_exists:
|
|
298
|
+
self.delete(object_model.name, toml_only=True)
|
|
299
|
+
elif not overwrite and object_exists:
|
|
300
|
+
raise ValueError(
|
|
301
|
+
f"'{object_model.name}' name is already used by another {self.display_name.lower()}. Choose a different name"
|
|
302
|
+
)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, Optional, Union
|
|
5
|
+
|
|
6
|
+
import geopandas as gpd
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
from cht_cyclones.tropical_cyclone import TropicalCyclone
|
|
10
|
+
|
|
11
|
+
from flood_adapt.config.site import Site
|
|
12
|
+
from flood_adapt.dbs_classes.interface.element import AbstractDatabaseElement
|
|
13
|
+
from flood_adapt.dbs_classes.interface.static import IDbsStatic
|
|
14
|
+
from flood_adapt.objects.benefits.benefits import Benefit
|
|
15
|
+
from flood_adapt.objects.events.events import Event
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class IDatabase(ABC):
|
|
19
|
+
base_path: Path
|
|
20
|
+
input_path: Path
|
|
21
|
+
output_path: Path
|
|
22
|
+
static_path: Path
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def site(self) -> Site: ...
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def static(self) -> IDbsStatic: ...
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
@abstractmethod
|
|
34
|
+
def events(self) -> AbstractDatabaseElement: ...
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def scenarios(self) -> AbstractDatabaseElement: ...
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def strategies(self) -> AbstractDatabaseElement: ...
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def measures(self) -> AbstractDatabaseElement: ...
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
@abstractmethod
|
|
50
|
+
def projections(self) -> AbstractDatabaseElement: ...
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def benefits(self) -> AbstractDatabaseElement: ...
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def __init__(
|
|
58
|
+
self, database_path: Union[str, os.PathLike], site_name: str
|
|
59
|
+
) -> None: ...
|
|
60
|
+
|
|
61
|
+
@abstractmethod
|
|
62
|
+
def interp_slr(self, slr_scenario: str, year: float) -> float:
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
@abstractmethod
|
|
66
|
+
def plot_slr_scenarios(self) -> str:
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
@abstractmethod
|
|
70
|
+
def write_to_csv(self, name: str, event: Event, df: pd.DataFrame) -> None:
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
@abstractmethod
|
|
74
|
+
def write_cyc(self, event: Event, track: TropicalCyclone) -> None:
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
@abstractmethod
|
|
78
|
+
def check_benefit_scenarios(self, benefit: Benefit) -> pd.DataFrame:
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
@abstractmethod
|
|
82
|
+
def create_benefit_scenarios(self, benefit: Benefit) -> None:
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
@abstractmethod
|
|
86
|
+
def run_benefit(self, benefit_name: Union[str, list[str]]) -> None:
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
@abstractmethod
|
|
90
|
+
def update(self) -> None:
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
@abstractmethod
|
|
94
|
+
def get_outputs(self) -> dict[str, Any]:
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
@abstractmethod
|
|
98
|
+
def get_topobathy_path(self) -> str:
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
@abstractmethod
|
|
102
|
+
def get_index_path(self) -> str:
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
@abstractmethod
|
|
106
|
+
def get_depth_conversion(self) -> float:
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
@abstractmethod
|
|
110
|
+
def get_max_water_level(
|
|
111
|
+
self, scenario_name: str, return_period: Optional[int] = None
|
|
112
|
+
) -> np.ndarray:
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
@abstractmethod
|
|
116
|
+
def get_building_footprints(self, scenario_name: str) -> gpd.GeoDataFrame:
|
|
117
|
+
pass
|
|
118
|
+
|
|
119
|
+
@abstractmethod
|
|
120
|
+
def get_roads(self, scenario_name: str) -> gpd.GeoDataFrame:
|
|
121
|
+
pass
|
|
122
|
+
|
|
123
|
+
@abstractmethod
|
|
124
|
+
def get_aggregation(self, scenario_name: str) -> dict[str, gpd.GeoDataFrame]:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
@abstractmethod
|
|
128
|
+
def get_aggregation_benefits(
|
|
129
|
+
self, benefit_name: str
|
|
130
|
+
) -> dict[str, gpd.GeoDataFrame]:
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
@abstractmethod
|
|
134
|
+
def get_object_list(self, object_type: str) -> dict[str, Any]:
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
@abstractmethod
|
|
138
|
+
def has_run_hazard(self, scenario_name: str) -> None:
|
|
139
|
+
pass
|
|
140
|
+
|
|
141
|
+
@abstractmethod
|
|
142
|
+
def run_scenario(self, scenario_name: Union[str, list[str]]) -> None:
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
@abstractmethod
|
|
146
|
+
def cleanup(self) -> None:
|
|
147
|
+
pass
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any, Generic, TypeVar
|
|
4
|
+
|
|
5
|
+
from flood_adapt.objects.object_model import Object
|
|
6
|
+
|
|
7
|
+
T_OBJECT_MODEL = TypeVar("T_OBJECT_MODEL", bound=Object)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AbstractDatabaseElement(ABC, Generic[T_OBJECT_MODEL]):
|
|
11
|
+
input_path: Path
|
|
12
|
+
output_path: Path
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def __init__(self):
|
|
16
|
+
"""Abstract class for database elements."""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def get(self, name: str) -> T_OBJECT_MODEL:
|
|
21
|
+
"""Return the object of the type of the database with the given name.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
name : str
|
|
26
|
+
name of the object to be returned
|
|
27
|
+
|
|
28
|
+
Returns
|
|
29
|
+
-------
|
|
30
|
+
IObject
|
|
31
|
+
object of the type of the specified object model
|
|
32
|
+
"""
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
@abstractmethod
|
|
36
|
+
def list_objects(self) -> dict[str, list[Any]]:
|
|
37
|
+
"""Return a dictionary with info on the objects that currently exist in the database.
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
dict[str, Any]
|
|
42
|
+
Includes 'name', 'description', 'path' and 'last_modification_date' info, as well as the objects themselves
|
|
43
|
+
"""
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def copy(self, old_name: str, new_name: str, new_description: str):
|
|
48
|
+
"""Copy (duplicate) an existing object, and give it a new name.
|
|
49
|
+
|
|
50
|
+
Parameters
|
|
51
|
+
----------
|
|
52
|
+
old_name : str
|
|
53
|
+
name of the existing measure
|
|
54
|
+
new_name : str
|
|
55
|
+
name of the new measure
|
|
56
|
+
new_description : str
|
|
57
|
+
description of the new measure
|
|
58
|
+
"""
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
@abstractmethod
|
|
62
|
+
def save(
|
|
63
|
+
self,
|
|
64
|
+
object_model: T_OBJECT_MODEL,
|
|
65
|
+
overwrite: bool = False,
|
|
66
|
+
):
|
|
67
|
+
"""Save an object in the database.
|
|
68
|
+
|
|
69
|
+
This only saves the toml file. If the object also contains a geojson file, this should be saved separately.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
object_model : Object
|
|
74
|
+
object to be saved in the database
|
|
75
|
+
overwrite : bool, optional
|
|
76
|
+
whether to overwrite the object if it already exists in the
|
|
77
|
+
database, by default False
|
|
78
|
+
toml_only : bool, optional
|
|
79
|
+
whether to only save the toml file or all associated data. By default, save everything
|
|
80
|
+
|
|
81
|
+
Raises
|
|
82
|
+
------
|
|
83
|
+
ValueError
|
|
84
|
+
Raise error if name is already in use.
|
|
85
|
+
"""
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
@abstractmethod
|
|
89
|
+
def edit(self, object_model: T_OBJECT_MODEL):
|
|
90
|
+
"""Edits an already existing object in the database.
|
|
91
|
+
|
|
92
|
+
Parameters
|
|
93
|
+
----------
|
|
94
|
+
object : IObject
|
|
95
|
+
object to be edited in the database
|
|
96
|
+
|
|
97
|
+
Raises
|
|
98
|
+
------
|
|
99
|
+
ValueError
|
|
100
|
+
Raise error if name is already in use.
|
|
101
|
+
"""
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
@abstractmethod
|
|
105
|
+
def delete(self, name: str, toml_only: bool = False):
|
|
106
|
+
"""Delete an already existing object in the database.
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
name : str
|
|
111
|
+
name of the object to be deleted
|
|
112
|
+
toml_only : bool, optional
|
|
113
|
+
whether to only delete the toml file or the entire folder. If the folder is empty after deleting the toml,
|
|
114
|
+
it will always be deleted. By default False
|
|
115
|
+
|
|
116
|
+
Raises
|
|
117
|
+
------
|
|
118
|
+
ValueError
|
|
119
|
+
Raise error if object to be deleted is already in use.
|
|
120
|
+
"""
|
|
121
|
+
pass
|
|
122
|
+
|
|
123
|
+
@abstractmethod
|
|
124
|
+
def check_higher_level_usage(self, name: str) -> list[str]:
|
|
125
|
+
"""Check if an object is used in a higher level object.
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
name : str
|
|
130
|
+
name of the object to be checked
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
list[str]
|
|
135
|
+
list of higher level objects that use the object
|
|
136
|
+
"""
|
|
137
|
+
pass
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Union
|
|
4
|
+
|
|
5
|
+
import geopandas as gpd
|
|
6
|
+
import pandas as pd
|
|
7
|
+
from cht_cyclones.cyclone_track_database import CycloneTrackDatabase
|
|
8
|
+
|
|
9
|
+
from flood_adapt.adapter.sfincs_adapter import SfincsAdapter
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class IDbsStatic(ABC):
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def get_aggregation_areas(self) -> dict: ...
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def get_model_boundary(self) -> gpd.GeoDataFrame: ...
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def get_model_grid(self): ...
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def get_obs_points(self) -> gpd.GeoDataFrame: ...
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def get_static_map(self, path: Union[str, Path]) -> gpd.GeoDataFrame: ...
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def get_slr_scn_names(self) -> list: ...
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def get_green_infra_table(self, measure_type: str) -> pd.DataFrame: ...
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def get_buildings(self) -> gpd.GeoDataFrame: ...
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def get_property_types(self) -> list: ...
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def get_overland_sfincs_model(self) -> SfincsAdapter: ...
|
|
42
|
+
|
|
43
|
+
@abstractmethod
|
|
44
|
+
def get_offshore_sfincs_model(self) -> SfincsAdapter: ...
|
|
45
|
+
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def get_cyclone_track_database(self) -> CycloneTrackDatabase: ...
|