flood-adapt 1.1.1__py3-none-any.whl → 1.1.3__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 CHANGED
@@ -1,5 +1,5 @@
1
1
  # has to be here at the start to avoid circular imports
2
- __version__ = "1.1.1"
2
+ __version__ = "1.1.3"
3
3
 
4
4
  from flood_adapt import adapter, database_builder, dbs_classes, objects
5
5
  from flood_adapt.config.config import Settings
@@ -677,23 +677,20 @@ class SfincsAdapter(IHazardAdapter):
677
677
 
678
678
  def add_obs_points(self):
679
679
  """Add observation points provided in the site toml to SFINCS model."""
680
- if self.settings.obs_point is None:
680
+ obs_points = self.settings.obs_point
681
+ if not obs_points:
681
682
  return
682
- logger.info("Adding observation points to the overland flood model")
683
683
 
684
- obs_points = self.settings.obs_point
685
- names = []
686
- lat = []
687
- lon = []
688
- for pt in obs_points:
689
- names.append(pt.name)
690
- lat.append(pt.lat)
691
- lon.append(pt.lon)
692
-
693
- # create GeoDataFrame from obs_points in site file
684
+ names = [pt.name for pt in obs_points]
685
+ lat = [pt.lat for pt in obs_points]
686
+ lon = [pt.lon for pt in obs_points]
687
+
688
+ logger.info("Adding observation points to the overland flood model")
694
689
  df = pd.DataFrame({"name": names})
695
690
  gdf = gpd.GeoDataFrame(
696
- df, geometry=gpd.points_from_xy(lon, lat), crs="EPSG:4326"
691
+ df,
692
+ geometry=gpd.points_from_xy(lon, lat),
693
+ crs="EPSG:4326",
697
694
  )
698
695
 
699
696
  # Add locations to SFINCS file
@@ -1310,10 +1307,14 @@ class SfincsAdapter(IHazardAdapter):
1310
1307
  )
1311
1308
  return
1312
1309
 
1310
+ model_rivers = self._read_river_locations()
1311
+ if model_rivers.empty:
1312
+ logger.warning(
1313
+ "Cannot add discharge forcing: No rivers defined in the sfincs model."
1314
+ )
1315
+ return
1313
1316
  logger.info(f"Setting discharge forcing for river: {discharge.river.name}")
1314
-
1315
1317
  time_frame = self.get_model_time()
1316
- model_rivers = self._read_river_locations()
1317
1318
 
1318
1319
  # Check that the river is defined in the model and that the coordinates match
1319
1320
  river_loc = shapely.Point(
@@ -1711,17 +1712,22 @@ class SfincsAdapter(IHazardAdapter):
1711
1712
 
1712
1713
  def _read_river_locations(self) -> gpd.GeoDataFrame:
1713
1714
  path = self.get_model_root() / "sfincs.src"
1714
-
1715
- with open(path) as f:
1716
- lines = f.readlines()
1715
+ lines = []
1716
+ if path.exists():
1717
+ with open(path) as f:
1718
+ lines = f.readlines()
1717
1719
  coords = [(float(line.split()[0]), float(line.split()[1])) for line in lines]
1718
1720
  points = [shapely.Point(coord) for coord in coords]
1719
1721
 
1720
1722
  return gpd.GeoDataFrame({"geometry": points}, crs=self._model.crs)
1721
1723
 
1722
1724
  def _read_waterlevel_boundary_locations(self) -> gpd.GeoDataFrame:
1723
- with open(self.get_model_root() / "sfincs.bnd") as f:
1724
- lines = f.readlines()
1725
+ path = self.get_model_root() / "sfincs.bnd"
1726
+ lines = []
1727
+ if path.exists():
1728
+ with open(path) as f:
1729
+ lines = f.readlines()
1730
+
1725
1731
  coords = [(float(line.split()[0]), float(line.split()[1])) for line in lines]
1726
1732
  points = [shapely.Point(coord) for coord in coords]
1727
1733
 
@@ -10,6 +10,16 @@ from flood_adapt.database_builder.database_builder import (
10
10
  create_database,
11
11
  )
12
12
 
13
+ from .metrics_utils import (
14
+ BuildingsInfographicModel,
15
+ EventInfographicModel,
16
+ HomesInfographicModel,
17
+ ImpactCategoriesModel,
18
+ MetricModel,
19
+ RiskInfographicModel,
20
+ RoadsInfographicModel,
21
+ )
22
+
13
23
  __all__ = [
14
24
  "Basins",
15
25
  "ConfigModel",
@@ -20,4 +30,11 @@ __all__ = [
20
30
  "TideGaugeConfigModel",
21
31
  "UnitSystems",
22
32
  "create_database",
33
+ "BuildingsInfographicModel",
34
+ "EventInfographicModel",
35
+ "HomesInfographicModel",
36
+ "MetricModel",
37
+ "RiskInfographicModel",
38
+ "RoadsInfographicModel",
39
+ "ImpactCategoriesModel",
23
40
  ]
@@ -32,10 +32,15 @@ from flood_adapt.config.fiat import (
32
32
  from flood_adapt.config.gui import (
33
33
  AggregationDmgLayer,
34
34
  BenefitsLayer,
35
+ FieldName,
36
+ FilterCondition,
37
+ FilterGroup,
35
38
  FloodMapLayer,
36
39
  FootprintsDmgLayer,
37
40
  GuiModel,
38
41
  GuiUnitModel,
42
+ LogicalOperator,
43
+ MetricLayer,
39
44
  OutputLayers,
40
45
  PlottingModel,
41
46
  SyntheticTideModel,
@@ -70,6 +75,15 @@ from flood_adapt.config.site import (
70
75
  Site,
71
76
  StandardObjectModel,
72
77
  )
78
+ from flood_adapt.database_builder.metrics_utils import (
79
+ BuildingsInfographicModel,
80
+ EventInfographicModel,
81
+ HomesInfographicModel,
82
+ MetricModel,
83
+ Metrics,
84
+ RiskInfographicModel,
85
+ RoadsInfographicModel,
86
+ )
73
87
  from flood_adapt.dbs_classes.database import Database
74
88
  from flood_adapt.misc.debug_timer import debug_timer
75
89
  from flood_adapt.misc.log import FloodAdaptLogging
@@ -87,16 +101,6 @@ from flood_adapt.objects.projections.projections import (
87
101
  )
88
102
  from flood_adapt.objects.strategies.strategies import Strategy
89
103
 
90
- from .metrics_utils import (
91
- BuildingsInfographicModel,
92
- EventInfographicModel,
93
- HomesInfographicModel,
94
- MetricModel,
95
- Metrics,
96
- RiskInfographicModel,
97
- RoadsInfographicModel,
98
- )
99
-
100
104
  logger = FloodAdaptLogging.getLogger("DatabaseBuilder")
101
105
 
102
106
 
@@ -130,16 +134,17 @@ def path_check(str_path: str, config_path: Optional[Path] = None) -> str:
130
134
 
131
135
 
132
136
  class SpatialJoinModel(BaseModel):
133
- """Represents a spatial join model.
137
+ """
138
+ Model for representing a spatial join between geometries and tabular data.
134
139
 
135
- Attributes
140
+ Parameters
136
141
  ----------
137
- name : Optional[str], default None
138
- The name of the model.
142
+ name : Optional[str]
143
+ Name of the spatial join (optional).
139
144
  file : str
140
- The file associated with the model.
145
+ Path to the file containing the spatial data to join.
141
146
  field_name : str
142
- The field name used for the spatial join.
147
+ Name of the field used for joining.
143
148
  """
144
149
 
145
150
  name: Optional[str] = None
@@ -148,14 +153,13 @@ class SpatialJoinModel(BaseModel):
148
153
 
149
154
 
150
155
  class UnitSystems(str, Enum):
151
- """Enumeration for accepted values for the unit_system field.
156
+ """
157
+ Enumeration for supported unit systems.
152
158
 
153
- Attributes
154
- ----------
155
- imperial : str
156
- Represents the imperial unit system.
157
- metric : str
158
- Represents the metric unit system.
159
+ Values
160
+ ------
161
+ imperial : Imperial units (feet, miles, etc.)
162
+ metric : Metric units (meters, kilometers, etc.)
159
163
  """
160
164
 
161
165
  imperial = "imperial"
@@ -163,36 +167,30 @@ class UnitSystems(str, Enum):
163
167
 
164
168
 
165
169
  class FootprintsOptions(str, Enum):
166
- """Enumeration for accepted values for the building_footprints field.
170
+ """
171
+ Enumeration for building footprints data sources.
167
172
 
168
- Attributes
169
- ----------
170
- OSM : str
171
- Use OpenStreetMap for building footprints.
173
+ Values
174
+ ------
175
+ OSM : Use OpenStreetMap for building footprints.
172
176
  """
173
177
 
174
178
  OSM = "OSM"
175
179
 
176
180
 
177
181
  class Basins(str, Enum):
178
- """Enumeration class representing different basins.
182
+ """
183
+ Enumeration of global cyclone basins.
179
184
 
180
- Attributes
181
- ----------
182
- NA : str
183
- North Atlantic
184
- SA : str
185
- South Atlantic
186
- EP : str
187
- Eastern North Pacific (which includes the Central Pacific region)
188
- WP : str
189
- Western North Pacific
190
- SP : str
191
- South Pacific
192
- SI : str
193
- South Indian
194
- NI : str
195
- North Indian
185
+ Values
186
+ ------
187
+ NA : North Atlantic
188
+ SA : South Atlantic
189
+ EP : Eastern North Pacific (includes Central Pacific)
190
+ WP : Western North Pacific
191
+ SP : South Pacific
192
+ SI : South Indian
193
+ NI : North Indian
196
194
  """
197
195
 
198
196
  NA = "NA"
@@ -205,59 +203,67 @@ class Basins(str, Enum):
205
203
 
206
204
 
207
205
  class GuiConfigModel(BaseModel):
208
- """Represents a GUI model for FloodAdapt.
206
+ """
207
+ Configuration for FloodAdapt GUI visualization scaling.
209
208
 
210
- Attributes
209
+ Parameters
211
210
  ----------
212
211
  max_flood_depth : float
213
- The last visualization bin will be ">value".
212
+ Maximum flood depth for visualization bins (last bin is ">value").
214
213
  max_aggr_dmg : float
215
- The last visualization bin will be ">value".
214
+ Maximum aggregated damage for visualization bins.
216
215
  max_footprint_dmg : float
217
- The last visualization bin will be ">value".
216
+ Maximum footprint damage for visualization bins.
218
217
  max_benefits : float
219
- The last visualization bin will be ">value".
218
+ Maximum benefits for visualization bins.
219
+ additional_aggregated_layers : Optional[list[MetricLayer]]
220
+ Additional metric layers for aggregation (optional).
220
221
  """
221
222
 
222
223
  max_flood_depth: float
223
224
  max_aggr_dmg: float
224
225
  max_footprint_dmg: float
225
226
  max_benefits: float
227
+ additional_aggregated_layers: Optional[list[MetricLayer]] = None
226
228
 
227
229
 
228
230
  class SviConfigModel(SpatialJoinModel):
229
- """Represents a model for the Social Vulnerability Index (SVI).
231
+ """
232
+ Model for Social Vulnerability Index (SVI) spatial join.
233
+
234
+ Inherits from SpatialJoinModel.
230
235
 
231
- Attributes
236
+ Parameters
232
237
  ----------
233
238
  threshold : float
234
- The threshold value for the SVI model to specify vulnerability.
239
+ Threshold value to specify vulnerability.
235
240
  """
236
241
 
237
242
  threshold: float
238
243
 
239
244
 
240
245
  class TideGaugeConfigModel(BaseModel):
241
- """Represents a tide gauge model.
246
+ """
247
+ Model for tide gauge configuration.
242
248
 
243
- Attributes
249
+ Parameters
244
250
  ----------
245
251
  source : TideGaugeSource
246
- The source of the tide gauge data.
247
- description : str, default ""
252
+ Source of tide gauge data.
253
+ description : str
248
254
  Description of the tide gauge.
249
- ref : Optional[str], default None
250
- The reference name. Should be defined in the water level references.
251
- id : Optional[int], default None
252
- The station ID.
253
- lon : Optional[float], default None
254
- Longitude of the tide gauge.
255
- lat : Optional[float], default None
256
- Latitude of the tide gauge.
257
- file : Optional[str], default None
258
- The file associated with the tide gauge data.
259
- max_distance : Optional[us.UnitfulLength], default None
260
- The maximum distance.
255
+ ref : Optional[str]
256
+ Reference name (should match water level references).
257
+ id : Optional[int]
258
+ Station ID.
259
+ lon : Optional[float]
260
+ Longitude.
261
+ lat : Optional[float]
262
+ Latitude.
263
+ file : Optional[str]
264
+ Path to tide gauge data file.
265
+ max_distance : Optional[us.UnitfulLength]
266
+ Maximum distance for gauge association.
261
267
  """
262
268
 
263
269
  source: TideGaugeSource
@@ -272,74 +278,76 @@ class TideGaugeConfigModel(BaseModel):
272
278
 
273
279
  class ConfigModel(BaseModel):
274
280
  """
275
- Represents the configuration model for FloodAdapt.
281
+ Main configuration model for FloodAdapt database builder.
276
282
 
277
- Attributes
283
+ Parameters
278
284
  ----------
279
285
  name : str
280
- The name of the site.
281
- description : Optional[str], default None
282
- The description of the site.
283
- database_path : Optional[str], default None
284
- The path to the database where all the sites are located.
286
+ Name of the site (must be valid for folder names).
287
+ description : Optional[str]
288
+ Description of the site.
289
+ database_path : Optional[str]
290
+ Path to the database root directory.
285
291
  unit_system : UnitSystems
286
- The unit system.
292
+ Unit system for all calculations (imperial or metric).
287
293
  gui : GuiConfigModel
288
- The GUI model representing scaling values for the layers.
289
- infographics : bool, default True
290
- Indicates if infographics are enabled.
291
- event_infographics : Optional[EventInfographicModel], default None
292
- Event infographic configuration.
293
- risk_infographics : Optional[RiskInfographicModel], default None
294
- Risk infographic configuration.
295
- event_additional_infometrics : Optional[list[MetricModel]], default None
294
+ GUI visualization scaling configuration.
295
+ infographics : bool
296
+ Enable/disable infographics.
297
+ event_infographics : Optional[EventInfographicModel]
298
+ Configuration for event infographics.
299
+ risk_infographics : Optional[RiskInfographicModel]
300
+ Configuration for risk infographics.
301
+ event_additional_infometrics : Optional[list[MetricModel]]
296
302
  Additional event infometrics.
297
- risk_additional_infometrics : Optional[list[MetricModel]], default None
303
+ risk_additional_infometrics : Optional[list[MetricModel]]
298
304
  Additional risk infometrics.
299
305
  fiat : str
300
- The FIAT model path.
301
- aggregation_areas : Optional[list[SpatialJoinModel]], default None
302
- The list of aggregation area models.
303
- building_footprints : Optional[SpatialJoinModel | FootprintsOptions], default FootprintsOptions.OSM
304
- The building footprints model or OSM option.
305
- fiat_buildings_name : str | list[str], default "buildings"
306
- The name(s) of the buildings geometry in the FIAT model.
307
- fiat_roads_name : Optional[str], default "roads"
308
- The name of the roads geometry in the FIAT model.
309
- bfe : Optional[SpatialJoinModel], default None
310
- The BFE model.
311
- svi : Optional[SviConfigModel], default None
312
- The SVI model.
313
- road_width : us.UnitfulLength, default 5 meters
314
- The road width.
315
- return_periods : Optional[list[int]], default None
316
- The list of return periods for risk calculations.
317
- floodmap_type : Optional[FloodmapType], default None
318
- The type of floodmap to use.
319
- references : Optional[WaterlevelReferenceModel], default None
320
- The water level reference model.
306
+ Path to the FIAT model directory.
307
+ aggregation_areas : Optional[list[SpatialJoinModel]]
308
+ List of aggregation area spatial join models.
309
+ building_footprints : Optional[SpatialJoinModel | FootprintsOptions]
310
+ Building footprints source or spatial join model.
311
+ fiat_buildings_name : str | list[str]
312
+ Name(s) of buildings geometry in FIAT model.
313
+ fiat_roads_name : Optional[str]
314
+ Name of roads geometry in FIAT model.
315
+ bfe : Optional[SpatialJoinModel]
316
+ Base Flood Elevation spatial join model.
317
+ svi : Optional[SviConfigModel]
318
+ Social Vulnerability Index spatial join model.
319
+ road_width : us.UnitfulLength
320
+ Road width (default 5 meters).
321
+ return_periods : Optional[list[int]]
322
+ List of return periods for risk calculations.
323
+ floodmap_type : Optional[FloodmapType]
324
+ Type of floodmap to use.
325
+ references : Optional[WaterlevelReferenceModel]
326
+ Water level reference model.
321
327
  sfincs_overland : FloodModel
322
- The overland SFINCS model.
323
- sfincs_offshore : Optional[FloodModel], default None
324
- The offshore SFINCS model.
325
- dem : Optional[DemModel], default None
326
- The DEM model.
327
- excluded_datums : list[str], default []
328
+ Overland SFINCS model configuration.
329
+ sfincs_offshore : Optional[FloodModel]
330
+ Offshore SFINCS model configuration.
331
+ dem : Optional[DemModel]
332
+ Digital Elevation Model configuration.
333
+ river_names : Optional[list[str]]
334
+ List of river names (optional).
335
+ excluded_datums : list[str]
328
336
  List of datums to exclude from plotting.
329
- slr_scenarios : Optional[SlrScenariosModel], default None
330
- The sea level rise scenarios model.
331
- scs : Optional[SCSModel], default None
332
- The SCS model.
333
- tide_gauge : Optional[TideGaugeConfigModel], default None
334
- The tide gauge model.
335
- cyclones : Optional[bool], default True
336
- Indicates if cyclones are enabled.
337
- cyclone_basin : Optional[Basins], default None
338
- The cyclone basin.
339
- obs_point : Optional[list[ObsPointModel]], default None
340
- The list of observation point models.
341
- probabilistic_set : Optional[str], default None
342
- The probabilistic set path.
337
+ slr_scenarios : Optional[SlrScenariosModel]
338
+ Sea level rise scenarios configuration.
339
+ scs : Optional[SCSModel]
340
+ SCS model configuration.
341
+ tide_gauge : Optional[TideGaugeConfigModel]
342
+ Tide gauge configuration.
343
+ cyclones : Optional[bool]
344
+ Enable/disable cyclones.
345
+ cyclone_basin : Optional[Basins]
346
+ Cyclone basin selection.
347
+ obs_point : Optional[list[ObsPointModel]]
348
+ List of observation point models.
349
+ probabilistic_set : Optional[str]
350
+ Path to probabilistic event set.
343
351
  """
344
352
 
345
353
  # General
@@ -375,7 +383,7 @@ class ConfigModel(BaseModel):
375
383
  sfincs_overland: FloodModel
376
384
  sfincs_offshore: Optional[FloodModel] = None
377
385
  dem: Optional[DemModel] = None
378
-
386
+ river_names: Optional[list[str]] = None
379
387
  excluded_datums: list[str] = Field(default_factory=list)
380
388
 
381
389
  slr_scenarios: Optional[SlrScenariosModel] = None
@@ -1347,7 +1355,12 @@ class DatabaseBuilder:
1347
1355
  if delete_sfincs_folder:
1348
1356
  gc.collect()
1349
1357
  if subgrid_sfincs_folder.exists() and subgrid_sfincs_folder.is_dir():
1350
- shutil.rmtree(subgrid_sfincs_folder)
1358
+ try:
1359
+ shutil.rmtree(subgrid_sfincs_folder)
1360
+ except Exception:
1361
+ logger.warning(
1362
+ f"Could not delete temporary SFINCS subgrid folder at {subgrid_sfincs_folder.as_posix()}."
1363
+ )
1351
1364
 
1352
1365
  return DemModel(
1353
1366
  filename=fa_subgrid_path.name, units=us.UnitTypesLength.meters
@@ -1393,39 +1406,43 @@ class DatabaseBuilder:
1393
1406
  else:
1394
1407
  logger.info("Observation points were provided in the config file.")
1395
1408
  obs_points = self.config.obs_point
1409
+
1396
1410
  if self.tide_gauge is not None:
1397
- # Check if the tide gauge point is within the SFINCS region
1398
- region = self.sfincs_overland_model.region
1399
- point = gpd.GeoSeries(
1400
- [gpd.points_from_xy([self.tide_gauge.lon], [self.tide_gauge.lat])[0]],
1401
- crs=4326,
1402
- )
1403
- region_4326 = region.to_crs(4326)
1404
- if not point.within(region_4326.unary_union).item():
1405
- logger.warning(
1406
- "The tide gauge location is outside the SFINCS region and will not be added as an observation point."
1407
- )
1408
- else:
1409
- logger.info(
1410
- "A tide gauge has been setup in the database. It will be used as an observation point as well."
1411
- )
1412
- obs_points.append(
1413
- ObsPointModel(
1414
- name=self.tide_gauge.name,
1415
- description="Tide gauge observation point",
1416
- ID=self.tide_gauge.ID,
1417
- lon=self.tide_gauge.lon,
1418
- lat=self.tide_gauge.lat,
1419
- )
1411
+ logger.info(
1412
+ "A tide gauge has been setup in the database. It will be used as an observation point as well."
1413
+ )
1414
+ obs_points.append(
1415
+ ObsPointModel(
1416
+ name=self.tide_gauge.name,
1417
+ description="Tide gauge observation point",
1418
+ ID=self.tide_gauge.ID,
1419
+ lon=self.tide_gauge.lon,
1420
+ lat=self.tide_gauge.lat,
1420
1421
  )
1422
+ )
1421
1423
 
1422
1424
  if not obs_points:
1423
1425
  logger.warning(
1424
1426
  "No observation points were provided in the config file or created from the tide gauge. No observation points will be available in FloodAdapt."
1425
1427
  )
1426
1428
  return None
1427
- else:
1428
- return obs_points
1429
+
1430
+ lon = [p.lon for p in obs_points]
1431
+ lat = [p.lat for p in obs_points]
1432
+ names = [p.name for p in obs_points]
1433
+ coords = gpd.GeoDataFrame(
1434
+ {"names": names},
1435
+ geometry=gpd.points_from_xy(lon, lat),
1436
+ crs="EPSG:4326",
1437
+ )
1438
+ coords = coords.to_crs(self.sfincs_overland_model.crs)
1439
+ model_region = self.sfincs_overland_model.region.union_all()
1440
+ valid_coords = coords.within(model_region)
1441
+ if not valid_coords.all():
1442
+ invalid = coords.loc[~valid_coords, "name"].tolist()
1443
+ raise ValueError(f"Observation points outside model domain: {invalid}")
1444
+
1445
+ return obs_points
1429
1446
 
1430
1447
  @debug_timer
1431
1448
  def create_rivers(self) -> list[RiverModel]:
@@ -1440,6 +1457,17 @@ class DatabaseBuilder:
1440
1457
  geometry=gpd.points_from_xy(df.x, df.y),
1441
1458
  crs=self.sfincs_overland_model.crs,
1442
1459
  )
1460
+
1461
+ if self.config.river_names:
1462
+ if len(self.config.river_names) != len(river_locs):
1463
+ msg = "The number of river names provided does not match the number of rivers found in the SFINCS model."
1464
+ logger.error(msg)
1465
+ raise ValueError(msg)
1466
+ else:
1467
+ river_locs["name"] = self.config.river_names
1468
+ else:
1469
+ river_locs["name"] = [f"river_{idx}" for idx in range(len(river_locs))]
1470
+
1443
1471
  rivers = []
1444
1472
  for idx, row in river_locs.iterrows():
1445
1473
  if "dis" in self.sfincs_overland_model.forcing:
@@ -1456,7 +1484,7 @@ class DatabaseBuilder:
1456
1484
  )
1457
1485
 
1458
1486
  river = RiverModel(
1459
- name=f"river_{idx}",
1487
+ name=row["name"],
1460
1488
  x_coordinate=row.x,
1461
1489
  y_coordinate=row.y,
1462
1490
  mean_discharge=us.UnitfulDischarge(
@@ -1782,6 +1810,69 @@ class DatabaseBuilder:
1782
1810
  ],
1783
1811
  threshold=0.0,
1784
1812
  )
1813
+ red_colors_6 = [
1814
+ "#FFFFFF",
1815
+ "#FEE9CE",
1816
+ "#FDBB84",
1817
+ "#FC844E",
1818
+ "#E03720",
1819
+ "#860000",
1820
+ ]
1821
+
1822
+ aggregated_metrics = []
1823
+
1824
+ building_count = MetricLayer(
1825
+ type="building_count",
1826
+ bins=[1, 10, 50, 200, 500], # TODO provide max values
1827
+ colors=red_colors_6,
1828
+ filters=FilterGroup(
1829
+ conditions=[
1830
+ FilterCondition(
1831
+ field_name=FieldName.NAME,
1832
+ values=["Count"],
1833
+ ),
1834
+ FilterCondition(
1835
+ field_name=FieldName.LONG_NAME,
1836
+ values=["(#)"],
1837
+ ),
1838
+ ],
1839
+ operator=LogicalOperator.OR,
1840
+ ),
1841
+ )
1842
+ aggregated_metrics.append(building_count)
1843
+
1844
+ if self.config.gui.additional_aggregated_layers:
1845
+ aggregated_metrics.extend(self.config.gui.additional_aggregated_layers)
1846
+
1847
+ if self._has_roads:
1848
+ bins = [0.0001, 1, 5, 10, 20] # in kms
1849
+ if self.unit_system == GuiUnitModel.imperial():
1850
+ # convert to miles
1851
+ bins = [
1852
+ us.UnitfulLength(value=b * 1000, units=us.UnitTypesLength.meters)
1853
+ .transform(us.UnitTypesLength.miles)
1854
+ .value
1855
+ for b in bins
1856
+ ]
1857
+ roads_length = MetricLayer(
1858
+ type="road_length",
1859
+ bins=bins, # TODO provide max values
1860
+ colors=red_colors_6,
1861
+ filters=FilterGroup(
1862
+ conditions=[
1863
+ FilterCondition(
1864
+ field_name=FieldName.NAME,
1865
+ values=["RoadsLength"],
1866
+ ),
1867
+ FilterCondition(
1868
+ field_name=FieldName.LONG_NAME,
1869
+ values=["roads"],
1870
+ ),
1871
+ ],
1872
+ operator=LogicalOperator.AND,
1873
+ ),
1874
+ )
1875
+ aggregated_metrics.append(roads_length)
1785
1876
 
1786
1877
  output_layers = OutputLayers(
1787
1878
  floodmap=FloodMapLayer(
@@ -1792,25 +1883,12 @@ class DatabaseBuilder:
1792
1883
  ),
1793
1884
  aggregation_dmg=AggregationDmgLayer(
1794
1885
  bins=[0.00001, 0.1 * ad_max, 0.25 * ad_max, 0.5 * ad_max, ad_max],
1795
- colors=[
1796
- "#FFFFFF",
1797
- "#FEE9CE",
1798
- "#FDBB84",
1799
- "#FC844E",
1800
- "#E03720",
1801
- "#860000",
1802
- ],
1886
+ colors=red_colors_6,
1803
1887
  ),
1888
+ aggregated_metrics=aggregated_metrics,
1804
1889
  footprints_dmg=FootprintsDmgLayer(
1805
1890
  bins=[0.00001, 0.06 * ftd_max, 0.2 * ftd_max, 0.4 * ftd_max, ftd_max],
1806
- colors=[
1807
- "#FFFFFF",
1808
- "#FEE9CE",
1809
- "#FDBB84",
1810
- "#FC844E",
1811
- "#E03720",
1812
- "#860000",
1813
- ],
1891
+ colors=red_colors_6,
1814
1892
  ),
1815
1893
  benefits=benefits_layer,
1816
1894
  )
@@ -1893,6 +1971,8 @@ class DatabaseBuilder:
1893
1971
  # Write the metrics config files
1894
1972
  self._write_infometrics(metrics, path_im, path_ig)
1895
1973
 
1974
+ self.metrics = metrics
1975
+
1896
1976
  def _create_mandatory_metrics(self, metrics):
1897
1977
  metrics.create_mandatory_metrics_event()
1898
1978
  if self._probabilistic_set_name is not None:
@@ -3,7 +3,7 @@ from pathlib import Path
3
3
  from typing import Any, Dict, List, Literal, Optional, Union
4
4
 
5
5
  import tomli_w
6
- from pydantic import BaseModel, Field, field_validator
6
+ from pydantic import BaseModel, Field, field_validator, model_validator
7
7
 
8
8
  from flood_adapt.adapter.fiat_adapter import _IMPACT_COLUMNS
9
9
 
@@ -131,52 +131,42 @@ class MetricModel(BaseModel):
131
131
  name : str
132
132
  The short name of the metric.
133
133
  long_name : Optional[str], default=None
134
- The long descriptive name of the metric. Defaults to `name` if not provided.
134
+ The long descriptive name of the metric. If not provided, defaults to `name`.
135
135
  show_in_metrics_table : Optional[bool], default=True
136
136
  Indicates whether the metric should be displayed in the metrics table.
137
+ show_in_map : Optional[bool], default=True
138
+ Indicates whether the metric should be displayed on the map.
137
139
  description : Optional[str], default=None
138
- A detailed description of the metric. Defaults to `name` if not provided.
140
+ A detailed description of the metric. If not provided, defaults to `name`.
139
141
  select : str
140
142
  The SQL select statement or expression for the metric.
141
143
  filter : Optional[str], default=""
142
144
  An optional SQL filter to apply to the metric. Defaults to no filter.
143
145
 
144
- Methods
145
- -------
146
- set_defaults(value, info)
147
- Sets default values for `long_name` and `description` fields using the `name` field if they are not provided.
146
+ Validation
147
+ ----------
148
+ If `long_name` or `description` are None, they will be set to the value of `name`.
148
149
  """
149
150
 
150
151
  name: str
151
152
  long_name: Optional[str] = None
152
153
  show_in_metrics_table: Optional[bool] = True
154
+ show_in_map: Optional[bool] = True
153
155
  description: Optional[str] = None
154
156
  select: str
155
157
  filter: Optional[str] = "" # This defaults to no filter
156
158
 
157
- @field_validator("long_name", "description", mode="after")
158
- @classmethod
159
- def set_defaults(cls, value, info):
160
- """
161
- Set default values for long_name and description fields.
159
+ @model_validator(mode="after")
160
+ def fill_defaults(self):
161
+ # If long_name is missing, copy name
162
+ if self.long_name is None:
163
+ self.long_name = self.name
162
164
 
163
- Parameters
164
- ----------
165
- value : Any
166
- The current field value.
167
- info : Any
168
- Field validation info containing all field values.
165
+ # If description is missing, copy long_name (which is now guaranteed)
166
+ if self.description is None:
167
+ self.description = self.long_name
169
168
 
170
- Returns
171
- -------
172
- str
173
- The field value or the default value from 'name' field.
174
- """
175
- # info.data contains all field values
176
- if value is None:
177
- # Use 'name' field as default
178
- return info.data.get("name")
179
- return value
169
+ return self
180
170
 
181
171
 
182
172
  class ImpactCategoriesModel(BaseModel):
@@ -233,7 +233,7 @@ class Database(IDatabase):
233
233
  if _type == FloodmapType.water_level:
234
234
  paths = [base_dir / "max_water_level_map.nc"]
235
235
  elif _type == FloodmapType.water_depth:
236
- paths = [base_dir / f"FloodMap_{self.name}.tif"]
236
+ paths = [base_dir / f"FloodMap_{scenario_name}.tif"]
237
237
  elif mode == Mode.risk:
238
238
  if _type == FloodmapType.water_level:
239
239
  paths = list(base_dir.glob("RP_*_maps.nc"))
@@ -4,6 +4,7 @@ from typing import ClassVar, Optional
4
4
 
5
5
  import cht_observations.observation_stations as cht_station
6
6
  import pandas as pd
7
+ import requests
7
8
  from noaa_coops.station import COOPSAPIError
8
9
  from pydantic import BaseModel, model_validator
9
10
 
@@ -178,7 +179,7 @@ class TideGauge(BaseModel):
178
179
  series = series.reindex(index, method="nearest")
179
180
  df = pd.DataFrame(data=series, index=index)
180
181
 
181
- except COOPSAPIError as e:
182
+ except (COOPSAPIError, requests.JSONDecodeError) as e:
182
183
  logger.error(
183
184
  f"Could not download tide gauge data for station {self.ID}. {e}"
184
185
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: flood-adapt
3
- Version: 1.1.1
3
+ Version: 1.1.3
4
4
  Summary: A software package support system which can be used to assess the benefits and costs of flood resilience measures
5
5
  Author-email: Gundula Winter <Gundula.Winter@deltares.nl>, Panos Athanasiou <Panos.Athanasiou@deltares.nl>, Frederique de Groen <Frederique.deGroen@deltares.nl>, Tim de Wilde <Tim.deWilde@deltares.nl>, Julian Hofer <Julian.Hofer@deltares.nl>, Daley Adrichem <Daley.Adrichem@deltares.nl>, Luuk Blom <Luuk.Blom@deltares.nl>
6
6
  License: ====================================================
@@ -1,8 +1,8 @@
1
- flood_adapt/__init__.py,sha256=qFXo1YJVbLyqFpONc_TfAdUhZw9fgTacsn1XbFq1LxM,779
1
+ flood_adapt/__init__.py,sha256=ZFaVlYxQCAmSCEcKRDh-vvJUduWCIiLhuc2dBFHMbaw,779
2
2
  flood_adapt/flood_adapt.py,sha256=HVFS4OFhcB0TqHtMw3kbEei0IfJxsciauHfG3XZ38-0,40747
3
3
  flood_adapt/adapter/__init__.py,sha256=vnF8NCkEVX-N-gtGS-J_A1H1YYAjihWjJZFyYGwcp8Q,180
4
4
  flood_adapt/adapter/fiat_adapter.py,sha256=seDjPoumkhUOd7qer3ni1_Ut3dwyq0-_yhJNaTEFc2E,60284
5
- flood_adapt/adapter/sfincs_adapter.py,sha256=SSZ5hlnHpXLmDQqbyBMfybdAQIOpYOqIsSzoKk4XLZg,78825
5
+ flood_adapt/adapter/sfincs_adapter.py,sha256=_S-fABsi4flOkbrbIy_ROTuZrJyIMZtJu2wNh-TYSYs,79040
6
6
  flood_adapt/adapter/sfincs_offshore.py,sha256=DkqGwx0Fx4dojY1YH8tW3MUS4Omgd5DC6QINEsTP0Uk,7659
7
7
  flood_adapt/adapter/interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  flood_adapt/adapter/interface/hazard_adapter.py,sha256=S2NIUAMSRgxC_E-tZRJ2qIP06U1zEVdn-MnvMTrn86s,2828
@@ -17,9 +17,9 @@ flood_adapt/config/hazard.py,sha256=Ev6mj78cZ_vQuJ11KYjhJOzmfRB6fz267OJeKI0bYaM,
17
17
  flood_adapt/config/impacts.py,sha256=O7vE7jB3GSXnkqAvv7TqJiJ_j1uJ3mck_KQ-ScsB3bo,3192
18
18
  flood_adapt/config/sfincs.py,sha256=y8C3PzFwwgMB_sb8rBzgteaQ8fCxep6DnZxuk0q__bc,4825
19
19
  flood_adapt/config/site.py,sha256=VR90jCHWcxgoQJptNyXy7LseGjXUDRtdOjNGCddFVzI,4328
20
- flood_adapt/database_builder/__init__.py,sha256=YsI5bGcAKYmsmb5W-spp91hzsKSTRtkXBLNRxLOWml4,474
21
- flood_adapt/database_builder/database_builder.py,sha256=WHCsRGZq2owNyuLMpk2wEnGR2QrELAVDqJfE8xG12JE,100855
22
- flood_adapt/database_builder/metrics_utils.py,sha256=VCLhEIViwlmGxh9LBoEGMsRcSEvktiKvh8IolUjHPfI,66459
20
+ flood_adapt/database_builder/__init__.py,sha256=nofsq8RqgoCKHXGq6P2ZN01H_GYbEpOzyQu0N_73suQ,901
21
+ flood_adapt/database_builder/database_builder.py,sha256=f9k-xbS5RC7fNs_qQZaSBvQO2es03OEfvCkWBO5qSGc,103498
22
+ flood_adapt/database_builder/metrics_utils.py,sha256=aU7YfXLmBjFT0fQQQl3o0yIzdFJ6XJGlld0GnkJytGc,66258
23
23
  flood_adapt/database_builder/templates/default_units/imperial.toml,sha256=zIjPlxIa2kWLUjSYisd8UolXGo5iKdFoDDz_JkKBXTM,295
24
24
  flood_adapt/database_builder/templates/default_units/metric.toml,sha256=tc0XMKs7xGL9noB9lAb0gyQfjYxzokgHa3NqpccxWl0,302
25
25
  flood_adapt/database_builder/templates/green_infra_table/green_infra_lookup_table.csv,sha256=ooQzNGQwAMSAphy5W2ZyR5boQlcwvPv9ToJx1MlZhVE,466
@@ -56,7 +56,7 @@ flood_adapt/database_builder/templates/infographics/images/truck.png,sha256=0Ihv
56
56
  flood_adapt/database_builder/templates/infographics/images/walking_person.png,sha256=vaxO4oGejK5Q4KyGXuew2YgpGPabpnwLyxTFH1WMbmo,11080
57
57
  flood_adapt/database_builder/templates/output_layers/bin_colors.toml,sha256=yN3_h2IimOyjtfhZ-ZoWyNa-2cAeFRNlbvaNTLhEMfA,417
58
58
  flood_adapt/dbs_classes/__init__.py,sha256=J-a6BEkjDhuUzzRKuAn_AtTg_D9wNIsmY3BnVTiC2JA,731
59
- flood_adapt/dbs_classes/database.py,sha256=6zYAhVJVL3bNjxEzObVn4jOnuSQJYmsEuWN85fOeDT4,23425
59
+ flood_adapt/dbs_classes/database.py,sha256=2OxzIrZOLmgv3wpq6cIKer1gchM6MuU2S9r2cHUZ4i8,23429
60
60
  flood_adapt/dbs_classes/dbs_benefit.py,sha256=ayEYz8ga49HLdYuUsDWZOuZnpRnBpTuyhvfe2IyWAKI,1825
61
61
  flood_adapt/dbs_classes/dbs_event.py,sha256=ak3kHan6L1EfC8agDLKiCe8gaY5leOmj_qUBsI61q9A,1869
62
62
  flood_adapt/dbs_classes/dbs_measure.py,sha256=vVs-LtnHJN7eSGIFUglJdpbtfq_QI_Ftkv4lh5mfnNM,4085
@@ -95,7 +95,7 @@ flood_adapt/objects/forcing/meteo_handler.py,sha256=rTxY5WNobK_Ifzj2eVcoSPGgb3Tz
95
95
  flood_adapt/objects/forcing/netcdf.py,sha256=ZBzFtN5joVs36lVjvYErVaHEylUQ6eKIhR0uk_MD-zM,1388
96
96
  flood_adapt/objects/forcing/plotting.py,sha256=Y7f_9bY8d9jbd7BqEAeRmof-aaJhlznM3_wGBOI7g-s,14828
97
97
  flood_adapt/objects/forcing/rainfall.py,sha256=e6P3IMzItvnsmXbcMXl1oV-d9LDuh3jTIc_vt6Kz5zo,3282
98
- flood_adapt/objects/forcing/tide_gauge.py,sha256=jGIh6jQlhecGkPfBaZ8NKbr7FlpmLZAwmlqgp8lEWu0,7143
98
+ flood_adapt/objects/forcing/tide_gauge.py,sha256=XhplyNHtCn0hRM1oeD5v-fMYAOLAJIKidmxKxVxCUlw,7188
99
99
  flood_adapt/objects/forcing/time_frame.py,sha256=1X3G0Ax18BHRvAomf-CW_ISRk_3qgAakwgZCIBxIkL4,2855
100
100
  flood_adapt/objects/forcing/timeseries.py,sha256=bD27JWzC3owq5ah3zPzJ7xoUzSH_t4J03s_SycYW0mQ,19740
101
101
  flood_adapt/objects/forcing/unit_system.py,sha256=EHz4ixI8nmjfDeyU2AszXTf6ebaqChbGg0PuJHMJdh8,16502
@@ -114,8 +114,8 @@ flood_adapt/objects/strategies/strategies.py,sha256=Jw-WJDCamL9p_7VEir3AdmYPMVAi
114
114
  flood_adapt/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
115
  flood_adapt/workflows/benefit_runner.py,sha256=eA21TuHdeZ6QYO8ehXri6BHlkyHsVsZphIdIca5g0KA,21824
116
116
  flood_adapt/workflows/scenario_runner.py,sha256=9_Y6GmMYhYoTRkBUIlju0eBy6DosGf4Zl2tgu1QEubI,4119
117
- flood_adapt-1.1.1.dist-info/LICENSE,sha256=Ui5E03pQ0EVKxvKA54lTPA1xrtgA2HMGLQai95eOzoE,36321
118
- flood_adapt-1.1.1.dist-info/METADATA,sha256=ZCiBsiXoCBBXNEMSsEhJbI5wZiVyW6aVH6EVZBaJY8k,48876
119
- flood_adapt-1.1.1.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
120
- flood_adapt-1.1.1.dist-info/top_level.txt,sha256=JvzMi6cTcQPEThCfpgMEeVny3ghI1urSH0CCgVIqSzw,12
121
- flood_adapt-1.1.1.dist-info/RECORD,,
117
+ flood_adapt-1.1.3.dist-info/LICENSE,sha256=Ui5E03pQ0EVKxvKA54lTPA1xrtgA2HMGLQai95eOzoE,36321
118
+ flood_adapt-1.1.3.dist-info/METADATA,sha256=7QOIs6mTL4QYNxEd9YCX7uNCWaAOfj_wtRg4buQi9NI,48876
119
+ flood_adapt-1.1.3.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
120
+ flood_adapt-1.1.3.dist-info/top_level.txt,sha256=JvzMi6cTcQPEThCfpgMEeVny3ghI1urSH0CCgVIqSzw,12
121
+ flood_adapt-1.1.3.dist-info/RECORD,,