Skip to content

Commit

Permalink
Merge pull request #288 from IN-CORE/release-1.9.0
Browse files Browse the repository at this point in the history
Release 1.9.0
  • Loading branch information
navarroc authored Mar 14, 2023
2 parents 045905f + cd19b6d commit cca58b5
Show file tree
Hide file tree
Showing 34 changed files with 4,054 additions and 119 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [1.9.0] - 2023-03-15

### Added
- Method in space service to add a dataset by space name [#273](https://github.com/IN-CORE/pyincore/issues/273)
- Method in space service to get space id by space name [#272](https://github.com/IN-CORE/pyincore/issues/272)
- Method in space service to remove dataset from the space [#283](https://github.com/IN-CORE/pyincore/issues/283)
- Method in space service to remove dataset by space name [#284](https://github.com/IN-CORE/pyincore/issues/284)
- Combined wind, surge-wave, and flood building loss [#276](https://github.com/IN-CORE/pyincore/issues/276)

### Changed
- Rewrote clustering utility function to use flexible archetype column [#247](https://github.com/IN-CORE/pyincore/issues/247)
- Made documentation containter to use requirements instead of environemt [#257](https://github.com/IN-CORE/pyincore/issues/257)
- Parallelized the HHRS analysis [#268](https://github.com/IN-CORE/pyincore/issues/268)
- Updated Salt Lake City CGE [#281](https://github.com/IN-CORE/pyincore/issues/281)
- Tested hurricane windfield test methods [#100](https://github.com/IN-CORE/incore-services/issues/100)
- Updatd Salt Lake City CGE formatting and handled infeasible case [#287](https://github.com/IN-CORE/pyincore/issues/287)

### Fixed
- Duplicate input spec for housing recovery sequential model [#263](https://github.com/IN-CORE/pyincore/issues/263)
- Updated building economic loss analysis to handle case when no occupancy multiplier is provided [#274](https://github.com/IN-CORE/pyincore/issues/274)

## [1.8.0] - 2022-11-16

### Changed
Expand Down
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ USER root

# install packages
WORKDIR /src
COPY environment.yml .
COPY requirements.txt .

ENV PATH "$MAMBA_ROOT_PREFIX/bin:$PATH"
RUN micromamba install -y -n base -c conda-forge \
sphinx sphinx_rtd_theme \
-f environment.yml
-f requirements.txt

# copy code and generate documentation
COPY . ./
Expand Down
4 changes: 2 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
author = ''

# The short X.Y version
version = '1.8'
version = '1.9'
# The full version, including alpha/beta/rc tags
release = '1.8.0'
release = '1.9.0'

# -- General configuration ---------------------------------------------------

Expand Down
6 changes: 6 additions & 0 deletions docs/source/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,15 @@ analyses/capitalshocks
:members:

analyses/combinedwindwavesurgebuildingdamage
============================================
.. autoclass:: pyincore.analyses.combinedwindwavesurgebuildingdamage.CombinedWindWaveSurgeBuildingDamage
:members:

analyses/combinedwindwavesurgebuildingloss
============================================
.. autoclass:: pyincore.analyses.combinedwindwavesurgebuildingloss.CombinedWindWaveSurgeBuildingLoss
:members:

analyses/cumulativebuildingdamage
=================================
.. autoclass:: cumulativebuildingdamage.cumulativebuildingdamage.CumulativeBuildingDamage
Expand Down
1 change: 1 addition & 0 deletions pyincore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from pyincore.utils.analysisutil import AnalysisUtil
from pyincore.utils.popdisloutputprocess import PopDislOutputProcess
from pyincore.utils.cgeoutputprocess import CGEOutputProcess
from pyincore.utils.hhrsoutputprocess import HHRSOutputProcess
from pyincore.dataset import Dataset, InventoryDataset, DamageRatioDataset
from pyincore.models.fragilitycurveset import FragilityCurveSet
from pyincore.models.repaircurveset import RepairCurveSet
Expand Down
10 changes: 7 additions & 3 deletions pyincore/analyses/buildingeconloss/buildingeconloss.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,12 @@ def run(self):
bldg_set = self.get_input_dataset("buildings").get_inventory_reader()

# Occupancy type of the exposure
occ_multiplier = self.get_input_dataset("occupancy_multiplier").get_csv_reader()
occ_mult_df = pd.DataFrame(occ_multiplier)
occ_multiplier = self.get_input_dataset("occupancy_multiplier")
if occ_multiplier is not None:
occ_multiplier = occ_multiplier.get_csv_reader()
occ_mult_df = pd.DataFrame(occ_multiplier)
else:
occ_mult_df = None

try:
prop_select = []
Expand Down Expand Up @@ -112,7 +116,7 @@ def add_multipliers(self, dmg_set_df, occ_mult_df):
dmg_set_df = pd.merge(dmg_set_df, occ_mult_df, how="left", left_on="occ_type",
right_on="occ_type", sort=True, copy=True)
else:
dmg_set_df = dmg_set_df["Multiplier"] = 1.0
dmg_set_df["Multiplier"] = 1.0

return dmg_set_df

Expand Down
83 changes: 52 additions & 31 deletions pyincore/analyses/buildingfunctionality/buildingfunctionality.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,9 @@ def run(self):
else:
poles_df = None

# All three above needs to be present at the same time or none
if not all(epf is None for epf in [interdependency_dict, substations_df, poles_df]) \
and not all(epf is not None for epf in [interdependency_dict, substations_df, poles_df]):
raise ValueError("To consider electric power availability in the analysis, please provide pole damage "
"samples, substation damage samples, and interdependency.")
if (poles_dataset is not None or substations_dataset is not None) and interdependency_dataset is None:
raise ValueError("Please provide interdependency table if pole or substation damage is "
"considered in the building functionality calculation.")

functionality_probabilities = []
functionality_samples = []
Expand Down Expand Up @@ -168,30 +166,53 @@ def functionality(self, building_guid, buildings, substations, poles, interdepen
if interdependency is not None:

if building_guid in interdependency.keys():
substations_mc_samples = substations.loc[interdependency[building_guid]["substations_guid"]]
poles_mc_samples = poles.loc[interdependency[building_guid]["poles_guid"]]

substation_list = []
try:
substation_list = substations_mc_samples["failure"].split(",")
except IndexError:
print("error with substations")
print(interdependency[building_guid]["substations_guid"])
return {building_guid: -1}

pole_list = []
try:
pole_list = poles_mc_samples["failure"].split(",")
except IndexError:
print("error with poles")
print(interdependency[building_guid]["poles_guid"])
return {building_guid: -1}

functionality_samples = [BuildingFunctionality._calc_functionality_samples(building_sample,
substation_sample,
pole_sample)
for building_sample, substation_sample, pole_sample in
zip(building_list, substation_list, pole_list)]
if substations is not None:
substations_mc_samples = substations.loc[interdependency[building_guid]["substations_guid"]]
substation_list = []
try:
substation_list = substations_mc_samples["failure"].split(",")
except IndexError:
print("error with substations")
print(interdependency[building_guid]["substations_guid"])
return {building_guid: -1}
else:
substation_list = None

if poles is not None:
poles_mc_samples = poles.loc[interdependency[building_guid]["poles_guid"]]
pole_list = []
try:
pole_list = poles_mc_samples["failure"].split(",")
except IndexError:
print("error with poles")
print(interdependency[building_guid]["poles_guid"])
return {building_guid: -1}
else:
pole_list = None

if substation_list is not None and pole_list is not None:
functionality_samples = [BuildingFunctionality._calc_functionality_samples(building_sample,
substation_sample,
pole_sample)
for building_sample, substation_sample, pole_sample in
zip(building_list, substation_list, pole_list)]
elif substation_list is not None:
functionality_samples = [BuildingFunctionality._calc_functionality_samples(building_sample,
substation_sample,
None)
for building_sample, substation_sample in
zip(building_list, substation_list)]
elif pole_list is not None:
functionality_samples = [BuildingFunctionality._calc_functionality_samples(building_sample,
None,
pole_sample)
for building_sample, pole_sample in
zip(building_list, pole_list)]
else:
functionality_samples = [BuildingFunctionality._calc_functionality_samples(building_sample,
None,
None)
for building_sample in building_list]
probability = BuildingFunctionality._calc_functionality_probability(functionality_samples)
return building_guid, ",".join([str(sample) for sample in functionality_samples]), probability

Expand All @@ -212,8 +233,8 @@ def _calc_functionality_samples(building_sample, substation_sample=None, pole_sa
Args:
building_sample (str): Monte Carlo samples of building functionality.
substation_sample (str): Monte Carlo samples of substation functionality.
pole_sample (str): Monte Carlo samples of pole functionality.
substation_sample (str|None): Monte Carlo samples of substation functionality.
pole_sample (str|None): Monte Carlo samples of pole functionality.
Returns:
int: 1 if building is functional, 0 otherwise
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

class CombinedWindWaveSurgeBuildingDamage(BaseAnalysis):
""" Determines overall building maximum damage state from wind, flood and surge-wave damage
and uses the maximum damage probabilities from the 3 damages to determine overall damage
Args:
incore_client (IncoreClient): Service authentication.
Expand Down Expand Up @@ -63,10 +64,70 @@ def run(self):
combined_output['f_max_ds'] = combined_output['f_max_ds'].replace(old_ds_vals, new_ds_vals)
combined_output['max_state'] = combined_output['max_state'].replace(old_ds_vals, new_ds_vals)

# Find combined damage
combined_bldg_dmg = self.get_combined_damage(wind_damage, surge_wave_damage, flood_damage)

# Create the result containing the 3 combined damages into a single damage
self.set_result_csv_data("ds_result", combined_bldg_dmg, self.get_parameter("result_name") + "_combined_dmg",
"dataframe")

# Create the result dataset
self.set_result_csv_data("result", combined_output, self.get_parameter("result_name"), "dataframe")

return True

def get_combined_damage(self, wind_dmg: pd.DataFrame, sw_dmg: pd.DataFrame, flood_dmg: pd.DataFrame):
"""Calculates overall building damage
Determines the overall building damage probabilities from the 3 hazards by taking the maximum.
Args:
wind_dmg (pd.DataFrame): Table of wind damage for the building inventory
sw_dmg (pd.DataFrame): Table of surge-wave damage for the building inventory
flood_dmg (pd.DataFrame): Table of flood damage for the building inventory
Returns:
pd.DataFrame: An table of combined damage probabilities for the building inventory
"""
flood_dmg.rename(columns={'LS_0': 'f_LS_0', 'LS_1': 'f_LS_1', 'LS_2': 'f_LS_2', 'DS_0': 'f_DS_0',
'DS_1': 'f_DS_1', 'DS_2': 'f_DS_2', 'DS_3': 'f_DS_3', 'haz_expose': 'f_haz_expose'},
inplace=True)

sw_dmg.rename(columns={'LS_0': 'sw_LS_0', 'LS_1': 'sw_LS_1', 'LS_2': 'sw_LS_2', 'DS_0': 'sw_DS_0',
'DS_1': 'sw_DS_1', 'DS_2': 'sw_DS_2', 'DS_3': 'sw_DS_3', 'haz_expose':
'sw_haz_expose'}, inplace=True)

wind_dmg.rename(columns={'LS_0': 'w_LS_0', 'LS_1': 'w_LS_1', 'LS_2': 'w_LS_2', 'DS_0': 'w_DS_0',
'DS_1': 'w_DS_1', 'DS_2': 'w_DS_2', 'DS_3': 'w_DS_3', 'haz_expose': 'w_haz_expose'},
inplace=True)

combined_df = pd.merge(pd.merge(wind_dmg, sw_dmg, on='guid'), flood_dmg, on='guid')

def find_match(row, col_name):
max_finder = {
row['f_DS_3']: 'f_',
row['w_DS_3']: 'w_',
row['sw_DS_3']: 'sw_'
}

return row[max_finder[max(max_finder.keys())] + col_name]

combined_df['LS_0'] = combined_df.apply(lambda x: find_match(x, col_name="LS_0"), axis=1)
combined_df['LS_1'] = combined_df.apply(lambda x: find_match(x, col_name="LS_1"), axis=1)
combined_df['LS_2'] = combined_df.apply(lambda x: find_match(x, col_name="LS_2"), axis=1)
combined_df['DS_0'] = combined_df.apply(lambda x: find_match(x, col_name="DS_0"), axis=1)
combined_df['DS_1'] = combined_df.apply(lambda x: find_match(x, col_name="DS_1"), axis=1)
combined_df['DS_2'] = combined_df.apply(lambda x: find_match(x, col_name="DS_2"), axis=1)
combined_df['DS_3'] = combined_df.apply(lambda x: find_match(x, col_name="DS_3"), axis=1)
combined_df['haz_expose'] = combined_df.apply(lambda x: find_match(x, col_name="haz_expose"), axis=1)

# Remove extra columns that are no longer needed
combined_df.drop(['w_LS_0', 'w_LS_1', 'w_LS_2', 'sw_LS_0', 'sw_LS_1', 'sw_LS_2', 'f_LS_0', 'f_LS_1',
'f_LS_2', 'w_DS_0', 'w_DS_1', 'w_DS_2', 'w_DS_3', 'sw_DS_0', 'sw_DS_1', 'sw_DS_2', 'sw_DS_3',
'f_DS_0', 'f_DS_1', 'f_DS_2', 'f_DS_3', 'w_haz_expose', 'sw_haz_expose', 'f_haz_expose'],
axis=1, inplace=True)

return combined_df

def get_spec(self):
"""Get specifications of the combined wind, wave, and surge building damage analysis.
Expand Down Expand Up @@ -108,6 +169,12 @@ def get_spec(self):

],
'output_datasets': [
{
'id': 'ds_result',
'parent_type': 'buildings',
'description': 'CSV file of damage states for building structural damage',
'type': 'ergo:buildingDamageVer6'
},
{
'id': 'result',
'parent_type': 'buildings',
Expand Down
10 changes: 10 additions & 0 deletions pyincore/analyses/combinedwindwavesurgebuildingloss/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (c) 2023 University of Illinois and others. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Mozilla Public License v2.0 which accompanies this distribution,
# and is available at https://www.mozilla.org/en-US/MPL/2.0/


from pyincore.analyses.combinedwindwavesurgebuildingloss.combinedwindwavesurgebuildingloss import \
CombinedWindWaveSurgeBuildingLoss

Loading

0 comments on commit cca58b5

Please sign in to comment.