Skip to content

Commit

Permalink
Merge pull request #60 from jinyan1214/releasedVersion
Browse files Browse the repository at this point in the history
jz - add Capacity Spectrum Method auto pop fix the bug in auto_pop when GF is not needed for transportation
  • Loading branch information
zsarnoczay authored Sep 30, 2024
2 parents 89a13ae + b95f304 commit 8954b62
Show file tree
Hide file tree
Showing 2 changed files with 326 additions and 5 deletions.
290 changes: 290 additions & 0 deletions pelicun/resources/auto/Hazus_Earthquake_CSM.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2023 Leland Stanford Junior University
# Copyright (c) 2023 The Regents of the University of California
#
# This file is part of pelicun.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# You should have received a copy of the BSD 3-Clause License along with
# pelicun. If not, see <http://www.opensource.org/licenses/>.
#
# Contributors:
# Adam Zsarnóczay

import pandas as pd

ap_DesignLevel = {1940: "LC", 1975: "MC", 2100: "HC"}
# ap_DesignLevel = {1940: 'PC', 1940: 'LC', 1975: 'MC', 2100: 'HC'}

ap_DesignLevel_W1 = {0: "LC", 1975: "MC", 2100: "HC"}
# ap_DesignLevel_W1 = {0: 'PC', 0: 'LC', 1975: 'MC', 2100: 'HC'}

ap_Occupancy = {
"Other/Unknown": "RES3",
"Residential - Single-Family": "RES1",
"Residential - Town-Home": "RES3",
"Residential - Multi-Family": "RES3",
"Residential - Mixed Use": "RES3",
"Office": "COM4",
"Hotel": "RES4",
"School": "EDU1",
"Industrial - Light": "IND2",
"Industrial - Warehouse": "IND2",
"Industrial - Heavy": "IND1",
"Retail": "COM1",
"Parking": "COM10",
}

convert_design_level = {
"High-Code": "HC",
"Moderate-Code": "MC",
"Low-Code": "LC",
"Pre-Code": "PC",
}


def convert_story_rise(structureType, stories):
if structureType in ["W1", "W2", "S3", "PC1", "MH"]:
# These archetypes have no rise information in their IDs
rise = None

else:
# First, check if we have valid story information
try:
stories = int(stories)

except (ValueError, TypeError):
raise ValueError(
'Missing "NumberOfStories" information, '
"cannot infer `rise` attribute of archetype"
)

if structureType == "RM1":
if stories <= 3:
rise = "L"

else:
rise = "M"

elif structureType == "URM":
if stories <= 2:
rise = "L"

else:
rise = "M"

elif structureType in [
"S1",
"S2",
"S4",
"S5",
"C1",
"C2",
"C3",
"PC2",
"RM2",
]:
if stories <= 3:
rise = "L"

elif stories <= 7:
rise = "M"

else:
rise = "H"

return rise


def auto_populate(AIM):
"""
Automatically creates a performance model for story EDP-based Hazus EQ analysis.
Parameters
----------
AIM: dict
Asset Information Model - provides features of the asset that can be
used to infer attributes of the performance model.
Returns
-------
GI_ap: dict
Extended General Information - extends the GI from the input AIM with
additional inferred features. These features are typically used in
intermediate steps during the auto-population and are not required
for the performance assessment. They are returned to allow reviewing
how these latent variables affect the final results.
DL_ap: dict
Damage and Loss parameters - these define the performance model and
details of the calculation.
CMP: DataFrame
Component assignment - Defines the components (in rows) and their
location, direction, and quantity (in columns).
"""

# extract the General Information
GI = AIM.get("GeneralInformation", None)

if GI is None:
# TODO: show an error message
pass

# initialize the auto-populated GI
GI_ap = GI.copy()

assetType = AIM["assetType"]
ground_failure = AIM["Applications"]["DL"]["ApplicationData"]["ground_failure"]

if assetType == "Buildings":
# get the building parameters
bt = GI["StructureType"] # building type

# get the design level
dl = GI.get("DesignLevel", None)

if dl is None:
# If there is no DesignLevel provided, we assume that the YearBuilt is
# available
year_built = GI["YearBuilt"]

if "W1" in bt:
DesignL = ap_DesignLevel_W1
else:
DesignL = ap_DesignLevel

for year in sorted(DesignL.keys()):
if year_built <= year:
dl = DesignL[year]
break

GI_ap["DesignLevel"] = dl
# get the number of stories / height
stories = GI.get("NumberOfStories", None)

# We assume that the structure type does not include height information
# and we append it here based on the number of story information
rise = convert_story_rise(bt, stories)

# get the number of stories / height
stories = GI.get("NumberOfStories", None)

if rise is None:
# To prevent STR.W2.None.LC
FG_S = f"STR.{bt}.{dl}"
else:
FG_S = f"STR.{bt}.{rise}.{dl}"
# FG_S = f"STR.{bt}.{dl}"
FG_NSD = "NSD"
FG_NSA = f"NSA.{dl}"

CMP = pd.DataFrame(
{
f"{FG_S}": [
"ea",
1,
1,
1,
"N/A",
],
f"{FG_NSA}": [
"ea",
1,
0,
1,
"N/A",
],
f"{FG_NSD}": [
"ea",
1,
1,
1,
"N/A",
],
},
index=["Units", "Location", "Direction", "Theta_0", "Family"],
).T

# if needed, add components to simulate damage from ground failure
if ground_failure:
foundation_type = "S"

# fmt: off
FG_GF_H = f'GF.H.{foundation_type}' # noqa
FG_GF_V = f'GF.V.{foundation_type}' # noqa
CMP_GF = pd.DataFrame( # noqa
{f'{FG_GF_H}':[ 'ea', 1, 1, 1, 'N/A'], # noqa
f'{FG_GF_V}':[ 'ea', 1, 3, 1, 'N/A']}, # noqa
index = [ 'Units','Location','Direction','Theta_0','Family'] # noqa
).T # noqa
# fmt: on

CMP = pd.concat([CMP, CMP_GF], axis=0)

# get the occupancy class
if GI["OccupancyClass"] in ap_Occupancy.keys():
ot = ap_Occupancy[GI["OccupancyClass"]]
else:
ot = GI["OccupancyClass"]

plan_area = GI.get("PlanArea", 1.0)

repair_config = {
"ConsequenceDatabase": "Hazus Earthquake - Buildings",
"MapApproach": "Automatic",
"DecisionVariables": {
"Cost": True,
"Carbon": False,
"Energy": False,
"Time": False,
},
}

DL_ap = {
"Asset": {
"ComponentAssignmentFile": "CMP_QNT.csv",
"ComponentDatabase": "Hazus Earthquake - Buildings",
"NumberOfStories": f"{stories}",
"OccupancyType": f"{ot}",
"PlanArea": str(plan_area),
},
"Damage": {"DamageProcess": "Hazus Earthquake"},
"Demands": {},
"Losses": {"Repair": repair_config},
"Options": {
"NonDirectionalMultipliers": {"ALL": 1.0},
},
}

else:
print(
f"AssetType: {assetType} is not supported "
f"in Hazus Earthquake Capacity Spectrum Method-based DL method"
)

return GI_ap, DL_ap, CMP
41 changes: 36 additions & 5 deletions pelicun/resources/auto/Hazus_Earthquake_IM.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,11 +423,21 @@ def auto_populate(AIM):

# fmt: off
CMP = pd.DataFrame( # noqa
{f'HWB.GS.{bt[3:]}': [ 'ea', 1, 1, 1, 'N/A'], # noqa
f'HWB.GF': [ 'ea', 1, 1, 1, 'N/A']}, # noqa
{f'HWB.GS.{bt[3:]}': [ 'ea', 1, 1, 1, 'N/A']}, # noqa
index = [ 'Units','Location','Direction','Theta_0','Family'] # noqa
).T # noqa
# fmt: on
# if needed, add components to simulate damage from ground failure
if ground_failure:

# fmt: off
CMP_GF = pd.DataFrame( # noqa
{f'HWB.GF': [ 'ea', 1, 1, 1, 'N/A']}, # noqa
index = [ 'Units','Location','Direction','Theta_0','Family'] # noqa
).T # noqa
# fmt: on

CMP = pd.concat([CMP, CMP_GF], axis=0)

DL_ap = {
"Asset": {
Expand Down Expand Up @@ -456,11 +466,21 @@ def auto_populate(AIM):

# fmt: off
CMP = pd.DataFrame( # noqa
{f'HTU.GS.{tt[3:]}': [ 'ea', 1, 1, 1, 'N/A'], # noqa
f'HTU.GF': [ 'ea', 1, 1, 1, 'N/A']}, # noqa
{f'HTU.GS.{tt[3:]}': [ 'ea', 1, 1, 1, 'N/A']}, # noqa
index = [ 'Units','Location','Direction','Theta_0','Family'] # noqa
).T # noqa
# fmt: on
# if needed, add components to simulate damage from ground failure
if ground_failure:

# fmt: off
CMP_GF = pd.DataFrame( # noqa
{f'HTU.GF': [ 'ea', 1, 1, 1, 'N/A']}, # noqa
index = [ 'Units','Location','Direction','Theta_0','Family'] # noqa
).T # noqa
# fmt: on

CMP = pd.concat([CMP, CMP_GF], axis=0)

DL_ap = {
"Asset": {
Expand Down Expand Up @@ -488,11 +508,22 @@ def auto_populate(AIM):

# fmt: off
CMP = pd.DataFrame( # noqa
{f'HRD.GF.{rt[3:]}':[ 'ea', 1, 1, 1, 'N/A']}, # noqa
{}, # noqa
index = [ 'Units','Location','Direction','Theta_0','Family'] # noqa
).T # noqa
# fmt: on

if ground_failure:

# fmt: off
CMP_GF = pd.DataFrame( # noqa
{f'HRD.GF.{rt[3:]}':[ 'ea', 1, 1, 1, 'N/A']}, # noqa
index = [ 'Units','Location','Direction','Theta_0','Family'] # noqa
).T # noqa
# fmt: on

CMP = pd.concat([CMP, CMP_GF], axis=0)

DL_ap = {
"Asset": {
"ComponentAssignmentFile": "CMP_QNT.csv",
Expand Down

0 comments on commit 8954b62

Please sign in to comment.