Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 57 additions & 17 deletions rct229/rulesets/ashrae9012019/section6/section6rule7.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,31 @@
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 PROPOSED
from rct229.schema.config import ureg
from rct229.schema.schema_enums import SchemaEnums
from rct229.utils.jsonpath_utils import find_all

MSG_WARN_NA_LTG_POWER = "The zone contains a not-applicable space type with lighting power. Verify that the mandatory daylighting control requirements are met, if applicable."
MSG_WARN_DAYLIGHT_NO_SCHEDULE = "Some of the spaces in zone are modeled with window(s) and/or skylight(s) and have daylighting controls modeled explicitly in the simulation tool. Verify that the mandatory lighting control requirements are met."
MSG_WARN_DAYLIGHT = "Some of the spaces in zone are modeled with window(s) and/or skylight(s) and have daylighting controls modeled via schedule adjustment. Verify that the mandatory lighting control requirements are met, and that the supporting documentation is provided for the schedule adjustment."
MSG_WARN_NO_DAYLIGHT = "Some of the spaces in zone are modeled with fenestration but no daylighting controls. The design must include mandatory daylighting controls unless any of the exceptions to 90.1 section 9.4.1.1 apply."

DOOR = SchemaEnums.schema_enums["SubsurfaceClassificationOptions"].DOOR
EXTERIOR = SchemaEnums.schema_enums["SurfaceAdjacencyOptions"].EXTERIOR
NONE = SchemaEnums.schema_enums["LightingDaylightingControlOptions"].NONE
LIGHTING_SPACE = SchemaEnums.schema_enums["LightingSpaceOptions2019ASHRAE901TG37"]

NOT_APPLICABLE_SPACE_TYPES = [
LIGHTING_SPACE.DORMITORY_LIVING_QUARTERS,
LIGHTING_SPACE.FIRE_STATION_SLEEPING_QUARTERS,
LIGHTING_SPACE.HEALTHCARE_FACILITY_OPERATING_ROOM,
# LIGHTING_SPACE.OUTPATIENT_HEALTH_CARE_FACILITIES_CLASS_1_IMAGING_ROOMS,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is NOT one of the LightingSpaceOptions2019ASHRAE901TG37, but one of the VentilationSpaceOptions2019ASHRAE901. I believe this is a mistake in the RDS, but I'd like to bring it up for double-checking.

LIGHTING_SPACE.DWELLING_UNIT,
LIGHTING_SPACE.GUEST_ROOM,
LIGHTING_SPACE.STORAGE_ROOM_SMALL,
LIGHTING_SPACE.PARKING_AREA_INTERIOR,
LIGHTING_SPACE.NONE,
]


class PRM9012019Rule66m62(RuleDefinitionListIndexedBase):
Expand Down Expand Up @@ -55,7 +70,7 @@ def get_calc_vals(self, context, data=None):
> 0
)

has_daylight_control_flag = (
has_daylight_control_flag_p = (
len(
find_all(
# interior_lighting instances with daylighting_control_type set to NONE
Expand All @@ -66,49 +81,74 @@ def get_calc_vals(self, context, data=None):
> 0
)

daylight_schedule_adjustment_flag = any(
daylight_schedule_adjustment_flag_p = any(
find_all(
# interior_lighting instances with are_schedules_used_for_modeling_daylighting_control set to True
"$.spaces[*].interior_lighting[*][?(@.are_schedules_used_for_modeling_daylighting_control = true)]",
zone_p,
)
)

na_space_with_lighting_power_flag_P = any(
[
space_p.get("lighting_space_type") in NOT_APPLICABLE_SPACE_TYPES
and sum(
[
int_ltg_p.get("power_per_area", 0 * ureg("W/m2"))
for int_ltg_p in find_all("$.interior_lighting[*]", space_p)
]
)
for space_p in find_all("$.spaces[*]", zone_p)
]
)

return {
"daylight_flag_p": daylight_flag_p,
"has_daylight_control_flag": has_daylight_control_flag,
"daylight_schedule_adjustment_flag": daylight_schedule_adjustment_flag,
"has_daylight_control_flag_p": has_daylight_control_flag_p,
"daylight_schedule_adjustment_flag_p": daylight_schedule_adjustment_flag_p,
"na_space_with_lighting_power_flag_P": na_space_with_lighting_power_flag_P,
}

def manual_check_required(self, context, calc_vals=None, data=None):
na_space_with_lighting_power_flag_P = calc_vals[
"na_space_with_lighting_power_flag_P"
]
daylight_flag_p = calc_vals["daylight_flag_p"]
has_daylight_control_flag = calc_vals["has_daylight_control_flag"]
has_daylight_control_flag_p = calc_vals["has_daylight_control_flag_p"]

return daylight_flag_p and has_daylight_control_flag
return na_space_with_lighting_power_flag_P or (
daylight_flag_p and has_daylight_control_flag_p
)

def get_manual_check_required_msg(self, context, calc_vals=None, data=None):
daylight_schedule_adjustment_flag = calc_vals[
"daylight_schedule_adjustment_flag"
na_space_with_lighting_power_flag_P = calc_vals[
"na_space_with_lighting_power_flag_P"
]
daylight_schedule_adjustment_flag_p = calc_vals[
"daylight_schedule_adjustment_flag_p"
]

return (
MSG_WARN_DAYLIGHT
if daylight_schedule_adjustment_flag
else MSG_WARN_DAYLIGHT_NO_SCHEDULE
)
if na_space_with_lighting_power_flag_P:
UNDETERMINED_MSG = MSG_WARN_NA_LTG_POWER
elif daylight_schedule_adjustment_flag_p:
UNDETERMINED_MSG = MSG_WARN_DAYLIGHT
elif not daylight_schedule_adjustment_flag_p:
UNDETERMINED_MSG = MSG_WARN_DAYLIGHT_NO_SCHEDULE

return UNDETERMINED_MSG

def rule_check(self, context, calc_vals, data=None):
daylight_flag_p = calc_vals["daylight_flag_p"]
has_daylight_control_flag = calc_vals["has_daylight_control_flag"]
has_daylight_control_flag_p = calc_vals["has_daylight_control_flag_p"]

return not daylight_flag_p and not has_daylight_control_flag
return not daylight_flag_p and not has_daylight_control_flag_p

def get_fail_msg(self, context, calc_vals=None, data=None):
daylight_flag_p = calc_vals["daylight_flag_p"]
has_daylight_control_flag = calc_vals["has_daylight_control_flag"]
has_daylight_control_flag_p = calc_vals["has_daylight_control_flag_p"]

return (
MSG_WARN_NO_DAYLIGHT
if daylight_flag_p and not has_daylight_control_flag
if daylight_flag_p and not has_daylight_control_flag_p
else ""
)
74 changes: 57 additions & 17 deletions rct229/rulesets/ashrae9012022/section6/section6rule7.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,31 @@
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.ashrae9012022 import PROPOSED
from rct229.schema.config import ureg
from rct229.schema.schema_enums import SchemaEnums
from rct229.utils.jsonpath_utils import find_all

MSG_WARN_NA_LTG_POWER = "The zone contains a not-applicable space type with lighting power. Verify that the mandatory daylighting control requirements are met, if applicable."
MSG_WARN_DAYLIGHT_NO_SCHEDULE = "Some of the spaces in zone are modeled with window(s) and/or skylight(s) and have daylighting controls modeled explicitly in the simulation tool. Verify that the mandatory lighting control requirements are met."
MSG_WARN_DAYLIGHT = "Some of the spaces in zone are modeled with window(s) and/or skylight(s) and have daylighting controls modeled via schedule adjustment. Verify that the mandatory lighting control requirements are met, and that the supporting documentation is provided for the schedule adjustment."
MSG_WARN_NO_DAYLIGHT = "Some of the spaces in zone are modeled with fenestration but no daylighting controls. The design must include mandatory daylighting controls unless any of the exceptions to 90.1 section 9.4.1.1 apply."

DOOR = SchemaEnums.schema_enums["SubsurfaceClassificationOptions"].DOOR
EXTERIOR = SchemaEnums.schema_enums["SurfaceAdjacencyOptions"].EXTERIOR
NONE = SchemaEnums.schema_enums["LightingDaylightingControlOptions"].NONE
LIGHTING_SPACE = SchemaEnums.schema_enums["LightingSpaceOptions2019ASHRAE901TG37"]

NOT_APPLICABLE_SPACE_TYPES = [
LIGHTING_SPACE.DORMITORY_LIVING_QUARTERS,
LIGHTING_SPACE.FIRE_STATION_SLEEPING_QUARTERS,
LIGHTING_SPACE.HEALTHCARE_FACILITY_OPERATING_ROOM,
# LIGHTING_SPACE.OUTPATIENT_HEALTH_CARE_FACILITIES_CLASS_1_IMAGING_ROOMS,
LIGHTING_SPACE.DWELLING_UNIT,
LIGHTING_SPACE.GUEST_ROOM,
LIGHTING_SPACE.STORAGE_ROOM_SMALL,
LIGHTING_SPACE.PARKING_AREA_INTERIOR,
LIGHTING_SPACE.NONE,
]


class PRM9012022Rule66m62(RuleDefinitionListIndexedBase):
Expand Down Expand Up @@ -55,7 +70,7 @@ def get_calc_vals(self, context, data=None):
> 0
)

has_daylight_control_flag = (
has_daylight_control_flag_p = (
len(
find_all(
# interior_lighting instances with daylighting_control_type set to NONE
Expand All @@ -66,49 +81,74 @@ def get_calc_vals(self, context, data=None):
> 0
)

daylight_schedule_adjustment_flag = any(
daylight_schedule_adjustment_flag_p = any(
find_all(
# interior_lighting instances with are_schedules_used_for_modeling_daylighting_control set to True
"$.spaces[*].interior_lighting[*][?(@.are_schedules_used_for_modeling_daylighting_control = true)]",
zone_p,
)
)

na_space_with_lighting_power_flag_P = any(
[
space_p.get("lighting_space_type") in NOT_APPLICABLE_SPACE_TYPES
and sum(
[
int_ltg_p.get("power_per_area", 0 * ureg("W/m2"))
for int_ltg_p in find_all("$.interior_lighting[*]", space_p)
]
)
for space_p in find_all("$.spaces[*]", zone_p)
]
)

return {
"daylight_flag_p": daylight_flag_p,
"has_daylight_control_flag": has_daylight_control_flag,
"daylight_schedule_adjustment_flag": daylight_schedule_adjustment_flag,
"has_daylight_control_flag_p": has_daylight_control_flag_p,
"daylight_schedule_adjustment_flag_p": daylight_schedule_adjustment_flag_p,
"na_space_with_lighting_power_flag_P": na_space_with_lighting_power_flag_P,
}

def manual_check_required(self, context, calc_vals=None, data=None):
na_space_with_lighting_power_flag_P = calc_vals[
"na_space_with_lighting_power_flag_P"
]
daylight_flag_p = calc_vals["daylight_flag_p"]
has_daylight_control_flag = calc_vals["has_daylight_control_flag"]
has_daylight_control_flag_p = calc_vals["has_daylight_control_flag_p"]

return daylight_flag_p and has_daylight_control_flag
return na_space_with_lighting_power_flag_P or (
daylight_flag_p and has_daylight_control_flag_p
)

def get_manual_check_required_msg(self, context, calc_vals=None, data=None):
daylight_schedule_adjustment_flag = calc_vals[
"daylight_schedule_adjustment_flag"
na_space_with_lighting_power_flag_P = calc_vals[
"na_space_with_lighting_power_flag_P"
]
daylight_schedule_adjustment_flag_p = calc_vals[
"daylight_schedule_adjustment_flag_p"
]

return (
MSG_WARN_DAYLIGHT
if daylight_schedule_adjustment_flag
else MSG_WARN_DAYLIGHT_NO_SCHEDULE
)
if na_space_with_lighting_power_flag_P:
UNDETERMINED_MSG = MSG_WARN_NA_LTG_POWER
elif daylight_schedule_adjustment_flag_p:
UNDETERMINED_MSG = MSG_WARN_DAYLIGHT
elif not daylight_schedule_adjustment_flag_p:
UNDETERMINED_MSG = MSG_WARN_DAYLIGHT_NO_SCHEDULE

return UNDETERMINED_MSG

def rule_check(self, context, calc_vals, data=None):
daylight_flag_p = calc_vals["daylight_flag_p"]
has_daylight_control_flag = calc_vals["has_daylight_control_flag"]
has_daylight_control_flag_p = calc_vals["has_daylight_control_flag_p"]

return not daylight_flag_p and not has_daylight_control_flag
return not daylight_flag_p and not has_daylight_control_flag_p

def get_fail_msg(self, context, calc_vals=None, data=None):
daylight_flag_p = calc_vals["daylight_flag_p"]
has_daylight_control_flag = calc_vals["has_daylight_control_flag"]
has_daylight_control_flag_p = calc_vals["has_daylight_control_flag_p"]

return (
MSG_WARN_NO_DAYLIGHT
if daylight_flag_p and not has_daylight_control_flag
if daylight_flag_p and not has_daylight_control_flag_p
else ""
)
Loading
Loading