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
27 changes: 16 additions & 11 deletions docs/ashrae_90p1_2019/section6/Rule6-4.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

**Appendix G Section:** Section G3.1-6 Modeling Requirements for the Baseline

**Applicability:** All required data elements exist for B_RMR
**Applicability:** All required data elements exist for B_RMD
**Applicability Checks:** None
**Manual Check:** No
**Manual Check:** No

**Evaluation Context:** Each Data Element
**Data Lookup:** Table G3.7
Expand All @@ -21,11 +21,11 @@

## Rule Logic:

- For each building segment in the baseline model: `building_segment_b in B_RMR.building.building_segments:`
- For each building segment in the baseline model: `building_segment_b in B_RMD.building.building_segments:`

- Get matching building segment in R_RMR: `building_segment_p = match_data_element(P_RMR, BuildingSegments, building_segment_b.id)`
- Get matching building segment in R_RMD: `building_segment_p = match_data_element(P_RMD, BuildingSegments, building_segment_b.id)`

- Get lighting status type dictionary for P_RMR: `space_lighting_status_type_dict_p = get_lighting_status_type(building_segment_p)`
- Get lighting status type dictionary for P_RMD: `space_lighting_status_type_dict_p = get_lighting_status_type(building_segment_p)`

- For each thermal block in building segment: `thermal_block_b in building_segment_b.thermal_blocks:`

Expand All @@ -36,24 +36,29 @@
- For each space in zone: `space_b in zone_b.spaces:`

- Get total lighting power density in space: `total_space_LPD_b = sum(interior_lighting.power_per_area for interior_lighting in space_b.interior_lighting)`

- Get the space function to later check if the space is crawl space, interstitial space, or plenum: `space_function_b = space_b.function`

- Skip evaluation for any spaces that are plenums, crawl spaces, or interstitial spaces and have no lighting power modeled: `if ( total_space_LPD_b == 0 ) AND ( space_function_b in [CRAWL_SPACE, INTERSTITIAL_SPACE, PLENUM] ): continue`

- Get lighting status type for space: `space_lighting_status_type = space_lighting_status_type_dict_p[match_data_element(P_RMR, Spaces, space_b.id).id]`
- Get lighting status type for space: `space_lighting_status_type = space_lighting_status_type_dict_p[match_data_element(P_RMD, Spaces, space_b.id).id]`

- Check if lighting space type is specified, get lighting power density allowance from Table G3.7: `if space_b.lighting_space_type: LPD_allowance_b = data_lookup(table_G3_7, space_b.lighting_space_type)`

- Else, lighting space type is not specified, assume "Office-Open Plan" as lighting space type to get lighting power density allowance from Table G3.7: `else: LPD_allowance_b = data_lookup(table_G3_7, "OFFICE-OPEN PLAN")`

**Rule Assertion:**
- Case 1: If space has lighting power and is crawl space, interstitial space, or plenum: UNDETERMINED `if ( total_space_LPD_b > 0 ) AND ( space_function_b in [CRAWL_SPACE, INTERSTITIAL_SPACE, PLENUM] ): UNDETERMINED and raise_warning f"Space function is {space_function_b} and has lighting power modeled. Unable to determine whether this space should be included in the check."`

- Case 1: If space lighting status type is as-designed or as-existing, and lighting space type is not specified: `if ( space_lighting_status_type == "AS-DESIGNED OR AS-EXISTING" ) AND ( NOT space_b.lighting_space_type ): FAIL and raise_warning "P_RMR LIGHTING STATUS TYPE IS AS-DESIGNED OR AS-EXISTING. BUT LIGHTING SPACE TYPE IN B_RMR IS NOT SPECIFIED."`
- Case 2: Else if space lighting status type is as-designed or as-existing, and lighting space type is not specified: UNDETERMINED ` else if ( space_lighting_status_type == "AS-DESIGNED OR AS-EXISTING" ) AND ( NOT space_b.lighting_space_type ): UNDETERMINED and raise_warning "The proposed lighting status is 'AS-DESIGNED OR AS-EXISTING' but the baseline lighting space type was not specified."`

- Case 2: Else if space lighting status type is as-designed or as-existing, and space total interior lighting power density in B_RMR matches Table G3.7: `else if ( space_lighting_status_type == "AS-DESIGNED OR AS-EXISTING" ) AND ( total_space_LPD_b == LPD_allowance_b ): PASS`
- Case 3: Else if space lighting status type is as-designed or as-existing, and space total interior lighting power density in B_RMD matches Table G3.7: PASS `else if ( space_lighting_status_type == "AS-DESIGNED OR AS-EXISTING" ) AND ( total_space_LPD_b == LPD_allowance_b ): PASS`

- Case 3: Else if space lighting status type is as-designed or as-existing, and space total interior lighting power density in B_RMR does not match Table G3.7: `else if ( space_lighting_status_type == "AS-DESIGNED OR AS-EXISTING" ) AND ( total_space_LPD_b != LPD_allowance_b ): FAIL`
- Case 4: Else if space lighting status type is as-designed or as-existing, and space total interior lighting power density in B_RMD does not match Table G3.7: FAIL `else if ( space_lighting_status_type == "AS-DESIGNED OR AS-EXISTING" ) AND ( total_space_LPD_b != LPD_allowance_b ): FAIL`

- Case 4: Else if space lighting status type is not-yet designed or matches Table_9_5_1, and space total interior lighting power density in B_RMR matches Table G3.7: `else if ( space_lighting_status_type == "NOT-YET DESIGNED OR MATCH TABLE_9_5_1" ) AND ( total_space_LPD_b == LPD_allowance_b ): PASS`
- Case 5: Else if space lighting status type is not-yet designed or matches Table_9_5_1, and space total interior lighting power density in B_RMD matches Table G3.7: PASS `else if ( space_lighting_status_type == "NOT-YET DESIGNED OR MATCH TABLE_9_5_1" ) AND ( total_space_LPD_b == LPD_allowance_b ): PASS`

- Case 5: Else, space lighting status type is not-yet designed or matches Table_9_5_1, and space total interior lighting power density in B_RMR does not match Table G3.7: `else if ( space_lighting_status_type == "NOT-YET DESIGNED OR MATCH TABLE_9_5_1" ) AND ( total_space_LPD_b != LPD_allowance_b ): FAIL`
- Case 6: Else, space lighting status type is not-yet designed or matches Table_9_5_1, and space total interior lighting power density in B_RMD does not match Table G3.7: FAIL `else if ( space_lighting_status_type == "NOT-YET DESIGNED OR MATCH TABLE_9_5_1" ) AND ( total_space_LPD_b != LPD_allowance_b ): FAIL`

**Notes:**
1. Requirements from addendum AF to 90.1-2019 have not been incorporated into this RDS.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -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",
],
)
1 change: 1 addition & 0 deletions rct229/rulesets/ashrae9012019/data_fns/table_G3_7_fns.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
162 changes: 112 additions & 50 deletions rct229/rulesets/ashrae9012019/section6/section6rule4.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@
OFFICE_OPEN_PLAN = SchemaEnums.schema_enums[
"LightingSpaceOptions2019ASHRAE901TG37"
].OFFICE_OPEN_PLAN
FAIL_MSG = "P_RMD lighting status type is as-designed or as-existing. But lighting space type in B_RMD is not specified."
CASE1_MSG = "The baseline model included at least one plenum, crawlspace, or interstitial space with lighting power. Unable to determine whether these spaces should be included in the check."
CASE2_MSG = "Proposed lighting status type is as-designed or as-existing, but the baseline lighting space type is not specified."
SpaceFunctionOptions = SchemaEnums.schema_enums["SpaceFunctionOptions"]
NA_SPACE_FUNCTIONS = [
SpaceFunctionOptions.PLENUM,
SpaceFunctionOptions.CRAWL_SPACE,
SpaceFunctionOptions.INTERSTITIAL_SPACE,
]


class PRM9012019Rule22l93(RuleDefinitionListIndexedBase):
Expand Down Expand Up @@ -74,15 +81,28 @@ def __init__(self):
def create_data(self, context, data=None):
zone_b = context.BASELINE_0

# We will need this after Weili's update to table_G3_7_lookup()
return {"avg_zone_ht_b": get_avg_zone_height(zone_b)}

def list_filter(self, context_item, data):
space_b = context_item.BASELINE_0
total_space_lpd_b = sum(
find_all("$.interior_lighting[*].power_per_area", space_b),
start=ZERO.POWER_PER_AREA,
)

is_na_or_none = (
space_b.get("function") in NA_SPACE_FUNCTIONS
or space_b.get("lighting_space_type") == "NONE"
)

# Exclude only NA or NONE spaces with zero lighting
return not (is_na_or_none and total_space_lpd_b == ZERO.POWER_PER_AREA)

class SpaceRule(RuleDefinitionBase):
def __init__(self):
super(
PRM9012019Rule22l93.BuildingSegmentRule.ZoneRule.SpaceRule, self
).__init__(
fail_msg=FAIL_MSG,
rmds_used=produce_ruleset_model_description(
USER=False, BASELINE_0=True, PROPOSED=True
),
Expand All @@ -101,42 +121,102 @@ def get_calc_vals(self, context, data=None):
find_all("$.interior_lighting[*].power_per_area", space_b),
start=ZERO.POWER_PER_AREA,
)
space_function_b = space_b.get("function")
lighting_space_type_b = space_b.get("lighting_space_type")

space_lighting_status_type_p = data[
"building_segment_lighting_status_type_dict_p"
][space_p["id"]]
lpd_allowance_b = (
table_G3_7_lookup(
space_b["lighting_space_type"],

# Determine LPD allowance
if lighting_space_type_b is not None:
lpd_allowance_b = table_G3_7_lookup(
lighting_space_type_b,
data["avg_zone_ht_b"],
getattr_(space_b, "Space", "floor_area"),
)
if "lighting_space_type" in space_b
else table_G3_7_lookup(
)["lpd"]
else:
lpd_allowance_b = table_G3_7_lookup(
OFFICE_OPEN_PLAN,
data["avg_zone_ht_b"],
getattr_(space_b, "Space", "floor_area"),
)
)["lpd"]
)["lpd"]

return {
"lighting_space_type_b": space_b.get("lighting_space_type"),
"space_function_b": space_function_b,
"lighting_space_type_b": lighting_space_type_b,
"total_space_lpd_b": CalcQ("power_density", total_space_lpd_b),
"space_lighting_status_type_p": space_lighting_status_type_p,
"lpd_allowance_b": CalcQ("power_density", lpd_allowance_b),
"lpd_allowance_b": (
CalcQ("power_density", lpd_allowance_b)
if lpd_allowance_b is not None
else None
),
}

def rule_check(self, context, calc_vals=None, data=None):
space_b = context.BASELINE_0
lighting_space_type_b = space_b.get("lighting_space_type")
def manual_check_required(self, context, calc_vals=None, data=None):
space_function_b = calc_vals["space_function_b"]
lighting_space_type_b = calc_vals["lighting_space_type_b"]
space_lighting_status_type_p = calc_vals[
"space_lighting_status_type_p"
]
total_space_lpd_b = calc_vals["total_space_lpd_b"]

# Case 1: NA space with lighting
if (
space_function_b in NA_SPACE_FUNCTIONS
and total_space_lpd_b > ZERO.POWER_PER_AREA
):
return True

# Case 2: as-designed / as-existing but lighting space type missing
if (
space_lighting_status_type_p
== LightingStatusType.AS_DESIGNED_OR_AS_EXISTING
and lighting_space_type_b is None
):
return True

return False

def get_manual_check_required_msg(
self, context, calc_vals=None, data=None
):
space_function_b = calc_vals["space_function_b"]
lighting_space_type_b = calc_vals["lighting_space_type_b"]
space_lighting_status_type_p = calc_vals[
"space_lighting_status_type_p"
]
total_space_lpd_b = calc_vals["total_space_lpd_b"]

# Case 1: NA space with lighting
if (
space_function_b in NA_SPACE_FUNCTIONS
and total_space_lpd_b > ZERO.POWER_PER_AREA
):
return CASE1_MSG

# Case 2: as-designed/as-existing but baseline lighting space type missing
if (
space_lighting_status_type_p
== LightingStatusType.AS_DESIGNED_OR_AS_EXISTING
and lighting_space_type_b is None
):
return CASE2_MSG

return ""

def rule_check(self, context, calc_vals=None, data=None):
space_function_b = calc_vals["space_function_b"]
lighting_space_type_b = calc_vals["lighting_space_type_b"]
space_lighting_status_type_p = calc_vals[
"space_lighting_status_type_p"
]
total_space_lpd_b = calc_vals["total_space_lpd_b"]
lpd_allowance_b = calc_vals["lpd_allowance_b"]

return (
# Not Case 1
# Not Case 2
not (
space_lighting_status_type_p
== LightingStatusType.AS_DESIGNED_OR_AS_EXISTING
Expand All @@ -156,45 +236,27 @@ def rule_check(self, context, calc_vals=None, data=None):
)

def is_tolerance_fail(self, context, calc_vals=None, data=None):
space_b = context.BASELINE_0
lighting_space_type_b = space_b.get("lighting_space_type")

space_function_b = calc_vals["space_function_b"]
lighting_space_type_b = calc_vals["lighting_space_type_b"]
space_lighting_status_type_p = calc_vals[
"space_lighting_status_type_p"
]
total_space_lpd_b = calc_vals["total_space_lpd_b"]
lpd_allowance_b = calc_vals["lpd_allowance_b"]

return (
# Not Case 1
not (
space_lighting_status_type_p
== LightingStatusType.AS_DESIGNED_OR_AS_EXISTING
and not lighting_space_type_b
)
# Passes for both values of space_lighting_status_type_p
and (
space_lighting_status_type_p
in [
LightingStatusType.AS_DESIGNED_OR_AS_EXISTING,
LightingStatusType.NOT_YET_DESIGNED_OR_MATCH_TABLE_9_5_1,
]
and std_equal(lpd_allowance_b, total_space_lpd_b)
)
)
if (
space_function_b in NA_SPACE_FUNCTIONS
and total_space_lpd_b > ZERO.POWER_PER_AREA
):
return False

def get_fail_msg(self, context, calc_vals=None, data=None):
space_b = context.BASELINE_0
lighting_space_type_b = space_b.get("lighting_space_type")
if lighting_space_type_b == "NONE":
return False

space_lighting_status_type_p = calc_vals[
"space_lighting_status_type_p"
]
if space_lighting_status_type_p in [
LightingStatusType.AS_DESIGNED_OR_AS_EXISTING,
LightingStatusType.NOT_YET_DESIGNED_OR_MATCH_TABLE_9_5_1,
]:
return std_equal(lpd_allowance_b, total_space_lpd_b)

return (
"P_RMD lighting status type is as-designed or as-existing. But lighting space type in B_RMD is not specified."
if space_lighting_status_type_p
== LightingStatusType.AS_DESIGNED_OR_AS_EXISTING
and not lighting_space_type_b
else ""
)
return False
Loading
Loading