Skip to content

Commit

Permalink
Transition to using the submodule resource files.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioannis-vm committed Dec 3, 2024
1 parent 56da5f6 commit f4d6af5
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 45 deletions.
10 changes: 8 additions & 2 deletions pelicun/assessment.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,10 @@ def get_default_data(self, data_name: str) -> pd.DataFrame:
'Please use `loss_repair_DB` instead.'
)

data_path = f'{base.pelicun_path}/resources/SimCenterDBDL/{data_name}.csv'
data_path = file_io.substitute_default_path(
[f'PelicunDefault/{data_name}.csv']
)[0]
assert isinstance(data_path, str)

data = file_io.load_data(
data_path, None, orientation=1, reindex=False, log=self.log
Expand Down Expand Up @@ -249,7 +252,10 @@ def get_default_metadata(self, data_name: str) -> dict:
'`fragility_DB` is deprecated and will be dropped in '
'future versions of pelicun. Please use `damage_DB` instead.'
)
data_path = f'{base.pelicun_path}/resources/SimCenterDBDL/{data_name}.json'
data_path = file_io.substitute_default_path(
[f'PelicunDefault/{data_name}.json']
)[0]
assert isinstance(data_path, str)

with Path(data_path).open(encoding='utf-8') as f:
data = json.load(f)
Expand Down
79 changes: 55 additions & 24 deletions pelicun/file_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

from __future__ import annotations

import json
from pathlib import Path

import numpy as np
Expand Down Expand Up @@ -250,30 +251,33 @@ def substitute_default_path(
data_paths: list[str | pd.DataFrame],
) -> list[str | pd.DataFrame]:
"""
Substitute the default directory path with a specified path.
Substitute the default directory path.
This function iterates over a list of data paths and replaces
occurrences of the 'PelicunDefault/' substring with the path
specified by `base.pelicun_path` concatenated with
'/resources/SimCenterDBDL/'. This operation is performed to update
paths that are using a default location to a user-defined location
within the pelicun framework. The updated list of paths is then
returned.
occurrences of the 'PelicunDefault/' substring by looking up the
filename in a resource mapping file located at
`{base.pelicun_path}/resources/dlml_resource_paths.json`. If a
match is found, the file path is replaced with the value found in
the `resource_paths` dictionary. The updated list of paths is
then returned.
Parameters
----------
data_paths: list of str
data_paths: list of str or pd.DataFrame
A list containing the paths to data files. These paths may
include a placeholder directory 'PelicunDefault/' that needs
to be substituted with the actual path specified in
`base.pelicun_path`.
to be substituted with the actual path specified in the
resource mapping.
Returns
-------
list of str
The list with updated paths where 'PelicunDefault/' has been
replaced with the specified path in `base.pelicun_path`
concatenated with '/resources/SimCenterDBDL/'.
list of str or pd.DataFrame
Raises
------
KeyError
If the file after 'PelicunDefault/' does not exist in the
`resource_paths` keys.
Notes
-----
Expand All @@ -282,26 +286,53 @@ def substitute_default_path(
are located.
- If a path in the input list does not contain 'PelicunDefault/',
it is added to the output list unchanged.
- If the file after 'PelicunDefault/' does not exist in the
`resource_paths` keys, a `KeyError` is raised.
Examples
--------
>>> data_paths = ['PelicunDefault/data/file1.txt',
'data/file2.txt']
>>> data_paths = ['PelicunDefault/data/file1.txt', 'data/file2.txt']
>>> substitute_default_path(data_paths)
['{base.pelicun_path}/resources/SimCenterDBDL/data/file1.txt',
['{base.pelicun_path}/resources/SimCenterDBDL/updated_path/file1_v2.txt',
'data/file2.txt']
"""
# Load the resource paths from the JSON file
resource_file_path = (
Path(base.pelicun_path) / 'resources' / 'dlml_resource_paths.json'
)
with resource_file_path.open('r') as file:
resource_paths = json.load(file)

updated_paths: list[str | pd.DataFrame] = []
for data_path in data_paths:
if isinstance(data_path, str) and 'PelicunDefault/' in data_path:
path = data_path.replace(
'PelicunDefault/',
f'{base.pelicun_path}/resources/SimCenterDBDL/',
for data_path_str in data_paths:
if isinstance(data_path_str, str) and 'PelicunDefault/' in data_path_str:
data_path = Path(data_path_str)
# Extract the filename after 'PelicunDefault/'
file_name = (
data_path.parts[-1]
if 'PelicunDefault' in data_path.parts
else data_path.name
)
updated_paths.append(path)

# Check if the filename exists in the resource paths
# dictionary
if file_name not in resource_paths:
msg = f'File `{file_name}` not found in resource paths.'
raise KeyError(msg)

# Substitute the path with the corresponding value from
# the dictionary
updated_path = str(
Path(base.pelicun_path)
/ 'resources'
/ 'DamageAndLossModelLibrary'
/ resource_paths[file_name]
)
updated_paths.append(updated_path)
else:
updated_paths.append(data_path)
updated_paths.append(data_path_str)

return updated_paths


Expand Down
2 changes: 1 addition & 1 deletion pelicun/model/damage_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1362,7 +1362,7 @@ def parse_scaling_specification(scaling_specification: dict) -> dict: # noqa: C
"""
# if there are contents, ensure they are valid.
# See docstring for an example of what is expected.
parsed_scaling_specification = defaultdict(dict)
parsed_scaling_specification: dict = defaultdict(dict)
# validate contents
for key, value in scaling_specification.items():
# loop through limit states
Expand Down
2 changes: 1 addition & 1 deletion pelicun/resources/DamageAndLossModelLibrary
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"damage_DB_FEMA_P58_2nd.json": "seismic/building/component/FEMA P-58 2nd Edition/fragility.json",
"damage_DB_Hazus_EQ_bldg.csv": "seismic/building/portfolio/Hazus v5.1/fragility.csv",
"damage_DB_Hazus_EQ_bldg.json": "seismic/building/portfolio/Hazus v5.1/fragility.json",
"damage_DB_Hazus_EQ_story.csv": "seismic/building/subassembly/Hazus v5.1/fragility.csv",
"damage_DB_Hazus_EQ_story.json": "seismic/building/subassembly/Hazus v5.1/fragility.json",
"damage_DB_Hazus_EQ_trnsp.csv": "seismic/transportation_network/portfolio/Hazus v5.1/fragility.csv",
"damage_DB_Hazus_EQ_trnsp.json": "seismic/transportation_network/portfolio/Hazus v5.1/fragility.json",
"damage_DB_Hazus_EQ_water.csv": "seismic/water_network/portfolio/fragility.csv",
Expand All @@ -13,8 +15,10 @@
"loss_repair_DB_FEMA_P58_2nd.json": "seismic/building/component/FEMA P-58 2nd Edition/consequence_repair.json",
"loss_repair_DB_Hazus_EQ_bldg.csv": "seismic/building/portfolio/Hazus v5.1/consequence_repair.csv",
"loss_repair_DB_Hazus_EQ_bldg.json": "seismic/building/portfolio/Hazus v5.1/consequence_repair.json",
"loss_repair_DB_Hazus_EQ_story.csv": "seismic/building/subassembly/Hazus v5.1/consequence_repair.csv",
"loss_repair_DB_Hazus_EQ_story.json": "seismic/building/subassembly/Hazus v5.1/consequence_repair.json",
"loss_repair_DB_Hazus_EQ_trnsp.csv": "seismic/transportation_network/portfolio/Hazus v5.1/consequence_repair.csv",
"loss_repair_DB_Hazus_EQ_trnsp.json": "seismic/transportation_network/portfolio/Hazus v5.1/consequence_repair.json",
"loss_repair_DB_SimCenter_Hazus_HU_bldg.csv": "hurricane/building/portfolio/Hazus v4.2/consequence_repair_fitted.csv",
"combined_loss_matrices/Wind_Flood_Hazus_HU_bldg.csv": "hurricane/building/portfolio/Hazus v4.2/combined_loss_matrices/Wind_Flood.csv"
"Wind_Flood_Hazus_HU_bldg.csv": "hurricane/building/portfolio/Hazus v4.2/combined_loss_matrices/Wind_Flood.csv"
}
2 changes: 2 additions & 0 deletions pelicun/tests/basic/test_damage_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,8 @@ def test__create_dmg_RVs(self, assessment_instance: Assessment) -> None:
for rv_name, rv in capacity_rv_reg.RV.items():
uniform_sample = rv._uni_sample
sample = rv.sample
assert uniform_sample is not None
assert sample is not None
for i in range(len(operation_list)):
if rv_name == 'FRG-cmp.A-1-2-3-1-1':
theta = 1.20 * 30.0
Expand Down
14 changes: 5 additions & 9 deletions pelicun/tests/basic/test_file_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,19 +141,15 @@ def test_save_to_csv() -> None:


def test_substitute_default_path() -> None:
prior_path = file_io.base.pelicun_path
file_io.base.pelicun_path = Path('some_path')
input_paths: list[str | pd.DataFrame] = [
'PelicunDefault/data/file1.txt',
'/data/file2.txt',
]
expected_paths = [
'some_path/resources/SimCenterDBDL/data/file1.txt',
'PelicunDefault/damage_DB_FEMA_P58_2nd.csv',
'/data/file2.txt',
]
result_paths = file_io.substitute_default_path(input_paths)
assert result_paths == expected_paths
file_io.base.pelicun_path = prior_path
assert (
'seismic/building/component/FEMA P-58 2nd Edition/fragility.csv'
) in result_paths[0]
assert result_paths[1] == '/data/file2.txt'


def test_load_data() -> None:
Expand Down
11 changes: 6 additions & 5 deletions pelicun/tests/basic/test_loss_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
import pandas as pd
import pytest

from pelicun import model, uq
from pelicun import file_io, model, uq
from pelicun.base import ensure_value
from pelicun.model.loss_model import (
LossModel,
Expand Down Expand Up @@ -450,11 +450,12 @@ def test_aggregate_losses_combination(
# combined loss, result of interpolation
l_comb = 0.904

file_path = file_io.substitute_default_path(
['PelicunDefault/Wind_Flood_Hazus_HU_bldg.csv']
)[0]
assert isinstance(file_path, str)
combination_array = pd.read_csv(
(
'pelicun/resources/SimCenterDBDL/combined_loss_matrices/'
'Wind_Flood_Hazus_HU_bldg.csv'
),
file_path,
index_col=None,
header=None,
).to_numpy()
Expand Down
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ exclude = [
"rulesets",
"pelicun/tests/dl_calculation/e7/auto_HU_NJ.py",
"pelicun/tests/dl_calculation/e8/auto_HU_LA.py",
"pelicun/tests/dl_calculation/e9/custom_pop.py"
"pelicun/tests/dl_calculation/e9/custom_pop.py",
"pelicun/resources/DamageAndLossModelLibrary/"
]

[tool.ruff.lint]
Expand Down Expand Up @@ -37,7 +38,7 @@ quote-style = "single"

[tool.codespell]
ignore-words = ["ignore_words.txt"]
skip = ["*.html", "./htmlcov/*", "./doc_src/build/*", "./pelicun.egg-info/*", "./doc_src/*", "./doc/build/*", "*/rulesets/*", "custom_pop.py", "*/SimCenterDBDL/*", "auto_HU_NJ.py", "auto_HU_LA.py", "custom_pop.py"]
skip = ["*.html", "./htmlcov/*", "./doc_src/build/*", "./pelicun.egg-info/*", "./doc_src/*", "./doc/build/*", "*/rulesets/*", "custom_pop.py", "*/SimCenterDBDL/*", "auto_HU_NJ.py", "auto_HU_LA.py", "custom_pop.py", "*/resources/DamageAndLossModelLibrary/*"]

[tool.mypy]
ignore_missing_imports = true
Expand Down

0 comments on commit f4d6af5

Please sign in to comment.