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.
- flood_adapt/__init__.py +26 -22
- flood_adapt/adapter/__init__.py +9 -9
- flood_adapt/adapter/fiat_adapter.py +1541 -1541
- flood_adapt/adapter/interface/hazard_adapter.py +70 -70
- flood_adapt/adapter/interface/impact_adapter.py +36 -36
- flood_adapt/adapter/interface/model_adapter.py +89 -89
- flood_adapt/adapter/interface/offshore.py +19 -19
- flood_adapt/adapter/sfincs_adapter.py +1848 -1848
- flood_adapt/adapter/sfincs_offshore.py +193 -193
- flood_adapt/config/config.py +248 -248
- flood_adapt/config/fiat.py +219 -219
- flood_adapt/config/gui.py +331 -331
- flood_adapt/config/sfincs.py +481 -336
- flood_adapt/config/site.py +129 -129
- flood_adapt/database_builder/database_builder.py +2210 -2210
- flood_adapt/database_builder/templates/default_units/imperial.toml +9 -9
- flood_adapt/database_builder/templates/default_units/metric.toml +9 -9
- flood_adapt/database_builder/templates/green_infra_table/green_infra_lookup_table.csv +10 -10
- flood_adapt/database_builder/templates/infographics/OSM/config_charts.toml +90 -90
- flood_adapt/database_builder/templates/infographics/OSM/config_people.toml +57 -57
- flood_adapt/database_builder/templates/infographics/OSM/config_risk_charts.toml +121 -121
- flood_adapt/database_builder/templates/infographics/OSM/config_roads.toml +65 -65
- flood_adapt/database_builder/templates/infographics/OSM/styles.css +45 -45
- flood_adapt/database_builder/templates/infographics/US_NSI/config_charts.toml +126 -126
- flood_adapt/database_builder/templates/infographics/US_NSI/config_people.toml +60 -60
- flood_adapt/database_builder/templates/infographics/US_NSI/config_risk_charts.toml +121 -121
- flood_adapt/database_builder/templates/infographics/US_NSI/config_roads.toml +65 -65
- flood_adapt/database_builder/templates/infographics/US_NSI/styles.css +45 -45
- flood_adapt/database_builder/templates/infometrics/OSM/metrics_additional_risk_configs.toml +4 -4
- flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config.toml +143 -143
- flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config_risk.toml +153 -153
- flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config.toml +127 -127
- flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config_risk.toml +57 -57
- flood_adapt/database_builder/templates/infometrics/US_NSI/metrics_additional_risk_configs.toml +4 -4
- flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config.toml +191 -191
- flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config_risk.toml +153 -153
- flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config.toml +178 -178
- flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config_risk.toml +57 -57
- flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config.toml +9 -9
- flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config_risk.toml +65 -65
- flood_adapt/database_builder/templates/output_layers/bin_colors.toml +5 -5
- flood_adapt/database_builder.py +16 -16
- flood_adapt/dbs_classes/__init__.py +21 -21
- flood_adapt/dbs_classes/database.py +495 -684
- flood_adapt/dbs_classes/dbs_benefit.py +77 -76
- flood_adapt/dbs_classes/dbs_event.py +61 -59
- flood_adapt/dbs_classes/dbs_measure.py +112 -111
- flood_adapt/dbs_classes/dbs_projection.py +34 -34
- flood_adapt/dbs_classes/dbs_scenario.py +137 -137
- flood_adapt/dbs_classes/dbs_static.py +274 -273
- flood_adapt/dbs_classes/dbs_strategy.py +130 -129
- flood_adapt/dbs_classes/dbs_template.py +279 -278
- flood_adapt/dbs_classes/interface/database.py +107 -139
- flood_adapt/dbs_classes/interface/element.py +121 -121
- flood_adapt/dbs_classes/interface/static.py +47 -47
- flood_adapt/flood_adapt.py +1207 -1178
- flood_adapt/misc/database_user.py +16 -16
- flood_adapt/misc/exceptions.py +22 -0
- flood_adapt/misc/log.py +183 -183
- flood_adapt/misc/path_builder.py +54 -54
- flood_adapt/misc/utils.py +185 -185
- flood_adapt/objects/__init__.py +82 -82
- flood_adapt/objects/benefits/benefits.py +61 -61
- flood_adapt/objects/events/event_factory.py +135 -135
- flood_adapt/objects/events/event_set.py +88 -84
- flood_adapt/objects/events/events.py +234 -234
- flood_adapt/objects/events/historical.py +58 -58
- flood_adapt/objects/events/hurricane.py +68 -67
- flood_adapt/objects/events/synthetic.py +46 -50
- flood_adapt/objects/forcing/__init__.py +92 -92
- flood_adapt/objects/forcing/csv.py +68 -68
- flood_adapt/objects/forcing/discharge.py +66 -66
- flood_adapt/objects/forcing/forcing.py +150 -150
- flood_adapt/objects/forcing/forcing_factory.py +182 -182
- flood_adapt/objects/forcing/meteo_handler.py +93 -93
- flood_adapt/objects/forcing/netcdf.py +40 -40
- flood_adapt/objects/forcing/plotting.py +453 -429
- flood_adapt/objects/forcing/rainfall.py +98 -98
- flood_adapt/objects/forcing/tide_gauge.py +191 -191
- flood_adapt/objects/forcing/time_frame.py +90 -90
- flood_adapt/objects/forcing/timeseries.py +564 -564
- flood_adapt/objects/forcing/unit_system.py +580 -580
- flood_adapt/objects/forcing/waterlevels.py +108 -108
- flood_adapt/objects/forcing/wind.py +124 -124
- flood_adapt/objects/measures/measure_factory.py +92 -92
- flood_adapt/objects/measures/measures.py +529 -529
- flood_adapt/objects/object_model.py +74 -68
- flood_adapt/objects/projections/projections.py +103 -103
- flood_adapt/objects/scenarios/scenarios.py +22 -22
- flood_adapt/objects/strategies/strategies.py +89 -89
- flood_adapt/workflows/benefit_runner.py +579 -554
- flood_adapt/workflows/floodmap.py +85 -85
- flood_adapt/workflows/impacts_integrator.py +85 -85
- flood_adapt/workflows/scenario_runner.py +70 -70
- {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/LICENSE +674 -674
- {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/METADATA +866 -865
- flood_adapt-0.3.10.dist-info/RECORD +140 -0
- flood_adapt-0.3.9.dist-info/RECORD +0 -139
- {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/WHEEL +0 -0
- {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/top_level.txt +0 -0
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
import math
|
|
2
|
-
import os
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import Annotated
|
|
5
|
-
|
|
6
|
-
import numpy as np
|
|
7
|
-
import pandas as pd
|
|
8
|
-
from pydantic import BaseModel
|
|
9
|
-
|
|
10
|
-
from flood_adapt.misc.utils import (
|
|
11
|
-
copy_file_to_output_dir,
|
|
12
|
-
validate_file_extension,
|
|
13
|
-
)
|
|
14
|
-
from flood_adapt.objects.forcing import unit_system as us
|
|
15
|
-
from flood_adapt.objects.forcing.forcing import (
|
|
16
|
-
ForcingSource,
|
|
17
|
-
IWaterlevel,
|
|
18
|
-
)
|
|
19
|
-
from flood_adapt.objects.forcing.time_frame import (
|
|
20
|
-
TimeFrame,
|
|
21
|
-
)
|
|
22
|
-
from flood_adapt.objects.forcing.timeseries import (
|
|
23
|
-
CSVTimeseries,
|
|
24
|
-
SyntheticTimeseries,
|
|
25
|
-
TimeseriesFactory,
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class SurgeModel(BaseModel):
|
|
30
|
-
"""BaseModel describing the expected variables and data types for harmonic tide parameters of synthetic model."""
|
|
31
|
-
|
|
32
|
-
timeseries: SyntheticTimeseries
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class TideModel(BaseModel):
|
|
36
|
-
"""BaseModel describing the expected variables and data types for harmonic tide parameters of synthetic model."""
|
|
37
|
-
|
|
38
|
-
harmonic_amplitude: us.UnitfulLength
|
|
39
|
-
harmonic_phase: us.UnitfulTime
|
|
40
|
-
harmonic_period: us.UnitfulTime = us.UnitfulTime(
|
|
41
|
-
value=12.4, units=us.UnitTypesTime.hours
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
45
|
-
index = pd.date_range(
|
|
46
|
-
start=time_frame.start_time,
|
|
47
|
-
end=time_frame.end_time,
|
|
48
|
-
freq=time_frame.time_step,
|
|
49
|
-
name="time",
|
|
50
|
-
)
|
|
51
|
-
seconds = np.arange(len(index)) * time_frame.time_step.total_seconds()
|
|
52
|
-
seconds.round(decimals=0)
|
|
53
|
-
|
|
54
|
-
amp = self.harmonic_amplitude.value
|
|
55
|
-
omega = 2 * math.pi / (self.harmonic_period.convert(us.UnitTypesTime.seconds))
|
|
56
|
-
phase_seconds = self.harmonic_phase.convert(us.UnitTypesTime.seconds)
|
|
57
|
-
|
|
58
|
-
tide = amp * np.cos(omega * (seconds - phase_seconds))
|
|
59
|
-
return pd.DataFrame(data=tide, index=index)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
class WaterlevelSynthetic(IWaterlevel):
|
|
63
|
-
source: ForcingSource = ForcingSource.SYNTHETIC
|
|
64
|
-
|
|
65
|
-
surge: SurgeModel
|
|
66
|
-
tide: TideModel
|
|
67
|
-
|
|
68
|
-
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
69
|
-
tide_df = self.tide.to_dataframe(time_frame=time_frame)
|
|
70
|
-
|
|
71
|
-
surge_df = TimeseriesFactory.from_object(self.surge.timeseries).to_dataframe(
|
|
72
|
-
time_frame=time_frame
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
# Combine
|
|
76
|
-
tide_df.columns = ["waterlevel"]
|
|
77
|
-
surge_df.columns = ["waterlevel"]
|
|
78
|
-
surge_df = surge_df.reindex(tide_df.index, method="nearest", limit=1).fillna(
|
|
79
|
-
value=self.surge.timeseries.fill_value
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
wl_df = tide_df.add(surge_df, axis="index", fill_value=0)
|
|
83
|
-
wl_df.columns = ["waterlevel"]
|
|
84
|
-
|
|
85
|
-
return wl_df
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
class WaterlevelCSV(IWaterlevel):
|
|
89
|
-
source: ForcingSource = ForcingSource.CSV
|
|
90
|
-
|
|
91
|
-
path: Annotated[Path, validate_file_extension([".csv"])]
|
|
92
|
-
units: us.UnitTypesLength = us.UnitTypesLength.meters
|
|
93
|
-
|
|
94
|
-
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
95
|
-
return CSVTimeseries.load_file(
|
|
96
|
-
path=self.path, units=us.UnitfulLength(value=0, units=self.units)
|
|
97
|
-
).to_dataframe(time_frame=time_frame)
|
|
98
|
-
|
|
99
|
-
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
100
|
-
self.path = copy_file_to_output_dir(self.path, Path(output_dir))
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
class WaterlevelModel(IWaterlevel):
|
|
104
|
-
source: ForcingSource = ForcingSource.MODEL
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
class WaterlevelGauged(IWaterlevel):
|
|
108
|
-
source: ForcingSource = ForcingSource.GAUGED
|
|
1
|
+
import math
|
|
2
|
+
import os
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pandas as pd
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
from flood_adapt.misc.utils import (
|
|
11
|
+
copy_file_to_output_dir,
|
|
12
|
+
validate_file_extension,
|
|
13
|
+
)
|
|
14
|
+
from flood_adapt.objects.forcing import unit_system as us
|
|
15
|
+
from flood_adapt.objects.forcing.forcing import (
|
|
16
|
+
ForcingSource,
|
|
17
|
+
IWaterlevel,
|
|
18
|
+
)
|
|
19
|
+
from flood_adapt.objects.forcing.time_frame import (
|
|
20
|
+
TimeFrame,
|
|
21
|
+
)
|
|
22
|
+
from flood_adapt.objects.forcing.timeseries import (
|
|
23
|
+
CSVTimeseries,
|
|
24
|
+
SyntheticTimeseries,
|
|
25
|
+
TimeseriesFactory,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SurgeModel(BaseModel):
|
|
30
|
+
"""BaseModel describing the expected variables and data types for harmonic tide parameters of synthetic model."""
|
|
31
|
+
|
|
32
|
+
timeseries: SyntheticTimeseries
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TideModel(BaseModel):
|
|
36
|
+
"""BaseModel describing the expected variables and data types for harmonic tide parameters of synthetic model."""
|
|
37
|
+
|
|
38
|
+
harmonic_amplitude: us.UnitfulLength
|
|
39
|
+
harmonic_phase: us.UnitfulTime
|
|
40
|
+
harmonic_period: us.UnitfulTime = us.UnitfulTime(
|
|
41
|
+
value=12.4, units=us.UnitTypesTime.hours
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
45
|
+
index = pd.date_range(
|
|
46
|
+
start=time_frame.start_time,
|
|
47
|
+
end=time_frame.end_time,
|
|
48
|
+
freq=time_frame.time_step,
|
|
49
|
+
name="time",
|
|
50
|
+
)
|
|
51
|
+
seconds = np.arange(len(index)) * time_frame.time_step.total_seconds()
|
|
52
|
+
seconds.round(decimals=0)
|
|
53
|
+
|
|
54
|
+
amp = self.harmonic_amplitude.value
|
|
55
|
+
omega = 2 * math.pi / (self.harmonic_period.convert(us.UnitTypesTime.seconds))
|
|
56
|
+
phase_seconds = self.harmonic_phase.convert(us.UnitTypesTime.seconds)
|
|
57
|
+
|
|
58
|
+
tide = amp * np.cos(omega * (seconds - phase_seconds))
|
|
59
|
+
return pd.DataFrame(data=tide, index=index)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class WaterlevelSynthetic(IWaterlevel):
|
|
63
|
+
source: ForcingSource = ForcingSource.SYNTHETIC
|
|
64
|
+
|
|
65
|
+
surge: SurgeModel
|
|
66
|
+
tide: TideModel
|
|
67
|
+
|
|
68
|
+
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
69
|
+
tide_df = self.tide.to_dataframe(time_frame=time_frame)
|
|
70
|
+
|
|
71
|
+
surge_df = TimeseriesFactory.from_object(self.surge.timeseries).to_dataframe(
|
|
72
|
+
time_frame=time_frame
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Combine
|
|
76
|
+
tide_df.columns = ["waterlevel"]
|
|
77
|
+
surge_df.columns = ["waterlevel"]
|
|
78
|
+
surge_df = surge_df.reindex(tide_df.index, method="nearest", limit=1).fillna(
|
|
79
|
+
value=self.surge.timeseries.fill_value
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
wl_df = tide_df.add(surge_df, axis="index", fill_value=0)
|
|
83
|
+
wl_df.columns = ["waterlevel"]
|
|
84
|
+
|
|
85
|
+
return wl_df
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class WaterlevelCSV(IWaterlevel):
|
|
89
|
+
source: ForcingSource = ForcingSource.CSV
|
|
90
|
+
|
|
91
|
+
path: Annotated[Path, validate_file_extension([".csv"])]
|
|
92
|
+
units: us.UnitTypesLength = us.UnitTypesLength.meters
|
|
93
|
+
|
|
94
|
+
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
95
|
+
return CSVTimeseries.load_file(
|
|
96
|
+
path=self.path, units=us.UnitfulLength(value=0, units=self.units)
|
|
97
|
+
).to_dataframe(time_frame=time_frame)
|
|
98
|
+
|
|
99
|
+
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
100
|
+
self.path = copy_file_to_output_dir(self.path, Path(output_dir))
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class WaterlevelModel(IWaterlevel):
|
|
104
|
+
source: ForcingSource = ForcingSource.MODEL
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class WaterlevelGauged(IWaterlevel):
|
|
108
|
+
source: ForcingSource = ForcingSource.GAUGED
|
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from typing import Annotated, Any
|
|
4
|
-
|
|
5
|
-
import pandas as pd
|
|
6
|
-
import xarray as xr
|
|
7
|
-
|
|
8
|
-
from flood_adapt.misc.utils import (
|
|
9
|
-
copy_file_to_output_dir,
|
|
10
|
-
validate_file_extension,
|
|
11
|
-
)
|
|
12
|
-
from flood_adapt.objects.forcing import unit_system as us
|
|
13
|
-
from flood_adapt.objects.forcing.forcing import (
|
|
14
|
-
ForcingSource,
|
|
15
|
-
IWind,
|
|
16
|
-
)
|
|
17
|
-
from flood_adapt.objects.forcing.netcdf import validate_netcdf_forcing
|
|
18
|
-
from flood_adapt.objects.forcing.timeseries import (
|
|
19
|
-
CSVTimeseries,
|
|
20
|
-
SyntheticTimeseries,
|
|
21
|
-
TimeFrame,
|
|
22
|
-
TimeseriesFactory,
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class WindConstant(IWind):
|
|
27
|
-
source: ForcingSource = ForcingSource.CONSTANT
|
|
28
|
-
|
|
29
|
-
speed: us.UnitfulVelocity
|
|
30
|
-
direction: us.UnitfulDirection
|
|
31
|
-
|
|
32
|
-
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
33
|
-
time = pd.date_range(
|
|
34
|
-
start=time_frame.start_time,
|
|
35
|
-
end=time_frame.end_time,
|
|
36
|
-
freq=time_frame.time_step,
|
|
37
|
-
name="time",
|
|
38
|
-
)
|
|
39
|
-
data = {
|
|
40
|
-
"mag": [self.speed.value for _ in range(len(time))],
|
|
41
|
-
"dir": [self.direction.value for _ in range(len(time))],
|
|
42
|
-
}
|
|
43
|
-
return pd.DataFrame(data=data, index=time)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class WindSynthetic(IWind):
|
|
47
|
-
source: ForcingSource = ForcingSource.SYNTHETIC
|
|
48
|
-
|
|
49
|
-
magnitude: SyntheticTimeseries
|
|
50
|
-
direction: SyntheticTimeseries
|
|
51
|
-
|
|
52
|
-
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
53
|
-
time = pd.date_range(
|
|
54
|
-
start=time_frame.start_time,
|
|
55
|
-
end=time_frame.end_time,
|
|
56
|
-
freq=time_frame.time_step,
|
|
57
|
-
name="time",
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
magnitude = TimeseriesFactory.from_object(self.magnitude).to_dataframe(
|
|
61
|
-
time_frame=time_frame,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
direction = TimeseriesFactory.from_object(self.direction).to_dataframe(
|
|
65
|
-
time_frame=time_frame,
|
|
66
|
-
)
|
|
67
|
-
return pd.DataFrame(
|
|
68
|
-
index=time,
|
|
69
|
-
data={
|
|
70
|
-
"mag": magnitude.reindex(time).to_numpy().flatten(),
|
|
71
|
-
"dir": direction.reindex(time).to_numpy().flatten(),
|
|
72
|
-
},
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
class WindTrack(IWind):
|
|
77
|
-
source: ForcingSource = ForcingSource.TRACK
|
|
78
|
-
|
|
79
|
-
path: Annotated[Path, validate_file_extension([".cyc", ".spw"])]
|
|
80
|
-
# path to cyc file, set this when creating it
|
|
81
|
-
|
|
82
|
-
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
83
|
-
if self.path:
|
|
84
|
-
self.path = copy_file_to_output_dir(self.path, Path(output_dir))
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
class WindCSV(IWind):
|
|
88
|
-
source: ForcingSource = ForcingSource.CSV
|
|
89
|
-
|
|
90
|
-
path: Annotated[Path, validate_file_extension([".csv"])]
|
|
91
|
-
|
|
92
|
-
units: dict[str, Any] = {
|
|
93
|
-
"speed": us.UnitTypesVelocity.mps,
|
|
94
|
-
"direction": us.UnitTypesDirection.degrees,
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
98
|
-
return CSVTimeseries.load_file(
|
|
99
|
-
path=self.path, units=us.UnitfulVelocity(value=0, units=self.units["speed"])
|
|
100
|
-
).to_dataframe(time_frame)
|
|
101
|
-
|
|
102
|
-
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
103
|
-
self.path = copy_file_to_output_dir(self.path, Path(output_dir))
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
class WindMeteo(IWind):
|
|
107
|
-
source: ForcingSource = ForcingSource.METEO
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
class WindNetCDF(IWind):
|
|
111
|
-
source: ForcingSource = ForcingSource.NETCDF
|
|
112
|
-
units: us.UnitTypesVelocity = us.UnitTypesVelocity.mps
|
|
113
|
-
|
|
114
|
-
path: Annotated[Path, validate_file_extension([".nc"])]
|
|
115
|
-
|
|
116
|
-
def read(self) -> xr.Dataset:
|
|
117
|
-
required_vars = ("wind10_v", "wind10_u", "press_msl")
|
|
118
|
-
required_coords = ("time", "lat", "lon")
|
|
119
|
-
with xr.open_dataset(self.path) as ds:
|
|
120
|
-
validated_ds = validate_netcdf_forcing(ds, required_vars, required_coords)
|
|
121
|
-
return validated_ds
|
|
122
|
-
|
|
123
|
-
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
124
|
-
self.path = copy_file_to_output_dir(self.path, Path(output_dir))
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Annotated, Any
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import xarray as xr
|
|
7
|
+
|
|
8
|
+
from flood_adapt.misc.utils import (
|
|
9
|
+
copy_file_to_output_dir,
|
|
10
|
+
validate_file_extension,
|
|
11
|
+
)
|
|
12
|
+
from flood_adapt.objects.forcing import unit_system as us
|
|
13
|
+
from flood_adapt.objects.forcing.forcing import (
|
|
14
|
+
ForcingSource,
|
|
15
|
+
IWind,
|
|
16
|
+
)
|
|
17
|
+
from flood_adapt.objects.forcing.netcdf import validate_netcdf_forcing
|
|
18
|
+
from flood_adapt.objects.forcing.timeseries import (
|
|
19
|
+
CSVTimeseries,
|
|
20
|
+
SyntheticTimeseries,
|
|
21
|
+
TimeFrame,
|
|
22
|
+
TimeseriesFactory,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class WindConstant(IWind):
|
|
27
|
+
source: ForcingSource = ForcingSource.CONSTANT
|
|
28
|
+
|
|
29
|
+
speed: us.UnitfulVelocity
|
|
30
|
+
direction: us.UnitfulDirection
|
|
31
|
+
|
|
32
|
+
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
33
|
+
time = pd.date_range(
|
|
34
|
+
start=time_frame.start_time,
|
|
35
|
+
end=time_frame.end_time,
|
|
36
|
+
freq=time_frame.time_step,
|
|
37
|
+
name="time",
|
|
38
|
+
)
|
|
39
|
+
data = {
|
|
40
|
+
"mag": [self.speed.value for _ in range(len(time))],
|
|
41
|
+
"dir": [self.direction.value for _ in range(len(time))],
|
|
42
|
+
}
|
|
43
|
+
return pd.DataFrame(data=data, index=time)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class WindSynthetic(IWind):
|
|
47
|
+
source: ForcingSource = ForcingSource.SYNTHETIC
|
|
48
|
+
|
|
49
|
+
magnitude: SyntheticTimeseries
|
|
50
|
+
direction: SyntheticTimeseries
|
|
51
|
+
|
|
52
|
+
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
53
|
+
time = pd.date_range(
|
|
54
|
+
start=time_frame.start_time,
|
|
55
|
+
end=time_frame.end_time,
|
|
56
|
+
freq=time_frame.time_step,
|
|
57
|
+
name="time",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
magnitude = TimeseriesFactory.from_object(self.magnitude).to_dataframe(
|
|
61
|
+
time_frame=time_frame,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
direction = TimeseriesFactory.from_object(self.direction).to_dataframe(
|
|
65
|
+
time_frame=time_frame,
|
|
66
|
+
)
|
|
67
|
+
return pd.DataFrame(
|
|
68
|
+
index=time,
|
|
69
|
+
data={
|
|
70
|
+
"mag": magnitude.reindex(time).to_numpy().flatten(),
|
|
71
|
+
"dir": direction.reindex(time).to_numpy().flatten(),
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class WindTrack(IWind):
|
|
77
|
+
source: ForcingSource = ForcingSource.TRACK
|
|
78
|
+
|
|
79
|
+
path: Annotated[Path, validate_file_extension([".cyc", ".spw"])]
|
|
80
|
+
# path to cyc file, set this when creating it
|
|
81
|
+
|
|
82
|
+
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
83
|
+
if self.path:
|
|
84
|
+
self.path = copy_file_to_output_dir(self.path, Path(output_dir))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class WindCSV(IWind):
|
|
88
|
+
source: ForcingSource = ForcingSource.CSV
|
|
89
|
+
|
|
90
|
+
path: Annotated[Path, validate_file_extension([".csv"])]
|
|
91
|
+
|
|
92
|
+
units: dict[str, Any] = {
|
|
93
|
+
"speed": us.UnitTypesVelocity.mps,
|
|
94
|
+
"direction": us.UnitTypesDirection.degrees,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
def to_dataframe(self, time_frame: TimeFrame) -> pd.DataFrame:
|
|
98
|
+
return CSVTimeseries.load_file(
|
|
99
|
+
path=self.path, units=us.UnitfulVelocity(value=0, units=self.units["speed"])
|
|
100
|
+
).to_dataframe(time_frame)
|
|
101
|
+
|
|
102
|
+
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
103
|
+
self.path = copy_file_to_output_dir(self.path, Path(output_dir))
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class WindMeteo(IWind):
|
|
107
|
+
source: ForcingSource = ForcingSource.METEO
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class WindNetCDF(IWind):
|
|
111
|
+
source: ForcingSource = ForcingSource.NETCDF
|
|
112
|
+
units: us.UnitTypesVelocity = us.UnitTypesVelocity.mps
|
|
113
|
+
|
|
114
|
+
path: Annotated[Path, validate_file_extension([".nc"])]
|
|
115
|
+
|
|
116
|
+
def read(self) -> xr.Dataset:
|
|
117
|
+
required_vars = ("wind10_v", "wind10_u", "press_msl")
|
|
118
|
+
required_coords = ("time", "lat", "lon")
|
|
119
|
+
with xr.open_dataset(self.path) as ds:
|
|
120
|
+
validated_ds = validate_netcdf_forcing(ds, required_vars, required_coords)
|
|
121
|
+
return validated_ds
|
|
122
|
+
|
|
123
|
+
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
124
|
+
self.path = copy_file_to_output_dir(self.path, Path(output_dir))
|
|
@@ -1,92 +1,92 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from typing import Union
|
|
3
|
-
|
|
4
|
-
import tomli
|
|
5
|
-
|
|
6
|
-
from flood_adapt.objects.measures.measures import (
|
|
7
|
-
Buyout,
|
|
8
|
-
Elevate,
|
|
9
|
-
FloodProof,
|
|
10
|
-
FloodWall,
|
|
11
|
-
GreenInfrastructure,
|
|
12
|
-
Measure,
|
|
13
|
-
MeasureType,
|
|
14
|
-
Pump,
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class MeasureFactory:
|
|
19
|
-
@staticmethod
|
|
20
|
-
def get_measure_type(filepath: Union[str, os.PathLike]):
|
|
21
|
-
"""Get a measure type from toml file."""
|
|
22
|
-
with open(filepath, mode="rb") as fp:
|
|
23
|
-
toml = tomli.load(fp)
|
|
24
|
-
type = toml.get("type")
|
|
25
|
-
return MeasureType(type)
|
|
26
|
-
|
|
27
|
-
@staticmethod
|
|
28
|
-
def get_measure_object(filepath: Union[str, os.PathLike]) -> Measure:
|
|
29
|
-
measure_type = MeasureFactory.get_measure_type(filepath)
|
|
30
|
-
|
|
31
|
-
if MeasureType.is_impact(measure_type):
|
|
32
|
-
return ImpactMeasureFactory.get_impact_measure(measure_type).load_file(
|
|
33
|
-
filepath
|
|
34
|
-
)
|
|
35
|
-
elif MeasureType.is_hazard(measure_type):
|
|
36
|
-
return HazardMeasureFactory.get_hazard_measure(measure_type).load_file(
|
|
37
|
-
filepath
|
|
38
|
-
)
|
|
39
|
-
else:
|
|
40
|
-
raise ValueError(f"Measure type {measure_type} not recognized.")
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class ImpactMeasureFactory:
|
|
44
|
-
"""Simple parser to get the respective measure subclass from a measure type string given in the config file.
|
|
45
|
-
|
|
46
|
-
Args:
|
|
47
|
-
type (str): name of measure type
|
|
48
|
-
|
|
49
|
-
Returns
|
|
50
|
-
-------
|
|
51
|
-
Measure: Measure subclass
|
|
52
|
-
"""
|
|
53
|
-
|
|
54
|
-
@staticmethod
|
|
55
|
-
def get_impact_measure(impact_measure: str):
|
|
56
|
-
if impact_measure == "elevate_properties":
|
|
57
|
-
return Elevate
|
|
58
|
-
elif impact_measure == "buyout_properties":
|
|
59
|
-
return Buyout
|
|
60
|
-
elif impact_measure == "floodproof_properties":
|
|
61
|
-
return FloodProof
|
|
62
|
-
else:
|
|
63
|
-
raise ValueError(f"Measure type {impact_measure} not recognized.")
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
class HazardMeasureFactory:
|
|
67
|
-
"""Simple parser to get the respective measure subclass from a measure type string given in the config file.
|
|
68
|
-
|
|
69
|
-
Args:
|
|
70
|
-
type (str): name of measure type
|
|
71
|
-
|
|
72
|
-
Returns
|
|
73
|
-
-------
|
|
74
|
-
Measure: Measure subclass
|
|
75
|
-
"""
|
|
76
|
-
|
|
77
|
-
@staticmethod
|
|
78
|
-
def get_hazard_measure(hazard_measure: str):
|
|
79
|
-
if (
|
|
80
|
-
hazard_measure == "floodwall" or hazard_measure == "levee"
|
|
81
|
-
): # these should use the same class right?
|
|
82
|
-
return FloodWall
|
|
83
|
-
elif (
|
|
84
|
-
hazard_measure == "water_square"
|
|
85
|
-
or hazard_measure == "total_storage"
|
|
86
|
-
or hazard_measure == "greening"
|
|
87
|
-
):
|
|
88
|
-
return GreenInfrastructure
|
|
89
|
-
elif hazard_measure == "pump":
|
|
90
|
-
return Pump
|
|
91
|
-
else:
|
|
92
|
-
raise ValueError(f"Measure type {hazard_measure} not recognized.")
|
|
1
|
+
import os
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
import tomli
|
|
5
|
+
|
|
6
|
+
from flood_adapt.objects.measures.measures import (
|
|
7
|
+
Buyout,
|
|
8
|
+
Elevate,
|
|
9
|
+
FloodProof,
|
|
10
|
+
FloodWall,
|
|
11
|
+
GreenInfrastructure,
|
|
12
|
+
Measure,
|
|
13
|
+
MeasureType,
|
|
14
|
+
Pump,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MeasureFactory:
|
|
19
|
+
@staticmethod
|
|
20
|
+
def get_measure_type(filepath: Union[str, os.PathLike]):
|
|
21
|
+
"""Get a measure type from toml file."""
|
|
22
|
+
with open(filepath, mode="rb") as fp:
|
|
23
|
+
toml = tomli.load(fp)
|
|
24
|
+
type = toml.get("type")
|
|
25
|
+
return MeasureType(type)
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def get_measure_object(filepath: Union[str, os.PathLike]) -> Measure:
|
|
29
|
+
measure_type = MeasureFactory.get_measure_type(filepath)
|
|
30
|
+
|
|
31
|
+
if MeasureType.is_impact(measure_type):
|
|
32
|
+
return ImpactMeasureFactory.get_impact_measure(measure_type).load_file(
|
|
33
|
+
filepath
|
|
34
|
+
)
|
|
35
|
+
elif MeasureType.is_hazard(measure_type):
|
|
36
|
+
return HazardMeasureFactory.get_hazard_measure(measure_type).load_file(
|
|
37
|
+
filepath
|
|
38
|
+
)
|
|
39
|
+
else:
|
|
40
|
+
raise ValueError(f"Measure type {measure_type} not recognized.")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ImpactMeasureFactory:
|
|
44
|
+
"""Simple parser to get the respective measure subclass from a measure type string given in the config file.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
type (str): name of measure type
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
Measure: Measure subclass
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def get_impact_measure(impact_measure: str):
|
|
56
|
+
if impact_measure == "elevate_properties":
|
|
57
|
+
return Elevate
|
|
58
|
+
elif impact_measure == "buyout_properties":
|
|
59
|
+
return Buyout
|
|
60
|
+
elif impact_measure == "floodproof_properties":
|
|
61
|
+
return FloodProof
|
|
62
|
+
else:
|
|
63
|
+
raise ValueError(f"Measure type {impact_measure} not recognized.")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class HazardMeasureFactory:
|
|
67
|
+
"""Simple parser to get the respective measure subclass from a measure type string given in the config file.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
type (str): name of measure type
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
Measure: Measure subclass
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def get_hazard_measure(hazard_measure: str):
|
|
79
|
+
if (
|
|
80
|
+
hazard_measure == "floodwall" or hazard_measure == "levee"
|
|
81
|
+
): # these should use the same class right?
|
|
82
|
+
return FloodWall
|
|
83
|
+
elif (
|
|
84
|
+
hazard_measure == "water_square"
|
|
85
|
+
or hazard_measure == "total_storage"
|
|
86
|
+
or hazard_measure == "greening"
|
|
87
|
+
):
|
|
88
|
+
return GreenInfrastructure
|
|
89
|
+
elif hazard_measure == "pump":
|
|
90
|
+
return Pump
|
|
91
|
+
else:
|
|
92
|
+
raise ValueError(f"Measure type {hazard_measure} not recognized.")
|