Skip to content

Commit 5075f30

Browse files
committed
Tests OSM file open/read
1 parent cd30085 commit 5075f30

File tree

3 files changed

+5764
-4
lines changed

3 files changed

+5764
-4
lines changed

src/osut/osut.py

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,68 @@ def uo() -> dict:
206206
return _uo
207207

208208

209+
def are_standardOpaqueLayers(lc=None) -> bool:
210+
"""
211+
Validates if every material in a layered construction is standard & opaque.
212+
213+
Args:
214+
lc:
215+
an OpenStudio layered construction
216+
217+
Returns:
218+
Whether all layers are valid. False if invalid inputs (see logs).
219+
220+
"""
221+
mth = "osut.are_standardOpaqueLayers"
222+
cl = openstudio.model.LayeredConstruction
223+
224+
if not hasattr(lc, CN.NS):
225+
return oslg.invalid("layered construction", mth, 1, DBG, 0.0)
226+
227+
id = lc.nameString()
228+
229+
if not isinstance(lc, cl):
230+
return oslg.mismatch(id, lc, cl, mth, CN.DBG, 0.0)
231+
232+
for m in lc.layers():
233+
if not m.to_StandardOpaqueMaterial(): return False
234+
235+
return True
236+
237+
238+
def thickness(lc=None) -> float:
239+
"""
240+
Returns total (standard opaque) layered construction thickness (m).
241+
242+
Args:
243+
lc:
244+
an OpenStudio layered construction
245+
246+
Returns:
247+
Construction thickness. 0.0 if invalid inputs (see logs).
248+
249+
"""
250+
mth = "osut.thickness"
251+
cl = openStudio.model.LayeredConstruction
252+
d = 0.0
253+
254+
if not hasattr(lc, CN.NS):
255+
return oslg.invalid("layered construction", mth, 1, DBG, 0.0)
256+
257+
id = lc.nameString()
258+
259+
if not isinstance(lc, cl):
260+
return oslg.mismatch(id, lc, cl, mth, CN.DBG, 0.0)
261+
262+
if not osut.are_standardOpaqueLayers(lc):
263+
log(CN.ERR, "%s holds non-StandardOpaqueMaterial(s) %s" % (id, mth))
264+
return d
265+
266+
for m in lc.layers(): d += m.thickness()
267+
268+
return d
269+
270+
209271
def rsi(lc=None, film=0.0, t=0.0) -> float:
210272
"""
211273
Returns a construction's 'standard calc' thermal resistance (m2•K/W), which
@@ -307,7 +369,7 @@ def insulatingLayer(lc=None) -> dict:
307369
i = 0 # iterator
308370

309371
if not hasattr(lc, CN.NS):
310-
return oslg.invalid("lc", mth, 1, CN.DBG, res)
372+
return oslg.invalid("layered construction", mth, 1, CN.DBG, res)
311373

312374
id = lc.nameString()
313375

@@ -725,3 +787,106 @@ def genConstruction(model=None, specs=dict()):
725787
layer.setThickness(d)
726788

727789
return c
790+
791+
792+
def genShade(subs=openstudio.model.SubSurfaceVector()) -> bool:
793+
"""
794+
Generates solar shade(s) (e.g. roller, textile) for glazed OpenStudio
795+
SubSurfaces (v321+), controlled to minimize overheating in cooling months
796+
(May to October in Northern Hemisphere), when outdoor dry bulb temperature
797+
is above 18°C and impinging solar radiation is above 100 W/m2.
798+
799+
Args:
800+
subs:
801+
A list of sub surfaces.
802+
803+
Returns:
804+
Whether successfully generated. False if invalid input (see logs).
805+
806+
"""
807+
# Filter OpenStudio warnings for ShadingControl:
808+
# ref: https://github.com/NREL/OpenStudio/issues/4911
809+
# str = ".*(?<!ShadingControl)$"
810+
# openstudio.Logger().instance().standardOutLogger().setChannelRegex(str)
811+
812+
mth = "osut.genShade"
813+
v = int("".join(openstudio.openStudioVersion().split(".")))
814+
cl = openstudio.model.SubSurfaceVector
815+
816+
if v < 321: return False
817+
818+
if not isinstance(subs, cl):
819+
return oslg.mismatch("subs", subs, cl, mth, CN.DBG, False)
820+
821+
if not subs:
822+
return oslg.empty("subs", mth, CN.WRN, False)
823+
824+
# Shading availability period.
825+
model = subs[0].model()
826+
id = "onoff"
827+
onoff = model.getScheduleTypeLimitsByName(id)
828+
829+
if onoff:
830+
onoff = onoff.get()
831+
else:
832+
onoff = openstudio.model.ScheduleTypeLimits(model)
833+
onoff.setName(id)
834+
onoff.setLowerLimitValue(0)
835+
onoff.setUpperLimitValue(1)
836+
onoff.setNumericType("Discrete")
837+
onoff.setUnitType("Availability")
838+
839+
# Shading schedule.
840+
id = "OSut.SHADE.Ruleset"
841+
sch = model.getScheduleRulesetByName(id)
842+
843+
if sch:
844+
sch = sch.get()
845+
else:
846+
sch = openstudio.model.ScheduleRuleset(model, 0)
847+
sch.setName(id)
848+
sch.setScheduleTypeLimits(onoff)
849+
sch.defaultDaySchedule.setName("OSut.SHADE.Ruleset.Default")
850+
851+
# Summer cooling rule.
852+
id = "OSut.SHADE.ScheduleRule"
853+
rule = model.getScheduleRuleByName(id)
854+
855+
if rule:
856+
rule = rule.get()
857+
else:
858+
may = openstudio.MonthOfYear("May")
859+
october = openstudio.MonthOfYear("Oct")
860+
start = openstudio.Date(may, 1)
861+
finish = openstudio.Date(october, 31)
862+
863+
rule = openstudio.model.ScheduleRule(sch)
864+
rule.setName(id)
865+
rule.setStartDate(start)
866+
rule.setEndDate(finish)
867+
rule.setApplyAllDays(true)
868+
rule.daySchedule.setName("OSut.SHADE.Rule.Default")
869+
rule.daySchedule.addValue(openstudio.Time(0,24,0,0), 1)
870+
871+
# Shade object.
872+
id = "OSut.SHADE"
873+
shd = mdl.getShadeByName(id)
874+
875+
if shd:
876+
shd = shd.get()
877+
else:
878+
shd = openstudio.model.Shade(mdl)
879+
shd.setName(id)
880+
881+
# Shading control (unique to each call).
882+
id = "OSut.ShadingControl"
883+
ctl = openstudio.model.ShadingControl(shd)
884+
ctl.setName(id)
885+
ctl.setSchedule(sch)
886+
ctl.setShadingControlType("OnIfHighOutdoorAirTempAndHighSolarOnWindow")
887+
ctl.setSetpoint(18) # °C
888+
ctl.setSetpoint2(100) # W/m2
889+
ctl.setMultipleSurfaceControlType("Group")
890+
ctl.setSubSurfaces(subs)
891+
892+
return True

0 commit comments

Comments
 (0)