From b42cb3fd6d49df4dbf68d40754773ce50c0feb4c Mon Sep 17 00:00:00 2001 From: John Vouvakis Manousakis Date: Thu, 24 Oct 2024 05:43:01 -0700 Subject: [PATCH] Revert changes to ruleset files. --- .../rulesets/BldgClassRulesets.py | 183 ++----- .../rulesets/BuildingClassRulesets.py | 189 +++----- .../rulesets/FloodAssmRulesets.py | 117 ++--- .../rulesets/FloodClassRulesets.py | 237 ++++----- .../dl_calculation/rulesets/FloodRulesets.py | 236 ++++----- .../rulesets/MetaVarRulesets.py | 453 ++++++++---------- .../rulesets/WindCECBRulesets.py | 94 ++-- .../rulesets/WindCERBRulesets.py | 93 ++-- .../dl_calculation/rulesets/WindEFRulesets.py | 279 +++++------ .../rulesets/WindMECBRulesets.py | 105 ++-- .../rulesets/WindMERBRulesets.py | 107 +++-- .../dl_calculation/rulesets/WindMHRulesets.py | 65 ++- .../rulesets/WindMLRIRulesets.py | 92 ++-- .../rulesets/WindMLRMRulesets.py | 236 +++++---- .../rulesets/WindMMUHRulesets.py | 158 +++--- .../rulesets/WindMSFRulesets.py | 221 +++++---- .../rulesets/WindMetaVarRulesets.py | 413 ++++++++-------- .../rulesets/WindSECBRulesets.py | 102 ++-- .../rulesets/WindSERBRulesets.py | 101 ++-- .../rulesets/WindSPMBRulesets.py | 68 +-- .../rulesets/WindWMUHRulesets.py | 180 +++---- .../rulesets/WindWSFRulesets.py | 195 ++++---- pyproject.toml | 4 +- 23 files changed, 1849 insertions(+), 2079 deletions(-) diff --git a/pelicun/tests/dl_calculation/rulesets/BldgClassRulesets.py b/pelicun/tests/dl_calculation/rulesets/BldgClassRulesets.py index fd1f53bdf..60432ff41 100644 --- a/pelicun/tests/dl_calculation/rulesets/BldgClassRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/BldgClassRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,10 +43,13 @@ # Meredith Lockhead # Tracy Kijewski-Correa +import random +import numpy as np +import datetime -def building_class(bim: dict, hazard: str) -> str: # noqa: C901 +def building_class(BIM, hazard): """ - Short description. + Short description Long description @@ -60,182 +64,97 @@ def building_class(bim: dict, hazard: str) -> str: # noqa: C901 ------- bldg_class: str One of the standard building class labels from HAZUS - """ + # check hazard - if hazard not in {'wind', 'inundation'}: - print(f'WARNING: The provided hazard is not recognized: {hazard}') # noqa: T201 + if hazard not in ['wind', 'inundation']: + print(f'WARNING: The provided hazard is not recognized: {hazard}') if hazard == 'wind': - if bim['BuildingType'] == 'Wood': - if (bim['OccupancyClass'] == 'RES1') or ( - (bim['RoofShape'] != 'flt') and (bim['OccupancyClass'] == '') # noqa: PLC1901 - ): + if BIM['BuildingType'] == "Wood": + if ((BIM['OccupancyClass'] == 'RES1') or + ((BIM['RoofShape'] != 'flt') and (BIM['OccupancyClass'] == ''))): # OccupancyClass = RES1 # Wood Single-Family Homes (WSF1 or WSF2) # OR roof type = flat (HAZUS can only map flat to WSF1) # OR default (by '') - if ( - bim['RoofShape'] == 'flt' - ): # checking if there is a misclassication - bim['RoofShape'] = ( - # ensure the WSF has gab (by default, note gab - # is more vulnerable than hip) - 'gab' - ) + if BIM['RoofShape'] == 'flt': # checking if there is a misclassication + BIM['RoofShape'] = 'gab' # ensure the WSF has gab (by default, note gab is more vulneable than hip) bldg_class = 'WSF' else: # OccupancyClass = RES3, RES5, RES6, or COM8 # Wood Multi-Unit Hotel (WMUH1, WMUH2, or WMUH3) bldg_class = 'WMUH' - elif bim['BuildingType'] == 'Steel': - if (bim['DesignLevel'] == 'E') and ( - bim['OccupancyClass'] - in {'RES3A', 'RES3B', 'RES3C', 'RES3D', 'RES3E', 'RES3F'} - ): + elif BIM['BuildingType'] == "Steel": + if ((BIM['DesignLevel'] == 'E') and + (BIM['OccupancyClass'] in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + 'RES3E', 'RES3F'])): # Steel Engineered Residential Building (SERBL, SERBM, SERBH) bldg_class = 'SERB' - elif (bim['DesignLevel'] == 'E') and ( - bim['OccupancyClass'] - in { - 'COM1', - 'COM2', - 'COM3', - 'COM4', - 'COM5', - 'COM6', - 'COM7', - 'COM8', - 'COM9', - 'COM10', - } - ): + elif ((BIM['DesignLevel'] == 'E') and + (BIM['OccupancyClass'] in ['COM1', 'COM2', 'COM3', 'COM4', 'COM5', + 'COM6', 'COM7', 'COM8', 'COM9','COM10'])): # Steel Engineered Commercial Building (SECBL, SECBM, SECBH) bldg_class = 'SECB' - elif (bim['DesignLevel'] == 'PE') and ( - bim['OccupancyClass'] - not in {'RES3A', 'RES3B', 'RES3C', 'RES3D', 'RES3E', 'RES3F'} - ): + elif ((BIM['DesignLevel'] == 'PE') and + (BIM['OccupancyClass'] not in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + 'RES3E', 'RES3F'])): # Steel Pre-Engineered Metal Building (SPMBS, SPMBM, SPMBL) bldg_class = 'SPMB' else: bldg_class = 'SECB' - elif bim['BuildingType'] == 'Concrete': - if (bim['DesignLevel'] == 'E') and ( - bim['OccupancyClass'] - in { - 'RES3A', - 'RES3B', - 'RES3C', - 'RES3D', - 'RES3E', - 'RES3F', - 'RES5', - 'RES6', - } - ): + elif BIM['BuildingType'] == "Concrete": + if ((BIM['DesignLevel'] == 'E') and + (BIM['OccupancyClass'] in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + 'RES3E', 'RES3F', 'RES5', 'RES6'])): # Concrete Engineered Residential Building (CERBL, CERBM, CERBH) bldg_class = 'CERB' - elif (bim['DesignLevel'] == 'E') and ( - bim['OccupancyClass'] - in { - 'COM1', - 'COM2', - 'COM3', - 'COM4', - 'COM5', - 'COM6', - 'COM7', - 'COM8', - 'COM9', - 'COM10', - } - ): + elif ((BIM['DesignLevel'] == 'E') and + (BIM['OccupancyClass'] in ['COM1', 'COM2', 'COM3', 'COM4', 'COM5', + 'COM6', 'COM7', 'COM8', 'COM9','COM10'])): # Concrete Engineered Commercial Building (CECBL, CECBM, CECBH) bldg_class = 'CECB' else: bldg_class = 'CECB' - elif bim['BuildingType'] == 'Masonry': - if bim['OccupancyClass'] == 'RES1': + elif BIM['BuildingType'] == "Masonry": + if BIM['OccupancyClass'] == 'RES1': # OccupancyClass = RES1 # Masonry Single-Family Homes (MSF1 or MSF2) bldg_class = 'MSF' - elif ( - bim['OccupancyClass'] - in {'RES3A', 'RES3B', 'RES3C', 'RES3D', 'RES3E', 'RES3F'} - ) and (bim['DesignLevel'] == 'E'): + elif ((BIM['OccupancyClass'] in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + 'RES3E', 'RES3F']) and (BIM['DesignLevel'] == 'E')): # Masonry Engineered Residential Building (MERBL, MERBM, MERBH) bldg_class = 'MERB' - elif ( - bim['OccupancyClass'] - in { - 'COM1', - 'COM2', - 'COM3', - 'COM4', - 'COM5', - 'COM6', - 'COM7', - 'COM8', - 'COM9', - 'COM10', - } - ) and (bim['DesignLevel'] == 'E'): + elif ((BIM['OccupancyClass'] in ['COM1', 'COM2', 'COM3', 'COM4', + 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', + 'COM10']) and (BIM['DesignLevel'] == 'E')): # Masonry Engineered Commercial Building (MECBL, MECBM, MECBH) bldg_class = 'MECB' - elif bim['OccupancyClass'] in { - 'IND1', - 'IND2', - 'IND3', - 'IND4', - 'IND5', - 'IND6', - }: + elif BIM['OccupancyClass'] in ['IND1', 'IND2', 'IND3', 'IND4', 'IND5', 'IND6']: # Masonry Low-Rise Masonry Warehouse/Factory (MLRI) bldg_class = 'MLRI' - elif bim['OccupancyClass'] in { - 'RES3A', - 'RES3B', - 'RES3C', - 'RES3D', - 'RES3E', - 'RES3F', - 'RES5', - 'RES6', - 'COM8', - }: + elif BIM['OccupancyClass'] in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + 'RES3E', 'RES3F', 'RES5', 'RES6', 'COM8']: # OccupancyClass = RES3X or COM8 # Masonry Multi-Unit Hotel/Motel (MMUH1, MMUH2, or MMUH3) bldg_class = 'MMUH' - elif (bim['NumberOfStories'] == 1) and ( - bim['OccupancyClass'] in {'COM1', 'COM2'} - ): + elif ((BIM['NumberOfStories'] == 1) and + (BIM['OccupancyClass'] in ['COM1', 'COM2'])): # Low-Rise Masonry Strip Mall (MLRM1 or MLRM2) bldg_class = 'MLRM' - # elif ( - # BIM['OccupancyClass'] - # in [ - # 'RES3A', - # 'RES3B', - # 'RES3C', - # 'RES3D', - # 'RES3E', - # 'RES3F', - # 'RES5', - # 'RES6', - # 'COM8', - # ] - # ) and (BIM['DesignLevel'] in ['NE', 'ME']): - # # Masonry Multi-Unit Hotel/Motel Non-Engineered - # # (MMUH1NE, MMUH2NE, or MMUH3NE) - # bldg_class = 'MMUHNE' else: - bldg_class = 'MECB' # for others not covered by the above + bldg_class = 'MECB' # for others not covered by the above + #elif ((BIM['OccupancyClass'] in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + # 'RES3E', 'RES3F', 'RES5', 'RES6', + # 'COM8']) and (BIM['DesignLevel'] in ['NE', 'ME'])): + # # Masonry Multi-Unit Hotel/Motel Non-Engineered + # # (MMUH1NE, MMUH2NE, or MMUH3NE) + # bldg_class = 'MMUHNE' - elif bim['BuildingType'] == 'Manufactured': + elif BIM['BuildingType'] == "Manufactured": bldg_class = 'MH' else: diff --git a/pelicun/tests/dl_calculation/rulesets/BuildingClassRulesets.py b/pelicun/tests/dl_calculation/rulesets/BuildingClassRulesets.py index e3a593a50..b646946f0 100644 --- a/pelicun/tests/dl_calculation/rulesets/BuildingClassRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/BuildingClassRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,10 +43,14 @@ # Meredith Lockhead # Tracy Kijewski-Correa +import random +import numpy as np +import datetime -def building_class(bim: dict, hazard: str) -> str: # noqa: C901 + +def building_class(BIM, hazard): """ - Short description. + Short description Long description @@ -58,196 +63,112 @@ def building_class(bim: dict, hazard: str) -> str: # noqa: C901 ------- bldg_class: str One of the standard building class labels from HAZUS - """ + # check hazard - if hazard not in {'wind', 'inundation'}: - print(f'WARNING: The provided hazard is not recognized: {hazard}') # noqa: T201 + if hazard not in ['wind', 'inundation']: + print(f'WARNING: The provided hazard is not recognized: {hazard}') if hazard == 'wind': - if bim['BuildingType'] == 'Wood': - if (bim['OccupancyClass'] == 'RES1') or ( - (bim['RoofShape'] != 'flt') and (bim['OccupancyClass'] == '') # noqa: PLC1901 - ): + + if BIM['BuildingType'] == 'Wood': + if ((BIM['OccupancyClass'] == 'RES1') or + ((BIM['RoofShape'] != 'flt') and (BIM['OccupancyClass'] == ''))): # BuildingType = 3001 # OccupancyClass = RES1 # Wood Single-Family Homes (WSF1 or WSF2) # OR roof type = flat (HAZUS can only map flat to WSF1) # OR default (by '') - if ( - bim['RoofShape'] == 'flt' - ): # checking if there is a misclassication - bim['RoofShape'] = ( - # ensure the WSF has gab (by default, note gab - # is more vulnerable than hip) - 'gab' - ) + if BIM['RoofShape'] == 'flt': # checking if there is a misclassication + BIM['RoofShape'] = 'gab' # ensure the WSF has gab (by default, note gab is more vulneable than hip) bldg_class = 'WSF' else: # BuildingType = 3001 # OccupancyClass = RES3, RES5, RES6, or COM8 # Wood Multi-Unit Hotel (WMUH1, WMUH2, or WMUH3) bldg_class = 'WMUH' - elif bim['BuildingType'] == 'Steel': - if (bim['DesignLevel'] == 'E') and ( - bim['OccupancyClass'] - in {'RES3A', 'RES3B', 'RES3C', 'RES3D', 'RES3E', 'RES3F'} - ): + elif BIM['BuildingType'] == 'Steel': + if ((BIM['DesignLevel'] == 'E') and + (BIM['OccupancyClass'] in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + 'RES3E', 'RES3F'])): # BuildingType = 3002 # Steel Engineered Residential Building (SERBL, SERBM, SERBH) bldg_class = 'SERB' - elif (bim['DesignLevel'] == 'E') and ( - bim['OccupancyClass'] - in { - 'COM1', - 'COM2', - 'COM3', - 'COM4', - 'COM5', - 'COM6', - 'COM7', - 'COM8', - 'COM9', - 'COM10', - } - ): + elif ((BIM['DesignLevel'] == 'E') and + (BIM['OccupancyClass'] in ['COM1', 'COM2', 'COM3', 'COM4', 'COM5', + 'COM6', 'COM7', 'COM8', 'COM9','COM10'])): # BuildingType = 3002 # Steel Engineered Commercial Building (SECBL, SECBM, SECBH) bldg_class = 'SECB' - elif (bim['DesignLevel'] == 'PE') and ( - bim['OccupancyClass'] - not in {'RES3A', 'RES3B', 'RES3C', 'RES3D', 'RES3E', 'RES3F'} - ): + elif ((BIM['DesignLevel'] == 'PE') and + (BIM['OccupancyClass'] not in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + 'RES3E', 'RES3F'])): # BuildingType = 3002 # Steel Pre-Engineered Metal Building (SPMBS, SPMBM, SPMBL) bldg_class = 'SPMB' else: bldg_class = 'SECB' - elif bim['BuildingType'] == 'Concrete': - if (bim['DesignLevel'] == 'E') and ( - bim['OccupancyClass'] - in { - 'RES3A', - 'RES3B', - 'RES3C', - 'RES3D', - 'RES3E', - 'RES3F', - 'RES5', - 'RES6', - } - ): + elif BIM['BuildingType'] == 'Concrete': + if ((BIM['DesignLevel'] == 'E') and + (BIM['OccupancyClass'] in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + 'RES3E', 'RES3F', 'RES5', 'RES6'])): # BuildingType = 3003 # Concrete Engineered Residential Building (CERBL, CERBM, CERBH) bldg_class = 'CERB' - elif (bim['DesignLevel'] == 'E') and ( - bim['OccupancyClass'] - in { - 'COM1', - 'COM2', - 'COM3', - 'COM4', - 'COM5', - 'COM6', - 'COM7', - 'COM8', - 'COM9', - 'COM10', - } - ): + elif ((BIM['DesignLevel'] == 'E') and + (BIM['OccupancyClass'] in ['COM1', 'COM2', 'COM3', 'COM4', 'COM5', + 'COM6', 'COM7', 'COM8', 'COM9','COM10'])): # BuildingType = 3003 # Concrete Engineered Commercial Building (CECBL, CECBM, CECBH) bldg_class = 'CECB' else: bldg_class = 'CECB' - elif bim['BuildingType'] == 'Masonry': - if bim['OccupancyClass'] == 'RES1': + elif BIM['BuildingType'] == 'Masonry': + if BIM['OccupancyClass'] == 'RES1': # BuildingType = 3004 # OccupancyClass = RES1 # Masonry Single-Family Homes (MSF1 or MSF2) bldg_class = 'MSF' - elif ( - bim['OccupancyClass'] - in {'RES3A', 'RES3B', 'RES3C', 'RES3D', 'RES3E', 'RES3F'} - ) and (bim['DesignLevel'] == 'E'): + elif ((BIM['OccupancyClass'] in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + 'RES3E', 'RES3F']) and (BIM['DesignLevel'] == 'E')): # BuildingType = 3004 # Masonry Engineered Residential Building (MERBL, MERBM, MERBH) bldg_class = 'MERB' - elif ( - bim['OccupancyClass'] - in { - 'COM1', - 'COM2', - 'COM3', - 'COM4', - 'COM5', - 'COM6', - 'COM7', - 'COM8', - 'COM9', - 'COM10', - } - ) and (bim['DesignLevel'] == 'E'): + elif ((BIM['OccupancyClass'] in ['COM1', 'COM2', 'COM3', 'COM4', + 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', + 'COM10']) and (BIM['DesignLevel'] == 'E')): # BuildingType = 3004 # Masonry Engineered Commercial Building (MECBL, MECBM, MECBH) bldg_class = 'MECB' - elif bim['OccupancyClass'] in { - 'IND1', - 'IND2', - 'IND3', - 'IND4', - 'IND5', - 'IND6', - }: + elif BIM['OccupancyClass'] in ['IND1', 'IND2', 'IND3', 'IND4', 'IND5', 'IND6']: # BuildingType = 3004 # Masonry Low-Rise Masonry Warehouse/Factory (MLRI) bldg_class = 'MLRI' - elif bim['OccupancyClass'] in { - 'RES3A', - 'RES3B', - 'RES3C', - 'RES3D', - 'RES3E', - 'RES3F', - 'RES5', - 'RES6', - 'COM8', - }: + elif BIM['OccupancyClass'] in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + 'RES3E', 'RES3F', 'RES5', 'RES6', 'COM8']: # BuildingType = 3004 # OccupancyClass = RES3X or COM8 # Masonry Multi-Unit Hotel/Motel (MMUH1, MMUH2, or MMUH3) bldg_class = 'MMUH' - elif (bim['NumberOfStories'] == 1) and ( - bim['OccupancyClass'] in {'COM1', 'COM2'} - ): + elif ((BIM['NumberOfStories'] == 1) and + (BIM['OccupancyClass'] in ['COM1', 'COM2'])): # BuildingType = 3004 # Low-Rise Masonry Strip Mall (MLRM1 or MLRM2) bldg_class = 'MLRM' - # elif ( - # BIM['OccupancyClass'] - # in [ - # 'RES3A', - # 'RES3B', - # 'RES3C', - # 'RES3D', - # 'RES3E', - # 'RES3F', - # 'RES5', - # 'RES6', - # 'COM8', - # ] - # ) and (BIM['DesignLevel'] in ['NE', 'ME']): - # # BuildingType = 3004 - # # Masonry Multi-Unit Hotel/Motel Non-Engineered - # # (MMUH1NE, MMUH2NE, or MMUH3NE) - # return 'MMUHNE' else: - bldg_class = 'MECB' # for others not covered by the above - elif bim['BuildingType'] == 'Manufactured': + bldg_class = 'MECB' # for others not covered by the above + #elif ((BIM['OccupancyClass'] in ['RES3A', 'RES3B', 'RES3C', 'RES3D', + # 'RES3E', 'RES3F', 'RES5', 'RES6', + # 'COM8']) and (BIM['DesignLevel'] in ['NE', 'ME'])): + # # BuildingType = 3004 + # # Masonry Multi-Unit Hotel/Motel Non-Engineered + # # (MMUH1NE, MMUH2NE, or MMUH3NE) + # return 'MMUHNE' + elif BIM['BuildingType'] == 'Manufactured': bldg_class = 'MH' else: bldg_class = 'WMUH' # if nan building type is provided, return the dominant class - return bldg_class + return bldg_class \ No newline at end of file diff --git a/pelicun/tests/dl_calculation/rulesets/FloodAssmRulesets.py b/pelicun/tests/dl_calculation/rulesets/FloodAssmRulesets.py index c06a6bdbe..658d2e4a3 100644 --- a/pelicun/tests/dl_calculation/rulesets/FloodAssmRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/FloodAssmRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -43,13 +44,14 @@ # Meredith Lockhead # Tracy Kijewski-Correa +import random +import numpy as np +import datetime +import math -from __future__ import annotations - - -def Assm_config(bim: dict) -> tuple[str, str]: +def Assm_config(BIM): """ - Rules to identify the flood vulnerability category. + Rules to identify the flood vunerability category Parameters ---------- @@ -59,88 +61,45 @@ def Assm_config(bim: dict) -> tuple[str, str]: Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + year = BIM['YearBuilt'] # just for the sake of brevity # Flood Type - if bim['FloodZone'] == 'AO': - flood_type = 'raz' # Riverline/A-Zone - elif bim['FloodZone'] in {'AE', 'AH', 'A'}: - flood_type = 'caz' # Costal/A-Zone - elif bim['FloodZone'] == 'VE': - flood_type = 'cvz' # Costal/V-Zone + if BIM['FloodZone'] in ['AO']: + flood_type = 'raz' # Riverline/A-Zone + elif BIM['FloodZone'] in ['AE', 'AH', 'A']: + flood_type = 'caz' # Costal/A-Zone + elif BIM['FloodZone'] in ['VE']: + flood_type = 'cvz' # Costal/V-Zone else: - flood_type = 'caz' # Default + flood_type = 'caz' # Default # PostFIRM - post_firm = False # Default - city_list = [ - 'Absecon', - 'Atlantic', - 'Brigantine', - 'Buena', - 'Buena Vista', - 'Corbin City', - 'Egg Harbor City', - 'Egg Harbor', - 'Estell Manor', - 'Folsom', - 'Galloway', - 'Hamilton', - 'Hammonton', - 'Linwood', - 'Longport', - 'Margate City', - 'Mullica', - 'Northfield', - 'Pleasantville', - 'Port Republic', - 'Somers Point', - 'Ventnor City', - 'Weymouth', - ] - year_list = [ - 1976, - 1971, - 1971, - 1983, - 1979, - 1981, - 1982, - 1983, - 1978, - 1982, - 1983, - 1977, - 1982, - 1983, - 1974, - 1974, - 1982, - 1979, - 1983, - 1983, - 1982, - 1971, - 1979, - ] - for i in range(22): - post_firm = ( - (bim['City'] == city_list[i]) and (year > year_list[i]) - ) or post_firm + PostFIRM = False # Default + city_list = ['Absecon', 'Atlantic', 'Brigantine', 'Buena', 'Buena Vista', + 'Corbin City', 'Egg Harbor City', 'Egg Harbor', 'Estell Manor', + 'Folsom', 'Galloway', 'Hamilton', 'Hammonton', 'Linwood', + 'Longport', 'Margate City', 'Mullica', 'Northfield', + 'Pleasantville', 'Port Republic', 'Somers Point', + 'Ventnor City', 'Weymouth'] + year_list = [1976, 1971, 1971, 1983, 1979, 1981, 1982, 1983, 1978, 1982, + 1983, 1977, 1982, 1983, 1974, 1974, 1982, 1979, 1983, 1983, + 1982, 1971, 1979] + for i in range(0,22): + PostFIRM = (((BIM['City'] == city_list[i]) and (year > year_list[i])) or \ + PostFIRM) # fl_assm - fl_assm = ( - f"{'fl_surge_assm'}_" - f"{bim['OccupancyClass']}_" - f"{int(post_firm)}_" - f"{flood_type}" - ) + fl_assm = f"{'fl_surge_assm'}_" \ + f"{BIM['OccupancyClass']}_" \ + f"{int(PostFIRM)}_" \ + f"{flood_type}" # hu_assm - hu_assm = f"{'hu_surge_assm'}_{bim['OccupancyClass']}_{int(post_firm)}" + hu_assm = f"{'hu_surge_assm'}_" \ + f"{BIM['OccupancyClass']}_" \ + f"{int(PostFIRM)}" - return hu_assm, fl_assm + return hu_assm, fl_assm \ No newline at end of file diff --git a/pelicun/tests/dl_calculation/rulesets/FloodClassRulesets.py b/pelicun/tests/dl_calculation/rulesets/FloodClassRulesets.py index 954235e2a..702c829ec 100644 --- a/pelicun/tests/dl_calculation/rulesets/FloodClassRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/FloodClassRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -44,10 +45,9 @@ import numpy as np - -def FL_config(bim: dict) -> str: # noqa: C901 +def FL_config(BIM): """ - Rules to identify the flood vulnerability category. + Rules to identify the flood vunerability category Parameters ---------- @@ -57,126 +57,143 @@ def FL_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + year = BIM['YearBuilt'] # just for the sake of brevity # Flood Type - if bim['FloodZone'] == 'AO': - flood_type = 'raz' # Riverline/A-Zone - elif bim['FloodZone'] in {'A', 'AE'} or bim['FloodZone'].startswith('V'): - flood_type = 'cvz' # Costal-Zone + if BIM['FloodZone'] == 'AO': + flood_type = 'raz' # Riverline/A-Zone + elif BIM['FloodZone'] in ['A', 'AE']: + flood_type = 'cvz' # Costal-Zone + elif BIM['FloodZone'].startswith('V'): + flood_type = 'cvz' # Costal-Zone else: - flood_type = 'cvz' # Default + flood_type = 'cvz' # Default - # flake8 - unused variable: `FFE` - # # First Floor Elevation (FFE) - # if flood_type in ['raz', 'caz']: - # FFE = BIM['FirstFloorElevation'] - # else: - # FFE = BIM['FirstFloorElevation'] - 1.0 + # First Floor Elevation (FFE) + if flood_type in ['raz', 'caz']: + FFE = BIM['FirstFloorElevation'] + else: + FFE = BIM['FirstFloorElevation'] - 1.0 # PostFIRM - post_firm = False # Default - city_list = [ - 'Absecon', - 'Atlantic', - 'Brigantine', - 'Buena', - 'Buena Vista', - 'Corbin City', - 'Egg Harbor City', - 'Egg Harbor', - 'Estell Manor', - 'Folsom', - 'Galloway', - 'Hamilton', - 'Hammonton', - 'Linwood', - 'Longport', - 'Margate City', - 'Mullica', - 'Northfield', - 'Pleasantville', - 'Port Republic', - 'Somers Point', - 'Ventnor City', - 'Weymouth', - ] - year_list = [ - 1976, - 1971, - 1971, - 1983, - 1979, - 1981, - 1982, - 1983, - 1978, - 1982, - 1983, - 1977, - 1982, - 1983, - 1974, - 1974, - 1982, - 1979, - 1983, - 1983, - 1982, - 1971, - 1979, - ] - for i in range(22): - post_firm = ( - (bim['City'] == city_list[i]) and (year > year_list[i]) - ) or post_firm + PostFIRM = False # Default + city_list = ['Absecon', 'Atlantic', 'Brigantine', 'Buena', 'Buena Vista', + 'Corbin City', 'Egg Harbor City', 'Egg Harbor', 'Estell Manor', + 'Folsom', 'Galloway', 'Hamilton', 'Hammonton', 'Linwood', + 'Longport', 'Margate City', 'Mullica', 'Northfield', + 'Pleasantville', 'Port Republic', 'Somers Point', + 'Ventnor City', 'Weymouth'] + year_list = [1976, 1971, 1971, 1983, 1979, 1981, 1982, 1983, 1978, 1982, + 1983, 1977, 1982, 1983, 1974, 1974, 1982, 1979, 1983, 1983, + 1982, 1971, 1979] + for i in range(0,22): + PostFIRM = (((BIM['City'] == city_list[i]) and (year > year_list[i])) or \ + PostFIRM) # Basement Type - if bim['SplitLevel'] and (bim['FoundationType'] == 3504): - bmt_type = 'spt' # Split-Level Basement - elif bim['FoundationType'] in {3501, 3502, 3503, 3505, 3506, 3507}: - bmt_type = 'bn' # No Basement - elif (not bim['SplitLevel']) and (bim['FoundationType'] == 3504): - bmt_type = 'bw' # Basement + if BIM['SplitLevel'] and (BIM['FoundationType'] == 3504): + bmt_type = 'spt' # Split-Level Basement + elif BIM['FoundationType'] in [3501, 3502, 3503, 3505, 3506, 3507]: + bmt_type = 'bn' # No Basement + elif (not BIM['SplitLevel']) and (BIM['FoundationType'] == 3504): + bmt_type = 'bw' # Basement else: - bmt_type = 'bw' # Default + bmt_type = 'bw' # Default - if bim['OccupancyClass'] not in {'RES1', 'RES2'}: - if 'RES3' in bim['OccupancyClass']: - fl_config = f"{'fl'}_" f"{'RES3'}" + # Duration + dur = 'short' + + # Occupancy Type + if BIM['OccupancyClass'] == 'RES1': + if BIM['NumberOfStories'] == 1: + if flood_type == 'raz': + OT = 'SF1XA' + elif flood_type == 'cvz': + OT = 'SF1XV' else: - fl_config = f"{'fl'}_" f"{bim['OccupancyClass']}" - elif bim['OccupancyClass'] == 'RES2': - fl_config = f"{'fl'}_" f"{bim['OccupancyClass']}_" f"{flood_type}" - elif bmt_type == 'spt': - fl_config = ( - f"{'fl'}_" - f"{bim['OccupancyClass']}_" - f"{'sl'}_" - f"{'bw'}_" - f"{flood_type}" - ) + if bmt_type == 'nav': + if flood_type == 'raz': + OT = 'SF2XA' + elif flood_type == 'cvz': + OT = 'SF2XV' + elif bmt_type == 'bmt': + if flood_type == 'raz': + OT = 'SF2BA' + elif flood_type == 'cvz': + OT = 'SF2BV' + elif bmt_type == 'spt': + if flood_type == 'raz': + OT = 'SF2SA' + elif flood_type == 'cvz': + OT = 'SF2SV' + elif 'RES3' in BIM['OccupancyClass']: + OT = 'APT' else: - st = 's' + str(np.min([bim['NumberOfStories'], 3])) - fl_config = ( - f"{'fl'}_" - f"{bim['OccupancyClass']}_" - f"{st}_" - f"{bmt_type}_" - f"{flood_type}" - ) + ap_OT = { + 'RES2': 'MH', + 'RES4': 'HOT', + 'RES5': 'NURSE', + 'RES6': 'NURSE', + 'COM1': 'RETAL', + 'COM2': 'WHOLE', + 'COM3': 'SERVICE', + 'COM4': 'OFFICE', + 'COM5': 'BANK', + 'COM6': 'HOSP', + 'COM7': 'MED', + 'COM8': 'REC', + 'COM9': 'THEAT', + 'COM10': 'GARAGE', + 'IND1': 'INDH', + 'IND2': 'INDL', + 'IND3': 'CHEM', + 'IND4': 'PROC', + 'IND5': 'CHEM', + 'IND6': 'CONST', + 'AGR1': 'AGRI', + 'REL1': 'RELIG', + 'GOV1': 'CITY', + 'GOV2': 'EMERG', + 'EDU1': 'SCHOOL', + 'EDU2': 'SCHOOL' + } + ap_OT[BIM['OccupancyClass']] + + + if not (BIM['OccupancyClass'] in ['RES1', 'RES2']): + if 'RES3' in BIM['OccupancyClass']: + fl_config = f"{'fl'}_" \ + f"{'RES3'}" + else: + fl_config = f"{'fl'}_" \ + f"{BIM['OccupancyClass']}" + elif BIM['OccupancyClass'] == 'RES2': + fl_config = f"{'fl'}_" \ + f"{BIM['OccupancyClass']}_" \ + f"{flood_type}" + else: + if bmt_type == 'spt': + fl_config = f"{'fl'}_" \ + f"{BIM['OccupancyClass']}_" \ + f"{'sl'}_" \ + f"{'bw'}_" \ + f"{flood_type}" + else: + st = 's'+str(np.min([BIM['NumberOfStories'],3])) + fl_config = f"{'fl'}_" \ + f"{BIM['OccupancyClass']}_" \ + f"{st}_" \ + f"{bmt_type}_" \ + f"{flood_type}" # extend the BIM dictionary - bim.update( - { - 'FloodType': flood_type, - 'BasementType': bmt_type, - 'PostFIRM': post_firm, - } - ) + BIM.update(dict( + FloodType = flood_type, + BasementType=bmt_type, + PostFIRM=PostFIRM, + )) - return fl_config + return fl_config \ No newline at end of file diff --git a/pelicun/tests/dl_calculation/rulesets/FloodRulesets.py b/pelicun/tests/dl_calculation/rulesets/FloodRulesets.py index 7d8864b8f..882d8d933 100644 --- a/pelicun/tests/dl_calculation/rulesets/FloodRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/FloodRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -44,10 +45,9 @@ import numpy as np - -def FL_config(bim: dict) -> str: # noqa: C901 +def FL_config(BIM): """ - Rules to identify the flood vulnerability category. + Rules to identify the flood vunerability category Parameters ---------- @@ -57,126 +57,144 @@ def FL_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + year = BIM['YearBuilt'] # just for the sake of brevity # Flood Type - if bim['FloodZone'] == 'AO': - flood_type = 'raz' # Riverline/A-Zone - elif bim['FloodZone'] in {'A', 'AE'} or bim['FloodZone'].startswith('V'): - flood_type = 'cvz' # Costal-Zone + if BIM['FloodZone'] == 'AO': + flood_type = 'raz' # Riverline/A-Zone + elif BIM['FloodZone'] in ['A', 'AE']: + flood_type = 'cvz' # Costal-Zone + elif BIM['FloodZone'].startswith('V'): + flood_type = 'cvz' # Costal-Zone else: - flood_type = 'cvz' # Default + flood_type = 'cvz' # Default - # flake8 - unused variable: `FFE`. - # # First Floor Elevation (FFE) - # if flood_type in ['raz', 'caz']: - # FFE = BIM['FirstFloorElevation'] - # else: - # FFE = BIM['FirstFloorElevation'] - 1.0 + # First Floor Elevation (FFE) + if flood_type in ['raz', 'caz']: + FFE = BIM['FirstFloorElevation'] + else: + FFE = BIM['FirstFloorElevation'] - 1.0 # PostFIRM - post_firm = False # Default - city_list = [ - 'Absecon', - 'Atlantic', - 'Brigantine', - 'Buena', - 'Buena Vista', - 'Corbin City', - 'Egg Harbor City', - 'Egg Harbor', - 'Estell Manor', - 'Folsom', - 'Galloway', - 'Hamilton', - 'Hammonton', - 'Linwood', - 'Longport', - 'Margate City', - 'Mullica', - 'Northfield', - 'Pleasantville', - 'Port Republic', - 'Somers Point', - 'Ventnor City', - 'Weymouth', - ] - year_list = [ - 1976, - 1971, - 1971, - 1983, - 1979, - 1981, - 1982, - 1983, - 1978, - 1982, - 1983, - 1977, - 1982, - 1983, - 1974, - 1974, - 1982, - 1979, - 1983, - 1983, - 1982, - 1971, - 1979, - ] - for i in range(22): - post_firm = ( - (bim['City'] == city_list[i]) and (year > year_list[i]) - ) or post_firm + PostFIRM = False # Default + city_list = ['Absecon', 'Atlantic', 'Brigantine', 'Buena', 'Buena Vista', + 'Corbin City', 'Egg Harbor City', 'Egg Harbor', 'Estell Manor', + 'Folsom', 'Galloway', 'Hamilton', 'Hammonton', 'Linwood', + 'Longport', 'Margate City', 'Mullica', 'Northfield', + 'Pleasantville', 'Port Republic', 'Somers Point', + 'Ventnor City', 'Weymouth'] + year_list = [1976, 1971, 1971, 1983, 1979, 1981, 1982, 1983, 1978, 1982, + 1983, 1977, 1982, 1983, 1974, 1974, 1982, 1979, 1983, 1983, + 1982, 1971, 1979] + for i in range(0,22): + PostFIRM = (((BIM['City'] == city_list[i]) and (year > year_list[i])) or \ + PostFIRM) # Basement Type - if bim['SplitLevel'] and (bim['FoundationType'] == 3504): - bmt_type = 'spt' # Split-Level Basement - elif bim['FoundationType'] in {3501, 3502, 3503, 3505, 3506, 3507}: - bmt_type = 'bn' # No Basement - elif (not bim['SplitLevel']) and (bim['FoundationType'] == 3504): - bmt_type = 'bw' # Basement + if BIM['SplitLevel'] and (BIM['FoundationType'] == 3504): + bmt_type = 'spt' # Split-Level Basement + elif BIM['FoundationType'] in [3501, 3502, 3503, 3505, 3506, 3507]: + bmt_type = 'bn' # No Basement + elif (not BIM['SplitLevel']) and (BIM['FoundationType'] == 3504): + bmt_type = 'bw' # Basement + else: + bmt_type = 'bw' # Default + + # Duration + dur = 'short' + + # Occupancy Type + if BIM['OccupancyClass'] == 'RES1': + if BIM['NumberOfStories'] == 1: + if flood_type == 'raz': + OT = 'SF1XA' + elif flood_type == 'cvz': + OT = 'SF1XV' + else: + if bmt_type == 'nav': + if flood_type == 'raz': + OT = 'SF2XA' + elif flood_type == 'cvz': + OT = 'SF2XV' + elif bmt_type == 'bmt': + if flood_type == 'raz': + OT = 'SF2BA' + elif flood_type == 'cvz': + OT = 'SF2BV' + elif bmt_type == 'spt': + if flood_type == 'raz': + OT = 'SF2SA' + elif flood_type == 'cvz': + OT = 'SF2SV' + elif 'RES3' in BIM['OccupancyClass']: + OT = 'APT' else: - bmt_type = 'bw' # Default + ap_OT = { + 'RES2': 'MH', + 'RES4': 'HOT', + 'RES5': 'NURSE', + 'RES6': 'NURSE', + 'COM1': 'RETAL', + 'COM2': 'WHOLE', + 'COM3': 'SERVICE', + 'COM4': 'OFFICE', + 'COM5': 'BANK', + 'COM6': 'HOSP', + 'COM7': 'MED', + 'COM8': 'REC', + 'COM9': 'THEAT', + 'COM10': 'GARAGE', + 'IND1': 'INDH', + 'IND2': 'INDL', + 'IND3': 'CHEM', + 'IND4': 'PROC', + 'IND5': 'CHEM', + 'IND6': 'CONST', + 'AGR1': 'AGRI', + 'REL1': 'RELIG', + 'GOV1': 'CITY', + 'GOV2': 'EMERG', + 'EDU1': 'SCHOOL', + 'EDU2': 'SCHOOL' + } + ap_OT[BIM['OccupancyClass']] + - if bim['OccupancyClass'] not in {'RES1', 'RES2'}: - if 'RES3' in bim['OccupancyClass']: - fl_config = f"{'fl'}_" f"{'RES3'}" + if not (BIM['OccupancyClass'] in ['RES1', 'RES2']): + if 'RES3' in BIM['OccupancyClass']: + fl_config = f"{'fl'}_" \ + f"{'RES3'}" else: - fl_config = f"{'fl'}_" f"{bim['OccupancyClass']}" - elif bim['OccupancyClass'] == 'RES2': - fl_config = f"{'fl'}_" f"{bim['OccupancyClass']}_" f"{flood_type}" - elif bmt_type == 'spt': - fl_config = ( - f"{'fl'}_" - f"{bim['OccupancyClass']}_" - f"{'sl'}_" - f"{'bw'}_" - f"{flood_type}" - ) + fl_config = f"{'fl'}_" \ + f"{BIM['OccupancyClass']}" + elif BIM['OccupancyClass'] == 'RES2': + fl_config = f"{'fl'}_" \ + f"{BIM['OccupancyClass']}_" \ + f"{flood_type}" else: - st = 's' + str(np.min([bim['NumberOfStories'], 3])) - fl_config = ( - f"{'fl'}_" - f"{bim['OccupancyClass']}_" - f"{st}_" - f"{bmt_type}_" - f"{flood_type}" - ) + if bmt_type == 'spt': + fl_config = f"{'fl'}_" \ + f"{BIM['OccupancyClass']}_" \ + f"{'sl'}_" \ + f"{'bw'}_" \ + f"{flood_type}" + else: + st = 's'+str(np.min([BIM['NumberOfStories'],3])) + fl_config = f"{'fl'}_" \ + f"{BIM['OccupancyClass']}_" \ + f"{st}_" \ + f"{bmt_type}_" \ + f"{flood_type}" # extend the BIM dictionary - bim.update( - { - 'FloodType': flood_type, - 'BasementType': bmt_type, - 'PostFIRM': post_firm, - } - ) + BIM.update(dict( + FloodType = flood_type, + BasementType=bmt_type, + PostFIRM=PostFIRM, + )) return fl_config + diff --git a/pelicun/tests/dl_calculation/rulesets/MetaVarRulesets.py b/pelicun/tests/dl_calculation/rulesets/MetaVarRulesets.py index cc6155740..cfd50c7f2 100644 --- a/pelicun/tests/dl_calculation/rulesets/MetaVarRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/MetaVarRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,16 +43,13 @@ # Meredith Lockhead # Tracy Kijewski-Correa -from __future__ import annotations - import numpy as np - -def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: C901 +def parse_BIM(BIM_in, location, hazards): """ Parses the information provided in the BIM model. - The attributes below list the expected metadata in the BIM file + The atrributes below list the expected metadata in the BIM file Parameters ---------- @@ -85,140 +83,132 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: ------- BIM: dictionary Parsed building characteristics. - - Raises - ------ - KeyError - In case of missing attributes. - """ + # check location - if location not in {'LA', 'NJ'}: - print(f'WARNING: The provided location is not recognized: {location}') # noqa: T201 + if location not in ['LA', 'NJ']: + print(f'WARNING: The provided location is not recognized: {location}') # check hazard for hazard in hazards: - if hazard not in {'wind', 'inundation'}: - print(f'WARNING: The provided hazard is not recognized: {hazard}') # noqa: T201 + if hazard not in ['wind', 'inundation']: + print(f'WARNING: The provided hazard is not recognized: {hazard}') # initialize the BIM dict - bim = {} + BIM = {} if 'wind' in hazards: # maps roof type to the internal representation - ap_roof_type = { - 'hip': 'hip', + ap_RoofType = { + 'hip' : 'hip', 'hipped': 'hip', - 'Hip': 'hip', + 'Hip' : 'hip', 'gabled': 'gab', - 'gable': 'gab', - 'Gable': 'gab', - 'flat': 'flt', - 'Flat': 'flt', + 'gable' : 'gab', + 'Gable' : 'gab', + 'flat' : 'flt', + 'Flat' : 'flt' } # maps roof system to the internal representation - ap_roof_system = {'Wood': 'trs', 'OWSJ': 'ows', 'N/A': 'trs'} - roof_system = bim_in.get('RoofSystem', 'Wood') - - # flake8 - unused variable: `ap_NoUnits`. - # # maps number of units to the internal representation - # ap_NoUnits = { - # 'Single': 'sgl', - # 'Multiple': 'mlt', - # 'Multi': 'mlt', - # 'nav': 'nav', - # } + ap_RoofSystem = { + 'Wood': 'trs', + 'OWSJ': 'ows', + 'N/A': 'trs' + } + roof_system = BIM_in.get('RoofSystem', 'Wood') + + # maps number of units to the internal representation + ap_NoUnits = { + 'Single': 'sgl', + 'Multiple': 'mlt', + 'Multi': 'mlt', + 'nav': 'nav' + } # Average January Temp. - ap_ajt = {'Above': 'above', 'Below': 'below'} + ap_ajt = { + 'Above': 'above', + 'Below': 'below' + } # Year built alname_yearbuilt = ['yearBuilt', 'YearBuiltMODIV', 'YearBuiltNJDEP'] - yearbuilt = bim_in.get('YearBuilt') + yearbuilt = BIM_in.get('YearBuilt', None) # if none of the above works, set a default if yearbuilt is None: for alname in alname_yearbuilt: - if alname in bim_in: - yearbuilt = bim_in[alname] + if alname in BIM_in.keys(): + yearbuilt = BIM_in[alname] break if yearbuilt is None: yearbuilt = 1985 # Number of Stories - alname_nstories = [ - 'stories', - 'NumberofStories0', - 'NumberofStories', - 'NumberofStories1', - ] + alname_nstories = ['stories', 'NumberofStories0', 'NumberofStories', 'NumberofStories1'] - nstories = bim_in.get('NumberOfStories') + nstories = BIM_in.get('NumberOfStories', None) if nstories is None: for alname in alname_nstories: - if alname in bim_in: - nstories = bim_in[alname] + if alname in BIM_in.keys(): + nstories = BIM_in[alname] break if nstories is None: - msg = 'NumberOfStories attribute missing, cannot autopopulate' - raise KeyError(msg) + raise KeyError("NumberOfStories attribute missing, cannot autopopulate") # Plan Area alname_area = ['area', 'PlanArea1', 'Area', 'PlanArea0'] - area = bim_in.get('PlanArea') + area = BIM_in.get('PlanArea', None) if area is None: for alname in alname_area: - if alname in bim_in: - area = bim_in[alname] + if alname in BIM_in.keys(): + area = BIM_in[alname] break if area is None: - msg = 'PlanArea attribute missing, cannot autopopulate' - raise KeyError(msg) + raise KeyError("PlanArea attribute missing, cannot autopopulate") # Design Wind Speed alname_dws = ['DWSII', 'DesignWindSpeed'] - dws = bim_in.get('DesignWindSpeed') + dws = BIM_in.get('DesignWindSpeed', None) if dws is None: for alname in alname_dws: - if alname in bim_in: - dws = bim_in[alname] + if alname in BIM_in.keys(): + dws = BIM_in[alname] break if dws is None: - msg = 'DesignWindSpeed attribute missing, cannot autopopulate' - raise KeyError(msg) + raise KeyError("DesignWindSpeed attribute missing, cannot autopopulate") # occupancy type alname_occupancy = ['occupancy', 'OccupancyClass'] - oc = bim_in.get('OccupancyClass') + oc = BIM_in.get('OccupancyClass', None) if oc is None: for alname in alname_occupancy: - if alname in bim_in: - oc = bim_in[alname] + if alname in BIM_in.keys(): + oc = BIM_in[alname] break if oc is None: - msg = 'OccupancyClass attribute missing, cannot autopopulate' - raise KeyError(msg) + raise KeyError("OccupancyClass attribute missing, cannot autopopulate") # if getting RES3 then converting it to default RES3A if oc == 'RES3': oc = 'RES3A' # maps for BuildingType - ap_building_type_nj = { + ap_BuildingType_NJ = { # Coastal areas with a 1% or greater chance of flooding and an # additional hazard associated with storm waves. 3001: 'Wood', @@ -229,117 +219,111 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: } if location == 'NJ': # NJDEP code for flood zone needs to be converted - buildingtype = ap_building_type_nj[bim_in['BuildingType']] - + buildingtype = ap_BuildingType_NJ[BIM_in['BuildingType']] + elif location == 'LA': # standard input should provide the building type as a string - buildingtype = bim_in['BuildingType'] - - # maps for design level (Marginal Engineered is mapped to - # Engineered as defauplt) - ap_design_level = {'E': 'E', 'NE': 'NE', 'PE': 'PE', 'ME': 'E'} - design_level = bim_in.get('DesignLevel', 'E') + buildingtype = BIM_in['BuildingType'] + + # maps for design level (Marginal Engineered is mapped to Engineered as default) + ap_DesignLevel = { + 'E': 'E', + 'NE': 'NE', + 'PE': 'PE', + 'ME': 'E' + } + design_level = BIM_in.get('DesignLevel','E') # flood zone - flood_zone = bim_in.get('FloodZone', 'X') + flood_zone = BIM_in.get('FloodZone', 'X') # add the parsed data to the BIM dict - bim.update( - { - 'OccupancyClass': str(oc), - 'BuildingType': buildingtype, - 'YearBuilt': int(yearbuilt), - 'NumberOfStories': int(nstories), - 'PlanArea': float(area), - 'V_ult': float(dws), - 'AvgJanTemp': ap_ajt[bim_in.get('AvgJanTemp', 'Below')], - 'RoofShape': ap_roof_type[bim_in['RoofShape']], - 'RoofSlope': float(bim_in.get('RoofSlope', 0.25)), # default 0.25 - 'SheathingThickness': float( - bim_in.get('SheathingThick', 1.0) - ), # default 1.0 - 'RoofSystem': str( - ap_roof_system[roof_system] - ), # only valid for masonry structures - 'Garage': float(bim_in.get('Garage', -1.0)), - 'LULC': bim_in.get('LULC', -1), - 'MeanRoofHt': float(bim_in.get('MeanRoofHt', 15.0)), # default 15 - 'WindowArea': float(bim_in.get('WindowArea', 0.20)), - 'WindZone': str(bim_in.get('WindZone', 'I')), - 'FloodZone': str(flood_zone), - } - ) + BIM.update(dict( + OccupancyClass=str(oc), + BuildingType=buildingtype, + YearBuilt=int(yearbuilt), + NumberOfStories=int(nstories), + PlanArea=float(area), + V_ult=float(dws), + AvgJanTemp=ap_ajt[BIM_in.get('AvgJanTemp','Below')], + RoofShape=ap_RoofType[BIM_in['RoofShape']], + RoofSlope=float(BIM_in.get('RoofSlope',0.25)), # default 0.25 + SheathingThickness=float(BIM_in.get('SheathingThick',1.0)), # default 1.0 + RoofSystem=str(ap_RoofSystem[roof_system]), # only valid for masonry structures + Garage=float(BIM_in.get('Garage',-1.0)), + LULC=BIM_in.get('LULC',-1), + MeanRoofHt=float(BIM_in.get('MeanRoofHt',15.0)), # default 15 + WindowArea=float(BIM_in.get('WindowArea',0.20)), + WindZone=str(BIM_in.get('WindZone', 'I')), + FloodZone =str(flood_zone) + )) if 'inundation' in hazards: + # maps for split level - ap_split_level = {'NO': 0, 'YES': 1} + ap_SplitLevel = { + 'NO': 0, + 'YES': 1 + } # foundation type - foundation = bim_in.get('FoundationType', 3501) + foundation = BIM_in.get('FoundationType',3501) # number of units - nunits = bim_in.get('NoUnits', 1) - - # flake8 - unused variable: `ap_FloodZone`. - # # maps for flood zone - # ap_FloodZone = { - # # Coastal areas with a 1% or greater chance of flooding and an - # # additional hazard associated with storm waves. - # 6101: 'VE', - # 6102: 'VE', - # 6103: 'AE', - # 6104: 'AE', - # 6105: 'AO', - # 6106: 'AE', - # 6107: 'AH', - # 6108: 'AO', - # 6109: 'A', - # 6110: 'X', - # 6111: 'X', - # 6112: 'X', - # 6113: 'OW', - # 6114: 'D', - # 6115: 'NA', - # 6119: 'NA', - # } - - # flake8 - unused variable: `floodzone_fema`. - # if isinstance(BIM_in['FloodZone'], int): - # # NJDEP code for flood zone (conversion to the FEMA designations) - # floodzone_fema = ap_FloodZone[BIM_in['FloodZone']] - # else: - # # standard input should follow the FEMA flood zone designations - # floodzone_fema = BIM_in['FloodZone'] + nunits = BIM_in.get('NoUnits',1) + + # maps for flood zone + ap_FloodZone = { + # Coastal areas with a 1% or greater chance of flooding and an + # additional hazard associated with storm waves. + 6101: 'VE', + 6102: 'VE', + 6103: 'AE', + 6104: 'AE', + 6105: 'AO', + 6106: 'AE', + 6107: 'AH', + 6108: 'AO', + 6109: 'A', + 6110: 'X', + 6111: 'X', + 6112: 'X', + 6113: 'OW', + 6114: 'D', + 6115: 'NA', + 6119: 'NA' + } + if type(BIM_in['FloodZone']) == int: + # NJDEP code for flood zone (conversion to the FEMA designations) + floodzone_fema = ap_FloodZone[BIM_in['FloodZone']] + else: + # standard input should follow the FEMA flood zone designations + floodzone_fema = BIM_in['FloodZone'] # add the parsed data to the BIM dict - bim.update( - { - 'DesignLevel': str( - ap_design_level[design_level] - ), # default engineered - 'NumberOfUnits': int(nunits), - 'FirstFloorElevation': float(bim_in.get('FirstFloorHt1', 10.0)), - 'SplitLevel': bool( - ap_split_level[bim_in.get('SplitLevel', 'NO')] - ), # dfault: no - 'FoundationType': int(foundation), # default: pile - 'City': bim_in.get('City', 'NA'), - } - ) + BIM.update(dict( + DesignLevel=str(ap_DesignLevel[design_level]), # default engineered + NumberOfUnits=int(nunits), + FirstFloorElevation=float(BIM_in.get('FirstFloorHt1',10.0)), + SplitLevel=bool(ap_SplitLevel[BIM_in.get('SplitLevel','NO')]), # dfault: no + FoundationType=int(foundation), # default: pile + City=BIM_in.get('City','NA') + )) # add inferred, generic meta-variables if 'wind' in hazards: + # Hurricane-Prone Region (HRP) # Areas vulnerable to hurricane, defined as the U.S. Atlantic Ocean and # Gulf of Mexico coasts where the ultimate design wind speed, V_ult is # greater than a pre-defined limit. - if bim['YearBuilt'] >= 2016: + if BIM['YearBuilt'] >= 2016: # The limit is 115 mph in IRC 2015 - hpr = bim['V_ult'] > 115.0 + HPR = BIM['V_ult'] > 115.0 else: # The limit is 90 mph in IRC 2009 and earlier versions - hpr = bim['V_ult'] > 90.0 + HPR = BIM['V_ult'] > 90.0 # Wind Borne Debris # Areas within hurricane-prone regions are affected by debris if one of @@ -349,30 +333,25 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: # (2) In areas where the ultimate design wind speed is greater than # general_lim # The flood_lim and general_lim limits depend on the year of construction - if bim['YearBuilt'] >= 2016: + if BIM['YearBuilt'] >= 2016: # In IRC 2015: - flood_lim = 130.0 # mph - general_lim = 140.0 # mph + flood_lim = 130.0 # mph + general_lim = 140.0 # mph else: # In IRC 2009 and earlier versions - flood_lim = 110.0 # mph - general_lim = 120.0 # mph + flood_lim = 110.0 # mph + general_lim = 120.0 # mph # Areas within hurricane-prone regions located in accordance with # one of the following: # (1) Within 1 mile (1.61 km) of the coastal mean high water line # where the ultimate design wind speed is 130 mph (58m/s) or greater. # (2) In areas where the ultimate design wind speed is 140 mph (63.5m/s) # or greater. (Definitions: Chapter 2, 2015 NJ Residential Code) - if not hpr: - wbd = False + if not HPR: + WBD = False else: - wbd = ( - ( - bim['FloodZone'].startswith('A') - or bim['FloodZone'].startswith('V') - ) - and bim['V_ult'] >= flood_lim - ) or (bim['V_ult'] >= general_lim) + WBD = (((BIM['FloodZone'].startswith('A') or BIM['FloodZone'].startswith('V')) and + BIM['V_ult'] >= flood_lim) or (BIM['V_ult'] >= general_lim)) # Terrain # open (0.03) = 3 @@ -380,92 +359,68 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: # suburban (0.35) = 35 # light trees (0.70) = 70 # trees (1.00) = 100 - # Mapped to Land Use Categories in NJ (see - # https://www.state.nj.us/dep/gis/ - # digidownload/metadata/lulc02/anderson2002.html) by T. Wu - # group (see internal report on roughness calculations, Table - # 4). These are mapped to Hazus definitions as follows: Open - # Water (5400s) with zo=0.01 and barren land (7600) with - # zo=0.04 assume Open Open Space Developed, Low Intensity - # Developed, Medium Intensity Developed (1110-1140) assumed - # zo=0.35-0.4 assume Suburban High Intensity Developed (1600) - # with zo=0.6 assume Lt. Tree Forests of all classes - # (4100-4300) assumed zo=0.6 assume Lt. Tree Shrub (4400) with - # zo=0.06 assume Open Grasslands, pastures and agricultural - # areas (2000 series) with zo=0.1-0.15 assume Lt. Suburban - # Woody Wetlands (6250) with zo=0.3 assume suburban Emergent - # Herbaceous Wetlands (6240) with zo=0.03 assume Open - # Note: HAZUS category of trees (1.00) does not apply to any - # LU/LC in NJ - terrain = 15 # Default in Reorganized Rulesets - WIND - if location == 'NJ': - if bim['FloodZone'].startswith('V') or bim['FloodZone'] in { - 'A', - 'AE', - 'A1-30', - 'AR', - 'A99', - }: + # Mapped to Land Use Categories in NJ (see https://www.state.nj.us/dep/gis/ + # digidownload/metadata/lulc02/anderson2002.html) by T. Wu group + # (see internal report on roughness calculations, Table 4). + # These are mapped to Hazus defintions as follows: + # Open Water (5400s) with zo=0.01 and barren land (7600) with zo=0.04 assume Open + # Open Space Developed, Low Intensity Developed, Medium Intensity Developed + # (1110-1140) assumed zo=0.35-0.4 assume Suburban + # High Intensity Developed (1600) with zo=0.6 assume Lt. Tree + # Forests of all classes (4100-4300) assumed zo=0.6 assume Lt. Tree + # Shrub (4400) with zo=0.06 assume Open + # Grasslands, pastures and agricultural areas (2000 series) with + # zo=0.1-0.15 assume Lt. Suburban + # Woody Wetlands (6250) with zo=0.3 assume suburban + # Emergent Herbaceous Wetlands (6240) with zo=0.03 assume Open + # Note: HAZUS category of trees (1.00) does not apply to any LU/LC in NJ + terrain = 15 # Default in Reorganized Rulesets - WIND + if location == "NJ": + if (BIM['FloodZone'].startswith('V') or BIM['FloodZone'] in ['A', 'AE', 'A1-30', 'AR', 'A99']): terrain = 3 - elif ((bim['LULC'] >= 5000) and (bim['LULC'] <= 5999)) or ( - ((bim['LULC'] == 4400) or (bim['LULC'] == 6240)) - or (bim['LULC'] == 7600) - ): - terrain = 3 # Open - elif (bim['LULC'] >= 2000) and (bim['LULC'] <= 2999): - terrain = 15 # Light suburban - elif ((bim['LULC'] >= 1110) and (bim['LULC'] <= 1140)) or ( - (bim['LULC'] >= 6250) and (bim['LULC'] <= 6252) - ): - terrain = 35 # Suburban - elif ((bim['LULC'] >= 4100) and (bim['LULC'] <= 4300)) or ( - bim['LULC'] == 1600 - ): - terrain = 70 # light trees - elif location == 'LA': - if bim['FloodZone'].startswith('V') or bim['FloodZone'] in { - 'A', - 'AE', - 'A1-30', - 'AR', - 'A99', - }: + elif ((BIM['LULC'] >= 5000) and (BIM['LULC'] <= 5999)): + terrain = 3 # Open + elif ((BIM['LULC'] == 4400) or (BIM['LULC'] == 6240)) or (BIM['LULC'] == 7600): + terrain = 3 # Open + elif ((BIM['LULC'] >= 2000) and (BIM['LULC'] <= 2999)): + terrain = 15 # Light suburban + elif ((BIM['LULC'] >= 1110) and (BIM['LULC'] <= 1140)) or ((BIM['LULC'] >= 6250) and (BIM['LULC'] <= 6252)): + terrain = 35 # Suburban + elif ((BIM['LULC'] >= 4100) and (BIM['LULC'] <= 4300)) or (BIM['LULC'] == 1600): + terrain = 70 # light trees + elif location == "LA": + if (BIM['FloodZone'].startswith('V') or BIM['FloodZone'] in ['A', 'AE', 'A1-30', 'AR', 'A99']): terrain = 3 - elif ((bim['LULC'] >= 50) and (bim['LULC'] <= 59)) or ( - ((bim['LULC'] == 44) or (bim['LULC'] == 62)) or (bim['LULC'] == 76) - ): - terrain = 3 # Open - elif (bim['LULC'] >= 20) and (bim['LULC'] <= 29): - terrain = 15 # Light suburban - elif (bim['LULC'] == 11) or (bim['LULC'] == 61): - terrain = 35 # Suburban - elif ((bim['LULC'] >= 41) and (bim['LULC'] <= 43)) or ( - bim['LULC'] in {16, 17} - ): - terrain = 70 # light trees - - bim.update( - { - # Nominal Design Wind Speed - # Former term was “Basic Wind Speed”; it is now the “Nominal Design - # Wind Speed (V_asd). Unit: mph." - 'V_asd': np.sqrt(0.6 * bim['V_ult']), - 'HazardProneRegion': hpr, - 'WindBorneDebris': wbd, - 'TerrainRoughness': terrain, - } - ) + elif ((BIM['LULC'] >= 50) and (BIM['LULC'] <= 59)): + terrain = 3 # Open + elif ((BIM['LULC'] == 44) or (BIM['LULC'] == 62)) or (BIM['LULC'] == 76): + terrain = 3 # Open + elif ((BIM['LULC'] >= 20) and (BIM['LULC'] <= 29)): + terrain = 15 # Light suburban + elif (BIM['LULC'] == 11) or (BIM['LULC'] == 61): + terrain = 35 # Suburban + elif ((BIM['LULC'] >= 41) and (BIM['LULC'] <= 43)) or (BIM['LULC'] in [16, 17]): + terrain = 70 # light trees + + BIM.update(dict( + # Nominal Design Wind Speed + # Former term was “Basic Wind Speed”; it is now the “Nominal Design + # Wind Speed (V_asd). Unit: mph." + V_asd = np.sqrt(0.6 * BIM['V_ult']), + + HazardProneRegion=HPR, + WindBorneDebris=WBD, + TerrainRoughness=terrain, + )) if 'inundation' in hazards: - bim.update( - { - # Flood Risk - # Properties in the High Water Zone (within 1 mile of - # the coast) are at risk of flooding and other - # wind-borne debris action. - # TODO: need high water zone for this and move it to inputs! # noqa: TD002 - 'FloodRisk': True, - } - ) - - return bim + + BIM.update(dict( + # Flood Risk + # Properties in the High Water Zone (within 1 mile of the coast) are at + # risk of flooding and other wind-borne debris action. + FloodRisk=True, # TODO: need high water zone for this and move it to inputs! + )) + + return BIM + diff --git a/pelicun/tests/dl_calculation/rulesets/WindCECBRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindCECBRulesets.py index 5b52b7a45..c034a6b4f 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindCECBRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindCECBRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -43,11 +44,12 @@ # Tracy Kijewski-Correa import random +import numpy as np +import datetime - -def CECB_config(bim: dict) -> str: # noqa: C901 +def CECB_config(BIM): """ - Rules to identify a HAZUS CECB configuration based on BIM data. + Rules to identify a HAZUS CECB configuration based on BIM data Parameters ---------- @@ -57,25 +59,26 @@ def CECB_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof cover - if bim['RoofShape'] in {'gab', 'hip'}: + if BIM['RoofShape'] in ['gab', 'hip']: roof_cover = 'bur' # Warning: HAZUS does not have N/A option for CECB, so here we use bur - elif year >= 1975: - roof_cover = 'spm' else: - # year < 1975 - roof_cover = 'bur' + if year >= 1975: + roof_cover = 'spm' + else: + # year < 1975 + roof_cover = 'bur' # shutters if year >= 2000: - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # BOCA 1996 and earlier: # Shutters were not required by code until the 2000 IBC. Before 2000, the # percentage of commercial buildings that have shutters is assumed to be @@ -85,51 +88,52 @@ def CECB_config(bim: dict) -> str: # noqa: C901 # facilities. In addition to that, 46% of business owners reported boarding # up their businesses before Hurricane Katrina. In addition, compliance # rates based on the Homeowners Survey data hover between 43 and 50 percent. - elif bim['WindBorneDebris']: - shutters = random.random() < 0.46 else: - shutters = False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.46 + else: + shutters = False # Wind Debris (widd in HAZSU) # HAZUS A: Res/Comm, B: Varies by direction, C: Residential, D: None - widd = 'C' # residential (default) - if bim['OccupancyClass'] in {'RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', 'RES3D'}: - widd = 'C' # residential - elif bim['OccupancyClass'] == 'AGR1': - widd = 'D' # None + WIDD = 'C' # residential (default) + if BIM['OccupancyClass'] in ['RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', + 'RES3D']: + WIDD = 'C' # residential + elif BIM['OccupancyClass'] == 'AGR1': + WIDD = 'D' # None else: - widd = 'A' # Res/Comm + WIDD = 'A' # Res/Comm # Window area ratio - if bim['WindowArea'] < 0.33: - wwr = 'low' - elif bim['WindowArea'] < 0.5: - wwr = 'med' + if BIM['WindowArea'] < 0.33: + WWR = 'low' + elif BIM['WindowArea'] < 0.5: + WWR = 'med' else: - wwr = 'hig' + WWR = 'hig' - if bim['NumberOfStories'] <= 2: + if BIM['NumberOfStories'] <= 2: bldg_tag = 'C.ECB.L' - elif bim['NumberOfStories'] <= 5: + elif BIM['NumberOfStories'] <= 5: bldg_tag = 'C.ECB.M' else: bldg_tag = 'C.ECB.H' # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'Shutters': shutters, - 'WindowAreaRatio': wwr, - 'WindDebrisClass': widd, - } - ) + BIM.update(dict( + RoofCover = roof_cover, + Shutters = shutters, + WindowAreaRatio = WWR, + WindDebrisClass = WIDD + )) + + bldg_config = f"{bldg_tag}." \ + f"{roof_cover}." \ + f"{int(shutters)}." \ + f"{WIDD}." \ + f"{WWR}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config - return ( - f"{bldg_tag}." - f"{roof_cover}." - f"{int(shutters)}." - f"{widd}." - f"{wwr}." - f"{int(bim['TerrainRoughness'])}" - ) diff --git a/pelicun/tests/dl_calculation/rulesets/WindCERBRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindCERBRulesets.py index 0b75ebad3..41f8faab0 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindCERBRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindCERBRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -43,11 +44,12 @@ # Tracy Kijewski-Correa import random +import numpy as np +import datetime - -def CERB_config(bim: dict) -> str: # noqa: C901 +def CERB_config(BIM): """ - Rules to identify a HAZUS CERB configuration based on BIM data. + Rules to identify a HAZUS CERB configuration based on BIM data Parameters ---------- @@ -57,25 +59,26 @@ def CERB_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof cover - if bim['RoofShape'] in {'gab', 'hip'}: + if BIM['RoofShape'] in ['gab', 'hip']: roof_cover = 'bur' # Warning: HAZUS does not have N/A option for CECB, so here we use bur - elif year >= 1975: - roof_cover = 'spm' else: - # year < 1975 - roof_cover = 'bur' + if year >= 1975: + roof_cover = 'spm' + else: + # year < 1975 + roof_cover = 'bur' # shutters if year >= 2000: - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # BOCA 1996 and earlier: # Shutters were not required by code until the 2000 IBC. Before 2000, the # percentage of commercial buildings that have shutters is assumed to be @@ -85,51 +88,51 @@ def CERB_config(bim: dict) -> str: # noqa: C901 # facilities. In addition to that, 46% of business owners reported boarding # up their businesses before Hurricane Katrina. In addition, compliance # rates based on the Homeowners Survey data hover between 43 and 50 percent. - elif bim['WindBorneDebris']: - shutters = random.random() < 0.45 else: - shutters = False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.45 + else: + shutters = False # Wind Debris (widd in HAZUS) # HAZUS A: Res/Comm, B: Varies by direction, C: Residential, D: None - widd = 'C' # residential (default) - if bim['OccupancyClass'] in {'RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', 'RES3D'}: - widd = 'C' # residential - elif bim['OccupancyClass'] == 'AGR1': - widd = 'D' # None + WIDD = 'C' # residential (default) + if BIM['OccupancyClass'] in ['RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', + 'RES3D']: + WIDD = 'C' # residential + elif BIM['OccupancyClass'] == 'AGR1': + WIDD = 'D' # None else: - widd = 'A' # Res/Comm + WIDD = 'A' # Res/Comm # Window area ratio - if bim['WindowArea'] < 0.33: - wwr = 'low' - elif bim['WindowArea'] < 0.5: - wwr = 'med' + if BIM['WindowArea'] < 0.33: + WWR = 'low' + elif BIM['WindowArea'] < 0.5: + WWR = 'med' else: - wwr = 'hig' + WWR = 'hig' - if bim['NumberOfStories'] <= 2: + if BIM['NumberOfStories'] <= 2: bldg_tag = 'C.ERB.L' - elif bim['NumberOfStories'] <= 5: + elif BIM['NumberOfStories'] <= 5: bldg_tag = 'C.ERB.M' else: bldg_tag = 'C.ERB.H' # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'Shutters': shutters, - 'WindowAreaRatio': wwr, - 'WindDebrisClass': widd, - } - ) + BIM.update(dict( + RoofCover = roof_cover, + Shutters = shutters, + WindowAreaRatio = WWR, + WindDebrisClass = WIDD + )) + + bldg_config = f"{bldg_tag}." \ + f"{roof_cover}." \ + f"{int(shutters)}." \ + f"{WIDD}." \ + f"{WWR}." \ + f"{int(BIM['TerrainRoughness'])}" - return ( - f"{bldg_tag}." - f"{roof_cover}." - f"{int(shutters)}." - f"{widd}." - f"{wwr}." - f"{int(bim['TerrainRoughness'])}" - ) + return bldg_config diff --git a/pelicun/tests/dl_calculation/rulesets/WindEFRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindEFRulesets.py index bd81df21b..1762eb5ce 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindEFRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindEFRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,13 +43,14 @@ # Meredith Lockhead # Tracy Kijewski-Correa -import datetime import random +import numpy as np +import datetime -def HUEFFS_config(bim: dict) -> str: +def HUEFFS_config(BIM): """ - Rules to identify a HAZUS HUEFFS/HUEFSS configuration based on BIM data. + Rules to identify a HAZUS HUEFFS/HUEFSS configuration based on BIM data Parameters ---------- @@ -58,62 +60,63 @@ def HUEFFS_config(bim: dict) -> str: Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof cover - roof_cover = 'spm' if year >= 1975 else 'bur' + if year >= 1975: + roof_cover = 'spm' + else: + # year < 1975 + roof_cover = 'bur' # Wind debris - widd = 'A' + WIDD = 'A' # Roof deck age - if year >= (datetime.datetime.now(tz=datetime.timezone.utc).year - 50): - dq = 'god' # new or average + if year >= (datetime.datetime.now().year - 50): + DQ = 'god' # new or average else: - dq = 'por' # old + DQ = 'por' # old # Metal-RDA if year > 2000: - if bim['V_ult'] <= 142: - mrda = 'std' # standard + if BIM['V_ult'] <= 142: + MRDA = 'std' # standard else: - mrda = 'sup' # superior + MRDA = 'sup' # superior else: - mrda = 'std' # standard + MRDA = 'std' # standard # Shutters - shutters = int(bim['WBD']) + shutters = int(BIM['WBD']) # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'RoofDeckAttachmentM': mrda, - 'RoofDeckAge': dq, - 'WindDebrisClass': widd, - 'Shutters': shutters, - } - ) + BIM.update(dict( + RoofCover = roof_cover, + RoofDeckAttachmentM = MRDA, + RoofDeckAge=DQ, + WindDebrisClass = WIDD, + Shutters = shutters + )) bldg_tag = 'HUEF.FS' - return ( - f"{bldg_tag}." - f"{roof_cover}." - f"{shutters}." - f"{widd}." - f"{dq}." - f"{mrda}." - f"{int(bim['TerrainRoughness'])}" - ) - - -def HUEFSS_config(bim: dict) -> str: + bldg_config = f"{bldg_tag}." \ + f"{roof_cover}." \ + f"{shutters}." \ + f"{WIDD}." \ + f"{DQ}." \ + f"{MRDA}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config + +def HUEFSS_config(BIM): """ - Rules to identify a HAZUS HUEFFS/HUEFSS configuration based on BIM data. + Rules to identify a HAZUS HUEFFS/HUEFSS configuration based on BIM data Parameters ---------- @@ -123,11 +126,11 @@ def HUEFSS_config(bim: dict) -> str: Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof cover if year >= 1975: @@ -137,52 +140,50 @@ def HUEFSS_config(bim: dict) -> str: roof_cover = 'bur' # Wind debris - widd = 'A' + WIDD = 'A' # Roof deck age - if year >= (datetime.datetime.now(tz=datetime.timezone.utc).year - 50): - dq = 'god' # new or average + if year >= (datetime.datetime.now().year - 50): + DQ = 'god' # new or average else: - dq = 'por' # old + DQ = 'por' # old # Metal-RDA if year > 2000: - if bim['V_ult'] <= 142: - mrda = 'std' # standard + if BIM['V_ult'] <= 142: + MRDA = 'std' # standard else: - mrda = 'sup' # superior + MRDA = 'sup' # superior else: - mrda = 'std' # standard + MRDA = 'std' # standard # Shutters - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'RoofDeckAttachmentM': mrda, - 'RoofDeckAge': dq, - 'WindDebrisClass': widd, - 'Shutters': shutters, - } - ) + BIM.update(dict( + RoofCover = roof_cover, + RoofDeckAttachmentM = MRDA, + RoofDeckAge=DQ, + WindDebrisClass = WIDD, + Shutters=shutters + )) bldg_tag = 'HUEF.S.S' - return ( - f"{bldg_tag}." - f"{roof_cover}." - f"{int(shutters)}." - f"{widd}." - f"{dq}." - f"{mrda}." - f"{int(bim['TerrainRoughness'])}" - ) - - -def HUEFH_config(bim: dict) -> str: + bldg_config = f"{bldg_tag}." \ + f"{roof_cover}." \ + f"{int(shutters)}." \ + f"{WIDD}." \ + f"{DQ}." \ + f"{MRDA}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config + + +def HUEFH_config(BIM): """ - Rules to identify a HAZUS HUEFH configuration based on BIM data. + Rules to identify a HAZUS HUEFH configuration based on BIM data Parameters ---------- @@ -192,11 +193,11 @@ def HUEFH_config(bim: dict) -> str: Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof cover if year >= 1975: @@ -206,50 +207,47 @@ def HUEFH_config(bim: dict) -> str: roof_cover = 'bur' # Wind debris - widd = 'A' + WIDD = 'A' # Shutters - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # Metal-RDA if year > 2000: - if bim['V_ult'] <= 142: - mrda = 'std' # standard + if BIM['V_ult'] <= 142: + MRDA = 'std' # standard else: - mrda = 'sup' # superior + MRDA = 'sup' # superior else: - mrda = 'std' # standard + MRDA = 'std' # standard - if bim['NumberOfStories'] <= 2: + if BIM['NumberOfStories'] <=2: bldg_tag = 'HUEF.H.S' - elif bim['NumberOfStories'] <= 5: + elif BIM['NumberOfStories'] <= 5: bldg_tag = 'HUEF.H.M' else: bldg_tag = 'HUEF.H.L' # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'RoofDeckAttachmentM': mrda, - 'WindDebrisClass': widd, - 'Shutters': shutters, - } - ) - - return ( - f"{bldg_tag}." - f"{roof_cover}." - f"{widd}." - f"{mrda}." - f"{int(shutters)}." - f"{int(bim['TerrainRoughness'])}" - ) - - -def HUEFS_config(bim: dict) -> str: + BIM.update(dict( + RoofCover = roof_cover, + RoofDeckAttachmentM = MRDA, + WindDebrisClass = WIDD, + Shutters=shutters + )) + + bldg_config = f"{bldg_tag}." \ + f"{roof_cover}." \ + f"{WIDD}." \ + f"{MRDA}." \ + f"{int(shutters)}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config + +def HUEFS_config(BIM): """ - Rules to identify a HAZUS HUEFS configuration based on BIM data. + Rules to identify a HAZUS HUEFS configuration based on BIM data Parameters ---------- @@ -259,11 +257,11 @@ def HUEFS_config(bim: dict) -> str: Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof cover if year >= 1975: @@ -273,43 +271,46 @@ def HUEFS_config(bim: dict) -> str: roof_cover = 'bur' # Wind debris - widd = 'C' + WIDD = 'C' # Shutters if year > 2000: - shutters = bim['WindBorneDebris'] - elif bim['WindBorneDebris']: - shutters = random.random() < 0.46 + shutters = BIM['WindBorneDebris'] else: - shutters = False + # year <= 2000 + if BIM['WindBorneDebris']: + shutters = random.random() < 0.46 + else: + shutters = False # Metal-RDA if year > 2000: - if bim['V_ult'] <= 142: - mrda = 'std' # standard + if BIM['V_ult'] <= 142: + MRDA = 'std' # standard else: - mrda = 'sup' # superior + MRDA = 'sup' # superior else: - mrda = 'std' # standard + MRDA = 'std' # standard - bldg_tag = 'HUEF.S.M' if bim['NumberOfStories'] <= 2 else 'HUEF.S.L' + if BIM['NumberOfStories'] <=2: + bldg_tag = 'HUEF.S.M' + else: + bldg_tag = 'HUEF.S.L' # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'RoofDeckAttachmentM': mrda, - 'WindDebrisClass': widd, - 'Shutters': shutters, - } - ) - - return ( - f"{bldg_tag}." - f"{roof_cover}." - f"{int(shutters)}." - f"{widd}." - f"null." - f"{mrda}." - f"{int(bim['TerrainRoughness'])}" - ) + BIM.update(dict( + RoofCover = roof_cover, + RoofDeckAttachmentM = MRDA, + WindDebrisClass = WIDD, + Shutters=shutters + )) + + bldg_config = f"{bldg_tag}." \ + f"{roof_cover}." \ + f"{int(shutters)}." \ + f"{WIDD}." \ + f"null." \ + f"{MRDA}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config \ No newline at end of file diff --git a/pelicun/tests/dl_calculation/rulesets/WindMECBRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindMECBRulesets.py index 42db6dc07..137844f7b 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindMECBRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindMECBRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -44,10 +45,9 @@ import random - -def MECB_config(bim: dict) -> str: # noqa: C901 +def MECB_config(BIM): """ - Rules to identify a HAZUS MECB configuration based on BIM data. + Rules to identify a HAZUS MECB configuration based on BIM data Parameters ---------- @@ -57,84 +57,85 @@ def MECB_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof cover - if bim['RoofShape'] in {'gab', 'hip'}: + if BIM['RoofShape'] in ['gab', 'hip']: roof_cover = 'bur' - # no info, using the default supported by HAZUS - elif year >= 1975: - roof_cover = 'spm' + # no info, using the default supoorted by HAZUS else: - # year < 1975 - roof_cover = 'bur' + if year >= 1975: + roof_cover = 'spm' + else: + # year < 1975 + roof_cover = 'bur' # shutters if year >= 2000: - shutters = bim['WindBorneDebris'] - elif bim['WindBorneDebris']: - shutters = random.random() < 0.46 + shutters = BIM['WindBorneDebris'] else: - shutters = False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.46 + else: + shutters = False # Wind Debris (widd in HAZSU) # HAZUS A: Res/Comm, B: Varies by direction, C: Residential, D: None - widd = 'C' # residential (default) - if bim['OccupancyClass'] in {'RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', 'RES3D'}: - widd = 'C' # residential - elif bim['OccupancyClass'] == 'AGR1': - widd = 'D' # None + WIDD = 'C' # residential (default) + if BIM['OccupancyClass'] in ['RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', + 'RES3D']: + WIDD = 'C' # residential + elif BIM['OccupancyClass'] == 'AGR1': + WIDD = 'D' # None else: - widd = 'A' # Res/Comm + WIDD = 'A' # Res/Comm # Metal RDA # 1507.2.8.1 High Wind Attachment. # Underlayment applied in areas subject to high winds (Vasd greater # than 110 mph as determined in accordance with Section 1609.3.1) shall # be applied with corrosion-resistant fasteners in accordance with - # the manufacturer's instructions. Fasteners are to be applied along + # the manufacturer’s instructions. Fasteners are to be applied along # the overlap not more than 36 inches on center. - if bim['V_ult'] > 142: - mrda = 'std' # standard + if BIM['V_ult'] > 142: + MRDA = 'std' # standard else: - mrda = 'sup' # superior + MRDA = 'sup' # superior # Window area ratio - if bim['WindowArea'] < 0.33: - wwr = 'low' - elif bim['WindowArea'] < 0.5: - wwr = 'med' + if BIM['WindowArea'] < 0.33: + WWR = 'low' + elif BIM['WindowArea'] < 0.5: + WWR = 'med' else: - wwr = 'hig' + WWR = 'hig' - if bim['NumberOfStories'] <= 2: + if BIM['NumberOfStories'] <= 2: bldg_tag = 'M.ECB.L' - elif bim['NumberOfStories'] <= 5: + elif BIM['NumberOfStories'] <= 5: bldg_tag = 'M.ECB.M' else: bldg_tag = 'M.ECB.H' # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'RoofDeckAttachmentM': mrda, - 'Shutters': shutters, - 'WindowAreaRatio': wwr, - 'WindDebrisClass': widd, - } - ) + BIM.update(dict( + RoofCover = roof_cover, + RoofDeckAttachmentM = MRDA, + Shutters = shutters, + WindowAreaRatio = WWR, + WindDebrisClass = WIDD + )) + + bldg_config = f"{bldg_tag}." \ + f"{roof_cover}." \ + f"{int(shutters)}." \ + f"{WIDD}." \ + f"{MRDA}." \ + f"{WWR}." \ + f"{int(BIM['TerrainRoughness'])}" - return ( - f"{bldg_tag}." - f"{roof_cover}." - f"{int(shutters)}." - f"{widd}." - f"{mrda}." - f"{wwr}." - f"{int(bim['TerrainRoughness'])}" - ) + return bldg_config diff --git a/pelicun/tests/dl_calculation/rulesets/WindMERBRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindMERBRulesets.py index 4158cd74e..2299b8dbb 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindMERBRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindMERBRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -43,11 +44,12 @@ # Tracy Kijewski-Correa import random +import numpy as np +import datetime - -def MERB_config(bim: dict) -> str: # noqa: C901 +def MERB_config(BIM): """ - Rules to identify a HAZUS MERB configuration based on BIM data. + Rules to identify a HAZUS MERB configuration based on BIM data Parameters ---------- @@ -57,84 +59,85 @@ def MERB_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof cover - if bim['RoofShape'] in {'gab', 'hip'}: + if BIM['RoofShape'] in ['gab', 'hip']: roof_cover = 'bur' - # no info, using the default supported by HAZUS - elif year >= 1975: - roof_cover = 'spm' + # no info, using the default supoorted by HAZUS else: - # year < 1975 - roof_cover = 'bur' + if year >= 1975: + roof_cover = 'spm' + else: + # year < 1975 + roof_cover = 'bur' # shutters if year >= 2000: - shutters = bim['WindBorneDebris'] - elif bim['WindBorneDebris']: - shutters = random.random() < 0.45 + shutters = BIM['WindBorneDebris'] else: - shutters = False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.45 + else: + shutters = False # Wind Debris (widd in HAZSU) # HAZUS A: Res/Comm, B: Varies by direction, C: Residential, D: None - widd = 'C' # residential (default) - if bim['OccupancyClass'] in {'RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', 'RES3D'}: - widd = 'C' # residential - elif bim['OccupancyClass'] == 'AGR1': - widd = 'D' # None + WIDD = 'C' # residential (default) + if BIM['OccupancyClass'] in ['RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', + 'RES3D']: + WIDD = 'C' # residential + elif BIM['OccupancyClass'] == 'AGR1': + WIDD = 'D' # None else: - widd = 'A' # Res/Comm + WIDD = 'A' # Res/Comm # Metal RDA # 1507.2.8.1 High Wind Attachment. # Underlayment applied in areas subject to high winds (Vasd greater # than 110 mph as determined in accordance with Section 1609.3.1) shall # be applied with corrosion-resistant fasteners in accordance with - # the manufacturer's instructions. Fasteners are to be applied along + # the manufacturer’s instructions. Fasteners are to be applied along # the overlap not more than 36 inches on center. - if bim['V_ult'] > 142: - mrda = 'std' # standard + if BIM['V_ult'] > 142: + MRDA = 'std' # standard else: - mrda = 'sup' # superior + MRDA = 'sup' # superior # Window area ratio - if bim['WindowArea'] < 0.33: - wwr = 'low' - elif bim['WindowArea'] < 0.5: - wwr = 'med' + if BIM['WindowArea'] < 0.33: + WWR = 'low' + elif BIM['WindowArea'] < 0.5: + WWR = 'med' else: - wwr = 'hig' + WWR = 'hig' - if bim['NumberOfStories'] <= 2: + if BIM['NumberOfStories'] <= 2: bldg_tag = 'M.ERB.L' - elif bim['NumberOfStories'] <= 5: + elif BIM['NumberOfStories'] <= 5: bldg_tag = 'M.ERB.M' else: bldg_tag = 'M.ERB.H' # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'RoofDeckAttachmentM': mrda, - 'Shutters': shutters, - 'WindowAreaRatio': wwr, - 'WindDebrisClass': widd, - } - ) + BIM.update(dict( + RoofCover = roof_cover, + RoofDeckAttachmentM = MRDA, + Shutters = shutters, + WindowAreaRatio = WWR, + WindDebrisClass = WIDD + )) + + bldg_config = f"{bldg_tag}." \ + f"{roof_cover}." \ + f"{int(shutters)}." \ + f"{WIDD}." \ + f"{MRDA}." \ + f"{WWR}." \ + f"{int(BIM['TerrainRoughness'])}" - return ( - f"{bldg_tag}." - f"{roof_cover}." - f"{int(shutters)}." - f"{widd}." - f"{mrda}." - f"{wwr}." - f"{int(bim['TerrainRoughness'])}" - ) + return bldg_config diff --git a/pelicun/tests/dl_calculation/rulesets/WindMHRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindMHRulesets.py index 37480fc17..db6ebe8a3 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindMHRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindMHRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -43,11 +44,12 @@ # Tracy Kijewski-Correa import random +import numpy as np +import datetime - -def MH_config(bim: dict) -> str: +def MH_config(BIM): """ - Rules to identify a HAZUS WSF configuration based on BIM data. + Rules to identify a HAZUS WSF configuration based on BIM data Parameters ---------- @@ -57,44 +59,55 @@ def MH_config(bim: dict) -> str: Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity if year <= 1976: # MHPHUD bldg_tag = 'MH.PHUD' - shutters = random.random() < 0.45 if bim['WindBorneDebris'] else False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.45 + else: + shutters = False # TieDowns - tie_downs = random.random() < 0.45 + TD = random.random() < 0.45 elif year <= 1994: # MH76HUD bldg_tag = 'MH.76HUD' - shutters = random.random() < 0.45 if bim['WindBorneDebris'] else False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.45 + else: + shutters = False # TieDowns - tie_downs = random.random() < 0.45 + TD = random.random() < 0.45 else: # MH94HUD I, II, III - shutters = bim['V_ult'] >= 100.0 + if BIM['V_ult'] >= 100.0: + shutters = True + else: + shutters = False # TieDowns - tie_downs = bim['V_ult'] >= 70.0 + if BIM['V_ult'] >= 70.0: + TD = True + else: + TD = False - bldg_tag = 'MH.94HUD' + bim['WindZone'] + bldg_tag = 'MH.94HUD' + BIM['WindZone'] # extend the BIM dictionary - bim.update( - { - 'TieDowns': tie_downs, - 'Shutters': shutters, - } - ) + BIM.update(dict( + TieDowns = TD, + Shutters = shutters, + )) + + bldg_config = f"{bldg_tag}." \ + f"{int(shutters)}." \ + f"{int(TD)}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config - return ( - f"{bldg_tag}." - f"{int(shutters)}." - f"{int(tie_downs)}." - f"{int(bim['TerrainRoughness'])}" - ) diff --git a/pelicun/tests/dl_calculation/rulesets/WindMLRIRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindMLRIRulesets.py index 3a46c7199..09b833976 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindMLRIRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindMLRIRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,12 +43,13 @@ # Meredith Lockhead # Tracy Kijewski-Correa +import random +import numpy as np import datetime - -def MLRI_config(bim: dict) -> str: +def MLRI_config(BIM): """ - Rules to identify a HAZUS MLRI configuration based on BIM data. + Rules to identify a HAZUS MLRI configuration based on BIM data Parameters ---------- @@ -57,14 +59,14 @@ def MLRI_config(bim: dict) -> str: Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # MR - mr = True + MR = True # Shutters shutters = False @@ -74,50 +76,46 @@ def MLRI_config(bim: dict) -> str: # Underlayment applied in areas subject to high winds (Vasd greater # than 110 mph as determined in accordance with Section 1609.3.1) shall # be applied with corrosion-resistant fasteners in accordance with - # the manufacturer's instructions. Fasteners are to be applied along + # the manufacturer’s instructions. Fasteners are to be applied along # the overlap not more than 36 inches on center. - if bim['V_ult'] > 142: - mrda = 'std' # standard + if BIM['V_ult'] > 142: + MRDA = 'std' # standard else: - mrda = 'sup' # superior + MRDA = 'sup' # superior - if bim['RoofShape'] in {'gab', 'hip'}: + if BIM['RoofShape'] in ['gab', 'hip']: roof_cover = 'null' - roof_quality = 'god' # default supported by HAZUS - elif year >= 1975: - roof_cover = 'spm' - if bim['YearBuilt'] >= ( - datetime.datetime.now(tz=datetime.timezone.utc).year - 35 - ): - roof_quality = 'god' - else: - roof_quality = 'por' + roof_quality = 'god' # default supported by HAZUS else: - # year < 1975 - roof_cover = 'bur' - if bim['YearBuilt'] >= ( - datetime.datetime.now(tz=datetime.timezone.utc).year - 30 - ): - roof_quality = 'god' + if year >= 1975: + roof_cover = 'spm' + if BIM['YearBuilt'] >= (datetime.datetime.now().year - 35): + roof_quality = 'god' + else: + roof_quality = 'por' else: - roof_quality = 'por' - + # year < 1975 + roof_cover = 'bur' + if BIM['YearBuilt'] >= (datetime.datetime.now().year - 30): + roof_quality = 'god' + else: + roof_quality = 'por' + # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'RoofQuality': roof_quality, - 'RoofDeckAttachmentM': mrda, - 'Shutters': shutters, - 'MasonryReinforcing': mr, - } - ) + BIM.update(dict( + RoofCover = roof_cover, + RoofQuality = roof_quality, + RoofDeckAttachmentM = MRDA, + Shutters = shutters, + MasonryReinforcing = MR, + )) + + bldg_config = f"M.LRI." \ + f"{int(shutters)}." \ + f"{int(MR)}." \ + f"{roof_quality}." \ + f"{MRDA}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config - return ( - f"M.LRI." - f"{int(shutters)}." - f"{int(mr)}." - f"{roof_quality}." - f"{mrda}." - f"{int(bim['TerrainRoughness'])}" - ) diff --git a/pelicun/tests/dl_calculation/rulesets/WindMLRMRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindMLRMRulesets.py index 8354e8b30..c63f39313 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindMLRMRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindMLRMRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,13 +43,13 @@ # Meredith Lockhead # Tracy Kijewski-Correa -import datetime import random +import numpy as np +import datetime - -def MLRM_config(bim: dict) -> str: # noqa: C901 +def MLRM_config(BIM): """ - Rules to identify a HAZUS MLRM configuration based on BIM data. + Rules to identify a HAZUS MLRM configuration based on BIM data Parameters ---------- @@ -58,17 +59,17 @@ def MLRM_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Note the only roof option for commercial masonry in NJ appraisers manual # is OSWJ, so this suggests they do not even see alternate roof system # ref: Custom Inventory google spreadsheet H-37 10/01/20 # This could be commented for other regions if detailed data are available - bim['RoofSystem'] = 'ows' + BIM['RoofSystem'] = 'ows' # Roof cover # Roof cover does not apply to gable and hip roofs @@ -80,138 +81,135 @@ def MLRM_config(bim: dict) -> str: # noqa: C901 # Shutters # IRC 2000-2015: - # R301.2.1.2 in NJ IRC 2015 says protection of openings required - # for buildings located in WindBorneDebris regions, mentions - # impact-rated protection for glazing, impact-resistance for - # garage door glazed openings, and finally states that wood - # structural panels with a thickness > 7/16" and a span <8' can be - # used, as long as they are precut, attached to the framing - # surrounding the opening, and the attachments are resistant to - # corrosion and are able to resist component and cladding loads; + # R301.2.1.2 in NJ IRC 2015 says protection of openings required for + # buildings located in WindBorneDebris regions, mentions impact-rated protection for + # glazing, impact-resistance for garage door glazed openings, and finally + # states that wood structural panels with a thickness > 7/16" and a + # span <8' can be used, as long as they are precut, attached to the framing + # surrounding the opening, and the attachments are resistant to corrosion + # and are able to resist component and cladding loads; # Earlier IRC editions provide similar rules. - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # Masonry Reinforcing (MR) - # R606.6.4.1.2 Metal Reinforcement states that walls other than - # interior non-load-bearing walls shall be anchored at vertical - # intervals of not more than 8 inches with joint reinforcement of - # not less than 9-gage. Therefore this ruleset assumes that all - # exterior or load-bearing masonry walls will have - # reinforcement. Since our considerations deal with wind speed, I - # made the assumption that only exterior walls are being taken + # R606.6.4.1.2 Metal Reinforcement states that walls other than interior + # non-load-bearing walls shall be anchored at vertical intervals of not + # more than 8 inches with joint reinforcement of not less than 9 gage. + # Therefore this ruleset assumes that all exterior or load-bearing masonry + # walls will have reinforcement. Since our considerations deal with wind + # speed, I made the assumption that only exterior walls are being taken # into consideration. - mr = True + MR = True # Wind Debris (widd in HAZSU) # HAZUS A: Res/Comm, B: Varies by direction, C: Residential, D: None - widd = 'C' # residential (default) - if bim['OccupancyClass'] in {'RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', 'RES3D'}: - widd = 'C' # residential - elif bim['OccupancyClass'] == 'AGR1': - widd = 'D' # None + WIDD = 'C' # residential (default) + if BIM['OccupancyClass'] in ['RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', + 'RES3D']: + WIDD = 'C' # residential + elif BIM['OccupancyClass'] == 'AGR1': + WIDD = 'D' # None else: - widd = 'A' # Res/Comm + WIDD = 'A' # Res/Comm - if bim['RoofSystem'] == 'ows': + if BIM['RoofSystem'] == 'ows': # RDA - rda = 'null' # Doesn't apply to OWSJ + RDA = 'null' # Doesn't apply to OWSJ # Roof deck age (DQ) # Average lifespan of a steel joist roof is roughly 50 years according # to the source below. Therefore, if constructed 50 years before the # current year, the roof deck should be considered old. # https://www.metalroofing.systems/metal-roofing-pros-cons/ - if year >= (datetime.datetime.now(tz=datetime.timezone.utc).year - 50): - dq = 'god' # new or average + if year >= (datetime.datetime.now().year - 50): + DQ = 'god' # new or average else: - dq = 'por' # old + DQ = 'por' # old # RWC - rwc = 'null' # Doesn't apply to OWSJ + RWC = 'null' # Doesn't apply to OWSJ # Metal RDA # 1507.2.8.1 High Wind Attachment. # Underlayment applied in areas subject to high winds (Vasd greater # than 110 mph as determined in accordance with Section 1609.3.1) shall # be applied with corrosion-resistant fasteners in accordance with - # the manufacturer's instructions. Fasteners are to be applied along + # the manufacturer’s instructions. Fasteners are to be applied along # the overlap not more than 36 inches on center. - if bim['V_ult'] > 142: - mrda = 'std' # standard + if BIM['V_ult'] > 142: + MRDA = 'std' # standard else: - mrda = 'sup' # superior + MRDA = 'sup' # superior - elif bim['RoofSystem'] == 'trs': + elif BIM['RoofSystem'] == 'trs': # This clause should not be activated for NJ # RDA - if bim['TerrainRoughness'] >= 35: # suburban or light trees - if bim['V_ult'] > 130.0: - rda = '8s' # 8d @ 6"/6" 'D' + if BIM['TerrainRoughness'] >= 35: # suburban or light trees + if BIM['V_ult'] > 130.0: + RDA = '8s' # 8d @ 6"/6" 'D' else: - rda = '8d' # 8d @ 6"/12" 'B' - elif bim['V_ult'] > 110.0: - rda = '8s' # 8d @ 6"/6" 'D' - else: - rda = '8d' # 8d @ 6"/12" 'B' + RDA = '8d' # 8d @ 6"/12" 'B' + else: # light suburban or open + if BIM['V_ult'] > 110.0: + RDA = '8s' # 8d @ 6"/6" 'D' + else: + RDA = '8d' # 8d @ 6"/12" 'B' # Metal RDA - mrda = 'null' # Doesn't apply to Wood Truss + MRDA = 'null' # Doesn't apply to Wood Truss # Roof deck agea (DQ) - dq = 'null' # Doesn't apply to Wood Truss + DQ = 'null' # Doesn't apply to Wood Truss # RWC - if bim['V_ult'] > 110: - rwc = 'strap' # Strap + if BIM['V_ult'] > 110: + RWC = 'strap' # Strap else: - rwc = 'tnail' # Toe-nail + RWC = 'tnail' # Toe-nail # shutters if year >= 2000: - shutters = bim['WindBorneDebris'] - elif bim['WindBorneDebris']: - shutters = random.random() < 0.46 + shutters = BIM['WindBorneDebris'] else: - shutters = False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.46 + else: + shutters = False - if bim['MeanRoofHt'] < 15.0: + if BIM['MeanRoofHt'] < 15.0: # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'RoofDeckAttachmentW': rda, - 'RoofDeckAttachmentM': mrda, - 'RoofDeckAge': dq, - 'RoofToWallConnection': rwc, - 'Shutters': shutters, - 'MasonryReinforcing': mr, - 'WindowAreaRatio': widd, - } - ) + BIM.update(dict( + RoofCover = roof_cover, + RoofDeckAttachmentW = RDA, + RoofDeckAttachmentM = MRDA, + RoofDeckAge = DQ, + RoofToWallConnection = RWC, + Shutters = shutters, + MasonryReinforcing = MR, + WindowAreaRatio = WIDD + )) # if it's MLRM1, configure outputs - bldg_config = ( - f"M.LRM.1." - f"{roof_cover}." - f"{int(shutters)}." - f"{int(mr)}." - f"{widd}." - f"{bim['RoofSystem']}." - f"{rda}." - f"{rwc}." - f"{dq}." - f"{mrda}." - f"{int(bim['TerrainRoughness'])}" - ) + bldg_config = f"M.LRM.1." \ + f"{roof_cover}." \ + f"{int(shutters)}." \ + f"{int(MR)}." \ + f"{WIDD}." \ + f"{BIM['RoofSystem']}." \ + f"{RDA}." \ + f"{RWC}." \ + f"{DQ}." \ + f"{MRDA}." \ + f"{int(BIM['TerrainRoughness'])}" else: unit_tag = 'null' # MLRM2 needs more rulesets - if bim['RoofSystem'] == 'trs': - joist_spacing: int | str = 'null' - elif bim['RoofSystem'] == 'ows': - if bim['NumberOfUnits'] == 1: + if BIM['RoofSystem'] == 'trs': + joist_spacing = 'null' + elif BIM['RoofSystem'] == 'ows': + if BIM['NumberOfUnits'] == 1: joist_spacing = 'null' unit_tag = 'sgl' else: @@ -219,34 +217,30 @@ def MLRM_config(bim: dict) -> str: # noqa: C901 unit_tag = 'mlt' # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'RoofDeckAttachmentW': rda, - 'RoofDeckAttachmentM': mrda, - 'RoofDeckAge': dq, - 'RoofToWallConnection': rwc, - 'Shutters': shutters, - 'MasonryReinforcing': mr, - 'WindDebrisClass': widd, - 'UnitType': unit_tag, - } - ) - - bldg_config = ( - f"M.LRM.2." - f"{roof_cover}." - f"{int(shutters)}." - f"{int(mr)}." - f"{widd}." - f"{bim['RoofSystem']}." - f"{rda}." - f"{rwc}." - f"{dq}." - f"{mrda}." - f"{unit_tag}." - f"{joist_spacing}." - f"{int(bim['TerrainRoughness'])}" - ) - - return bldg_config + BIM.update(dict( + RoofCover = roof_cover, + RoofDeckAttachmentW = RDA, + RoofDeckAttachmentM = MRDA, + RoofDeckAge = DQ, + RoofToWallConnection = RWC, + Shutters = shutters, + MasonryReinforcing = MR, + WindDebrisClass = WIDD, + UnitType=unit_tag + )) + + bldg_config = f"M.LRM.2." \ + f"{roof_cover}." \ + f"{int(shutters)}." \ + f"{int(MR)}." \ + f"{WIDD}." \ + f"{BIM['RoofSystem']}." \ + f"{RDA}." \ + f"{RWC}." \ + f"{DQ}." \ + f"{MRDA}." \ + f"{unit_tag}." \ + f"{joist_spacing}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config \ No newline at end of file diff --git a/pelicun/tests/dl_calculation/rulesets/WindMMUHRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindMMUHRulesets.py index 83ded54f1..3d27cbe09 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindMMUHRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindMMUHRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,13 +43,12 @@ # Meredith Lockhead # Tracy Kijewski-Correa -import datetime import random +import datetime - -def MMUH_config(bim: dict) -> str: # noqa: C901 +def MMUH_config(BIM): """ - Rules to identify a HAZUS MMUH configuration based on BIM data. + Rules to identify a HAZUS MMUH configuration based on BIM data Parameters ---------- @@ -58,25 +58,25 @@ def MMUH_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Secondary Water Resistance (SWR) # Minimum drainage recommendations are in place in NJ (See below). # However, SWR indicates a code-plus practice. - swr: int | str = 'null' # Default - if bim['RoofShape'] == 'flt': - swr = 'null' - elif bim['RoofShape'] in {'hip', 'gab'}: - swr = int(random.random() < 0.6) + SWR = "null" # Default + if BIM['RoofShape'] == 'flt': + SWR = 'null' + elif BIM['RoofShape'] in ['hip', 'gab']: + SWR = int(random.random() < 0.6) # Roof cover & Roof quality # Roof cover and quality do not apply to gable and hip roofs - if bim['RoofShape'] in {'gab', 'hip'}: + if BIM['RoofShape'] in ['gab', 'hip']: roof_cover = 'null' roof_quality = 'null' @@ -93,29 +93,26 @@ def MMUH_config(bim: dict) -> str: # noqa: C901 # We assume that all flat roofs built before 1975 are BURs and all roofs # built after 1975 are SPMs. # Nothing in NJ Building Code or in the Hazus manual specifies what - # constitutes “good” and “poor” roof conditions, so ruleset is dependent + # constitutes “good” and “poor” roof conditions, so ruleset is dependant # on the age of the roof and average lifespan of BUR and SPM roofs. # We assume that the average lifespan of a BUR roof is 30 years and the # average lifespan of a SPM is 35 years. Therefore, BURs installed before # 1990 are in poor condition, and SPMs installed before 1985 are in poor # condition. - elif year >= 1975: - roof_cover = 'spm' - if bim['YearBuilt'] >= ( - datetime.datetime.now(tz=datetime.timezone.utc).year - 35 - ): - roof_quality = 'god' - else: - roof_quality = 'por' else: - # year < 1975 - roof_cover = 'bur' - if bim['YearBuilt'] >= ( - datetime.datetime.now(tz=datetime.timezone.utc).year - 30 - ): - roof_quality = 'god' + if year >= 1975: + roof_cover = 'spm' + if BIM['YearBuilt'] >= (datetime.datetime.now().year - 35): + roof_quality = 'god' + else: + roof_quality = 'por' else: - roof_quality = 'por' + # year < 1975 + roof_cover = 'bur' + if BIM['YearBuilt'] >= (datetime.datetime.now().year - 30): + roof_quality = 'god' + else: + roof_quality = 'por' # Roof Deck Attachment (RDA) # IRC 2009-2015: @@ -130,35 +127,35 @@ def MMUH_config(bim: dict) -> str: # noqa: C901 # roughness length in the ruleset herein. # The base rule was then extended to the exposures closest to suburban and # light suburban, even though these are not considered by the code. - if bim['TerrainRoughness'] >= 35: # suburban or light trees - if bim['V_ult'] > 130.0: - rda = '8s' # 8d @ 6"/6" 'D' + if BIM['TerrainRoughness'] >= 35: # suburban or light trees + if BIM['V_ult'] > 130.0: + RDA = '8s' # 8d @ 6"/6" 'D' else: - rda = '8d' # 8d @ 6"/12" 'B' - elif bim['V_ult'] > 110.0: - rda = '8s' # 8d @ 6"/6" 'D' - else: - rda = '8d' # 8d @ 6"/12" 'B' + RDA = '8d' # 8d @ 6"/12" 'B' + else: # light suburban or open + if BIM['V_ult'] > 110.0: + RDA = '8s' # 8d @ 6"/6" 'D' + else: + RDA = '8d' # 8d @ 6"/12" 'B' # Roof-Wall Connection (RWC) - if bim['V_ult'] > 110.0: - rwc = 'strap' # Strap + if BIM['V_ult'] > 110.0: + RWC = 'strap' # Strap else: - rwc = 'tnail' # Toe-nail + RWC = 'tnail' # Toe-nail # Shutters # IRC 2000-2015: - # R301.2.1.2 in NJ IRC 2015 says protection of openings required - # for buildings located in WindBorneDebris regions, mentions - # impact-rated protection for glazing, impact-resistance for - # garage door glazed openings, and finally states that wood - # structural panels with a thickness > 7/16" and a span <8' can be - # used, as long as they are precut, attached to the framing - # surrounding the opening, and the attachments are resistant to - # corrosion and are able to resist component and cladding loads; + # R301.2.1.2 in NJ IRC 2015 says protection of openings required for + # buildings located in WindBorneDebris regions, mentions impact-rated protection for + # glazing, impact-resistance for garage door glazed openings, and finally + # states that wood structural panels with a thickness > 7/16" and a + # span <8' can be used, as long as they are precut, attached to the framing + # surrounding the opening, and the attachments are resistant to corrosion + # and are able to resist component and cladding loads; # Earlier IRC editions provide similar rules. if year >= 2000: - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # BOCA 1996 and earlier: # Shutters were not required by code until the 2000 IBC. Before 2000, the # percentage of commercial buildings that have shutters is assumed to be @@ -168,46 +165,45 @@ def MMUH_config(bim: dict) -> str: # noqa: C901 # facilities. In addition to that, 46% of business owners reported boarding # up their businesses before Hurricane Katrina. In addition, compliance # rates based on the Homeowners Survey data hover between 43 and 50 percent. - elif bim['WindBorneDebris']: - shutters = random.random() < 0.46 else: - shutters = False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.46 + else: + shutters = False # Masonry Reinforcing (MR) # R606.6.4.1.2 Metal Reinforcement states that walls other than interior # non-load-bearing walls shall be anchored at vertical intervals of not - # more than 8 inches with joint reinforcement of not less than 9-gage. + # more than 8 inches with joint reinforcement of not less than 9 gage. # Therefore this ruleset assumes that all exterior or load-bearing masonry # walls will have reinforcement. Since our considerations deal with wind # speed, I made the assumption that only exterior walls are being taken # into consideration. - mr = True + MR = True - stories = min(bim['NumberOfStories'], 3) + stories = min(BIM['NumberOfStories'], 3) # extend the BIM dictionary - bim.update( - { - 'SecondaryWaterResistance': swr, - 'RoofCover': roof_cover, - 'RoofQuality': roof_quality, - 'RoofDeckAttachmentW': rda, - 'RoofToWallConnection': rwc, - 'Shutters': shutters, - 'MasonryReinforcing': mr, - } - ) - - return ( - f"M.MUH." - f"{int(stories)}." - f"{bim['RoofShape']}." - f"{int(swr)}." - f"{roof_cover}." - f"{roof_quality}." - f"{rda}." - f"{rwc}." - f"{int(shutters)}." - f"{int(mr)}." - f"{int(bim['TerrainRoughness'])}" - ) + BIM.update(dict( + SecondaryWaterResistance = SWR, + RoofCover = roof_cover, + RoofQuality = roof_quality, + RoofDeckAttachmentW = RDA, + RoofToWallConnection = RWC, + Shutters = shutters, + MasonryReinforcing = MR, + )) + + bldg_config = f"M.MUH." \ + f"{int(stories)}." \ + f"{BIM['RoofShape']}." \ + f"{int(SWR)}." \ + f"{roof_cover}." \ + f"{roof_quality}." \ + f"{RDA}." \ + f"{RWC}." \ + f"{int(shutters)}." \ + f"{int(MR)}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config diff --git a/pelicun/tests/dl_calculation/rulesets/WindMSFRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindMSFRulesets.py index bb538715b..a9878d9de 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindMSFRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindMSFRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,13 +43,12 @@ # Meredith Lockhead # Tracy Kijewski-Correa -import datetime import random +import datetime - -def MSF_config(bim: dict) -> str: # noqa: C901 +def MSF_config(BIM): """ - Rules to identify a HAZUS MSF configuration based on BIM data. + Rules to identify a HAZUS MSF configuration based on BIM data Parameters ---------- @@ -58,37 +58,36 @@ def MSF_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof-Wall Connection (RWC) - if bim['HazardProneRegion']: - rwc = 'strap' # Strap + if BIM['HazardProneRegion']: + RWC = 'strap' # Strap else: - rwc = 'tnail' # Toe-nail + RWC = 'tnail' # Toe-nail # Roof Frame Type - rft = bim['RoofSystem'] + RFT = BIM['RoofSystem'] # Story Flag - stories = min(bim['NumberOfStories'], 2) + stories = min(BIM['NumberOfStories'], 2) # Shutters # IRC 2000-2015: - # R301.2.1.2 in NJ IRC 2015 says protection of openings required - # for buildings located in WindBorneDebris regions, mentions - # impact-rated protection for glazing, impact-resistance for - # garage door glazed openings, and finally states that wood - # structural panels with a thickness > 7/16" and a span <8' can be - # used, as long as they are precut, attached to the framing - # surrounding the opening, and the attachments are resistant to - # corrosion and are able to resist component and cladding loads; + # R301.2.1.2 in NJ IRC 2015 says protection of openings required for + # buildings located in WindBorneDebris regions, mentions impact-rated protection for + # glazing, impact-resistance for garage door glazed openings, and finally + # states that wood structural panels with a thickness > 7/16" and a + # span <8' can be used, as long as they are precut, attached to the framing + # surrounding the opening, and the attachments are resistant to corrosion + # and are able to resist component and cladding loads; # Earlier IRC editions provide similar rules. if year >= 2000: - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # BOCA 1996 and earlier: # Shutters were not required by code until the 2000 IBC. Before 2000, the # percentage of commercial buildings that have shutters is assumed to be @@ -98,12 +97,15 @@ def MSF_config(bim: dict) -> str: # noqa: C901 # facilities. In addition to that, 46% of business owners reported boarding # up their businesses before Hurricane Katrina. In addition, compliance # rates based on the Homeowners Survey data hover between 43 and 50 percent. - elif bim['WindBorneDebris']: - shutters = random.random() < 0.45 else: - shutters = False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.45 + else: + shutters = False + + + if BIM['RoofSystem'] == 'trs': - if bim['RoofSystem'] == 'trs': # Roof Deck Attachment (RDA) # IRC codes: # NJ code requires 8d nails (with spacing 6”/12”) for sheathing thicknesses @@ -112,22 +114,22 @@ def MSF_config(bim: dict) -> str: # noqa: C901 # codes. Commentary for Table R602.3(1) indicates 8d nails with 6”/6” # spacing (enhanced roof spacing) for ultimate wind speeds greater than # a speed_lim. speed_lim depends on the year of construction - rda = '6d' # Default (aka A) in Reorganized Rulesets - WIND + RDA = '6d' # Default (aka A) in Reorganized Rulesets - WIND if year >= 2016: # IRC 2015 - speed_lim = 130.0 # mph + speed_lim = 130.0 # mph else: # IRC 2000 - 2009 - speed_lim = 100.0 # mph - if bim['V_ult'] > speed_lim: - rda = '8s' # 8d @ 6"/6" ('D' in the Reorganized Rulesets - WIND) + speed_lim = 100.0 # mph + if BIM['V_ult'] > speed_lim: + RDA = '8s' # 8d @ 6"/6" ('D' in the Reorganized Rulesets - WIND) else: - rda = '8d' # 8d @ 6"/12" ('B' in the Reorganized Rulesets - WIND) + RDA = '8d' # 8d @ 6"/12" ('B' in the Reorganized Rulesets - WIND) # Secondary Water Resistance (SWR) # Minimum drainage recommendations are in place in NJ (See below). # However, SWR indicates a code-plus practice. - swr: int | float | str = random.random() < 0.6 + SWR = random.random() < 0.6 # Garage # As per IRC 2015: @@ -144,68 +146,69 @@ def MSF_config(bim: dict) -> str: # noqa: C901 # (and therefore do not have any strength requirements) that are older than # 30 years are considered to be weak, whereas those from the last 30 years # are considered to be standard. - if bim['Garage'] == -1: + if BIM['Garage'] == -1: # no garage data, using the default "none" garage = 'no' - elif year > (datetime.datetime.now(tz=datetime.timezone.utc).year - 30): - if bim['Garage'] < 1: - garage = 'no' # None - elif shutters: - garage = 'sup' # SFBC 1994 - else: - garage = 'std' # Standard - elif bim['Garage'] < 1: - garage = 'no' # None - elif shutters: - garage = 'sup' else: - garage = 'wkd' # Weak + if year > (datetime.datetime.now().year - 30): + if BIM['Garage'] < 1: + garage = 'no' # None + else: + if shutters: + garage = 'sup' # SFBC 1994 + else: + garage = 'std' # Standard + else: + # year <= current year - 30 + if BIM['Garage'] < 1: + garage = 'no' # None + else: + if shutters: + garage = 'sup' + else: + garage = 'wkd' # Weak # Masonry Reinforcing (MR) # R606.6.4.1.2 Metal Reinforcement states that walls other than interior # non-load-bearing walls shall be anchored at vertical intervals of not - # more than 8 inches with joint reinforcement of not less than 9-gage. + # more than 8 inches with joint reinforcement of not less than 9 gage. # Therefore this ruleset assumes that all exterior or load-bearing masonry # walls will have reinforcement. Since our considerations deal with wind # speed, I made the assumption that only exterior walls are being taken # into consideration. - mr = True + MR = True - stories = min(bim['NumberOfStories'], 2) + stories = min(BIM['NumberOfStories'], 2) # extend the BIM dictionary - bim.update( - { - 'SecondaryWaterResistance': swr, - 'RoofDeckAttachmentW': rda, - 'RoofToWallConnection': rwc, - 'Shutters': shutters, - 'AugmentGarage': garage, - 'MasonryReinforcing': mr, - } - ) + BIM.update(dict( + SecondaryWaterResistance = SWR, + RoofDeckAttachmentW = RDA, + RoofToWallConnection = RWC, + Shutters = shutters, + AugmentGarage = garage, + MasonryReinforcing = MR, + )) - bldg_config = ( - f"M.SF." - f"{int(stories)}." - f"{bim['RoofShape']}." - f"{rwc}." - f"{rft}." - f"{rda}." - f"{int(shutters)}." - f"{int(swr)}." - f"{garage}." - f"{int(mr)}." - f"null." - f"{int(bim['TerrainRoughness'])}" - ) + bldg_config = f"M.SF." \ + f"{int(stories)}." \ + f"{BIM['RoofShape']}." \ + f"{RWC}." \ + f"{RFT}." \ + f"{RDA}." \ + f"{int(shutters)}." \ + f"{int(SWR)}." \ + f"{garage}." \ + f"{int(MR)}." \ + f"null." \ + f"{int(BIM['TerrainRoughness'])}" else: # Roof system = OSJW # r # A 2015 study found that there were 750,000 metal roof installed in 2015, # out of 5 million new roofs in the US annually. If these numbers stay - # relatively stable, that implies that roughly 15% of roofs are smlt. + # relatively stable, that implies that roughtly 15% of roofs are smlt. # ref. link: https://www.bdcnetwork.com/blog/metal-roofs-are-soaring- # popularity-residential-marmet roof_cover_options = ['smtl', 'cshl'] @@ -216,54 +219,44 @@ def MSF_config(bim: dict) -> str: # noqa: C901 # high wind attachments are required for DSWII > 142 mph # NJ IBC 1507.4.5 (for smtl) # high wind attachment are required for DSWII > 142 mph - if bim['V_ult'] > 142.0: - rda = 'sup' # superior + if BIM['V_ult'] > 142.0: + RDA = 'sup' # superior else: - rda = 'std' # standard + RDA = 'std' # standard # Secondary Water Resistance (SWR) # Minimum drainage recommendations are in place in NJ (See below). # However, SWR indicates a code-plus practice. + SWR = 'null' # Default + if BIM['RoofShape'] == 'flt': + SWR = int(True) + elif ((BIM['RoofShape'] in ['hip', 'gab']) and + (roof_cover=='cshl') and (RDA=='sup')): + SWR = int(random.random() < 0.6) - # Default - swr = 'null' # type: ignore[no-redef] - - if bim['RoofShape'] == 'flt': - swr = int(True) # type: ignore[assignment] - elif ( - (bim['RoofShape'] in {'hip', 'gab'}) - and (roof_cover == 'cshl') - and (rda == 'sup') - ): - swr = int(random.random() < 0.6) - - stories = min(bim['NumberOfStories'], 2) + stories = min(BIM['NumberOfStories'], 2) # extend the BIM dictionary - bim.update( - { - 'SecondaryWaterResistance': swr, - 'RoofDeckAttachmentW': rda, - 'RoofToWallConnection': rwc, - 'Shutters': shutters, - 'AugmentGarage': garage, # type: ignore[used-before-def] - 'MasonryReinforcing': mr, # type: ignore[used-before-def] - } - ) + BIM.update(dict( + SecondaryWaterResistance = SWR, + RoofDeckAttachmentW = RDA, + RoofToWallConnection = RWC, + Shutters = shutters, + AugmentGarage = garage, + MasonryReinforcing = MR, + )) - bldg_config = ( - f"M.SF." - f"{int(stories)}." - f"{bim['RoofShape']}." - f"{rwc}." - f"{rft}." - f"{rda}." - f"{int(shutters)}." - f"{swr}." - f"null." - f"null." - f"{roof_cover}." - f"{int(bim['TerrainRoughness'])}" - ) + bldg_config = f"M.SF." \ + f"{int(stories)}." \ + f"{BIM['RoofShape']}." \ + f"{RWC}." \ + f"{RFT}." \ + f"{RDA}." \ + f"{int(shutters)}." \ + f"{SWR}." \ + f"null." \ + f"null." \ + f"{roof_cover}." \ + f"{int(BIM['TerrainRoughness'])}" return bldg_config diff --git a/pelicun/tests/dl_calculation/rulesets/WindMetaVarRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindMetaVarRulesets.py index af608140c..baf5108d8 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindMetaVarRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindMetaVarRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,13 +43,13 @@ # Meredith Lockhead # Tracy Kijewski-Correa -from __future__ import annotations - +import random import numpy as np import pandas as pd +import datetime +import math - -def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: C901, PLR0912 +def parse_BIM(BIM_in, location, hazards): """ Parses the information provided in the AIM model. @@ -82,66 +83,77 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: ------- BIM_ap: dictionary Parsed building characteristics. - """ + # check location - if location not in {'LA', 'NJ'}: - print(f'WARNING: The provided location is not recognized: {location}') # noqa: T201 + if location not in ['LA', 'NJ']: + print(f'WARNING: The provided location is not recognized: {location}') # check hazard for hazard in hazards: - if hazard not in {'wind', 'inundation'}: - print(f'WARNING: The provided hazard is not recognized: {hazard}') # noqa: T201 + if hazard not in ['wind', 'inundation']: + print(f'WARNING: The provided hazard is not recognized: {hazard}') # initialize the BIM dict - bim_ap = bim_in.copy() + BIM_ap = BIM_in.copy() if 'wind' in hazards: + # maps roof type to the internal representation - ap_roof_type = { - 'hip': 'hip', + ap_RoofType = { + 'hip' : 'hip', 'hipped': 'hip', - 'Hip': 'hip', + 'Hip' : 'hip', 'gabled': 'gab', - 'gable': 'gab', - 'Gable': 'gab', - 'flat': 'flt', - 'Flat': 'flt', + 'gable' : 'gab', + 'Gable' : 'gab', + 'flat' : 'flt', + 'Flat' : 'flt' } # maps roof system to the internal representation - ap_roof_syste = {'Wood': 'trs', 'OWSJ': 'ows', 'N/A': 'trs'} - roof_system = bim_in.get('RoofSystem', 'Wood') + ap_RoofSyste = { + 'Wood': 'trs', + 'OWSJ': 'ows', + 'N/A': 'trs' + } + roof_system = BIM_in.get('RoofSystem','Wood') if pd.isna(roof_system): roof_system = 'Wood' - # flake8 - unused variable: `ap_NoUnits`. - # # maps number of units to the internal representation - # ap_NoUnits = { - # 'Single': 'sgl', - # 'Multiple': 'mlt', - # 'Multi': 'mlt', - # 'nav': 'nav', - # } - - # maps for design level (Marginal Engineered is mapped to - # Engineered as default) - ap_design_level = {'E': 'E', 'NE': 'NE', 'PE': 'PE', 'ME': 'E'} - design_level = bim_in.get('DesignLevel', 'E') + # maps number of units to the internal representation + ap_NoUnits = { + 'Single': 'sgl', + 'Multiple': 'mlt', + 'Multi': 'mlt', + 'nav': 'nav' + } + + # maps for design level (Marginal Engineered is mapped to Engineered as default) + ap_DesignLevel = { + 'E': 'E', + 'NE': 'NE', + 'PE': 'PE', + 'ME': 'E' + } + design_level = BIM_in.get('DesignLevel','E') if pd.isna(design_level): design_level = 'E' # Average January Temp. - ap_ajt = {'Above': 'above', 'Below': 'below'} + ap_ajt = { + 'Above': 'above', + 'Below': 'below' + } # Year built alname_yearbuilt = ['YearBuiltNJDEP', 'yearBuilt', 'YearBuiltMODIV'] yearbuilt = None try: - yearbuilt = bim_in['YearBuilt'] - except KeyError: + yearbuilt = BIM_in['YearBuilt'] + except: for i in alname_yearbuilt: - if i in bim_in: - yearbuilt = bim_in[i] + if i in BIM_in.keys(): + yearbuilt = BIM_in[i] break # if none of the above works, set a default @@ -149,19 +161,14 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: yearbuilt = 1985 # Number of Stories - alname_nstories = [ - 'stories', - 'NumberofStories0', - 'NumberofStories', - 'NumberofStories1', - ] + alname_nstories = ['stories', 'NumberofStories0', 'NumberofStories', 'NumberofStories1'] nstories = None try: - nstories = bim_in['NumberOfStories'] - except KeyError as e: + nstories = BIM_in['NumberOfStories'] + except Exception as e: for i in alname_nstories: - if i in bim_in: - nstories = bim_in[i] + if i in BIM_in.keys(): + nstories = BIM_in[i] break # if none of the above works, we need to raise an exception @@ -172,11 +179,11 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: alname_area = ['area', 'PlanArea1', 'Area', 'PlanArea0'] area = None try: - area = bim_in['PlanArea'] - except KeyError as e: + area = BIM_in['PlanArea'] + except Exception as e: for i in alname_area: - if i in bim_in: - area = bim_in[i] + if i in BIM_in.keys(): + area = BIM_in[i] break # if none of the above works, we need to raise an exception @@ -186,21 +193,22 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: # Design Wind Speed alname_dws = ['DSWII', 'DWSII', 'DesignWindSpeed'] - dws = bim_in.get('DesignWindSpeed') + dws = BIM_in.get('DesignWindSpeed', None) if dws is None: for alname in alname_dws: - if alname in bim_in: - dws = bim_in[alname] + if alname in BIM_in.keys(): + dws = BIM_in[alname] break + alname_occupancy = ['occupancy'] oc = None try: - oc = bim_in['OccupancyClass'] - except KeyError as e: + oc = BIM_in['OccupancyClass'] + except Exception as e: for i in alname_occupancy: - if i in bim_in: - oc = bim_in[i] + if i in BIM_in.keys(): + oc = BIM_in[i] break # if none of the above works, we need to raise an exception @@ -212,7 +220,7 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: oc = 'RES3A' # maps for flood zone - ap_flood_zone = { + ap_FloodZone = { # Coastal areas with a 1% or greater chance of flooding and an # additional hazard associated with storm waves. 6101: 'VE', @@ -230,17 +238,17 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: 6113: 'OW', 6114: 'D', 6115: 'NA', - 6119: 'NA', + 6119: 'NA' } - if isinstance(bim_in['FloodZone'], int): + if type(BIM_in['FloodZone']) == int: # NJDEP code for flood zone (conversion to the FEMA designations) - floodzone_fema = ap_flood_zone[bim_in['FloodZone']] + floodzone_fema = ap_FloodZone[BIM_in['FloodZone']] else: # standard input should follow the FEMA flood zone designations - floodzone_fema = bim_in['FloodZone'] + floodzone_fema = BIM_in['FloodZone'] # maps for BuildingType - ap_building_type_nj = { + ap_BuildingType_NJ = { # Coastal areas with a 1% or greater chance of flooding and an # additional hazard associated with storm waves. 3001: 'Wood', @@ -251,62 +259,55 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: } if location == 'NJ': # NJDEP code for flood zone needs to be converted - buildingtype = ap_building_type_nj[bim_in['BuildingType']] + buildingtype = ap_BuildingType_NJ[BIM_in['BuildingType']] elif location == 'LA': # standard input should provide the building type as a string - buildingtype = bim_in['BuildingType'] + buildingtype = BIM_in['BuildingType'] # first, pull in the provided data - bim_ap.update( - { - 'OccupancyClass': str(oc), - 'BuildingType': buildingtype, - 'YearBuilt': int(yearbuilt), - # double check with Tracy for format - (NumberStories0 - # is 4-digit code) - # (NumberStories1 is image-processed story number) - 'NumberOfStories': int(nstories), - 'PlanArea': float(area), - 'FloodZone': floodzone_fema, - 'V_ult': float(dws), - 'AvgJanTemp': ap_ajt[bim_in.get('AvgJanTemp', 'Below')], - 'RoofShape': ap_roof_type[bim_in['RoofShape']], - 'RoofSlope': float(bim_in.get('RoofSlope', 0.25)), # default 0.25 - 'SheathingThickness': float( - bim_in.get('SheathingThick', 1.0) - ), # default 1.0 - 'RoofSystem': str( - ap_roof_syste[roof_system] - ), # only valid for masonry structures - 'Garage': float(bim_in.get('Garage', -1.0)), - 'LULC': bim_in.get('LULC', -1), - 'z0': float( - bim_in.get('z0', -1) - ), # if the z0 is already in the input file - 'Terrain': bim_in.get('Terrain', -1), - 'MeanRoofHt': float(bim_in.get('MeanRoofHt', 15.0)), # default 15 - 'DesignLevel': str( - ap_design_level[design_level] - ), # default engineered - 'WindowArea': float(bim_in.get('WindowArea', 0.20)), - 'WoodZone': str(bim_in.get('WindZone', 'I')), - } - ) + BIM_ap.update(dict( + OccupancyClass=str(oc), + BuildingType=buildingtype, + YearBuilt=int(yearbuilt), + # double check with Tracy for format - (NumberStories0 is 4-digit code) + # (NumberStories1 is image-processed story number) + NumberOfStories=int(nstories), + PlanArea=float(area), + FloodZone=floodzone_fema, + V_ult=float(dws), + AvgJanTemp=ap_ajt[BIM_in.get('AvgJanTemp','Below')], + RoofShape=ap_RoofType[BIM_in['RoofShape']], + RoofSlope=float(BIM_in.get('RoofSlope',0.25)), # default 0.25 + SheathingThickness=float(BIM_in.get('SheathingThick',1.0)), # default 1.0 + RoofSystem=str(ap_RoofSyste[roof_system]), # only valid for masonry structures + Garage=float(BIM_in.get('Garage',-1.0)), + LULC=BIM_in.get('LULC',-1), + z0 = float(BIM_in.get('z0',-1)), # if the z0 is already in the input file + Terrain = BIM_in.get('Terrain',-1), + MeanRoofHt=float(BIM_in.get('MeanRoofHt',15.0)), # default 15 + DesignLevel=str(ap_DesignLevel[design_level]), # default engineered + WindowArea=float(BIM_in.get('WindowArea',0.20)), + WoodZone=str(BIM_in.get('WindZone', 'I')) + )) if 'inundation' in hazards: + # maps for split level - ap_split_level = {'NO': 0, 'YES': 1} + ap_SplitLevel = { + 'NO': 0, + 'YES': 1 + } - foundation = bim_in.get('FoundationType', 3501) + foundation = BIM_in.get('FoundationType',3501) if pd.isna(foundation): foundation = 3501 - nunits = bim_in.get('NoUnits', 1) + nunits = BIM_in.get('NoUnits',1) if pd.isna(nunits): nunits = 1 # maps for flood zone - ap_flood_zone = { + ap_FloodZone = { # Coastal areas with a 1% or greater chance of flooding and an # additional hazard associated with storm waves. 6101: 'VE', @@ -324,45 +325,40 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: 6113: 'OW', 6114: 'D', 6115: 'NA', - 6119: 'NA', + 6119: 'NA' } - if isinstance(bim_in['FloodZone'], int): + if type(BIM_in['FloodZone']) == int: # NJDEP code for flood zone (conversion to the FEMA designations) - floodzone_fema = ap_flood_zone[bim_in['FloodZone']] + floodzone_fema = ap_FloodZone[BIM_in['FloodZone']] else: # standard input should follow the FEMA flood zone designations - floodzone_fema = bim_in['FloodZone'] + floodzone_fema = BIM_in['FloodZone'] # add the parsed data to the BIM dict - bim_ap.update( - { - 'DesignLevel': str( - ap_design_level[design_level] - ), # default engineered - 'NumberOfUnits': int(nunits), - 'FirstFloorElevation': float(bim_in.get('FirstFloorHt1', 10.0)), - 'SplitLevel': bool( - ap_split_level[bim_in.get('SplitLevel', 'NO')] - ), # dfault: no - 'FoundationType': int(foundation), # default: pile - 'City': bim_in.get('City', 'NA'), - 'FloodZone': str(floodzone_fema), - } - ) + BIM_ap.update(dict( + DesignLevel=str(ap_DesignLevel[design_level]), # default engineered + NumberOfUnits=int(nunits), + FirstFloorElevation=float(BIM_in.get('FirstFloorHt1',10.0)), + SplitLevel=bool(ap_SplitLevel[BIM_in.get('SplitLevel','NO')]), # dfault: no + FoundationType=int(foundation), # default: pile + City=BIM_in.get('City','NA'), + FloodZone =str(floodzone_fema) + )) # add inferred, generic meta-variables if 'wind' in hazards: + # Hurricane-Prone Region (HRP) # Areas vulnerable to hurricane, defined as the U.S. Atlantic Ocean and # Gulf of Mexico coasts where the ultimate design wind speed, V_ult is # greater than a pre-defined limit. - if bim_ap['YearBuilt'] >= 2016: + if BIM_ap['YearBuilt'] >= 2016: # The limit is 115 mph in IRC 2015 - hpr = bim_ap['V_ult'] > 115.0 + HPR = BIM_ap['V_ult'] > 115.0 else: # The limit is 90 mph in IRC 2009 and earlier versions - hpr = bim_ap['V_ult'] > 90.0 + HPR = BIM_ap['V_ult'] > 90.0 # Wind Borne Debris # Areas within hurricane-prone regions are affected by debris if one of @@ -372,30 +368,25 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: # (2) In areas where the ultimate design wind speed is greater than # general_lim # The flood_lim and general_lim limits depend on the year of construction - if bim_ap['YearBuilt'] >= 2016: + if BIM_ap['YearBuilt'] >= 2016: # In IRC 2015: - flood_lim = 130.0 # mph - general_lim = 140.0 # mph + flood_lim = 130.0 # mph + general_lim = 140.0 # mph else: # In IRC 2009 and earlier versions - flood_lim = 110.0 # mph - general_lim = 120.0 # mph + flood_lim = 110.0 # mph + general_lim = 120.0 # mph # Areas within hurricane-prone regions located in accordance with # one of the following: # (1) Within 1 mile (1.61 km) of the coastal mean high water line # where the ultimate design wind speed is 130 mph (58m/s) or greater. # (2) In areas where the ultimate design wind speed is 140 mph (63.5m/s) # or greater. (Definitions: Chapter 2, 2015 NJ Residential Code) - if not hpr: - wbd = False + if not HPR: + WBD = False else: - wbd = ( - ( - bim_ap['FloodZone'].startswith('A') - or bim_ap['FloodZone'].startswith('V') - ) - and bim_ap['V_ult'] >= flood_lim - ) or (bim_ap['V_ult'] >= general_lim) + WBD = (((BIM_ap['FloodZone'].startswith('A') or BIM_ap['FloodZone'].startswith('V')) and + BIM_ap['V_ult'] >= flood_lim) or (BIM_ap['V_ult'] >= general_lim)) # Terrain # open (0.03) = 3 @@ -406,87 +397,69 @@ def parse_BIM(bim_in: dict, location: str, hazards: list[str]) -> dict: # noqa: # Mapped to Land Use Categories in NJ (see https://www.state.nj.us/dep/gis/ # digidownload/metadata/lulc02/anderson2002.html) by T. Wu group # (see internal report on roughness calculations, Table 4). - # These are mapped to Hazus definitions as follows: - # Open Water (5400s) with zo=0.01 and barren land (7600) with - # zo=0.04 assume Open Open Space Developed, Low Intensity - # Developed, Medium Intensity Developed (1110-1140) assumed - # zo=0.35-0.4 assume Suburban High Intensity Developed (1600) - # with zo=0.6 assume Lt. Tree Forests of all classes - # (4100-4300) assumed zo=0.6 assume Lt. Tree Shrub (4400) with - # zo=0.06 assume Open Grasslands, pastures and agricultural - # areas (2000 series) with zo=0.1-0.15 assume Lt. Suburban - # Woody Wetlands (6250) with zo=0.3 assume suburban Emergent - # Herbaceous Wetlands (6240) with zo=0.03 assume Open + # These are mapped to Hazus defintions as follows: + # Open Water (5400s) with zo=0.01 and barren land (7600) with zo=0.04 assume Open + # Open Space Developed, Low Intensity Developed, Medium Intensity Developed + # (1110-1140) assumed zo=0.35-0.4 assume Suburban + # High Intensity Developed (1600) with zo=0.6 assume Lt. Tree + # Forests of all classes (4100-4300) assumed zo=0.6 assume Lt. Tree + # Shrub (4400) with zo=0.06 assume Open + # Grasslands, pastures and agricultural areas (2000 series) with + # zo=0.1-0.15 assume Lt. Suburban + # Woody Wetlands (6250) with zo=0.3 assume suburban + # Emergent Herbaceous Wetlands (6240) with zo=0.03 assume Open # Note: HAZUS category of trees (1.00) does not apply to any LU/LC in NJ - terrain = 15 # Default in Reorganized Rulesets - WIND - lulc = bim_ap['LULC'] - terrain = bim_ap['Terrain'] - if bim_ap['z0'] > 0: - terrain = int(100 * bim_ap['z0']) - elif lulc > 0: - if bim_ap['FloodZone'].startswith('V') or bim_ap['FloodZone'] in { - 'A', - 'AE', - 'A1-30', - 'AR', - 'A99', - }: + terrain = 15 # Default in Reorganized Rulesets - WIND + LULC = BIM_ap['LULC'] + TER = BIM_ap['Terrain'] + if (BIM_ap['z0'] > 0): + terrain = int(100 * BIM_ap['z0']) + elif (LULC > 0): + if (BIM_ap['FloodZone'].startswith('V') or BIM_ap['FloodZone'] in ['A', 'AE', 'A1-30', 'AR', 'A99']): terrain = 3 - elif ((lulc >= 5000) and (lulc <= 5999)) or ( - (lulc in {4400, 6240}) or (lulc == 7600) - ): - terrain = 3 # Open - elif (lulc >= 2000) and (lulc <= 2999): - terrain = 15 # Light suburban - elif ((lulc >= 1110) and (lulc <= 1140)) or ( - (lulc >= 6250) and (lulc <= 6252) - ): - terrain = 35 # Suburban - elif ((lulc >= 4100) and (lulc <= 4300)) or (lulc == 1600): - terrain = 70 # light trees - elif terrain > 0: - if bim_ap['FloodZone'].startswith('V') or bim_ap['FloodZone'] in { - 'A', - 'AE', - 'A1-30', - 'AR', - 'A99', - }: + elif ((LULC >= 5000) and (LULC <= 5999)): + terrain = 3 # Open + elif ((LULC == 4400) or (LULC == 6240)) or (LULC == 7600): + terrain = 3 # Open + elif ((LULC >= 2000) and (LULC <= 2999)): + terrain = 15 # Light suburban + elif ((LULC >= 1110) and (LULC <= 1140)) or ((LULC >= 6250) and (LULC <= 6252)): + terrain = 35 # Suburban + elif ((LULC >= 4100) and (LULC <= 4300)) or (LULC == 1600): + terrain = 70 # light trees + elif (TER > 0): + if (BIM_ap['FloodZone'].startswith('V') or BIM_ap['FloodZone'] in ['A', 'AE', 'A1-30', 'AR', 'A99']): terrain = 3 - elif ((terrain >= 50) and (terrain <= 59)) or ( - (terrain in {44, 62}) or (terrain == 76) - ): - terrain = 3 # Open - elif (terrain >= 20) and (terrain <= 29): - terrain = 15 # Light suburban - elif terrain in {11, 61}: - terrain = 35 # Suburban - elif ((terrain >= 41) and (terrain <= 43)) or (terrain in {16, 17}): - terrain = 70 # light trees - - bim_ap.update( - { - # Nominal Design Wind Speed - # Former term was “Basic Wind Speed”; it is now the “Nominal Design - # Wind Speed (V_asd). Unit: mph." - 'V_asd': np.sqrt(0.6 * bim_ap['V_ult']), - 'HazardProneRegion': hpr, - 'WindBorneDebris': wbd, - 'TerrainRoughness': terrain, - } - ) + elif ((TER >= 50) and (TER <= 59)): + terrain = 3 # Open + elif ((TER == 44) or (TER == 62)) or (TER == 76): + terrain = 3 # Open + elif ((TER >= 20) and (TER <= 29)): + terrain = 15 # Light suburban + elif (TER == 11) or (TER == 61): + terrain = 35 # Suburban + elif ((TER >= 41) and (TER <= 43)) or (TER in [16, 17]): + terrain = 70 # light trees + + BIM_ap.update(dict( + # Nominal Design Wind Speed + # Former term was “Basic Wind Speed”; it is now the “Nominal Design + # Wind Speed (V_asd). Unit: mph." + V_asd = np.sqrt(0.6 * BIM_ap['V_ult']), + + HazardProneRegion=HPR, + WindBorneDebris=WBD, + TerrainRoughness=terrain, + )) if 'inundation' in hazards: - bim_ap.update( - { - # Flood Risk - # Properties in the High Water Zone (within 1 mile of - # the coast) are at risk of flooding and other - # wind-borne debris action. - # TODO: need high water zone for this and move it to # noqa: TD002 - # inputs! - 'FloodRisk': True, - } - ) - - return bim_ap + + BIM_ap.update(dict( + # Flood Risk + # Properties in the High Water Zone (within 1 mile of the coast) are at + # risk of flooding and other wind-borne debris action. + FloodRisk=True, # TODO: need high water zone for this and move it to inputs! + )) + + return BIM_ap + diff --git a/pelicun/tests/dl_calculation/rulesets/WindSECBRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindSECBRulesets.py index b95effa50..d07f63fdf 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindSECBRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindSECBRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -44,10 +45,9 @@ import random - -def SECB_config(bim: dict) -> str: # noqa: C901 +def SECB_config(BIM): """ - Rules to identify a HAZUS SECB configuration based on BIM data. + Rules to identify a HAZUS SECB configuration based on BIM data Parameters ---------- @@ -57,25 +57,26 @@ def SECB_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this building + A string that identifies a specific configration within this buidling class. - """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof cover - if bim['RoofShape'] in {'gab', 'hip'}: + if BIM['RoofShape'] in ['gab', 'hip']: roof_cover = 'bur' # Warning: HAZUS does not have N/A option for CECB, so here we use bur - elif year >= 1975: - roof_cover = 'spm' else: - # year < 1975 - roof_cover = 'bur' + if year >= 1975: + roof_cover = 'spm' + else: + # year < 1975 + roof_cover = 'bur' # shutters if year >= 2000: - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # BOCA 1996 and earlier: # Shutters were not required by code until the 2000 IBC. Before 2000, the # percentage of commercial buildings that have shutters is assumed to be @@ -85,65 +86,66 @@ def SECB_config(bim: dict) -> str: # noqa: C901 # facilities. In addition to that, 46% of business owners reported boarding # up their businesses before Hurricane Katrina. In addition, compliance # rates based on the Homeowners Survey data hover between 43 and 50 percent. - elif bim['WindBorneDebris']: - shutters = random.random() < 0.46 else: - shutters = False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.46 + else: + shutters = False # Wind Debris (widd in HAZSU) # HAZUS A: Res/Comm, B: Varies by direction, C: Residential, D: None - widd = 'C' # residential (default) - if bim['OccupancyClass'] in {'RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', 'RES3D'}: - widd = 'C' # residential - elif bim['OccupancyClass'] == 'AGR1': - widd = 'D' # None + WIDD = 'C' # residential (default) + if BIM['OccupancyClass'] in ['RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', + 'RES3D']: + WIDD = 'C' # residential + elif BIM['OccupancyClass'] == 'AGR1': + WIDD = 'D' # None else: - widd = 'A' # Res/Comm + WIDD = 'A' # Res/Comm # Window area ratio - if bim['WindowArea'] < 0.33: - wwr = 'low' - elif bim['WindowArea'] < 0.5: - wwr = 'med' + if BIM['WindowArea'] < 0.33: + WWR = 'low' + elif BIM['WindowArea'] < 0.5: + WWR = 'med' else: - wwr = 'hig' + WWR = 'hig' # Metal RDA # 1507.2.8.1 High Wind Attachment. # Underlayment applied in areas subject to high winds (Vasd greater # than 110 mph as determined in accordance with Section 1609.3.1) shall # be applied with corrosion-resistant fasteners in accordance with - # the manufacturer's instructions. Fasteners are to be applied along + # the manufacturer’s instructions. Fasteners are to be applied along # the overlap not more than 36 inches on center. - if bim['V_ult'] > 142: - mrda = 'std' # standard + if BIM['V_ult'] > 142: + MRDA = 'std' # standard else: - mrda = 'sup' # superior + MRDA = 'sup' # superior - if bim['NumberOfStories'] <= 2: + if BIM['NumberOfStories'] <= 2: bldg_tag = 'S.ECB.L' - elif bim['NumberOfStories'] <= 5: + elif BIM['NumberOfStories'] <= 5: bldg_tag = 'S.ECB.M' else: bldg_tag = 'S.ECB.H' # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'WindowAreaRatio': wwr, - 'RoofDeckAttachmentM': mrda, - 'Shutters': shutters, - 'WindDebrisClass': widd, - } - ) + BIM.update(dict( + RoofCover = roof_cover, + WindowAreaRatio = WWR, + RoofDeckAttachmentM = MRDA, + Shutters = shutters, + WindDebrisClass=WIDD + )) + + bldg_config = f"{bldg_tag}." \ + f"{roof_cover}." \ + f"{int(shutters)}." \ + f"{WIDD}." \ + f"{MRDA}." \ + f"{WWR}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config - return ( - f"{bldg_tag}." - f"{roof_cover}." - f"{int(shutters)}." - f"{widd}." - f"{mrda}." - f"{wwr}." - f"{int(bim['TerrainRoughness'])}" - ) diff --git a/pelicun/tests/dl_calculation/rulesets/WindSERBRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindSERBRulesets.py index 942fd7a7b..d6711b347 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindSERBRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindSERBRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -44,10 +45,9 @@ import random - -def SERB_config(bim: dict) -> str: # noqa: C901 +def SERB_config(BIM): """ - Rules to identify a HAZUS SERB configuration based on BIM data. + Rules to identify a HAZUS SERB configuration based on BIM data Parameters ---------- @@ -57,25 +57,26 @@ def SERB_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this building + A string that identifies a specific configration within this buidling class. - """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof cover - if bim['RoofShape'] in {'gab', 'hip'}: + if BIM['RoofShape'] in ['gab', 'hip']: roof_cover = 'bur' # Warning: HAZUS does not have N/A option for CECB, so here we use bur - elif year >= 1975: - roof_cover = 'spm' else: - # year < 1975 - roof_cover = 'bur' + if year >= 1975: + roof_cover = 'spm' + else: + # year < 1975 + roof_cover = 'bur' # shutters if year >= 2000: - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # BOCA 1996 and earlier: # Shutters were not required by code until the 2000 IBC. Before 2000, the # percentage of commercial buildings that have shutters is assumed to be @@ -85,65 +86,65 @@ def SERB_config(bim: dict) -> str: # noqa: C901 # facilities. In addition to that, 46% of business owners reported boarding # up their businesses before Hurricane Katrina. In addition, compliance # rates based on the Homeowners Survey data hover between 43 and 50 percent. - elif bim['WindBorneDebris']: - shutters = random.random() < 0.46 else: - shutters = False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.46 + else: + shutters = False # Wind Debris (widd in HAZSU) # HAZUS A: Res/Comm, B: Varies by direction, C: Residential, D: None - widd = 'C' # residential (default) - if bim['OccupancyClass'] in {'RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', 'RES3D'}: - widd = 'C' # residential - elif bim['OccupancyClass'] == 'AGR1': - widd = 'D' # None + WIDD = 'C' # residential (default) + if BIM['OccupancyClass'] in ['RES1', 'RES2', 'RES3A', 'RES3B', 'RES3C', + 'RES3D']: + WIDD = 'C' # residential + elif BIM['OccupancyClass'] == 'AGR1': + WIDD = 'D' # None else: - widd = 'A' # Res/Comm + WIDD = 'A' # Res/Comm # Window area ratio - if bim['WindowArea'] < 0.33: - wwr = 'low' - elif bim['WindowArea'] < 0.5: - wwr = 'med' + if BIM['WindowArea'] < 0.33: + WWR = 'low' + elif BIM['WindowArea'] < 0.5: + WWR = 'med' else: - wwr = 'hig' + WWR = 'hig' # Metal RDA # 1507.2.8.1 High Wind Attachment. # Underlayment applied in areas subject to high winds (Vasd greater # than 110 mph as determined in accordance with Section 1609.3.1) shall # be applied with corrosion-resistant fasteners in accordance with - # the manufacturer's instructions. Fasteners are to be applied along + # the manufacturer’s instructions. Fasteners are to be applied along # the overlap not more than 36 inches on center. - if bim['V_ult'] > 142: - mrda = 'std' # standard + if BIM['V_ult'] > 142: + MRDA = 'std' # standard else: - mrda = 'sup' # superior + MRDA = 'sup' # superior - if bim['NumberOfStories'] <= 2: + if BIM['NumberOfStories'] <= 2: bldg_tag = 'S.ERB.L' - elif bim['NumberOfStories'] <= 5: + elif BIM['NumberOfStories'] <= 5: bldg_tag = 'S.ERB.M' else: bldg_tag = 'S.ERB.H' # extend the BIM dictionary - bim.update( - { - 'RoofCover': roof_cover, - 'WindowAreaRatio': wwr, - 'RoofDeckAttachmentM': mrda, - 'Shutters': shutters, - 'WindDebrisClass': widd, - } - ) + BIM.update(dict( + RoofCover = roof_cover, + WindowAreaRatio = WWR, + RoofDeckAttachmentM = MRDA, + Shutters = shutters, + WindDebrisClass=WIDD + )) + + bldg_config = f"{bldg_tag}." \ + f"{roof_cover}." \ + f"{int(shutters)}." \ + f"{WIDD}." \ + f"{MRDA}." \ + f"{WWR}." \ + f"{int(BIM['TerrainRoughness'])}" - return ( - f"{bldg_tag}." - f"{roof_cover}." - f"{int(shutters)}." - f"{widd}." - f"{mrda}." - f"{wwr}." - f"{int(bim['TerrainRoughness'])}" - ) + return bldg_config diff --git a/pelicun/tests/dl_calculation/rulesets/WindSPMBRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindSPMBRulesets.py index 16c653833..42f8a6407 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindSPMBRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindSPMBRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,13 +43,14 @@ # Meredith Lockhead # Tracy Kijewski-Correa -import datetime import random +import numpy as np +import datetime -def SPMB_config(bim: dict) -> str: +def SPMB_config(BIM): """ - Rules to identify a HAZUS SPMB configuration based on BIM data. + Rules to identify a HAZUS SPMB configuration based on BIM data Parameters ---------- @@ -58,23 +60,21 @@ def SPMB_config(bim: dict) -> str: Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Roof Deck Age (~ Roof Quality) - if bim['YearBuilt'] >= ( - datetime.datetime.now(tz=datetime.timezone.utc).year - 50 - ): + if BIM['YearBuilt'] >= (datetime.datetime.now().year - 50): roof_quality = 'god' else: roof_quality = 'por' # shutters if year >= 2000: - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # BOCA 1996 and earlier: # Shutters were not required by code until the 2000 IBC. Before 2000, the # percentage of commercial buildings that have shutters is assumed to be @@ -84,43 +84,43 @@ def SPMB_config(bim: dict) -> str: # facilities. In addition to that, 46% of business owners reported boarding # up their businesses before Hurricane Katrina. In addition, compliance # rates based on the Homeowners Survey data hover between 43 and 50 percent. - elif bim['WindBorneDebris']: - shutters = random.random() < 0.46 else: - shutters = False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.46 + else: + shutters = False # Metal RDA # 1507.2.8.1 High Wind Attachment. # Underlayment applied in areas subject to high winds (Vasd greater # than 110 mph as determined in accordance with Section 1609.3.1) shall # be applied with corrosion-resistant fasteners in accordance with - # the manufacturer's instructions. Fasteners are to be applied along + # the manufacturer’s instructions. Fasteners are to be applied along # the overlap not more than 36 inches on center. - if bim['V_ult'] > 142: - mrda = 'std' # standard + if BIM['V_ult'] > 142: + MRDA = 'std' # standard else: - mrda = 'sup' # superior + MRDA = 'sup' # superior - if bim['PlanArea'] <= 4000: + if BIM['PlanArea'] <= 4000: bldg_tag = 'S.PMB.S' - elif bim['PlanArea'] <= 50000: + elif BIM['PlanArea'] <= 50000: bldg_tag = 'S.PMB.M' else: bldg_tag = 'S.PMB.L' # extend the BIM dictionary - bim.update( - { - 'RoofQuality': roof_quality, - 'RoofDeckAttachmentM': mrda, - 'Shutters': shutters, - } - ) + BIM.update(dict( + RoofQuality = roof_quality, + RoofDeckAttachmentM = MRDA, + Shutters = shutters + )) + + bldg_config = f"{bldg_tag}." \ + f"{int(shutters)}." \ + f"{roof_quality}." \ + f"{MRDA}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config - return ( - f"{bldg_tag}." - f"{int(shutters)}." - f"{roof_quality}." - f"{mrda}." - f"{int(bim['TerrainRoughness'])}" - ) diff --git a/pelicun/tests/dl_calculation/rulesets/WindWMUHRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindWMUHRulesets.py index 9de71dc26..6d5fe338d 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindWMUHRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindWMUHRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,13 +43,12 @@ # Meredith Lockhead # Tracy Kijewski-Correa -import datetime import random +import datetime - -def WMUH_config(bim: dict) -> str: # noqa: C901 +def WMUH_config(BIM): """ - Rules to identify a HAZUS WMUH configuration based on BIM data. + Rules to identify a HAZUS WMUH configuration based on BIM data Parameters ---------- @@ -58,35 +58,37 @@ def WMUH_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Secondary Water Resistance (SWR) - swr: str | int = 0 # Default + SWR = 0 # Default if year > 2000: - if bim['RoofShape'] == 'flt': - swr = 'null' # because SWR is not a question for flat roofs - elif bim['RoofShape'] in {'gab', 'hip'}: - swr = int(random.random() < 0.6) + if BIM['RoofShape'] == 'flt': + SWR = 'null' # because SWR is not a question for flat roofs + elif BIM['RoofShape'] in ['gab','hip']: + SWR = int(random.random() < 0.6) elif year > 1987: - if bim['RoofShape'] == 'flt': - swr = 'null' # because SWR is not a question for flat roofs - elif (bim['RoofShape'] == 'gab') or (bim['RoofShape'] == 'hip'): - if bim['RoofSlope'] < 0.33: - swr = int(True) + if BIM['RoofShape'] == 'flt': + SWR = 'null' # because SWR is not a question for flat roofs + elif (BIM['RoofShape'] == 'gab') or (BIM['RoofShape'] == 'hip'): + if BIM['RoofSlope'] < 0.33: + SWR = int(True) else: - swr = int(bim['AvgJanTemp'] == 'below') - elif bim['RoofShape'] == 'flt': - swr = 'null' # because SWR is not a question for flat roofs + SWR = int(BIM['AvgJanTemp'] == 'below') else: - swr = int(random.random() < 0.3) + # year <= 1987 + if BIM['RoofShape'] == 'flt': + SWR = 'null' # because SWR is not a question for flat roofs + else: + SWR = int(random.random() < 0.3) # Roof cover & Roof quality # Roof cover and quality do not apply to gable and hip roofs - if bim['RoofShape'] in {'gab', 'hip'}: + if BIM['RoofShape'] in ['gab', 'hip']: roof_cover = 'null' roof_quality = 'null' # NJ Building Code Section 1507 (in particular 1507.10 and 1507.12) address @@ -102,29 +104,26 @@ def WMUH_config(bim: dict) -> str: # noqa: C901 # We assume that all flat roofs built before 1975 are BURs and all roofs # built after 1975 are SPMs. # Nothing in NJ Building Code or in the Hazus manual specifies what - # constitutes “good” and “poor” roof conditions, so ruleset is dependent + # constitutes “good” and “poor” roof conditions, so ruleset is dependant # on the age of the roof and average lifespan of BUR and SPM roofs. # We assume that the average lifespan of a BUR roof is 30 years and the # average lifespan of a SPM is 35 years. Therefore, BURs installed before # 1990 are in poor condition, and SPMs installed before 1985 are in poor # condition. - elif year >= 1975: - roof_cover = 'spm' - if bim['YearBuilt'] >= ( - datetime.datetime.now(tz=datetime.timezone.utc).year - 35 - ): - roof_quality = 'god' - else: - roof_quality = 'por' else: - # year < 1975 - roof_cover = 'bur' - if bim['YearBuilt'] >= ( - datetime.datetime.now(tz=datetime.timezone.utc).year - 30 - ): - roof_quality = 'god' + if year >= 1975: + roof_cover = 'spm' + if BIM['YearBuilt'] >= (datetime.datetime.now().year - 35): + roof_quality = 'god' + else: + roof_quality = 'por' else: - roof_quality = 'por' + # year < 1975 + roof_cover = 'bur' + if BIM['YearBuilt'] >= (datetime.datetime.now().year - 30): + roof_quality = 'god' + else: + roof_quality = 'por' # Roof Deck Attachment (RDA) # IRC 2009-2015: @@ -140,15 +139,16 @@ def WMUH_config(bim: dict) -> str: # noqa: C901 # The base rule was then extended to the exposures closest to suburban and # light suburban, even though these are not considered by the code. if year > 2009: - if bim['TerrainRoughness'] >= 35: # suburban or light trees - if bim['V_ult'] > 168.0: - rda = '8s' # 8d @ 6"/6" 'D' + if BIM['TerrainRoughness'] >= 35: # suburban or light trees + if BIM['V_ult'] > 168.0: + RDA = '8s' # 8d @ 6"/6" 'D' else: - rda = '8d' # 8d @ 6"/12" 'B' - elif bim['V_ult'] > 142.0: - rda = '8s' # 8d @ 6"/6" 'D' - else: - rda = '8d' # 8d @ 6"/12" 'B' + RDA = '8d' # 8d @ 6"/12" 'B' + else: # light suburban or open + if BIM['V_ult'] > 142.0: + RDA = '8s' # 8d @ 6"/6" 'D' + else: + RDA = '8d' # 8d @ 6"/12" 'B' # IRC 2000-2006: # Table 2304.9.1, Line 31 of the 2006 # NJ IBC requires 8d nails (with spacing 6”/12”) for sheathing thicknesses @@ -158,47 +158,49 @@ def WMUH_config(bim: dict) -> str: # noqa: C901 # change of connector at a certain wind speed. # Thus, all RDAs are assumed to be 8d @ 6”/12”. elif year > 2000: - rda = '8d' # 8d @ 6"/12" 'B' + RDA = '8d' # 8d @ 6"/12" 'B' # BOCA 1996: # The BOCA 1996 Building Code Requires 8d nails (with spacing 6”/12”) for # roof sheathing thickness up to 1". See Table 2305.2, Section 4. # Attachment requirements are given based on sheathing thickness, basic # wind speed, and the mean roof height of the building. elif year > 1996: - if (bim['V_ult'] >= 103) and (bim['MeanRoofHt'] >= 25.0): - rda = '8s' # 8d @ 6"/6" 'D' + if (BIM['V_ult'] >= 103 ) and (BIM['MeanRoofHt'] >= 25.0): + RDA = '8s' # 8d @ 6"/6" 'D' else: - rda = '8d' # 8d @ 6"/12" 'B' + RDA = '8d' # 8d @ 6"/12" 'B' # BOCA 1993: # The BOCA 1993 Building Code Requires 8d nails (with spacing 6”/12”) for # sheathing thicknesses of 19/32 inches or greater, and 6d nails (with # spacing 6”/12”) for sheathing thicknesses of ½ inches or less. # See Table 2305.2, Section 4. elif year > 1993: - if bim['SheathingThickness'] <= 0.5: - rda = '6d' # 6d @ 6"/12" 'A' + if BIM['SheathingThickness'] <= 0.5: + RDA = '6d' # 6d @ 6"/12" 'A' else: - rda = '8d' # 8d @ 6"/12" 'B' - elif bim['SheathingThickness'] <= 0.5: - rda = '6d' # 6d @ 6"/12" 'A' + RDA = '8d' # 8d @ 6"/12" 'B' else: - rda = '8d' # 8d @ 6"/12" 'B' + # year <= 1993 + if BIM['SheathingThickness'] <= 0.5: + RDA = '6d' # 6d @ 6"/12" 'A' + else: + RDA = '8d' # 8d @ 6"/12" 'B' # Roof-Wall Connection (RWC) # IRC 2000-2015: # 1507.2.8.1 High Wind Attachment. Underlayment applied in areas subject # to high winds (Vasd greater than 110 mph as determined in accordance # with Section 1609.3.1) shall be applied with corrosion-resistant - # fasteners in accordance with the manufacturer's instructions. Fasteners + # fasteners in accordance with the manufacturer’s instructions. Fasteners # are to be applied along the overlap not more than 36 inches on center. # Underlayment installed where Vasd, in accordance with section 1609.3.1 # equals or exceeds 120 mph shall be attached in a grid pattern of 12 # inches between side laps with a 6-inch spacing at the side laps. if year > 2000: - if bim['V_ult'] > 142.0: - rwc = 'strap' # Strap + if BIM['V_ult'] > 142.0: + RWC = 'strap' # Strap else: - rwc = 'tnail' # Toe-nail + RWC = 'tnail' # Toe-nail # BOCA 1996 and earlier: # There is no mention of straps or enhanced tie-downs of any kind in the # BOCA codes, and there is no description of these adoptions in IBHS @@ -211,7 +213,7 @@ def WMUH_config(bim: dict) -> str: # noqa: C901 # codes, it is assumed that New Jersey did not adopt these standards until # the 2000 IBC. else: - rwc = 'tnail' # Toe-nail + RWC = 'tnail' # Toe-nail # Shutters # IRC 2000-2015: @@ -226,7 +228,7 @@ def WMUH_config(bim: dict) -> str: # noqa: C901 # are classified as a Group R-3 or R-4 occupancy. # Earlier IRC editions provide similar rules. if year >= 2000: - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # BOCA 1996 and earlier: # Shutters were not required by code until the 2000 IBC. Before 2000, the # percentage of commercial buildings that have shutters is assumed to be @@ -236,36 +238,36 @@ def WMUH_config(bim: dict) -> str: # noqa: C901 # facilities. In addition to that, 46% of business owners reported boarding # up their businesses before Hurricane Katrina. In addition, compliance # rates based on the Homeowners Survey data hover between 43 and 50 percent. - elif bim['WindBorneDebris']: - shutters = random.random() < 0.46 else: - shutters = False + if BIM['WindBorneDebris']: + shutters = random.random() < 0.46 + else: + shutters = False # Stories # Buildings with more than 3 stories are mapped to the 3-story configuration - stories = min(bim['NumberOfStories'], 3) + stories = min(BIM['NumberOfStories'], 3) # extend the BIM dictionary - bim.update( - { - 'SecondaryWaterResistance': swr, - 'RoofCover': roof_cover, - 'RoofQuality': roof_quality, - 'RoofDeckAttachmentW': rda, - 'RoofToWallConnection': rwc, - 'Shutters': shutters, - } - ) + BIM.update(dict( + SecondaryWaterResistance = SWR, + RoofCover = roof_cover, + RoofQuality = roof_quality, + RoofDeckAttachmentW = RDA, + RoofToWallConnection = RWC, + Shutters = shutters + )) + + bldg_config = f"W.MUH." \ + f"{int(stories)}." \ + f"{BIM['RoofShape']}." \ + f"{roof_cover}." \ + f"{roof_quality}." \ + f"{SWR}." \ + f"{RDA}." \ + f"{RWC}." \ + f"{int(shutters)}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config - return ( - f"W.MUH." - f"{int(stories)}." - f"{bim['RoofShape']}." - f"{roof_cover}." - f"{roof_quality}." - f"{swr}." - f"{rda}." - f"{rwc}." - f"{int(shutters)}." - f"{int(bim['TerrainRoughness'])}" - ) diff --git a/pelicun/tests/dl_calculation/rulesets/WindWSFRulesets.py b/pelicun/tests/dl_calculation/rulesets/WindWSFRulesets.py index c619e326b..957ecbf9c 100644 --- a/pelicun/tests/dl_calculation/rulesets/WindWSFRulesets.py +++ b/pelicun/tests/dl_calculation/rulesets/WindWSFRulesets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Copyright (c) 2018 Leland Stanford Junior University # Copyright (c) 2018 The Regents of the University of California @@ -42,13 +43,12 @@ # Meredith Lockhead # Tracy Kijewski-Correa -import datetime import random +import datetime - -def WSF_config(bim: dict) -> str: # noqa: C901 +def WSF_config(BIM): """ - Rules to identify a HAZUS WSF configuration based on BIM data. + Rules to identify a HAZUS WSF configuration based on BIM data Parameters ---------- @@ -58,21 +58,21 @@ def WSF_config(bim: dict) -> str: # noqa: C901 Returns ------- config: str - A string that identifies a specific configuration within this - building class. - + A string that identifies a specific configration within this buidling + class. """ - year = bim['YearBuilt'] # just for the sake of brevity + + year = BIM['YearBuilt'] # just for the sake of brevity # Secondary Water Resistance (SWR) # Minimum drainage recommendations are in place in NJ (See below). # However, SWR indicates a code-plus practice. - swr = False # Default in Reorganzied Rulesets - WIND + SWR = False # Default in Reorganzied Rulesets - WIND if year > 2000: # For buildings built after 2000, SWR is based on homeowner compliance # data from NC Coastal Homeowner Survey (2017) to capture potential # human behavior (% of sealed roofs in NC dataset). - swr = random.random() < 0.6 + SWR = random.random() < 0.6 elif year > 1983: # CABO 1995: # According to 903.2 in the 1995 CABO, for roofs with slopes between @@ -91,13 +91,13 @@ def WSF_config(bim: dict) -> str: # noqa: C901 # Almost all other roof types require underlayment of some sort, but # the ruleset is based on asphalt shingles because it is most # conservative. - if bim['RoofShape'] == 'flt': # note there is actually no 'flt' - swr = True - elif bim['RoofShape'] in {'gab', 'hip'}: - if bim['RoofSlope'] <= 0.17: - swr = True - elif bim['RoofSlope'] < 0.33: - swr = bim['AvgJanTemp'] == 'below' + if BIM['RoofShape'] == 'flt': # note there is actually no 'flt' + SWR = True + elif BIM['RoofShape'] in ['gab','hip']: + if BIM['RoofSlope'] <= 0.17: + SWR = True + elif BIM['RoofSlope'] < 0.33: + SWR = (BIM['AvgJanTemp'] == 'below') # Roof Deck Attachment (RDA) # IRC codes: @@ -107,42 +107,34 @@ def WSF_config(bim: dict) -> str: # noqa: C901 # codes. Commentary for Table R602.3(1) indicates 8d nails with 6”/6” # spacing (enhanced roof spacing) for ultimate wind speeds greater than # a speed_lim. speed_lim depends on the year of construction - rda = '6d' # Default (aka A) in Reorganized Rulesets - WIND + RDA = '6d' # Default (aka A) in Reorganized Rulesets - WIND if year > 2000: if year >= 2016: # IRC 2015 - speed_lim = 130.0 # mph + speed_lim = 130.0 # mph else: # IRC 2000 - 2009 - speed_lim = 100.0 # mph - if bim['V_ult'] > speed_lim: - rda = '8s' # 8d @ 6"/6" ('D' in the Reorganized Rulesets - WIND) + speed_lim = 100.0 # mph + if BIM['V_ult'] > speed_lim: + RDA = '8s' # 8d @ 6"/6" ('D' in the Reorganized Rulesets - WIND) else: - rda = '8d' # 8d @ 6"/12" ('B' in the Reorganized Rulesets - WIND) + RDA = '8d' # 8d @ 6"/12" ('B' in the Reorganized Rulesets - WIND) elif year > 1995: - if (bim['SheathingThickness'] >= 0.3125) and ( - bim['SheathingThickness'] <= 0.5 - ): - rda = '6d' # 6d @ 6"/12" ('A' in the Reorganized Rulesets - WIND) - elif (bim['SheathingThickness'] >= 0.59375) and ( - bim['SheathingThickness'] <= 1.125 - ): - rda = '8d' # 8d @ 6"/12" ('B' in the Reorganized Rulesets - WIND) + if ((BIM['SheathingThickness'] >= 0.3125) and (BIM['SheathingThickness'] <= 0.5)): + RDA = '6d' # 6d @ 6"/12" ('A' in the Reorganized Rulesets - WIND) + elif ((BIM['SheathingThickness'] >= 0.59375) and (BIM['SheathingThickness'] <= 1.125)): + RDA = '8d' # 8d @ 6"/12" ('B' in the Reorganized Rulesets - WIND) elif year > 1986: - if (bim['SheathingThickness'] >= 0.3125) and ( - bim['SheathingThickness'] <= 0.5 - ): - rda = '6d' # 6d @ 6"/12" ('A' in the Reorganized Rulesets - WIND) - elif (bim['SheathingThickness'] >= 0.59375) and ( - bim['SheathingThickness'] <= 1.0 - ): - rda = '8d' # 8d @ 6"/12" ('B' in the Reorganized Rulesets - WIND) - elif (bim['SheathingThickness'] >= 0.3125) and ( - bim['SheathingThickness'] <= 0.5 - ): - rda = '6d' # 6d @ 6"/12" ('A' in the Reorganized Rulesets - WIND) - elif (bim['SheathingThickness'] >= 0.625) and (bim['SheathingThickness'] <= 1.0): - rda = '8d' # 8d @ 6"/12" ('B' in the Reorganized Rulesets - WIND) + if ((BIM['SheathingThickness'] >= 0.3125) and (BIM['SheathingThickness'] <= 0.5)): + RDA = '6d' # 6d @ 6"/12" ('A' in the Reorganized Rulesets - WIND) + elif ((BIM['SheathingThickness'] >= 0.59375) and (BIM['SheathingThickness'] <= 1.0)): + RDA = '8d' # 8d @ 6"/12" ('B' in the Reorganized Rulesets - WIND) + else: + # year <= 1986 + if ((BIM['SheathingThickness'] >= 0.3125) and (BIM['SheathingThickness'] <= 0.5)): + RDA = '6d' # 6d @ 6"/12" ('A' in the Reorganized Rulesets - WIND) + elif ((BIM['SheathingThickness'] >= 0.625) and (BIM['SheathingThickness'] <= 1.0)): + RDA = '8d' # 8d @ 6"/12" ('B' in the Reorganized Rulesets - WIND) # Roof-Wall Connection (RWC) # IRC 2015 @@ -154,10 +146,10 @@ def WSF_config(bim: dict) -> str: # noqa: C901 # will assume that if classified as HazardProneRegion, then enhanced # connection would be used. if year > 2015: - if bim['HazardProneRegion']: - rwc = 'strap' # Strap + if BIM['HazardProneRegion']: + RWC = 'strap' # Strap else: - rwc = 'tnail' # Toe-nail + RWC = 'tnail' # Toe-nail # IRC 2000-2009 # In Section R802.11.1 Uplift Resistance of the NJ 2009 IRC, roof # assemblies which are subject to wind uplift pressures of 20 pounds per @@ -175,10 +167,10 @@ def WSF_config(bim: dict) -> str: # noqa: C901 # 110 mph begin to generate pressures of 20 psf in high pressure zones of # the roof. Thus 110 mph is used as the critical velocity. elif year > 1992: - if bim['V_ult'] > 110: - rwc = 'strap' # Strap + if BIM['V_ult'] > 110: + RWC = 'strap' # Strap else: - rwc = 'tnail' # Toe-nail + RWC = 'tnail' # Toe-nail # CABO 1989 and earlier # There is no mention of straps or enhanced tie-downs in the CABO codes # older than 1992, and there is no description of these adoptions in IBHS @@ -191,7 +183,7 @@ def WSF_config(bim: dict) -> str: # noqa: C901 # buildings are toe nails before 1992. else: # year <= 1992 - rwc = 'tnail' # Toe-nail + RWC = 'tnail' # Toe-nail # Shutters # IRC 2000-2015: @@ -204,7 +196,7 @@ def WSF_config(bim: dict) -> str: # noqa: C901 # and are able to resist component and cladding loads; # Earlier IRC editions provide similar rules. if year > 2000: - shutters = bim['WindBorneDebris'] + shutters = BIM['WindBorneDebris'] # CABO: # Based on Human Subjects Data, roughly 45% of houses built in the 1980s # and 1990s had entries that implied they had shutters on at some or all of @@ -214,10 +206,12 @@ def WSF_config(bim: dict) -> str: # noqa: C901 # 1992 to 1995, 33/74 entries (44.59%) with shutters # 1986 to 1992, 36/79 entries (45.57%) with shutters # 1983 to 1986, 19/44 entries (43.18%) with shutters - elif bim['WindBorneDebris']: - shutters = random.random() < 0.45 else: - shutters = False + # year <= 2000 + if BIM['WindBorneDebris']: + shutters = random.random() < 0.45 + else: + shutters = False # Garage # As per IRC 2015: @@ -234,54 +228,57 @@ def WSF_config(bim: dict) -> str: # noqa: C901 # WindBorneDebris (and therefore do not have any strength requirements) that # are older than 30 years are considered to be weak, whereas those from the # last 30 years are considered to be standard. - if bim['Garage'] == -1: + if BIM['Garage'] == -1: # no garage data, using the default "standard" garage = 'std' - shutters = 0 # HAZUS ties standard garage to w/o shutters - elif year > 2000: - if shutters: - if bim['Garage'] < 1: - garage = 'no' + shutters = 0 # HAZUS ties standard garage to w/o shutters + else: + if year > 2000: + if shutters: + if BIM['Garage'] < 1: + garage = 'no' + else: + garage = 'sup' # SFBC 1994 + shutters = 1 # HAZUS ties SFBC 1994 to with shutters else: - garage = 'sup' # SFBC 1994 - shutters = 1 # HAZUS ties SFBC 1994 to with shutters - elif bim['Garage'] < 1: - garage = 'no' # None - else: - garage = 'std' # Standard - shutters = 0 # HAZUS ties standard garage to w/o shutters - elif year > (datetime.datetime.now(tz=datetime.timezone.utc).year - 30): - if bim['Garage'] < 1: - garage = 'no' # None + if BIM['Garage'] < 1: + garage = 'no' # None + else: + garage = 'std' # Standard + shutters = 0 # HAZUS ties standard garage to w/o shutters + elif year > (datetime.datetime.now().year - 30): + if BIM['Garage'] < 1: + garage = 'no' # None + else: + garage = 'std' # Standard + shutters = 0 # HAZUS ties standard garage to w/o shutters else: - garage = 'std' # Standard - shutters = 0 # HAZUS ties standard garage to w/o shutters - elif bim['Garage'] < 1: - garage = 'no' # None - else: - garage = 'wkd' # Weak - shutters = 0 # HAZUS ties weak garage to w/o shutters + # year <= current year - 30 + if BIM['Garage'] < 1: + garage = 'no' # None + else: + garage = 'wkd' # Weak + shutters = 0 # HAZUS ties weak garage to w/o shutters # extend the BIM dictionary - bim.update( - { - 'SecondaryWaterResistance': swr, - 'RoofDeckAttachmentW': rda, - 'RoofToWallConnection': rwc, - 'Shutters': shutters, - 'Garage': garage, - } - ) + BIM.update(dict( + SecondaryWaterResistance = SWR, + RoofDeckAttachmentW = RDA, + RoofToWallConnection = RWC, + Shutters = shutters, + Garage = garage + )) # building configuration tag - return ( - f"W.SF." - f"{int(min(bim['NumberOfStories'], 2))}." - f"{bim['RoofShape']}." - f"{int(swr)}." - f"{rda}." - f"{rwc}." - f"{garage}." - f"{int(shutters)}." - f"{int(bim['TerrainRoughness'])}" - ) + bldg_config = f"W.SF." \ + f"{int(min(BIM['NumberOfStories'],2))}." \ + f"{BIM['RoofShape']}." \ + f"{int(SWR)}." \ + f"{RDA}." \ + f"{RWC}." \ + f"{garage}." \ + f"{int(shutters)}." \ + f"{int(BIM['TerrainRoughness'])}" + + return bldg_config + diff --git a/pyproject.toml b/pyproject.toml index c08979782..3f313d44a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,6 @@ [tool.ruff] line-length = 85 +exclude = ["rulesets"] [tool.ruff.lint] # Enable all known categories @@ -22,14 +23,13 @@ max-bool-expr=5 "pelicun/tests/*" = ["D", "N802", "SLF001", "PLR2004", "PLR6301"] "pelicun/resources/auto/*" = ["ALL"] "pelicun/tools/HDF_to_CSV.py" = ["ALL"] -"pelicun/tests/dl_calculation/rulesets/*" = ["N999"] [tool.ruff.format] quote-style = "single" [tool.codespell] ignore-words = ["ignore_words.txt"] -skip = ["*.html", "./htmlcov/*", "./doc_src/build/*", "./pelicun.egg-info/*", "./doc_src/*", "./doc/build/*"] +skip = ["*.html", "./htmlcov/*", "./doc_src/build/*", "./pelicun.egg-info/*", "./doc_src/*", "./doc/build/*", "*/rulesets/*"] [tool.mypy] ignore_missing_imports = true