-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RS/YJ/Rule 11-12 #1524
base: develop
Are you sure you want to change the base?
RS/YJ/Rule 11-12 #1524
Changes from 24 commits
d2d0ff3
6173f28
ce9e82b
a9fd6e2
fa2802b
05909ea
3cf0ef4
962ee32
35fc2ef
36b1f34
d0132a8
0a5fc3c
828b682
571768c
a1dc2bc
97c5b20
ea3790e
c29b727
16bec25
fae1f4e
2e67166
6f66505
697b754
5adc687
88d9188
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
"section5", | ||
"section6", | ||
"section10", | ||
"section11", | ||
"section12", | ||
"section16", | ||
"section18", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Add all available rule modules in __all__ | ||
import importlib | ||
|
||
__all__ = [ | ||
# "section11rule1", | ||
# "section11rule2", | ||
# "section11rule3", | ||
# "section11rule4", | ||
# "section11rule5", | ||
"section11rule6", | ||
# "section11rule7", | ||
# "section11rule8", | ||
# "section11rule9", | ||
# "section11rule10", | ||
# "section11rule11", | ||
"section11rule12", | ||
# "section11rule13", | ||
# "section11rule14", | ||
# "section11rule15", | ||
# "section11rule16", | ||
# "section11rule17", | ||
] | ||
|
||
|
||
def __getattr__(name): | ||
if name in __all__: | ||
return importlib.import_module("." + name, __name__) | ||
raise AttributeError(f"module {__name__!r} has no attribute {name!r}") | ||
|
||
|
||
def __dir__(): | ||
return sorted(__all__) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
from rct229.rule_engine.partial_rule_definition import PartialRuleDefinition | ||
from rct229.rule_engine.rule_list_indexed_base import RuleDefinitionListIndexedBase | ||
from rct229.rule_engine.ruleset_model_factory import produce_ruleset_model_description | ||
from rct229.rule_engine.rulesets import LeapYear | ||
from rct229.rulesets.ashrae9012019 import BASELINE_0 | ||
from rct229.rulesets.ashrae9012019.ruleset_functions.get_swh_uses_associated_with_each_building_segment import ( | ||
get_swh_uses_associated_with_each_building_segment, | ||
) | ||
from rct229.utils.assertions import getattr_ | ||
from rct229.utils.utility_functions import find_exactly_one_schedule | ||
|
||
APPLICABILITY_MSG = ( | ||
"This building is a 24hr-facility with service water heating loads. If the building meets the prescriptive criteria for use of condenser heat recovery systems described in 90.1 Section 6.5.6.2, a system meeting the requirements of that section shall be included in the baseline building design regardless of the exceptions to Section 6.5.6.2. " | ||
"(Exceptions: 1. Facilities that employ condenser heat recovery for space heating with a heat recovery design exceeding 30% of the peak water-cooled condenser load at design conditions." | ||
" 2. Facilities that provide 60% of their service water heating from site-solar energy or siterecovered energy or from other sources.) Recommend manual review to determine if project complies." | ||
) | ||
|
||
|
||
class Section11Rule12(RuleDefinitionListIndexedBase): | ||
"""Rule 12 of ASHRAE 90.1-2019 Appendix G Section 11 (Service Water Heating)""" | ||
|
||
def __init__(self): | ||
super(Section11Rule12, self).__init__( | ||
rmds_used=produce_ruleset_model_description( | ||
USER=False, BASELINE_0=True, PROPOSED=True | ||
), | ||
each_rule=Section11Rule12.RMDRule(), | ||
index_rmd=BASELINE_0, | ||
id="11-12", | ||
description="For large, 24-hour-per-day facilities that meet the prescriptive criteria for use of condenser heat recovery systems described in Section 6.5.6.2, a system meeting the requirements of that section shall be included in the baseline building design regardless of the exceptions to Section 6.5.6.2.", | ||
ruleset_section_title="Service Water Heating", | ||
standard_section="Table G3.1 #11, baseline column, d + exception", | ||
is_primary_rule=False, | ||
list_path="ruleset_model_descriptions[0]", | ||
data_items={"is_leap_year_b": (BASELINE_0, "calendar/is_leap_year")}, | ||
) | ||
|
||
class RMDRule(RuleDefinitionListIndexedBase): | ||
def __init__(self): | ||
super(Section11Rule12.RMDRule, self).__init__( | ||
rmds_used=produce_ruleset_model_description( | ||
USER=False, BASELINE_0=True, PROPOSED=True | ||
), | ||
each_rule=Section11Rule12.RMDRule.BuildingRule(), | ||
index_rmd=BASELINE_0, | ||
list_path="$.buildings[*]", | ||
) | ||
|
||
def create_data(self, context, data): | ||
rmd_b = context.BASELINE_0 | ||
rmd_p = context.PROPOSED | ||
|
||
return {"rmd_b": rmd_b, "rmd_p": rmd_p} | ||
|
||
class BuildingRule(RuleDefinitionListIndexedBase): | ||
def __init__(self): | ||
super(Section11Rule12.RMDRule.BuildingRule, self).__init__( | ||
rmds_used=produce_ruleset_model_description( | ||
USER=False, BASELINE_0=True, PROPOSED=True | ||
), | ||
each_rule=Section11Rule12.RMDRule.BuildingRule.BuildingSegmentRule(), | ||
index_rmd=BASELINE_0, | ||
list_path="$.building_segments[*]", | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to add a is_applicable here to check the logic check that there is SWH in the proposed model AND that the building has a 24hr operating schedule In RDS logic section, it is also said: |
||
|
||
def create_data(self, context, data): | ||
building_b = context.BASELINE_0 | ||
rmd_b = data["rmd_b"] | ||
is_leap_year_b = data["is_leap_year_b"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
bldg_open_sch_id_b = getattr_( | ||
building_b, "buildings", "building_open_schedule" | ||
) | ||
|
||
bldg_open_sch_b = find_exactly_one_schedule(rmd_b, bldg_open_sch_id_b)[ | ||
"hourly_values" | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Following the above |
||
|
||
hours_this_year = ( | ||
LeapYear.LEAP_YEAR_HOURS | ||
if is_leap_year_b | ||
else LeapYear.REGULAR_YEAR_HOURS | ||
) | ||
|
||
return { | ||
"bldg_open_sch_b": bldg_open_sch_b, | ||
"hours_this_year": hours_this_year, | ||
} | ||
|
||
def list_filter(self, context_item, data): | ||
bldg_open_sch_b = data["bldg_open_sch_b"] | ||
hours_this_year = data["hours_this_year"] | ||
|
||
return sum(bldg_open_sch_b) == hours_this_year | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure what is this filtering. |
||
|
||
class BuildingSegmentRule(RuleDefinitionListIndexedBase): | ||
def __init__(self): | ||
super( | ||
Section11Rule12.RMDRule.BuildingRule.BuildingSegmentRule, self | ||
).__init__( | ||
rmds_used=produce_ruleset_model_description( | ||
USER=False, BASELINE_0=True, PROPOSED=True | ||
), | ||
each_rule=Section11Rule12.RMDRule.BuildingRule.BuildingSegmentRule.SWHRule(), | ||
index_rmd=BASELINE_0, | ||
list_path="$.zones[*].spaces[*].service_water_heating_uses[*]", | ||
) | ||
|
||
def create_data(self, context, data): | ||
building_segment_p = context.PROPOSED | ||
rmd_p = data["rmd_p"] | ||
|
||
service_water_heating_use_ids_list_p = ( | ||
get_swh_uses_associated_with_each_building_segment( | ||
rmd_p, building_segment_p["id"] | ||
) | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will move this logic to RMD level. for example, creating a swh_uses_associated_with_each_building_segment_p:
{
building_segment_id: get_swh_uses_associated_with_each_building_segment(
rmd_p, building_segment_p["id"]
)
for building_segment_id in find_all("$.buildings[*].building_segments[*].id, rmd_p
} I can skip this create data here. |
||
|
||
return { | ||
"service_water_heating_use_ids_list_p": service_water_heating_use_ids_list_p | ||
} | ||
|
||
def list_filter(self, context_item, data): | ||
swh_use_p = context_item.PROPOSED | ||
served_by_distribution_system_p = getattr_( | ||
swh_use_p, | ||
"service_water_heating_uses", | ||
"served_by_distribution_system", | ||
) | ||
service_water_heating_use_ids_list_p = data[ | ||
"service_water_heating_use_ids_list_p" | ||
] | ||
|
||
return ( | ||
served_by_distribution_system_p | ||
in service_water_heating_use_ids_list_p | ||
) | ||
|
||
class SWHRule(PartialRuleDefinition): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think the rule shall be evaluated at service water use level. Instead, I think it should be at the Building level. Also, if we check the logic - a great amount of logic is to verify whether the building has SWH load and it is operate 24 hours. |
||
def __init__(self): | ||
super( | ||
Section11Rule12.RMDRule.BuildingRule.BuildingSegmentRule.SWHRule, | ||
self, | ||
).__init__( | ||
rmds_used=produce_ruleset_model_description( | ||
USER=False, BASELINE_0=False, PROPOSED=True | ||
), | ||
manual_check_required_msg=APPLICABILITY_MSG, | ||
) | ||
|
||
def applicability_check(self, context, calc_vals, data): | ||
swh_use_p = context.PROPOSED | ||
|
||
return ( | ||
getattr_(swh_use_p, "service_water_heating_uses", "use") > 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For this part, please see the email between Juan and me (Sep 19th - title: RCT, Question about ServiceWaterHeatingUse-USE unit). Please let me know if you think differently. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need to care about the unit for now. |
||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
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_uses_associated_with_each_building_segment import ( | ||
get_swh_uses_associated_with_each_building_segment, | ||
) | ||
from rct229.utils.jsonpath_utils import find_all, find_exactly_one_with_field_value | ||
|
||
|
||
class Section11Rule6(RuleDefinitionListIndexedBase): | ||
"""Rule 6 of ASHRAE 90.1-2019 Appendix G Section 11 (Service Water Heating)""" | ||
|
||
def __init__(self): | ||
super(Section11Rule6, self).__init__( | ||
rmds_used=produce_ruleset_model_description( | ||
USER=False, BASELINE_0=True, PROPOSED=False | ||
), | ||
each_rule=Section11Rule6.RMDRule(), | ||
index_rmd=BASELINE_0, | ||
id="11-6", | ||
description="Piping losses shall not be modeled.", | ||
ruleset_section_title="Service Water Heating", | ||
standard_section="Table G3.1 #11, baseline column, i", | ||
is_primary_rule=True, | ||
list_path="ruleset_model_descriptions[0]", | ||
) | ||
|
||
class RMDRule(RuleDefinitionListIndexedBase): | ||
def __init__(self): | ||
super(Section11Rule6.RMDRule, self).__init__( | ||
rmds_used=produce_ruleset_model_description( | ||
USER=False, BASELINE_0=True, PROPOSED=False | ||
), | ||
each_rule=Section11Rule6.RMDRule.BuildingSegmentRule(), | ||
index_rmd=BASELINE_0, | ||
list_path="buildings[*].building_segments[*]", | ||
) | ||
|
||
def create_data(self, context, data): | ||
rmd_b = context.BASELINE_0 | ||
|
||
return {"rmd_b": rmd_b} | ||
|
||
class BuildingSegmentRule(RuleDefinitionBase): | ||
def __init__(self): | ||
super(Section11Rule6.RMDRule.BuildingSegmentRule, self).__init__( | ||
rmds_used=produce_ruleset_model_description( | ||
USER=False, | ||
BASELINE_0=True, | ||
PROPOSED=False, | ||
), | ||
) | ||
|
||
def get_calc_vals(self, context, data=None): | ||
rmd_b = data["rmd_b"] | ||
building_segment_b = context.BASELINE_0 | ||
|
||
swh_distribution_and_eq_list = ( | ||
get_swh_uses_associated_with_each_building_segment( | ||
rmd_b, building_segment_b["id"] | ||
) | ||
) | ||
|
||
for piping_id in swh_distribution_and_eq_list: | ||
service_water_piping_b = find_exactly_one_with_field_value( | ||
"$.service_water_heating_distribution_systems[*]", | ||
"id", | ||
piping_id, | ||
rmd_b, | ||
) | ||
|
||
piping_losses_modeled_b = any( | ||
find_all( | ||
"$.service_water_piping[*].are_thermal_losses_modeled", | ||
service_water_piping_b, | ||
) | ||
) | ||
|
||
return {"piping_losses_modeled_b": piping_losses_modeled_b} | ||
|
||
def rule_check(self, context, calc_vals=None, data=None): | ||
piping_losses_modeled_b = calc_vals["piping_losses_modeled_b"] | ||
|
||
return not piping_losses_modeled_b |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can make a
create_data
function and add data: