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.
Files changed (139) hide show
  1. flood_adapt/__init__.py +22 -0
  2. flood_adapt/adapter/__init__.py +9 -0
  3. flood_adapt/adapter/fiat_adapter.py +1502 -0
  4. flood_adapt/adapter/interface/__init__.py +0 -0
  5. flood_adapt/adapter/interface/hazard_adapter.py +70 -0
  6. flood_adapt/adapter/interface/impact_adapter.py +36 -0
  7. flood_adapt/adapter/interface/model_adapter.py +89 -0
  8. flood_adapt/adapter/interface/offshore.py +19 -0
  9. flood_adapt/adapter/sfincs_adapter.py +1857 -0
  10. flood_adapt/adapter/sfincs_offshore.py +193 -0
  11. flood_adapt/config/__init__.py +0 -0
  12. flood_adapt/config/config.py +245 -0
  13. flood_adapt/config/fiat.py +219 -0
  14. flood_adapt/config/gui.py +224 -0
  15. flood_adapt/config/sfincs.py +336 -0
  16. flood_adapt/config/site.py +124 -0
  17. flood_adapt/database_builder/__init__.py +0 -0
  18. flood_adapt/database_builder/database_builder.py +2175 -0
  19. flood_adapt/database_builder/templates/default_units/imperial.toml +9 -0
  20. flood_adapt/database_builder/templates/default_units/metric.toml +9 -0
  21. flood_adapt/database_builder/templates/green_infra_table/green_infra_lookup_table.csv +10 -0
  22. flood_adapt/database_builder/templates/icons/black_down_48x48.png +0 -0
  23. flood_adapt/database_builder/templates/icons/black_left_48x48.png +0 -0
  24. flood_adapt/database_builder/templates/icons/black_right_48x48.png +0 -0
  25. flood_adapt/database_builder/templates/icons/black_up_48x48.png +0 -0
  26. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-16_white_down.png +0 -0
  27. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-16_white_left.png +0 -0
  28. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-16_white_right.png +0 -0
  29. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-16_white_up.png +0 -0
  30. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_black_down.png +0 -0
  31. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_black_left.png +0 -0
  32. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_black_right.png +0 -0
  33. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_black_up.png +0 -0
  34. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_white_left.png +0 -0
  35. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_white_right.png +0 -0
  36. flood_adapt/database_builder/templates/icons/white_down_48x48.png +0 -0
  37. flood_adapt/database_builder/templates/icons/white_left_48x48.png +0 -0
  38. flood_adapt/database_builder/templates/icons/white_right_48x48.png +0 -0
  39. flood_adapt/database_builder/templates/icons/white_up_48x48.png +0 -0
  40. flood_adapt/database_builder/templates/infographics/OSM/config_charts.toml +90 -0
  41. flood_adapt/database_builder/templates/infographics/OSM/config_people.toml +57 -0
  42. flood_adapt/database_builder/templates/infographics/OSM/config_risk_charts.toml +121 -0
  43. flood_adapt/database_builder/templates/infographics/OSM/config_roads.toml +65 -0
  44. flood_adapt/database_builder/templates/infographics/OSM/styles.css +45 -0
  45. flood_adapt/database_builder/templates/infographics/US_NSI/config_charts.toml +126 -0
  46. flood_adapt/database_builder/templates/infographics/US_NSI/config_people.toml +60 -0
  47. flood_adapt/database_builder/templates/infographics/US_NSI/config_risk_charts.toml +121 -0
  48. flood_adapt/database_builder/templates/infographics/US_NSI/config_roads.toml +65 -0
  49. flood_adapt/database_builder/templates/infographics/US_NSI/styles.css +45 -0
  50. flood_adapt/database_builder/templates/infographics/images/ambulance.png +0 -0
  51. flood_adapt/database_builder/templates/infographics/images/car.png +0 -0
  52. flood_adapt/database_builder/templates/infographics/images/cart.png +0 -0
  53. flood_adapt/database_builder/templates/infographics/images/firetruck.png +0 -0
  54. flood_adapt/database_builder/templates/infographics/images/hospital.png +0 -0
  55. flood_adapt/database_builder/templates/infographics/images/house.png +0 -0
  56. flood_adapt/database_builder/templates/infographics/images/info.png +0 -0
  57. flood_adapt/database_builder/templates/infographics/images/money.png +0 -0
  58. flood_adapt/database_builder/templates/infographics/images/person.png +0 -0
  59. flood_adapt/database_builder/templates/infographics/images/school.png +0 -0
  60. flood_adapt/database_builder/templates/infographics/images/truck.png +0 -0
  61. flood_adapt/database_builder/templates/infographics/images/walking_person.png +0 -0
  62. flood_adapt/database_builder/templates/infometrics/OSM/metrics_additional_risk_configs.toml +4 -0
  63. flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config.toml +143 -0
  64. flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config_risk.toml +153 -0
  65. flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config.toml +127 -0
  66. flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config_risk.toml +57 -0
  67. flood_adapt/database_builder/templates/infometrics/US_NSI/metrics_additional_risk_configs.toml +4 -0
  68. flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config.toml +191 -0
  69. flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config_risk.toml +153 -0
  70. flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config.toml +178 -0
  71. flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config_risk.toml +57 -0
  72. flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config.toml +9 -0
  73. flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config_risk.toml +65 -0
  74. flood_adapt/database_builder/templates/mapbox_layers/bin_colors.toml +5 -0
  75. flood_adapt/database_builder.py +16 -0
  76. flood_adapt/dbs_classes/__init__.py +21 -0
  77. flood_adapt/dbs_classes/database.py +716 -0
  78. flood_adapt/dbs_classes/dbs_benefit.py +97 -0
  79. flood_adapt/dbs_classes/dbs_event.py +91 -0
  80. flood_adapt/dbs_classes/dbs_measure.py +103 -0
  81. flood_adapt/dbs_classes/dbs_projection.py +52 -0
  82. flood_adapt/dbs_classes/dbs_scenario.py +150 -0
  83. flood_adapt/dbs_classes/dbs_static.py +261 -0
  84. flood_adapt/dbs_classes/dbs_strategy.py +147 -0
  85. flood_adapt/dbs_classes/dbs_template.py +302 -0
  86. flood_adapt/dbs_classes/interface/database.py +147 -0
  87. flood_adapt/dbs_classes/interface/element.py +137 -0
  88. flood_adapt/dbs_classes/interface/static.py +47 -0
  89. flood_adapt/flood_adapt.py +1371 -0
  90. flood_adapt/misc/__init__.py +0 -0
  91. flood_adapt/misc/database_user.py +16 -0
  92. flood_adapt/misc/log.py +183 -0
  93. flood_adapt/misc/path_builder.py +54 -0
  94. flood_adapt/misc/utils.py +185 -0
  95. flood_adapt/objects/__init__.py +59 -0
  96. flood_adapt/objects/benefits/__init__.py +0 -0
  97. flood_adapt/objects/benefits/benefits.py +61 -0
  98. flood_adapt/objects/events/__init__.py +0 -0
  99. flood_adapt/objects/events/event_factory.py +135 -0
  100. flood_adapt/objects/events/event_set.py +84 -0
  101. flood_adapt/objects/events/events.py +221 -0
  102. flood_adapt/objects/events/historical.py +55 -0
  103. flood_adapt/objects/events/hurricane.py +64 -0
  104. flood_adapt/objects/events/synthetic.py +48 -0
  105. flood_adapt/objects/forcing/__init__.py +0 -0
  106. flood_adapt/objects/forcing/csv.py +68 -0
  107. flood_adapt/objects/forcing/discharge.py +66 -0
  108. flood_adapt/objects/forcing/forcing.py +142 -0
  109. flood_adapt/objects/forcing/forcing_factory.py +182 -0
  110. flood_adapt/objects/forcing/meteo_handler.py +93 -0
  111. flood_adapt/objects/forcing/netcdf.py +40 -0
  112. flood_adapt/objects/forcing/plotting.py +428 -0
  113. flood_adapt/objects/forcing/rainfall.py +98 -0
  114. flood_adapt/objects/forcing/tide_gauge.py +191 -0
  115. flood_adapt/objects/forcing/time_frame.py +77 -0
  116. flood_adapt/objects/forcing/timeseries.py +552 -0
  117. flood_adapt/objects/forcing/unit_system.py +580 -0
  118. flood_adapt/objects/forcing/waterlevels.py +108 -0
  119. flood_adapt/objects/forcing/wind.py +124 -0
  120. flood_adapt/objects/measures/__init__.py +0 -0
  121. flood_adapt/objects/measures/measure_factory.py +92 -0
  122. flood_adapt/objects/measures/measures.py +506 -0
  123. flood_adapt/objects/object_model.py +68 -0
  124. flood_adapt/objects/projections/__init__.py +0 -0
  125. flood_adapt/objects/projections/projections.py +89 -0
  126. flood_adapt/objects/scenarios/__init__.py +0 -0
  127. flood_adapt/objects/scenarios/scenarios.py +22 -0
  128. flood_adapt/objects/strategies/__init__.py +0 -0
  129. flood_adapt/objects/strategies/strategies.py +68 -0
  130. flood_adapt/workflows/__init__.py +0 -0
  131. flood_adapt/workflows/benefit_runner.py +541 -0
  132. flood_adapt/workflows/floodmap.py +85 -0
  133. flood_adapt/workflows/impacts_integrator.py +82 -0
  134. flood_adapt/workflows/scenario_runner.py +69 -0
  135. flood_adapt-0.3.0.dist-info/LICENSE +21 -0
  136. flood_adapt-0.3.0.dist-info/METADATA +183 -0
  137. flood_adapt-0.3.0.dist-info/RECORD +139 -0
  138. flood_adapt-0.3.0.dist-info/WHEEL +5 -0
  139. flood_adapt-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1371 @@
1
+ import os
2
+ from pathlib import Path
3
+ from typing import Any, List, Optional, Type, Union
4
+
5
+ import geopandas as gpd
6
+ import numpy as np
7
+ import pandas as pd
8
+ from cht_cyclones.tropical_cyclone import TropicalCyclone
9
+ from fiat_toolbox.infographics.infographics_factory import InforgraphicFactory
10
+ from fiat_toolbox.metrics_writer.fiat_read_metrics_file import MetricsFileReader
11
+ from hydromt_sfincs.quadtree import QuadtreeGrid
12
+
13
+ from flood_adapt.config.site import Site
14
+ from flood_adapt.dbs_classes.database import Database
15
+ from flood_adapt.misc.log import FloodAdaptLogging
16
+ from flood_adapt.objects.benefits.benefits import Benefit
17
+ from flood_adapt.objects.events.event_factory import (
18
+ EventFactory,
19
+ )
20
+ from flood_adapt.objects.events.event_set import EventSet
21
+ from flood_adapt.objects.events.events import (
22
+ Event,
23
+ Mode,
24
+ Template,
25
+ )
26
+ from flood_adapt.objects.forcing import unit_system as us
27
+ from flood_adapt.objects.forcing.csv import read_csv as _read_csv
28
+ from flood_adapt.objects.forcing.forcing import (
29
+ ForcingType,
30
+ IForcing,
31
+ )
32
+ from flood_adapt.objects.forcing.forcing_factory import ForcingFactory
33
+ from flood_adapt.objects.forcing.plotting import (
34
+ plot_forcing as _plot_forcing,
35
+ )
36
+ from flood_adapt.objects.forcing.tide_gauge import TideGauge
37
+ from flood_adapt.objects.forcing.time_frame import TimeFrame
38
+ from flood_adapt.objects.measures.measures import (
39
+ Buyout,
40
+ Elevate,
41
+ FloodProof,
42
+ FloodWall,
43
+ GreenInfrastructure,
44
+ Measure,
45
+ Pump,
46
+ )
47
+ from flood_adapt.objects.projections.projections import Projection
48
+ from flood_adapt.objects.scenarios.scenarios import Scenario
49
+ from flood_adapt.objects.strategies.strategies import Strategy
50
+ from flood_adapt.workflows.impacts_integrator import Impacts
51
+
52
+
53
+ class FloodAdapt:
54
+ database: Database
55
+
56
+ def __init__(self, database_path: Path) -> None:
57
+ """Initialize the FloodAdapt class with a database path.
58
+
59
+ Parameters
60
+ ----------
61
+ database_path : Path
62
+ The path to the database file.
63
+ """
64
+ self.database = Database(
65
+ database_path=database_path.parent, database_name=database_path.name
66
+ )
67
+ self.logger = FloodAdaptLogging.getLogger()
68
+
69
+ # Measures
70
+ def get_measures(self) -> dict[str, Any]:
71
+ """
72
+ Get all measures from the database.
73
+
74
+ Returns
75
+ -------
76
+ dict[str, Any]
77
+ A dictionary containing all measures.
78
+ Includes keys: 'name', 'description', 'path', 'last_modification_date', 'objects'
79
+ Each value is a list of the corresponding attribute for each measure.
80
+ """
81
+ return self.database.measures.list_objects()
82
+
83
+ def get_measure(self, name: str) -> Measure:
84
+ """
85
+ Get a measure from the database by name.
86
+
87
+ Parameters
88
+ ----------
89
+ name : str
90
+ The name of the measure to retrieve.
91
+
92
+ Returns
93
+ -------
94
+ Measure
95
+ The measure object with the given name.
96
+
97
+ Raises
98
+ ------
99
+ ValueError
100
+ If the measure with the given name does not exist.
101
+ """
102
+ return self.database.measures.get(name)
103
+
104
+ def create_measure(self, attrs: dict[str, Any], type: str = None) -> Measure:
105
+ """Create a measure from a dictionary of attributes and a type string.
106
+
107
+ Parameters
108
+ ----------
109
+ attrs : dict[str, Any]
110
+ Dictionary of attributes for the measure.
111
+ type : str
112
+ Type of measure to create.
113
+
114
+ Returns
115
+ -------
116
+ Measure
117
+ Measure object.
118
+ """
119
+ if type == "elevate_properties":
120
+ return Elevate(**attrs)
121
+ elif type == "buyout_properties":
122
+ return Buyout(**attrs)
123
+ elif type == "floodproof_properties":
124
+ return FloodProof(**attrs)
125
+ elif type in ["floodwall", "thin_dam", "levee"]:
126
+ return FloodWall(**attrs)
127
+ elif type in ["pump", "culvert"]:
128
+ return Pump(**attrs)
129
+ elif type in ["water_square", "total_storage", "greening"]:
130
+ return GreenInfrastructure(**attrs)
131
+ else:
132
+ raise ValueError(f"Invalid measure type: {type}")
133
+
134
+ def save_measure(self, measure: Measure, overwrite: bool = False) -> None:
135
+ """Save an event object to the database.
136
+
137
+ Parameters
138
+ ----------
139
+ measure : Measure
140
+ The measure object to save.
141
+
142
+ Raises
143
+ ------
144
+ ValueError
145
+ If the event object is not valid.
146
+ """
147
+ self.database.measures.save(measure, overwrite=overwrite)
148
+
149
+ def edit_measure(self, measure: Measure) -> None:
150
+ """Edit an event object in the database.
151
+
152
+ Parameters
153
+ ----------
154
+ measure : Measure
155
+ The measure object to edit.
156
+
157
+
158
+ Raises
159
+ ------
160
+ ValueError
161
+ If the event object does not exist.
162
+ """
163
+ self.database.measures.edit(measure)
164
+
165
+ def delete_measure(self, name: str) -> None:
166
+ """Delete an event from the database.
167
+
168
+ Parameters
169
+ ----------
170
+ name : str
171
+ The name of the event to delete.
172
+
173
+ Raises
174
+ ------
175
+ ValueError
176
+ If the event does not exist.
177
+ """
178
+ self.database.measures.delete(name)
179
+
180
+ def copy_measure(self, old_name: str, new_name: str, new_description: str) -> None:
181
+ """Copy an event in the database.
182
+
183
+ Parameters
184
+ ----------
185
+ old_name : str
186
+ The name of the event to copy.
187
+ new_name : str
188
+ The name of the new event.
189
+ new_description : str
190
+ The description of the new event
191
+ """
192
+ self.database.measures.copy(old_name, new_name, new_description)
193
+
194
+ def calculate_polygon_area(self, gdf: gpd.GeoDataFrame, site: Site) -> float:
195
+ """
196
+ Calculate the area of a polygon from a GeoDataFrame.
197
+
198
+ Parameters
199
+ ----------
200
+ gdf : gpd.GeoDataFrame
201
+ A GeoDataFrame containing the polygon geometry.
202
+ site : Site
203
+ An instance of Site representing the site information.
204
+
205
+ Returns
206
+ -------
207
+ float: The area of the polygon in the specified units.
208
+ """
209
+ return GreenInfrastructure.calculate_polygon_area(gdf=gdf, site=site)
210
+
211
+ def calculate_volume(
212
+ self,
213
+ area: us.UnitfulArea,
214
+ height: us.UnitfulHeight = us.UnitfulHeight(
215
+ value=0.0, units=us.UnitTypesLength.meters
216
+ ),
217
+ percent_area: float = 100.0,
218
+ ) -> float:
219
+ """
220
+ Calculate the volume of green infrastructure based on the given area, height, and percent area.
221
+
222
+ Parameters
223
+ ----------
224
+ area : float
225
+ The area of the green infrastructure in square units.
226
+ height : float
227
+ The height of the green infrastructure in units. Defaults to 0.0.
228
+ percent_area : float
229
+ The percentage of the area to be considered. Defaults to 100.0.
230
+
231
+
232
+ Returns
233
+ -------
234
+ float: The calculated volume of the green infrastructure.
235
+ """
236
+ return GreenInfrastructure.calculate_volume(
237
+ area=area, height=height, percent_area=percent_area
238
+ )
239
+
240
+ def get_green_infra_table(self, measure_type: str) -> pd.DataFrame:
241
+ """Return a table with different types of green infrastructure measures and their infiltration depths.
242
+
243
+ Parameters
244
+ ----------
245
+ measure_type : str
246
+ The type of green infrastructure measure.
247
+
248
+ Returns
249
+ -------
250
+ pd.DataFrame
251
+ A table with different types of green infrastructure measures and their infiltration depths.
252
+
253
+ """
254
+ return self.database.static.get_green_infra_table(measure_type)
255
+
256
+ # Strategies
257
+ def get_strategies(self) -> dict[str, Any]:
258
+ """
259
+ Get all strategies from the database.
260
+
261
+ Returns
262
+ -------
263
+ dict[str, Any]
264
+ A dictionary containing all strategies.
265
+ Includes keys: 'name', 'description', 'path', 'last_modification_date', 'objects'
266
+ Each value is a list of the corresponding attribute for each strategy.
267
+ """
268
+ return self.database.strategies.list_objects()
269
+
270
+ def get_strategy(self, name: str) -> Strategy:
271
+ """
272
+ Get a strategy from the database by name.
273
+
274
+ Parameters
275
+ ----------
276
+ name : str
277
+ The name of the strategy to retrieve.
278
+
279
+ Returns
280
+ -------
281
+ Strategy
282
+ The strategy object with the given name.
283
+
284
+ Raises
285
+ ------
286
+ ValueError
287
+ If the strategy with the given name does not exist.
288
+ """
289
+ return self.database.strategies.get(name)
290
+
291
+ def create_strategy(self, attrs: dict[str, Any]) -> Strategy:
292
+ """Create a new strategy object.
293
+
294
+ Parameters
295
+ ----------
296
+ attrs : dict[str, Any]
297
+ The attributes of the strategy object to create. Should adhere to the Strategy schema.
298
+
299
+ Returns
300
+ -------
301
+ Strategy
302
+ The strategy object
303
+
304
+ Raises
305
+ ------
306
+ ValueError
307
+ If the strategy with the given name does not exist.
308
+ If attrs does not adhere to the Strategy schema.
309
+ """
310
+ return Strategy(**attrs)
311
+
312
+ def save_strategy(self, strategy: Strategy) -> None:
313
+ """
314
+ Save a strategy object to the database.
315
+
316
+ Parameters
317
+ ----------
318
+ strategy : Strategy
319
+ The strategy object to save.
320
+
321
+ Raises
322
+ ------
323
+ ValueError
324
+ If the strategy object is not valid.
325
+ If the strategy object already exists.
326
+ """
327
+ self.database.strategies.save(strategy)
328
+
329
+ def delete_strategy(self, name: str) -> None:
330
+ """
331
+ Delete a strategy from the database.
332
+
333
+ Parameters
334
+ ----------
335
+ name : str
336
+ The name of the strategy to delete.
337
+
338
+ Raises
339
+ ------
340
+ ValueError
341
+ If the strategy does not exist.
342
+ """
343
+ self.database.strategies.delete(name)
344
+
345
+ # Events
346
+ def get_events(self) -> dict[str, Any]:
347
+ """Get all events from the database.
348
+
349
+ Returns
350
+ -------
351
+ dict[str, Any]
352
+ A dictionary containing all events.
353
+ Includes keys: 'name', 'description', 'path', 'last_modification_date', 'objects'
354
+ Each value is a list of the corresponding attribute for each benefit.
355
+ """
356
+ return self.database.events.list_objects()
357
+
358
+ def get_event(self, name: str) -> Event | EventSet:
359
+ """Get an event from the database by name.
360
+
361
+ Parameters
362
+ ----------
363
+ name : str
364
+ The name of the event to retrieve.
365
+
366
+ Returns
367
+ -------
368
+ Event | EventSet
369
+ The event with the given name.
370
+
371
+ Raises
372
+ ------
373
+ ValueError
374
+ If the event with the given name does not exist.
375
+ """
376
+ return self.database.events.get(name)
377
+
378
+ def get_event_mode(self, name: str) -> Mode:
379
+ """Get the mode of an event from the database by name.
380
+
381
+ Parameters
382
+ ----------
383
+ name : str
384
+
385
+ Returns
386
+ -------
387
+ Mode
388
+ The mode of the event with the given name, either `risk` or `single_event`.
389
+ """
390
+ return self.database.events.get(name).mode
391
+
392
+ def create_event(self, attrs: dict[str, Any] | Event) -> Event:
393
+ """Create a event object from a dictionary of attributes.
394
+
395
+ Parameters
396
+ ----------
397
+ attrs : Event [str, Any]
398
+ Dictionary of attributes
399
+
400
+ Returns
401
+ -------
402
+ Event
403
+ Depending on attrs.template an event object.
404
+ Can be of type: Synthetic, Historical, Hurricane.
405
+ """
406
+ return EventFactory.load_dict(attrs)
407
+
408
+ def create_event_set(
409
+ self, attrs: dict[str, Any] | EventSet, sub_events: list[Event]
410
+ ) -> EventSet:
411
+ """Create a event set object from a dictionary of attributes.
412
+
413
+ Parameters
414
+ ----------
415
+ attrs : EventSet [str, Any]
416
+ Dictionary of attributes
417
+ sub_events : list[Event]
418
+ List of events in the event set
419
+
420
+ Returns
421
+ -------
422
+ EventSet
423
+ EventSet object
424
+ """
425
+ return EventSet(**attrs, sub_events=sub_events)
426
+
427
+ @staticmethod
428
+ def list_forcings() -> list[Type[IForcing]]:
429
+ return ForcingFactory.list_forcings()
430
+
431
+ @staticmethod
432
+ def get_allowed_forcings(template: Template) -> dict[str, List[str]]:
433
+ return EventFactory.get_allowed_forcings(template)
434
+
435
+ def save_event(self, event: Event) -> None:
436
+ """Save an event object to the database.
437
+
438
+ Parameters
439
+ ----------
440
+ event : Event
441
+ The event object to save.
442
+
443
+ Raises
444
+ ------
445
+ ValueError
446
+ If the event object is not valid.
447
+ """
448
+ self.database.events.save(event)
449
+
450
+ def save_timeseries_csv(self, name: str, event: Event, df: pd.DataFrame) -> None:
451
+ """Save timeseries data to a csv file.
452
+
453
+ Parameters
454
+ ----------
455
+ name : str
456
+ Name of the event
457
+ event : Event
458
+ Event object
459
+ df : pd.DataFrame
460
+ Dataframe of timeseries data
461
+ """
462
+ self.database.write_to_csv(name, event, df)
463
+
464
+ def edit_event(self, event: Event) -> None:
465
+ """Edit an event object in the database.
466
+
467
+ Parameters
468
+ ----------
469
+ event : Event
470
+ The event object to edit.
471
+
472
+ Raises
473
+ ------
474
+ ValueError
475
+ If the event object does not exist.
476
+ If the event is used in a scenario.
477
+ """
478
+ self.database.events.edit(event)
479
+
480
+ def delete_event(self, name: str) -> None:
481
+ """Delete an event from the database.
482
+
483
+ Parameters
484
+ ----------
485
+ name : str
486
+ The name of the event to delete.
487
+
488
+ Raises
489
+ ------
490
+ ValueError
491
+ If the event does not exist.
492
+ If the event is used in a scenario.
493
+ """
494
+ self.database.events.delete(name)
495
+
496
+ def copy_event(self, old_name: str, new_name: str, new_description: str) -> None:
497
+ """Copy an event in the database.
498
+
499
+ Parameters
500
+ ----------
501
+ old_name : str
502
+ The name of the event to copy.
503
+ new_name : str
504
+ The name of the new event.
505
+ new_description : str
506
+ The description of the new event
507
+ """
508
+ self.database.events.copy(old_name, new_name, new_description)
509
+
510
+ def check_higher_level_usage(self, name: str) -> list[str]:
511
+ """Check if an event is used in a scenario.
512
+
513
+ Parameters
514
+ ----------
515
+ name : str
516
+ name of the event to be checked
517
+
518
+ Returns
519
+ -------
520
+ list[str]
521
+ list of scenario names where the event is used
522
+
523
+ """
524
+ return self.database.events.check_higher_level_usage(name)
525
+
526
+ def download_wl_data(
527
+ self,
528
+ tide_gauge: TideGauge,
529
+ time: TimeFrame,
530
+ units: us.UnitTypesLength,
531
+ out_path: str,
532
+ ) -> pd.DataFrame:
533
+ """Download water level data from a station or tide gauge.
534
+
535
+ Parameters
536
+ ----------
537
+ tide_gauge : TideGauge
538
+ Tide gauge object to download data from
539
+ time: TimeFrame
540
+ Time model object containing start and end time
541
+ units : UnitTypesLength
542
+ Units that data the returned data will be converted to
543
+ out_path : str
544
+ Path to save the data to
545
+ """
546
+ return tide_gauge.get_waterlevels_in_time_frame(
547
+ time=time,
548
+ units=units,
549
+ out_path=Path(out_path),
550
+ )
551
+
552
+ def read_csv(self, csvpath: Union[str, os.PathLike]) -> pd.DataFrame:
553
+ """Read a csv file into a pandas DataFrame.
554
+
555
+ Parameters
556
+ ----------
557
+ csvpath : Union[str, os.PathLike]
558
+ Path to the csv file
559
+
560
+ Returns
561
+ -------
562
+ pd.DataFrame
563
+ DataFrame containing the data from the csv file
564
+ """
565
+ return _read_csv(csvpath)
566
+
567
+ def plot_forcing(
568
+ self, event: Event, forcing_type: ForcingType
569
+ ) -> tuple[str, Optional[List[Exception]]]:
570
+ """Plot forcing data for an event.
571
+
572
+ Parameters
573
+ ----------
574
+ event : Event
575
+ The event object
576
+ forcing_type : ForcingType
577
+ The type of forcing data to plot
578
+ """
579
+ return _plot_forcing(event, self.database.site, forcing_type)
580
+
581
+ def save_cyclone_track(self, event: Event, track: TropicalCyclone):
582
+ """Save cyclone track data to the event folder.
583
+
584
+ Parameters
585
+ ----------
586
+ event : Event
587
+ The event object
588
+ track : TropicalCyclone
589
+ The cyclone track data
590
+ """
591
+ self.database.write_cyc(event, track)
592
+
593
+ def get_cyclone_track_by_index(self, index: int) -> TropicalCyclone:
594
+ return self.database.static.get_cyclone_track_database().get_track(index)
595
+
596
+ # Projections
597
+ def get_projections(self) -> dict[str, Any]:
598
+ """
599
+ Get all projections from the database.
600
+
601
+ Returns
602
+ -------
603
+ dict[str, Any]
604
+ A dictionary containing all projections.
605
+ Includes keys: 'name', 'description', 'path', 'last_modification_date', 'objects'
606
+ Each value is a list of the corresponding attribute for each projection.
607
+ """
608
+ return self.database.projections.list_objects()
609
+
610
+ def get_projection(self, name: str) -> Projection:
611
+ """Get a projection from the database by name.
612
+
613
+ Parameters
614
+ ----------
615
+ name : str
616
+ The name of the projection to retrieve.
617
+
618
+ Returns
619
+ -------
620
+ Projection
621
+ The projection object with the given name.
622
+
623
+ Raises
624
+ ------
625
+ ValueError
626
+ If the projection with the given name does not exist.
627
+ """
628
+ return self.database.projections.get(name)
629
+
630
+ def create_projection(self, attrs: dict[str, Any]) -> Projection:
631
+ """Create a new projection object.
632
+
633
+ Parameters
634
+ ----------
635
+ attrs : dict[str, Any]
636
+ The attributes of the projection object to create. Should adhere to the Projection schema.
637
+
638
+ Returns
639
+ -------
640
+ Projection
641
+ The projection object created from the attributes.
642
+
643
+ Raises
644
+ ------
645
+ ValueError
646
+ If the attributes do not adhere to the Projection schema.
647
+ """
648
+ return Projection(**attrs)
649
+
650
+ def save_projection(self, projection: Projection) -> None:
651
+ """Save a projection object to the database.
652
+
653
+ Parameters
654
+ ----------
655
+ projection : Projection
656
+ The projection object to save.
657
+
658
+ Raises
659
+ ------
660
+ ValueError
661
+ If the projection object is not valid.
662
+ """
663
+ self.database.projections.save(projection)
664
+
665
+ def edit_projection(self, projection: Projection) -> None:
666
+ """Edit a projection object in the database.
667
+
668
+ Parameters
669
+ ----------
670
+ projection : Projection
671
+ The projection object to edit.
672
+
673
+ Raises
674
+ ------
675
+ ValueError
676
+ If the projection object does not exist.
677
+ """
678
+ self.database.projections.edit(projection)
679
+
680
+ def delete_projection(self, name: str) -> None:
681
+ """Delete a projection from the database.
682
+
683
+ Parameters
684
+ ----------
685
+ name : str
686
+ The name of the projection to delete.
687
+
688
+ Raises
689
+ ------
690
+ ValueError
691
+ If the projection does not exist.
692
+ If the projection is used in a scenario.
693
+ """
694
+ self.database.projections.delete(name)
695
+
696
+ def copy_projection(
697
+ self, old_name: str, new_name: str, new_description: str
698
+ ) -> None:
699
+ """Copy a projection in the database.
700
+
701
+ Parameters
702
+ ----------
703
+ old_name : str
704
+ The name of the projection to copy.
705
+ new_name : str
706
+ The name of the new projection.
707
+ new_description : str
708
+ The description of the new projection
709
+ """
710
+ self.database.projections.copy(old_name, new_name, new_description)
711
+
712
+ def get_slr_scn_names(
713
+ self,
714
+ ) -> list:
715
+ """
716
+ Get all sea level rise scenario names from the database.
717
+
718
+ Returns
719
+ -------
720
+ list
721
+ List of scenario names
722
+ """
723
+ return self.database.static.get_slr_scn_names()
724
+
725
+ def interp_slr(self, slr_scenario: str, year: float) -> float:
726
+ """
727
+ Interpolate sea level rise for a given scenario and year.
728
+
729
+ Parameters
730
+ ----------
731
+ slr_scenario : str
732
+ The name of the sea level rise scenario.
733
+ year : float
734
+ The year to interpolate sea level rise for.
735
+
736
+ Returns
737
+ -------
738
+ float
739
+ The interpolated sea level rise for the given scenario and year.
740
+ """
741
+ return self.database.interp_slr(slr_scenario, year)
742
+
743
+ def plot_slr_scenarios(self) -> str:
744
+ """
745
+ Plot sea level rise scenarios.
746
+
747
+ Returns
748
+ -------
749
+ str
750
+ The path to the html plot of the sea level rise scenarios.
751
+ """
752
+ return self.database.plot_slr_scenarios()
753
+
754
+ # Scenarios
755
+ def get_scenarios(self) -> dict[str, Any]:
756
+ """Get all scenarios from the database.
757
+
758
+ Returns
759
+ -------
760
+ dict[str, Any]
761
+ A dictionary containing all scenarios.
762
+ Includes keys: 'name', 'description', 'path', 'last_modification_date', 'objects'.
763
+ Each value is a list of the corresponding attribute for each scenario.
764
+ """
765
+ return self.database.scenarios.list_objects()
766
+
767
+ def get_scenario(self, name: str) -> Scenario:
768
+ """Get a scenario from the database by name.
769
+
770
+ Parameters
771
+ ----------
772
+ name : str
773
+ The name of the scenario to retrieve.
774
+
775
+ Returns
776
+ -------
777
+ Scenario
778
+ The scenario object with the given name.
779
+
780
+ Raises
781
+ ------
782
+ ValueError
783
+ If the scenario with the given name does not exist.
784
+ """
785
+ return self.database.scenarios.get(name)
786
+
787
+ def create_scenario(self, attrs: dict[str, Any]) -> Scenario:
788
+ """Create a new scenario object.
789
+
790
+ Parameters
791
+ ----------
792
+ attrs : dict[str, Any]
793
+ The attributes of the scenario object to create. Should adhere to the Scenario schema.
794
+
795
+ Returns
796
+ -------
797
+ Scenario
798
+ The scenario object created from the attributes.
799
+
800
+ Raises
801
+ ------
802
+ ValueError
803
+ If the attributes do not adhere to the Scenario schema.
804
+ """
805
+ return Scenario(**attrs)
806
+
807
+ def save_scenario(self, scenario: Scenario) -> tuple[bool, str]:
808
+ """Save the scenario to the database.
809
+
810
+ Parameters
811
+ ----------
812
+ scenario : Scenario
813
+ The scenario to save.
814
+
815
+ Returns
816
+ -------
817
+ bool
818
+ Whether the scenario was saved successfully.
819
+ str
820
+ The error message if the scenario was not saved successfully.
821
+ """
822
+ try:
823
+ self.database.scenarios.save(scenario)
824
+ return True, ""
825
+ except Exception as e:
826
+ return False, str(e)
827
+
828
+ def edit_scenario(self, scenario: Scenario) -> None:
829
+ """Edit a scenario object in the database.
830
+
831
+ Parameters
832
+ ----------
833
+ scenario : Scenario
834
+ The scenario object to edit.
835
+
836
+ Raises
837
+ ------
838
+ ValueError
839
+ If the scenario object does not exist.
840
+ """
841
+ self.database.scenarios.edit(scenario)
842
+
843
+ def delete_scenario(self, name: str) -> None:
844
+ """Delete a scenario from the database.
845
+
846
+ Parameters
847
+ ----------
848
+ name : str
849
+ The name of the scenario to delete.
850
+
851
+ Raises
852
+ ------
853
+ ValueError
854
+ If the scenario does not exist.
855
+ """
856
+ self.database.scenarios.delete(name)
857
+
858
+ def run_scenario(self, name: Union[str, list[str]]) -> None:
859
+ """Run a scenario.
860
+
861
+ Parameters
862
+ ----------
863
+ name : Union[str, list[str]]
864
+ The name(s) of the scenario to run.
865
+
866
+ Raises
867
+ ------
868
+ ValueError
869
+ If the scenario does not exist.
870
+ """
871
+ self.database.run_scenario(name)
872
+
873
+ # Outputs
874
+ def get_outputs(
875
+ self,
876
+ ) -> dict[str, Any]:
877
+ """Get all completed scenarios from the database.
878
+
879
+ Returns
880
+ -------
881
+ dict[str, Any]
882
+ A dictionary containing all scenarios.
883
+ Includes keys: 'name', 'description', 'path', 'last_modification_date', 'objects'
884
+ Each value is a list of the corresponding attribute for each output.
885
+ """
886
+ return self.database.get_outputs()
887
+
888
+ def get_topobathy_path(self) -> str:
889
+ """
890
+ Return the path of the topobathy tiles in order to create flood maps with water level maps.
891
+
892
+ Returns
893
+ -------
894
+ str
895
+ The path to the topobathy file.
896
+
897
+ """
898
+ return self.database.get_topobathy_path()
899
+
900
+ def get_index_path(self) -> str:
901
+ """
902
+ Return the path of the index tiles which are used to connect each water level cell with the topobathy tiles.
903
+
904
+ Returns
905
+ -------
906
+ str
907
+ The path to the index file.
908
+ """
909
+ return self.database.get_index_path()
910
+
911
+ def get_depth_conversion(self) -> float:
912
+ """
913
+ Return the flood depth conversion that is need in the gui to plot the flood map.
914
+
915
+ Returns
916
+ -------
917
+ float
918
+ The flood depth conversion.
919
+ """
920
+ return self.database.get_depth_conversion()
921
+
922
+ def get_max_water_level(self, name: str, rp: int = None) -> np.ndarray:
923
+ """
924
+ Return the maximum water level for the given scenario.
925
+
926
+ Parameters
927
+ ----------
928
+ name : str
929
+ The name of the scenario.
930
+ rp : int, optional
931
+ The return period of the water level, by default None
932
+
933
+ Returns
934
+ -------
935
+ np.ndarray
936
+ 2D gridded map with the maximum waterlevels for each cell.
937
+ """
938
+ return self.database.get_max_water_level(name, rp)
939
+
940
+ def get_building_footprints(self, name: str) -> gpd.GeoDataFrame:
941
+ """
942
+ Return a geodataframe of the impacts at the footprint level.
943
+
944
+ Parameters
945
+ ----------
946
+ name : str
947
+ The name of the scenario.
948
+
949
+ Returns
950
+ -------
951
+ gpd.GeoDataFrame
952
+ The impact footprints for the scenario.
953
+ """
954
+ return self.database.get_building_footprints(name)
955
+
956
+ def get_aggregation(self, name: str) -> dict[str, gpd.GeoDataFrame]:
957
+ """
958
+ Return a dictionary with the aggregated impacts as geodataframes.
959
+
960
+ Parameters
961
+ ----------
962
+ name : str
963
+ The name of the scenario.
964
+
965
+ Returns
966
+ -------
967
+ dict[str, gpd.GeoDataFrame]
968
+ The aggregated impacts for the scenario.
969
+ """
970
+ return self.database.get_aggregation(name)
971
+
972
+ def get_roads(self, name: str) -> gpd.GeoDataFrame:
973
+ """
974
+ Return a geodataframe of the impacts at roads.
975
+
976
+ Parameters
977
+ ----------
978
+ name : str
979
+ The name of the scenario.
980
+
981
+ Returns
982
+ -------
983
+ gpd.GeoDataFrame
984
+ The impacted roads for the scenario.
985
+ """
986
+ return self.database.get_roads(name)
987
+
988
+ def get_obs_point_timeseries(self, name: str) -> gpd.GeoDataFrame:
989
+ """Return the HTML strings of the water level timeseries for the given scenario.
990
+
991
+ Parameters
992
+ ----------
993
+ name : str
994
+ The name of the scenario.
995
+
996
+ Returns
997
+ -------
998
+ str
999
+ The HTML strings of the water level timeseries
1000
+ """
1001
+ # Get the impacts objects from the scenario
1002
+ scenario = self.database.scenarios.get(name)
1003
+ hazard = Impacts(scenario).hazard
1004
+
1005
+ # Check if the scenario has run
1006
+ if not hazard.has_run:
1007
+ raise ValueError(
1008
+ f"Scenario {name} has not been run. Please run the scenario first."
1009
+ )
1010
+
1011
+ output_path = self.database.scenarios.output_path.joinpath(hazard.name)
1012
+ gdf = self.database.static.get_obs_points()
1013
+ gdf["html"] = [
1014
+ str(output_path.joinpath("Flooding", f"{station}_timeseries.html"))
1015
+ for station in gdf.name
1016
+ ]
1017
+
1018
+ return gdf
1019
+
1020
+ def get_infographic(self, name: str) -> str:
1021
+ """Return the HTML string of the infographic for the given scenario.
1022
+
1023
+ Parameters
1024
+ ----------
1025
+ name : str
1026
+ The name of the scenario.
1027
+
1028
+ Returns
1029
+ -------
1030
+ str
1031
+ The HTML string of the infographic.
1032
+ """
1033
+ # Get the impacts objects from the scenario
1034
+ database = self.database
1035
+ scn = database.scenarios.get(name)
1036
+ impact = Impacts(scenario=scn)
1037
+ event_mode = self.database.events.get(scn.event).mode
1038
+
1039
+ # Check if the scenario has run
1040
+ if not impact.has_run_check():
1041
+ raise ValueError(
1042
+ f"Scenario {name} has not been run. Please run the scenario first."
1043
+ )
1044
+
1045
+ config_path = database.static_path.joinpath("templates", "infographics")
1046
+ output_path = database.scenarios.output_path.joinpath(impact.name)
1047
+ metrics_outputs_path = output_path.joinpath(f"Infometrics_{impact.name}.csv")
1048
+
1049
+ infographic_path = InforgraphicFactory.create_infographic_file_writer(
1050
+ infographic_mode=event_mode,
1051
+ scenario_name=impact.name,
1052
+ metrics_full_path=metrics_outputs_path,
1053
+ config_base_path=config_path,
1054
+ output_base_path=output_path,
1055
+ ).get_infographics_html()
1056
+
1057
+ return infographic_path
1058
+
1059
+ def get_infometrics(self, name: str) -> pd.DataFrame:
1060
+ """Return the metrics for the given scenario.
1061
+
1062
+ Parameters
1063
+ ----------
1064
+ name : str
1065
+ The name of the scenario.
1066
+
1067
+ Returns
1068
+ -------
1069
+ pd.DataFrame
1070
+
1071
+ Raises
1072
+ ------
1073
+ FileNotFoundError
1074
+ If the metrics file does not exist.
1075
+ """
1076
+ # Create the infographic path
1077
+ metrics_path = self.database.scenarios.output_path.joinpath(
1078
+ name,
1079
+ f"Infometrics_{name}.csv",
1080
+ )
1081
+
1082
+ # Check if the file exists
1083
+ if not metrics_path.exists():
1084
+ raise FileNotFoundError(
1085
+ f"The metrics file for scenario {name}({str(metrics_path)}) does not exist."
1086
+ )
1087
+
1088
+ # Read the metrics file
1089
+ return MetricsFileReader(str(metrics_path)).read_metrics_from_file(
1090
+ include_long_names=True,
1091
+ include_description=True,
1092
+ include_metrics_table_selection=True,
1093
+ )
1094
+
1095
+ # Static
1096
+ @staticmethod
1097
+ def read_database(
1098
+ database_path: Union[str, os.PathLike], site_name: str
1099
+ ) -> Database:
1100
+ """Given a path and a site name returns a IDatabase object.
1101
+
1102
+ Parameters
1103
+ ----------
1104
+ database_path : Union[str, os.PathLike]
1105
+ path to database
1106
+ site_name : str
1107
+ name of the site
1108
+
1109
+ Returns
1110
+ -------
1111
+ IDatabase
1112
+ """
1113
+ return Database(database_path, site_name)
1114
+
1115
+ def get_aggregation_areas(
1116
+ self,
1117
+ ) -> dict[str, gpd.GeoDataFrame]:
1118
+ """Get a list of the aggregation areas that are provided in the site configuration.
1119
+
1120
+ These are expected to much the ones in the FIAT model.
1121
+
1122
+ Returns
1123
+ -------
1124
+ dict[str, GeoDataFrame]
1125
+ list of geodataframes with the polygons defining the aggregation areas
1126
+ """
1127
+ return self.database.static.get_aggregation_areas()
1128
+
1129
+ def get_obs_points(
1130
+ self,
1131
+ ) -> gpd.GeoDataFrame:
1132
+ """Get the observation points specified in the site.toml.
1133
+
1134
+ These are also added to the flood hazard model. They are used as marker locations to plot water level time series in the output tab.
1135
+
1136
+ Returns
1137
+ -------
1138
+ gpd.GeoDataFrame
1139
+ gpd.GeoDataFrame with observation points from the site.toml.
1140
+ """
1141
+ return self.database.static.get_obs_points()
1142
+
1143
+ def get_model_boundary(
1144
+ self,
1145
+ ) -> gpd.GeoDataFrame:
1146
+ """Get the model boundary that is used in SFINCS.
1147
+
1148
+ Returns
1149
+ -------
1150
+ GeoDataFrame
1151
+ GeoDataFrame with the model boundary
1152
+ """
1153
+ return self.database.static.get_model_boundary()
1154
+
1155
+ def get_model_grid(
1156
+ self,
1157
+ ) -> QuadtreeGrid:
1158
+ """Get the model grid that is used in SFINCS.
1159
+
1160
+ Returns
1161
+ -------
1162
+ QuadtreeGrid
1163
+ QuadtreeGrid with the model grid
1164
+ """
1165
+ return self.database.static.get_model_grid()
1166
+
1167
+ def get_svi_map(
1168
+ self,
1169
+ ) -> Union[gpd.GeoDataFrame, None]:
1170
+ """Get the SVI map that are used in Fiat.
1171
+
1172
+ Returns
1173
+ -------
1174
+ gpd.GeoDataFrame
1175
+ gpd.GeoDataFrames with the SVI map, None if not available
1176
+ """
1177
+ if self.database.site.fiat.config.svi:
1178
+ return self.database.static.get_static_map(
1179
+ self.database.site.fiat.config.svi.geom
1180
+ )
1181
+ else:
1182
+ return None
1183
+
1184
+ def get_static_map(self, path: Union[str, Path]) -> Union[gpd.GeoDataFrame, None]:
1185
+ """Get a static map from the database.
1186
+
1187
+ Parameters
1188
+ ----------
1189
+ path : Union[str, Path]
1190
+ path to the static map
1191
+
1192
+ Returns
1193
+ -------
1194
+ gpd.gpd.GeoDataFrame
1195
+ gpd.GeoDataFrame with the static map
1196
+ """
1197
+ try:
1198
+ return self.database.static.get_static_map(path)
1199
+ except Exception:
1200
+ return None
1201
+
1202
+ def get_buildings(self) -> gpd.GeoDataFrame:
1203
+ """Get the buildings exposure that are used in Fiat.
1204
+
1205
+ Returns
1206
+ -------
1207
+ gpd.GeoDataFrame
1208
+ gpd.GeoDataFrames with the buildings from FIAT exposure
1209
+ """
1210
+ return self.database.static.get_buildings()
1211
+
1212
+ def get_property_types(self) -> list:
1213
+ """Get the property types that are used in the exposure.
1214
+
1215
+ Returns
1216
+ -------
1217
+ list
1218
+ list of property types
1219
+ """
1220
+ return self.database.static.get_property_types()
1221
+
1222
+ def get_hazard_measure_types(self):
1223
+ """Get list of all implemented hazard measure types."""
1224
+ raise NotImplementedError
1225
+
1226
+ def get_impact_measure_types(self):
1227
+ """Get list of all implemented impact measure types."""
1228
+ raise NotImplementedError
1229
+
1230
+ def get_event_templates(self):
1231
+ """Get list of all implemented event templates."""
1232
+ raise NotImplementedError
1233
+
1234
+ # Benefits
1235
+ def get_benefits(self) -> dict[str, Any]:
1236
+ """Get all benefits from the database.
1237
+
1238
+ Returns
1239
+ -------
1240
+ dict[str, Any]
1241
+ A dictionary containing all benefits.
1242
+ Includes keys: 'name', 'description', 'path', 'last_modification_date', 'objects'
1243
+ Each value is a list of the corresponding attribute for each benefit.
1244
+ """
1245
+ # sorting and filtering either with PyQt table or in the API
1246
+ return self.database.benefits.list_objects()
1247
+
1248
+ def get_benefit(self, name: str) -> Benefit:
1249
+ """Get a benefit from the database by name.
1250
+
1251
+ Parameters
1252
+ ----------
1253
+ name : str
1254
+ The name of the benefit to retrieve.
1255
+
1256
+ Returns
1257
+ -------
1258
+ Benefit
1259
+ The benefit object with the given name. See [Benefit](/api_ref/) for details.
1260
+
1261
+ Raises
1262
+ ------
1263
+ ValueError
1264
+ If the benefit with the given name does not exist.
1265
+ """
1266
+ return self.database.benefits.get(name)
1267
+
1268
+ def create_benefit(self, attrs: dict[str, Any]) -> Benefit:
1269
+ """Create a new benefit object.
1270
+
1271
+ Parameters
1272
+ ----------
1273
+ attrs : dict[str, Any]
1274
+ The attributes of the benefit object to create. Should adhere to the Benefit schema.
1275
+ """
1276
+ return Benefit(**attrs)
1277
+
1278
+ def save_benefit(self, benefit: Benefit) -> None:
1279
+ """Save a benefit object to the database.
1280
+
1281
+ Parameters
1282
+ ----------
1283
+ benefit : Benefit
1284
+ The benefit object to save.
1285
+
1286
+ Raises
1287
+ ------
1288
+ ValueError
1289
+ If the benefit object is not valid.
1290
+ """
1291
+ self.database.benefits.save(benefit)
1292
+
1293
+ def edit_benefit(self, benefit: Benefit) -> None:
1294
+ """Edit a benefit object in the database.
1295
+
1296
+ Parameters
1297
+ ----------
1298
+ benefit : Benefit
1299
+ The benefit object to edit.
1300
+
1301
+ Raises
1302
+ ------
1303
+ ValueError
1304
+ If the benefit object does not exist.
1305
+ """
1306
+ self.database.benefits.edit(benefit)
1307
+
1308
+ def delete_benefit(self, name: str) -> None:
1309
+ """Delete a benefit object from the database.
1310
+
1311
+ Parameters
1312
+ ----------
1313
+ name : str
1314
+ The name of the benefit object to delete.
1315
+
1316
+ Raises
1317
+ ------
1318
+ ValueError
1319
+ If the benefit object does not exist.
1320
+ """
1321
+ self.database.benefits.delete(name)
1322
+
1323
+ def check_benefit_scenarios(self, benefit: Benefit) -> pd.DataFrame:
1324
+ """Return a dataframe with the scenarios needed for this benefit assessment run.
1325
+
1326
+ Parameters
1327
+ ----------
1328
+ benefit : Benefit
1329
+ The benefit object to check.
1330
+
1331
+ Returns
1332
+ -------
1333
+ pd.DataFrame
1334
+ A dataframe with the scenarios needed for this benefit assessment run.
1335
+ """
1336
+ return self.database.check_benefit_scenarios(benefit)
1337
+
1338
+ def create_benefit_scenarios(self, benefit: Benefit):
1339
+ """Create the benefit scenarios.
1340
+
1341
+ Parameters
1342
+ ----------
1343
+ benefit : Benefit
1344
+ The benefit object to create scenarios for.
1345
+ """
1346
+ self.database.create_benefit_scenarios(benefit)
1347
+
1348
+ def run_benefit(self, name: Union[str, list[str]]) -> None:
1349
+ """Run the benefit assessment.
1350
+
1351
+ Parameters
1352
+ ----------
1353
+ name : Union[str, list[str]]
1354
+ The name of the benefit object to run.
1355
+ """
1356
+ self.database.run_benefit(name)
1357
+
1358
+ def get_aggregation_benefits(self, name: str) -> dict[str, gpd.GeoDataFrame]:
1359
+ """Get the aggregation benefits for a benefit assessment.
1360
+
1361
+ Parameters
1362
+ ----------
1363
+ name : str
1364
+ The name of the benefit assessment.
1365
+
1366
+ Returns
1367
+ -------
1368
+ gpd.GeoDataFrame
1369
+ The aggregation benefits for the benefit assessment.
1370
+ """
1371
+ return self.database.get_aggregation_benefits(name)