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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 -1536
  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 -1846
  9. flood_adapt/adapter/sfincs_offshore.py +193 -193
  10. flood_adapt/config/config.py +248 -290
  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 -688
  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 -89
  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 -544
  92. flood_adapt/workflows/floodmap.py +85 -85
  93. flood_adapt/workflows/impacts_integrator.py +85 -82
  94. flood_adapt/workflows/scenario_runner.py +70 -70
  95. {flood_adapt-0.3.8.dist-info → flood_adapt-0.3.10.dist-info}/LICENSE +674 -674
  96. {flood_adapt-0.3.8.dist-info → flood_adapt-0.3.10.dist-info}/METADATA +866 -860
  97. flood_adapt-0.3.10.dist-info/RECORD +140 -0
  98. flood_adapt-0.3.8.dist-info/RECORD +0 -139
  99. {flood_adapt-0.3.8.dist-info → flood_adapt-0.3.10.dist-info}/WHEEL +0 -0
  100. {flood_adapt-0.3.8.dist-info → flood_adapt-0.3.10.dist-info}/top_level.txt +0 -0
@@ -1,85 +1,85 @@
1
- import os
2
- from pathlib import Path
3
-
4
- from flood_adapt.config.sfincs import FloodmapType
5
- from flood_adapt.misc.database_user import DatabaseUser
6
- from flood_adapt.misc.log import FloodAdaptLogging
7
- from flood_adapt.objects.events.event_set import EventSet
8
- from flood_adapt.objects.events.events import Mode
9
- from flood_adapt.objects.strategies.strategies import Strategy
10
-
11
-
12
- class FloodMap(DatabaseUser):
13
- logger = FloodAdaptLogging.getLogger("FloodMap")
14
-
15
- type: FloodmapType
16
-
17
- name: str
18
- path: Path | os.PathLike | list[Path | os.PathLike]
19
- event_set: EventSet
20
-
21
- def __init__(self, scenario_name: str) -> None:
22
- self.name = scenario_name
23
- self.type = self.database.site.fiat.config.floodmap_type
24
- self._get_flood_map_paths()
25
-
26
- def _get_flood_map_paths(self):
27
- base_dir = self.database.scenarios.output_path / self.name / "Flooding"
28
- # TODO check naming of files
29
- if self.mode == Mode.single_event:
30
- if self.type == FloodmapType.water_level:
31
- self.path = base_dir / "max_water_level_map.nc"
32
- elif self.type == FloodmapType.water_depth:
33
- self.path = base_dir / f"FloodMap_{self.name}.tif"
34
- elif self.mode == Mode.risk:
35
- if self.type == FloodmapType.water_level:
36
- self.path = list(base_dir.glob("RP_*_maps.nc"))
37
- elif self.type == FloodmapType.water_depth:
38
- self.path = list(base_dir.glob("RP_*_maps.tif"))
39
-
40
- @property
41
- def has_run(self) -> bool:
42
- if self.mode == Mode.single_event:
43
- return self.path.exists()
44
- elif self.mode == Mode.risk:
45
- check_files = [RP_map.exists() for RP_map in self.path]
46
- check_rps = len(self.path) == len(
47
- self.database.site.fiat.risk.return_periods
48
- )
49
- return all(check_files) & check_rps
50
-
51
- @property
52
- def scenario(self):
53
- if hasattr(self, "_scenario"):
54
- return self._scenario
55
- self._scenario = self.database.scenarios.get(self.name)
56
- return self._scenario
57
-
58
- @property
59
- def mode(self):
60
- if hasattr(self, "_mode"):
61
- return self._mode
62
- self._mode = self.database.events.get(self.scenario.event).mode
63
- return self._mode
64
-
65
- @property
66
- def crs(self):
67
- if hasattr(self, "_crs"):
68
- return self._crs
69
- self._crs = self.database.site.crs
70
- return self._crs
71
-
72
- @property
73
- def hazard_strategy(self) -> Strategy:
74
- return self.database.strategies.get(
75
- self.scenario.strategy
76
- ).get_hazard_strategy()
77
-
78
- @property
79
- def physical_projection(self):
80
- if hasattr(self, "_physical_projection"):
81
- return self._physical_projection
82
- self._physical_projection = self.database.projections.get(
83
- self.scenario.projection
84
- ).physical_projection
85
- return self._physical_projection
1
+ import os
2
+ from pathlib import Path
3
+
4
+ from flood_adapt.config.sfincs import FloodmapType
5
+ from flood_adapt.misc.database_user import DatabaseUser
6
+ from flood_adapt.misc.log import FloodAdaptLogging
7
+ from flood_adapt.objects.events.event_set import EventSet
8
+ from flood_adapt.objects.events.events import Mode
9
+ from flood_adapt.objects.strategies.strategies import Strategy
10
+
11
+
12
+ class FloodMap(DatabaseUser):
13
+ logger = FloodAdaptLogging.getLogger("FloodMap")
14
+
15
+ type: FloodmapType
16
+
17
+ name: str
18
+ path: Path | os.PathLike | list[Path | os.PathLike]
19
+ event_set: EventSet
20
+
21
+ def __init__(self, scenario_name: str) -> None:
22
+ self.name = scenario_name
23
+ self.type = self.database.site.fiat.config.floodmap_type
24
+ self._get_flood_map_paths()
25
+
26
+ def _get_flood_map_paths(self):
27
+ base_dir = self.database.scenarios.output_path / self.name / "Flooding"
28
+ # TODO check naming of files
29
+ if self.mode == Mode.single_event:
30
+ if self.type == FloodmapType.water_level:
31
+ self.path = base_dir / "max_water_level_map.nc"
32
+ elif self.type == FloodmapType.water_depth:
33
+ self.path = base_dir / f"FloodMap_{self.name}.tif"
34
+ elif self.mode == Mode.risk:
35
+ if self.type == FloodmapType.water_level:
36
+ self.path = list(base_dir.glob("RP_*_maps.nc"))
37
+ elif self.type == FloodmapType.water_depth:
38
+ self.path = list(base_dir.glob("RP_*_maps.tif"))
39
+
40
+ @property
41
+ def has_run(self) -> bool:
42
+ if self.mode == Mode.single_event:
43
+ return self.path.exists()
44
+ elif self.mode == Mode.risk:
45
+ check_files = [RP_map.exists() for RP_map in self.path]
46
+ check_rps = len(self.path) == len(
47
+ self.database.site.fiat.risk.return_periods
48
+ )
49
+ return all(check_files) & check_rps
50
+
51
+ @property
52
+ def scenario(self):
53
+ if hasattr(self, "_scenario"):
54
+ return self._scenario
55
+ self._scenario = self.database.scenarios.get(self.name)
56
+ return self._scenario
57
+
58
+ @property
59
+ def mode(self):
60
+ if hasattr(self, "_mode"):
61
+ return self._mode
62
+ self._mode = self.database.events.get(self.scenario.event).mode
63
+ return self._mode
64
+
65
+ @property
66
+ def crs(self):
67
+ if hasattr(self, "_crs"):
68
+ return self._crs
69
+ self._crs = self.database.site.crs
70
+ return self._crs
71
+
72
+ @property
73
+ def hazard_strategy(self) -> Strategy:
74
+ return self.database.strategies.get(
75
+ self.scenario.strategy
76
+ ).get_hazard_strategy()
77
+
78
+ @property
79
+ def physical_projection(self):
80
+ if hasattr(self, "_physical_projection"):
81
+ return self._physical_projection
82
+ self._physical_projection = self.database.projections.get(
83
+ self.scenario.projection
84
+ ).physical_projection
85
+ return self._physical_projection
@@ -1,82 +1,85 @@
1
- from pathlib import Path
2
-
3
- from flood_adapt.misc.database_user import DatabaseUser
4
- from flood_adapt.misc.log import FloodAdaptLogging
5
- from flood_adapt.misc.path_builder import (
6
- ObjectDir,
7
- TopLevelDir,
8
- db_path,
9
- )
10
- from flood_adapt.objects.projections.projections import SocioEconomicChange
11
- from flood_adapt.objects.scenarios.scenarios import Scenario
12
- from flood_adapt.objects.strategies.strategies import Strategy
13
- from flood_adapt.workflows.floodmap import FloodMap
14
-
15
-
16
- class Impacts(DatabaseUser):
17
- """All information related to the impacts of the scenario.
18
-
19
- Includes methods to run the impact models or check if they has already been run.
20
- """
21
-
22
- logger = FloodAdaptLogging.getLogger("Impacts")
23
- name: str
24
-
25
- def __init__(self, scenario: Scenario):
26
- self.name = scenario.name
27
- self.scenario = scenario
28
- self.site_info = self.database.site
29
- self.models = [
30
- self.database.static.get_fiat_model()
31
- ] # for now only FIAT adapter
32
-
33
- @property
34
- def hazard(self) -> FloodMap:
35
- return FloodMap(self.name)
36
-
37
- @property
38
- def socio_economic_change(self) -> SocioEconomicChange:
39
- return self.database.projections.get(
40
- self.scenario.projection
41
- ).socio_economic_change
42
-
43
- @property
44
- def impact_strategy(self) -> Strategy:
45
- return self.database.strategies.get(
46
- self.scenario.strategy
47
- ).get_impact_strategy()
48
-
49
- @property
50
- def results_path(self) -> Path:
51
- return db_path(
52
- TopLevelDir.output, object_dir=ObjectDir.scenario, obj_name=self.name
53
- )
54
-
55
- @property
56
- def impacts_path(self) -> Path:
57
- return self.results_path / "Impacts"
58
-
59
- @property
60
- def has_run(self) -> bool:
61
- return self.has_run_check()
62
-
63
- def run(self):
64
- """Run the impact model(s)."""
65
- if self.has_run:
66
- self.logger.info("Impacts have already been run.")
67
- return
68
- for model in self.models:
69
- model.run(self.scenario)
70
-
71
- def has_run_check(self) -> bool:
72
- """Check if the impact has been run.
73
-
74
- Returns
75
- -------
76
- bool
77
- _description_
78
- """
79
- checks = []
80
- for model in self.models:
81
- checks.append(model.has_run(self.scenario))
82
- return all(checks)
1
+ from pathlib import Path
2
+
3
+ from flood_adapt.misc.database_user import DatabaseUser
4
+ from flood_adapt.misc.log import FloodAdaptLogging
5
+ from flood_adapt.misc.path_builder import (
6
+ ObjectDir,
7
+ TopLevelDir,
8
+ db_path,
9
+ )
10
+ from flood_adapt.objects.projections.projections import SocioEconomicChange
11
+ from flood_adapt.objects.scenarios.scenarios import Scenario
12
+ from flood_adapt.objects.strategies.strategies import Strategy
13
+ from flood_adapt.workflows.floodmap import FloodMap
14
+
15
+
16
+ class Impacts(DatabaseUser):
17
+ """All information related to the impacts of the scenario.
18
+
19
+ Includes methods to run the impact models or check if they has already been run.
20
+ """
21
+
22
+ logger = FloodAdaptLogging.getLogger("Impacts")
23
+ name: str
24
+
25
+ def __init__(self, scenario: Scenario):
26
+ self.name = scenario.name
27
+ self.scenario = scenario
28
+ self.site_info = self.database.site
29
+
30
+ @property
31
+ def models(self):
32
+ """Return the list of impact models."""
33
+ models = [self.database.static.get_fiat_model()] # for now only FIAT adapter
34
+ return models
35
+
36
+ @property
37
+ def hazard(self) -> FloodMap:
38
+ return FloodMap(self.name)
39
+
40
+ @property
41
+ def socio_economic_change(self) -> SocioEconomicChange:
42
+ return self.database.projections.get(
43
+ self.scenario.projection
44
+ ).socio_economic_change
45
+
46
+ @property
47
+ def impact_strategy(self) -> Strategy:
48
+ return self.database.strategies.get(
49
+ self.scenario.strategy
50
+ ).get_impact_strategy()
51
+
52
+ @property
53
+ def results_path(self) -> Path:
54
+ return db_path(
55
+ TopLevelDir.output, object_dir=ObjectDir.scenario, obj_name=self.name
56
+ )
57
+
58
+ @property
59
+ def impacts_path(self) -> Path:
60
+ return self.results_path / "Impacts"
61
+
62
+ @property
63
+ def has_run(self) -> bool:
64
+ return self.has_run_check()
65
+
66
+ def run(self):
67
+ """Run the impact model(s)."""
68
+ if self.has_run:
69
+ self.logger.info("Impacts have already been run.")
70
+ return
71
+ for model in self.models:
72
+ model.run(self.scenario)
73
+
74
+ def has_run_check(self) -> bool:
75
+ """Check if the impact has been run.
76
+
77
+ Returns
78
+ -------
79
+ bool
80
+ _description_
81
+ """
82
+ checks = []
83
+ for model in self.models:
84
+ checks.append(model.has_run(self.scenario))
85
+ return all(checks)
@@ -1,70 +1,70 @@
1
- from flood_adapt import __version__
2
- from flood_adapt.dbs_classes.interface.database import IDatabase
3
- from flood_adapt.misc.log import FloodAdaptLogging
4
- from flood_adapt.misc.utils import finished_file_exists, write_finished_file
5
- from flood_adapt.objects.scenarios.scenarios import Scenario
6
- from flood_adapt.workflows.impacts_integrator import Impacts
7
-
8
-
9
- class ScenarioRunner:
10
- """class holding all information related to a scenario."""
11
-
12
- def __init__(self, database: IDatabase, scenario: Scenario) -> None:
13
- """Create a Scenario object."""
14
- self.logger = FloodAdaptLogging.getLogger("ScenarioRunner")
15
- self._database = database
16
- self._load_objects(scenario)
17
- self.site_info = self._database.site
18
- self.results_path = self._database.scenarios.output_path / self._scenario.name
19
-
20
- def _load_objects(self, scenario: Scenario) -> None:
21
- """Load objects from the database."""
22
- self._scenario = scenario
23
- self._event = self._database.events.get(scenario.event)
24
- self._projection = self._database.projections.get(scenario.projection)
25
- self._strategy = self._database.strategies.get(scenario.strategy)
26
-
27
- @property
28
- def impacts(self) -> Impacts:
29
- return Impacts(
30
- scenario=self._scenario,
31
- )
32
-
33
- def run(self) -> None:
34
- """Run hazard and impact models for the scenario."""
35
- self._database.has_run_hazard(self._scenario.name)
36
- self._load_objects(self._scenario)
37
- self.results_path.mkdir(parents=True, exist_ok=True)
38
-
39
- # Initiate the logger for all the integrator scripts.
40
- log_file = self.results_path.joinpath(f"logfile_{self._scenario.name}.log")
41
- with FloodAdaptLogging.to_file(file_path=log_file):
42
- self.logger.info(f"FloodAdapt version `{__version__}`")
43
- self.logger.info(f"Started evaluation of `{self._scenario.name}`")
44
-
45
- hazard_models = [
46
- self._database.static.get_overland_sfincs_model(),
47
- ]
48
- for hazard in hazard_models:
49
- if not hazard.run_completed(self._scenario):
50
- hazard.run(self._scenario)
51
- else:
52
- self.logger.info(
53
- f"Hazard for scenario '{self._scenario.name}' has already been run."
54
- )
55
-
56
- if not self.impacts.has_run:
57
- self.impacts.run()
58
- else:
59
- self.logger.info(
60
- f"Impacts for scenario `{self._scenario.name}` has already been run."
61
- )
62
-
63
- self.logger.info(f"Finished evaluation of `{self._scenario.name}`")
64
-
65
- # write finished file to indicate that the scenario has been run
66
- write_finished_file(self.results_path)
67
-
68
- def has_run_check(self):
69
- """Check if the scenario has been run."""
70
- return finished_file_exists(self.results_path)
1
+ from flood_adapt import __version__
2
+ from flood_adapt.dbs_classes.interface.database import IDatabase
3
+ from flood_adapt.misc.log import FloodAdaptLogging
4
+ from flood_adapt.misc.utils import finished_file_exists, write_finished_file
5
+ from flood_adapt.objects.scenarios.scenarios import Scenario
6
+ from flood_adapt.workflows.impacts_integrator import Impacts
7
+
8
+
9
+ class ScenarioRunner:
10
+ """class holding all information related to a scenario."""
11
+
12
+ def __init__(self, database: IDatabase, scenario: Scenario) -> None:
13
+ """Create a Scenario object."""
14
+ self.logger = FloodAdaptLogging.getLogger("ScenarioRunner")
15
+ self._database = database
16
+ self._load_objects(scenario)
17
+ self.site_info = self._database.site
18
+ self.results_path = self._database.scenarios.output_path / self._scenario.name
19
+
20
+ def _load_objects(self, scenario: Scenario) -> None:
21
+ """Load objects from the database."""
22
+ self._scenario = scenario
23
+ self._event = self._database.events.get(scenario.event)
24
+ self._projection = self._database.projections.get(scenario.projection)
25
+ self._strategy = self._database.strategies.get(scenario.strategy)
26
+
27
+ @property
28
+ def impacts(self) -> Impacts:
29
+ return Impacts(
30
+ scenario=self._scenario,
31
+ )
32
+
33
+ def run(self) -> None:
34
+ """Run hazard and impact models for the scenario."""
35
+ self._database.has_run_hazard(self._scenario.name)
36
+ self._load_objects(self._scenario)
37
+ self.results_path.mkdir(parents=True, exist_ok=True)
38
+
39
+ # Initiate the logger for all the integrator scripts.
40
+ log_file = self.results_path.joinpath(f"logfile_{self._scenario.name}.log")
41
+ with FloodAdaptLogging.to_file(file_path=log_file):
42
+ self.logger.info(f"FloodAdapt version `{__version__}`")
43
+ self.logger.info(f"Started evaluation of `{self._scenario.name}`")
44
+
45
+ hazard_models = [
46
+ self._database.static.get_overland_sfincs_model(),
47
+ ]
48
+ for hazard in hazard_models:
49
+ if not hazard.run_completed(self._scenario):
50
+ hazard.run(self._scenario)
51
+ else:
52
+ self.logger.info(
53
+ f"Hazard for scenario '{self._scenario.name}' has already been run."
54
+ )
55
+
56
+ if not self.impacts.has_run:
57
+ self.impacts.run()
58
+ else:
59
+ self.logger.info(
60
+ f"Impacts for scenario `{self._scenario.name}` has already been run."
61
+ )
62
+
63
+ self.logger.info(f"Finished evaluation of `{self._scenario.name}`")
64
+
65
+ # write finished file to indicate that the scenario has been run
66
+ write_finished_file(self.results_path)
67
+
68
+ def has_run_check(self):
69
+ """Check if the scenario has been run."""
70
+ return finished_file_exists(self.results_path)