flood-adapt 0.3.9__py3-none-any.whl → 0.3.11__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 +1853 -1848
  9. flood_adapt/adapter/sfincs_offshore.py +187 -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 +533 -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 +1229 -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 +236 -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 +551 -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.11.dist-info}/LICENSE +674 -674
  96. {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.11.dist-info}/METADATA +867 -865
  97. flood_adapt-0.3.11.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.11.dist-info}/WHEEL +0 -0
  100. {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.11.dist-info}/top_level.txt +0 -0
@@ -1,234 +1,236 @@
1
- import os
2
- from enum import Enum
3
- from pathlib import Path
4
- from typing import Any, ClassVar, List, Optional, Protocol, runtime_checkable
5
-
6
- import tomli
7
- from pydantic import (
8
- Field,
9
- field_serializer,
10
- field_validator,
11
- model_validator,
12
- )
13
-
14
- from flood_adapt.config.config import Settings
15
- from flood_adapt.objects.forcing.forcing import (
16
- ForcingSource,
17
- ForcingType,
18
- IForcing,
19
- )
20
- from flood_adapt.objects.forcing.forcing_factory import ForcingFactory
21
- from flood_adapt.objects.forcing.time_frame import TimeFrame
22
- from flood_adapt.objects.object_model import Object
23
-
24
-
25
- class Mode(str, Enum):
26
- """Class describing the accepted input for the variable mode in Event.
27
-
28
- Attributes
29
- ----------
30
- single_event : The single event mode.
31
- risk : The risk mode.
32
- """
33
-
34
- single_event = "single_event"
35
- risk = "risk"
36
-
37
-
38
- class Template(str, Enum):
39
- """Class describing the accepted input for the variable template in Event.
40
-
41
- Attributes
42
- ----------
43
- Synthetic : The synthetic template.
44
- Hurricane : The hurricane template.
45
- Historical : The historical template.
46
- """
47
-
48
- Synthetic = "Synthetic"
49
- Hurricane = "Hurricane"
50
- Historical = "Historical"
51
-
52
- @property
53
- def description(self) -> str:
54
- match self:
55
- case Template.Historical:
56
- return "Select a time period for a historic event. This method can use offshore wind and pressure fields for the selected time period to simulate nearshore water levels or download gauged waterlevels to perform a realistic simulation. These water levels are used together with rainfall and river discharge input to simulate flooding in the site area."
57
- case Template.Hurricane:
58
- return "Select a historical hurricane track from the hurricane database, and shift the track if desired."
59
- case Template.Synthetic:
60
- return "Customize a synthetic event by specifying the waterlevels, wind, rainfall and river discharges without being based on a historical event."
61
- case _:
62
- raise ValueError(f"Invalid event template: {self}")
63
-
64
-
65
- @runtime_checkable
66
- class PathBasedForcing(Protocol):
67
- """Protocol for forcing classes that have a path attribute.
68
-
69
- Performing an isinstance check on this class will return True if the class has a path attribute (even if it is None).
70
- """
71
-
72
- path: Path
73
-
74
-
75
- class Event(Object):
76
- """The accepted input for an event in FloodAdapt.
77
-
78
- Attributes
79
- ----------
80
- name : str
81
- The name of the event.
82
- description : str
83
- The description of the event. Defaults to "".
84
- time : TimeFrame
85
- The time frame of the event.
86
- template : Template
87
- The template of the event.
88
- mode : Mode
89
- The mode of the event.
90
- rainfall_multiplier : float
91
- The rainfall multiplier of the event.
92
- forcings : dict[ForcingType, list[IForcing]]
93
- The forcings of the event.
94
- """
95
-
96
- ALLOWED_FORCINGS: ClassVar[dict[ForcingType, List[ForcingSource]]]
97
-
98
- time: TimeFrame
99
- template: Template
100
- mode: Mode = Mode.single_event
101
-
102
- forcings: dict[ForcingType, list[IForcing]] = Field(default_factory=dict)
103
- rainfall_multiplier: float = Field(default=1.0, ge=0)
104
-
105
- @classmethod
106
- def get_allowed_forcings(cls) -> dict[str, List[str]]:
107
- return {k.value: [s.value for s in v] for k, v in cls.ALLOWED_FORCINGS.items()}
108
-
109
- def get_forcings(self) -> list[IForcing]:
110
- """Return a list of all forcings in the event."""
111
- return [forcing for forcings in self.forcings.values() for forcing in forcings]
112
-
113
- def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
114
- """Save any additional files associated with the event."""
115
- for forcing in self.get_forcings():
116
- forcing.save_additional(output_dir)
117
-
118
- @classmethod
119
- def load_file(cls, file_path: Path | str | os.PathLike) -> "Event":
120
- """Load object from file.
121
-
122
- Parameters
123
- ----------
124
- file_path : Path | str | os.PathLike
125
- Path to the file to load.
126
-
127
- """
128
- with open(file_path, mode="rb") as fp:
129
- toml = tomli.load(fp)
130
-
131
- event = cls.model_validate(toml)
132
-
133
- # Update all forcings with paths to absolute paths
134
- for forcing in event.get_forcings():
135
- if isinstance(forcing, PathBasedForcing):
136
- if forcing.path.exists():
137
- continue
138
- elif forcing.path == Path(forcing.path.name):
139
- # convert relative path to absolute path
140
- in_dir = Path(file_path).parent / forcing.path.name
141
- if not in_dir.exists():
142
- raise FileNotFoundError(
143
- f"Failed to load Event. File {forcing.path} does not exist in {in_dir.parent}."
144
- )
145
- forcing.path = in_dir
146
- else:
147
- raise FileNotFoundError(
148
- f"Failed to load Event. File {forcing.path} does not exist."
149
- )
150
-
151
- return event
152
-
153
- @staticmethod
154
- def _parse_forcing_from_dict(
155
- forcing_attrs: dict[str, Any] | IForcing,
156
- ftype: Optional[ForcingType] = None,
157
- fsource: Optional[ForcingSource] = None,
158
- ) -> IForcing:
159
- if isinstance(forcing_attrs, IForcing):
160
- # forcing_attrs is already a forcing object
161
- return forcing_attrs
162
- elif isinstance(forcing_attrs, dict):
163
- # forcing_attrs is a dict with valid forcing attributes
164
- if "type" not in forcing_attrs and ftype:
165
- forcing_attrs["type"] = ftype
166
- if "source" not in forcing_attrs and fsource:
167
- forcing_attrs["source"] = fsource
168
-
169
- return ForcingFactory.load_dict(forcing_attrs)
170
- else:
171
- raise ValueError(
172
- f"Invalid forcing attributes: {forcing_attrs}. "
173
- "Forcings must be one of:\n"
174
- "1. Instance of IForcing\n"
175
- "2. dict with the keys `type` (ForcingType), `source` (ForcingSource) specifying the class, and with valid forcing attributes for that class."
176
- )
177
-
178
- @field_validator("forcings", mode="before")
179
- @classmethod
180
- def create_forcings(
181
- cls, value: dict[str, list[dict[str, Any]]]
182
- ) -> dict[ForcingType, list[IForcing]]:
183
- forcings = {}
184
- for ftype, forcing_list in value.items():
185
- ftype = ForcingType(ftype)
186
- forcings[ftype] = [
187
- cls._parse_forcing_from_dict(forcing, ftype) for forcing in forcing_list
188
- ]
189
- return forcings
190
-
191
- @model_validator(mode="after")
192
- def validate_forcings(self):
193
- def validate_concrete_forcing(concrete_forcing):
194
- type = concrete_forcing.type
195
- source = concrete_forcing.source
196
-
197
- # Check type
198
- if type not in self.__class__.ALLOWED_FORCINGS:
199
- allowed_types = ", ".join(
200
- t.value for t in self.__class__.ALLOWED_FORCINGS.keys()
201
- )
202
- raise ValueError(
203
- f"Forcing type {type.value} is not allowed. Allowed types are: {allowed_types}"
204
- )
205
-
206
- # Check source
207
- if source not in self.__class__.ALLOWED_FORCINGS[type]:
208
- allowed_sources = ", ".join(
209
- s.value for s in self.__class__.ALLOWED_FORCINGS[type]
210
- )
211
- raise ValueError(
212
- f"Forcing source {source.value} is not allowed for forcing type {type.value}. "
213
- f"Allowed sources are: {allowed_sources}"
214
- )
215
-
216
- if Settings().validate_allowed_forcings and hasattr(self, "ALLOWED_FORCINGS"):
217
- # Validate forcings
218
- for _, concrete_forcings in self.forcings.items():
219
- for concrete_forcing in concrete_forcings:
220
- validate_concrete_forcing(concrete_forcing)
221
-
222
- return self
223
-
224
- @field_serializer("forcings")
225
- @classmethod
226
- def serialize_forcings(
227
- cls, value: dict[ForcingType, List[IForcing]]
228
- ) -> dict[str, List[dict[str, Any]]]:
229
- dct = {}
230
- for ftype, forcing_list in value.items():
231
- dct[ftype.value] = [
232
- forcing.model_dump(exclude_none=True) for forcing in forcing_list
233
- ]
234
- return dct
1
+ import os
2
+ from enum import Enum
3
+ from pathlib import Path
4
+ from typing import Any, ClassVar, List, Optional, Protocol, runtime_checkable
5
+
6
+ import tomli
7
+ from pydantic import (
8
+ Field,
9
+ field_serializer,
10
+ field_validator,
11
+ model_validator,
12
+ )
13
+
14
+ from flood_adapt.config.config import Settings
15
+ from flood_adapt.objects.forcing.forcing import (
16
+ ForcingSource,
17
+ ForcingType,
18
+ IForcing,
19
+ )
20
+ from flood_adapt.objects.forcing.forcing_factory import ForcingFactory
21
+ from flood_adapt.objects.forcing.time_frame import TimeFrame
22
+ from flood_adapt.objects.object_model import Object
23
+
24
+
25
+ class Mode(str, Enum):
26
+ """Class describing the accepted input for the variable mode in Event.
27
+
28
+ Attributes
29
+ ----------
30
+ single_event : The single event mode.
31
+ risk : The risk mode.
32
+ """
33
+
34
+ single_event = "single_event"
35
+ risk = "risk"
36
+
37
+
38
+ class Template(str, Enum):
39
+ """Class describing the accepted input for the variable template in Event.
40
+
41
+ Attributes
42
+ ----------
43
+ Synthetic : The synthetic template.
44
+ Hurricane : The hurricane template.
45
+ Historical : The historical template.
46
+ """
47
+
48
+ Synthetic = "Synthetic"
49
+ Hurricane = "Hurricane"
50
+ Historical = "Historical"
51
+
52
+ @property
53
+ def description(self) -> str:
54
+ match self:
55
+ case Template.Historical:
56
+ return "Select and optionally modify a real event by specifying a past time period."
57
+ case Template.Hurricane:
58
+ return (
59
+ "Select a historical hurricane track from the hurricane database."
60
+ )
61
+ case Template.Synthetic:
62
+ return "Build a custom event by specifying wind, water levels, rainfall, and discharge."
63
+ case _:
64
+ raise ValueError(f"Invalid event template: {self}")
65
+
66
+
67
+ @runtime_checkable
68
+ class PathBasedForcing(Protocol):
69
+ """Protocol for forcing classes that have a path attribute.
70
+
71
+ Performing an isinstance check on this class will return True if the class has a path attribute (even if it is None).
72
+ """
73
+
74
+ path: Path
75
+
76
+
77
+ class Event(Object):
78
+ """The accepted input for an event in FloodAdapt.
79
+
80
+ Attributes
81
+ ----------
82
+ name : str
83
+ The name of the event.
84
+ description : str
85
+ The description of the event. Defaults to "".
86
+ time : TimeFrame
87
+ The time frame of the event.
88
+ template : Template
89
+ The template of the event.
90
+ mode : Mode
91
+ The mode of the event.
92
+ rainfall_multiplier : float
93
+ The rainfall multiplier of the event.
94
+ forcings : dict[ForcingType, list[IForcing]]
95
+ The forcings of the event.
96
+ """
97
+
98
+ ALLOWED_FORCINGS: ClassVar[dict[ForcingType, List[ForcingSource]]]
99
+
100
+ time: TimeFrame
101
+ template: Template
102
+ mode: Mode = Mode.single_event
103
+
104
+ forcings: dict[ForcingType, list[IForcing]] = Field(default_factory=dict)
105
+ rainfall_multiplier: float = Field(default=1.0, ge=0)
106
+
107
+ @classmethod
108
+ def get_allowed_forcings(cls) -> dict[str, List[str]]:
109
+ return {k.value: [s.value for s in v] for k, v in cls.ALLOWED_FORCINGS.items()}
110
+
111
+ def get_forcings(self) -> list[IForcing]:
112
+ """Return a list of all forcings in the event."""
113
+ return [forcing for forcings in self.forcings.values() for forcing in forcings]
114
+
115
+ def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
116
+ """Save any additional files associated with the event."""
117
+ for forcing in self.get_forcings():
118
+ forcing.save_additional(output_dir)
119
+
120
+ @classmethod
121
+ def load_file(cls, file_path: Path | str | os.PathLike) -> "Event":
122
+ """Load object from file.
123
+
124
+ Parameters
125
+ ----------
126
+ file_path : Path | str | os.PathLike
127
+ Path to the file to load.
128
+
129
+ """
130
+ with open(file_path, mode="rb") as fp:
131
+ toml = tomli.load(fp)
132
+
133
+ event = cls.model_validate(toml)
134
+
135
+ # Update all forcings with paths to absolute paths
136
+ for forcing in event.get_forcings():
137
+ if isinstance(forcing, PathBasedForcing):
138
+ if forcing.path.exists():
139
+ continue
140
+ elif forcing.path == Path(forcing.path.name):
141
+ # convert relative path to absolute path
142
+ in_dir = Path(file_path).parent / forcing.path.name
143
+ if not in_dir.exists():
144
+ raise FileNotFoundError(
145
+ f"Failed to load Event. File {forcing.path} does not exist in {in_dir.parent}."
146
+ )
147
+ forcing.path = in_dir
148
+ else:
149
+ raise FileNotFoundError(
150
+ f"Failed to load Event. File {forcing.path} does not exist."
151
+ )
152
+
153
+ return event
154
+
155
+ @staticmethod
156
+ def _parse_forcing_from_dict(
157
+ forcing_attrs: dict[str, Any] | IForcing,
158
+ ftype: Optional[ForcingType] = None,
159
+ fsource: Optional[ForcingSource] = None,
160
+ ) -> IForcing:
161
+ if isinstance(forcing_attrs, IForcing):
162
+ # forcing_attrs is already a forcing object
163
+ return forcing_attrs
164
+ elif isinstance(forcing_attrs, dict):
165
+ # forcing_attrs is a dict with valid forcing attributes
166
+ if "type" not in forcing_attrs and ftype:
167
+ forcing_attrs["type"] = ftype
168
+ if "source" not in forcing_attrs and fsource:
169
+ forcing_attrs["source"] = fsource
170
+
171
+ return ForcingFactory.load_dict(forcing_attrs)
172
+ else:
173
+ raise ValueError(
174
+ f"Invalid forcing attributes: {forcing_attrs}. "
175
+ "Forcings must be one of:\n"
176
+ "1. Instance of IForcing\n"
177
+ "2. dict with the keys `type` (ForcingType), `source` (ForcingSource) specifying the class, and with valid forcing attributes for that class."
178
+ )
179
+
180
+ @field_validator("forcings", mode="before")
181
+ @classmethod
182
+ def create_forcings(
183
+ cls, value: dict[str, list[dict[str, Any]]]
184
+ ) -> dict[ForcingType, list[IForcing]]:
185
+ forcings = {}
186
+ for ftype, forcing_list in value.items():
187
+ ftype = ForcingType(ftype)
188
+ forcings[ftype] = [
189
+ cls._parse_forcing_from_dict(forcing, ftype) for forcing in forcing_list
190
+ ]
191
+ return forcings
192
+
193
+ @model_validator(mode="after")
194
+ def validate_forcings(self):
195
+ def validate_concrete_forcing(concrete_forcing):
196
+ type = concrete_forcing.type
197
+ source = concrete_forcing.source
198
+
199
+ # Check type
200
+ if type not in self.__class__.ALLOWED_FORCINGS:
201
+ allowed_types = ", ".join(
202
+ t.value for t in self.__class__.ALLOWED_FORCINGS.keys()
203
+ )
204
+ raise ValueError(
205
+ f"Forcing type {type.value} is not allowed. Allowed types are: {allowed_types}"
206
+ )
207
+
208
+ # Check source
209
+ if source not in self.__class__.ALLOWED_FORCINGS[type]:
210
+ allowed_sources = ", ".join(
211
+ s.value for s in self.__class__.ALLOWED_FORCINGS[type]
212
+ )
213
+ raise ValueError(
214
+ f"Forcing source {source.value} is not allowed for forcing type {type.value}. "
215
+ f"Allowed sources are: {allowed_sources}"
216
+ )
217
+
218
+ if Settings().validate_allowed_forcings and hasattr(self, "ALLOWED_FORCINGS"):
219
+ # Validate forcings
220
+ for _, concrete_forcings in self.forcings.items():
221
+ for concrete_forcing in concrete_forcings:
222
+ validate_concrete_forcing(concrete_forcing)
223
+
224
+ return self
225
+
226
+ @field_serializer("forcings")
227
+ @classmethod
228
+ def serialize_forcings(
229
+ cls, value: dict[ForcingType, List[IForcing]]
230
+ ) -> dict[str, List[dict[str, Any]]]:
231
+ dct = {}
232
+ for ftype, forcing_list in value.items():
233
+ dct[ftype.value] = [
234
+ forcing.model_dump(exclude_none=True) for forcing in forcing_list
235
+ ]
236
+ return dct
@@ -1,58 +1,58 @@
1
- from typing import ClassVar, List
2
-
3
- from flood_adapt.objects.events.events import Event, Template
4
- from flood_adapt.objects.forcing.forcing import (
5
- ForcingSource,
6
- ForcingType,
7
- )
8
- from flood_adapt.objects.forcing.time_frame import TimeFrame
9
-
10
- __all__ = ["HistoricalEvent", "TimeFrame"]
11
-
12
-
13
- class HistoricalEvent(Event):
14
- """BaseModel describing the expected variables and data types for parameters of HistoricalEvent that extend the parent class Event.
15
-
16
- Attributes
17
- ----------
18
- name : str
19
- The name of the event.
20
- description : str
21
- The description of the event. Defaults to "".
22
- time : TimeFrame
23
- The time frame of the event.
24
- template : Template
25
- The template of the event. Defaults to Template.Historical.
26
- mode : Mode
27
- The mode of the event. Defaults to Mode.single_event.
28
- rainfall_multiplier : float
29
- The rainfall multiplier of the event. Defaults to 1.0.
30
- forcings : dict[ForcingType, list[IForcing]]
31
- The forcings of the event.
32
- """
33
-
34
- ALLOWED_FORCINGS: ClassVar[dict[ForcingType, List[ForcingSource]]] = {
35
- ForcingType.RAINFALL: [
36
- ForcingSource.CSV,
37
- ForcingSource.METEO,
38
- ForcingSource.SYNTHETIC,
39
- ForcingSource.CONSTANT,
40
- ],
41
- ForcingType.WIND: [
42
- ForcingSource.CSV,
43
- ForcingSource.METEO,
44
- ForcingSource.CONSTANT,
45
- ],
46
- ForcingType.WATERLEVEL: [
47
- ForcingSource.MODEL,
48
- ForcingSource.CSV,
49
- ForcingSource.SYNTHETIC,
50
- ForcingSource.GAUGED,
51
- ],
52
- ForcingType.DISCHARGE: [
53
- ForcingSource.CSV,
54
- ForcingSource.SYNTHETIC,
55
- ForcingSource.CONSTANT,
56
- ],
57
- }
58
- template: Template = Template.Historical
1
+ from typing import ClassVar, List
2
+
3
+ from flood_adapt.objects.events.events import Event, Template
4
+ from flood_adapt.objects.forcing.forcing import (
5
+ ForcingSource,
6
+ ForcingType,
7
+ )
8
+ from flood_adapt.objects.forcing.time_frame import TimeFrame
9
+
10
+ __all__ = ["HistoricalEvent", "TimeFrame"]
11
+
12
+
13
+ class HistoricalEvent(Event):
14
+ """BaseModel describing the expected variables and data types for parameters of HistoricalEvent that extend the parent class Event.
15
+
16
+ Attributes
17
+ ----------
18
+ name : str
19
+ The name of the event.
20
+ description : str
21
+ The description of the event. Defaults to "".
22
+ time : TimeFrame
23
+ The time frame of the event.
24
+ template : Template
25
+ The template of the event. Defaults to Template.Historical.
26
+ mode : Mode
27
+ The mode of the event. Defaults to Mode.single_event.
28
+ rainfall_multiplier : float
29
+ The rainfall multiplier of the event. Defaults to 1.0.
30
+ forcings : dict[ForcingType, list[IForcing]]
31
+ The forcings of the event.
32
+ """
33
+
34
+ ALLOWED_FORCINGS: ClassVar[dict[ForcingType, List[ForcingSource]]] = {
35
+ ForcingType.RAINFALL: [
36
+ ForcingSource.CSV,
37
+ ForcingSource.METEO,
38
+ ForcingSource.SYNTHETIC,
39
+ ForcingSource.CONSTANT,
40
+ ],
41
+ ForcingType.WIND: [
42
+ ForcingSource.CSV,
43
+ ForcingSource.METEO,
44
+ ForcingSource.CONSTANT,
45
+ ],
46
+ ForcingType.WATERLEVEL: [
47
+ ForcingSource.MODEL,
48
+ ForcingSource.CSV,
49
+ ForcingSource.SYNTHETIC,
50
+ ForcingSource.GAUGED,
51
+ ],
52
+ ForcingType.DISCHARGE: [
53
+ ForcingSource.CSV,
54
+ ForcingSource.SYNTHETIC,
55
+ ForcingSource.CONSTANT,
56
+ ],
57
+ }
58
+ template: Template = Template.Historical