diff --git a/docs/section16/Rule16-1.md b/docs/section16/Rule16-1.md index 7e0c3e0db4..6479569954 100644 --- a/docs/section16/Rule16-1.md +++ b/docs/section16/Rule16-1.md @@ -5,7 +5,7 @@ **Rule Description:** The elevator peak motor power shall be calculated according to the equation in Table G3.1-16 **Rule Assertion:** B-RMR = expected value **Appendix G Section:** G3.1 -**Appendix G Section Reference:** Table G3.1-16 Baseline Building Performance +**Appendix G Section Reference:** Table G3.1-16 Baseline Building Performance **Data Lookup:** Table G3.9.1, Table G3.9.2, Table G3.9.3 **Evaluation Context:** Each elevator @@ -26,7 +26,7 @@ data_lookup - Get the elevator cab counterweight: `elevator_cab_counterweight_b = elevator.cab_counterweight` - Get the elevator design load: `elevator_design_load_b = elevator.design_load` - Get the elevator speed: `elevator_speed_b = elevator.speed` - - If any detailed elevator data parameters are not defined: `if any(param == Null for param in [total_floors_served_b, elevator_motor_power_b, elevator_cab_weight_b, elevator_cab_counterweight_b, elevator_design_load_b, elevator_speed_b]): is_undetermined = true` + - If any detailed elevator data parameters are not defined: `if any(param == Null for param in [total_floors_served_b, elevator_motor_power_b, elevator_cab_weight_b, elevator_cab_counterweight_b, elevator_design_load_b, elevator_speed_b]): has_undetermined = true` - Get the elevator mechanical efficiency: `elevator_mechanical_efficiency_b = data_lookup('table_g3.9.2', total_floors_served_b)['mechanical_efficiency']` - Calculate the motor brake horsepower: `motor_brake_horsepower_b = (elevator_cab_weight_b + elevator_design_load_b - elevator_cab_counterweight_b) * elevator_speed_b / 33000 / elevator_mechanical_efficiency_b` - If the total number of floors is greater than 4: `if total_floors_served_b > 4:` @@ -36,7 +36,7 @@ data_lookup - Calculate the expected peak motor power: `expected_peak_motor_power = motor_brake_horsepower_b * 746 / elevator_motor_efficiency_b` **Rule Assertion:** - - Case 1: If the number of floors in the building could not be determined or any detailed elevator data parameters are not defined, outcome = UNDETERMINED: `if is_undetermined: UNDETERMINED` + - Case 1: If the number of floors in the building could not be determined or any detailed elevator data parameters are not defined, outcome = UNDETERMINED: `if has_undetermined: UNDETERMINED` - Case 2: If the calculated peak motor power is equal to the expected value: `if elevator_motor_power_b == expected_peak_motor_power: PASS` - Case 3: Else: `else: FAIL` diff --git a/rct229/rulesets/ashrae9012019/data/ashrae_90_1_table_G3_9_1.json b/rct229/rulesets/ashrae9012019/data/ashrae_90_1_table_G3_9_1.json new file mode 100644 index 0000000000..079d54e9a3 --- /dev/null +++ b/rct229/rulesets/ashrae9012019/data/ashrae_90_1_table_G3_9_1.json @@ -0,0 +1,23 @@ +{ + "performance_rating_method_motor_efficiency_requirements": [ + {"shaft_input_power": 1.0, "full_load_motor_efficiency_for_modeling": 0.825}, + {"shaft_input_power": 1.5, "full_load_motor_efficiency_for_modeling": 0.840}, + {"shaft_input_power": 2.0, "full_load_motor_efficiency_for_modeling": 0.840}, + {"shaft_input_power": 3.0, "full_load_motor_efficiency_for_modeling": 0.875}, + {"shaft_input_power": 5.0, "full_load_motor_efficiency_for_modeling": 0.875}, + {"shaft_input_power": 7.5, "full_load_motor_efficiency_for_modeling": 0.895}, + {"shaft_input_power": 10.0, "full_load_motor_efficiency_for_modeling": 0.895}, + {"shaft_input_power": 15.0, "full_load_motor_efficiency_for_modeling": 0.910}, + {"shaft_input_power": 20.0, "full_load_motor_efficiency_for_modeling": 0.910}, + {"shaft_input_power": 25.0, "full_load_motor_efficiency_for_modeling": 0.924}, + {"shaft_input_power": 30.0, "full_load_motor_efficiency_for_modeling": 0.924}, + {"shaft_input_power": 40.0, "full_load_motor_efficiency_for_modeling": 0.930}, + {"shaft_input_power": 50.0, "full_load_motor_efficiency_for_modeling": 0.930}, + {"shaft_input_power": 60.0, "full_load_motor_efficiency_for_modeling": 0.936}, + {"shaft_input_power": 75.0, "full_load_motor_efficiency_for_modeling": 0.941}, + {"shaft_input_power": 100.0, "full_load_motor_efficiency_for_modeling": 0.945}, + {"shaft_input_power": 125.0, "full_load_motor_efficiency_for_modeling": 0.945}, + {"shaft_input_power": 150.0, "full_load_motor_efficiency_for_modeling": 0.950}, + {"shaft_input_power": 200.0, "full_load_motor_efficiency_for_modeling": 0.950} + ] +} diff --git a/rct229/rulesets/ashrae9012019/data/ashrae_90_1_table_G3_9_2.json b/rct229/rulesets/ashrae9012019/data/ashrae_90_1_table_G3_9_2.json new file mode 100644 index 0000000000..69e0130ce3 --- /dev/null +++ b/rct229/rulesets/ashrae9012019/data/ashrae_90_1_table_G3_9_2.json @@ -0,0 +1,14 @@ +{ + "performance_rating_method_baseline_elevator_motor": [ + { + "number_of_stories": "less than or equal to 4", + "motor_type": "Hydraulic", + "mechanical_efficiency": 0.58 + }, + { + "number_of_stories": "greater than 4", + "motor_type": "Traction", + "mechanical_efficiency": 0.64 + } + ] +} diff --git a/rct229/rulesets/ashrae9012019/data/ashrae_90_1_table_G3_9_3.json b/rct229/rulesets/ashrae9012019/data/ashrae_90_1_table_G3_9_3.json new file mode 100644 index 0000000000..7b661755e9 --- /dev/null +++ b/rct229/rulesets/ashrae9012019/data/ashrae_90_1_table_G3_9_3.json @@ -0,0 +1,9 @@ +{ + "performance_rating_method_hydraulic_elevator_motor_efficiency": [ + {"shaft_input_power": 10, "full_load_motor_efficiency_for_modeling": 0.72}, + {"shaft_input_power": 20, "full_load_motor_efficiency_for_modeling": 0.75}, + {"shaft_input_power": 30, "full_load_motor_efficiency_for_modeling": 0.78}, + {"shaft_input_power": 40, "full_load_motor_efficiency_for_modeling": 0.78}, + {"shaft_input_power": 100, "full_load_motor_efficiency_for_modeling": 0.80} + ] +} diff --git a/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_1_fins.py b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_1_fins.py index 34d9cac2b6..42c1ce5058 100644 --- a/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_1_fins.py +++ b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_1_fins.py @@ -1,9 +1,19 @@ +from typing import TypedDict + +from pint import Quantity from rct229.rulesets.ashrae9012019.data import data from rct229.rulesets.ashrae9012019.data_fns.table_utils import find_osstd_table_entry from rct229.schema.config import ureg +from rct229.utils.assertions import assert_ + +class FullLoadMotorEfficiency(TypedDict): + full_load_motor_efficiency_for_modeling: float -def table_G3_9_1_lookup(shaft_input_power): + +def table_G3_9_1_lookup( + shaft_input_power: Quantity, +) -> FullLoadMotorEfficiency: """Returns the full-load motor efficiency for motors as required by ASHRAE 90.1 Table G3.9.1 Parameters ---------- @@ -13,54 +23,60 @@ def table_G3_9_1_lookup(shaft_input_power): Returns ------- dict - {nominal_full_load_efficiency - The full load motor efficiency by Table G3.9.1} + {full_load_motor_efficiency_for_modeling - The full load motor efficiency by Table G3.9.1} """ - if 0 * ureg("hp") <= shaft_input_power < 1.0 * ureg("hp"): - minimum_shaft_input_power = 0.0 - elif 1.0 * ureg("hp") <= shaft_input_power < 1.5 * ureg("hp"): + assert_( + shaft_input_power > 0.0 * ureg("hp"), + "The `shaft_input_power` must be greater than 0.0 hp.", + ) + shaft_input_power_mag = shaft_input_power.magnitude + + if shaft_input_power_mag <= 1.0: minimum_shaft_input_power = 1.0 - elif 1.5 * ureg("hp") <= shaft_input_power < 2.0 * ureg("hp"): + elif shaft_input_power_mag <= 1.5: minimum_shaft_input_power = 1.5 - elif 2.0 * ureg("hp") <= shaft_input_power < 5.0 * ureg("hp"): + elif shaft_input_power_mag <= 2.0: minimum_shaft_input_power = 2.0 - elif 3.0 * ureg("hp") <= shaft_input_power < 7.5 * ureg("hp"): + elif shaft_input_power_mag <= 3.0: minimum_shaft_input_power = 3.0 - elif 5.0 * ureg("hp") <= shaft_input_power < 7.5 * ureg("hp"): + elif shaft_input_power_mag <= 5.0: minimum_shaft_input_power = 5.0 - elif 7.5 * ureg("hp") <= shaft_input_power < 10.0 * ureg("hp"): + elif shaft_input_power_mag <= 7.5: minimum_shaft_input_power = 7.5 - elif 10.0 * ureg("hp") <= shaft_input_power < 15.0 * ureg("hp"): + elif shaft_input_power_mag <= 10.0: minimum_shaft_input_power = 10.0 - elif 15.0 * ureg("hp") <= shaft_input_power < 20.0 * ureg("hp"): + elif shaft_input_power_mag <= 15.0: minimum_shaft_input_power = 15.0 - elif 20.0 * ureg("hp") <= shaft_input_power < 25.0 * ureg("hp"): + elif shaft_input_power_mag <= 20.0: minimum_shaft_input_power = 20.0 - elif 25.0 * ureg("hp") <= shaft_input_power < 30.0 * ureg("hp"): + elif shaft_input_power_mag <= 25.0: minimum_shaft_input_power = 25.0 - elif 30.0 * ureg("hp") <= shaft_input_power < 40.0 * ureg("hp"): + elif shaft_input_power_mag <= 30.0: minimum_shaft_input_power = 30.0 - elif 40.0 * ureg("hp") <= shaft_input_power < 50.0 * ureg("hp"): + elif shaft_input_power_mag <= 40.0: minimum_shaft_input_power = 40.0 - elif 50.0 * ureg("hp") <= shaft_input_power < 60.0 * ureg("hp"): + elif shaft_input_power_mag <= 50.0: minimum_shaft_input_power = 50.0 - elif 60.0 * ureg("hp") <= shaft_input_power < 75.0 * ureg("hp"): + elif shaft_input_power_mag <= 60.0: minimum_shaft_input_power = 60.0 - elif 75.0 * ureg("hp") <= shaft_input_power < 100.0 * ureg("hp"): + elif shaft_input_power_mag <= 75.0: minimum_shaft_input_power = 75.0 - elif 100.0 * ureg("hp") <= shaft_input_power < 125.0 * ureg("hp"): + elif shaft_input_power_mag <= 100.0: minimum_shaft_input_power = 100.0 - elif 125.0 * ureg("hp") <= shaft_input_power < 150.0 * ureg("hp"): + elif shaft_input_power_mag <= 125.0: minimum_shaft_input_power = 125.0 - elif 150.0 * ureg("hp") <= shaft_input_power < 200.0 * ureg("hp"): + elif shaft_input_power_mag <= 150.0: minimum_shaft_input_power = 150.0 - elif 200.0 * ureg("hp") <= shaft_input_power: + else: minimum_shaft_input_power = 200.0 - nominal_full_load_efficiency = find_osstd_table_entry( - [("minimum_capacity", minimum_shaft_input_power)], - osstd_table=data["ashrae_90_1_prm_2019.motors"], - )["nominal_full_load_efficiency"] + full_load_motor_efficiency_for_modeling = find_osstd_table_entry( + [("shaft_input_power", minimum_shaft_input_power)], + osstd_table=data["ashrae_90_1_table_G3_9_1"], + )["full_load_motor_efficiency_for_modeling"] - return {"nominal_full_load_efficiency": nominal_full_load_efficiency} + return { + "full_load_motor_efficiency_for_modeling": full_load_motor_efficiency_for_modeling + } diff --git a/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_1_fins_test.py b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_1_fins_test.py index ee4f067665..b6f77fc571 100644 --- a/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_1_fins_test.py +++ b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_1_fins_test.py @@ -2,19 +2,19 @@ from rct229.schema.config import ureg -def test__table_G3_9_lookup__1_shaft_input_power(): +def test__table_G3_9_lookup__1_2_shaft_input_power(): assert table_G3_9_1_lookup( - shaft_input_power=0.5 * ureg("hp"), - ) == {"nominal_full_load_efficiency": 0.825} + shaft_input_power=1.2 * ureg("hp"), + ) == {"full_load_motor_efficiency_for_modeling": 0.840} def test__table_G3_9_lookup__7_5_shaft_input_power(): assert table_G3_9_1_lookup( shaft_input_power=7.5 * ureg("hp"), - ) == {"nominal_full_load_efficiency": 0.895} + ) == {"full_load_motor_efficiency_for_modeling": 0.895} def test__table_G3_9_lookup__50_shaft_input_power(): assert table_G3_9_1_lookup( shaft_input_power=50.0 * ureg("hp"), - ) == {"nominal_full_load_efficiency": 0.93} + ) == {"full_load_motor_efficiency_for_modeling": 0.93} diff --git a/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_2_fins.py b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_2_fins.py new file mode 100644 index 0000000000..ff08c7293b --- /dev/null +++ b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_2_fins.py @@ -0,0 +1,42 @@ +from typing import TypedDict + +from rct229.rulesets.ashrae9012019.data import data +from rct229.rulesets.ashrae9012019.data_fns.table_utils import find_osstd_table_entry + + +class MechanicalEfficiency(TypedDict): + mechanical_efficiency: float + motor_type: str + + +def table_G3_9_2_lookup(number_of_stories: int) -> MechanicalEfficiency: + """Returns the full-load motor efficiency for motors as required by ASHRAE 90.1 Table G3.9.2 + Parameters + ---------- + number_of_stories: int + number of stories including basement - the value must be greater than 0. + + Returns + ------- + dict + {mechanical_efficiency - The mechanical efficiency by Table G3.9.2 + motor_type - The motor type by Table G3.9.2} + + Raises: + ------- + TypeError: when the number_of_stories is less or equal to 0, the function will raise this error + """ + + number_of_stories = ( + "less than or equal to 4" if number_of_stories <= 4 else "greater than 4" + ) + + ashrae_90_1_table_G3_9_2 = find_osstd_table_entry( + [("number_of_stories", number_of_stories)], + osstd_table=data["ashrae_90_1_table_G3_9_2"], + ) + + mechanical_efficiency = ashrae_90_1_table_G3_9_2["mechanical_efficiency"] + motor_type = ashrae_90_1_table_G3_9_2["motor_type"] + + return {"mechanical_efficiency": mechanical_efficiency, "motor_type": motor_type} diff --git a/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_2_fins_test.py b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_2_fins_test.py new file mode 100644 index 0000000000..4c8ec49838 --- /dev/null +++ b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_2_fins_test.py @@ -0,0 +1,13 @@ +from rct229.rulesets.ashrae9012019.data_fns.table_G3_9_2_fins import table_G3_9_2_lookup + + +def test__table_G3_9_lookup__4_story_building(): + assert table_G3_9_2_lookup( + number_of_stories=4, + ) == {"mechanical_efficiency": 0.58, "motor_type": "Hydraulic"} + + +def test__table_G3_9_lookup__6_story_building(): + assert table_G3_9_2_lookup( + number_of_stories=6, + ) == {"mechanical_efficiency": 0.64, "motor_type": "Traction"} diff --git a/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_3_fins.py b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_3_fins.py new file mode 100644 index 0000000000..3015ea225e --- /dev/null +++ b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_3_fins.py @@ -0,0 +1,46 @@ +import math + +from pint import Quantity +from rct229.rulesets.ashrae9012019.data import data +from rct229.rulesets.ashrae9012019.data_fns.table_G3_9_1_fins import ( + FullLoadMotorEfficiency, +) +from rct229.rulesets.ashrae9012019.data_fns.table_utils import find_osstd_table_entry +from rct229.utils.assertions import assert_ + + +def table_G3_9_3_lookup(shaft_input_power: Quantity) -> FullLoadMotorEfficiency: + """Returns the full-load motor efficiency for motors as required by ASHRAE 90.1 Table G3.9.2 + Parameters + ---------- + shaft_input_power: Quantity + shaft input power value + + Returns + ------- + dict + {full_load_motor_efficiency_for_modeling - The full load motor efficiency for modeling by Table G3.9.3} + + Raises: + ------- + TypeError: when the shaft_input_power_mag is less or equal to 0, the function will raise this error + """ + + shaft_input_power_mag = shaft_input_power.to("hp").magnitude + assert_( + shaft_input_power_mag > 0, + "shaft input power is a negative value, incorrect data.", + ) + shaft_input_power = math.ceil(shaft_input_power_mag / 10) * 10 + + if shaft_input_power > 40: + shaft_input_power = 100 + + full_load_motor_efficiency_for_modeling = find_osstd_table_entry( + [("shaft_input_power", shaft_input_power)], + osstd_table=data["ashrae_90_1_table_G3_9_3"], + )["full_load_motor_efficiency_for_modeling"] + + return { + "full_load_motor_efficiency_for_modeling": full_load_motor_efficiency_for_modeling + } diff --git a/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_3_fins_test.py b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_3_fins_test.py new file mode 100644 index 0000000000..08c037e2c4 --- /dev/null +++ b/rct229/rulesets/ashrae9012019/data_fns/table_G3_9_3_fins_test.py @@ -0,0 +1,20 @@ +from rct229.rulesets.ashrae9012019.data_fns.table_G3_9_3_fins import table_G3_9_3_lookup +from rct229.schema.config import ureg + + +def test__table_G3_9_lookup__15_hp_shaft_power(): + assert table_G3_9_3_lookup( + shaft_input_power=15.0 * ureg("hp"), + ) == {"full_load_motor_efficiency_for_modeling": 0.75} + + +def test__table_G3_9_lookup__25_hp_shaft_power(): + assert table_G3_9_3_lookup( + shaft_input_power=25.0 * ureg("hp"), + ) == {"full_load_motor_efficiency_for_modeling": 0.78} + + +def test__table_G3_9_lookup__105_hp_shaft_power(): + assert table_G3_9_3_lookup( + shaft_input_power=105.0 * ureg("hp"), + ) == {"full_load_motor_efficiency_for_modeling": 0.80} diff --git a/rct229/rulesets/ashrae9012019/section16/__init__.py b/rct229/rulesets/ashrae9012019/section16/__init__.py index 39de5da832..758a59dddc 100644 --- a/rct229/rulesets/ashrae9012019/section16/__init__.py +++ b/rct229/rulesets/ashrae9012019/section16/__init__.py @@ -2,7 +2,7 @@ # Add all available rule modules in __all__ __all__ = [ - # "section16rule1", + "section16rule1", "section16rule2", "section16rule3", "section16rule4", diff --git a/rct229/rulesets/ashrae9012019/section16/section16rule1.py b/rct229/rulesets/ashrae9012019/section16/section16rule1.py new file mode 100644 index 0000000000..daf0b2191f --- /dev/null +++ b/rct229/rulesets/ashrae9012019/section16/section16rule1.py @@ -0,0 +1,134 @@ +from rct229.rule_engine.rule_base import RuleDefinitionBase +from rct229.rule_engine.rule_list_indexed_base import RuleDefinitionListIndexedBase +from rct229.rule_engine.ruleset_model_factory import produce_ruleset_model_description +from rct229.rulesets.ashrae9012019 import BASELINE_0 +from rct229.rulesets.ashrae9012019.data_fns.table_G3_9_1_fins import table_G3_9_1_lookup +from rct229.rulesets.ashrae9012019.data_fns.table_G3_9_2_fins import table_G3_9_2_lookup +from rct229.rulesets.ashrae9012019.data_fns.table_G3_9_3_fins import table_G3_9_3_lookup +from rct229.schema.config import ureg +from rct229.utils.assertions import assert_, getattr_ +from rct229.utils.jsonpath_utils import find_all +from rct229.utils.pint_utils import ZERO, CalcQ +from rct229.utils.std_comparisons import std_equal + + +class Section16Rule1(RuleDefinitionListIndexedBase): + """Rule 1 of ASHRAE 90.1-2019 Appendix G Section 16 (Elevators)""" + + def __init__(self): + super(Section16Rule1, self).__init__( + rmds_used=produce_ruleset_model_description( + USER=False, + BASELINE_0=True, + PROPOSED=True, + ), + each_rule=Section16Rule1.ElevatorRule(), + index_rmd=BASELINE_0, + id="16-1", + description="The elevator peak motor power shall be calculated according to the equation in Table G3.1-16.", + ruleset_section_title="Elevators", + standard_section="Section G3.1", + is_primary_rule=True, + rmd_context="ruleset_model_descriptions/0", + list_path="$.buildings[*].elevators[*]", + ) + + def is_applicable(self, context, data=None): + rmd_b = context.BASELINE_0 + rmd_p = context.PROPOSED + + elevators_list_b = find_all("$.buildings[*].elevators[*]", rmd_b) + elevators_list_p = find_all("$.buildings[*].elevators[*]", rmd_p) + + return elevators_list_p and elevators_list_b + + class ElevatorRule(RuleDefinitionBase): + def __init__(self): + super(Section16Rule1.ElevatorRule, self).__init__( + rmds_used=produce_ruleset_model_description( + USER=False, + BASELINE_0=True, + PROPOSED=False, + ), + ) + + def get_calc_vals(self, context, data=None): + elevator_b = context.BASELINE_0 + + total_floors_served_b = getattr_( + elevator_b, "elevators", "number_of_floors_served" + ) + assert_( + total_floors_served_b > 1, + "The `number of floors served` value must be greater than 1.", + ) + + elevator_motor_power_b = getattr_(elevator_b, "elevators", "motor_power") + + elevator_cab_weight_b = getattr_(elevator_b, "elevators", "cab_weight") + elevator_cab_counterweight_b = getattr_( + elevator_b, "elevators", "cab_counterweight" + ) + elevator_design_load_b = getattr_(elevator_b, "elevators", "design_load") + assert_( + elevator_cab_weight_b + + elevator_design_load_b + - elevator_cab_counterweight_b + > ZERO.WEIGHT, + "Elevator cab counter weight shall be smaller than the sum of cab weight and design load. A " + "typical cab counter weight is the sum of cab weight and 40% of design load.", + ) + + elevator_speed_b = getattr_(elevator_b, "elevators", "speed") + elevator_mechanical_efficiency_b = table_G3_9_2_lookup( + total_floors_served_b + )["mechanical_efficiency"] + + # From Table G3.1 16 Elevators + # bhp (hp) = (Weight of Car + Rated Load – Counterweight) × Speed of Car / (33,000 × h_mechanical) + # P_m (W) = bhp x 746 / h_motor + # Where, + # Weight of Car: the proposed design elevator car weight, lb + # Rated Load: the proposed design elevator load at which to operate, lb + # Counterweight of Car: the elevator car counterweight, from Table G3.9.2, lb + # Speed of Car: the speed of the proposed elevator, ft/min + # h_mechanical: the mechanical efficiency of the elevator from Table G3.9.2 + # h_motor: the motor efficiency from Table G3.9.2 + # Pm: peak elevator motor power, W + motor_brake_horsepower_b = ( + ( + elevator_cab_weight_b.to("lb") + + elevator_design_load_b.to("lb") + - elevator_cab_counterweight_b.to("lb") + ) + * elevator_speed_b.to("ft/min") + / (33000 * elevator_mechanical_efficiency_b) + ).m * ureg("hp") + + elevator_motor_efficiency_b = ( + table_G3_9_1_lookup(motor_brake_horsepower_b)[ + "full_load_motor_efficiency_for_modeling" + ] + if total_floors_served_b > 4 + else table_G3_9_3_lookup(motor_brake_horsepower_b)[ + "full_load_motor_efficiency_for_modeling" + ] + ) + expected_peak_motor_power_b = ( + motor_brake_horsepower_b / elevator_motor_efficiency_b + ) + + return { + "expected_peak_motor_power_b": CalcQ( + "electric_power", expected_peak_motor_power_b + ), + "elevator_motor_power_b": CalcQ( + "electric_power", elevator_motor_power_b + ), + } + + def rule_check(self, context, calc_vals=None, data=None): + expected_peak_motor_power_b = calc_vals["expected_peak_motor_power_b"] + elevator_motor_power_b = calc_vals["elevator_motor_power_b"] + + return std_equal(expected_peak_motor_power_b, elevator_motor_power_b) diff --git a/rct229/rulesets/ashrae9012019/section19/section19rule18.py b/rct229/rulesets/ashrae9012019/section19/section19rule18.py index a50178d753..1b8cd13efa 100644 --- a/rct229/rulesets/ashrae9012019/section19/section19rule18.py +++ b/rct229/rulesets/ashrae9012019/section19/section19rule18.py @@ -247,10 +247,10 @@ def get_calc_vals(self, context, data=None): min_BHP_b = (0.00062 * supply_flow_b).m * ureg("hp") expected_motor_efficiency_b = table_G3_9_1_lookup(expected_BHP_b)[ - "nominal_full_load_efficiency" + "full_load_motor_efficiency_for_modeling" ] min_motor_efficiency_b = table_G3_9_1_lookup(min_BHP_b)[ - "nominal_full_load_efficiency" + "full_load_motor_efficiency_for_modeling" ] expected_fan_wattage_b = expected_BHP_b / expected_motor_efficiency_b diff --git a/rct229/ruletest_engine/ruletest_jsons/ashrae9012019/section16/rule_16_1.json b/rct229/ruletest_engine/ruletest_jsons/ashrae9012019/section16/rule_16_1.json new file mode 100644 index 0000000000..9bf0b95b37 --- /dev/null +++ b/rct229/ruletest_engine/ruletest_jsons/ashrae9012019/section16/rule_16_1.json @@ -0,0 +1,1022 @@ +{ + "rule-16-1-a": { + "Section": 16, + "Rule": 1, + "Test": "a", + "test_description": "A baseline building with an elevator does not have the number of floors defined. ", + "expected_rule_outcome": "undetermined", + "standard": { + "rule_id": "16-1", + "ruleset_reference": 0, + "rule_description": "The elevator peak motor power shall be calculated according to the equation in Table G3.1-16", + "applicable_rmr": "Baseline Model", + "rule_assertion": "=", + "comparison_value": "Expected Value", + "rule_dependency": 0, + "mandatory_rule": "Yes", + "schema_version": "0.0.34" + }, + "rmr_transformations": { + "proposed": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ], + "elevators": [ + { + "id": "Elevator 1", + "number_of_floors_served": 4 + } + ] + } + ], + "type": "PROPOSED" + } + ] + }, + "baseline": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ], + "elevators": [ + { + "id": "Elevator 1", + "motor_power": 15000, + "cab_counterweight": 1360.8000000000002, + "cab_weight": 680.4000000000001, + "design_load": 907.2000000000002, + "speed": 0.5079999999999999 + } + ] + } + ], + "type": "BASELINE_0" + } + ] + } + } + }, + "rule-16-1-b": { + "Section": 16, + "Rule": 1, + "Test": "b", + "test_description": "A baseline building with an elevator does not have important elevator parameters defined.", + "expected_rule_outcome": "undetermined", + "standard": { + "rule_id": "16-1", + "ruleset_reference": 0, + "rule_description": "The elevator peak motor power shall be calculated according to the equation in Table G3.1-16", + "applicable_rmr": "Baseline Model", + "rule_assertion": "=", + "comparison_value": "Expected Value", + "rule_dependency": 0, + "mandatory_rule": "Yes", + "schema_version": "0.0.34" + }, + "rmr_transformations": { + "proposed": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ], + "elevators": [ + { + "id": "Elevator 1", + "number_of_floors_served": 4 + } + ] + } + ], + "type": "PROPOSED" + } + ] + }, + "baseline": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ], + "elevators": [ + { + "id": "Elevator 1", + "number_of_floors_served": 4 + } + ] + } + ], + "type": "BASELINE_0" + } + ] + } + } + }, + "rule-16-1-c": { + "Section": 16, + "Rule": 1, + "Test": "c", + "test_description": "A baseline building with 4 floors and an elevator has the appropriate performance metrics to meet the elevator motor power defined in Table G3.9.3. Expected result: PASS", + "expected_rule_outcome": "pass", + "standard": { + "rule_id": "16-1", + "ruleset_reference": 0, + "rule_description": "The elevator peak motor power shall be calculated according to the equation in Table G3.1-16", + "applicable_rmr": "Baseline Model", + "rule_assertion": "=", + "comparison_value": "Expected Value", + "rule_dependency": 0, + "mandatory_rule": "Yes", + "schema_version": "0.0.34" + }, + "rmr_transformations": { + "proposed": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ], + "elevators": [ + { + "id": "Elevator 1", + "number_of_floors_served": 4 + } + ] + } + ], + "type": "PROPOSED" + } + ] + }, + "baseline": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ], + "elevators": [ + { + "id": "Elevator 1", + "number_of_floors_served": 4, + "motor_power": 24984.593950111193, + "cab_counterweight": 226.80000000000004, + "cab_weight": 680.4000000000001, + "design_load": 1814.4000000000003, + "speed": 0.5079999999999999 + } + ] + } + ], + "type": "BASELINE_0" + } + ] + } + } + }, + "rule-16-1-d": { + "Section": 16, + "Rule": 1, + "Test": "d", + "test_description": "A baseline building with 4 floors and an elevator does not have the appropriate performance metrics to meet the elevator motor power defined in Table G3.9.3. Expected result: FAIL", + "expected_rule_outcome": "fail", + "standard": { + "rule_id": "16-1", + "ruleset_reference": 0, + "rule_description": "The elevator peak motor power shall be calculated according to the equation in Table G3.1-16", + "applicable_rmr": "Baseline Model", + "rule_assertion": "=", + "comparison_value": "Expected Value", + "rule_dependency": 0, + "mandatory_rule": "Yes", + "schema_version": "0.0.34" + }, + "rmr_transformations": { + "proposed": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ], + "elevators": [ + { + "id": "Elevator 1", + "number_of_floors_served": 4 + } + ] + } + ], + "type": "PROPOSED" + } + ] + }, + "baseline": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ], + "elevators": [ + { + "id": "Elevator 1", + "number_of_floors_served": 4, + "motor_power": 20000, + "cab_counterweight": 226.80000000000004, + "cab_weight": 680.4000000000001, + "design_load": 1814.4000000000003, + "speed": 0.5079999999999999 + } + ] + } + ], + "type": "BASELINE_0" + } + ] + } + } + }, + "rule-16-1-e": { + "Section": 16, + "Rule": 1, + "Test": "e", + "test_description": "A baseline building with 4 floors and an elevator exists but has no proposed equivalent. Expected result: NOT APPLICABLE", + "expected_rule_outcome": "not_applicable", + "standard": { + "rule_id": "16-1", + "ruleset_reference": 0, + "rule_description": "The elevator peak motor power shall be calculated according to the equation in Table G3.1-16", + "applicable_rmr": "Baseline Model", + "rule_assertion": "=", + "comparison_value": "Expected Value", + "rule_dependency": 0, + "mandatory_rule": "Yes", + "schema_version": "0.0.34" + }, + "rmr_transformations": { + "proposed": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ] + } + ], + "type": "PROPOSED" + } + ] + }, + "baseline": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ], + "elevators": [ + { + "id": "Elevator 1", + "number_of_floors_served": 4, + "motor_power": 20000, + "cab_counterweight": 226.80000000000004, + "cab_weight": 680.4000000000001, + "design_load": 1814.4000000000003, + "speed": 0.5079999999999999 + } + ] + } + ], + "type": "BASELINE_0" + } + ] + } + } + }, + "rule-16-1-f": { + "Section": 16, + "Rule": 1, + "Test": "f", + "test_description": "A propsed building with 4 floors and an elevator exists but has no baseline elevator equivalent. Expected result: NOT APPLICABLE", + "expected_rule_outcome": "not_applicable", + "standard": { + "rule_id": "16-1", + "ruleset_reference": 0, + "rule_description": "The elevator peak motor power shall be calculated according to the equation in Table G3.1-16", + "applicable_rmr": "Baseline Model", + "rule_assertion": "=", + "comparison_value": "Expected Value", + "rule_dependency": 0, + "mandatory_rule": "Yes", + "schema_version": "0.0.34" + }, + "rmr_transformations": { + "proposed": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ], + "elevators": [ + { + "id": "Elevator 1", + "number_of_floors_served": 4, + "motor_power": 20000, + "cab_counterweight": 500, + "cab_weight": 1500, + "design_load": 4000, + "speed": 100 + } + ] + } + ], + "type": "PROPOSED" + } + ] + }, + "baseline": { + "id": "ASHRAE229 1", + "weather": { + "climate_zone": "CZ4A" + }, + "calendar": { + "is_leap_year": false + }, + "data_timestamp": "2024-02-12T12:00Z", + "ruleset_model_descriptions": [ + { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "floor_name": "Floor 1" + }, + { + "id": "Thermal Zone 2", + "floor_name": "Floor 2", + "spaces": [ + { + "id": "Space 2" + } + ] + }, + { + "id": "Thermal Zone 3", + "spaces": [ + { + "id": "Space 3" + } + ], + "floor_name": "Floor 3" + }, + { + "id": "Thermal Zone 4", + "spaces": [ + { + "id": "Space 4" + } + ], + "floor_name": "Floor 4" + }, + { + "id": "Thermal Zone 5", + "spaces": [ + { + "id": "Space 5" + } + ], + "floor_name": "Floor 5" + } + ] + } + ] + } + ], + "type": "BASELINE_0" + } + ] + } + } + } +} \ No newline at end of file diff --git a/rct229/utils/pint_utils.py b/rct229/utils/pint_utils.py index 8f9f165b9b..0a247319e5 100644 --- a/rct229/utils/pint_utils.py +++ b/rct229/utils/pint_utils.py @@ -88,6 +88,7 @@ class ZERO: """Class holding zero values for various pint quantities""" LENGTH: Quantity = 0 * ureg("ft") + WEIGHT: Quantity = 0 * ureg("lb") AREA: Quantity = LENGTH * LENGTH VOLUME: Quantity = AREA * LENGTH