flood-adapt 0.3.9__py3-none-any.whl → 0.3.10__py3-none-any.whl

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