From 1bd25efcb5276209ae25536782b7a24bc5af73da Mon Sep 17 00:00:00 2001 From: yunjoonjung Date: Thu, 2 Oct 2025 12:56:51 -0700 Subject: [PATCH 1/5] Initial commit --- .../ashrae9012019/section5/test/rebaseline.py | 103 +++ .../rulesets/ashrae9012022/data/__init__.py | 14 + .../data/ashrae_90_1_table_J_6.json | 148 ++++ .../ashrae9012022/data_fns/table_J_6_fns.py | 33 + .../data_fns/table_J_6_fns_test.py | 29 + .../ashrae9012022/data_fns/table_utils.py | 161 ++++ .../data_fns/table_utils_test.py | 24 + .../ruleset_functions/__init__.py | 0 .../is_chiller_performance_app_j.py | 164 ++++ .../is_chiller_performance_app_j_test.py | 720 ++++++++++++++++++ 10 files changed, 1396 insertions(+) create mode 100644 rct229/rulesets/ashrae9012019/section5/test/rebaseline.py create mode 100644 rct229/rulesets/ashrae9012022/data/__init__.py create mode 100644 rct229/rulesets/ashrae9012022/data/ashrae_90_1_table_J_6.json create mode 100644 rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns.py create mode 100644 rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns_test.py create mode 100644 rct229/rulesets/ashrae9012022/data_fns/table_utils.py create mode 100644 rct229/rulesets/ashrae9012022/data_fns/table_utils_test.py create mode 100644 rct229/rulesets/ashrae9012022/ruleset_functions/__init__.py create mode 100644 rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py create mode 100644 rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py diff --git a/rct229/rulesets/ashrae9012019/section5/test/rebaseline.py b/rct229/rulesets/ashrae9012019/section5/test/rebaseline.py new file mode 100644 index 0000000000..2ad9c19ff9 --- /dev/null +++ b/rct229/rulesets/ashrae9012019/section5/test/rebaseline.py @@ -0,0 +1,103 @@ +import pandas as pd + + +def filter_by_conditions(df, conditions): + """Filter DataFrame by multiple conditions""" + query_parts = [] + for col, val in conditions.items(): + if val is not None: + if isinstance(val, str): + query_parts.append(f'{col} == "{val}"') + else: + query_parts.append(f"{col} == {val}") + + query_str = " & ".join(query_parts) + if query_str: + return df.query(query_str) + else: + return df + + +def recalculate_permit_based_average( + filtered_data, climate_zones, level_number, credit_name, bldg_type +): + # Define column names + cz_col = ["Credit", "CZ1", "CZ2", "CZ3", "CZ4", "CZ4C", "CZ5", "CZ6", "CZ7", "CZ8"] + result_df = pd.DataFrame(columns=cz_col) + new_row_template = {cz: None for cz in cz_col} + + for level_no in level_number: + new_row = new_row_template.copy() + if "baseline" in credit_name: + new_row["Credit"] = "baseline" + else: + new_row["Credit"] = f"{credit_name}_level{level_no}" + + for cz in climate_zones.keys(): + data = filtered_data[bldg_type][cz][str(level_no)] + new_row[cz] = ( + data["Total.Site.EUI.kBtu_ft2"] * data["permits"] + ).sum() / data["permits"].sum() + + new_row_df = pd.DataFrame([new_row]) + result_df = pd.concat([result_df, new_row_df], ignore_index=True) + + return result_df + + +def calc_agg_value_by_climate_zone(credit_name: str, level_number: list[int]): + level_number = sorted(level_number) + + # Read credit csv + credit = pd.read_csv(f"./{credit_name}.csv", delimiter=",") + + # Define climate zones and moisture regimes + climate_zones = { + "CZ1": {"climate_zone": "Climate Zone 1", "moisture_regime": None}, + "CZ2": {"climate_zone": "Climate Zone 2", "moisture_regime": None}, + "CZ3": {"climate_zone": "Climate Zone 3", "moisture_regime": None}, + "CZ4": {"climate_zone": "Climate Zone 4", "moisture_regime": None}, + "CZ4C": {"climate_zone": "Climate Zone 4", "moisture_regime": "Marine"}, + "CZ5": {"climate_zone": "Climate Zone 5", "moisture_regime": None}, + "CZ6": {"climate_zone": "Climate Zone 6", "moisture_regime": None}, + "CZ7": {"climate_zone": "Climate Zone 7", "moisture_regime": None}, + "CZ8": {"climate_zone": "Climate Zone 8", "moisture_regime": None}, + } + + # Define building types + bldg_types = ["all", "Single-Family", "Multifamily"] + + # Filter credit data by level, building type, and climate zone + filtered_data = {} + for bldg_type in bldg_types: + filtered_data[bldg_type] = {} + credit_bldg_type = ( + credit if bldg_type == "all" else credit[credit["bldg_type"] == bldg_type] + ) + + for cz, conditions in climate_zones.items(): + filtered_data[bldg_type][cz] = {} + filtered_cz = filter_by_conditions(credit_bldg_type, conditions)[ + ["level_0", "Total.Site.EUI.kBtu_ft2", "permits"] + ] + + for level_no in level_number: + filtered_data[bldg_type][cz][str(level_no)] = filtered_cz[ + filtered_cz["level_0"] == level_no + ][["Total.Site.EUI.kBtu_ft2", "permits"]] + + # Recalculate permit-based average for all building types + all_bldg_type_df = recalculate_permit_based_average( + filtered_data, climate_zones, level_number, credit_name, "all" + ) + SF_df = recalculate_permit_based_average( + filtered_data, climate_zones, level_number, credit_name, "Single-Family" + ) + MF_df = recalculate_permit_based_average( + filtered_data, climate_zones, level_number, credit_name, "Multifamily" + ) + + return {"all_bldg_type_df": all_bldg_type_df, "SF_df": SF_df, "MF_df": MF_df} + + +test = calc_agg_value_by_climate_zone("filtered_baseline", [0]) diff --git a/rct229/rulesets/ashrae9012022/data/__init__.py b/rct229/rulesets/ashrae9012022/data/__init__.py new file mode 100644 index 0000000000..358e185ded --- /dev/null +++ b/rct229/rulesets/ashrae9012022/data/__init__.py @@ -0,0 +1,14 @@ +import glob +import json +from os.path import basename, dirname, join + +# A dictionary that will contain all the data in this folder +data = {} + +# Get a list of the JSON file names in this folder +_json_paths = glob.glob(join(dirname(__file__), "*.json")) + +# Import each JSON file and store the contents in data +for json_path in _json_paths: + with open(json_path) as file: + data[basename(json_path)[:-5]] = json.load(file) diff --git a/rct229/rulesets/ashrae9012022/data/ashrae_90_1_table_J_6.json b/rct229/rulesets/ashrae9012022/data/ashrae_90_1_table_J_6.json new file mode 100644 index 0000000000..14b9078f81 --- /dev/null +++ b/rct229/rulesets/ashrae9012022/data/ashrae_90_1_table_J_6.json @@ -0,0 +1,148 @@ +{ + "performance_curve_coefficient": [ + { + "Set": "V", + "EIR-f-T": [ + 2.044998, + -0.047515, + 0.000505, + -0.008787, + 0.000175, + -0.00012 + ], + "CAP-f-T": [ + -0.981909, + 0.076674, + -0.000687, + 0.00392, + -0.000058, + 0.000006 + ], + "EIR-f-PLR": [ + 0.276037, + 0.253577, + 0.466353 + ] + }, + { + "Set": "X", + "EIR-f-T": [ + 1.037805, + -0.024695, + 0.000329, + 0.00313, + 0.000102, + -0.000159 + ], + "CAP-f-T": [ + -0.683858, + 0.065283, + -0.000602, + 0.002347, + -0.00005, + 0.000036 + ], + "EIR-f-PLR": [ + 0.250801, + 0.345915, + 0.399138 + ] + }, + { + "Set": "Y", + "EIR-f-T": [ + 1.188945, + -0.039426, + 0.000413, + 0.012888, + 0.000002, + -0.000098 + ], + "CAP-f-T": [ + -0.160681, + 0.04439, + -0.000429, + 0.001024, + -0.000035, + 0.000055 + ], + "EIR-f-PLR": [ + 0.320097, + 0.074356, + 0.602938 + ] + }, + { + "Set": "Z", + "EIR-f-T": [ + 0.857485, + -0.036148, + 0.000314, + 0.022356, + -0.000108, + 0.000001 + ], + "CAP-f-T": [ + -0.061958, + 0.054739, + -0.00055, + -0.008177, + 0.000005, + 0.000101 + ], + "EIR-f-PLR": [ + 0.281669, + 0.202762, + 0.515409 + ] + }, + { + "Set": "AA", + "EIR-f-T": [ + 0.479847, + -0.035964, + 0.000225, + 0.031377, + -0.000183, + 0.000085 + ], + "CAP-f-T": [ + -0.128081, + 0.050459, + -0.000581, + -0.004297, + -0.000049, + 0.0002 + ], + "EIR-f-PLR": [ + 0.339494, + 0.04909, + 0.611582 + ] + }, + { + "Set": "AB", + "EIR-f-T": [ + 0.74721, + -0.038874, + 0.000313, + 0.027638, + -0.000133, + -0.000008 + ], + "CAP-f-T": [ + 0.117208, + 0.04294, + -0.000478, + -0.00393, + -0.000045, + 0.000155 + ], + "EIR-f-PLR": [ + 0.309752, + 0.153649, + 0.536462 + ] + } + ] +} \ No newline at end of file diff --git a/rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns.py b/rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns.py new file mode 100644 index 0000000000..48caf4c3ce --- /dev/null +++ b/rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns.py @@ -0,0 +1,33 @@ +from rct229.rulesets.ashrae9012022.data import data +from rct229.rulesets.ashrae9012022.data_fns.table_utils import find_osstd_table_entry + + +def table_J_6_lookup(Set: str, output_variable: str) -> list[float]: + """Returns the performance curve coefficients as specified in ASHRAE 90.1 Table J-6 + + Parameters + ---------- + Set : str + One of the set specified in Table J-6 ("V", "X", "Y", "Z", "AA", "AB") + output_variable: str + One of the performance curve types ("EIR-f-T", "CAP-f-T", "EIR-f_PLR") + + Returns + ------- + list of floats + + """ + + if Set not in ("V", "X", "Y", "Z", "AA", "AB"): + return None + + if output_variable not in ("EIR-f-T", "CAP-f-T", "EIR-f-PLR"): + return None + + osstd_entry = find_osstd_table_entry( + [("Set", Set)], + osstd_table=data["ashrae_90_1_table_J_6"], + ) + performance_coefficient = osstd_entry[output_variable] + + return performance_coefficient diff --git a/rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns_test.py b/rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns_test.py new file mode 100644 index 0000000000..f91819fccc --- /dev/null +++ b/rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns_test.py @@ -0,0 +1,29 @@ +from rct229.rulesets.ashrae9012022.data_fns.table_J_6_fns import ( + table_J_6_lookup, +) + + +def test__table_J_6_X_EIR_f_T(): + assert table_J_6_lookup("X", "EIR-f-T") == [ + 1.037805, + -0.024695, + 0.000329, + 0.00313, + 0.000102, + -0.000159, + ] + + +def test__table_J_6_Y_CAP_f_T(): + assert table_J_6_lookup("Y", "CAP-f-T") == [ + -0.160681, + 0.04439, + -0.000429, + 0.001024, + -0.000035, + 0.000055, + ] + + +def test__table_J_6_AA_EIR_f_PLR(): + assert table_J_6_lookup("AA", "EIR-f_PLR") == [0.339494, 0.04909, 0.611582] diff --git a/rct229/rulesets/ashrae9012022/data_fns/table_utils.py b/rct229/rulesets/ashrae9012022/data_fns/table_utils.py new file mode 100644 index 0000000000..8de760f06f --- /dev/null +++ b/rct229/rulesets/ashrae9012022/data_fns/table_utils.py @@ -0,0 +1,161 @@ +from rct229.schema.schema_enums import SchemaEnums + + +def find_osstd_table_entry(match_field_name_value_pairs, osstd_table): + """Find a specific entry in an OSSTD table + + This takes advantage of the consistent structure across all the OSSTD + JSON files. Each file contains a dictionary with a single key. The value + associated with that key is a list of dictionaries. This function searches + through those inner dictionaries to find one that matches all the + provided + match_field_name: match_field_value + pairs. + + Parameters + ---------- + match_field_name_value_pairs : list of 2-tuples + List of (match_field_name, match_field_value) tuples + osstd_table : dict + The OSSTD table data as loaded from its JSON file + + Returns + ------- + dict + The matching table entry + """ + assert type(osstd_table) is dict + + keys = list(osstd_table) + assert len(keys) == 1 + + data_list = osstd_table[keys[0]] + assert type(data_list) is list + + matching_entries = list( + filter( + lambda entry: all( + [ + entry[match_field_name] == match_field_value + for ( + match_field_name, + match_field_value, + ) in match_field_name_value_pairs + ] + ), + data_list, + ) + ) + assert ( + len(matching_entries) == 1 + ), f"Not exactly one match in OSSTD for {match_field_name_value_pairs}, found {len(matching_entries)} instead." + + matching_entry = matching_entries[0] + assert type(matching_entry) is dict + + return matching_entries[0] + + +def find_osstd_table_entries(match_field_name_value_pairs, osstd_table: dict): + """Find specific entries in an OSSTD table + + This takes advantage of the consistent structure accross all the OSSTD + JSON files. Each file contains a dictionary with a single key. The value + associated with that key is a list of dictionaries. This function searches + through those inner dictionaries to find all entries that match all the + provided match_field_name_value_pairs + + Parameters + ---------- + match_field_name_value_pairs : list of 2-tuples + List of (match_field_name, match_field_value) tuples + osstd_table : dict + The OSSTD table data as loaded from its JSON file + + Returns + ------- + list + The matching table entries + """ + assert type(osstd_table) is dict + + keys = list(osstd_table) + assert len(keys) == 1 + + data_list = osstd_table[keys[0]] + assert type(data_list) is list + + matching_entries = list( + filter( + lambda entry: all( + [ + entry[match_field_name] == match_field_value + for ( + match_field_name, + match_field_value, + ) in match_field_name_value_pairs + ] + ), + data_list, + ) + ) + + assert len(matching_entries) > 0, "No entries found in the table" + + for matching_entry in matching_entries: + assert type(matching_entry) is dict + + return matching_entries + + +def check_enumeration_to_osstd_match_field_value_map( + match_field_name, + enum_type, + osstd_table, + enumeration_to_match_field_value_map, + exclude_enum_names=[], +): + """A sanity check for an enumeration to OSSTD match field value map + + Checks that + 1. Each enumerated value (except for those in exclude_enum_names) is a + key in the map + 2. There is actually a matching entry in the underlying OSSTD table + corresponding to each enumated value + + This function only applies to OSSTD tables that have a field name, + match_field_name, whose values are unique in the OSSTD table. + + Parameters + ---------- + match_field_name : str + Field name for the OSSTD lookup + enum_type : str + The name of an enumeration from the ruleset + osstd_table : dict + An OSSTD table + enumeration_to_match_field_value_map : dict + The map to be checked + exclude_enum_names: list + A list of strings of the enumeration names to be excluded from the check + For example, "NONE" may be used as a flag that is not intended to be + looked up. + + Returns + ------- + dict + The matching table entry + """ + for e in SchemaEnums.schema_enums[enum_type].get_list(): + if e in exclude_enum_names: + continue + + # Make sure each space type in the enumeration is in our map + match_field_value = enumeration_to_match_field_value_map[e] + assert match_field_value is not None, f"{e} is not in the map" + + # Make sure there is a corresponding entry in the OSSTD table + # find_osstd_table_entry() will throw if not + entry = find_osstd_table_entry( + [(match_field_name, match_field_value)], osstd_table + ) diff --git a/rct229/rulesets/ashrae9012022/data_fns/table_utils_test.py b/rct229/rulesets/ashrae9012022/data_fns/table_utils_test.py new file mode 100644 index 0000000000..1c60b4671a --- /dev/null +++ b/rct229/rulesets/ashrae9012022/data_fns/table_utils_test.py @@ -0,0 +1,24 @@ +from rct229.rulesets.ashrae9012019.data_fns.table_utils import find_osstd_table_entry + +FAKE_OSSTD_TABLE = { + "fake_list": [ + { + "match_field": 1, + "other_field": "some_value", + }, + { + "match_field": 2, + "other_field": "some_other_value", + }, + ] +} + + +def test__find_osstd_table_entry__with_single_pair(): + assert find_osstd_table_entry( + [("match_field", 2)], + osstd_table=FAKE_OSSTD_TABLE, + ) == { + "match_field": 2, + "other_field": "some_other_value", + } diff --git a/rct229/rulesets/ashrae9012022/ruleset_functions/__init__.py b/rct229/rulesets/ashrae9012022/ruleset_functions/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py new file mode 100644 index 0000000000..e6baa67c5c --- /dev/null +++ b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py @@ -0,0 +1,164 @@ +from rct229.rulesets.ashrae9012022.data_fns.table_J_6_fns import table_J_6_lookup +from rct229.schema.config import ureg +from rct229.schema.schema_enums import SchemaEnums +from rct229.utils.assertions import getattr_ +from rct229.utils.std_comparisons import std_equal_with_precision + +ENERGY_SOURCE = SchemaEnums.schema_enums["EnergySourceOptions"] +CHILLER_COMPRESSOR = SchemaEnums.schema_enums["ChillerCompressorOptions"] + +EXPECTED_VALIDATION_PLR = [0.25, 0.5, 0.75, 1] +EXPECTED_CHWT_TEMPS = [39, 45, 50, 55] +EXPECTED_ECWT_TEMPS = [60, 104, 85, 72.5, 97.5] + + +def is_chiller_performance_app_j(chiller: dict) -> bool: + """ + Evaluates whether the chiller performance curves align with the sets of performance curves specified in Appendix J of ASHRAE 90.1-2022 Appendix G. + :param chiller: + """ + + compressor_type = getattr_(chiller, "chillers", "compressor_type") + rated_capacity = getattr_(chiller, "chillers", "rated_capacity") + if compressor_type == CHILLER_COMPRESSOR.CENTRIFUGAL: + if rated_capacity < 150 * ureg("ton"): + curve_set = "Z" + elif 150 * ureg("ton") <= rated_capacity < 300 * ureg("ton"): + curve_set = "AA" + else: + curve_set = "AB" + elif compressor_type in ( + CHILLER_COMPRESSOR.POSITIVE_DISPLACEMENT, + CHILLER_COMPRESSOR.SCROLL, + CHILLER_COMPRESSOR.SCREW, + ): + if rated_capacity < 150 * ureg("ton"): + curve_set = "V" + elif rated_capacity > 300 * ureg("ton"): + curve_set = "Y" + else: + curve_set = "X" + else: + curve_set = None + + if curve_set is not None: + rated_power = ( + rated_capacity / chiller["full_load_efficiency"] + if chiller.get("full_load_efficiency") + else 0.0 + ) + + eir_f_t_coefficients = table_J_6_lookup(curve_set, "EIR-f-T") + cap_f_t_coefficients = table_J_6_lookup(curve_set, "CAP-f-T") + plr_coefficients = table_J_6_lookup(curve_set, "EIR-f-PLR") + + capacity_validation_pts_dict = {} + for capacity_validation_point in chiller.get("capacity_operating_points", []): + chilled_water_supply_temp = capacity_validation_point.get( + "chilled_water_supply_temperature", 0.0 * ureg("degC") + ).to("degF") + condenser_temp = capacity_validation_point.get( + "condenser_temperature", 0.0 * ureg("degC") + ).to("degF") + + dict_key = f"{int(round(chilled_water_supply_temp.m, 1))}, {int(round(condenser_temp.m, 1))}" + capacity_validation_pts_dict[dict_key] = capacity_validation_point.get( + "capacity" + ) + + power_validation_pts_dict = {} + for power_validation_point in chiller.get("power_operating_points", []): + chilled_water_supply_temp = power_validation_point.get( + "chilled_water_supply_temperature", 0.0 * ureg("degC") + ).to("degF") + condenser_temp = power_validation_point.get( + "condenser_temperature", 0.0 * ureg("degC") + ).to("degF") + dict_key = f"{int(round(chilled_water_supply_temp.m, 1))}, {int(round(condenser_temp.m, 1))}" + + power_validation_pts_dict.setdefault(dict_key, []) + power_validation_pts_dict[dict_key].append(power_validation_point) + + given_capacities = {} + missing_capacity_validation_points = [] + non_matching_capacity_validation_points = [] + for chwt in EXPECTED_CHWT_TEMPS: + for ecwt in EXPECTED_ECWT_TEMPS: + dict_key = f"{chwt}, {ecwt}" + if capacity_validation_pts_dict.get(dict_key): + expected_capacity = ( + cap_f_t_coefficients[0] + + cap_f_t_coefficients[1] * chwt + + cap_f_t_coefficients[2] * chwt**2 + + cap_f_t_coefficients[3] * ecwt + + cap_f_t_coefficients[4] * ecwt**2 + + cap_f_t_coefficients[5] * chwt * ecwt + ) * rated_capacity + + given_capacity = capacity_validation_pts_dict[dict_key] + given_capacities[dict_key] = given_capacity + + if not std_equal_with_precision( + given_capacity, expected_capacity, 1 * ureg("W") + ): + non_matching_capacity_validation_points.append( + {"CHWT": chwt, "ECWT": ecwt} + ) + + else: + missing_capacity_validation_points.append( + {"CHWT": chwt, "ECWT": ecwt} + ) + + non_matching_power_validation_points = [] + missing_power_validation_points = [] + for chwt in EXPECTED_CHWT_TEMPS: + for ecwt in EXPECTED_ECWT_TEMPS: + dict_key = f"{chwt}, {ecwt}" + if power_validation_pts_dict.get(dict_key): + given_plrs = [] + for power_validation_point in power_validation_pts_dict[dict_key]: + load = power_validation_point.get("load", 0.0 * ureg("W")) + given_power = power_validation_point.get("result") + plr = load / given_capacities[dict_key] + + if plr in EXPECTED_VALIDATION_PLR: + given_plrs.append(plr) + eir_plr = ( + plr_coefficients[0] + + plr_coefficients[1] * plr + + plr_coefficients[2] * plr**2 + ) + eir_ft = ( + eir_f_t_coefficients[0] + + eir_f_t_coefficients[1] * chwt + + eir_f_t_coefficients[2] * chwt**2 + + eir_f_t_coefficients[3] * ecwt + + eir_f_t_coefficients[4] * ecwt**2 + + eir_f_t_coefficients[5] * chwt * ecwt + ) + + expected_power = ( + given_capacity[dict_key] + * eir_ft + * eir_plr + * rated_power + / rated_capacity + ) + + if expected_power == given_power: + missing_power_validation_points.append( + {"CHWT": chwt, "ECWT": ecwt, "PLR": "ALL"} + ) + else: + missing_power_validation_points.append( + {"CHWT": chwt, "ECWT": ecwt, "PLR": plr} + ) + + return ( + len(non_matching_capacity_validation_points) + == len(missing_capacity_validation_points) + == len(non_matching_power_validation_points) + == len(missing_power_validation_points) + == 0 + ) diff --git a/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py new file mode 100644 index 0000000000..eef2da070e --- /dev/null +++ b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py @@ -0,0 +1,720 @@ +from rct229.rulesets.ashrae9012022.ruleset_functions.is_chiller_performance_app_j import ( + is_chiller_performance_app_j, +) +from rct229.schema.schema_utils import quantify_rmd +from rct229.schema.validate import schema_validate_rpd + +TEST_RMD = { + "id": "RMD 1", + "buildings": [ + { + "id": "Building 1", + "building_segments": [ + { + "id": "Building Segment 1", + "zones": [ + { + "id": "Thermal Zone 1", + "terminals": [ + { + "id": "VAV Air Terminal 1", + "is_supply_ducted": True, + "type": "VARIABLE_AIR_VOLUME", + "served_by_heating_ventilating_air_conditioning_system": "System 7", + "heating_source": "HOT_WATER", + "heating_from_loop": "Boiler Loop 1", + } + ], + }, + { + "id": "Thermal Zone 2", + "terminals": [ + { + "id": "VAV Air Terminal 2", + "is_supply_ducted": True, + "type": "VARIABLE_AIR_VOLUME", + "served_by_heating_ventilating_air_conditioning_system": "System 7", + "heating_source": "HOT_WATER", + "heating_from_loop": "Boiler Loop 1", + } + ], + }, + ], + "heating_ventilating_air_conditioning_systems": [ + { + "id": "System 7", + "cooling_system": { + "id": "CHW Coil 1", + "type": "FLUID_LOOP", + "chilled_water_loop": "Secondary CHW Loop 1", + }, + "preheat_system": { + "id": "Preheat Coil 1", + "type": "FLUID_LOOP", + "hot_water_loop": "Boiler Loop 1", + }, + "fan_system": { + "id": "VAV Fan System 1", + "fan_control": "VARIABLE_SPEED_DRIVE", + "supply_fans": [{"id": "Supply Fan 1"}], + "return_fans": [{"id": "Return Fan 1"}], + }, + } + ], + } + ], + } + ], + "boilers": [ + {"id": "Boiler 1", "loop": "Boiler Loop 1", "energy_source_type": "NATURAL_GAS"} + ], + "chillers": [ + { + "id": "Chiller 1", + "cooling_loop": "Chiller Loop 1", + "compressor_type": "CENTRIFUGAL", + "rated_capacity": 527550.0, + "condensing_loop": "Condenser Loop 1", + "efficiency_metric_values": [5.5], + "efficiency_metric_types": ["FULL_LOAD_EFFICIENCY_RATED"], + "capacity_operating_points": [ + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 15.5555555555556, + "capacity": 522221.2, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 22.500000000000057, + "capacity": 360333, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 29.444444444444457, + "capacity": 349216, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 36.388888888888914, + "capacity": 336763, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 40.00000000000006, + "capacity": 417000.315, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 15.5555555555556, + "capacity": 358539, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 22.500000000000057, + "capacity": 348758, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 29.444444444444457, + "capacity": 337641, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 36.388888888888914, + "capacity": 325188, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 40.00000000000006, + "capacity": 317423, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 15.5555555555556, + "capacity": 345663, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 22.500000000000057, + "capacity": 335882, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 29.444444444444457, + "capacity": 324765, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 36.388888888888914, + "capacity": 312312, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 40.00000000000006, + "capacity": 304547, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 15.5555555555556, + "capacity": 331486, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 22.500000000000057, + "capacity": 321705, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 29.444444444444457, + "capacity": 310588, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 36.388888888888914, + "capacity": 298135, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 40.00000000000006, + "capacity": 290370, + }, + ], + "power_operating_points": [ + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 15.5555555555556, + "load": 87925.0, + "power": 55019, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 15.5555555555556, + "load": 175850.0, + "power": 77828, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 15.5555555555556, + "load": 263775.0, + "power": 100637, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 15.5555555555556, + "load": 351700.0, + "power": 123446, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 22.500000000000057, + "load": 87925.0, + "power": 81486, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 22.500000000000057, + "load": 175850.0, + "power": 115280, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 22.500000000000057, + "load": 263775.0, + "power": 149074, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 22.500000000000057, + "load": 351700.0, + "power": 182868, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 29.444444444444457, + "load": 87925.0, + "power": 107867, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 29.444444444444457, + "load": 175850.0, + "power": 152616, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 29.444444444444457, + "load": 263775.0, + "power": 197365, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 29.444444444444457, + "load": 351700.0, + "power": 242114, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 36.388888888888914, + "load": 87925.0, + "power": 134316, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 36.388888888888914, + "load": 175850.0, + "power": 190020, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 36.388888888888914, + "load": 263775.0, + "power": 245724, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 36.388888888888914, + "load": 351700.0, + "power": 301428, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 40.00000000000006, + "load": 87925.0, + "power": 151006, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 40.00000000000006, + "load": 175850.0, + "power": 213695, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 40.00000000000006, + "load": 263775.0, + "power": 276384, + }, + { + "chilled_water_supply_temperature": 3.888888888888914, + "condenser_temperature": 40.00000000000006, + "load": 351700.0, + "power": 339073, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 15.5555555555556, + "load": 87925.0, + "power": 61435, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 15.5555555555556, + "load": 175850.0, + "power": 86959, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 15.5555555555556, + "load": 263775.0, + "power": 112483, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 15.5555555555556, + "load": 351700.0, + "power": 138007, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 22.500000000000057, + "load": 87925.0, + "power": 82089, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 22.500000000000057, + "load": 175850.0, + "power": 116199, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 22.500000000000057, + "load": 263775.0, + "power": 150309, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 22.500000000000057, + "load": 351700.0, + "power": 184419, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 29.444444444444457, + "load": 87925.0, + "power": 102780, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 29.444444444444457, + "load": 175850.0, + "power": 145487, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 29.444444444444457, + "load": 263775.0, + "power": 188194, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 29.444444444444457, + "load": 351700.0, + "power": 230901, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 36.388888888888914, + "load": 87925.0, + "power": 123508, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 36.388888888888914, + "load": 175850.0, + "power": 174812, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 36.388888888888914, + "load": 263775.0, + "power": 226116, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 36.388888888888914, + "load": 351700.0, + "power": 277420, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 40.00000000000006, + "load": 87925.0, + "power": 136670, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 40.00000000000006, + "load": 175850.0, + "power": 193502, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 40.00000000000006, + "load": 263775.0, + "power": 250334, + }, + { + "chilled_water_supply_temperature": 7.222222222222285, + "condenser_temperature": 40.00000000000006, + "load": 351700.0, + "power": 307166, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 15.5555555555556, + "load": 87925.0, + "power": 71585, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 15.5555555555556, + "load": 175850.0, + "power": 101313, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 15.5555555555556, + "load": 263775.0, + "power": 131041, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 15.5555555555556, + "load": 351700.0, + "power": 160769, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 22.500000000000057, + "load": 87925.0, + "power": 89197, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 22.500000000000057, + "load": 175850.0, + "power": 126234, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 22.500000000000057, + "load": 263775.0, + "power": 163271, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 22.500000000000057, + "load": 351700.0, + "power": 200308, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 29.444444444444457, + "load": 87925.0, + "power": 106846, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 29.444444444444457, + "load": 175850.0, + "power": 151193, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 29.444444444444457, + "load": 263775.0, + "power": 195540, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 29.444444444444457, + "load": 351700.0, + "power": 239887, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 36.388888888888914, + "load": 87925.0, + "power": 124532, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 36.388888888888914, + "load": 175850.0, + "power": 176189, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 36.388888888888914, + "load": 263775.0, + "power": 227846, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 36.388888888888914, + "load": 351700.0, + "power": 279503, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 40.00000000000006, + "load": 87925.0, + "power": 135953, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 40.00000000000006, + "load": 175850.0, + "power": 192407, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 40.00000000000006, + "load": 263775.0, + "power": 248861, + }, + { + "chilled_water_supply_temperature": 10.000000000000057, + "condenser_temperature": 40.00000000000006, + "load": 351700.0, + "power": 305315, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 15.5555555555556, + "load": 87925.0, + "power": 81472, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 15.5555555555556, + "load": 175850.0, + "power": 115332, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 15.5555555555556, + "load": 263775.0, + "power": 149192, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 15.5555555555556, + "load": 351700.0, + "power": 183052, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 22.500000000000057, + "load": 87925.0, + "power": 96456, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 22.500000000000057, + "load": 175850.0, + "power": 136508, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 22.500000000000057, + "load": 263775.0, + "power": 176560, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 22.500000000000057, + "load": 351700.0, + "power": 216612, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 29.444444444444457, + "load": 87925.0, + "power": 111478, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 29.444444444444457, + "load": 175850.0, + "power": 157722, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 29.444444444444457, + "load": 263775.0, + "power": 203966, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 29.444444444444457, + "load": 351700.0, + "power": 250210, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 36.388888888888914, + "load": 87925.0, + "power": 126537, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 36.388888888888914, + "load": 175850.0, + "power": 179074, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 36.388888888888914, + "load": 263775.0, + "power": 231611, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 36.388888888888914, + "load": 351700.0, + "power": 284148, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 40.00000000000006, + "load": 87925.0, + "power": 136465, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 40.00000000000006, + "load": 175850.0, + "power": 193186, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 40.00000000000006, + "load": 263775.0, + "power": 249907, + }, + { + "chilled_water_supply_temperature": 12.777777777777828, + "condenser_temperature": 40.00000000000006, + "load": 351700.0, + "power": 306628, + }, + ], + } + ], + "pumps": [ + { + "id": "Boiler Pump 1", + "loop_or_piping": "Boiler Loop 1", + "speed_control": "FIXED_SPEED", + }, + { + "id": "Chiller Pump 1", + "loop_or_piping": "Chiller Loop 1", + "speed_control": "FIXED_SPEED", + }, + { + "id": "Secondary CHW Pump", + "loop_or_piping": "Secondary CHW Loop 1", + "speed_control": "VARIABLE_SPEED", + }, + ], + "fluid_loops": [ + {"id": "Boiler Loop 1", "type": "HEATING"}, + { + "id": "Chiller Loop 1", + "type": "COOLING", + "child_loops": [{"id": "Secondary CHW Loop 1", "type": "COOLING"}], + }, + {"id": "Condenser Loop 1", "type": "CONDENSER"}, + ], + "heat_rejections": [{"id": "Heat Rejection 1", "loop": "Condenser Loop 1"}], + "type": "BASELINE_0", +} + +TEST_RMD_12 = { + "id": "229_01", + "ruleset_model_descriptions": [TEST_RMD], + "metadata": { + "schema_author": "ASHRAE SPC 229 Schema Working Group", + "schema_name": "Ruleset Evaluation Schema", + "schema_version": "0.1.3", + "author": "author_example", + "description": "description_example", + "time_of_creation": "2024-02-12T09:00Z", + }, +} + +TEST_CHILLER = quantify_rmd(TEST_RMD_12)["ruleset_model_descriptions"][0]["chillers"][0] + + +def test__TEST_RPD__is_valid(): + schema_validation_result = schema_validate_rpd(TEST_RMD_12) + assert schema_validation_result[ + "passed" + ], f"Schema error: {schema_validation_result['error']}" + + +def test__get_hvac_zone_list_w_area_dict(): + assert is_chiller_performance_app_j(TEST_CHILLER) is True From 8b4faf3466e75784ca25ea177eb3937b61d3ffa0 Mon Sep 17 00:00:00 2001 From: yunjoonjung Date: Mon, 13 Oct 2025 17:59:48 -0700 Subject: [PATCH 2/5] Updated fn logic --- .../is_chiller_performance_app_j.py | 70 +- .../is_chiller_performance_app_j_test.py | 642 +++--------------- 2 files changed, 154 insertions(+), 558 deletions(-) diff --git a/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py index e6baa67c5c..dfdc4b6212 100644 --- a/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py +++ b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py @@ -7,15 +7,26 @@ ENERGY_SOURCE = SchemaEnums.schema_enums["EnergySourceOptions"] CHILLER_COMPRESSOR = SchemaEnums.schema_enums["ChillerCompressorOptions"] -EXPECTED_VALIDATION_PLR = [0.25, 0.5, 0.75, 1] -EXPECTED_CHWT_TEMPS = [39, 45, 50, 55] -EXPECTED_ECWT_TEMPS = [60, 104, 85, 72.5, 97.5] +EXPECTED_VALIDATION_PLR = [0.25, 0.50, 0.75, 1.00] +EXPECTED_CHILLED_WATER_TEMPS = [39, 45, 50, 55] +EXPECTED_ENTERING_CONDENSER_WATER_TEMPS = [60, 104, 85, 72.5, 97.5] def is_chiller_performance_app_j(chiller: dict) -> bool: """ Evaluates whether the chiller performance curves align with the sets of performance curves specified in Appendix J of ASHRAE 90.1-2022 Appendix G. - :param chiller: + + Parameters + ---------- + chiller: dict + The chiller object containing all relevant data for the chiller to be validated against the performance curves in Appendix J of ASHRAE 90.1-2022. + This includes the rated capacity, full load efficiency (COP), compressor type, and the lists of capacity and power validation points. + + Returns + ------- + bool + boolean value indicating whether the chiller performance validation passed or failed. + """ compressor_type = getattr_(chiller, "chillers", "compressor_type") @@ -44,7 +55,7 @@ def is_chiller_performance_app_j(chiller: dict) -> bool: if curve_set is not None: rated_power = ( rated_capacity / chiller["full_load_efficiency"] - if chiller.get("full_load_efficiency") + if getattr_(chiller, "chillers", "full_load_efficiency") > 0.0 else 0.0 ) @@ -63,7 +74,7 @@ def is_chiller_performance_app_j(chiller: dict) -> bool: dict_key = f"{int(round(chilled_water_supply_temp.m, 1))}, {int(round(condenser_temp.m, 1))}" capacity_validation_pts_dict[dict_key] = capacity_validation_point.get( - "capacity" + "capacity", 0.0 * ureg("W") ) power_validation_pts_dict = {} @@ -82,8 +93,8 @@ def is_chiller_performance_app_j(chiller: dict) -> bool: given_capacities = {} missing_capacity_validation_points = [] non_matching_capacity_validation_points = [] - for chwt in EXPECTED_CHWT_TEMPS: - for ecwt in EXPECTED_ECWT_TEMPS: + for chwt in EXPECTED_CHILLED_WATER_TEMPS: + for ecwt in EXPECTED_ENTERING_CONDENSER_WATER_TEMPS: dict_key = f"{chwt}, {ecwt}" if capacity_validation_pts_dict.get(dict_key): expected_capacity = ( @@ -104,7 +115,6 @@ def is_chiller_performance_app_j(chiller: dict) -> bool: non_matching_capacity_validation_points.append( {"CHWT": chwt, "ECWT": ecwt} ) - else: missing_capacity_validation_points.append( {"CHWT": chwt, "ECWT": ecwt} @@ -112,17 +122,28 @@ def is_chiller_performance_app_j(chiller: dict) -> bool: non_matching_power_validation_points = [] missing_power_validation_points = [] - for chwt in EXPECTED_CHWT_TEMPS: - for ecwt in EXPECTED_ECWT_TEMPS: + for chwt in EXPECTED_CHILLED_WATER_TEMPS: + for ecwt in EXPECTED_ENTERING_CONDENSER_WATER_TEMPS: dict_key = f"{chwt}, {ecwt}" if power_validation_pts_dict.get(dict_key): given_plrs = [] for power_validation_point in power_validation_pts_dict[dict_key]: load = power_validation_point.get("load", 0.0 * ureg("W")) - given_power = power_validation_point.get("result") - plr = load / given_capacities[dict_key] + given_power = power_validation_point.get( + "result", 0.0 * ureg("W") + ) + plr = ( + load / given_capacities[dict_key] + if given_capacities[dict_key] > 0.0 * ureg("W") + else 0.0 + ) - if plr in EXPECTED_VALIDATION_PLR: + if any( + [ + std_equal_with_precision(plr, expected_plr, 2) + for expected_plr in EXPECTED_VALIDATION_PLR + ] + ): given_plrs.append(plr) eir_plr = ( plr_coefficients[0] @@ -137,23 +158,28 @@ def is_chiller_performance_app_j(chiller: dict) -> bool: + eir_f_t_coefficients[4] * ecwt**2 + eir_f_t_coefficients[5] * chwt * ecwt ) - expected_power = ( - given_capacity[dict_key] + given_capacities[dict_key] * eir_ft * eir_plr * rated_power / rated_capacity ) - if expected_power == given_power: - missing_power_validation_points.append( + if not std_equal_with_precision( + given_power, expected_power, 1 * ureg("W") + ): + non_matching_power_validation_points.append( {"CHWT": chwt, "ECWT": ecwt, "PLR": "ALL"} ) - else: - missing_power_validation_points.append( - {"CHWT": chwt, "ECWT": ecwt, "PLR": plr} - ) + else: + missing_power_validation_points.append( + {"CHWT": chwt, "ECWT": ecwt, "PLR": plr} + ) + else: + missing_power_validation_points.append( + {"CHWT": chwt, "ECWT": ecwt, "PLR": plr} + ) return ( len(non_matching_capacity_validation_points) diff --git a/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py index eef2da070e..fab01a7b4c 100644 --- a/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py +++ b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py @@ -1,6 +1,7 @@ from rct229.rulesets.ashrae9012022.ruleset_functions.is_chiller_performance_app_j import ( is_chiller_performance_app_j, ) +from rct229.schema.config import ureg from rct229.schema.schema_utils import quantify_rmd from rct229.schema.validate import schema_validate_rpd @@ -74,592 +75,161 @@ "cooling_loop": "Chiller Loop 1", "compressor_type": "CENTRIFUGAL", "rated_capacity": 527550.0, + "full_load_efficiency": 3.2, "condensing_loop": "Condenser Loop 1", "efficiency_metric_values": [5.5], "efficiency_metric_types": ["FULL_LOAD_EFFICIENCY_RATED"], "capacity_operating_points": [ { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 15.5555555555556, + "chilled_water_supply_temperature": (39 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (60 * ureg("degF")).to("degC").m, "capacity": 522221.2, }, { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 22.500000000000057, - "capacity": 360333, + "chilled_water_supply_temperature": (39 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (104 * ureg("degF")).to("degC").m, + "capacity": 417000.3, }, { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 29.444444444444457, - "capacity": 349216, + "chilled_water_supply_temperature": (39 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (85 * ureg("degF")).to("degC").m, + "capacity": 474715.3, }, { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 36.388888888888914, - "capacity": 336763, + "chilled_water_supply_temperature": (39 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, + "capacity": 522221.2, }, { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 40.00000000000006, - "capacity": 417000.315, + "chilled_water_supply_temperature": (39 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, + "capacity": 565443.4, }, { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 15.5555555555556, - "capacity": 358539, + "chilled_water_supply_temperature": (45 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (60 * ureg("degF")).to("degC").m, + "capacity": 565443.4, }, { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 22.500000000000057, - "capacity": 348758, + "chilled_water_supply_temperature": (45 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (104 * ureg("degF")).to("degC").m, + "capacity": 488077.1, }, { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 29.444444444444457, - "capacity": 337641, + "chilled_water_supply_temperature": (45 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (85 * ureg("degF")).to("degC").m, + "capacity": 533764.0, }, { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 36.388888888888914, - "capacity": 325188, + "chilled_water_supply_temperature": (45 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, + "capacity": 522221.2, }, { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 40.00000000000006, - "capacity": 317423, + "chilled_water_supply_temperature": (45 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, + "capacity": 522221.2, }, { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 15.5555555555556, - "capacity": 345663, + "chilled_water_supply_temperature": (50 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (60 * ureg("degF")).to("degC").m, + "capacity": 584604.0, }, { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 22.500000000000057, - "capacity": 335882, + "chilled_water_supply_temperature": (50 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (104 * ureg("degF")).to("degC").m, + "capacity": 530449.9, }, { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 29.444444444444457, - "capacity": 324765, + "chilled_water_supply_temperature": (50 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (85 * ureg("degF")).to("degC").m, + "capacity": 530449.9, }, { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 36.388888888888914, - "capacity": 312312, + "chilled_water_supply_temperature": (50 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, + "capacity": 522221.2, }, { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 40.00000000000006, - "capacity": 304547, + "chilled_water_supply_temperature": (50 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, + "capacity": 566113.4, }, { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 15.5555555555556, - "capacity": 331486, + "chilled_water_supply_temperature": (55 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (60 * ureg("degF")).to("degC").m, + "capacity": 566113.4, }, { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 22.500000000000057, - "capacity": 321705, + "chilled_water_supply_temperature": (55 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (104 * ureg("degF")).to("degC").m, + "capacity": 557497.4, }, { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 29.444444444444457, - "capacity": 310588, + "chilled_water_supply_temperature": (55 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (85 * ureg("degF")).to("degC").m, + "capacity": 583137.4, }, { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 36.388888888888914, - "capacity": 298135, + "chilled_water_supply_temperature": (55 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, + "capacity": 522221.2, }, { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 40.00000000000006, - "capacity": 290370, + "chilled_water_supply_temperature": (55 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, + "capacity": 583137.4, }, ], "power_operating_points": [ { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 15.5555555555556, - "load": 87925.0, + "chilled_water_supply_temperature": (39 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (60 * ureg("degF")).to("degC").m, + "load": 522221.2, "power": 55019, }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 15.5555555555556, - "load": 175850.0, - "power": 77828, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 15.5555555555556, - "load": 263775.0, - "power": 100637, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 15.5555555555556, - "load": 351700.0, - "power": 123446, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 22.500000000000057, - "load": 87925.0, - "power": 81486, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 22.500000000000057, - "load": 175850.0, - "power": 115280, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 22.500000000000057, - "load": 263775.0, - "power": 149074, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 22.500000000000057, - "load": 351700.0, - "power": 182868, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 29.444444444444457, - "load": 87925.0, - "power": 107867, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 29.444444444444457, - "load": 175850.0, - "power": 152616, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 29.444444444444457, - "load": 263775.0, - "power": 197365, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 29.444444444444457, - "load": 351700.0, - "power": 242114, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 36.388888888888914, - "load": 87925.0, - "power": 134316, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 36.388888888888914, - "load": 175850.0, - "power": 190020, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 36.388888888888914, - "load": 263775.0, - "power": 245724, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 36.388888888888914, - "load": 351700.0, - "power": 301428, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 40.00000000000006, - "load": 87925.0, - "power": 151006, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 40.00000000000006, - "load": 175850.0, - "power": 213695, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 40.00000000000006, - "load": 263775.0, - "power": 276384, - }, - { - "chilled_water_supply_temperature": 3.888888888888914, - "condenser_temperature": 40.00000000000006, - "load": 351700.0, - "power": 339073, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 15.5555555555556, - "load": 87925.0, - "power": 61435, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 15.5555555555556, - "load": 175850.0, - "power": 86959, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 15.5555555555556, - "load": 263775.0, - "power": 112483, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 15.5555555555556, - "load": 351700.0, - "power": 138007, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 22.500000000000057, - "load": 87925.0, - "power": 82089, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 22.500000000000057, - "load": 175850.0, - "power": 116199, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 22.500000000000057, - "load": 263775.0, - "power": 150309, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 22.500000000000057, - "load": 351700.0, - "power": 184419, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 29.444444444444457, - "load": 87925.0, - "power": 102780, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 29.444444444444457, - "load": 175850.0, - "power": 145487, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 29.444444444444457, - "load": 263775.0, - "power": 188194, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 29.444444444444457, - "load": 351700.0, - "power": 230901, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 36.388888888888914, - "load": 87925.0, - "power": 123508, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 36.388888888888914, - "load": 175850.0, - "power": 174812, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 36.388888888888914, - "load": 263775.0, - "power": 226116, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 36.388888888888914, - "load": 351700.0, - "power": 277420, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 40.00000000000006, - "load": 87925.0, - "power": 136670, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 40.00000000000006, - "load": 175850.0, - "power": 193502, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 40.00000000000006, - "load": 263775.0, - "power": 250334, - }, - { - "chilled_water_supply_temperature": 7.222222222222285, - "condenser_temperature": 40.00000000000006, - "load": 351700.0, - "power": 307166, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 15.5555555555556, - "load": 87925.0, - "power": 71585, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 15.5555555555556, - "load": 175850.0, - "power": 101313, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 15.5555555555556, - "load": 263775.0, - "power": 131041, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 15.5555555555556, - "load": 351700.0, - "power": 160769, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 22.500000000000057, - "load": 87925.0, - "power": 89197, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 22.500000000000057, - "load": 175850.0, - "power": 126234, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 22.500000000000057, - "load": 263775.0, - "power": 163271, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 22.500000000000057, - "load": 351700.0, - "power": 200308, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 29.444444444444457, - "load": 87925.0, - "power": 106846, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 29.444444444444457, - "load": 175850.0, - "power": 151193, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 29.444444444444457, - "load": 263775.0, - "power": 195540, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 29.444444444444457, - "load": 351700.0, - "power": 239887, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 36.388888888888914, - "load": 87925.0, - "power": 124532, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 36.388888888888914, - "load": 175850.0, - "power": 176189, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 36.388888888888914, - "load": 263775.0, - "power": 227846, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 36.388888888888914, - "load": 351700.0, - "power": 279503, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 40.00000000000006, - "load": 87925.0, - "power": 135953, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 40.00000000000006, - "load": 175850.0, - "power": 192407, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 40.00000000000006, - "load": 263775.0, - "power": 248861, - }, - { - "chilled_water_supply_temperature": 10.000000000000057, - "condenser_temperature": 40.00000000000006, - "load": 351700.0, - "power": 305315, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 15.5555555555556, - "load": 87925.0, - "power": 81472, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 15.5555555555556, - "load": 175850.0, - "power": 115332, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 15.5555555555556, - "load": 263775.0, - "power": 149192, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 15.5555555555556, - "load": 351700.0, - "power": 183052, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 22.500000000000057, - "load": 87925.0, - "power": 96456, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 22.500000000000057, - "load": 175850.0, - "power": 136508, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 22.500000000000057, - "load": 263775.0, - "power": 176560, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 22.500000000000057, - "load": 351700.0, - "power": 216612, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 29.444444444444457, - "load": 87925.0, - "power": 111478, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 29.444444444444457, - "load": 175850.0, - "power": 157722, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 29.444444444444457, - "load": 263775.0, - "power": 203966, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 29.444444444444457, - "load": 351700.0, - "power": 250210, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 36.388888888888914, - "load": 87925.0, - "power": 126537, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 36.388888888888914, - "load": 175850.0, - "power": 179074, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 36.388888888888914, - "load": 263775.0, - "power": 231611, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 36.388888888888914, - "load": 351700.0, - "power": 284148, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 40.00000000000006, - "load": 87925.0, - "power": 136465, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 40.00000000000006, - "load": 175850.0, - "power": 193186, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 40.00000000000006, - "load": 263775.0, - "power": 249907, - }, - { - "chilled_water_supply_temperature": 12.777777777777828, - "condenser_temperature": 40.00000000000006, - "load": 351700.0, - "power": 306628, - }, ], } ], From c072d6099197a3d44ec7fb31ed0780465818bfa8 Mon Sep 17 00:00:00 2001 From: yunjoonjung Date: Tue, 21 Oct 2025 15:53:21 -0700 Subject: [PATCH 3/5] Added unit tests & Updated logics --- .../is_chiller_performance_app_j.py | 90 +++++--- .../is_chiller_performance_app_j_test.py | 207 ++++++++++++++++-- 2 files changed, 253 insertions(+), 44 deletions(-) diff --git a/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py index dfdc4b6212..38b86d16bf 100644 --- a/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py +++ b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j.py @@ -1,15 +1,17 @@ from rct229.rulesets.ashrae9012022.data_fns.table_J_6_fns import table_J_6_lookup from rct229.schema.config import ureg from rct229.schema.schema_enums import SchemaEnums -from rct229.utils.assertions import getattr_ +from rct229.utils.assertions import assert_, getattr_ from rct229.utils.std_comparisons import std_equal_with_precision ENERGY_SOURCE = SchemaEnums.schema_enums["EnergySourceOptions"] CHILLER_COMPRESSOR = SchemaEnums.schema_enums["ChillerCompressorOptions"] +CHILLER_EFFICIENCY_METRIC = SchemaEnums.schema_enums["ChillerEfficiencyMetricOptions"] + EXPECTED_VALIDATION_PLR = [0.25, 0.50, 0.75, 1.00] -EXPECTED_CHILLED_WATER_TEMPS = [39, 45, 50, 55] -EXPECTED_ENTERING_CONDENSER_WATER_TEMPS = [60, 104, 85, 72.5, 97.5] +EXPECTED_CHILLED_WATER_TEMPS = [39.0, 45.0, 50.0, 55.0] +EXPECTED_ENTERING_CONDENSER_WATER_TEMPS = [60.0, 72.5, 85.0, 97.5, 104.0] def is_chiller_performance_app_j(chiller: dict) -> bool: @@ -53,39 +55,67 @@ def is_chiller_performance_app_j(chiller: dict) -> bool: curve_set = None if curve_set is not None: - rated_power = ( - rated_capacity / chiller["full_load_efficiency"] - if getattr_(chiller, "chillers", "full_load_efficiency") > 0.0 - else 0.0 + # The first element is "FULL_LOAD_EFFICIENCY_RATED" + full_load_efficiency_rated = getattr_( + chiller, "chillers", "efficiency_metric_values" + )[0] + assert_( + full_load_efficiency_rated > 0, + "The `full_load_efficiency_rated` value must be greater than 0.", ) + rated_power = rated_capacity / full_load_efficiency_rated + eir_f_t_coefficients = table_J_6_lookup(curve_set, "EIR-f-T") cap_f_t_coefficients = table_J_6_lookup(curve_set, "CAP-f-T") plr_coefficients = table_J_6_lookup(curve_set, "EIR-f-PLR") capacity_validation_pts_dict = {} - for capacity_validation_point in chiller.get("capacity_operating_points", []): - chilled_water_supply_temp = capacity_validation_point.get( - "chilled_water_supply_temperature", 0.0 * ureg("degC") + capacity_operating_points = getattr_( + chiller, "chillers", "capacity_operating_points" + ) + for capacity_validation_point in capacity_operating_points: + chilled_water_supply_temp = getattr_( + capacity_validation_point, + "capacity_operating_points", + "chilled_water_supply_temperature", ).to("degF") - condenser_temp = capacity_validation_point.get( - "condenser_temperature", 0.0 * ureg("degC") + condenser_temp = getattr_( + capacity_validation_point, + "capacity_operating_points", + "condenser_temperature", ).to("degF") - dict_key = f"{int(round(chilled_water_supply_temp.m, 1))}, {int(round(condenser_temp.m, 1))}" - capacity_validation_pts_dict[dict_key] = capacity_validation_point.get( - "capacity", 0.0 * ureg("W") + dict_key = ( + f"{round(chilled_water_supply_temp.m, 1)}, {round(condenser_temp.m, 1)}" + ) + capacity_validation_pts_dict[dict_key] = getattr_( + capacity_validation_point, + "capacity_operating_points", + "capacity", + ) + assert_( + capacity_validation_pts_dict[dict_key] > 0, + "The 'capacity' value must be greater than 0 W.", ) power_validation_pts_dict = {} - for power_validation_point in chiller.get("power_operating_points", []): - chilled_water_supply_temp = power_validation_point.get( - "chilled_water_supply_temperature", 0.0 * ureg("degC") + power_operating_points = getattr_(chiller, "chillers", "power_operating_points") + for power_validation_point in power_operating_points: + chilled_water_supply_temp = getattr_( + power_validation_point, + "power_operating_points", + "chilled_water_supply_temperature", ).to("degF") - condenser_temp = power_validation_point.get( - "condenser_temperature", 0.0 * ureg("degC") + condenser_temp = getattr_( + power_validation_point, + "power_operating_points", + "condenser_temperature", ).to("degF") - dict_key = f"{int(round(chilled_water_supply_temp.m, 1))}, {int(round(condenser_temp.m, 1))}" + + dict_key = ( + f"{round(chilled_water_supply_temp.m, 1)}, {round(condenser_temp.m, 1)}" + ) power_validation_pts_dict.setdefault(dict_key, []) power_validation_pts_dict[dict_key].append(power_validation_point) @@ -126,25 +156,25 @@ def is_chiller_performance_app_j(chiller: dict) -> bool: for ecwt in EXPECTED_ENTERING_CONDENSER_WATER_TEMPS: dict_key = f"{chwt}, {ecwt}" if power_validation_pts_dict.get(dict_key): - given_plrs = [] for power_validation_point in power_validation_pts_dict[dict_key]: - load = power_validation_point.get("load", 0.0 * ureg("W")) - given_power = power_validation_point.get( - "result", 0.0 * ureg("W") + load = getattr_( + power_validation_point, "power_operating_points", "load" + ) + given_power = getattr_( + power_validation_point, "power_operating_points", "power" ) + plr = ( load / given_capacities[dict_key] - if given_capacities[dict_key] > 0.0 * ureg("W") - else 0.0 - ) + ) # no need to check `given_capacities[dict_key]` = 0.0 (checked in line 95) + # plr.m because plr is a "dimensionless" unit if any( [ - std_equal_with_precision(plr, expected_plr, 2) + std_equal_with_precision(plr.m, expected_plr, 2) for expected_plr in EXPECTED_VALIDATION_PLR ] ): - given_plrs.append(plr) eir_plr = ( plr_coefficients[0] + plr_coefficients[1] * plr diff --git a/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py index fab01a7b4c..16ab65e92d 100644 --- a/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py +++ b/rct229/rulesets/ashrae9012022/ruleset_functions/is_chiller_performance_app_j_test.py @@ -1,9 +1,13 @@ +import copy + +import pytest from rct229.rulesets.ashrae9012022.ruleset_functions.is_chiller_performance_app_j import ( is_chiller_performance_app_j, ) from rct229.schema.config import ureg from rct229.schema.schema_utils import quantify_rmd from rct229.schema.validate import schema_validate_rpd +from rct229.utils.assertions import RCTFailureException TEST_RMD = { "id": "RMD 1", @@ -75,7 +79,6 @@ "cooling_loop": "Chiller Loop 1", "compressor_type": "CENTRIFUGAL", "rated_capacity": 527550.0, - "full_load_efficiency": 3.2, "condensing_loop": "Condenser Loop 1", "efficiency_metric_values": [5.5], "efficiency_metric_types": ["FULL_LOAD_EFFICIENCY_RATED"], @@ -106,14 +109,14 @@ .to("degC") .m, "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, - "capacity": 522221.2, + "capacity": 502507.3, }, { "chilled_water_supply_temperature": (39 * ureg("degF")) .to("degC") .m, "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, - "capacity": 565443.4, + "capacity": 438845.2, }, { "chilled_water_supply_temperature": (45 * ureg("degF")) @@ -141,14 +144,14 @@ .to("degC") .m, "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, - "capacity": 522221.2, + "capacity": 553642.8, }, { "chilled_water_supply_temperature": (45 * ureg("degF")) .to("degC") .m, "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, - "capacity": 522221.2, + "capacity": 505807.2, }, { "chilled_water_supply_temperature": (50 * ureg("degF")) @@ -169,28 +172,28 @@ .to("degC") .m, "condenser_temperature": (85 * ureg("degF")).to("degC").m, - "capacity": 530449.9, + "capacity": 566113.4, }, { "chilled_water_supply_temperature": (50 * ureg("degF")) .to("degC") .m, "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, - "capacity": 522221.2, + "capacity": 579397.7, }, { "chilled_water_supply_temperature": (50 * ureg("degF")) .to("degC") .m, "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, - "capacity": 566113.4, + "capacity": 544750.9, }, { "chilled_water_supply_temperature": (55 * ureg("degF")) .to("degC") .m, "condenser_temperature": (60 * ureg("degF")).to("degC").m, - "capacity": 566113.4, + "capacity": 588439.3, }, { "chilled_water_supply_temperature": (55 * ureg("degF")) @@ -211,14 +214,14 @@ .to("degC") .m, "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, - "capacity": 522221.2, + "capacity": 589827.4, }, { "chilled_water_supply_temperature": (55 * ureg("degF")) .to("degC") .m, "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, - "capacity": 583137.4, + "capacity": 568369.3, }, ], "power_operating_points": [ @@ -228,7 +231,159 @@ .m, "condenser_temperature": (60 * ureg("degF")).to("degC").m, "load": 522221.2, - "power": 55019, + "power": 79979.2, + }, + { + "chilled_water_supply_temperature": (39 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 93409.8, + }, + { + "chilled_water_supply_temperature": (39 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (85.0 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 102356.5, + }, + { + "chilled_water_supply_temperature": (39 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 107134.4, + }, + { + "chilled_water_supply_temperature": (39 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (104 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 108084.6, + }, + { + "chilled_water_supply_temperature": (45 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (60 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 71797.9, + }, + { + "chilled_water_supply_temperature": (45 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 84935.4, + }, + { + "chilled_water_supply_temperature": (45 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (85.0 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 93202.5, + }, + { + "chilled_water_supply_temperature": (45 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 96760.4, + }, + { + "chilled_water_supply_temperature": (45 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (104 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 96800.8, + }, + { + "chilled_water_supply_temperature": (50 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (60 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 66960.6, + }, + { + "chilled_water_supply_temperature": (50 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 80260.3, + }, + { + "chilled_water_supply_temperature": (50 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (85.0 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 88538.4, + }, + { + "chilled_water_supply_temperature": (50 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 91899.9, + }, + { + "chilled_water_supply_temperature": (50 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (104 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 91737.6, + }, + { + "chilled_water_supply_temperature": (55 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (60 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 63538.7, + }, + { + "chilled_water_supply_temperature": (55 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (72.5 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 77160.5, + }, + { + "chilled_water_supply_temperature": (55 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (85.0 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 85681.6, + }, + { + "chilled_water_supply_temperature": (55 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (97.5 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 89177.3, + }, + { + "chilled_water_supply_temperature": (55 * ureg("degF")) + .to("degC") + .m, + "condenser_temperature": (104 * ureg("degF")).to("degC").m, + "load": 522221.2, + "power": 89031.4, }, ], } @@ -286,5 +441,29 @@ def test__TEST_RPD__is_valid(): ], f"Schema error: {schema_validation_result['error']}" -def test__get_hvac_zone_list_w_area_dict(): - assert is_chiller_performance_app_j(TEST_CHILLER) is True +def test__is_chiller_performance_app_j__pass(): + assert is_chiller_performance_app_j(TEST_CHILLER) + + +def test__is_chiller_performance_app_j__pass(): + assert is_chiller_performance_app_j(TEST_CHILLER) + + +def test__is_chiller_performance_app_j__zero_full_load_efficiency_rated(): + with pytest.raises( + RCTFailureException, + match="The `full_load_efficiency_rated` value must be greater than 0.", + ): + TEST_CHILLER_ZERO_EFFI = copy.deepcopy(TEST_CHILLER) + TEST_CHILLER_ZERO_EFFI["efficiency_metric_values"][0] = 0.0 + is_chiller_performance_app_j(TEST_CHILLER_ZERO_EFFI) + + +def test__is_chiller_performance_app_j__zero_capacity(): + with pytest.raises( + RCTFailureException, + match="The 'capacity' value must be greater than 0 W.", + ): + TEST_CHILLER_ZERO_EFFI = copy.deepcopy(TEST_CHILLER) + TEST_CHILLER_ZERO_EFFI["capacity_operating_points"][0]["capacity"] = 0.0 + is_chiller_performance_app_j(TEST_CHILLER_ZERO_EFFI) From cb7ab3dfbcc562cb373dae364f16989bbb66a27c Mon Sep 17 00:00:00 2001 From: yunjoonjung Date: Tue, 21 Oct 2025 15:58:00 -0700 Subject: [PATCH 4/5] Removed unneeded file --- .../ashrae9012019/section5/test/rebaseline.py | 103 ------------------ 1 file changed, 103 deletions(-) delete mode 100644 rct229/rulesets/ashrae9012019/section5/test/rebaseline.py diff --git a/rct229/rulesets/ashrae9012019/section5/test/rebaseline.py b/rct229/rulesets/ashrae9012019/section5/test/rebaseline.py deleted file mode 100644 index 2ad9c19ff9..0000000000 --- a/rct229/rulesets/ashrae9012019/section5/test/rebaseline.py +++ /dev/null @@ -1,103 +0,0 @@ -import pandas as pd - - -def filter_by_conditions(df, conditions): - """Filter DataFrame by multiple conditions""" - query_parts = [] - for col, val in conditions.items(): - if val is not None: - if isinstance(val, str): - query_parts.append(f'{col} == "{val}"') - else: - query_parts.append(f"{col} == {val}") - - query_str = " & ".join(query_parts) - if query_str: - return df.query(query_str) - else: - return df - - -def recalculate_permit_based_average( - filtered_data, climate_zones, level_number, credit_name, bldg_type -): - # Define column names - cz_col = ["Credit", "CZ1", "CZ2", "CZ3", "CZ4", "CZ4C", "CZ5", "CZ6", "CZ7", "CZ8"] - result_df = pd.DataFrame(columns=cz_col) - new_row_template = {cz: None for cz in cz_col} - - for level_no in level_number: - new_row = new_row_template.copy() - if "baseline" in credit_name: - new_row["Credit"] = "baseline" - else: - new_row["Credit"] = f"{credit_name}_level{level_no}" - - for cz in climate_zones.keys(): - data = filtered_data[bldg_type][cz][str(level_no)] - new_row[cz] = ( - data["Total.Site.EUI.kBtu_ft2"] * data["permits"] - ).sum() / data["permits"].sum() - - new_row_df = pd.DataFrame([new_row]) - result_df = pd.concat([result_df, new_row_df], ignore_index=True) - - return result_df - - -def calc_agg_value_by_climate_zone(credit_name: str, level_number: list[int]): - level_number = sorted(level_number) - - # Read credit csv - credit = pd.read_csv(f"./{credit_name}.csv", delimiter=",") - - # Define climate zones and moisture regimes - climate_zones = { - "CZ1": {"climate_zone": "Climate Zone 1", "moisture_regime": None}, - "CZ2": {"climate_zone": "Climate Zone 2", "moisture_regime": None}, - "CZ3": {"climate_zone": "Climate Zone 3", "moisture_regime": None}, - "CZ4": {"climate_zone": "Climate Zone 4", "moisture_regime": None}, - "CZ4C": {"climate_zone": "Climate Zone 4", "moisture_regime": "Marine"}, - "CZ5": {"climate_zone": "Climate Zone 5", "moisture_regime": None}, - "CZ6": {"climate_zone": "Climate Zone 6", "moisture_regime": None}, - "CZ7": {"climate_zone": "Climate Zone 7", "moisture_regime": None}, - "CZ8": {"climate_zone": "Climate Zone 8", "moisture_regime": None}, - } - - # Define building types - bldg_types = ["all", "Single-Family", "Multifamily"] - - # Filter credit data by level, building type, and climate zone - filtered_data = {} - for bldg_type in bldg_types: - filtered_data[bldg_type] = {} - credit_bldg_type = ( - credit if bldg_type == "all" else credit[credit["bldg_type"] == bldg_type] - ) - - for cz, conditions in climate_zones.items(): - filtered_data[bldg_type][cz] = {} - filtered_cz = filter_by_conditions(credit_bldg_type, conditions)[ - ["level_0", "Total.Site.EUI.kBtu_ft2", "permits"] - ] - - for level_no in level_number: - filtered_data[bldg_type][cz][str(level_no)] = filtered_cz[ - filtered_cz["level_0"] == level_no - ][["Total.Site.EUI.kBtu_ft2", "permits"]] - - # Recalculate permit-based average for all building types - all_bldg_type_df = recalculate_permit_based_average( - filtered_data, climate_zones, level_number, credit_name, "all" - ) - SF_df = recalculate_permit_based_average( - filtered_data, climate_zones, level_number, credit_name, "Single-Family" - ) - MF_df = recalculate_permit_based_average( - filtered_data, climate_zones, level_number, credit_name, "Multifamily" - ) - - return {"all_bldg_type_df": all_bldg_type_df, "SF_df": SF_df, "MF_df": MF_df} - - -test = calc_agg_value_by_climate_zone("filtered_baseline", [0]) From 00ec7ef6ab7493225fedcb3386d18197321682ff Mon Sep 17 00:00:00 2001 From: yunjoonjung Date: Tue, 21 Oct 2025 16:05:33 -0700 Subject: [PATCH 5/5] Replaced underscore with dash --- rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns_test.py b/rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns_test.py index f91819fccc..b8beba04d0 100644 --- a/rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns_test.py +++ b/rct229/rulesets/ashrae9012022/data_fns/table_J_6_fns_test.py @@ -26,4 +26,4 @@ def test__table_J_6_Y_CAP_f_T(): def test__table_J_6_AA_EIR_f_PLR(): - assert table_J_6_lookup("AA", "EIR-f_PLR") == [0.339494, 0.04909, 0.611582] + assert table_J_6_lookup("AA", "EIR-f-PLR") == [0.339494, 0.04909, 0.611582]