diff --git a/docs/ashrae_90p1_2019/section6/Rule6-7.md b/docs/ashrae_90p1_2019/section6/Rule6-7.md index 44439ea470..115489191e 100644 --- a/docs/ashrae_90p1_2019/section6/Rule6-7.md +++ b/docs/ashrae_90p1_2019/section6/Rule6-7.md @@ -1,19 +1,27 @@ - # Lighting - Rule 6-7 **Rule ID:** 6-7 **Rule Description:** Proposed building is modeled with daylighting controls directly or through schedule adjustments. **Appendix G Section:** Section 6 Lighting -**Appendix G Section Reference:** Section G3.1-6(h) Lighting: Modeling Requirements for the Proposed design +**Appendix G Section Reference:** Section G3.1-6(h) Lighting: Modeling Requirements for the Proposed design, Table 9.6.1 Minimum Control Requirements -**Applicability:** All required data elements exist for P_RMR +**Applicability:** All required data elements exist for P_RMD **Applicability Checks:** None **Manual Check:** Yes **Evaluation Context:** Each Data Element **Data Lookup:** None ## Rule Logic: +- List lighting space types that have no daylighting control requirements: `not_applicable_space_types = ["DORMITORY_LIVING_QUARTERS", "FIRE_STATION_SLEEPING_QUARTERS", "HEALTHCARE_FACILITY_OPERATING_ROOM", "OUTPATIENT_HEALTH_CARE_FACILITIES_CLASS_1_IMAGING_ROOMS", "DWELLING_UNIT", "GUEST_ROOM", "STORAGE_ROOM_SMALL", "PARKING_AREA_INTERIOR", "NONE"]` + +- Check if each zone has window or skylight in the building segment in the Proposed model: `For zone_p in P_RMD...zones:` + + - Initialize not-applicable space with lighting power flag as FALSE: `na_space_with_lighting_power_flag = FALSE` -- Check if each zone has window or skylight in the building segment in the Proposed model: `For zone_p in P_RMR...zones:` + - For each space in zone, compute total lighting power density and set flag if not-applicable space has lighting power: + `if space.lighting_space_type in not_applicable_space_types and sum(lighting.power_per_area for lighting in space.interior_lighting) > 0: na_space_with_lighting_power_flag = TRUE` + + - Check if all spaces in the zone are in the list of not_applicable space types and no not-applicable space has lighting power, if so, skip the zone: + `if all(space.lighting_space_type in not_applicable_space_types for space in zone_p.spaces) and not na_space_with_lighting_power_flag: continue` - For each surfaces in zone: `surface_p in zone_p.surfaces` @@ -31,20 +39,21 @@ **Rule Assertion:** For each zone in the Proposed model: - - Case 1, if the zone has window or skylight and daylight control, and daylight control is not modeled using schedule: `if ( daylight_flag_p == TRUE ) AND ( has_daylight_control_flag == TRUE ) AND ( NOT daylight_schedule_adjustment_flag ): UNDETERMINED and raise_warning "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."` + - Case 1, if the zone contains a not-applicable space type with lighting power: `if na_space_with_lighting_power_flag: UNDETERMINED and raise_warning "THE ZONE CONTAINS A NOT-APPLICABLE SPACE TYPE WITH LIGHTING POWER. VERIFY THAT THE MANDATORY DAYLIGHTING CONTROL REQUIREMENTS ARE MET, IF APPLICABLE."` + + - Case 2, if the zone has window or skylight and daylight control, and daylight control is not modeled using schedule: `if ( daylight_flag_p == TRUE ) AND ( has_daylight_control_flag == TRUE ) AND ( NOT daylight_schedule_adjustment_flag ): UNDETERMINED and raise_warning "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."` - - Case 2, else if the zone has window or skylight and daylight control, and daylight control is modeled using schedule: `if ( daylight_flag_p == TRUE ) AND ( has_daylight_control_flag == TRUE ) AND ( daylight_schedule_adjustment_flag ): UNDETERMINED and raise_warning "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."` + - Case 3, else if the zone has window or skylight and daylight control, and daylight control is modeled using schedule: `if ( daylight_flag_p == TRUE ) AND ( has_daylight_control_flag == TRUE ) AND ( daylight_schedule_adjustment_flag ): UNDETERMINED and raise_warning "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."` - - Case 3, else if the zone has window or skylight and daylight control is not modeled: `else if ( daylight_flag_p == TRUE ) AND ( has_daylight_control_flag == FALSE ): FAIL and raise_warning "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(E) APPLY."` + - Case 4, else if the zone has window or skylight and daylight control is not modeled: `else if ( daylight_flag_p == TRUE ) AND ( has_daylight_control_flag == FALSE ): FAIL and raise_warning "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(E) APPLY."` - - Case 4, else if the zone does not have window or skylight and daylight control is modeled: `else if ( daylight_flag_p == FALSE ) AND ( has_daylight_control_flag == TRUE ): FAIL` + - Case 5, else if the zone does not have window or skylight and daylight control is modeled: `else if ( daylight_flag_p == FALSE ) AND ( has_daylight_control_flag == TRUE ): FAIL` - - Case 5, else, the zone does not have window or skylight and no daylight control is modeled: `else: PASS` + - Case 6, else, the zone does not have window or skylight and no daylight control is modeled: `else: PASS` **Notes:** 1. Updated the Rule ID from 6-12 to 6-8 on 6/3/2022 2. Updated the Rule ID from 6-8 to 6-7 on 6/8/2022 - 3. The rule has been written to apply to user RMR, it should instead be implemented to apply to P-RMR- should discuss - + 3. Lighting space types that have no daylighting control requirements are taken from Table 9.6.1 rows with no REQ under the daylighting control columns. **[Back](../_toc.md)** diff --git a/rct229/rulesets/ashrae9012019/data/ashrae_90_1_prm_2019.prm_interior_lighting.json b/rct229/rulesets/ashrae9012019/data/ashrae_90_1_prm_2019.prm_interior_lighting.json index ac03f7bf21..ad4a0e37c1 100644 --- a/rct229/rulesets/ashrae9012019/data/ashrae_90_1_prm_2019.prm_interior_lighting.json +++ b/rct229/rulesets/ashrae9012019/data/ashrae_90_1_prm_2019.prm_interior_lighting.json @@ -1832,6 +1832,19 @@ "occup_sensor_auto_on_svgs": 0.1, "occup_sensor_savings": 0.125, "notes": null + }, + { + "template": "90.1-PRM-2019", + "lpd_space_type": "none", + "primary_space_type": "none", + "secondary_space_type": "none", + "w/ft^2": 0, + "w/ft": null, + "isresidential": 0, + "manon_or_partauto": 0, + "occup_sensor_auto_on_svgs": 0, + "occup_sensor_savings": 0, + "notes": null } ] } diff --git a/rct229/rulesets/ashrae9012019/data_fns/table_9_6_1_fns_test.py b/rct229/rulesets/ashrae9012019/data_fns/table_9_6_1_fns_test.py index 915ae7eb7e..6d7870b155 100644 --- a/rct229/rulesets/ashrae9012019/data_fns/table_9_6_1_fns_test.py +++ b/rct229/rulesets/ashrae9012019/data_fns/table_9_6_1_fns_test.py @@ -133,5 +133,6 @@ def test__building_type_enumeration_to_lpd_map(): "TRANSPORTATION_FACILITY_TICKET_COUNTER", "WAREHOUSE_STORAGE_AREA_MEDIUM_TO_BULKY_PALLETIZED_ITEMS", "WAREHOUSE_STORAGE_AREA_SMALLER_HAND_CARRIED_ITEMS", + "NONE", ], ) diff --git a/rct229/rulesets/ashrae9012019/data_fns/table_G3_7_fns.py b/rct229/rulesets/ashrae9012019/data_fns/table_G3_7_fns.py index 09064ada10..e724ddc209 100644 --- a/rct229/rulesets/ashrae9012019/data_fns/table_G3_7_fns.py +++ b/rct229/rulesets/ashrae9012019/data_fns/table_G3_7_fns.py @@ -112,6 +112,7 @@ "TRANSPORTATION_FACILITY_TICKET_COUNTER": "transportation ticket counter", "WAREHOUSE_STORAGE_AREA_MEDIUM_TO_BULKY_PALLETIZED_ITEMS": "warehouse - bulk storage", "WAREHOUSE_STORAGE_AREA_SMALLER_HAND_CARRIED_ITEMS": "warehouse - fine storage", + "NONE": "none", } FULL_AUTO_ON = SchemaEnums.schema_enums["LightingOccupancyControlOptions"].FULL_AUTO_ON diff --git a/rct229/rulesets/ashrae9012019/section6/section6rule7.py b/rct229/rulesets/ashrae9012019/section6/section6rule7.py index 6b8402f3f9..6f1c8054a6 100644 --- a/rct229/rulesets/ashrae9012019/section6/section6rule7.py +++ b/rct229/rulesets/ashrae9012019/section6/section6rule7.py @@ -5,10 +5,15 @@ from rct229.schema.schema_enums import SchemaEnums from rct229.utils.jsonpath_utils import find_all +MSG_WARN_NA_SPACE_WITH_LIGHTING = "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." +VentilationSpaceOptions = SchemaEnums.schema_enums[ + "VentilationSpaceOptions2019ASHRAE901" +] +LightingSpaceOptions = SchemaEnums.schema_enums["LightingSpaceOptions2019ASHRAE901TG37"] DOOR = SchemaEnums.schema_enums["SubsurfaceClassificationOptions"].DOOR EXTERIOR = SchemaEnums.schema_enums["SurfaceAdjacencyOptions"].EXTERIOR NONE = SchemaEnums.schema_enums["LightingDaylightingControlOptions"].NONE @@ -32,6 +37,44 @@ def __init__(self): list_path="ruleset_model_descriptions[0].buildings[*].building_segments[*].zones[*]", ) + def list_filter(self, context_item, data): + zone_p = context_item.PROPOSED + + not_applicable_space_types = { + LightingSpaceOptions.DORMITORY_LIVING_QUARTERS, + LightingSpaceOptions.FIRE_STATION_SLEEPING_QUARTERS, + LightingSpaceOptions.HEALTHCARE_FACILITY_OPERATING_ROOM, + VentilationSpaceOptions.OUTPATIENT_HEALTH_CARE_FACILITIES_CLASS_1_IMAGING_ROOMS, + LightingSpaceOptions.DWELLING_UNIT, + LightingSpaceOptions.GUEST_ROOM, + LightingSpaceOptions.STORAGE_ROOM_SMALL, + LightingSpaceOptions.PARKING_AREA_INTERIOR, + LightingSpaceOptions.NONE, + } + + spaces = zone_p.get("spaces", []) + + na_space_with_lighting_power = any( + ( + space.get("lighting_space_type") in not_applicable_space_types + or space.get("ventilation_space_type") in not_applicable_space_types + ) + and sum( + il.get("power_per_area", 0) for il in space.get("interior_lighting", []) + ) + > 0 + for space in spaces + ) + + # Skip only if all spaces are not applicable and none have lighting power + return not ( + all( + space.get("lighting_space_type") in not_applicable_space_types + for space in spaces + ) + and not na_space_with_lighting_power + ) + class ZoneRule(RuleDefinitionBase): def __init__(self): super(PRM9012019Rule66m62.ZoneRule, self).__init__( @@ -44,71 +87,109 @@ def __init__(self): def get_calc_vals(self, context, data=None): zone_p = context.PROPOSED - daylight_flag_p = ( + not_applicable_space_types = { + LightingSpaceOptions.DORMITORY_LIVING_QUARTERS, + LightingSpaceOptions.FIRE_STATION_SLEEPING_QUARTERS, + LightingSpaceOptions.HEALTHCARE_FACILITY_OPERATING_ROOM, + VentilationSpaceOptions.OUTPATIENT_HEALTH_CARE_FACILITIES_CLASS_1_IMAGING_ROOMS, + LightingSpaceOptions.DWELLING_UNIT, + LightingSpaceOptions.GUEST_ROOM, + LightingSpaceOptions.STORAGE_ROOM_SMALL, + LightingSpaceOptions.PARKING_AREA_INTERIOR, + LightingSpaceOptions.NONE, + } + + has_na_space_with_lighting_power = any( + ( + space.get("lighting_space_type") in not_applicable_space_types + or space.get("ventilation_space_type") in not_applicable_space_types + ) + and sum( + il.get("power_per_area", 0) + for il in space.get("interior_lighting", []) + ) + > 0 + for space in zone_p.get("spaces", []) + ) + + is_daylighting_control_expected = ( len( find_all( - # Doors in a surface adjacent to exterior - f'$.surfaces[*][?(@.adjacent_to = "{EXTERIOR}")].subsurfaces[*][?(@.classification != "{DOOR}")]', + f'$.surfaces[*][?(@.adjacent_to = "{EXTERIOR}")].' + f'subsurfaces[*][?(@.classification != "{DOOR}")]', zone_p, ) ) > 0 ) - has_daylight_control_flag = ( + is_daylighting_control_modeled = ( len( find_all( - # interior_lighting instances with daylighting_control_type set to NONE - f'$.spaces[*].interior_lighting[*][?(@.daylighting_control_type!= "{NONE}")]', + f"$.spaces[*].interior_lighting[*]" + f'[?(@.daylighting_control_type != "{NONE}")]', zone_p, ) ) > 0 ) - daylight_schedule_adjustment_flag = 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, + are_schedules_used_for_modeling_daylighting_controls = ( + len( + find_all( + "$.spaces[*].interior_lighting[*]" + "[?(@.are_schedules_used_for_modeling_daylighting_control = true)]", + zone_p, + ) ) + > 0 ) return { - "daylight_flag_p": daylight_flag_p, - "has_daylight_control_flag": has_daylight_control_flag, - "daylight_schedule_adjustment_flag": daylight_schedule_adjustment_flag, + "na_space_with_lighting_power": has_na_space_with_lighting_power, + "is_daylighting_control_expected": is_daylighting_control_expected, + "is_daylighting_control_modeled": is_daylighting_control_modeled, + "are_schedules_used_for_modeling_daylighting_controls": ( + are_schedules_used_for_modeling_daylighting_controls + ), } def manual_check_required(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"] - - return daylight_flag_p and has_daylight_control_flag + return calc_vals["na_space_with_lighting_power"] or ( + calc_vals["is_daylighting_control_expected"] + and calc_vals["is_daylighting_control_modeled"] + ) def get_manual_check_required_msg(self, context, calc_vals=None, data=None): - daylight_schedule_adjustment_flag = calc_vals[ - "daylight_schedule_adjustment_flag" - ] + if calc_vals["na_space_with_lighting_power"]: + return MSG_WARN_NA_SPACE_WITH_LIGHTING return ( MSG_WARN_DAYLIGHT - if daylight_schedule_adjustment_flag + if calc_vals["are_schedules_used_for_modeling_daylighting_controls"] else MSG_WARN_DAYLIGHT_NO_SCHEDULE ) - 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"] + def rule_check(self, context, calc_vals=None, data=None): + is_daylighting_control_expected = calc_vals[ + "is_daylighting_control_expected" + ] + is_daylighting_control_modeled = calc_vals["is_daylighting_control_modeled"] - return not daylight_flag_p and not has_daylight_control_flag + return ( + not is_daylighting_control_expected + and not is_daylighting_control_modeled + ) 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"] + is_daylighting_control_expected = calc_vals[ + "is_daylighting_control_expected" + ] + is_daylighting_control_modeled = calc_vals["is_daylighting_control_modeled"] return ( MSG_WARN_NO_DAYLIGHT - if daylight_flag_p and not has_daylight_control_flag + if is_daylighting_control_expected + and not is_daylighting_control_modeled else "" ) diff --git a/rct229/schema/Enumerations2019ASHRAE901.schema.json b/rct229/schema/Enumerations2019ASHRAE901.schema.json index 119e5fe2e3..203766c9c2 100644 --- a/rct229/schema/Enumerations2019ASHRAE901.schema.json +++ b/rct229/schema/Enumerations2019ASHRAE901.schema.json @@ -257,7 +257,8 @@ "TRANSPORTATION_FACILITY_AIRPORT_CONCOURSE", "TRANSPORTATION_FACILITY_TICKET_COUNTER", "WAREHOUSE_STORAGE_AREA_MEDIUM_TO_BULKY_PALLETIZED_ITEMS", - "WAREHOUSE_STORAGE_AREA_SMALLER_HAND_CARRIED_ITEMS" + "WAREHOUSE_STORAGE_AREA_SMALLER_HAND_CARRIED_ITEMS", + "NONE" ], "descriptions": [ "Atrium - Low/Medium", @@ -362,7 +363,8 @@ "Transportation Facility - Airport concourse", "Transportation Facility - Ticket counter", "Warehouse \u00e2\u20ac\u201d Storage Area - Medium to bulky, palletized items", - "Warehouse \u00e2\u20ac\u201d Storage Area - Smaller, hand-carried items" + "Warehouse \u00e2\u20ac\u201d Storage Area - Smaller, hand-carried items", + "None" ], "notes": [ null, @@ -467,7 +469,7 @@ null, null, null, - null + "Indicates that the space will have no occupancy, such as an elevator shaft." ] }, "LightingPurposeOptions2019ASHRAE901": {