Skip to content

Commit e9df568

Browse files
authored
Merge pull request #30 from zsarnoczay/main
Add Pelicun config files for Hazus 6.1 seismic
2 parents 7bdd7be + 756cb28 commit e9df568

2 files changed

Lines changed: 320 additions & 0 deletions

File tree

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"type": "object",
4+
"properties": {
5+
"StructureType":{
6+
"type": "string",
7+
"enum": [
8+
"W1", "W2",
9+
"S1", "S2", "S3", "S4", "S5",
10+
"C1", "C2", "C3",
11+
"PC1", "PC2",
12+
"RM1", "RM2", "URM",
13+
"MH"
14+
]
15+
},
16+
"DesignLevel":{
17+
"type": "string",
18+
"enum": [
19+
"Pre-Code",
20+
"Low-Code",
21+
"Moderate-Code",
22+
"High-Code",
23+
"Very High-Code",
24+
"Severe-Code"
25+
]
26+
},
27+
"HeightClass":{
28+
"type": ["string","null"],
29+
"enum": [
30+
"Low-Rise",
31+
"Mid-Rise",
32+
"High-Rise",
33+
null
34+
]
35+
},
36+
"GroundFailure": {
37+
"type": "boolean"
38+
},
39+
"FoundationType":{
40+
"type": "string",
41+
"enum": [
42+
"Shallow",
43+
"Deep"
44+
]
45+
},
46+
"OccupancyClass": {
47+
"type": "string",
48+
"enum": [
49+
"RES1","RES2","RES3","RES4","RES5","RES6",
50+
"COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","COM10",
51+
"IND1","IND2","IND3","IND4","IND5","IND6",
52+
"AGR1",
53+
"REL1",
54+
"GOV1","GOV2",
55+
"EDU1","EDU2"
56+
]
57+
}
58+
},
59+
"required": ["StructureType","DesignLevel"],
60+
"allOf": [
61+
{
62+
"if": {
63+
"properties": {
64+
"StructureType": {
65+
"enum": [
66+
"S1", "S2", "S4", "S5",
67+
"C1", "C2", "C3",
68+
"PC2",
69+
"RM1", "RM2", "URM"
70+
]
71+
}
72+
}
73+
},
74+
"then": {
75+
"properties": {
76+
"HeightClass": {
77+
"type": "string"
78+
}
79+
},
80+
"required": ["HeightClass"]
81+
},
82+
"else": {
83+
"properties": {
84+
"HeightClass": {
85+
"type": "null"
86+
}
87+
},
88+
"required": []
89+
}
90+
},
91+
{
92+
"if": {
93+
"properties": {
94+
"StructureType": {
95+
"enum": [
96+
"RM1", "URM"
97+
]
98+
}
99+
}
100+
},
101+
"then": {
102+
"properties": {
103+
"HeightClass": {
104+
"enum": [
105+
"Low-Rise",
106+
"Mid-Rise"
107+
]
108+
}
109+
}
110+
}
111+
},
112+
{
113+
"if": {
114+
"properties": {
115+
"StructureType": {
116+
"enum": [
117+
"S5", "C3", "URM"
118+
]
119+
}
120+
}
121+
},
122+
"then": {
123+
"properties": {
124+
"DesignLevel": {
125+
"enum": [
126+
"Pre-Code",
127+
"Low-Code"
128+
]
129+
}
130+
}
131+
}
132+
},
133+
{
134+
"if": {
135+
"properties": {
136+
"GroundFailure":{
137+
"const": true
138+
}
139+
}
140+
},
141+
"then": {
142+
"required": ["FoundationType"]
143+
}
144+
}
145+
]
146+
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#
2+
# Copyright (c) 2023 Leland Stanford Junior University
3+
# Copyright (c) 2023 The Regents of the University of California
4+
#
5+
# This file is part of pelicun.
6+
#
7+
# Redistribution and use in source and binary forms, with or without
8+
# modification, are permitted provided that the following conditions are met:
9+
#
10+
# 1. Redistributions of source code must retain the above copyright notice,
11+
# this list of conditions and the following disclaimer.
12+
#
13+
# 2. Redistributions in binary form must reproduce the above copyright notice,
14+
# this list of conditions and the following disclaimer in the documentation
15+
# and/or other materials provided with the distribution.
16+
#
17+
# 3. Neither the name of the copyright holder nor the names of its contributors
18+
# may be used to endorse or promote products derived from this software without
19+
# specific prior written permission.
20+
#
21+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31+
# POSSIBILITY OF SUCH DAMAGE.
32+
#
33+
# You should have received a copy of the BSD 3-Clause License along with
34+
# pelicun. If not, see <http://www.opensource.org/licenses/>.
35+
#
36+
# Contributors:
37+
# Adam Zsarnóczay
38+
# Aakash Bangalore Satish
39+
40+
import json
41+
from pathlib import Path
42+
43+
import jsonschema
44+
from jsonschema import validate
45+
import pandas as pd
46+
47+
48+
def auto_populate(aim):
49+
"""
50+
Automatically creates a performance model for PGA-based Hazus EQ analysis.
51+
52+
Parameters
53+
----------
54+
AIM: dict
55+
Asset Information Model - provides features of the asset that can be
56+
used to infer attributes of the performance model.
57+
58+
Returns
59+
-------
60+
gi: dict
61+
The GI from the input AIM. Kept for backwards-compatibility, will be
62+
removed eventually.
63+
TODO(adamzs): remove this output once all auto-pop scripts have been
64+
replaced by mapping scripts.
65+
dl_ap: dict
66+
Damage and Loss parameters - these define the performance model and
67+
details of the calculation.
68+
comp: DataFrame
69+
Component assignment - Defines the components (in rows) and their
70+
location, direction, and quantity (in columns).
71+
"""
72+
73+
# extract the General Information
74+
gi = aim.get("GeneralInformation")
75+
76+
# make sure missing data is properly represented as null in the JSON
77+
for key, item in gi.items():
78+
if pd.isna(item):
79+
gi[key] = None
80+
81+
# add configuration data to the gi if it is not already there
82+
dl_app_data = aim['Applications']['DL']['ApplicationData']
83+
if gi.get("GroundFailure", None) == None:
84+
gi["GroundFailure"] = dl_app_data.get('ground_failure',None)
85+
86+
# load the schema assuming it is called "input_schema.json" and it is
87+
# stored next to the mapping script
88+
current_file_path = Path(__file__)
89+
current_directory = current_file_path.parent
90+
91+
with Path(current_directory / "input_schema.json").open(encoding="utf-8") as f:
92+
input_schema = json.load(f)
93+
94+
# validate the provided features against the required inputs
95+
try:
96+
validate(instance=gi, schema=input_schema)
97+
except jsonschema.exceptions.ValidationError as exc: # type: ignore
98+
msg = (
99+
"The provided building information does not conform to the input"
100+
" requirements for the chosen damage and loss model."
101+
)
102+
103+
raise ValueError(msg) from exc
104+
105+
# prepare the labels for model IDs
106+
structure_type = gi["StructureType"]
107+
108+
design_level_map = {
109+
"Pre-Code": "PC",
110+
"Low-Code": "LC",
111+
"Moderate-Code": "MC",
112+
"High-Code": "HC",
113+
"Very High-Code": "VC",
114+
"Severe-Code": "SC"
115+
}
116+
design_level = design_level_map[gi["DesignLevel"]]
117+
118+
height_class_map = {"Low-Rise": "L", "Mid-Rise": "M", "High-Rise": "H"}
119+
height_class_data = gi.get("HeightClass")
120+
121+
if height_class_data is not None:
122+
height_class = height_class_map[height_class_data]
123+
model_id = f"LF.{structure_type}.{height_class}.{design_level}"
124+
else:
125+
model_id = f"LF.{structure_type}.{design_level}"
126+
127+
comp = pd.DataFrame(
128+
{f"{model_id}": ["ea", 1, 1, 1, "N/A"]}, # noqa: E241
129+
index=["Units", "Location", "Direction", "Theta_0", "Family"], # noqa: E231, E251
130+
).T
131+
132+
# if needed, add components to simulate damage from ground failure
133+
if gi.get("GroundFailure"):
134+
foundation_type_map = {"Shallow": "S", "Deep": "D"}
135+
foundation_type = foundation_type_map[gi["FoundationType"]]
136+
137+
gf_model_id_h = f"GF.H.{foundation_type}"
138+
gf_model_id_v = f"GF.V.{foundation_type}"
139+
140+
comp_gf = pd.DataFrame(
141+
{
142+
f"{gf_model_id_h}": ["ea", 1, 1, 1, "N/A"], # noqa: E201, E231, E241
143+
f"{gf_model_id_v}": ["ea", 1, 3, 1, "N/A"],
144+
}, # noqa: E201, E231, E241
145+
index=["Units", "Location", "Direction", "Theta_0", "Family"], # noqa: E201, E231, E251
146+
).T
147+
148+
comp = pd.concat([comp, comp_gf], axis=0)
149+
150+
# get the occupancy class
151+
occupancy_type = gi["OccupancyClass"]
152+
153+
dl_ap = {
154+
"Asset": {
155+
"ComponentAssignmentFile": "CMP_QNT.csv",
156+
"ComponentDatabase": "Hazus Earthquake - Buildings",
157+
"NumberOfStories": 1, # there is only one component in a building-level resolution
158+
"OccupancyType": f"{occupancy_type}",
159+
"PlanArea": "1", # TODO(adamzs): check if this is even needed
160+
},
161+
"Damage": {"DamageProcess": "Hazus Earthquake"},
162+
"Demands": {},
163+
"Losses": {
164+
"Repair": {
165+
"ConsequenceDatabase": "Hazus Earthquake - Buildings",
166+
"MapApproach": "Automatic",
167+
}
168+
},
169+
"Options": {
170+
"NonDirectionalMultipliers": {"ALL": 1.0},
171+
},
172+
}
173+
174+
return gi, dl_ap, comp

0 commit comments

Comments
 (0)