flood-adapt 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. flood_adapt/__init__.py +22 -0
  2. flood_adapt/adapter/__init__.py +9 -0
  3. flood_adapt/adapter/fiat_adapter.py +1502 -0
  4. flood_adapt/adapter/interface/__init__.py +0 -0
  5. flood_adapt/adapter/interface/hazard_adapter.py +70 -0
  6. flood_adapt/adapter/interface/impact_adapter.py +36 -0
  7. flood_adapt/adapter/interface/model_adapter.py +89 -0
  8. flood_adapt/adapter/interface/offshore.py +19 -0
  9. flood_adapt/adapter/sfincs_adapter.py +1857 -0
  10. flood_adapt/adapter/sfincs_offshore.py +193 -0
  11. flood_adapt/config/__init__.py +0 -0
  12. flood_adapt/config/config.py +245 -0
  13. flood_adapt/config/fiat.py +219 -0
  14. flood_adapt/config/gui.py +224 -0
  15. flood_adapt/config/sfincs.py +336 -0
  16. flood_adapt/config/site.py +124 -0
  17. flood_adapt/database_builder/__init__.py +0 -0
  18. flood_adapt/database_builder/database_builder.py +2175 -0
  19. flood_adapt/database_builder/templates/default_units/imperial.toml +9 -0
  20. flood_adapt/database_builder/templates/default_units/metric.toml +9 -0
  21. flood_adapt/database_builder/templates/green_infra_table/green_infra_lookup_table.csv +10 -0
  22. flood_adapt/database_builder/templates/icons/black_down_48x48.png +0 -0
  23. flood_adapt/database_builder/templates/icons/black_left_48x48.png +0 -0
  24. flood_adapt/database_builder/templates/icons/black_right_48x48.png +0 -0
  25. flood_adapt/database_builder/templates/icons/black_up_48x48.png +0 -0
  26. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-16_white_down.png +0 -0
  27. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-16_white_left.png +0 -0
  28. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-16_white_right.png +0 -0
  29. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-16_white_up.png +0 -0
  30. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_black_down.png +0 -0
  31. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_black_left.png +0 -0
  32. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_black_right.png +0 -0
  33. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_black_up.png +0 -0
  34. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_white_left.png +0 -0
  35. flood_adapt/database_builder/templates/icons/icons8-triangle-arrow-24_white_right.png +0 -0
  36. flood_adapt/database_builder/templates/icons/white_down_48x48.png +0 -0
  37. flood_adapt/database_builder/templates/icons/white_left_48x48.png +0 -0
  38. flood_adapt/database_builder/templates/icons/white_right_48x48.png +0 -0
  39. flood_adapt/database_builder/templates/icons/white_up_48x48.png +0 -0
  40. flood_adapt/database_builder/templates/infographics/OSM/config_charts.toml +90 -0
  41. flood_adapt/database_builder/templates/infographics/OSM/config_people.toml +57 -0
  42. flood_adapt/database_builder/templates/infographics/OSM/config_risk_charts.toml +121 -0
  43. flood_adapt/database_builder/templates/infographics/OSM/config_roads.toml +65 -0
  44. flood_adapt/database_builder/templates/infographics/OSM/styles.css +45 -0
  45. flood_adapt/database_builder/templates/infographics/US_NSI/config_charts.toml +126 -0
  46. flood_adapt/database_builder/templates/infographics/US_NSI/config_people.toml +60 -0
  47. flood_adapt/database_builder/templates/infographics/US_NSI/config_risk_charts.toml +121 -0
  48. flood_adapt/database_builder/templates/infographics/US_NSI/config_roads.toml +65 -0
  49. flood_adapt/database_builder/templates/infographics/US_NSI/styles.css +45 -0
  50. flood_adapt/database_builder/templates/infographics/images/ambulance.png +0 -0
  51. flood_adapt/database_builder/templates/infographics/images/car.png +0 -0
  52. flood_adapt/database_builder/templates/infographics/images/cart.png +0 -0
  53. flood_adapt/database_builder/templates/infographics/images/firetruck.png +0 -0
  54. flood_adapt/database_builder/templates/infographics/images/hospital.png +0 -0
  55. flood_adapt/database_builder/templates/infographics/images/house.png +0 -0
  56. flood_adapt/database_builder/templates/infographics/images/info.png +0 -0
  57. flood_adapt/database_builder/templates/infographics/images/money.png +0 -0
  58. flood_adapt/database_builder/templates/infographics/images/person.png +0 -0
  59. flood_adapt/database_builder/templates/infographics/images/school.png +0 -0
  60. flood_adapt/database_builder/templates/infographics/images/truck.png +0 -0
  61. flood_adapt/database_builder/templates/infographics/images/walking_person.png +0 -0
  62. flood_adapt/database_builder/templates/infometrics/OSM/metrics_additional_risk_configs.toml +4 -0
  63. flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config.toml +143 -0
  64. flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config_risk.toml +153 -0
  65. flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config.toml +127 -0
  66. flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config_risk.toml +57 -0
  67. flood_adapt/database_builder/templates/infometrics/US_NSI/metrics_additional_risk_configs.toml +4 -0
  68. flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config.toml +191 -0
  69. flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config_risk.toml +153 -0
  70. flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config.toml +178 -0
  71. flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config_risk.toml +57 -0
  72. flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config.toml +9 -0
  73. flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config_risk.toml +65 -0
  74. flood_adapt/database_builder/templates/mapbox_layers/bin_colors.toml +5 -0
  75. flood_adapt/database_builder.py +16 -0
  76. flood_adapt/dbs_classes/__init__.py +21 -0
  77. flood_adapt/dbs_classes/database.py +716 -0
  78. flood_adapt/dbs_classes/dbs_benefit.py +97 -0
  79. flood_adapt/dbs_classes/dbs_event.py +91 -0
  80. flood_adapt/dbs_classes/dbs_measure.py +103 -0
  81. flood_adapt/dbs_classes/dbs_projection.py +52 -0
  82. flood_adapt/dbs_classes/dbs_scenario.py +150 -0
  83. flood_adapt/dbs_classes/dbs_static.py +261 -0
  84. flood_adapt/dbs_classes/dbs_strategy.py +147 -0
  85. flood_adapt/dbs_classes/dbs_template.py +302 -0
  86. flood_adapt/dbs_classes/interface/database.py +147 -0
  87. flood_adapt/dbs_classes/interface/element.py +137 -0
  88. flood_adapt/dbs_classes/interface/static.py +47 -0
  89. flood_adapt/flood_adapt.py +1371 -0
  90. flood_adapt/misc/__init__.py +0 -0
  91. flood_adapt/misc/database_user.py +16 -0
  92. flood_adapt/misc/log.py +183 -0
  93. flood_adapt/misc/path_builder.py +54 -0
  94. flood_adapt/misc/utils.py +185 -0
  95. flood_adapt/objects/__init__.py +59 -0
  96. flood_adapt/objects/benefits/__init__.py +0 -0
  97. flood_adapt/objects/benefits/benefits.py +61 -0
  98. flood_adapt/objects/events/__init__.py +0 -0
  99. flood_adapt/objects/events/event_factory.py +135 -0
  100. flood_adapt/objects/events/event_set.py +84 -0
  101. flood_adapt/objects/events/events.py +221 -0
  102. flood_adapt/objects/events/historical.py +55 -0
  103. flood_adapt/objects/events/hurricane.py +64 -0
  104. flood_adapt/objects/events/synthetic.py +48 -0
  105. flood_adapt/objects/forcing/__init__.py +0 -0
  106. flood_adapt/objects/forcing/csv.py +68 -0
  107. flood_adapt/objects/forcing/discharge.py +66 -0
  108. flood_adapt/objects/forcing/forcing.py +142 -0
  109. flood_adapt/objects/forcing/forcing_factory.py +182 -0
  110. flood_adapt/objects/forcing/meteo_handler.py +93 -0
  111. flood_adapt/objects/forcing/netcdf.py +40 -0
  112. flood_adapt/objects/forcing/plotting.py +428 -0
  113. flood_adapt/objects/forcing/rainfall.py +98 -0
  114. flood_adapt/objects/forcing/tide_gauge.py +191 -0
  115. flood_adapt/objects/forcing/time_frame.py +77 -0
  116. flood_adapt/objects/forcing/timeseries.py +552 -0
  117. flood_adapt/objects/forcing/unit_system.py +580 -0
  118. flood_adapt/objects/forcing/waterlevels.py +108 -0
  119. flood_adapt/objects/forcing/wind.py +124 -0
  120. flood_adapt/objects/measures/__init__.py +0 -0
  121. flood_adapt/objects/measures/measure_factory.py +92 -0
  122. flood_adapt/objects/measures/measures.py +506 -0
  123. flood_adapt/objects/object_model.py +68 -0
  124. flood_adapt/objects/projections/__init__.py +0 -0
  125. flood_adapt/objects/projections/projections.py +89 -0
  126. flood_adapt/objects/scenarios/__init__.py +0 -0
  127. flood_adapt/objects/scenarios/scenarios.py +22 -0
  128. flood_adapt/objects/strategies/__init__.py +0 -0
  129. flood_adapt/objects/strategies/strategies.py +68 -0
  130. flood_adapt/workflows/__init__.py +0 -0
  131. flood_adapt/workflows/benefit_runner.py +541 -0
  132. flood_adapt/workflows/floodmap.py +85 -0
  133. flood_adapt/workflows/impacts_integrator.py +82 -0
  134. flood_adapt/workflows/scenario_runner.py +69 -0
  135. flood_adapt-0.3.0.dist-info/LICENSE +21 -0
  136. flood_adapt-0.3.0.dist-info/METADATA +183 -0
  137. flood_adapt-0.3.0.dist-info/RECORD +139 -0
  138. flood_adapt-0.3.0.dist-info/WHEEL +5 -0
  139. flood_adapt-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,191 @@
1
+ from enum import Enum
2
+ from pathlib import Path
3
+ from typing import ClassVar, Optional
4
+
5
+ import cht_observations.observation_stations as cht_station
6
+ import pandas as pd
7
+ from noaa_coops.station import COOPSAPIError
8
+ from pydantic import BaseModel, model_validator
9
+
10
+ from flood_adapt.misc.log import FloodAdaptLogging
11
+ from flood_adapt.objects.forcing import unit_system as us
12
+ from flood_adapt.objects.forcing.time_frame import TimeFrame
13
+ from flood_adapt.objects.forcing.timeseries import CSVTimeseries
14
+
15
+
16
+ class TideGaugeSource(str, Enum):
17
+ """The accepted input for the variable source in tide_gauge."""
18
+
19
+ file = "file"
20
+ noaa_coops = "noaa_coops"
21
+
22
+
23
+ class TideGauge(BaseModel):
24
+ """The accepted input for the variable tide_gauge in Site.
25
+
26
+ The obs_station is used for the download of tide gauge data, to be added to the hazard model as water level boundary condition.
27
+
28
+ Attributes
29
+ ----------
30
+ name : Optional[int | str], default=None
31
+ Name of the tide gauge.
32
+ description : Optional[str], default=""
33
+ Description of the tide gauge.
34
+ source : TideGaugeSource
35
+ Source of the tide gauge data.
36
+ reference : str
37
+ Reference of the tide gauge data. Should be defined in site.sfincs.water_level
38
+ ID : Optional[int], default=None
39
+ ID of the tide gauge data.
40
+ file : Optional[Path], default=None
41
+ Only for file based tide gauges. Should be a path relative to the static folder.
42
+ lat : Optional[float], default=None
43
+ Latitude of the tide gauge data.
44
+ lon : Optional[float], default=None
45
+ Longitude of the tide gauge data.
46
+ units : us.UnitTypesLength, default=us.UnitTypesLength.meters
47
+ Units of the water levels in the downloaded file.
48
+
49
+ """
50
+
51
+ name: Optional[int | str] = None
52
+ description: Optional[str] = ""
53
+ source: TideGaugeSource
54
+ reference: str
55
+ ID: Optional[int] = None # Attribute used to download from correct gauge
56
+ file: Optional[Path] = None # for locally stored data
57
+ lat: Optional[float] = None
58
+ lon: Optional[float] = None
59
+ units: us.UnitTypesLength = (
60
+ us.UnitTypesLength.meters
61
+ ) # units of the water levels in the downloaded file
62
+
63
+ _cached_data: ClassVar[dict[str, pd.DataFrame]] = {}
64
+ logger: ClassVar = FloodAdaptLogging.getLogger("TideGauge")
65
+
66
+ @model_validator(mode="after")
67
+ def validate_selection_type(self) -> "TideGauge":
68
+ if self.source == TideGaugeSource.file and self.file is None:
69
+ raise ValueError(
70
+ "If `source` is 'file' a file path relative to the static folder should be provided with the attribute 'file'."
71
+ )
72
+ elif self.source == TideGaugeSource.noaa_coops and self.ID is None:
73
+ raise ValueError(
74
+ "If `source` is 'noaa_coops' the id of the station should be provided with the attribute 'ID'."
75
+ )
76
+
77
+ return self
78
+
79
+ def get_waterlevels_in_time_frame(
80
+ self,
81
+ time: TimeFrame,
82
+ out_path: Optional[Path] = None,
83
+ units: us.UnitTypesLength = us.UnitTypesLength.meters,
84
+ ) -> pd.DataFrame:
85
+ """Download waterlevel data from NOAA station using station_id, start and stop time.
86
+
87
+ Parameters
88
+ ----------
89
+ time : TimeFrame
90
+ Time model with start and end time.
91
+ tide_gauge : TideGauge
92
+ Tide gauge model.
93
+ out_path : Optional[Path], optional
94
+ Path to save the data, by default None.
95
+ units : us.UnitTypesLength, optional
96
+ Unit of the waterlevel, by default us.UnitTypesLength.meters.
97
+
98
+ Returns
99
+ -------
100
+ pd.DataFrame
101
+ Dataframe with time as index and the waterlevel for each observation station as columns.
102
+ """
103
+ self.logger.info(f"Retrieving waterlevels for tide gauge {self.ID} for {time}")
104
+ if self.file:
105
+ gauge_data = self._read_imported_waterlevels(time=time, path=self.file)
106
+ else:
107
+ gauge_data = self._download_tide_gauge_data(time=time)
108
+
109
+ if gauge_data is None:
110
+ self.logger.warning(
111
+ f"Could not retrieve waterlevels for tide gauge {self.ID}"
112
+ )
113
+ return pd.DataFrame()
114
+
115
+ gauge_data.columns = [f"waterlevel_{self.ID}"]
116
+ gauge_data = gauge_data * us.UnitfulLength(value=1.0, units=self.units).convert(
117
+ units
118
+ )
119
+
120
+ if out_path is not None:
121
+ Path(out_path).parent.mkdir(parents=True, exist_ok=True)
122
+ gauge_data.to_csv(Path(out_path))
123
+ return gauge_data
124
+
125
+ def _read_imported_waterlevels(self, time: TimeFrame, path: Path) -> pd.DataFrame:
126
+ """Read waterlevels from an imported csv file.
127
+
128
+ Parameters
129
+ ----------
130
+ path : Path
131
+ Path to the csv file containing the waterlevel data. The csv file should have a column with the waterlevel data and a column with the time data.
132
+
133
+ Returns
134
+ -------
135
+ pd.DataFrame
136
+ Dataframe with time as index and the waterlevel for each observation station as columns.
137
+ The data is sliced to the time range specified in the time model.
138
+ """
139
+ return CSVTimeseries.load_file(
140
+ path=path, units=us.UnitfulLength(value=0, units=self.units)
141
+ ).to_dataframe(time_frame=time)
142
+
143
+ def _download_tide_gauge_data(self, time: TimeFrame) -> pd.DataFrame | None:
144
+ """Download waterlevel data from NOAA station using station_id, start and stop time.
145
+
146
+ Parameters
147
+ ----------
148
+ obs_point : ObsPointModel
149
+ Observation point model.
150
+ source : str
151
+ Source of the data.
152
+
153
+ Returns
154
+ -------
155
+ pd.DataFrame
156
+ Dataframe with time as index and the waterlevel of the observation station as the column.
157
+ None
158
+ If the data could not be downloaded.
159
+ """
160
+ cache_key = f"{self.ID}_{time.start_time}_{time.end_time}"
161
+ if cache_key in self.__class__._cached_data:
162
+ self.logger.info("Tide gauge data retrieved from cache")
163
+ return self.__class__._cached_data[cache_key]
164
+
165
+ try:
166
+ source_obj = cht_station.source(self.source.value)
167
+ series = source_obj.get_data(
168
+ id=self.ID,
169
+ tstart=time.start_time,
170
+ tstop=time.end_time,
171
+ datum=self.reference,
172
+ )
173
+ index = pd.date_range(
174
+ start=time.start_time,
175
+ end=time.end_time,
176
+ freq=time.time_step,
177
+ name="time",
178
+ )
179
+ series = series.reindex(index, method="nearest")
180
+ df = pd.DataFrame(data=series, index=index)
181
+
182
+ except COOPSAPIError as e:
183
+ self.logger.error(
184
+ f"Could not download tide gauge data for station {self.ID}. {e}"
185
+ )
186
+ return None
187
+
188
+ # Cache the result
189
+ self.__class__._cached_data[cache_key] = df
190
+
191
+ return df
@@ -0,0 +1,77 @@
1
+ from datetime import datetime, timedelta
2
+
3
+ from pydantic import (
4
+ BaseModel,
5
+ field_validator,
6
+ model_validator,
7
+ )
8
+
9
+ from flood_adapt.objects.forcing import unit_system as us
10
+
11
+ REFERENCE_TIME = datetime(year=2021, month=1, day=1, hour=0, minute=0, second=0)
12
+
13
+
14
+ class TimeFrame(BaseModel):
15
+ start_time: datetime = REFERENCE_TIME
16
+ end_time: datetime = REFERENCE_TIME + timedelta(days=1)
17
+
18
+ @property
19
+ def time_step(self) -> timedelta:
20
+ return self._time_step
21
+
22
+ @field_validator("start_time", "end_time", mode="before")
23
+ @classmethod
24
+ def try_parse_datetime(cls, value: str | datetime) -> datetime:
25
+ SUPPORTED_DATETIME_FORMATS = [
26
+ "%Y%m%d %H%M%S",
27
+ "%Y-%m-%d %H:%M:%S",
28
+ "%Y-%m-%d %H:%M:%S.%f",
29
+ "%Y-%m-%d %H:%M:%S.%f%z",
30
+ ]
31
+ if not isinstance(value, datetime):
32
+ for fmt in SUPPORTED_DATETIME_FORMATS:
33
+ try:
34
+ value = datetime.strptime(value, fmt)
35
+ break
36
+ except Exception:
37
+ pass
38
+
39
+ if not isinstance(value, datetime):
40
+ raise ValueError(
41
+ f"Could not parse start time: {value}. Supported formats are {', '.join(SUPPORTED_DATETIME_FORMATS)}"
42
+ )
43
+ return value
44
+
45
+ @model_validator(mode="after")
46
+ def start_time_before_end_time(self):
47
+ if self.start_time >= self.end_time:
48
+ raise ValueError(
49
+ f"Start time: {self.start_time} must be before end time: {self.end_time}"
50
+ )
51
+ return self
52
+
53
+ @model_validator(mode="after")
54
+ def dynamic_timestep(self):
55
+ num_intervals = 1000
56
+ time_span = (self.end_time - self.start_time).total_seconds()
57
+
58
+ # Round the time step to the second for simplicity
59
+ self._time_step = timedelta(
60
+ seconds=int(timedelta(seconds=time_span / num_intervals).total_seconds())
61
+ )
62
+ return self
63
+
64
+ @property
65
+ def duration(self) -> timedelta:
66
+ return self.end_time - self.start_time
67
+
68
+ def duration_as_unitfultime(
69
+ self, unit: us.UnitTypesTime = us.UnitTypesTime.hours
70
+ ) -> us.UnitfulTime:
71
+ return us.UnitfulTime(
72
+ value=(self.duration).total_seconds(),
73
+ units=us.UnitTypesTime.seconds,
74
+ ).transform(unit)
75
+
76
+ def __str__(self) -> str:
77
+ return f"{self.start_time} - {self.end_time}"