From eb99682507417ca589f8a4d10cd79c7995cacdaa Mon Sep 17 00:00:00 2001 From: yunjoonjung Date: Mon, 2 Dec 2024 17:32:05 -0800 Subject: [PATCH] initial commit --- ...components_associated_with_each_swh_bat.py | 13 +- .../ashrae9012019/section11/__init__.py | 2 +- .../ashrae9012019/section11/section11rule8.py | 226 ++++++++++++++++++ .../resources/json_pointer_enumerations.json | 1 + 4 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 rct229/rulesets/ashrae9012019/section11/section11rule8.py diff --git a/rct229/rulesets/ashrae9012019/ruleset_functions/get_swh_components_associated_with_each_swh_bat.py b/rct229/rulesets/ashrae9012019/ruleset_functions/get_swh_components_associated_with_each_swh_bat.py index da85936cf7..2a911ad887 100644 --- a/rct229/rulesets/ashrae9012019/ruleset_functions/get_swh_components_associated_with_each_swh_bat.py +++ b/rct229/rulesets/ashrae9012019/ruleset_functions/get_swh_components_associated_with_each_swh_bat.py @@ -7,7 +7,7 @@ from rct229.rulesets.ashrae9012019.ruleset_functions.get_energy_required_to_heat_swh_use import ( get_energy_required_to_heat_swh_use, ) - +from rct229.utils.assertions import getattr_ from rct229.utils.jsonpath_utils import find_all from rct229.utils.pint_utils import ZERO from rct229.utils.utility_functions import ( @@ -75,7 +75,9 @@ def get_swh_components_associated_with_each_swh_bat( rmd, distribution_id ) ) - tanks = distribution.get("tanks") + tanks = getattr_( + distribution, "service_water_heating_distribution_systems", "tanks" + ) for tank in tanks: swh_and_equip_dict[swh_bat].tanks.append(tank["id"]) @@ -101,7 +103,12 @@ def get_swh_components_associated_with_each_swh_bat( in swh_and_equip_dict[swh_bat].swh_distribution ): swh_and_equip_dict[swh_bat].swh_heating_eq.append(swh_equip["id"]) - for solar_t in swh_equip.get("solar_thermal_systems"): + getattr_( + swh_equip, + "service_water_heating_equipment", + "solar_thermal_systems", + ) + for solar_t in swh_equip["solar_thermal_systems"]: swh_and_equip_dict[swh_bat].solar_thermal.append(solar_t["id"]) return swh_and_equip_dict diff --git a/rct229/rulesets/ashrae9012019/section11/__init__.py b/rct229/rulesets/ashrae9012019/section11/__init__.py index 9f0fc2c229..1ef27b7754 100644 --- a/rct229/rulesets/ashrae9012019/section11/__init__.py +++ b/rct229/rulesets/ashrae9012019/section11/__init__.py @@ -9,7 +9,7 @@ # "section11rule5", # "section11rule6", # "section11rule7", - # "section11rule8", + "section11rule8", # "section11rule9", # "section11rule10", # "section11rule11", diff --git a/rct229/rulesets/ashrae9012019/section11/section11rule8.py b/rct229/rulesets/ashrae9012019/section11/section11rule8.py new file mode 100644 index 0000000000..e306bdb908 --- /dev/null +++ b/rct229/rulesets/ashrae9012019/section11/section11rule8.py @@ -0,0 +1,226 @@ +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.ruleset_functions.get_swh_bats_and_swh_use import ( + get_swh_bats_and_swh_use, +) +from rct229.rulesets.ashrae9012019.ruleset_functions.get_swh_components_associated_with_each_swh_bat import ( + get_swh_components_associated_with_each_swh_bat, +) +from rct229.rulesets.ashrae9012019.ruleset_functions.get_swh_equipment_type import ( + get_swh_equipment_type, +) +from rct229.schema.schema_enums import SchemaEnums +from rct229.utils.jsonpath_utils import find_all + +SERVICE_WATER_HEATING_SPACE = SchemaEnums.schema_enums[ + "ServiceWaterHeatingSpaceOptions2019ASHRAE901" +] + +CASE3_MSG = ( + "The Service Water Heating Building Area type for this building segment is undetermined, and there are multiple building segments in the project. " + "Therefore it cannot be determined whether this building segment shares a service water heating building area type with one of the other building segments." +) +CASE4_MSG = ( + "The Service Water Heating Building Area Type is 'OTHER' and is applied to multiple building segments. " + "'OTHER' can describe multiple Service Water Heating Building Area Types. " + "Confirm that Service Water Heating Building Area Type is provided with one and only one service water heating system." +) + + +class Section11Rule8(RuleDefinitionListIndexedBase): + """Rule 8 of ASHRAE 90.1-2019 Appendix G Section 11 (Service Water Heating)""" + + def __init__(self): + super(Section11Rule8, self).__init__( + rmds_used=produce_ruleset_model_description( + USER=False, BASELINE_0=True, PROPOSED=True + ), + each_rule=Section11Rule8.RMDRule(), + index_rmd=BASELINE_0, + id="11-8", + description="One system per building area type shall be modeled in the baseline.", + ruleset_section_title="Service Water Heating", + standard_section="Table G3.1 #11, baseline column, a + b", + is_primary_rule=True, + list_path="ruleset_model_descriptions[0]", + required_fields={"$": ["calendar"], "$.calendar": ["is_leap_year"]}, + data_items={"is_leap_year": (BASELINE_0, "calendar/is_leap_year")}, + ) + + class RMDRule(RuleDefinitionListIndexedBase): + def __init__(self): + super(Section11Rule8.RMDRule, self).__init__( + rmds_used=produce_ruleset_model_description( + USER=False, + BASELINE_0=True, + PROPOSED=True, + ), + index_rmd=BASELINE_0, + each_rule=Section11Rule8.RMDRule.SWHBATRule(), + ) + + def create_data(self, context, data): + rmd_p = context.PROPOSED + rmd_b = context.BASELINE_0 + is_leap_year_b = data["is_leap_year"] + + num_of_bldg_segment_b = len( + find_all("$.buildings[*].building_segments[*]", rmd_b) + ) + + service_water_heating_uses_p = { + swh_use["id"]: swh_use.get("use", 0.0) + for swh_use in find_all( + "$.buildings[*].building_segments[*].zones[*].spaces[*].service_water_heating_uses[*]", + rmd_p, + ) + } + + swh_equip_type_b = { + swh_equip_id: get_swh_equipment_type(rmd_b, swh_equip_id) + for swh_equip_id in find_all( + "$.service_water_heating_equipment[*].id", rmd_b + ) + } + + swh_bats_and_uses_b = get_swh_components_associated_with_each_swh_bat( + rmd_b, is_leap_year_b + ) + + num_swh_systems_b = { + swh_bat: len(swh_use.swh_distribution) + for swh_bat, swh_use in swh_bats_and_uses_b.items() + } + num_swh_equipment_this_use_b = { + swh_bat: len(swh_use.swh_heating_eq) + for swh_bat, swh_use in swh_bats_and_uses_b.items() + } + + swh_bats_and_uses_p = get_swh_bats_and_swh_use(rmd_p) + + building_area_type_SWH_equip_dict_b = {} + building_area_type_and_uses_p = {} + for bat_type, SWH_Equipment_Associations in swh_bats_and_uses_b.items(): + building_area_type_SWH_equip_dict_b[bat_type] = {} + building_area_type_SWH_equip_dict_b[bat_type]["id"] = bat_type + building_area_type_SWH_equip_dict_b[bat_type][ + "SWH_Equipment_Associations" + ] = SWH_Equipment_Associations + + building_area_type_and_uses_p[bat_type] = {} + building_area_type_and_uses_p[bat_type]["id"] = bat_type + building_area_type_and_uses_p[bat_type][ + "swh_bats_and_uses_p" + ] = swh_bats_and_uses_p[bat_type] + + return { + "num_of_bldg_segment_b": num_of_bldg_segment_b, + "num_swh_systems_b": num_swh_systems_b, + "num_swh_equipment_this_use_b": num_swh_equipment_this_use_b, + "swh_bats_and_uses_b": swh_bats_and_uses_b, + "service_water_heating_uses_p": service_water_heating_uses_p, + "swh_equip_type_b": swh_equip_type_b, + "building_area_type_SWH_equip_dict_b": building_area_type_SWH_equip_dict_b, + "building_area_type_and_uses_p": building_area_type_and_uses_p, + } + + def create_context_list(self, context, data=None): + building_area_type_SWH_equip_dict_b = data[ + "building_area_type_SWH_equip_dict_b" + ] + building_area_type_and_uses_p = data["building_area_type_and_uses_p"] + + return [ + produce_ruleset_model_description( + USER=False, + BASELINE_0=building_area_type_SWH_equip_dict_b[bat_type], + PROPOSED=building_area_type_and_uses_p[bat_type], + ) + for bat_type, SWH_Equipment_Associations in building_area_type_SWH_equip_dict_b.items() + ] + + class SWHBATRule(RuleDefinitionBase): + def __init__(self): + super(Section11Rule8.RMDRule.SWHBATRule, self).__init__( + rmds_used=produce_ruleset_model_description( + USER=False, BASELINE_0=True, PROPOSED=True + ), + ) + + def is_applicable(self, context, data=None): + building_area_type_and_uses_p_b = context.PROPOSED + service_water_heating_uses_p = data["service_water_heating_uses_p"] + + return all( + [ + service_water_heating_uses_p[swh_uses_id_p] > 0.0 + for swh_uses_id_p in building_area_type_and_uses_p_b[ + "swh_bats_and_uses_p" + ] + ] + ) + + def get_calc_vals(self, context, data=None): + swh_bats_and_equip_dict_this_use = context.BASELINE_0 + num_of_bldg_segment_b = data["num_of_bldg_segment_b"] + swh_bats_and_uses_b = data["swh_bats_and_uses_b"] + + swh_bat_b = swh_bats_and_equip_dict_this_use["id"] + + num_swh_systems_b = data["num_swh_systems_b"][swh_bat_b] + num_swh_equipment_this_use_b = data["num_swh_equipment_this_use_b"][ + swh_bat_b + ] + + is_referenced_in_other_bats = False + if num_swh_systems_b == 1: + swh_dist_id = swh_bats_and_uses_b[swh_bat_b].swh_distribution[0] + for other_swh_bat in swh_bats_and_uses_b: + if other_swh_bat != swh_bat_b: + if ( + swh_dist_id + in swh_bats_and_uses_b[swh_bat_b].swh_distribution + ): + is_referenced_in_other_bats = True + + if swh_bat_b == SERVICE_WATER_HEATING_SPACE.ALL_OTHERS: + multiple_segments_with_bat_other = False + + return { + "num_of_bldg_segment_b": num_of_bldg_segment_b, + "is_referenced_in_other_bats": is_referenced_in_other_bats, + "multiple_segments_with_bat_other": multiple_segments_with_bat_other, + } + + def manual_check_required(self, context, calc_vals=None, data=None): + shw_bat_b = calc_vals["shw_bat_b"] + multiple_segments_with_bat_other = calc_vals[ + "multiple_segments_with_bat_other" + ] + + return shw_bat_b == "UNDETERMINED" or multiple_segments_with_bat_other + + def get_manual_check_required_msg(self, context, calc_vals=None, data=None): + shw_bat_b = calc_vals["shw_bat_b"] + multiple_segments_with_bat_other = calc_vals[ + "multiple_segments_with_bat_other" + ] + + UNDETERMINED_MSG = "" + if shw_bat_b == "UNDETERMINED": + UNDETERMINED_MSG = CASE3_MSG + elif not multiple_segments_with_bat_other: + UNDETERMINED_MSG = CASE4_MSG + + return UNDETERMINED_MSG + + def rule_check(self, context, calc_vals=None, data=None): + shw_bat = calc_vals["shw_bat"] + num_of_bldg_segment_b = calc_vals["num_of_bldg_segment_b"] + is_referenced_in_other_bats = calc_vals["is_referenced_in_other_bats "] + + return ( + shw_bat == "UNDETERMINED" and num_of_bldg_segment_b == 1 + ) or not is_referenced_in_other_bats diff --git a/rct229/ruletest_engine/ruletest_jsons/scripts/resources/json_pointer_enumerations.json b/rct229/ruletest_engine/ruletest_jsons/scripts/resources/json_pointer_enumerations.json index 5fd892ac51..5f4a101452 100644 --- a/rct229/ruletest_engine/ruletest_jsons/scripts/resources/json_pointer_enumerations.json +++ b/rct229/ruletest_engine/ruletest_jsons/scripts/resources/json_pointer_enumerations.json @@ -25,6 +25,7 @@ "schedules": "ruleset_model_descriptions[0]/schedules", "sensible_cool_capacity": "ruleset_model_descriptions[0]/buildings[0]/building_segments[0]/heating_ventilating_air_conditioning_systems[0]/cooling_system/sensible_cool_capacity", "service_water_heating_distribution_systems": "ruleset_model_descriptions[0]/service_water_heating_distribution_systems", + "service_water_heating_equipment": "ruleset_model_descriptions[0]/service_water_heating_equipment", "service_water_piping":"ruleset_model_descriptions[0]/service_water_heating_distribution_systems[0]/service_water_piping", "service_water_heating_uses":"ruleset_model_descriptions[0]/buildings[0]/building_segments[0]/zones[0]/spaces[0]/service_water_heating_uses", "spaces": "ruleset_model_descriptions[0]/buildings[0]/building_segments[0]/zones[0]/spaces",