Skip to content

Commit

Permalink
Merge branch 'develop' into RS/JX/Rule16-6
Browse files Browse the repository at this point in the history
# Conflicts:
#	rct229/rulesets/ashrae9012019/section16/__init__.py
  • Loading branch information
Jiarongx-Xie committed Jun 17, 2024
2 parents c878012 + 145bb5d commit c6cb6c4
Show file tree
Hide file tree
Showing 14 changed files with 88,955 additions and 19 deletions.
2 changes: 1 addition & 1 deletion docs/section16/Rule16-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
match_data_element, compare_schedules

**Applicability Check 1:**
- Rule is applicable if any building in the proposed RMD has an elevator: `if any(len(building.elevators) > 0 for building in P_RMD...buildings:`
- Rule is applicable if any building in the proposed RMD has an elevator: `if len(building.elevators_p > 0 for building in P_RMD...buildings:`

## Rule Logic:
- Determine if the project schedule uses a leap year: `is_leap_year = RPD.calendar.is_leap_year`
Expand Down
2 changes: 1 addition & 1 deletion docs/section16/Rule16-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
compare_schedules

**Applicability Check 1:**
- Rule is applicable if any building in the proposed RMD has an elevator: `if any(len(building.elevators) > 0 for building in P_RMD...buildings:`
- Rule is applicable if any building in the proposed RMD has an elevator: `if len(building_p.elevators) > 0 for building in P_RMD...buildings:`

## Rule Logic:
- Determine if the project schedule uses a leap year: `is_leap_year = RPD.calendar.is_leap_year`
Expand Down
2 changes: 1 addition & 1 deletion docs/section16/Rule16-4.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
compare_schedules

**Applicability Check 1:**
- Rule is applicable if any building in the proposed RMD has an elevator: `if any(len(building.elevators) > 0 for building in P_RMD...buildings:`
- Rule is applicable if any building in the proposed RMD has an elevator: `if len(building.elevators) > 0 for building in P_RMD...buildings:`

## Rule Logic:
- Determine if the project schedule uses a leap year: `is_leap_year = RPD.calendar.is_leap_year`
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "ruleset-checking-tool"
version = "0.2.7"
version = "0.2.8"
description = "PNNL ruleset checking tool"
authors = ["Weili Xu <[email protected]>", "Charlie Holly <[email protected]>", "Juan Gonzalez <[email protected]>", "Yun Joon Jung <[email protected]>", "Jiarong Xie <[email protected]>"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion rct229/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def cli():
Software test workflow, add sections to do test. \n
--ruleset or -rs: default is ashrae9012019, available: ashrae9012019\n
argument (optional): section string, \n
currently available: section1, section4, section5, section6, section10, section18, section19, section21, section22 and section23"""
currently available: section1, section4, section5, section6, section10, section16, section18, section19, section21, section22 and section23"""


@cli.command(
Expand Down
10 changes: 7 additions & 3 deletions rct229/rule_engine/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,18 +225,22 @@ def evaluate_rules(
else:
step = round(total_num_rules * 0.05)
counting_steps = list(range(0, total_num_rules, step))
if counting_steps[-1] < total_num_rules:
# ensure to add the 100% report
counting_steps.append(total_num_rules)

# counter starts at 1
rule_counter = 0
# Evaluate the rules
for rule in rules_list:
print(f"Processing Rule {rule.id}")
outcome = rule.evaluate(copied_rmds)
outcomes.append(outcome)
rule_counter += 1
if rule_counter in counting_steps:
print(
f"Project Evaluation Session ID: #{session_id}# => Compliance evaluation progress: {round(rule_counter / total_num_rules * 100)}%"
)
print(f"Processing Rule {rule.id}")
outcome = rule.evaluate(copied_rmds)
outcomes.append(outcome)

return {
"invalid_rmrs": invalid_rmds,
Expand Down
8 changes: 7 additions & 1 deletion rct229/rulesets/ashrae9012019/section16/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

# Add all available rule modules in __all__
__all__ = [
"section16rule6",
# "section16rule1",
"section16rule2",
"section16rule3",
"section16rule4",
# "section16rule5",
# "section16rule6",
# "section16rule7",
]


Expand Down
136 changes: 136 additions & 0 deletions rct229/rulesets/ashrae9012019/section16/section16rule2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
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.rule_engine.rulesets import LeapYear
from rct229.rulesets.ashrae9012019 import BASELINE_0
from rct229.rulesets.ashrae9012019.ruleset_functions.compare_schedules import (
compare_schedules,
)
from rct229.utils.assertions import getattr_
from rct229.utils.jsonpath_utils import find_all
from rct229.utils.utility_functions import find_exactly_one_schedule


class Section16Rule2(RuleDefinitionListIndexedBase):
"""Rule 2 of ASHRAE 90.1-2019 Appendix G Section 16 (Elevators)"""

def __init__(self):
super(Section16Rule2, self).__init__(
rmds_used=produce_ruleset_model_description(
USER=False,
BASELINE_0=True,
PROPOSED=True,
),
each_rule=Section16Rule2.RuleSetModelDescriptionRule(),
index_rmd=BASELINE_0,
id="16-2",
description="The baseline elevator motor use shall be modeled with the same schedule as the proposed design. Rule Assertion: B-RMD = P-RMD",
ruleset_section_title="Elevators",
standard_section="Section G3.1",
is_primary_rule=True,
list_path="ruleset_model_descriptions[0]",
required_fields={"$": ["calendar"], "$.calendar": ["is_leap_year"]},
data_items={"is_leap_year_b": (BASELINE_0, "calendar/is_leap_year")},
)

class RuleSetModelDescriptionRule(RuleDefinitionListIndexedBase):
def __init__(self):
super(Section16Rule2.RuleSetModelDescriptionRule, self).__init__(
rmds_used=produce_ruleset_model_description(
USER=False, BASELINE_0=True, PROPOSED=True
),
each_rule=Section16Rule2.RuleSetModelDescriptionRule.ElevatorRule(),
index_rmd=BASELINE_0,
list_path="buildings[*].elevators[*]",
)

def is_applicable(self, context, data=None):
rmd_b = context.BASELINE_0
rmd_p = context.PROPOSED

elevators_list_b = find_all("$.buildings[*].elevators[*]", rmd_b)
elevators_list_p = find_all("$.buildings[*].elevators[*]", rmd_p)

return elevators_list_p and elevators_list_b

def create_data(self, context, data):
rmd_b = context.BASELINE_0
rmd_p = context.PROPOSED

motor_use_schedule_b = {
sch_id: find_exactly_one_schedule(rmd_b, sch_id)["hourly_values"]
for sch_id in find_all(
"buildings[*].elevators[*].cab_motor_multiplier_schedule", rmd_b
)
}
motor_use_schedule_p = {
sch_id: find_exactly_one_schedule(rmd_p, sch_id)["hourly_values"]
for sch_id in find_all(
"buildings[*].elevators[*].cab_motor_multiplier_schedule", rmd_p
)
}
return {
"motor_use_schedule_b": motor_use_schedule_b,
"motor_use_schedule_p": motor_use_schedule_p,
}

class ElevatorRule(RuleDefinitionBase):
def __init__(self):
super(
Section16Rule2.RuleSetModelDescriptionRule.ElevatorRule, self
).__init__(
rmds_used=produce_ruleset_model_description(
USER=False,
BASELINE_0=True,
PROPOSED=True,
),
)

def get_calc_vals(self, context, data=None):
elevator_b = context.BASELINE_0
elevator_p = context.PROPOSED

motor_use_schedule_b = getattr_(
elevator_b, "elevators", "cab_motor_multiplier_schedule"
)
motor_use_schedule_p = getattr_(
elevator_p, "elevators", "cab_motor_multiplier_schedule"
)

is_leap_year_b = data["is_leap_year_b"]
motor_use_schedule_b = data["motor_use_schedule_b"][
motor_use_schedule_b
]
motor_use_schedule_p = data["motor_use_schedule_p"][
motor_use_schedule_p
]

mask_schedule = (
[1] * LeapYear.LEAP_YEAR_HOURS
if is_leap_year_b
else [1] * LeapYear.REGULAR_YEAR_HOURS
)

sch_total_hours_matched = compare_schedules(
motor_use_schedule_b,
motor_use_schedule_p,
mask_schedule,
is_leap_year_b,
)["total_hours_matched"]

return {
"motor_use_schedule_len_b": len(motor_use_schedule_b),
"motor_use_schedule_len_p": len(motor_use_schedule_p),
"sch_total_hours_matched": sch_total_hours_matched,
}

def rule_check(self, context, calc_vals=None, data=None):
sch_total_hours_matched = calc_vals["sch_total_hours_matched"]
motor_use_schedule_len_b = calc_vals["motor_use_schedule_len_b"]
motor_use_schedule_len_p = calc_vals["motor_use_schedule_len_p"]

return (
sch_total_hours_matched
== motor_use_schedule_len_b
== motor_use_schedule_len_p
)
135 changes: 135 additions & 0 deletions rct229/rulesets/ashrae9012019/section16/section16rule3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
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.rule_engine.rulesets import LeapYear
from rct229.rulesets.ashrae9012019 import PROPOSED
from rct229.rulesets.ashrae9012019.ruleset_functions.compare_schedules import (
compare_schedules,
)
from rct229.utils.assertions import getattr_
from rct229.utils.jsonpath_utils import find_all
from rct229.utils.utility_functions import find_exactly_one_schedule


class Section16Rule3(RuleDefinitionListIndexedBase):
"""Rule 3 of ASHRAE 90.1-2019 Appendix G Section 16 (Elevators)"""

def __init__(self):
super(Section16Rule3, self).__init__(
rmds_used=produce_ruleset_model_description(
USER=False,
BASELINE_0=False,
PROPOSED=True,
),
each_rule=Section16Rule3.RuleSetModelDescriptionRule(),
index_rmd=PROPOSED,
id="16-3",
description="The elevator cab ventilation fan shall be modeled with the same schedule as the elevator motor.",
ruleset_section_title="Elevators",
standard_section="Section G3.1",
is_primary_rule=True,
list_path="ruleset_model_descriptions[0]",
required_fields={"$": ["calendar"], "$.calendar": ["is_leap_year"]},
data_items={"is_leap_year_p": (PROPOSED, "calendar/is_leap_year")},
)

class RuleSetModelDescriptionRule(RuleDefinitionListIndexedBase):
def __init__(self):
super(Section16Rule3.RuleSetModelDescriptionRule, self).__init__(
rmds_used=produce_ruleset_model_description(
USER=False, BASELINE_0=False, PROPOSED=True
),
each_rule=Section16Rule3.RuleSetModelDescriptionRule.ElevatorRule(),
index_rmd=PROPOSED,
list_path="buildings[*].elevators[*]",
)

def is_applicable(self, context, data=None):
rmd_p = context.PROPOSED

return find_all("$.buildings[*].elevators[*]", rmd_p)

def create_data(self, context, data):
rmd_p = context.PROPOSED

cab_ventilation_schedule_p = {
sch_id: find_exactly_one_schedule(rmd_p, sch_id)["hourly_values"]
for sch_id in find_all(
"buildings[*].elevators[*].cab_ventilation_fan_multiplier_schedule",
rmd_p,
)
}
motor_use_schedule_p = {
sch_id: find_exactly_one_schedule(rmd_p, sch_id)["hourly_values"]
for sch_id in find_all(
"buildings[*].elevators[*].cab_motor_multiplier_schedule",
rmd_p,
)
}

return {
"cab_ventilation_schedule_p": cab_ventilation_schedule_p,
"motor_use_schedule_p": motor_use_schedule_p,
}

class ElevatorRule(RuleDefinitionBase):
def __init__(self):
super(
Section16Rule3.RuleSetModelDescriptionRule.ElevatorRule, self
).__init__(
rmds_used=produce_ruleset_model_description(
USER=False,
BASELINE_0=False,
PROPOSED=True,
),
)

def get_calc_vals(self, context, data=None):
elevator_p = context.PROPOSED
is_leap_year_p = data["is_leap_year_p"]

cab_ventilation_fan_multiplier_schedule_p = getattr_(
elevator_p, "elevators", "cab_ventilation_fan_multiplier_schedule"
)
cab_ventilation_schedule_p = data["cab_ventilation_schedule_p"][
cab_ventilation_fan_multiplier_schedule_p
]

cab_motor_multiplier_schedule_p = getattr_(
elevator_p, "elevators", "cab_motor_multiplier_schedule"
)
motor_use_schedule_p = data["motor_use_schedule_p"][
cab_motor_multiplier_schedule_p
]

mask_schedule = (
[1] * LeapYear.LEAP_YEAR_HOURS
if is_leap_year_p
else [1] * LeapYear.REGULAR_YEAR_HOURS
)

sch_total_hours_matched = compare_schedules(
cab_ventilation_schedule_p,
motor_use_schedule_p,
mask_schedule,
is_leap_year_p,
)["total_hours_matched"]

return {
"sch_total_hours_matched": sch_total_hours_matched,
"cab_ventilation_schedule_len_p": len(cab_ventilation_schedule_p),
"motor_use_schedule_len_p": len(motor_use_schedule_p),
}

def rule_check(self, context, calc_vals=None, data=None):
sch_total_hours_matched = calc_vals["sch_total_hours_matched"]
cab_ventilation_schedule_len_p = calc_vals[
"cab_ventilation_schedule_len_p"
]
motor_use_schedule_len_p = calc_vals["motor_use_schedule_len_p"]

return (
sch_total_hours_matched
== cab_ventilation_schedule_len_p
== motor_use_schedule_len_p
)
Loading

0 comments on commit c6cb6c4

Please sign in to comment.