flood-adapt 0.3.2__py3-none-any.whl → 0.3.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.
@@ -34,12 +34,16 @@ from flood_adapt.config.fiat import (
34
34
  SVIModel,
35
35
  )
36
36
  from flood_adapt.config.gui import (
37
+ AggregationDmgLayer,
38
+ BenefitsLayer,
39
+ FloodMapLayer,
40
+ FootprintsDmgLayer,
37
41
  GuiModel,
38
42
  GuiUnitModel,
39
- MapboxLayersModel,
43
+ OutputLayers,
40
44
  PlottingModel,
41
45
  SyntheticTideModel,
42
- VisualizationLayersModel,
46
+ VisualizationLayers,
43
47
  )
44
48
  from flood_adapt.config.sfincs import (
45
49
  Cstype,
@@ -645,6 +649,8 @@ class DatabaseBuilder:
645
649
  # Update elevations
646
650
  self.update_fiat_elevation()
647
651
 
652
+ self._svi = self.create_svi()
653
+
648
654
  config = FiatConfigModel(
649
655
  exposure_crs=self.fiat_model.exposure.crs,
650
656
  floodmap_type=self.read_floodmap_type(),
@@ -657,7 +663,7 @@ class DatabaseBuilder:
657
663
  save_simulation=False, # TODO
658
664
  infographics=self.config.infographics,
659
665
  aggregation=self._aggregation_areas,
660
- svi=self.create_svi(),
666
+ svi=self._svi,
661
667
  )
662
668
 
663
669
  # Update output geoms names
@@ -1489,23 +1495,28 @@ class DatabaseBuilder:
1489
1495
 
1490
1496
  ### SITE ###
1491
1497
  def create_site_config(self) -> Site:
1492
- # call this before fiat to ensure the dem is where its expected
1493
- sfincs = self.create_sfincs_config()
1494
-
1495
- # call this after sfincs to get waterlevel references
1496
- gui = self.create_gui_config()
1498
+ """Create the site configuration for the FloodAdapt model.
1499
+
1500
+ The order of these functions is important!
1501
+ 1. Create the SFINCS model.
1502
+ needs: water level references
1503
+ provides: updated water level references with optional tide gauge
1504
+ 2. Create the FIAT model.
1505
+ needs: water level references and optional probabilistic event set
1506
+ provides: svi and exposure geometries
1507
+ 3. Create the GUI model. (requires water level references and FIAT model to be updated)
1508
+ needs: water level references and FIAT model to be updated
1509
+ provides: gui model with output layers, visualization layers and plotting.
1497
1510
 
1498
- # set the probabilistic event set if provided
1511
+ """
1512
+ sfincs = self.create_sfincs_config()
1499
1513
  self.add_probabilistic_set()
1500
-
1501
- # Create the FIAT configuration
1502
1514
  fiat = self.create_fiat_model()
1503
- lon, lat = self.read_location() # Get centroid of site
1515
+ gui = self.create_gui_config()
1504
1516
 
1505
- # Set standard objects
1517
+ # Order doesnt matter from here
1518
+ lon, lat = self.read_location()
1506
1519
  std_objs = self.set_standard_objects()
1507
-
1508
- # Description of site
1509
1520
  description = (
1510
1521
  self.config.description if self.config.description else self.config.name
1511
1522
  )
@@ -1538,7 +1549,7 @@ class DatabaseBuilder:
1538
1549
  gui = GuiModel(
1539
1550
  units=self.unit_system,
1540
1551
  plotting=self.create_hazard_plotting_config(),
1541
- mapbox_layers=self.create_mapbox_layers_config(),
1552
+ output_layers=self.create_output_layers_config(),
1542
1553
  visualization_layers=self.create_visualization_layers(),
1543
1554
  )
1544
1555
 
@@ -1554,57 +1565,73 @@ class DatabaseBuilder:
1554
1565
  f"Unit system {self.config.unit_system} not recognized. Please choose 'imperial' or 'metric'."
1555
1566
  )
1556
1567
 
1557
- def create_visualization_layers(self) -> VisualizationLayersModel:
1558
- visualization_layers = VisualizationLayersModel(
1559
- default_bin_number=4,
1560
- default_colors=["#FFFFFF", "#FEE9CE", "#E03720", "#860000"],
1561
- layer_names=[],
1562
- layer_long_names=[],
1563
- layer_paths=[],
1564
- field_names=[],
1565
- bins=[],
1566
- colors=[],
1567
- )
1568
-
1568
+ def create_visualization_layers(self) -> VisualizationLayers:
1569
+ visualization_layers = VisualizationLayers()
1570
+ if self._svi is not None:
1571
+ visualization_layers.add_layer(
1572
+ name="svi",
1573
+ long_name="Social Vulnerability Index (SVI)",
1574
+ path=str(self.static_path / self._svi.geom),
1575
+ database_path=self.root,
1576
+ field_name="SVI",
1577
+ bins=[0.05, 0.2, 0.4, 0.6, 0.8],
1578
+ )
1569
1579
  return visualization_layers
1570
1580
 
1571
- def create_mapbox_layers_config(self) -> MapboxLayersModel:
1581
+ def create_output_layers_config(self) -> OutputLayers:
1572
1582
  # Read default colors from template
1573
1583
  fd_max = self.config.gui.max_flood_depth
1574
1584
  ad_max = self.config.gui.max_aggr_dmg
1575
1585
  ftd_max = self.config.gui.max_footprint_dmg
1576
1586
  b_max = self.config.gui.max_benefits
1577
1587
 
1578
- svi_bins = None
1579
- if self.config.svi is not None:
1580
- svi_bins = [0.05, 0.2, 0.4, 0.6, 0.8]
1581
-
1582
- mapbox_layers = MapboxLayersModel(
1583
- flood_map_depth_min=0.0, # mask areas with flood depth lower than this (zero = all depths shown) # TODO How to define this?
1584
- flood_map_zbmax=-9999, # mask areas with elevation lower than this (very negative = show all calculated flood depths) # TODO How to define this?,
1585
- flood_map_bins=[0.2 * fd_max, 0.6 * fd_max, fd_max],
1586
- damage_decimals=0,
1587
- footprints_dmg_type="absolute",
1588
- aggregation_dmg_bins=[
1589
- 0.00001,
1590
- 0.1 * ad_max,
1591
- 0.25 * ad_max,
1592
- 0.5 * ad_max,
1593
- ad_max,
1594
- ],
1595
- footprints_dmg_bins=[
1596
- 0.00001,
1597
- 0.06 * ftd_max,
1598
- 0.2 * ftd_max,
1599
- 0.4 * ftd_max,
1600
- ftd_max,
1601
- ],
1602
- benefits_bins=[0, 0.01, 0.02 * b_max, 0.2 * b_max, b_max],
1603
- svi_bins=svi_bins,
1604
- **self._get_bin_colors(),
1605
- )
1588
+ benefits_layer = None
1589
+ if self.config.probabilistic_set is not None:
1590
+ benefits_layer = BenefitsLayer(
1591
+ bins=[0, 0.01, 0.02 * b_max, 0.2 * b_max, b_max],
1592
+ colors=[
1593
+ "#FF7D7D",
1594
+ "#FFFFFF",
1595
+ "#DCEDC8",
1596
+ "#AED581",
1597
+ "#7CB342",
1598
+ "#33691E",
1599
+ ],
1600
+ threshold=0.0,
1601
+ )
1606
1602
 
1607
- return mapbox_layers
1603
+ output_layers = OutputLayers(
1604
+ floodmap=FloodMapLayer(
1605
+ bins=[0.2 * fd_max, 0.6 * fd_max, fd_max],
1606
+ colors=["#D7ECFB", "#8ABDDD", "#1C73A4", "#081D58"],
1607
+ zbmax=-9999,
1608
+ depth_min=0.0,
1609
+ ),
1610
+ aggregation_dmg=AggregationDmgLayer(
1611
+ bins=[0.00001, 0.1 * ad_max, 0.25 * ad_max, 0.5 * ad_max, ad_max],
1612
+ colors=[
1613
+ "#FFFFFF",
1614
+ "#FEE9CE",
1615
+ "#FDBB84",
1616
+ "#FC844E",
1617
+ "#E03720",
1618
+ "#860000",
1619
+ ],
1620
+ ),
1621
+ footprints_dmg=FootprintsDmgLayer(
1622
+ bins=[0.00001, 0.06 * ftd_max, 0.2 * ftd_max, 0.4 * ftd_max, ftd_max],
1623
+ colors=[
1624
+ "#FFFFFF",
1625
+ "#FEE9CE",
1626
+ "#FDBB84",
1627
+ "#FC844E",
1628
+ "#E03720",
1629
+ "#860000",
1630
+ ],
1631
+ ),
1632
+ benefits=benefits_layer,
1633
+ )
1634
+ return output_layers
1608
1635
 
1609
1636
  def create_hazard_plotting_config(self) -> PlottingModel:
1610
1637
  datum_names = [datum.name for datum in self.water_level_references.datums]
@@ -2159,7 +2186,7 @@ class DatabaseBuilder:
2159
2186
  """
2160
2187
  templates_path = Path(__file__).parent.resolve().joinpath("templates")
2161
2188
  with open(
2162
- templates_path.joinpath("mapbox_layers", "bin_colors.toml"), "rb"
2189
+ templates_path.joinpath("output_layers", "bin_colors.toml"), "rb"
2163
2190
  ) as f:
2164
2191
  bin_colors = tomli.load(f)
2165
2192
  return bin_colors
@@ -381,14 +381,6 @@ class Database(IDatabase):
381
381
  runner = BenefitRunner(self, benefit=benefit)
382
382
  runner.run_cost_benefit()
383
383
 
384
- def update(self) -> None:
385
- self.projections_list = self._projections.list_objects()
386
- self.events_list = self._events.list_objects()
387
- self.measures_list = self._measures.list_objects()
388
- self.strategies_list = self._strategies.list_objects()
389
- self.scenarios_list = self._scenarios.list_objects()
390
- self.benefits_list = self._benefits.list_objects()
391
-
392
384
  def get_outputs(self) -> dict[str, Any]:
393
385
  """Return a dictionary with info on the outputs that currently exist in the database.
394
386
 
@@ -397,7 +389,7 @@ class Database(IDatabase):
397
389
  dict[str, Any]
398
390
  Includes 'name', 'path', 'last_modification_date' and "finished" info
399
391
  """
400
- all_scenarios = pd.DataFrame(self._scenarios.list_objects())
392
+ all_scenarios = pd.DataFrame(self._scenarios.summarize_objects())
401
393
  if len(all_scenarios) > 0:
402
394
  df = all_scenarios[all_scenarios["finished"]]
403
395
  else:
@@ -585,17 +577,17 @@ class Database(IDatabase):
585
577
  """
586
578
  match object_type:
587
579
  case "projections":
588
- return self.projections.list_objects()
580
+ return self.projections.summarize_objects()
589
581
  case "events":
590
- return self.events.list_objects()
582
+ return self.events.summarize_objects()
591
583
  case "measures":
592
- return self.measures.list_objects()
584
+ return self.measures.summarize_objects()
593
585
  case "strategies":
594
- return self.strategies.list_objects()
586
+ return self.strategies.summarize_objects()
595
587
  case "scenarios":
596
- return self.scenarios.list_objects()
588
+ return self.scenarios.summarize_objects()
597
589
  case "benefits":
598
- return self.benefits.list_objects()
590
+ return self.benefits.summarize_objects()
599
591
  case _:
600
592
  raise ValueError(
601
593
  f"Object type '{object_type}' is not valid. Must be one of 'projections', 'events', 'measures', 'strategies' or 'scenarios'."
@@ -611,16 +603,20 @@ class Database(IDatabase):
611
603
  scenario_name : str
612
604
  name of the scenario to check if needs to be rerun for hazard
613
605
  """
614
- scenario = self._scenarios.get(scenario_name)
606
+ scenario = self.scenarios.get(scenario_name)
615
607
  runner = ScenarioRunner(self, scenario=scenario)
616
608
 
617
609
  # Dont do anything if the hazard model has already been run in itself
618
610
  if runner.impacts.hazard.has_run:
619
611
  return
620
612
 
613
+ scenarios = [
614
+ self.scenarios.get(scn)
615
+ for scn in self.scenarios.summarize_objects()["name"]
616
+ ]
621
617
  scns_simulated = [
622
618
  sim
623
- for sim in self.scenarios.list_objects()["objects"]
619
+ for sim in scenarios
624
620
  if self.scenarios.output_path.joinpath(sim.name, "Flooding").is_dir()
625
621
  ]
626
622
 
@@ -630,8 +626,9 @@ class Database(IDatabase):
630
626
  path_new = self.scenarios.output_path.joinpath(
631
627
  scenario.name, "Flooding"
632
628
  )
633
- runner._load_objects(scn)
634
- if runner.impacts.hazard.has_run: # only copy results if the hazard model has actually finished and skip simulation folders
629
+ _runner = ScenarioRunner(self, scenario=scn)
630
+
631
+ if _runner.impacts.hazard.has_run: # only copy results if the hazard model has actually finished and skip simulation folders
635
632
  shutil.copytree(
636
633
  existing,
637
634
  path_new,
@@ -642,40 +639,6 @@ class Database(IDatabase):
642
639
  f"Hazard simulation is used from the '{scn.name}' scenario"
643
640
  )
644
641
 
645
- def run_scenario(self, scenario_name: Union[str, list[str]]) -> None:
646
- """Run a scenario hazard and impacts.
647
-
648
- Parameters
649
- ----------
650
- scenario_name : Union[str, list[str]]
651
- name(s) of the scenarios to run.
652
-
653
- Raises
654
- ------
655
- RuntimeError
656
- If an error occurs while running one of the scenarios
657
- """
658
- if not isinstance(scenario_name, list):
659
- scenario_name = [scenario_name]
660
-
661
- errors = []
662
-
663
- for scn in scenario_name:
664
- try:
665
- self.has_run_hazard(scn)
666
- scenario = self.scenarios.get(scn)
667
- runner = ScenarioRunner(self, scenario=scenario)
668
- runner.run(scenario)
669
- except RuntimeError as e:
670
- errors.append(scn)
671
- self.logger.error(f"Error running scenario {scn}: {e}")
672
- if errors:
673
- raise RuntimeError(
674
- "FloodAdapt failed to run for the following scenarios: "
675
- + ", ".join(errors)
676
- + ". Check the logs for more information."
677
- )
678
-
679
642
  def cleanup(self) -> None:
680
643
  """
681
644
  Remove corrupted scenario output.
@@ -67,7 +67,10 @@ class DbsEvent(DbsTemplate[Event]):
67
67
  list of scenarios that use the event
68
68
  """
69
69
  # Get all the scenarios
70
- scenarios = self._database.scenarios.list_objects()["objects"]
70
+ scenarios = [
71
+ self._database.scenarios.get(scn)
72
+ for scn in self._database.scenarios.summarize_objects()["name"]
73
+ ]
71
74
 
72
75
  # Check if event is used in a scenario
73
76
  used_in_scenario = [
@@ -37,20 +37,17 @@ class DbsMeasure(DbsTemplate[Measure]):
37
37
  # Load and return the object
38
38
  return MeasureFactory.get_measure_object(full_path)
39
39
 
40
- def list_objects(self) -> dict[str, list[Any]]:
40
+ def summarize_objects(self) -> dict[str, list[Any]]:
41
41
  """Return a dictionary with info on the measures that currently exist in the database.
42
42
 
43
43
  Returns
44
44
  -------
45
45
  dict[str, Any]
46
- Includes 'name', 'description', 'path' and 'last_modification_date' info
46
+ Includes 'name', 'description', 'path' and 'last_modification_date' and 'geometry' info
47
47
  """
48
- measures = self._get_object_list()
48
+ measures = self._get_object_summary()
49
49
  objects = [self.get(name) for name in measures["name"]]
50
50
 
51
- measures["description"] = [obj.description for obj in objects]
52
- measures["objects"] = objects
53
-
54
51
  geometries = []
55
52
  for obj in objects:
56
53
  # If polygon is used read the polygon file
@@ -99,7 +96,10 @@ class DbsMeasure(DbsTemplate[Measure]):
99
96
  list of strategies that use the measure
100
97
  """
101
98
  # Get all the strategies
102
- strategies = self._database.strategies.list_objects()["objects"]
99
+ strategies = [
100
+ self._database.strategies.get(strategy)
101
+ for strategy in self._database.strategies.summarize_objects()["name"]
102
+ ]
103
103
 
104
104
  # Check if measure is used in a strategy
105
105
  used_in_strategy = [
@@ -42,7 +42,10 @@ class DbsProjection(DbsTemplate[Projection]):
42
42
  list of scenarios that use the projection
43
43
  """
44
44
  # Get all the scenarios
45
- scenarios = self._database.scenarios.list_objects()["objects"]
45
+ scenarios = [
46
+ self._database.scenarios.get(scn)
47
+ for scn in self._database.scenarios.summarize_objects()["name"]
48
+ ]
46
49
 
47
50
  # Check if projection is used in a scenario
48
51
  used_in_scenario = [
@@ -12,7 +12,7 @@ class DbsScenario(DbsTemplate[Scenario]):
12
12
  display_name = "Scenario"
13
13
  _object_class = Scenario
14
14
 
15
- def list_objects(self) -> dict[str, list[Any]]:
15
+ def summarize_objects(self) -> dict[str, list[Any]]:
16
16
  """Return a dictionary with info on the events that currently exist in the database.
17
17
 
18
18
  Returns
@@ -20,12 +20,18 @@ class DbsScenario(DbsTemplate[Scenario]):
20
20
  dict[str, Any]
21
21
  Includes 'name', 'description', 'path' and 'last_modification_date' info
22
22
  """
23
- scenarios = super().list_objects()
24
- objects = scenarios["objects"]
25
- scenarios["Projection"] = [obj.projection for obj in objects]
26
- scenarios["Event"] = [obj.event for obj in objects]
27
- scenarios["Strategy"] = [obj.strategy for obj in objects]
28
- scenarios["finished"] = [self.has_run_check(obj.name) for obj in objects]
23
+ scenarios = super().summarize_objects()
24
+ scenarios["Projection"] = [
25
+ self._read_variable_in_toml("projection", path)
26
+ for path in scenarios["path"]
27
+ ]
28
+ scenarios["Event"] = [
29
+ self._read_variable_in_toml("event", path) for path in scenarios["path"]
30
+ ]
31
+ scenarios["Strategy"] = [
32
+ self._read_variable_in_toml("strategy", path) for path in scenarios["path"]
33
+ ]
34
+ scenarios["finished"] = [self.has_run_check(scn) for scn in scenarios["name"]]
29
35
 
30
36
  return scenarios
31
37
 
@@ -87,7 +93,10 @@ class DbsScenario(DbsTemplate[Scenario]):
87
93
  list[str]
88
94
  list of benefits that use the scenario
89
95
  """
90
- benefits = self._database.benefits.list_objects()["objects"]
96
+ benefits = [
97
+ self._database.benefits.get(benefit)
98
+ for benefit in self._database.benefits.summarize_objects()["name"]
99
+ ]
91
100
  used_in_benefit = []
92
101
  for benefit in benefits:
93
102
  runner = BenefitRunner(database=self._database, benefit=benefit)
@@ -40,7 +40,7 @@ class DbsStrategy(DbsTemplate[Strategy]):
40
40
  ValueError
41
41
  Raise error if name is already in use.
42
42
  """
43
- object_exists = object_model.name in self.list_objects()["name"]
43
+ object_exists = object_model.name in self.summarize_objects()["name"]
44
44
 
45
45
  # If you want to overwrite the object, and the object already exists, first delete it. If it exists and you
46
46
  # don't want to overwrite, raise an error.
@@ -137,11 +137,13 @@ class DbsStrategy(DbsTemplate[Strategy]):
137
137
  list[str]
138
138
  list of scenarios that use the strategy
139
139
  """
140
- # Check if strategy is used in a scenario
140
+ scenarios = [
141
+ self._database.scenarios.get(scn)
142
+ for scn in self._database.scenarios.summarize_objects()["name"]
143
+ ]
144
+
141
145
  used_in_scenario = [
142
- scenario.name
143
- for scenario in self._database.scenarios.list_objects()["objects"]
144
- if name == scenario.strategy
146
+ scenario.name for scenario in scenarios if name == scenario.strategy
145
147
  ]
146
148
 
147
149
  return used_in_scenario
@@ -3,6 +3,7 @@ from datetime import datetime
3
3
  from pathlib import Path
4
4
  from typing import Any, TypeVar
5
5
 
6
+ import tomli
6
7
  import tomli_w
7
8
 
8
9
  from flood_adapt.dbs_classes.interface.database import IDatabase
@@ -47,25 +48,16 @@ class DbsTemplate(AbstractDatabaseElement[T_OBJECTMODEL]):
47
48
  # Load and return the object
48
49
  return self._object_class.load_file(full_path)
49
50
 
50
- def list_objects(self) -> dict[str, list[Any]]:
51
+ def summarize_objects(self) -> dict[str, list[Any]]:
51
52
  """Return a dictionary with info on the objects that currently exist in the database.
52
53
 
53
54
  Returns
54
55
  -------
55
56
  dict[str, list[Any]]
56
- A dictionary that contains the keys: `name`, 'path', 'last_modification_date', 'description', 'objects'
57
+ A dictionary that contains the keys: `name`, `description`, `path` and `last_modification_date`.
57
58
  Each key has a list of the corresponding values, where the index of the values corresponds to the same object.
58
59
  """
59
- # Check if all objects exist
60
- object_list = self._get_object_list()
61
-
62
- # Load all objects
63
- objects = [self.get(name) for name in object_list["name"]]
64
-
65
- # From the loaded objects, get the description and add them to the object_list
66
- object_list["description"] = [obj.description for obj in objects]
67
- object_list["objects"] = objects
68
- return object_list
60
+ return self._get_object_summary()
69
61
 
70
62
  def copy(self, old_name: str, new_name: str, new_description: str):
71
63
  """Copy (duplicate) an existing object, and give it a new name.
@@ -155,7 +147,7 @@ class DbsTemplate(AbstractDatabaseElement[T_OBJECTMODEL]):
155
147
  Raise error if name is already in use.
156
148
  """
157
149
  # Check if the object exists
158
- if object_model.name not in self.list_objects()["name"]:
150
+ if object_model.name not in self.summarize_objects()["name"]:
159
151
  raise ValueError(
160
152
  f"{self.display_name}: '{object_model.name}' does not exist. You cannot edit an {self.display_name.lower()} that does not exist."
161
153
  )
@@ -241,13 +233,13 @@ class DbsTemplate(AbstractDatabaseElement[T_OBJECTMODEL]):
241
233
  # level object. By default, return an empty list
242
234
  return []
243
235
 
244
- def _get_object_list(self) -> dict[str, list[Any]]:
236
+ def _get_object_summary(self) -> dict[str, list[Any]]:
245
237
  """Get a dictionary with all the toml paths and last modification dates that exist in the database of the given object_type.
246
238
 
247
239
  Returns
248
240
  -------
249
241
  dict[str, Any]
250
- A dictionary that contains the keys: `name` to `path` and `last_modification_date`
242
+ A dictionary that contains the keys: `name`, `description`, `path` and `last_modification_date`.
251
243
  Each key has a list of the corresponding values, where the index of the values corresponds to the same object.
252
244
  """
253
245
  # If the toml doesnt exist, we might be in the middle of saving a new object or could be a broken object.
@@ -258,19 +250,30 @@ class DbsTemplate(AbstractDatabaseElement[T_OBJECTMODEL]):
258
250
  if (dir / f"{dir.name}.toml").is_file()
259
251
  ]
260
252
  paths = [Path(dir / f"{dir.name}.toml") for dir in directories]
261
- names = [dir.name for dir in directories]
253
+
254
+ names = [self._read_variable_in_toml("name", path) for path in paths]
255
+ descriptions = [
256
+ self._read_variable_in_toml("description", path) for path in paths
257
+ ]
258
+
262
259
  last_modification_date = [
263
260
  datetime.fromtimestamp(file.stat().st_mtime) for file in paths
264
261
  ]
265
262
 
266
263
  objects = {
267
264
  "name": names,
265
+ "description": descriptions,
268
266
  "path": paths,
269
267
  "last_modification_date": last_modification_date,
270
268
  }
271
-
272
269
  return objects
273
270
 
271
+ @staticmethod
272
+ def _read_variable_in_toml(variable_name: str, toml_path: Path) -> str:
273
+ with open(toml_path, "rb") as f:
274
+ data = tomli.load(f)
275
+ return data.get(variable_name, "")
276
+
274
277
  def _validate_to_save(self, object_model: T_OBJECTMODEL, overwrite: bool) -> None:
275
278
  """Validate if the object can be saved.
276
279
 
@@ -285,11 +288,7 @@ class DbsTemplate(AbstractDatabaseElement[T_OBJECTMODEL]):
285
288
  Raise error if name is already in use.
286
289
  """
287
290
  # Check if the object exists
288
- if object_model.name in self.list_objects()["name"]:
289
- raise ValueError(
290
- f"{self.display_name}: '{object_model.name}' already exists. Choose a different name."
291
- )
292
- object_exists = object_model.name in self.list_objects()["name"]
291
+ object_exists = object_model.name in self.summarize_objects()["name"]
293
292
 
294
293
  # If you want to overwrite the object, and the object already exists, first delete it. If it exists and you
295
294
  # don't want to overwrite, raise an error.
@@ -86,10 +86,6 @@ class IDatabase(ABC):
86
86
  def run_benefit(self, benefit_name: Union[str, list[str]]) -> None:
87
87
  pass
88
88
 
89
- @abstractmethod
90
- def update(self) -> None:
91
- pass
92
-
93
89
  @abstractmethod
94
90
  def get_outputs(self) -> dict[str, Any]:
95
91
  pass
@@ -138,10 +134,6 @@ class IDatabase(ABC):
138
134
  def has_run_hazard(self, scenario_name: str) -> None:
139
135
  pass
140
136
 
141
- @abstractmethod
142
- def run_scenario(self, scenario_name: Union[str, list[str]]) -> None:
143
- pass
144
-
145
137
  @abstractmethod
146
138
  def cleanup(self) -> None:
147
139
  pass
@@ -33,7 +33,7 @@ class AbstractDatabaseElement(ABC, Generic[T_OBJECT_MODEL]):
33
33
  pass
34
34
 
35
35
  @abstractmethod
36
- def list_objects(self) -> dict[str, list[Any]]:
36
+ def summarize_objects(self) -> dict[str, list[Any]]:
37
37
  """Return a dictionary with info on the objects that currently exist in the database.
38
38
 
39
39
  Returns