flood-adapt 0.3.7__py3-none-any.whl → 0.3.9__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__ = "0.3.7"
2
+ __version__ = "0.3.9"
3
3
 
4
4
  from flood_adapt import adapter, dbs_classes, objects
5
5
  from flood_adapt.config.config import Settings
@@ -85,7 +85,7 @@ class FiatAdapter(IImpactAdapter):
85
85
  # TODO deal with all the relative paths for the files used
86
86
  # TODO IImpactAdapter and general Adapter class should NOT use the database
87
87
 
88
- _model: FiatModel # hydroMT-FIAT model
88
+ _model: Optional[FiatModel] = None
89
89
  config: Optional[FiatConfigModel] = None
90
90
  exe_path: Optional[os.PathLike] = None
91
91
  fiat_columns: FiatColumns
@@ -106,20 +106,27 @@ class FiatAdapter(IImpactAdapter):
106
106
  self.config_base_path = config_base_path
107
107
  self.exe_path = exe_path
108
108
  self.delete_crashed_runs = delete_crashed_runs
109
- self._model = FiatModel(root=str(model_root.resolve()), mode="r")
110
- self._model.read()
109
+ self._model_root = str(model_root.resolve())
111
110
  self.fiat_columns = _FIAT_COLUMNS
112
111
  self.impact_columns = _IMPACT_COLUMNS # columns of FA impact output
113
112
 
113
+ @property
114
+ def model(self) -> FiatModel:
115
+ """Lazily load and cache the FiatModel."""
116
+ if self._model is None:
117
+ self._model = FiatModel(root=self._model_root, mode="r")
118
+ self._model.read()
119
+ return self._model
120
+
114
121
  @property
115
122
  def model_root(self):
116
- return Path(self._model.root)
123
+ return Path(self.model.root)
117
124
 
118
125
  @property
119
126
  def damage_types(self):
120
127
  """Get the damage types that are present in the exposure."""
121
128
  types = []
122
- for col in self._model.exposure.exposure_db.columns:
129
+ for col in self.model.exposure.exposure_db.columns:
123
130
  if matches_pattern(col, self.fiat_columns.damage_function):
124
131
  name = extract_variables(col, self.fiat_columns.damage_function)["name"]
125
132
  types.append(name)
@@ -127,9 +134,9 @@ class FiatAdapter(IImpactAdapter):
127
134
 
128
135
  def read(self, path: Path) -> None:
129
136
  """Read the fiat model from the current model root."""
130
- if Path(self._model.root).resolve() != Path(path).resolve():
131
- self._model.set_root(root=str(path), mode="r")
132
- self._model.read()
137
+ if Path(self.model.root).resolve() != Path(path).resolve():
138
+ self.model.set_root(root=str(path), mode="r")
139
+ self.model.read()
133
140
 
134
141
  def write(self, path_out: Union[str, os.PathLike], overwrite: bool = True) -> None:
135
142
  """Write the fiat model configuration to a directory."""
@@ -141,8 +148,8 @@ class FiatAdapter(IImpactAdapter):
141
148
 
142
149
  write_mode = "w+" if overwrite else "w"
143
150
  with cd(path_out):
144
- self._model.set_root(root=str(path_out), mode=write_mode)
145
- self._model.write()
151
+ self.model.set_root(root=str(path_out), mode=write_mode)
152
+ self.model.write()
146
153
 
147
154
  def close_files(self):
148
155
  """Close all open files and clean up file handles."""
@@ -206,7 +213,7 @@ class FiatAdapter(IImpactAdapter):
206
213
  True if fiat has run, False if something went wrong
207
214
  """
208
215
  log_file = self.model_root.joinpath(
209
- self._model.config["output"]["path"], "fiat.log"
216
+ self.model.config["output"]["path"], "fiat.log"
210
217
  )
211
218
  if not log_file.exists():
212
219
  return False
@@ -365,13 +372,13 @@ class FiatAdapter(IImpactAdapter):
365
372
  The contents of the output CSV file.
366
373
  """
367
374
  # Get output path
368
- outputs_path = self.model_root.joinpath(self._model.config["output"]["path"])
375
+ outputs_path = self.model_root.joinpath(self.model.config["output"]["path"])
369
376
 
370
377
  # Get all csvs and concatenate them in a single table
371
378
  csv_outputs_df = []
372
- for output_csv in self._model.config["output"]["csv"]:
379
+ for output_csv in self.model.config["output"]["csv"]:
373
380
  csv_path = outputs_path.joinpath(
374
- self._model.config["output"]["csv"][output_csv]
381
+ self.model.config["output"]["csv"][output_csv]
375
382
  )
376
383
  output_csv_df = pd.read_csv(csv_path)
377
384
  csv_outputs_df.append(output_csv_df)
@@ -700,9 +707,9 @@ class FiatAdapter(IImpactAdapter):
700
707
  self.logger.info(f"Setting hazard to the {map_type} map {map_fn}")
701
708
  # Add the floodmap data to a data catalog with the unit conversion
702
709
  wl_current_units = us.UnitfulLength(value=1.0, units=units)
703
- conversion_factor = wl_current_units.convert(self._model.exposure.unit)
710
+ conversion_factor = wl_current_units.convert(self.model.exposure.unit)
704
711
 
705
- self._model.setup_hazard(
712
+ self.model.setup_hazard(
706
713
  map_fn=map_fn,
707
714
  map_type=map_type,
708
715
  rp=None,
@@ -737,29 +744,29 @@ class FiatAdapter(IImpactAdapter):
737
744
  # Get columns that include max damage
738
745
  damage_cols = [
739
746
  c
740
- for c in self._model.exposure.exposure_db.columns
747
+ for c in self.model.exposure.exposure_db.columns
741
748
  if matches_pattern(c, self.fiat_columns.max_potential_damage)
742
749
  ]
743
750
 
744
751
  # Get objects that are buildings (using site info)
745
- buildings_rows = ~self._model.exposure.exposure_db[
752
+ buildings_rows = ~self.model.exposure.exposure_db[
746
753
  self.fiat_columns.primary_object_type
747
754
  ].isin(self.config.non_building_names)
748
755
 
749
756
  # If ids are given use that as an additional filter
750
757
  if ids:
751
- buildings_rows = buildings_rows & self._model.exposure.exposure_db[
758
+ buildings_rows = buildings_rows & self.model.exposure.exposure_db[
752
759
  self.fiat_columns.object_id
753
760
  ].isin(ids)
754
761
 
755
762
  # Update columns using economic growth value
756
- updated_max_pot_damage = self._model.exposure.exposure_db.copy()
763
+ updated_max_pot_damage = self.model.exposure.exposure_db.copy()
757
764
  updated_max_pot_damage.loc[buildings_rows, damage_cols] *= (
758
765
  1.0 + economic_growth / 100.0
759
766
  )
760
767
 
761
768
  # update fiat model
762
- self._model.exposure.update_max_potential_damage(
769
+ self.model.exposure.update_max_potential_damage(
763
770
  updated_max_potential_damages=updated_max_pot_damage
764
771
  )
765
772
 
@@ -784,29 +791,29 @@ class FiatAdapter(IImpactAdapter):
784
791
  # Get columns that include max damage
785
792
  damage_cols = [
786
793
  c
787
- for c in self._model.exposure.exposure_db.columns
794
+ for c in self.model.exposure.exposure_db.columns
788
795
  if matches_pattern(c, self.fiat_columns.max_potential_damage)
789
796
  ]
790
797
 
791
798
  # Get objects that are buildings (using site info)
792
- buildings_rows = ~self._model.exposure.exposure_db[
799
+ buildings_rows = ~self.model.exposure.exposure_db[
793
800
  self.fiat_columns.primary_object_type
794
801
  ].isin(self.config.non_building_names)
795
802
 
796
803
  # If ids are given use that as an additional filter
797
804
  if ids:
798
- buildings_rows = buildings_rows & self._model.exposure.exposure_db[
805
+ buildings_rows = buildings_rows & self.model.exposure.exposure_db[
799
806
  self.fiat_columns.object_id
800
807
  ].isin(ids)
801
808
 
802
809
  # Update columns using economic growth value
803
- updated_max_pot_damage = self._model.exposure.exposure_db.copy()
810
+ updated_max_pot_damage = self.model.exposure.exposure_db.copy()
804
811
  updated_max_pot_damage.loc[buildings_rows, damage_cols] *= (
805
812
  1.0 + population_growth / 100.0
806
813
  )
807
814
 
808
815
  # update fiat model
809
- self._model.exposure.update_max_potential_damage(
816
+ self.model.exposure.update_max_potential_damage(
810
817
  updated_max_potential_damages=updated_max_pot_damage
811
818
  )
812
819
 
@@ -841,7 +848,7 @@ class FiatAdapter(IImpactAdapter):
841
848
  If `elevation_type` is not 'floodmap' or 'datum'.
842
849
  """
843
850
  self.logger.info(
844
- f"Applying population growth of {population_growth} %, by creating a new development area using the geometries from {area_path} and a ground floor height of {ground_floor_height} {self._model.exposure.unit} above '{elevation_type}'."
851
+ f"Applying population growth of {population_growth} %, by creating a new development area using the geometries from {area_path} and a ground floor height of {ground_floor_height} {self.model.exposure.unit} above '{elevation_type}'."
845
852
  )
846
853
  # Get reference type to align with hydromt
847
854
  if elevation_type == "floodmap":
@@ -870,12 +877,12 @@ class FiatAdapter(IImpactAdapter):
870
877
  ]
871
878
  new_dev_geom_name = Path(self.config.new_development_file_name).stem
872
879
  # Use hydromt function
873
- self._model.exposure.setup_new_composite_areas(
880
+ self.model.exposure.setup_new_composite_areas(
874
881
  percent_growth=population_growth,
875
882
  geom_file=Path(area_path),
876
883
  ground_floor_height=ground_floor_height,
877
884
  damage_types=self.damage_types,
878
- vulnerability=self._model.vulnerability,
885
+ vulnerability=self.model.vulnerability,
879
886
  ground_elevation=ground_elevation,
880
887
  aggregation_area_fn=aggregation_areas,
881
888
  attribute_names=attribute_names,
@@ -944,7 +951,7 @@ class FiatAdapter(IImpactAdapter):
944
951
  path_ref = self.config_base_path.joinpath(self.config.bfe.geom)
945
952
  height_reference = "geom"
946
953
  # Use hydromt function
947
- self._model.exposure.raise_ground_floor_height(
954
+ self.model.exposure.raise_ground_floor_height(
948
955
  raise_by=elevate.elevation.value,
949
956
  objectids=objectids,
950
957
  height_reference=height_reference,
@@ -954,7 +961,7 @@ class FiatAdapter(IImpactAdapter):
954
961
 
955
962
  elif elevate.elevation.type == "datum":
956
963
  # Use hydromt function
957
- self._model.exposure.raise_ground_floor_height(
964
+ self.model.exposure.raise_ground_floor_height(
958
965
  raise_by=elevate.elevation.value,
959
966
  objectids=objectids,
960
967
  height_reference="datum",
@@ -979,30 +986,28 @@ class FiatAdapter(IImpactAdapter):
979
986
  # Get columns that include max damage
980
987
  damage_cols = [
981
988
  c
982
- for c in self._model.exposure.exposure_db.columns
989
+ for c in self.model.exposure.exposure_db.columns
983
990
  if matches_pattern(c, self.fiat_columns.max_potential_damage)
984
991
  ]
985
992
 
986
993
  # Get objects that are buildings (using site info)
987
- buildings_rows = ~self._model.exposure.exposure_db[
994
+ buildings_rows = ~self.model.exposure.exposure_db[
988
995
  self.fiat_columns.primary_object_type
989
996
  ].isin(self.config.non_building_names)
990
997
 
991
998
  # Get rows that are affected
992
999
  objectids = self.get_object_ids(buyout)
993
1000
  rows = (
994
- self._model.exposure.exposure_db[self.fiat_columns.object_id].isin(
995
- objectids
996
- )
1001
+ self.model.exposure.exposure_db[self.fiat_columns.object_id].isin(objectids)
997
1002
  & buildings_rows
998
1003
  )
999
1004
 
1000
1005
  # Update columns
1001
- updated_max_pot_damage = self._model.exposure.exposure_db.copy()
1006
+ updated_max_pot_damage = self.model.exposure.exposure_db.copy()
1002
1007
  updated_max_pot_damage.loc[rows, damage_cols] *= 0
1003
1008
 
1004
1009
  # update fiat model
1005
- self._model.exposure.update_max_potential_damage(
1010
+ self.model.exposure.update_max_potential_damage(
1006
1011
  updated_max_potential_damages=updated_max_pot_damage
1007
1012
  )
1008
1013
 
@@ -1023,11 +1028,11 @@ class FiatAdapter(IImpactAdapter):
1023
1028
  objectids = self.get_object_ids(floodproof)
1024
1029
 
1025
1030
  # Use hydromt function
1026
- self._model.exposure.truncate_damage_function(
1031
+ self.model.exposure.truncate_damage_function(
1027
1032
  objectids=objectids,
1028
1033
  floodproof_to=floodproof.elevation.value,
1029
1034
  damage_function_types=self.damage_types,
1030
- vulnerability=self._model.vulnerability,
1035
+ vulnerability=self.model.vulnerability,
1031
1036
  )
1032
1037
 
1033
1038
  # STATIC METHODS
@@ -1046,11 +1051,11 @@ class FiatAdapter(IImpactAdapter):
1046
1051
  ValueError
1047
1052
  If the FIAT model does not have an exposure database initialized.
1048
1053
  """
1049
- if self._model.exposure is None:
1054
+ if self.model.exposure is None:
1050
1055
  raise ValueError(
1051
1056
  "FIAT model does not have exposure, make sure your model has been initialized."
1052
1057
  )
1053
- gdf_0 = self._model.exposure.select_objects(
1058
+ gdf_0 = self.model.exposure.select_objects(
1054
1059
  primary_object_type="ALL",
1055
1060
  non_building_names=self.config.non_building_names,
1056
1061
  return_gdf=True,
@@ -1081,7 +1086,7 @@ class FiatAdapter(IImpactAdapter):
1081
1086
  ValueError
1082
1087
  If no property types are found in the FIAT model.
1083
1088
  """
1084
- types = self._model.exposure.get_primary_object_type()
1089
+ types = self.model.exposure.get_primary_object_type()
1085
1090
  if types is None:
1086
1091
  raise ValueError("No property types found in the FIAT model.")
1087
1092
  types.append("all") # Add "all" type for using as identifier
@@ -1104,7 +1109,7 @@ class FiatAdapter(IImpactAdapter):
1104
1109
  A list of IDs for all buildings in the FIAT model.
1105
1110
  """
1106
1111
  # Get ids of existing buildings
1107
- ids = self._model.exposure.get_object_ids(
1112
+ ids = self.model.exposure.get_object_ids(
1108
1113
  "all", non_building_names=self.config.non_building_names
1109
1114
  )
1110
1115
  return ids
@@ -1145,7 +1150,7 @@ class FiatAdapter(IImpactAdapter):
1145
1150
  polygon_file = None
1146
1151
 
1147
1152
  # use the hydromt-fiat method to the ids
1148
- ids = self._model.exposure.get_object_ids(
1153
+ ids = self.model.exposure.get_object_ids(
1149
1154
  selection_type=measure.selection_type,
1150
1155
  property_type=measure.property_type,
1151
1156
  non_building_names=self.config.non_building_names,
@@ -1407,7 +1412,7 @@ class FiatAdapter(IImpactAdapter):
1407
1412
  self.logger.info("Calculating impacts at a building footprint scale")
1408
1413
 
1409
1414
  # Read the existing building points
1410
- buildings = self._model.exposure.select_objects(
1415
+ buildings = self.model.exposure.select_objects(
1411
1416
  primary_object_type="ALL",
1412
1417
  non_building_names=self.config.non_building_names,
1413
1418
  return_gdf=True,
@@ -12,7 +12,6 @@ import hydromt_sfincs.utils as utils
12
12
  import numpy as np
13
13
  import pandas as pd
14
14
  import plotly.express as px
15
- import plotly.graph_objects as go
16
15
  import pyproj
17
16
  import shapely
18
17
  import xarray as xr
@@ -201,7 +200,7 @@ class SfincsAdapter(IHazardAdapter):
201
200
  with cd(path):
202
201
  self.logger.info(f"Running SFINCS in {path}")
203
202
  process = subprocess.run(
204
- str(Settings().sfincs_path),
203
+ str(Settings().sfincs_bin_path),
205
204
  stdout=subprocess.PIPE,
206
205
  stderr=subprocess.PIPE,
207
206
  text=True,
@@ -677,7 +676,8 @@ class SfincsAdapter(IHazardAdapter):
677
676
  )
678
677
 
679
678
  event = self.database.events.get(scenario.event)
680
- self._add_tide_gauge_plot(fig, event, units=gui_units)
679
+ if self.settings.obs_point[ii].name == self.settings.tide_gauge.name:
680
+ self._add_tide_gauge_plot(fig, event, units=gui_units)
681
681
 
682
682
  # write html to results folder
683
683
  station_name = gdf.iloc[ii]["Name"]
@@ -686,26 +686,27 @@ class SfincsAdapter(IHazardAdapter):
686
686
 
687
687
  def add_obs_points(self):
688
688
  """Add observation points provided in the site toml to SFINCS model."""
689
- if self.settings.obs_point is not None:
690
- self.logger.info("Adding observation points to the overland flood model")
691
-
692
- obs_points = self.settings.obs_point
693
- names = []
694
- lat = []
695
- lon = []
696
- for pt in obs_points:
697
- names.append(pt.name)
698
- lat.append(pt.lat)
699
- lon.append(pt.lon)
689
+ if self.settings.obs_point is None:
690
+ return
691
+ self.logger.info("Adding observation points to the overland flood model")
700
692
 
701
- # create GeoDataFrame from obs_points in site file
702
- df = pd.DataFrame({"name": names})
703
- gdf = gpd.GeoDataFrame(
704
- df, geometry=gpd.points_from_xy(lon, lat), crs="EPSG:4326"
705
- )
693
+ obs_points = self.settings.obs_point
694
+ names = []
695
+ lat = []
696
+ lon = []
697
+ for pt in obs_points:
698
+ names.append(pt.name)
699
+ lat.append(pt.lat)
700
+ lon.append(pt.lon)
701
+
702
+ # create GeoDataFrame from obs_points in site file
703
+ df = pd.DataFrame({"name": names})
704
+ gdf = gpd.GeoDataFrame(
705
+ df, geometry=gpd.points_from_xy(lon, lat), crs="EPSG:4326"
706
+ )
706
707
 
707
- # Add locations to SFINCS file
708
- self._model.setup_observation_points(locations=gdf, merge=False)
708
+ # Add locations to SFINCS file
709
+ self._model.setup_observation_points(locations=gdf, merge=False)
709
710
 
710
711
  def get_wl_df_from_offshore_his_results(self) -> pd.DataFrame:
711
712
  """Create a pd.Dataframe with waterlevels from the offshore model at the bnd locations of the overland model.
@@ -1840,11 +1841,7 @@ class SfincsAdapter(IHazardAdapter):
1840
1841
 
1841
1842
  # If data is available, add to plot
1842
1843
  fig.add_trace(
1843
- go.Scatter(
1844
- x=pd.DatetimeIndex(df_gauge.index),
1845
- y=waterlevel,
1846
- line_color="#ea6404",
1847
- )
1844
+ px.line(waterlevel, color_discrete_sequence=["#ea6404"]).data[0]
1848
1845
  )
1849
1846
  fig["data"][0]["name"] = "model"
1850
1847
  fig["data"][1]["name"] = "measurement"
@@ -1,6 +1,6 @@
1
1
  from os import environ, listdir
2
2
  from pathlib import Path
3
- from platform import system
3
+ from typing import Optional
4
4
 
5
5
  import tomli
6
6
  import tomli_w
@@ -12,48 +12,6 @@ from pydantic import (
12
12
  )
13
13
  from pydantic_settings import BaseSettings, SettingsConfigDict
14
14
 
15
- DEFAULT_SYSTEM_FOLDER = Path(__file__).parents[1] / "system"
16
- DEFAULT_EXE_PATHS: dict[str, dict[str, Path]] = {
17
- "windows": {
18
- "sfincs": DEFAULT_SYSTEM_FOLDER / "win-64" / "sfincs" / "sfincs.exe",
19
- "fiat": DEFAULT_SYSTEM_FOLDER / "win-64" / "fiat" / "fiat.exe",
20
- },
21
- "linux": {
22
- "sfincs": DEFAULT_SYSTEM_FOLDER / "linux-64" / "sfincs" / "bin" / "sfincs",
23
- "fiat": DEFAULT_SYSTEM_FOLDER / "linux-64" / "fiat" / "fiat",
24
- },
25
- }
26
-
27
-
28
- def _default_exe_path(exe_name: str) -> Path:
29
- """
30
- Get the default path for the given executable name based on the system type.
31
-
32
- Parameters
33
- ----------
34
- exe_name : str
35
- The name of the executable (e.g., "sfincs", "fiat").
36
-
37
- Returns
38
- -------
39
- Path
40
- The default path to the executable.
41
-
42
- Raises
43
- ------
44
- ValueError
45
- If the system type is not recognized.
46
- """
47
- if system().lower() not in DEFAULT_EXE_PATHS:
48
- raise ValueError(
49
- f"System type '{system()}' is not recognized. Supported types are: {', '.join(DEFAULT_EXE_PATHS.keys())}."
50
- )
51
- if exe_name not in DEFAULT_EXE_PATHS[system().lower()]:
52
- raise ValueError(
53
- f"Executable name '{exe_name}' is not recognized. Supported names are: {', '.join(DEFAULT_EXE_PATHS[system().lower()].keys())}."
54
- )
55
- return DEFAULT_EXE_PATHS[system().lower()][exe_name]
56
-
57
15
 
58
16
  class Settings(BaseSettings):
59
17
  """
@@ -82,19 +40,19 @@ class Settings(BaseSettings):
82
40
  Attributes
83
41
  ----------
84
42
  database_name : str
85
- The name of the database.
43
+ The name of the database. Alias: `DATABASE_NAME` (environment variable).
86
44
  database_root : Path
87
- The root directory of the database.
45
+ The root directory of the database. Alias: `DATABASE_ROOT` (environment variable).
88
46
  delete_crashed_runs : bool
89
- Whether to delete crashed/corrupted runs immediately after they are detected.
90
- sfincs_path : Path
91
- The path to the SFINCS binary.
92
- fiat_path : Path
93
- The path to the FIAT binary.
47
+ Whether to delete crashed/corrupted runs immediately after they are detected. Alias: `DELETE_CRASHED_RUNS` (environment variable).
94
48
  validate_allowed_forcings : bool
95
- Whether to validate the forcing types and sources against the allowed forcings in the event model.
96
- validate_bin_paths : bool
97
- Whether to validate the existence of the paths to the SFINCS and FIAT binaries.
49
+ Whether to validate the forcing types and sources against the allowed forcings in the event model. Alias: `VALIDATE_ALLOWED_FORCINGS` (environment variable).
50
+ validate_binaries : bool
51
+ Whether to validate the existence of the paths to the SFINCS and FIAT binaries. Alias: `VALIDATE_BINARIES` (environment variable).
52
+ sfincs_bin_path : Path
53
+ The path to the SFINCS binary. Alias: `SFINCS_BIN_PATH` (environment variable).
54
+ fiat_bin_path : Path
55
+ The path to the FIAT binary. Alias: `FIAT_BIN_PATH` (environment variable).
98
56
 
99
57
  Properties
100
58
  ----------
@@ -133,22 +91,22 @@ class Settings(BaseSettings):
133
91
  description="Whether to validate the forcing types and sources against the allowed forcings in the event model.",
134
92
  exclude=True,
135
93
  )
136
- validate_bin_paths: bool = Field(
94
+ validate_binaries: bool = Field(
137
95
  alias="VALIDATE_BINARIES", # environment variable: VALIDATE_BINARIES
138
96
  default=False,
139
97
  description="Whether to validate the existence of the paths to the SFINCS and FIAT binaries.",
140
98
  exclude=True,
141
99
  )
142
100
 
143
- sfincs_path: Path = Field(
144
- default=_default_exe_path("sfincs"),
101
+ sfincs_bin_path: Optional[Path] = Field(
102
+ default=None,
145
103
  alias="SFINCS_BIN_PATH", # environment variable: SFINCS_BIN_PATH
146
104
  description="The path of the sfincs binary.",
147
105
  exclude=True,
148
106
  )
149
107
 
150
- fiat_path: Path = Field(
151
- default=_default_exe_path("fiat"),
108
+ fiat_bin_path: Optional[Path] = Field(
109
+ default=None,
152
110
  alias="FIAT_BIN_PATH", # environment variable: FIAT_BIN_PATH
153
111
  description="The path of the fiat binary.",
154
112
  exclude=True,
@@ -162,7 +120,7 @@ class Settings(BaseSettings):
162
120
  @model_validator(mode="after")
163
121
  def validate_settings(self):
164
122
  self._validate_database_path()
165
- if self.validate_bin_paths:
123
+ if self.validate_binaries:
166
124
  self._validate_fiat_path()
167
125
  self._validate_sfincs_path()
168
126
  self._update_environment_variables()
@@ -171,21 +129,21 @@ class Settings(BaseSettings):
171
129
  def _update_environment_variables(self):
172
130
  environ["DATABASE_ROOT"] = str(self.database_root)
173
131
  environ["DATABASE_NAME"] = self.database_name
174
- environ["SFINCS_BIN_PATH"] = str(self.sfincs_path)
175
- environ["FIAT_BIN_PATH"] = str(self.fiat_path)
176
- environ["SFINCS_PATH"] = str(self.sfincs_path)
177
- environ["FIAT_PATH"] = str(self.fiat_path)
178
132
 
179
133
  if self.delete_crashed_runs:
180
134
  environ["DELETE_CRASHED_RUNS"] = str(self.delete_crashed_runs)
181
135
  else:
182
136
  environ.pop("DELETE_CRASHED_RUNS", None)
137
+
183
138
  if self.validate_allowed_forcings:
184
139
  environ["VALIDATE_ALLOWED_FORCINGS"] = str(self.validate_allowed_forcings)
185
140
  else:
186
141
  environ.pop("VALIDATE_ALLOWED_FORCINGS", None)
187
- if self.validate_bin_paths:
188
- environ["VALIDATE_BINARIES"] = str(self.validate_bin_paths)
142
+
143
+ if self.validate_binaries:
144
+ environ["VALIDATE_BINARIES"] = str(self.validate_binaries)
145
+ environ["SFINCS_BIN_PATH"] = str(self.sfincs_bin_path)
146
+ environ["FIAT_BIN_PATH"] = str(self.fiat_bin_path)
189
147
  else:
190
148
  environ.pop("VALIDATE_BINARIES", None)
191
149
 
@@ -224,13 +182,13 @@ class Settings(BaseSettings):
224
182
  return self
225
183
 
226
184
  def _validate_sfincs_path(self):
227
- if not self.sfincs_path.exists():
228
- raise ValueError(f"SFINCS binary {self.sfincs_path} does not exist.")
185
+ if not self.sfincs_bin_path.exists():
186
+ raise ValueError(f"SFINCS binary {self.sfincs_bin_path} does not exist.")
229
187
  return self
230
188
 
231
189
  def _validate_fiat_path(self):
232
- if not self.fiat_path.exists():
233
- raise ValueError(f"FIAT binary {self.fiat_path} does not exist.")
190
+ if not self.fiat_bin_path.exists():
191
+ raise ValueError(f"FIAT binary {self.fiat_bin_path} does not exist.")
234
192
  return self
235
193
 
236
194
  @field_serializer("database_root", "database_path")
@@ -284,7 +242,7 @@ class Settings(BaseSettings):
284
242
  tomli_w.dump(
285
243
  self.model_dump(
286
244
  by_alias=True,
287
- exclude={"sfincs_path", "fiat_path", "database_path"},
245
+ exclude={"sfincs_bin_path", "fiat_bin_path", "database_path"},
288
246
  ),
289
247
  f,
290
248
  )
@@ -209,7 +209,7 @@ class FiatModel(BaseModel):
209
209
  config: FiatConfigModel
210
210
 
211
211
  benefits: Optional[BenefitsModel] = None
212
- risk: Optional[RiskModel] = None
212
+ risk: Optional[RiskModel] = RiskModel()
213
213
 
214
214
  @staticmethod
215
215
  def read_toml(path: Path) -> "FiatModel":
@@ -1280,9 +1280,9 @@ class DatabaseBuilder:
1280
1280
  relative_to_year=self.config.slr_scenarios.relative_to_year,
1281
1281
  )
1282
1282
 
1283
- def create_observation_points(self) -> list[ObsPointModel]:
1283
+ def create_observation_points(self) -> Union[list[ObsPointModel], None]:
1284
1284
  if self.config.obs_point is None:
1285
- return []
1285
+ return None
1286
1286
 
1287
1287
  self.logger.info("Observation points were provided in the config file.")
1288
1288
  return self.config.obs_point
@@ -14,7 +14,6 @@ from geopandas import GeoDataFrame
14
14
  from plotly.express import line
15
15
  from plotly.express.colors import sample_colorscale
16
16
 
17
- from flood_adapt.config.config import Settings
18
17
  from flood_adapt.config.site import Site
19
18
  from flood_adapt.dbs_classes.dbs_benefit import DbsBenefit
20
19
  from flood_adapt.dbs_classes.dbs_event import DbsEvent
@@ -336,7 +335,7 @@ class Database(IDatabase):
336
335
  benefit : Benefit
337
336
  """
338
337
  runner = BenefitRunner(self, benefit=benefit)
339
- return runner.check_scenarios()
338
+ return runner.scenarios
340
339
 
341
340
  def create_benefit_scenarios(self, benefit: Benefit) -> None:
342
341
  """Create any scenarios that are needed for the (cost-)benefit assessment and are not there already.
@@ -346,7 +345,6 @@ class Database(IDatabase):
346
345
  benefit : Benefit
347
346
  """
348
347
  runner = BenefitRunner(self, benefit=benefit)
349
- runner.check_scenarios()
350
348
 
351
349
  # Iterate through the scenarios needed and create them if not existing
352
350
  for index, row in runner.scenarios.iterrows():
@@ -369,9 +367,6 @@ class Database(IDatabase):
369
367
  raise e
370
368
  # otherwise, if it already exists and we dont need to save it, we can just continue
371
369
 
372
- # Update the scenarios check
373
- runner.check_scenarios()
374
-
375
370
  def run_benefit(self, benefit_name: Union[str, list[str]]) -> None:
376
371
  """Run a (cost-)benefit analysis.
377
372
 
@@ -654,9 +649,6 @@ class Database(IDatabase):
654
649
  - does not have a corresponding input
655
650
 
656
651
  """
657
- if not Settings().delete_crashed_runs:
658
- return
659
-
660
652
  if not self.scenarios.output_path.is_dir():
661
653
  return
662
654
 
@@ -78,7 +78,7 @@ class DbsScenario(DbsTemplate[Scenario]):
78
78
  used_in_benefit = []
79
79
  for benefit in benefits:
80
80
  runner = BenefitRunner(database=self._database, benefit=benefit)
81
- scenarios = runner.check_scenarios()["scenario created"].to_list()
81
+ scenarios = runner.scenarios["scenario created"].to_list()
82
82
  for scenario in scenarios:
83
83
  if name == scenario:
84
84
  used_in_benefit.append(benefit.name)
@@ -48,7 +48,8 @@ class DbsStatic(IDbsStatic):
48
48
  self.get_model_boundary()
49
49
  self.get_model_grid()
50
50
  self.get_obs_points()
51
- self.get_slr_scn_names()
51
+ if self._database.site.sfincs.slr_scenarios is not None:
52
+ self.get_slr_scn_names()
52
53
  self.get_buildings()
53
54
  self.get_property_types()
54
55
 
@@ -252,7 +253,7 @@ class DbsStatic(IDbsStatic):
252
253
  with FiatAdapter(
253
254
  model_root=template_path,
254
255
  config=self._database.site.fiat.config,
255
- exe_path=Settings().fiat_path,
256
+ exe_path=Settings().fiat_bin_path,
256
257
  delete_crashed_runs=Settings().delete_crashed_runs,
257
258
  config_base_path=self._database.static_path,
258
259
  ) as fm:
@@ -1,8 +1,9 @@
1
+ import math
1
2
  import os
2
3
  from pathlib import Path
3
4
  from typing import Optional
4
5
 
5
- from pydantic import BaseModel, Field
6
+ from pydantic import BaseModel, Field, model_validator
6
7
 
7
8
  from flood_adapt.misc.utils import resolve_filepath, save_file_to_database
8
9
  from flood_adapt.objects.forcing import unit_system as us
@@ -40,15 +41,15 @@ class SocioEconomicChange(BaseModel):
40
41
  Attributes
41
42
  ----------
42
43
  population_growth_existing : float
43
- The existing population growth rate. default=0.0
44
+ The population growth percentage of the existing area. default=0.0
44
45
  economic_growth : float
45
- The economic growth rate. default=0.0.
46
+ The economic growth percentage. default=0.0.
46
47
  population_growth_new : float
47
- The population growth rate for new developments. default=0.0.
48
+ The population growth percentage for the new development areas. default=0.0.
48
49
  new_development_elevation : Optional[us.UnitfulLengthRefValue]
49
- The elevation of new developments. default=None.
50
+ The elevation of the new development areas. default=None.
50
51
  new_development_shapefile : Optional[str]
51
- The path to the shapefile of new developments. default=None.
52
+ The path to the shapefile of the new development areas. default=None.
52
53
  """
53
54
 
54
55
  population_growth_existing: Optional[float] = 0.0
@@ -58,6 +59,15 @@ class SocioEconomicChange(BaseModel):
58
59
  new_development_elevation: Optional[us.UnitfulLengthRefValue] = None
59
60
  new_development_shapefile: Optional[str] = None
60
61
 
62
+ @model_validator(mode="after")
63
+ def validate_selection_type(self) -> "SocioEconomicChange":
64
+ if not math.isclose(self.population_growth_new or 0.0, 0.0, abs_tol=1e-8):
65
+ if self.new_development_shapefile is None:
66
+ raise ValueError(
67
+ "If `population_growth_new` is non-zero, then `new_development_shapefile` must also be provided."
68
+ )
69
+ return self
70
+
61
71
 
62
72
  class Projection(Object):
63
73
  """The accepted input for a projection in FloodAdapt.
@@ -66,6 +76,10 @@ class Projection(Object):
66
76
 
67
77
  Attributes
68
78
  ----------
79
+ name : str
80
+ Name of the object.
81
+ description : str
82
+ Description of the object. defaults to "".
69
83
  physical_projection : PhysicalProjection
70
84
  The physical projection model. Contains information about hazard drivers.
71
85
  socio_economic_change : SocioEconomicChange
@@ -73,8 +87,8 @@ class Projection(Object):
73
87
 
74
88
  """
75
89
 
76
- physical_projection: PhysicalProjection
77
- socio_economic_change: SocioEconomicChange
90
+ physical_projection: PhysicalProjection = PhysicalProjection()
91
+ socio_economic_change: SocioEconomicChange = SocioEconomicChange()
78
92
 
79
93
  def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
80
94
  if self.socio_economic_change.new_development_shapefile:
@@ -32,13 +32,24 @@ class BenefitRunner:
32
32
  self.benefit = benefit
33
33
 
34
34
  # Get output path based on database path
35
- self.check_scenarios()
36
35
  self.results_path = self.database.benefits.output_path.joinpath(
37
36
  self.benefit.name
38
37
  )
39
38
  self.site_info = self.database.site
40
39
  self.unit = self.site_info.fiat.config.damage_unit
41
40
 
41
+ @property
42
+ def scenarios(self) -> pd.DataFrame:
43
+ """Get the scenarios of the benefit analysis.
44
+
45
+ Returns
46
+ -------
47
+ pd.DataFrame
48
+ a table with the scenarios of the Benefit analysis and their status
49
+ """
50
+ self._scenarios = self.check_scenarios()
51
+ return self._scenarios
52
+
42
53
  @property
43
54
  def has_run(self):
44
55
  return self.has_run_check()
@@ -139,7 +150,7 @@ class BenefitRunner:
139
150
  scenarios_calc[scenario]["scenario run"] = False
140
151
 
141
152
  df = pd.DataFrame(scenarios_calc).T
142
- self.scenarios = df.astype(
153
+ scenarios = df.astype(
143
154
  dtype={
144
155
  "event": "str",
145
156
  "projection": "str",
@@ -148,7 +159,7 @@ class BenefitRunner:
148
159
  "scenario run": bool,
149
160
  }
150
161
  )
151
- return self.scenarios
162
+ return scenarios
152
163
 
153
164
  def ready_to_run(self) -> bool:
154
165
  """Check if all the required scenarios have already been run.
@@ -158,7 +169,6 @@ class BenefitRunner:
158
169
  bool
159
170
  True if required scenarios have been already run
160
171
  """
161
- self.check_scenarios()
162
172
  check = all(self.scenarios["scenario run"])
163
173
 
164
174
  return check
@@ -26,9 +26,12 @@ class Impacts(DatabaseUser):
26
26
  self.name = scenario.name
27
27
  self.scenario = scenario
28
28
  self.site_info = self.database.site
29
- self.models = [
30
- self.database.static.get_fiat_model()
31
- ] # for now only FIAT adapter
29
+
30
+ @property
31
+ def models(self):
32
+ """Return the list of impact models."""
33
+ models = [self.database.static.get_fiat_model()] # for now only FIAT adapter
34
+ return models
32
35
 
33
36
  @property
34
37
  def hazard(self) -> FloodMap:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: flood-adapt
3
- Version: 0.3.7
3
+ Version: 0.3.9
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: GNU GENERAL PUBLIC LICENSE
@@ -728,6 +728,8 @@ Requires-Dist: sphinx-rtd-theme<4.0,>=3.0; extra == "docs"
728
728
  Requires-Dist: regex<2025.0,>=2024.11; extra == "docs"
729
729
  Requires-Dist: minio<8,>=7.2.15; extra == "docs"
730
730
  Requires-Dist: python-dotenv<2.0,>=1.0; extra == "docs"
731
+ Requires-Dist: folium<1.0,>=0.19.0; extra == "docs"
732
+ Requires-Dist: mapclassify<3.0,>=2.8.0; extra == "docs"
731
733
  Provides-Extra: all
732
734
  Requires-Dist: flood-adapt[build,dev,docs]; extra == "all"
733
735
 
@@ -773,7 +775,7 @@ FloodAdapt uses a database to store, handle and organize input files, output fil
773
775
  To initialize FloodAdapt and configure the database, add the following lines to the top of your script / initialize function to validate and set the environment variables:
774
776
  ```python
775
777
  from pathlib import Path
776
- from flood_adapt.misc.config import Settings
778
+ from flood_adapt import Settings
777
779
 
778
780
  # Usually ends in `Database` and can contain multiple sites
779
781
  root = Path("path/to/your/database/root")
@@ -781,14 +783,17 @@ root = Path("path/to/your/database/root")
781
783
  # Specifies which site to use
782
784
  name = "database_name"
783
785
 
784
- # Contains the model kernels to run that perform the calculations
785
- system_folder = Path("path/to/your/system/folder")
786
+ # Define the paths to the model kernel binaries
787
+ sfincs_bin = Path("path/to/your/sfincs/bin.exe")
788
+ fiat_bin = Path("path/to/your/fiat/bin.exe")
786
789
 
787
790
  # Validate and set environment variables
788
791
  Settings(
789
792
  DATABASE_ROOT=root,
790
793
  DATABASE_NAME=name,
791
- SYSTEM_FOLDER=system_folder,
794
+ SFINCS_BIN_PATH=sfincs_bin,
795
+ FIAT_BIN_PATH=fiat_path,
796
+ VALIDATE_BINARIES=True,
792
797
  )
793
798
  ```
794
799
 
@@ -1,9 +1,9 @@
1
- flood_adapt/__init__.py,sha256=3yTRhIjKIPsLp4mwacrItlPRgNQWOePbrEkV31CWB8E,596
1
+ flood_adapt/__init__.py,sha256=FT9l7-5N5A3Sc_twCYjKyAk-PKpUsek6ghpGn9hfH8w,596
2
2
  flood_adapt/database_builder.py,sha256=eq_LAqaGpV-KJkLNBVvXjyjFRDQaBFA5ubANiuVsZWU,420
3
3
  flood_adapt/flood_adapt.py,sha256=7xjieOrFQigw7MvLJ9zNXTMKXF70D6zd2mZb6trWYDk,35344
4
4
  flood_adapt/adapter/__init__.py,sha256=C6XBZK8x4MHe3beeKa9rPbXn0-gBHPEPnTKn14C-5gI,249
5
- flood_adapt/adapter/fiat_adapter.py,sha256=2SYHzmW6z5L66S1qD4AlEeCW9deLfLi_h9K7HPFCYRY,57105
6
- flood_adapt/adapter/sfincs_adapter.py,sha256=ya7IjcLDe-sy9NSWl39bwp5Twy_PppWbkPkvGBXXH-M,72897
5
+ flood_adapt/adapter/fiat_adapter.py,sha256=Eh4S9q1tzQCstL0Xi9lvUluG65RKDV0-SDdeVBf2FK4,57240
6
+ flood_adapt/adapter/sfincs_adapter.py,sha256=JzCVich9thw-h3d7klK0a4eBaHBLMI27BKCHDt_-u8Q,72807
7
7
  flood_adapt/adapter/sfincs_offshore.py,sha256=BBdeCYKKDweFla05aE1Q9Fr-eXY1VzxQEfE_74lR7B8,7600
8
8
  flood_adapt/adapter/interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  flood_adapt/adapter/interface/hazard_adapter.py,sha256=1yZUNTrT3dtrD_PTJfczVkjNVB9JcQr64Y4xYRtR-sc,2758
@@ -11,13 +11,13 @@ flood_adapt/adapter/interface/impact_adapter.py,sha256=5KMUzUqT18pfjzVS2QT2PSnDJ
11
11
  flood_adapt/adapter/interface/model_adapter.py,sha256=i39fEsZ2gm1Q4PQ1vRX6CZ-1RwVSXVyPmppj1w6TfAE,2693
12
12
  flood_adapt/adapter/interface/offshore.py,sha256=hSsXKkU6rWPZH9wtquWkYsEvFSPuuU1l1MFZZ32qD20,462
13
13
  flood_adapt/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- flood_adapt/config/config.py,sha256=fFCPCSgalQEEZXRP2Ua4oHvMdR8MzBPs5Ohs1mBIQsM,10231
15
- flood_adapt/config/fiat.py,sha256=dgqmjuA7a6A9_QeQlObzxCG7u_h3Vcb94QOxPGygaLo,6036
14
+ flood_adapt/config/config.py,sha256=elEp5pZN7Med4o-n60NpitQi9Zi1HI3BERas0Pmg_28,9126
15
+ flood_adapt/config/fiat.py,sha256=PsCNEaRqyc_XSykDndPypWEF0fD9dvtQEHaHBVJqn3A,6043
16
16
  flood_adapt/config/gui.py,sha256=Ji6X9j1gC18evsHfeW3MwtWpOsod9fW0XMfd-GSx3DY,10157
17
17
  flood_adapt/config/sfincs.py,sha256=WHPPPtT9vxStsulElB_I8Hbtk3WNJs3Zqy-bfcy68fA,11279
18
18
  flood_adapt/config/site.py,sha256=zKuXCCecwfP6Ri2euhC6KHoANGXTm3NUKgEsxa6rGOg,4199
19
19
  flood_adapt/database_builder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- flood_adapt/database_builder/database_builder.py,sha256=mQ1Gy2pKBn8GtvTipQVlTjVGburfq45AG75UGGmF6ac,87541
20
+ flood_adapt/database_builder/database_builder.py,sha256=pdUZZW3fk47opyAIn7_RQ9EmZIiY_5cgAxbFu3Qk8eU,87556
21
21
  flood_adapt/database_builder/templates/default_units/imperial.toml,sha256=EYR0i4T_1fuoDe8R509pTd5fMKWCIaMo-pa6XdqANkA,286
22
22
  flood_adapt/database_builder/templates/default_units/metric.toml,sha256=eE54FdlUtnc6VNTE-U9n18rN0TN9_sTzsCokf2I8Sik,293
23
23
  flood_adapt/database_builder/templates/green_infra_table/green_infra_lookup_table.csv,sha256=T3CW2WmWjlrlDVurPTcAX6-DTH0EJdLIt0f_5r1ox-U,456
@@ -75,13 +75,13 @@ flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographi
75
75
  flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config_risk.toml,sha256=ayNiJHEMdRk82nhfV1srRNavUtxpQEWX71fJf9nsxu4,1988
76
76
  flood_adapt/database_builder/templates/output_layers/bin_colors.toml,sha256=OXlAdFfu3S99qrxFqn_Xu6ZIZMvk-0_LQhdsj5q_rZk,412
77
77
  flood_adapt/dbs_classes/__init__.py,sha256=_8DX6dK62U1RjRKz0zOgM0yR-kiBlBxz2dLkCWylmXc,710
78
- flood_adapt/dbs_classes/database.py,sha256=S9C-NOAZNelvFhJ20L_tYVO7lsdad9ZAy5DwYZhz084,24650
78
+ flood_adapt/dbs_classes/database.py,sha256=UNfFKal_YJyfLqOEhr9yR25-aQr6x7FHwC1LnZBsl_4,24424
79
79
  flood_adapt/dbs_classes/dbs_benefit.py,sha256=WgLXG37mrkIUq2cp8Y2ov2FYqxoGXHKe9h-7GnQd4Sw,2502
80
80
  flood_adapt/dbs_classes/dbs_event.py,sha256=UBJ3eYN1Nicx1MBWWBohgUiDXgINotQNDBc8lontsJ4,1618
81
81
  flood_adapt/dbs_classes/dbs_measure.py,sha256=wfVo6hUHdgqffGxvvm5zdwZ5Jed6oCJGvFqdilYlEX0,3875
82
82
  flood_adapt/dbs_classes/dbs_projection.py,sha256=_HOEsEQ43h2HnG6lFh_cFERGPWbEzZRg01tYIIjx_2I,1007
83
- flood_adapt/dbs_classes/dbs_scenario.py,sha256=NHjiRdV5dxYUtXR6FRGZ9c9Vng2-w-F1-Nn50lNbxXM,4665
84
- flood_adapt/dbs_classes/dbs_static.py,sha256=c5IluANnEVptTBGyTq1UVRAL4lLJ7KETbpujtcaRllY,9440
83
+ flood_adapt/dbs_classes/dbs_scenario.py,sha256=2qQcXS9zdyoEuGPQ6Gy954-9ND223-1EkA-m1qPQ5vU,4657
84
+ flood_adapt/dbs_classes/dbs_static.py,sha256=zGcLSeI2BftwsvkJeJhlZSCjX7ZZtRiEGpeZ9c6leyI,9513
85
85
  flood_adapt/dbs_classes/dbs_strategy.py,sha256=1p7zBu-SbIEXG_qaMTOZ363e7VTWWrzYDsjwhVQiGaI,4695
86
86
  flood_adapt/dbs_classes/dbs_template.py,sha256=0VdwrOgANk7ohZdp_HYW1D1_qXFVErq87AVvuMeNEk8,9955
87
87
  flood_adapt/dbs_classes/interface/database.py,sha256=StWp_f6iGyQosAI066CmZB6O55_UWmQ2JGJPUlw49j0,3338
@@ -122,18 +122,18 @@ flood_adapt/objects/measures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
122
122
  flood_adapt/objects/measures/measure_factory.py,sha256=v0eiFlsW47UpM2DQUKGu3Qio3s3JE4nB20W9T_9JAuA,2636
123
123
  flood_adapt/objects/measures/measures.py,sha256=60cwsdCNRFpxjnZLVemBwfqJ4TTxyf4PvwzxvqZA6Kg,18266
124
124
  flood_adapt/objects/projections/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
- flood_adapt/objects/projections/projections.py,sha256=rS8GtltLLH1IKzTPAk-7GSQtM8k3TkIDDxKc7jrhOjw,3272
125
+ flood_adapt/objects/projections/projections.py,sha256=uBwoT3bDTjjj800CV3iKVxIiX-8GeT1dyas5ZejOj9Y,3949
126
126
  flood_adapt/objects/scenarios/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
127
  flood_adapt/objects/scenarios/scenarios.py,sha256=Io2qUSiUggpIbVV4kxd7F46WYUJHyFL62RWq_2rFmsM,528
128
128
  flood_adapt/objects/strategies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
129
129
  flood_adapt/objects/strategies/strategies.py,sha256=znBOhUC3ft0-gJ4-vdufePNvJ9h8bPSIGhe3TkpBHk8,2892
130
130
  flood_adapt/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
131
- flood_adapt/workflows/benefit_runner.py,sha256=hvCCJOzqe57kWJ1wQ-8dqBNP88sah0d1LPQYmy6M57c,19980
131
+ flood_adapt/workflows/benefit_runner.py,sha256=GCSe1zTZQrNhcO6vkKyI0NnAemDO0su3FINjyvxOMho,20244
132
132
  flood_adapt/workflows/floodmap.py,sha256=6XatakhiZDkIi82VpRDb5dWtWAs-aSho8_iaCGph1_c,2932
133
- flood_adapt/workflows/impacts_integrator.py,sha256=Iq8namwu90SP_BTazUsDqROqOrJk7rGEyR6nA1Q7Vho,2330
133
+ flood_adapt/workflows/impacts_integrator.py,sha256=I1yptuY1h_v75Jo-ZMLIOzHkzhkcGXQptYpyoKf-JIc,2410
134
134
  flood_adapt/workflows/scenario_runner.py,sha256=mjiOr1_0oxJGXhwhPOstZo-pmCm1PBcKNz57bmw2htc,2914
135
- flood_adapt-0.3.7.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
136
- flood_adapt-0.3.7.dist-info/METADATA,sha256=FfRWOM1OyVjEQT5kRDxjua5Tpia4wcHNUkPqenhN2_k,51435
137
- flood_adapt-0.3.7.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
138
- flood_adapt-0.3.7.dist-info/top_level.txt,sha256=JvzMi6cTcQPEThCfpgMEeVny3ghI1urSH0CCgVIqSzw,12
139
- flood_adapt-0.3.7.dist-info/RECORD,,
135
+ flood_adapt-0.3.9.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
136
+ flood_adapt-0.3.9.dist-info/METADATA,sha256=c0PIRALbHBr1VODV3u6Ms2T5olC1TGoeOJsn7Xf7Ifk,51612
137
+ flood_adapt-0.3.9.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
138
+ flood_adapt-0.3.9.dist-info/top_level.txt,sha256=JvzMi6cTcQPEThCfpgMEeVny3ghI1urSH0CCgVIqSzw,12
139
+ flood_adapt-0.3.9.dist-info/RECORD,,