@@ -1299,6 +1299,141 @@ def isFenestrated(s=None) -> bool:
12991299 return True
13001300
13011301
1302+ # ---- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---- #
1303+ # ---- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---- #
1304+ # This next set of utilities (~850 lines) help distinguish spaces that are
1305+ # directly vs indirectly CONDITIONED, vs SEMIHEATED. The solution here
1306+ # relies as much as possible on space conditioning categories found in
1307+ # standards like ASHRAE 90.1 and energy codes like the Canadian NECBs.
1308+ #
1309+ # Both documents share many similarities, regardless of nomenclature. There
1310+ # are however noticeable differences between approaches on how a space is
1311+ # tagged as falling into one of the aforementioned categories. First, an
1312+ # overview of 90.1 requirements, with some minor edits for brevity/emphasis:
1313+ #
1314+ # www.pnnl.gov/main/publications/external/technical_reports/PNNL-26917.pdf
1315+ #
1316+ # 3.2.1. General Information - SPACE CONDITIONING CATEGORY
1317+ #
1318+ # - CONDITIONED space: an ENCLOSED space that has a heating and/or
1319+ # cooling system of sufficient size to maintain temperatures suitable
1320+ # for HUMAN COMFORT:
1321+ # - COOLED: cooled by a system >= 10 W/m2
1322+ # - HEATED: heated by a system, e.g. >= 50 W/m2 in Climate Zone CZ-7
1323+ # - INDIRECTLY: heated or cooled via adjacent space(s) provided:
1324+ # - UA of adjacent surfaces > UA of other surfaces
1325+ # or
1326+ # - intentional air transfer from HEATED/COOLED space > 3 ACH
1327+ #
1328+ # ... includes plenums, atria, etc.
1329+ #
1330+ # - SEMIHEATED space: an ENCLOSED space that has a heating system
1331+ # >= 10 W/m2, yet NOT a CONDITIONED space (see above).
1332+ #
1333+ # - UNCONDITIONED space: an ENCLOSED space that is NOT a conditioned
1334+ # space or a SEMIHEATED space (see above).
1335+ #
1336+ # NOTE: Crawlspaces, attics, and parking garages with natural or
1337+ # mechanical ventilation are considered UNENCLOSED spaces.
1338+ #
1339+ # 2.3.3 Modeling Requirements: surfaces adjacent to UNENCLOSED spaces
1340+ # shall be treated as exterior surfaces. All other UNENCLOSED surfaces
1341+ # are to be modeled as is in both proposed and baseline models. For
1342+ # instance, modeled fenestration in UNENCLOSED spaces would not be
1343+ # factored in WWR calculations.
1344+ #
1345+ #
1346+ # Related NECB definitions and concepts, starting with CONDITIONED space:
1347+ #
1348+ # "[...] the temperature of which is controlled to limit variation in
1349+ # response to the exterior ambient temperature by the provision, either
1350+ # DIRECTLY or INDIRECTLY, of heating or cooling [...]". Although criteria
1351+ # differ (e.g., not sizing-based), the general idea is sufficiently similar
1352+ # to ASHRAE 90.1 (e.g. heating and/or cooling based, no distinction for
1353+ # INDIRECTLY conditioned spaces like plenums).
1354+ #
1355+ # SEMIHEATED spaces are described in the NECB (yet not a defined term). The
1356+ # distinction is also based on desired/intended design space setpoint
1357+ # temperatures (here 15°C) - not system sizing criteria. No further treatment
1358+ # is implemented here to distinguish SEMIHEATED from CONDITIONED spaces;
1359+ # notwithstanding the AdditionalProperties tag (described further in this
1360+ # section), it is up to users to determine if a CONDITIONED space is
1361+ # indeed SEMIHEATED or not (e.g. based on MIN/MAX setpoints).
1362+ #
1363+ # The single NECB criterion distinguishing UNCONDITIONED ENCLOSED spaces
1364+ # (such as vestibules) from UNENCLOSED spaces (such as attics) remains the
1365+ # intention to ventilate - or rather to what degree. Regardless, the methods
1366+ # here are designed to process both classifications in the same way, namely
1367+ # by focusing on adjacent surfaces to CONDITIONED (or SEMIHEATED) spaces as
1368+ # part of the building envelope.
1369+
1370+ # In light of the above, OSut methods here are designed without a priori
1371+ # knowledge of explicit system sizing choices or access to iterative
1372+ # autosizing processes. As discussed in greater detail below, methods here
1373+ # are developed to rely on zoning and/or "intended" setpoint temperatures.
1374+ # In addition, OSut methods here cannot distinguish between UNCONDITIONED vs
1375+ # UNENCLOSED spaces from OpenStudio geometry alone. They are henceforth
1376+ # considered synonymous.
1377+ #
1378+ # For an OpenStudio model in an incomplete or preliminary state, e.g. holding
1379+ # fully-formed ENCLOSED spaces WITHOUT thermal zoning information or setpoint
1380+ # temperatures (early design stage assessments of form, porosity or
1381+ # envelope), OpenStudio spaces are considered CONDITIONED by default. This
1382+ # default behaviour may be reset based on the (Space) AdditionalProperties
1383+ # "space_conditioning_category" key (4x possible values), which is relied
1384+ # upon by OpenStudio-Standards:
1385+ #
1386+ # github.com/NREL/openstudio-standards/blob/
1387+ # d2b5e28928e712cb3f137ab5c1ad6d8889ca02b7/lib/openstudio-standards/
1388+ # standards/Standards.Space.rb#L1604C5-L1605C1
1389+ #
1390+ # OpenStudio-Standards recognizes 4x possible value strings:
1391+ # - "NonResConditioned"
1392+ # - "ResConditioned"
1393+ # - "Semiheated"
1394+ # - "Unconditioned"
1395+ #
1396+ # OSut maintains existing "space_conditioning_category" key/value pairs
1397+ # intact. Based on these, OSut methods may return related outputs:
1398+ #
1399+ # "space_conditioning_category" | OSut status | heating °C | cooling °C
1400+ # ------------------------------- ------------- ---------- ----------
1401+ # - "NonResConditioned" CONDITIONED 21.0 24.0
1402+ # - "ResConditioned" CONDITIONED 21.0 24.0
1403+ # - "Semiheated" SEMIHEATED 15.0 NA
1404+ # - "Unconditioned" UNCONDITIONED NA NA
1405+ #
1406+ # OSut also looks up another (Space) AdditionalProperties 'key',
1407+ # "indirectlyconditioned" to flag plenum or occupied spaces indirectly
1408+ # conditioned with transfer air only. The only accepted 'value' for an
1409+ # "indirectlyconditioned" 'key' is the name (string) of another (linked)
1410+ # space, e.g.:
1411+ #
1412+ # "indirectlyconditioned" space | linked space, e.g. "core_space"
1413+ # ------------------------------- ---------------------------------------
1414+ # return air plenum occupied space below
1415+ # supply air plenum occupied space above
1416+ # dead air space (not a plenum) nearby occupied space
1417+ #
1418+ # OSut doesn't validate whether the "indirectlyconditioned" space is actually
1419+ # adjacent to its linked space. It nonetheless relies on the latter's
1420+ # conditioning category (e.g. CONDITIONED, SEMIHEATED) to determine
1421+ # anticipated ambient temperatures in the former. For instance, an
1422+ # "indirectlyconditioned"-tagged return air plenum linked to a SEMIHEATED
1423+ # space is considered as free-floating in terms of cooling, and unlikely to
1424+ # have ambient conditions below 15°C under heating (winter) design
1425+ # conditions. OSut will associate this plenum to a 15°C heating setpoint
1426+ # temperature. If the SEMIHEATED space instead has a heating setpoint
1427+ # temperature of 7°C, then OSut will associate a 7°C heating setpoint to this
1428+ # plenum.
1429+ #
1430+ # Even with a (more developed) OpenStudio model holding valid space/zone
1431+ # setpoint temperatures, OSut gives priority to these AdditionalProperties.
1432+ # For instance, a CONDITIONED space can be considered INDIRECTLYCONDITIONED,
1433+ # even if its zone thermostat has a valid heating and/or cooling setpoint.
1434+ # This is in sync with OpenStudio-Standards' method
1435+ # "space_conditioning_category()".
1436+
13021437def hasAirLoopsHVAC (model = None ) -> bool :
13031438 """Validates if model has zones with HVAC air loops.
13041439
@@ -1668,14 +1803,14 @@ def maxHeatScheduledSetpoint(zone=None) -> dict:
16681803
16691804
16701805def hasHeatingTemperatureSetpoints (model = None ):
1671- """Confirms if model has zones with valid heating temperature setpoints .
1806+ """Confirms if model has zones with valid heating setpoint temperature .
16721807
16731808 Args:
16741809 model (openstudio.model.Model):
16751810 An OpenStudio model.
16761811
16771812 Returns:
1678- bool: Whether model holds valid heating temperature setpoints .
1813+ bool: Whether model holds valid heating setpoint temperatures .
16791814 False: If invalid inputs (see logs).
16801815 """
16811816 mth = "osut.hasHeatingTemperatureSetpoints"
@@ -1850,14 +1985,14 @@ def minCoolScheduledSetpoint(zone=None):
18501985
18511986
18521987def hasCoolingTemperatureSetpoints (model = None ):
1853- """Confirms if model has zones with valid cooling temperature setpoints .
1988+ """Confirms if model has zones with valid cooling setpoint temperatures .
18541989
18551990 Args:
18561991 model (openstudio.model.Model):
18571992 An OpenStudio model.
18581993
18591994 Returns:
1860- bool: Whether model holds valid cooling temperature setpoints .
1995+ bool: Whether model holds valid cooling setpoint temperatures .
18611996 False: If invalid inputs (see logs).
18621997 """
18631998 mth = "osut.hasCoolingTemperatureSetpoints"
@@ -3089,7 +3224,7 @@ def triads(pts=None, co=False) -> openstudio.Point3dVectorVector:
30893224
30903225 i3 = i2 + 1
30913226 if i3 == len (pts ): i3 = 0
3092-
3227+
30933228 p2 = pts [i2 ]
30943229 p3 = pts [i3 ]
30953230
0 commit comments