osut 0.7.0__tar.gz → 0.8.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {osut-0.7.0 → osut-0.8.2}/LICENSE +1 -1
- {osut-0.7.0 → osut-0.8.2}/PKG-INFO +3 -3
- {osut-0.7.0 → osut-0.8.2}/README.md +2 -2
- {osut-0.7.0 → osut-0.8.2}/pyproject.toml +1 -1
- {osut-0.7.0 → osut-0.8.2}/src/osut/osut.py +525 -291
- {osut-0.7.0 → osut-0.8.2}/src/osut.egg-info/PKG-INFO +3 -3
- {osut-0.7.0 → osut-0.8.2}/tests/test_osut.py +114 -40
- {osut-0.7.0 → osut-0.8.2}/setup.cfg +0 -0
- {osut-0.7.0 → osut-0.8.2}/src/osut/__init__.py +0 -0
- {osut-0.7.0 → osut-0.8.2}/src/osut.egg-info/SOURCES.txt +0 -0
- {osut-0.7.0 → osut-0.8.2}/src/osut.egg-info/dependency_links.txt +0 -0
- {osut-0.7.0 → osut-0.8.2}/src/osut.egg-info/requires.txt +0 -0
- {osut-0.7.0 → osut-0.8.2}/src/osut.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: osut
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.2
|
|
4
4
|
Summary: OpenStudio SDK utilities for Python
|
|
5
5
|
Author-email: Denis Bourgeois <denis@rd2.ca>
|
|
6
6
|
Maintainer-email: Denis Bourgeois <denis@rd2.ca>
|
|
@@ -19,7 +19,7 @@ Requires-Dist: oslg
|
|
|
19
19
|
Dynamic: license-file
|
|
20
20
|
|
|
21
21
|
# pyOSut
|
|
22
|
-
Python implementation of the
|
|
22
|
+
Python implementation of the _OSut_ Ruby gem for the OpenStudio SDK.
|
|
23
23
|
|
|
24
24
|
- PyPi [package](https://pypi.org/project/osut/)
|
|
25
25
|
- Ruby [gem](https://rubygems.org/gems/osut)
|
|
@@ -45,6 +45,6 @@ To import the _OSut_ module in a Python project:
|
|
|
45
45
|
|
|
46
46
|
____
|
|
47
47
|
|
|
48
|
-
To run the _OSut_ unit tests on a `git clone` of the
|
|
48
|
+
To run the _OSut_ unit tests on a `git clone` of the repo:
|
|
49
49
|
|
|
50
50
|
`python -m unittest`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# pyOSut
|
|
2
|
-
Python implementation of the
|
|
2
|
+
Python implementation of the _OSut_ Ruby gem for the OpenStudio SDK.
|
|
3
3
|
|
|
4
4
|
- PyPi [package](https://pypi.org/project/osut/)
|
|
5
5
|
- Ruby [gem](https://rubygems.org/gems/osut)
|
|
@@ -25,6 +25,6 @@ To import the _OSut_ module in a Python project:
|
|
|
25
25
|
|
|
26
26
|
____
|
|
27
27
|
|
|
28
|
-
To run the _OSut_ unit tests on a `git clone` of the
|
|
28
|
+
To run the _OSut_ unit tests on a `git clone` of the repo:
|
|
29
29
|
|
|
30
30
|
`python -m unittest`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# BSD 3-Clause License
|
|
2
2
|
#
|
|
3
|
-
# Copyright (c) 2022-
|
|
3
|
+
# Copyright (c) 2022-2026, rd2
|
|
4
4
|
#
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without
|
|
6
6
|
# modification, are permitted provided that the following conditions are met:
|
|
@@ -36,15 +36,24 @@ from dataclasses import dataclass
|
|
|
36
36
|
|
|
37
37
|
@dataclass(frozen=True)
|
|
38
38
|
class _CN:
|
|
39
|
-
DBG = oslg.CN.DEBUG
|
|
40
|
-
INF = oslg.CN.INFO
|
|
41
|
-
WRN = oslg.CN.WARN
|
|
42
|
-
ERR = oslg.CN.ERROR
|
|
43
|
-
FTL = oslg.CN.FATAL
|
|
44
|
-
TOL = 0.01
|
|
45
|
-
TOL2 = TOL * TOL
|
|
46
|
-
HEAD = 2.032
|
|
47
|
-
SILL = 0.762
|
|
39
|
+
DBG = oslg.CN.DEBUG # see github.com/rd2/pyOSlg
|
|
40
|
+
INF = oslg.CN.INFO # see github.com/rd2/pyOSlg
|
|
41
|
+
WRN = oslg.CN.WARN # see github.com/rd2/pyOSlg
|
|
42
|
+
ERR = oslg.CN.ERROR # see github.com/rd2/pyOSlg
|
|
43
|
+
FTL = oslg.CN.FATAL # see github.com/rd2/pyOSlg
|
|
44
|
+
TOL = 0.01 # default distance tolerance (m)
|
|
45
|
+
TOL2 = TOL * TOL # default area tolerance (m2)
|
|
46
|
+
HEAD = 2.032 # standard 80" door
|
|
47
|
+
SILL = 0.762 # standard 30" window sill
|
|
48
|
+
NS = "nameString" # OpenStudio object identifier method
|
|
49
|
+
DMIN = 0.010 # min. insulating material thickness
|
|
50
|
+
DMAX = 1.000 # max. insulating material thickness
|
|
51
|
+
KMIN = 0.010 # min. insulating material thermal conductivity
|
|
52
|
+
KMAX = 2.000 # max. insulating material thermal conductivity
|
|
53
|
+
UMAX = KMAX / DMIN # material USi upper limit, 200.000
|
|
54
|
+
UMIN = KMIN / DMAX # material USi lower limit, 0.010
|
|
55
|
+
RMIN = 1.0 / UMAX # material RSi lower limit, 0.005 (or R-IP 0.03)
|
|
56
|
+
RMAX = 1.0 / UMIN # material RSi upper limit, 100.000 (or R-IP 567.80)
|
|
48
57
|
CN = _CN()
|
|
49
58
|
|
|
50
59
|
# General surface orientations (see 'facets' method).
|
|
@@ -300,6 +309,456 @@ def clamp(value, minimum, maximum) -> float:
|
|
|
300
309
|
return value
|
|
301
310
|
|
|
302
311
|
|
|
312
|
+
def areStandardOpaqueLayers(lc=None) -> bool:
|
|
313
|
+
"""Validates if every material in a layered construction is standard/opaque.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
lc (openstudio.model.LayeredConstruction):
|
|
317
|
+
an OpenStudio layered construction
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
True: If all layers are valid (standard & opaque).
|
|
321
|
+
False: If invalid inputs (see logs).
|
|
322
|
+
|
|
323
|
+
"""
|
|
324
|
+
mth = "osut.areStandardOpaqueLayers"
|
|
325
|
+
cl = openstudio.model.LayeredConstruction
|
|
326
|
+
|
|
327
|
+
if not isinstance(lc, cl):
|
|
328
|
+
return oslg.mismatch("lc", lc, cl, mth, CN.DBG, 0.0)
|
|
329
|
+
|
|
330
|
+
for m in lc.layers():
|
|
331
|
+
if not m.to_StandardOpaqueMaterial(): return False
|
|
332
|
+
|
|
333
|
+
return True
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def thickness(lc=None) -> float:
|
|
337
|
+
"""Returns total (standard opaque) layered construction thickness (m).
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
lc (openstudio.model.LayeredConstruction):
|
|
341
|
+
an OpenStudio layered construction
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
float: A standard opaque construction thickness.
|
|
345
|
+
0.0: If invalid inputs (see logs).
|
|
346
|
+
|
|
347
|
+
"""
|
|
348
|
+
mth = "osut.thickness"
|
|
349
|
+
cl = openstudio.model.LayeredConstruction
|
|
350
|
+
d = 0.0
|
|
351
|
+
|
|
352
|
+
if not isinstance(lc, cl):
|
|
353
|
+
return oslg.mismatch("lc", lc, cl, mth, CN.DBG, 0.0)
|
|
354
|
+
if not areStandardOpaqueLayers(lc):
|
|
355
|
+
oslg.log(CN.ERR, "holding non-StandardOpaqueMaterial(s) %s" % mth)
|
|
356
|
+
return d
|
|
357
|
+
|
|
358
|
+
for m in lc.layers(): d += m.thickness()
|
|
359
|
+
|
|
360
|
+
return d
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def glazingAirFilmRSi(usi=5.85) -> float:
|
|
364
|
+
"""Returns total air film resistance of a fenestrated construction (m2•K/W).
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
usi (float):
|
|
368
|
+
A fenestrated construction's U-factor (W/m2•K).
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
float: Total air film resistances.
|
|
372
|
+
0.1216: If invalid input (see logs).
|
|
373
|
+
|
|
374
|
+
"""
|
|
375
|
+
# The sum of thermal resistances of calculated exterior and interior film
|
|
376
|
+
# coefficients under standard winter conditions are taken from:
|
|
377
|
+
#
|
|
378
|
+
# https://bigladdersoftware.com/epx/docs/9-6/engineering-reference/
|
|
379
|
+
# window-calculation-module.html#simple-window-model
|
|
380
|
+
#
|
|
381
|
+
# These remain acceptable approximations for flat windows, yet likely
|
|
382
|
+
# unsuitable for subsurfaces with curved or projecting shapes like domed
|
|
383
|
+
# skylights. The solution here is considered an adequate fix for reporting,
|
|
384
|
+
# awaiting eventual OpenStudio (and EnergyPlus) upgrades to report NFRC 100
|
|
385
|
+
# (or ISO) air film resistances under standard winter conditions.
|
|
386
|
+
#
|
|
387
|
+
# For U-factors above 8.0 W/m2•K (or invalid input), the function returns
|
|
388
|
+
# 0.1216 m2•K/W, which corresponds to a construction with a single glass
|
|
389
|
+
# layer thickness of 2mm & k = ~0.6 W/m.K.
|
|
390
|
+
#
|
|
391
|
+
# The EnergyPlus Engineering calculations were designed for vertical
|
|
392
|
+
# windows, not for horizontal, slanted or domed surfaces - use with caution.
|
|
393
|
+
mth = "osut.glazingAirFilmRSi"
|
|
394
|
+
val = 0.1216
|
|
395
|
+
|
|
396
|
+
try:
|
|
397
|
+
usi = float(usi)
|
|
398
|
+
except:
|
|
399
|
+
return oslg.mismatch("usi", usi, float, mth, CN.DBG, val)
|
|
400
|
+
|
|
401
|
+
if usi > 8.0:
|
|
402
|
+
return oslg.invalid("usi", mth, 1, CN.WRN, val)
|
|
403
|
+
elif usi < 0:
|
|
404
|
+
return oslg.negative("usi", mth, CN.WRN, val)
|
|
405
|
+
elif abs(usi) < CN.TOL:
|
|
406
|
+
return oslg.zero("usi", mth, CN.WRN, val)
|
|
407
|
+
|
|
408
|
+
rsi = 1 / (0.025342 * usi + 29.163853) # exterior film, next interior film
|
|
409
|
+
|
|
410
|
+
if usi < 5.85:
|
|
411
|
+
return rsi + 1 / (0.359073 * math.log(usi) + 6.949915)
|
|
412
|
+
|
|
413
|
+
return rsi + 1 / (1.788041 * usi - 2.886625)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def rsi(lc=None, film=0.0, t=0.0) -> float:
|
|
417
|
+
"""Returns a construction's 'standard calc' thermal resistance (m2•K/W),
|
|
418
|
+
which includes air film resistances. It excludes insulating effects of
|
|
419
|
+
shades, screens, etc. in the case of fenestrated constructions. Adapted
|
|
420
|
+
from BTAP's 'Material' Module "get_conductance" (P. Lopez).
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
lc (openstudio.model.LayeredConstruction):
|
|
424
|
+
an OpenStudio layered construction
|
|
425
|
+
film (float):
|
|
426
|
+
thermal resistance of surface air films (m2•K/W)
|
|
427
|
+
t (float):
|
|
428
|
+
gas temperature (°C) (optional)
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
float: A layered construction's thermal resistance.
|
|
432
|
+
0.0: If invalid input (see logs).
|
|
433
|
+
|
|
434
|
+
"""
|
|
435
|
+
mth = "osut.rsi"
|
|
436
|
+
cl = openstudio.model.LayeredConstruction
|
|
437
|
+
|
|
438
|
+
if not isinstance(lc, cl):
|
|
439
|
+
return oslg.mismatch("lc", lc, cl, mth, CN.DBG, 0.0)
|
|
440
|
+
|
|
441
|
+
try:
|
|
442
|
+
film = float(film)
|
|
443
|
+
except:
|
|
444
|
+
return oslg.mismatch("film", film, float, mth, CN.DBG, 0.0)
|
|
445
|
+
|
|
446
|
+
try:
|
|
447
|
+
t = float(t)
|
|
448
|
+
except:
|
|
449
|
+
return oslg.mismatch("temp K", t, float, mth, CN.DBG, 0.0)
|
|
450
|
+
|
|
451
|
+
t += 273.0 # °C to K
|
|
452
|
+
|
|
453
|
+
if t < 0:
|
|
454
|
+
return oslg.negative("temp K", mth, CN.ERR, 0.0)
|
|
455
|
+
if film < 0:
|
|
456
|
+
return oslg.negative("film", mth, CN.ERR, 0.0)
|
|
457
|
+
|
|
458
|
+
rsi = film
|
|
459
|
+
|
|
460
|
+
for m in lc.layers():
|
|
461
|
+
if m.to_SimpleGlazing():
|
|
462
|
+
return 1 / m.to_SimpleGlazing().get().uFactor()
|
|
463
|
+
elif m.to_StandardGlazing():
|
|
464
|
+
rsi += m.to_StandardGlazing().get().thermalResistance()
|
|
465
|
+
elif m.to_RefractionExtinctionGlazing():
|
|
466
|
+
rsi += m.to_RefractionExtinctionGlazing().get().thermalResistance()
|
|
467
|
+
elif m.to_Gas():
|
|
468
|
+
rsi += m.to_Gas().get().getThermalResistance(t)
|
|
469
|
+
elif m.to_GasMixture():
|
|
470
|
+
rsi += m.to_GasMixture().get().getThermalResistance(t)
|
|
471
|
+
|
|
472
|
+
# Opaque materials next.
|
|
473
|
+
if m.to_StandardOpaqueMaterial():
|
|
474
|
+
rsi += m.to_StandardOpaqueMaterial().get().thermalResistance()
|
|
475
|
+
elif m.to_MasslessOpaqueMaterial():
|
|
476
|
+
rsi += m.to_MasslessOpaqueMaterial()
|
|
477
|
+
elif m.to_RoofVegetation():
|
|
478
|
+
rsi += m.to_RoofVegetation().get().thermalResistance()
|
|
479
|
+
elif m.to_AirGap():
|
|
480
|
+
rsi += m.to_AirGap().get().thermalResistance()
|
|
481
|
+
|
|
482
|
+
return rsi
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def insulatingLayer(lc=None) -> dict:
|
|
486
|
+
"""Identifies a layered construction's (opaque) insulating layer.
|
|
487
|
+
|
|
488
|
+
Args:
|
|
489
|
+
lc (openStudio.model.LayeredConstruction):
|
|
490
|
+
an OpenStudio layered construction
|
|
491
|
+
|
|
492
|
+
Returns:
|
|
493
|
+
An insulating-layer dictionary:
|
|
494
|
+
- "index" (int): construction's insulating layer index [0, n layers)
|
|
495
|
+
- "type" (str): layer material type ("standard" or "massless")
|
|
496
|
+
- "r" (float): material thermal resistance in m2•K/W.
|
|
497
|
+
If unsuccessful, dictionary is voided as follows (see logs):
|
|
498
|
+
"index": None
|
|
499
|
+
"type": None
|
|
500
|
+
"r": 0.0
|
|
501
|
+
|
|
502
|
+
"""
|
|
503
|
+
mth = "osut.insulatingLayer"
|
|
504
|
+
cl = openstudio.model.LayeredConstruction
|
|
505
|
+
res = dict(index=None, type=None, r=0.0)
|
|
506
|
+
i = 0 # iterator
|
|
507
|
+
|
|
508
|
+
if not isinstance(lc, cl):
|
|
509
|
+
return oslg.mismatch("lc", lc, cl, mth, CN.DBG, res)
|
|
510
|
+
|
|
511
|
+
for l in lc.layers():
|
|
512
|
+
if l.to_MasslessOpaqueMaterial():
|
|
513
|
+
l = l.to_MasslessOpaqueMaterial().get()
|
|
514
|
+
|
|
515
|
+
if l.thermalResistance() < 0.001 or l.thermalResistance() < res["r"]:
|
|
516
|
+
i += 1
|
|
517
|
+
continue
|
|
518
|
+
else:
|
|
519
|
+
res["r" ] = m.thermalResistance()
|
|
520
|
+
res["index"] = i
|
|
521
|
+
res["type" ] = "massless"
|
|
522
|
+
|
|
523
|
+
if l.to_StandardOpaqueMaterial():
|
|
524
|
+
l = l.to_StandardOpaqueMaterial().get()
|
|
525
|
+
k = l.thermalConductivity()
|
|
526
|
+
d = l.thickness()
|
|
527
|
+
|
|
528
|
+
if (d < 0.003) or (k > 3.0) or (d / k < res["r"]):
|
|
529
|
+
i += 1
|
|
530
|
+
continue
|
|
531
|
+
else:
|
|
532
|
+
res["r" ] = d / k
|
|
533
|
+
res["index"] = i
|
|
534
|
+
res["type" ] = "standard"
|
|
535
|
+
|
|
536
|
+
i += 1
|
|
537
|
+
|
|
538
|
+
return res
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
def isUniqueMaterial(m=None) -> bool:
|
|
542
|
+
"""Validates whether a material is both uniquely reserved to a single
|
|
543
|
+
layered construction in a model, and referenced only once in the
|
|
544
|
+
construction. Limited to 'standard' or 'massless' materials.
|
|
545
|
+
|
|
546
|
+
Args:
|
|
547
|
+
m (openStudio.model.OpaqueMaterial):
|
|
548
|
+
an OpenStudio opaque material
|
|
549
|
+
|
|
550
|
+
Returns:
|
|
551
|
+
True: Whether material is unique.
|
|
552
|
+
False: If material is missing.
|
|
553
|
+
|
|
554
|
+
"""
|
|
555
|
+
mth = "osut.isUniqueMaterial"
|
|
556
|
+
cl = openstudio.model.OpaqueMaterial
|
|
557
|
+
|
|
558
|
+
if not isinstance(m, cl):
|
|
559
|
+
return oslg.mismatch("material", m, cl, mth, CN.DBG, False)
|
|
560
|
+
|
|
561
|
+
num = 0
|
|
562
|
+
lcs = m.model().getLayeredConstructions()
|
|
563
|
+
|
|
564
|
+
if m.to_MasslessOpaqueMaterial():
|
|
565
|
+
m = m.to_MasslessOpaqueMaterial().get()
|
|
566
|
+
|
|
567
|
+
for lc in lcs:
|
|
568
|
+
num += lc.getLayerIndices(m).size()
|
|
569
|
+
|
|
570
|
+
if num == 1: return True
|
|
571
|
+
|
|
572
|
+
if m.to_StandardOpaqueMaterial():
|
|
573
|
+
m = m.to_StandardOpaqueMaterial().get()
|
|
574
|
+
|
|
575
|
+
for lc in lcs:
|
|
576
|
+
num += lc.getLayerIndices(m).size()
|
|
577
|
+
|
|
578
|
+
if num == 1: return True
|
|
579
|
+
|
|
580
|
+
return False
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
def assignUniqueMaterial(lc=None, index=None) -> bool:
|
|
584
|
+
"""Sets a layered construction material as unique. Solution similar to
|
|
585
|
+
OpenStudio::Model::LayeredConstruction's 'ensureUniqueLayers', yet limited
|
|
586
|
+
here to a single indexed OpenStudio material, typically the principal
|
|
587
|
+
insulating material. Returns true if the indexed material is already unique.
|
|
588
|
+
Limited to 'standard' or 'massless' materials.
|
|
589
|
+
|
|
590
|
+
Args:
|
|
591
|
+
lc (OpenStudio::Model::LayeredConstruction):
|
|
592
|
+
A construction.
|
|
593
|
+
index:
|
|
594
|
+
The construction layer index of the material.
|
|
595
|
+
|
|
596
|
+
Returns:
|
|
597
|
+
True: If assigned as unique.
|
|
598
|
+
None: If invalid inputs (see logs).
|
|
599
|
+
|
|
600
|
+
"""
|
|
601
|
+
mth = "osut.assignUniqueMaterial"
|
|
602
|
+
cl = openstudio.model.LayeredConstruction
|
|
603
|
+
|
|
604
|
+
if not isinstance(lc, cl):
|
|
605
|
+
return oslg.mismatch("construction", lc, cl, mth, CN.DBG, False)
|
|
606
|
+
|
|
607
|
+
try:
|
|
608
|
+
index = int(index)
|
|
609
|
+
except:
|
|
610
|
+
return oslg.mismatch("index", index, int, mth, CN.DBG, False)
|
|
611
|
+
|
|
612
|
+
if index < 0 or index > lc.numLayers() - 1:
|
|
613
|
+
return oslg.invalid("index", mth, 0, CN.DBG, False)
|
|
614
|
+
|
|
615
|
+
m = lc.getLayer(index)
|
|
616
|
+
|
|
617
|
+
if m.to_MasslessOpaqueMaterial():
|
|
618
|
+
m = m.to_MasslessOpaqueMaterial().get()
|
|
619
|
+
|
|
620
|
+
if isUniqueMaterial(m): return True
|
|
621
|
+
|
|
622
|
+
mat = m.clone(m.model()).to_MasslessOpaqueMaterial().get()
|
|
623
|
+
return lc.setLayer(index, mat)
|
|
624
|
+
|
|
625
|
+
if m.to_StandardOpaqueMaterial():
|
|
626
|
+
m = m.to_StandardOpaqueMaterial().get()
|
|
627
|
+
|
|
628
|
+
if isUniqueMaterial(m): return True
|
|
629
|
+
|
|
630
|
+
mat = m.clone(m.model()).to_StandardOpaqueMaterial().get()
|
|
631
|
+
|
|
632
|
+
return False
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
def resetUo(lc=None, film=None, index=None, uo=None, uniq=False) -> float:
|
|
636
|
+
"""Resets a construction's Uo factor by adjusting its insulating layer
|
|
637
|
+
thermal conductivity, then if needed its thickness (or its RSi value if
|
|
638
|
+
massless). Unless material uniquness is requested, a matching material is
|
|
639
|
+
recovered instead of instantiating a new one. The latter is renamed
|
|
640
|
+
according to its adjusted conductivity/thickness (or RSi value).
|
|
641
|
+
|
|
642
|
+
Args:
|
|
643
|
+
lc (OpenStudio::Model::LayeredConstruction):
|
|
644
|
+
A construction.
|
|
645
|
+
film (float):
|
|
646
|
+
The construction air film resistance.
|
|
647
|
+
index (int):
|
|
648
|
+
The insulating layer's array index.
|
|
649
|
+
uo (float):
|
|
650
|
+
Desired Uo factor (with air film resistance).
|
|
651
|
+
uniq (bool):
|
|
652
|
+
Whether to enforce material uniqueness.
|
|
653
|
+
|
|
654
|
+
Returns:
|
|
655
|
+
float: New layer RSi [CN.RMIN, CN.RMAX].
|
|
656
|
+
0.0: If invalid inputs (see logs).
|
|
657
|
+
|
|
658
|
+
"""
|
|
659
|
+
mth = "osut.resetUo"
|
|
660
|
+
r = 0.0 # thermal resistance of new material
|
|
661
|
+
cl = openstudio.model.LayeredConstruction
|
|
662
|
+
|
|
663
|
+
if not isinstance(lc, cl):
|
|
664
|
+
return oslg.mismatch("construction", lc, cl, mth, CN.DBG, r)
|
|
665
|
+
if not isinstance(uniq, bool):
|
|
666
|
+
uniq = False
|
|
667
|
+
|
|
668
|
+
try:
|
|
669
|
+
film = float(film)
|
|
670
|
+
except:
|
|
671
|
+
return oslg.mismatch("film", film, float, mth, CN.DBG, r)
|
|
672
|
+
|
|
673
|
+
try:
|
|
674
|
+
index = int(index)
|
|
675
|
+
except:
|
|
676
|
+
return oslg.mismatch("index", index, int, mth, CN.DBG, r)
|
|
677
|
+
|
|
678
|
+
try:
|
|
679
|
+
uo = float(uo)
|
|
680
|
+
except:
|
|
681
|
+
return oslg.mismatch("uo", uo, float, mth, CN.DBG, r)
|
|
682
|
+
|
|
683
|
+
if film < 0:
|
|
684
|
+
return oslg.negative("film", mth, CN.DBG, r)
|
|
685
|
+
if index < 0 or index > lc.numLayers() - 1:
|
|
686
|
+
return oslg.invalid("index", mth, 3, CN.DBG, r)
|
|
687
|
+
if uo < CN.UMIN or uo > CN.UMAX:
|
|
688
|
+
uo = clamp(uo, CN.UMIN, CN.UMAX)
|
|
689
|
+
msg = "Resetting Uo %s to %.3f (%s)" % (lc.nameString(), uo, mth)
|
|
690
|
+
oslg.log(CN.WRN, msg)
|
|
691
|
+
|
|
692
|
+
r0 = rsi(lc, film) # current construction RSi value
|
|
693
|
+
ro = 1 / uo # desired construction RSi value
|
|
694
|
+
dR = ro - r0 # desired increase in construction RSi
|
|
695
|
+
m = lc.getLayer(index)
|
|
696
|
+
|
|
697
|
+
if m.to_MasslessOpaqueMaterial():
|
|
698
|
+
m = m.to_MasslessOpaqueMaterial().get()
|
|
699
|
+
r = m.thermalResistance()
|
|
700
|
+
if round(abs(dR), 2) == 0.00: return r
|
|
701
|
+
|
|
702
|
+
r = clamp(r + dR, RMIN, RMAX)
|
|
703
|
+
id = "OSut:RSi%.2f" % r
|
|
704
|
+
mt = lc.model().getMasslessOpaqueMaterialByName(id)
|
|
705
|
+
|
|
706
|
+
# Existing material?
|
|
707
|
+
if mt:
|
|
708
|
+
mt = mt.get()
|
|
709
|
+
|
|
710
|
+
if round(r, 2) == round(mt.thermalResistance(), 2) and uniq == False:
|
|
711
|
+
lc.setLayer(index, mt)
|
|
712
|
+
return r
|
|
713
|
+
|
|
714
|
+
mt = m.clone(m.model()).to_MasslessOpaqueMaterial().get()
|
|
715
|
+
mt.setName(id)
|
|
716
|
+
|
|
717
|
+
if not mt.setThermalResistance(r):
|
|
718
|
+
oslg.log(CN.WRN, "Failed to reset %s: RSi%.2f (%s)" % (id, r, mth))
|
|
719
|
+
return 0.0
|
|
720
|
+
|
|
721
|
+
lc.setLayer(index, mt)
|
|
722
|
+
return r
|
|
723
|
+
|
|
724
|
+
if m.to_StandardOpaqueMaterial():
|
|
725
|
+
m = m.to_StandardOpaqueMaterial().get()
|
|
726
|
+
r = m.thickness() / m.conductivity()
|
|
727
|
+
if round(abs(dR), 2) == 0.00: return r
|
|
728
|
+
|
|
729
|
+
k = clamp(m.thickness() / (r + dR), CN.KMIN, CN.KMAX)
|
|
730
|
+
d = clamp(k * (r + dR), CN.DMIN, CN.DMAX)
|
|
731
|
+
r = d / k
|
|
732
|
+
id = "OSut:K%.3f:%03d" % (k, d*1000)
|
|
733
|
+
mt = lc.model().getStandardOpaqueMaterialByName(id)
|
|
734
|
+
|
|
735
|
+
# Existing material?
|
|
736
|
+
if mt:
|
|
737
|
+
mt = mt.get()
|
|
738
|
+
rt = mt.thickness() / mt.conductivity()
|
|
739
|
+
|
|
740
|
+
if round(r, 2) == round(rt, 2) and uniq == False:
|
|
741
|
+
lc.setlayer(index, mt)
|
|
742
|
+
return r
|
|
743
|
+
|
|
744
|
+
mt = m.clone(m.model()).to_StandardOpaqueMaterial().get()
|
|
745
|
+
mt.setName(id)
|
|
746
|
+
|
|
747
|
+
if not mt.setThermalConductivity(k):
|
|
748
|
+
oslg.log(CN.WRN, "Failed to reset %s: K%.3f (%s)" % (id, k, mth))
|
|
749
|
+
return 0.0
|
|
750
|
+
|
|
751
|
+
if not mt.setThickness(d):
|
|
752
|
+
d = int(d*1000)
|
|
753
|
+
oslg.log(CN.WRN, "Failed to reset %s: %dmm (%s)" % (id, d, mth))
|
|
754
|
+
return 0.0
|
|
755
|
+
|
|
756
|
+
lc.setLayer(index, mt)
|
|
757
|
+
return r
|
|
758
|
+
|
|
759
|
+
return 0.0
|
|
760
|
+
|
|
761
|
+
|
|
303
762
|
def genConstruction(model=None, specs=dict()):
|
|
304
763
|
"""Generates an OpenStudio multilayered construction, + materials if needed.
|
|
305
764
|
|
|
@@ -345,12 +804,10 @@ def genConstruction(model=None, specs=dict()):
|
|
|
345
804
|
except:
|
|
346
805
|
return oslg.mismatch(id + " Uo", u, float, mth, CN.ERR)
|
|
347
806
|
|
|
348
|
-
if u <
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
if u > 5.678:
|
|
353
|
-
return oslg.invalid(id + " Uo (> 5.678)", mth, 2, CN.ERR)
|
|
807
|
+
if u < CN.UMIN or u > CN.UMAX:
|
|
808
|
+
u0 = u
|
|
809
|
+
u = clamp(u0, CN.UMIN, CN.UMAX)
|
|
810
|
+
oslg.log(CN.ERR, "Resetting Uo %.3f to %.3f (%s)" % (u0, u, mth))
|
|
354
811
|
|
|
355
812
|
# Optional specs. Log/reset if invalid.
|
|
356
813
|
if "clad" not in specs: specs["clad" ] = "light" # exterior
|
|
@@ -643,7 +1100,7 @@ def genConstruction(model=None, specs=dict()):
|
|
|
643
1100
|
if u and not a["glazing"]:
|
|
644
1101
|
ro = 1 / u - flm
|
|
645
1102
|
|
|
646
|
-
if ro >
|
|
1103
|
+
if ro > CN.RMIN:
|
|
647
1104
|
if specs["type"] == "door": # 1x layer, adjust conductivity
|
|
648
1105
|
layer = c.getLayer(0).to_StandardOpaqueMaterial()
|
|
649
1106
|
|
|
@@ -653,38 +1110,14 @@ def genConstruction(model=None, specs=dict()):
|
|
|
653
1110
|
layer = layer.get()
|
|
654
1111
|
k = layer.thickness() / ro
|
|
655
1112
|
layer.setConductivity(k)
|
|
656
|
-
|
|
657
|
-
else: # multiple layers, adjust insulating layer thickness
|
|
1113
|
+
else: # multiple layers
|
|
658
1114
|
lyr = insulatingLayer(c)
|
|
659
1115
|
|
|
660
|
-
if not lyr["index"] or not lyr["type"] or
|
|
661
|
-
return oslg.invalid(
|
|
1116
|
+
if not lyr["index"] or not lyr["type"] or round(lyr["r"], 2) == 0:
|
|
1117
|
+
return oslg.invalid(ide + " construction", mth, 0)
|
|
662
1118
|
|
|
663
1119
|
index = lyr["index"]
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
if not layer:
|
|
667
|
-
return oslg.invalid(id + " material %d" % index, mth, 0)
|
|
668
|
-
|
|
669
|
-
layer = layer.get()
|
|
670
|
-
k = layer.conductivity()
|
|
671
|
-
d = (ro - rsi(c) + lyr["r"]) * k
|
|
672
|
-
|
|
673
|
-
if d < 0.03:
|
|
674
|
-
m = id + " adjusted material thickness"
|
|
675
|
-
return oslg.invalid(m, mth, 0)
|
|
676
|
-
|
|
677
|
-
nom = re.sub(r'[^a-zA-Z]', '', layer.nameString())
|
|
678
|
-
nom = re.sub(r'OSut', '', nom)
|
|
679
|
-
nom = "OSut." + nom + ".%03d" % int(d * 1000)
|
|
680
|
-
|
|
681
|
-
if model.getStandardOpaqueMaterialByName(nom):
|
|
682
|
-
omat = model.getStandardOpaqueMaterialByName(nom).get()
|
|
683
|
-
c.setLayer(index, omat)
|
|
684
|
-
else:
|
|
685
|
-
layer.setName(nom)
|
|
686
|
-
layer.setThickness(d)
|
|
687
|
-
|
|
1120
|
+
resetUo(c, flm, index, u)
|
|
688
1121
|
return c
|
|
689
1122
|
|
|
690
1123
|
|
|
@@ -874,7 +1307,7 @@ def genMass(sps=None, ratio=2.0) -> bool:
|
|
|
874
1307
|
return True
|
|
875
1308
|
|
|
876
1309
|
|
|
877
|
-
def holdsConstruction(cset=None, base=None, gr=False, ex=False, type=""):
|
|
1310
|
+
def holdsConstruction(cset=None, base=None, gr=False, ex=False, type="") -> bool:
|
|
878
1311
|
"""Validates whether a default construction set holds a base construction.
|
|
879
1312
|
|
|
880
1313
|
Args:
|
|
@@ -886,7 +1319,7 @@ def holdsConstruction(cset=None, base=None, gr=False, ex=False, type=""):
|
|
|
886
1319
|
Whether ground-facing surface.
|
|
887
1320
|
ex (bool):
|
|
888
1321
|
Whether exterior-facing surface.
|
|
889
|
-
type:
|
|
1322
|
+
type (str):
|
|
890
1323
|
An OpenStudio surface (or sub surface) type (e.g. "Wall").
|
|
891
1324
|
|
|
892
1325
|
Returns:
|
|
@@ -1012,271 +1445,71 @@ def defaultConstructionSet(s=None):
|
|
|
1012
1445
|
|
|
1013
1446
|
ground = True if s.isGroundSurface() else False
|
|
1014
1447
|
exterior = True if bnd == "outdoors" else False
|
|
1448
|
+
adjacent = None
|
|
1449
|
+
aspace = None
|
|
1450
|
+
typ = None
|
|
1451
|
+
|
|
1452
|
+
if s.adjacentSurface():
|
|
1453
|
+
adjacent = s.adjacentSurface().get()
|
|
1454
|
+
typ = adjacent.surfaceType()
|
|
1455
|
+
|
|
1456
|
+
if adjacent.space():
|
|
1457
|
+
aspace = adjacent.space().get()
|
|
1015
1458
|
|
|
1016
1459
|
if space.defaultConstructionSet():
|
|
1017
|
-
|
|
1460
|
+
set = space.defaultConstructionSet().get()
|
|
1018
1461
|
|
|
1019
|
-
if holdsConstruction(
|
|
1462
|
+
if holdsConstruction(set, base, ground, exterior, type): return set
|
|
1463
|
+
elif aspace:
|
|
1464
|
+
if aspace.defaultConstructionSet():
|
|
1465
|
+
set = aspace.defaultConstructionSet().get()
|
|
1466
|
+
|
|
1467
|
+
if holdsConstruction(set, base, ground, exterior, typ): return set
|
|
1020
1468
|
|
|
1021
1469
|
if space.spaceType():
|
|
1022
1470
|
spacetype = space.spaceType().get()
|
|
1023
1471
|
|
|
1024
1472
|
if spacetype.defaultConstructionSet():
|
|
1025
|
-
|
|
1473
|
+
set = spacetype.defaultConstructionSet().get()
|
|
1474
|
+
|
|
1475
|
+
if holdsConstruction(set, base, ground, exterior, type): return set
|
|
1476
|
+
|
|
1477
|
+
if aspace and aspace.spaceType():
|
|
1478
|
+
spacetype = aspace.spaceType().get()
|
|
1479
|
+
|
|
1480
|
+
if spacetype.defaultConstructionSet():
|
|
1481
|
+
set = spacetype.defaultConstructionSet().get()
|
|
1026
1482
|
|
|
1027
|
-
if holdsConstruction(
|
|
1028
|
-
return cset
|
|
1483
|
+
if holdsConstruction(set, base, ground, exterior, typ): return set
|
|
1029
1484
|
|
|
1030
1485
|
if space.buildingStory():
|
|
1031
1486
|
story = space.buildingStory().get()
|
|
1032
1487
|
|
|
1033
1488
|
if story.defaultConstructionSet():
|
|
1034
|
-
|
|
1489
|
+
set = story.defaultConstructionSet().get()
|
|
1490
|
+
|
|
1491
|
+
if holdsConstruction(set, base, ground, exterior, type): return set
|
|
1035
1492
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1493
|
+
if aspace and aspace.buildingStory():
|
|
1494
|
+
story = aspace.buildingStory().get()
|
|
1038
1495
|
|
|
1496
|
+
if story.defaultConstructionSet():
|
|
1497
|
+
set = story.defaultConstructionSet().get()
|
|
1498
|
+
|
|
1499
|
+
if holdsConstruction(set, base, ground, exterior, typ):
|
|
1500
|
+
return set
|
|
1039
1501
|
|
|
1040
1502
|
building = mdl.getBuilding()
|
|
1041
1503
|
|
|
1042
1504
|
if building.defaultConstructionSet():
|
|
1043
|
-
|
|
1505
|
+
set = building.defaultConstructionSet().get()
|
|
1044
1506
|
|
|
1045
|
-
if holdsConstruction(
|
|
1046
|
-
return
|
|
1507
|
+
if holdsConstruction(set, base, ground, exterior, type):
|
|
1508
|
+
return set
|
|
1047
1509
|
|
|
1048
1510
|
return None
|
|
1049
1511
|
|
|
1050
1512
|
|
|
1051
|
-
def areStandardOpaqueLayers(lc=None) -> bool:
|
|
1052
|
-
"""Validates if every material in a layered construction is standard/opaque.
|
|
1053
|
-
|
|
1054
|
-
Args:
|
|
1055
|
-
lc (openstudio.model.LayeredConstruction):
|
|
1056
|
-
an OpenStudio layered construction
|
|
1057
|
-
|
|
1058
|
-
Returns:
|
|
1059
|
-
True: If all layers are valid (standard & opaque).
|
|
1060
|
-
False: If invalid inputs (see logs).
|
|
1061
|
-
|
|
1062
|
-
"""
|
|
1063
|
-
mth = "osut.areStandardOpaqueLayers"
|
|
1064
|
-
cl = openstudio.model.LayeredConstruction
|
|
1065
|
-
|
|
1066
|
-
if not isinstance(lc, cl):
|
|
1067
|
-
return oslg.mismatch("lc", lc, cl, mth, CN.DBG, 0.0)
|
|
1068
|
-
|
|
1069
|
-
for m in lc.layers():
|
|
1070
|
-
if not m.to_StandardOpaqueMaterial(): return False
|
|
1071
|
-
|
|
1072
|
-
return True
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
def thickness(lc=None) -> float:
|
|
1076
|
-
"""Returns total (standard opaque) layered construction thickness (m).
|
|
1077
|
-
|
|
1078
|
-
Args:
|
|
1079
|
-
lc (openstudio.model.LayeredConstruction):
|
|
1080
|
-
an OpenStudio layered construction
|
|
1081
|
-
|
|
1082
|
-
Returns:
|
|
1083
|
-
float: A standard opaque construction thickness.
|
|
1084
|
-
0.0: If invalid inputs (see logs).
|
|
1085
|
-
|
|
1086
|
-
"""
|
|
1087
|
-
mth = "osut.thickness"
|
|
1088
|
-
cl = openstudio.model.LayeredConstruction
|
|
1089
|
-
d = 0.0
|
|
1090
|
-
|
|
1091
|
-
if not isinstance(lc, cl):
|
|
1092
|
-
return oslg.mismatch("lc", lc, cl, mth, CN.DBG, 0.0)
|
|
1093
|
-
if not areStandardOpaqueLayers(lc):
|
|
1094
|
-
oslg.log(CN.ERR, "holding non-StandardOpaqueMaterial(s) %s" % mth)
|
|
1095
|
-
return d
|
|
1096
|
-
|
|
1097
|
-
for m in lc.layers(): d += m.thickness()
|
|
1098
|
-
|
|
1099
|
-
return d
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
def glazingAirFilmRSi(usi=5.85) -> float:
|
|
1103
|
-
"""Returns total air film resistance of a fenestrated construction (m2•K/W).
|
|
1104
|
-
|
|
1105
|
-
Args:
|
|
1106
|
-
usi (float):
|
|
1107
|
-
A fenestrated construction's U-factor (W/m2•K).
|
|
1108
|
-
|
|
1109
|
-
Returns:
|
|
1110
|
-
float: Total air film resistances.
|
|
1111
|
-
0.1216: If invalid input (see logs).
|
|
1112
|
-
|
|
1113
|
-
"""
|
|
1114
|
-
# The sum of thermal resistances of calculated exterior and interior film
|
|
1115
|
-
# coefficients under standard winter conditions are taken from:
|
|
1116
|
-
#
|
|
1117
|
-
# https://bigladdersoftware.com/epx/docs/9-6/engineering-reference/
|
|
1118
|
-
# window-calculation-module.html#simple-window-model
|
|
1119
|
-
#
|
|
1120
|
-
# These remain acceptable approximations for flat windows, yet likely
|
|
1121
|
-
# unsuitable for subsurfaces with curved or projecting shapes like domed
|
|
1122
|
-
# skylights. The solution here is considered an adequate fix for reporting,
|
|
1123
|
-
# awaiting eventual OpenStudio (and EnergyPlus) upgrades to report NFRC 100
|
|
1124
|
-
# (or ISO) air film resistances under standard winter conditions.
|
|
1125
|
-
#
|
|
1126
|
-
# For U-factors above 8.0 W/m2•K (or invalid input), the function returns
|
|
1127
|
-
# 0.1216 m2•K/W, which corresponds to a construction with a single glass
|
|
1128
|
-
# layer thickness of 2mm & k = ~0.6 W/m.K.
|
|
1129
|
-
#
|
|
1130
|
-
# The EnergyPlus Engineering calculations were designed for vertical
|
|
1131
|
-
# windows, not for horizontal, slanted or domed surfaces - use with caution.
|
|
1132
|
-
mth = "osut.glazingAirFilmRSi"
|
|
1133
|
-
val = 0.1216
|
|
1134
|
-
|
|
1135
|
-
try:
|
|
1136
|
-
usi = float(usi)
|
|
1137
|
-
except:
|
|
1138
|
-
return oslg.mismatch("usi", usi, float, mth, CN.DBG, val)
|
|
1139
|
-
|
|
1140
|
-
if usi > 8.0:
|
|
1141
|
-
return oslg.invalid("usi", mth, 1, CN.WRN, val)
|
|
1142
|
-
elif usi < 0:
|
|
1143
|
-
return oslg.negative("usi", mth, CN.WRN, val)
|
|
1144
|
-
elif abs(usi) < CN.TOL:
|
|
1145
|
-
return oslg.zero("usi", mth, CN.WRN, val)
|
|
1146
|
-
|
|
1147
|
-
rsi = 1 / (0.025342 * usi + 29.163853) # exterior film, next interior film
|
|
1148
|
-
|
|
1149
|
-
if usi < 5.85:
|
|
1150
|
-
return rsi + 1 / (0.359073 * math.log(usi) + 6.949915)
|
|
1151
|
-
|
|
1152
|
-
return rsi + 1 / (1.788041 * usi - 2.886625)
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
def rsi(lc=None, film=0.0, t=0.0) -> float:
|
|
1156
|
-
"""Returns a construction's 'standard calc' thermal resistance (m2•K/W),
|
|
1157
|
-
which includes air film resistances. It excludes insulating effects of
|
|
1158
|
-
shades, screens, etc. in the case of fenestrated constructions. Adapted
|
|
1159
|
-
from BTAP's 'Material' Module "get_conductance" (P. Lopez).
|
|
1160
|
-
|
|
1161
|
-
Args:
|
|
1162
|
-
lc (openstudio.model.LayeredConstruction):
|
|
1163
|
-
an OpenStudio layered construction
|
|
1164
|
-
film (float):
|
|
1165
|
-
thermal resistance of surface air films (m2•K/W)
|
|
1166
|
-
t (float):
|
|
1167
|
-
gas temperature (°C) (optional)
|
|
1168
|
-
|
|
1169
|
-
Returns:
|
|
1170
|
-
float: A layered construction's thermal resistance.
|
|
1171
|
-
0.0: If invalid input (see logs).
|
|
1172
|
-
|
|
1173
|
-
"""
|
|
1174
|
-
mth = "osut.rsi"
|
|
1175
|
-
cl = openstudio.model.LayeredConstruction
|
|
1176
|
-
|
|
1177
|
-
if not isinstance(lc, cl):
|
|
1178
|
-
return oslg.mismatch("lc", lc, cl, mth, CN.DBG, 0.0)
|
|
1179
|
-
|
|
1180
|
-
try:
|
|
1181
|
-
film = float(film)
|
|
1182
|
-
except:
|
|
1183
|
-
return oslg.mismatch("film", film, float, mth, CN.DBG, 0.0)
|
|
1184
|
-
|
|
1185
|
-
try:
|
|
1186
|
-
t = float(t)
|
|
1187
|
-
except:
|
|
1188
|
-
return oslg.mismatch("temp K", t, float, mth, CN.DBG, 0.0)
|
|
1189
|
-
|
|
1190
|
-
t += 273.0 # °C to K
|
|
1191
|
-
|
|
1192
|
-
if t < 0:
|
|
1193
|
-
return oslg.negative("temp K", mth, CN.ERR, 0.0)
|
|
1194
|
-
if film < 0:
|
|
1195
|
-
return oslg.negative("film", mth, CN.ERR, 0.0)
|
|
1196
|
-
|
|
1197
|
-
rsi = film
|
|
1198
|
-
|
|
1199
|
-
for m in lc.layers():
|
|
1200
|
-
if m.to_SimpleGlazing():
|
|
1201
|
-
return 1 / m.to_SimpleGlazing().get().uFactor()
|
|
1202
|
-
elif m.to_StandardGlazing():
|
|
1203
|
-
rsi += m.to_StandardGlazing().get().thermalResistance()
|
|
1204
|
-
elif m.to_RefractionExtinctionGlazing():
|
|
1205
|
-
rsi += m.to_RefractionExtinctionGlazing().get().thermalResistance()
|
|
1206
|
-
elif m.to_Gas():
|
|
1207
|
-
rsi += m.to_Gas().get().getThermalResistance(t)
|
|
1208
|
-
elif m.to_GasMixture():
|
|
1209
|
-
rsi += m.to_GasMixture().get().getThermalResistance(t)
|
|
1210
|
-
|
|
1211
|
-
# Opaque materials next.
|
|
1212
|
-
if m.to_StandardOpaqueMaterial():
|
|
1213
|
-
rsi += m.to_StandardOpaqueMaterial().get().thermalResistance()
|
|
1214
|
-
elif m.to_MasslessOpaqueMaterial():
|
|
1215
|
-
rsi += m.to_MasslessOpaqueMaterial()
|
|
1216
|
-
elif m.to_RoofVegetation():
|
|
1217
|
-
rsi += m.to_RoofVegetation().get().thermalResistance()
|
|
1218
|
-
elif m.to_AirGap():
|
|
1219
|
-
rsi += m.to_AirGap().get().thermalResistance()
|
|
1220
|
-
|
|
1221
|
-
return rsi
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
def insulatingLayer(lc=None) -> dict:
|
|
1225
|
-
"""Identifies a layered construction's (opaque) insulating layer.
|
|
1226
|
-
|
|
1227
|
-
Args:
|
|
1228
|
-
lc (openStudio.model.LayeredConstruction):
|
|
1229
|
-
an OpenStudio layered construction
|
|
1230
|
-
|
|
1231
|
-
Returns:
|
|
1232
|
-
An insulating-layer dictionary:
|
|
1233
|
-
- "index" (int): construction's insulating layer index [0, n layers)
|
|
1234
|
-
- "type" (str): layer material type ("standard" or "massless")
|
|
1235
|
-
- "r" (float): material thermal resistance in m2•K/W.
|
|
1236
|
-
If unsuccessful, dictionary is voided as follows (see logs):
|
|
1237
|
-
"index": None
|
|
1238
|
-
"type": None
|
|
1239
|
-
"r": 0.0
|
|
1240
|
-
|
|
1241
|
-
"""
|
|
1242
|
-
mth = "osut.insulatingLayer"
|
|
1243
|
-
cl = openstudio.model.LayeredConstruction
|
|
1244
|
-
res = dict(index=None, type=None, r=0.0)
|
|
1245
|
-
i = 0 # iterator
|
|
1246
|
-
|
|
1247
|
-
if not isinstance(lc, cl):
|
|
1248
|
-
return oslg.mismatch("lc", lc, cl, mth, CN.DBG, res)
|
|
1249
|
-
|
|
1250
|
-
for l in lc.layers():
|
|
1251
|
-
if l.to_MasslessOpaqueMaterial():
|
|
1252
|
-
l = l.to_MasslessOpaqueMaterial().get()
|
|
1253
|
-
|
|
1254
|
-
if l.thermalResistance() < 0.001 or l.thermalResistance() < res["r"]:
|
|
1255
|
-
i += 1
|
|
1256
|
-
continue
|
|
1257
|
-
else:
|
|
1258
|
-
res["r" ] = m.thermalResistance()
|
|
1259
|
-
res["index"] = i
|
|
1260
|
-
res["type" ] = "massless"
|
|
1261
|
-
|
|
1262
|
-
if l.to_StandardOpaqueMaterial():
|
|
1263
|
-
l = l.to_StandardOpaqueMaterial().get()
|
|
1264
|
-
k = l.thermalConductivity()
|
|
1265
|
-
d = l.thickness()
|
|
1266
|
-
|
|
1267
|
-
if (d < 0.003) or (k > 3.0) or (d / k < res["r"]):
|
|
1268
|
-
i += 1
|
|
1269
|
-
continue
|
|
1270
|
-
else:
|
|
1271
|
-
res["r" ] = d / k
|
|
1272
|
-
res["index"] = i
|
|
1273
|
-
res["type" ] = "standard"
|
|
1274
|
-
|
|
1275
|
-
i += 1
|
|
1276
|
-
|
|
1277
|
-
return res
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
1513
|
def areSpandrels(surfaces=None) -> bool:
|
|
1281
1514
|
"""Validates whether one or more opaque surface(s) can be considered as
|
|
1282
1515
|
curtain wall (or similar technology) spandrels, regardless of construction
|
|
@@ -1289,6 +1522,7 @@ def areSpandrels(surfaces=None) -> bool:
|
|
|
1289
1522
|
Returns:
|
|
1290
1523
|
bool: Whether surface(s) can be considered 'spandrels'.
|
|
1291
1524
|
False: If invalid input (see logs).
|
|
1525
|
+
|
|
1292
1526
|
"""
|
|
1293
1527
|
mth = "osut.areSpandrels"
|
|
1294
1528
|
cl = openstudio.model.Surface
|
|
@@ -1384,7 +1618,7 @@ def isFenestrated(s=None) -> bool:
|
|
|
1384
1618
|
# - UNCONDITIONED space: an ENCLOSED space that is NOT a conditioned
|
|
1385
1619
|
# space or a SEMIHEATED space (see above).
|
|
1386
1620
|
#
|
|
1387
|
-
#
|
|
1621
|
+
# Note: Crawlspaces, attics, and parking garages with natural or
|
|
1388
1622
|
# mechanical ventilation are considered UNENCLOSED spaces.
|
|
1389
1623
|
#
|
|
1390
1624
|
# 2.3.3 Modeling Requirements: surfaces adjacent to UNENCLOSED spaces
|
|
@@ -5320,7 +5554,7 @@ def spaceWidth(space=None) -> float:
|
|
|
5320
5554
|
polyg = list(polyg)
|
|
5321
5555
|
polyg.reverse()
|
|
5322
5556
|
|
|
5323
|
-
res = realignedFace(polyg)
|
|
5557
|
+
res = realignedFace(polyg, True)
|
|
5324
5558
|
if not res["box"]: return 0
|
|
5325
5559
|
|
|
5326
5560
|
# A bounded box's 'height', at its narrowest, is its 'width'.
|
|
@@ -5380,7 +5614,7 @@ def genAnchors(s=None, sset=[], tag="box") -> int:
|
|
|
5380
5614
|
# Validate individual subsets. Purge surface-specific leader line anchors.
|
|
5381
5615
|
for i, st in enumerate(sset):
|
|
5382
5616
|
str1 = ide + "subset %d" % (i+1)
|
|
5383
|
-
str2 = str1 + " %s" %
|
|
5617
|
+
str2 = str1 + " %s" % oslg.trim(tag)
|
|
5384
5618
|
|
|
5385
5619
|
if not isinstance(st, dict):
|
|
5386
5620
|
return oslg.mismatch(str1, st, dict, mth, CN.DBG, n)
|
|
@@ -5559,7 +5793,7 @@ def genExtendedVertices(s=None, sset=[], tag="vtx") -> openstudio.Point3dVector:
|
|
|
5559
5793
|
# Validate individual subsets.
|
|
5560
5794
|
for i, st in enumerate(sset):
|
|
5561
5795
|
str1 = ide + "subset %d" % (i+1)
|
|
5562
|
-
str2 = str1 + " %s" %
|
|
5796
|
+
str2 = str1 + " %s" % oslg.trim(tag)
|
|
5563
5797
|
|
|
5564
5798
|
if not isinstance(st, dict):
|
|
5565
5799
|
return oslg.mismatch(str1, st, dict, mth, CN.DBG, a)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: osut
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.2
|
|
4
4
|
Summary: OpenStudio SDK utilities for Python
|
|
5
5
|
Author-email: Denis Bourgeois <denis@rd2.ca>
|
|
6
6
|
Maintainer-email: Denis Bourgeois <denis@rd2.ca>
|
|
@@ -19,7 +19,7 @@ Requires-Dist: oslg
|
|
|
19
19
|
Dynamic: license-file
|
|
20
20
|
|
|
21
21
|
# pyOSut
|
|
22
|
-
Python implementation of the
|
|
22
|
+
Python implementation of the _OSut_ Ruby gem for the OpenStudio SDK.
|
|
23
23
|
|
|
24
24
|
- PyPi [package](https://pypi.org/project/osut/)
|
|
25
25
|
- Ruby [gem](https://rubygems.org/gems/osut)
|
|
@@ -45,6 +45,6 @@ To import the _OSut_ module in a Python project:
|
|
|
45
45
|
|
|
46
46
|
____
|
|
47
47
|
|
|
48
|
-
To run the _OSut_ unit tests on a `git clone` of the
|
|
48
|
+
To run the _OSut_ unit tests on a `git clone` of the repo:
|
|
49
49
|
|
|
50
50
|
`python -m unittest`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# BSD 3-Clause License
|
|
2
2
|
#
|
|
3
|
-
# Copyright (c) 2022-
|
|
3
|
+
# Copyright (c) 2022-2026, rd2
|
|
4
4
|
#
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without
|
|
6
6
|
# modification, are permitted provided that the following conditions are met:
|
|
@@ -130,7 +130,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
130
130
|
self.assertEqual(len(c.layers()), 4)
|
|
131
131
|
self.assertEqual(c.layers()[0].nameString(), "OSut.material.015")
|
|
132
132
|
self.assertEqual(c.layers()[1].nameString(), "OSut.drywall.015")
|
|
133
|
-
self.assertEqual(c.layers()[2].nameString(), "OSut.
|
|
133
|
+
self.assertEqual(c.layers()[2].nameString(), "OSut:K0.047:100")
|
|
134
134
|
self.assertEqual(c.layers()[3].nameString(), "OSut.drywall.015")
|
|
135
135
|
r = osut.rsi(c, osut.film()["wall"])
|
|
136
136
|
u = osut.uo()["wall"]
|
|
@@ -192,7 +192,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
192
192
|
self.assertTrue(c.layers())
|
|
193
193
|
self.assertEqual(len(c.layers()), 3)
|
|
194
194
|
self.assertEqual(c.layers()[0].nameString(), "OSut.drywall.015")
|
|
195
|
-
self.assertEqual(c.layers()[1].nameString(), "OSut.
|
|
195
|
+
self.assertEqual(c.layers()[1].nameString(), "OSut:K0.023:100")
|
|
196
196
|
self.assertEqual(c.layers()[2].nameString(), "OSut.drywall.015")
|
|
197
197
|
self.assertTrue("uo" in specs)
|
|
198
198
|
self.assertAlmostEqual(specs["uo"], 0.214, places=2)
|
|
@@ -214,7 +214,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
214
214
|
self.assertTrue(c.layers())
|
|
215
215
|
self.assertEqual(len(c.layers()), 3)
|
|
216
216
|
self.assertEqual(c.layers()[0].nameString(), "OSut.drywall.015")
|
|
217
|
-
self.assertEqual(c.layers()[1].nameString(), "OSut.
|
|
217
|
+
self.assertEqual(c.layers()[1].nameString(), "OSut:K0.023:100")
|
|
218
218
|
self.assertEqual(c.layers()[2].nameString(), "OSut.drywall.015")
|
|
219
219
|
self.assertTrue("uo" in specs)
|
|
220
220
|
self.assertAlmostEqual(specs["uo"], 0.214, places=3)
|
|
@@ -237,7 +237,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
237
237
|
self.assertEqual(len(c.layers()), 4)
|
|
238
238
|
self.assertEqual(c.layers()[0].nameString(), "OSut.material.015")
|
|
239
239
|
self.assertEqual(c.layers()[1].nameString(), "OSut.drywall.015")
|
|
240
|
-
self.assertEqual(c.layers()[2].nameString(), "OSut.
|
|
240
|
+
self.assertEqual(c.layers()[2].nameString(), "OSut:K0.024:100")
|
|
241
241
|
self.assertEqual(c.layers()[3].nameString(), "OSut.drywall.015")
|
|
242
242
|
self.assertTrue("uo" in specs)
|
|
243
243
|
self.assertAlmostEqual(specs["uo"], 0.214, places=3)
|
|
@@ -259,7 +259,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
259
259
|
self.assertTrue(c.layers())
|
|
260
260
|
self.assertEqual(len(c.layers()), 2)
|
|
261
261
|
self.assertEqual(c.layers()[0].nameString(), "OSut.drywall.015")
|
|
262
|
-
self.assertEqual(c.layers()[1].nameString(), "OSut.
|
|
262
|
+
self.assertEqual(c.layers()[1].nameString(), "OSut:K0.023:100")
|
|
263
263
|
self.assertTrue("uo" in specs)
|
|
264
264
|
self.assertAlmostEqual(specs["uo"], 0.214, places=3)
|
|
265
265
|
r = osut.rsi(c, osut.film()["wall"])
|
|
@@ -360,7 +360,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
360
360
|
self.assertTrue(c.layers())
|
|
361
361
|
self.assertEqual(len(c.layers()), 3)
|
|
362
362
|
self.assertEqual(c.layers()[0].nameString(), "OSut.material.015")
|
|
363
|
-
self.assertEqual(c.layers()[1].nameString(), "OSut.
|
|
363
|
+
self.assertEqual(c.layers()[1].nameString(), "OSut:K0.023:100")
|
|
364
364
|
self.assertEqual(c.layers()[2].nameString(), "OSut.drywall.015")
|
|
365
365
|
self.assertTrue("uo" in specs)
|
|
366
366
|
self.assertAlmostEqual(specs["uo"], 0.214, places=2)
|
|
@@ -382,7 +382,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
382
382
|
self.assertTrue(c.layers())
|
|
383
383
|
self.assertEqual(len(c.layers()), 3)
|
|
384
384
|
self.assertEqual(c.layers()[0].nameString(), "OSut.material.015")
|
|
385
|
-
self.assertEqual(c.layers()[1].nameString(), "OSut.
|
|
385
|
+
self.assertEqual(c.layers()[1].nameString(), "OSut:K0.023:100")
|
|
386
386
|
self.assertEqual(c.layers()[2].nameString(), "OSut.concrete.100")
|
|
387
387
|
self.assertTrue("uo" in specs)
|
|
388
388
|
self.assertAlmostEqual(specs["uo"], 0.214, places=3)
|
|
@@ -404,7 +404,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
404
404
|
self.assertTrue(c.layers())
|
|
405
405
|
self.assertEqual(len(c.layers()), 2)
|
|
406
406
|
self.assertEqual(c.layers()[0].nameString(), "OSut.concrete.200")
|
|
407
|
-
self.assertEqual(c.layers()[1].nameString(), "OSut.
|
|
407
|
+
self.assertEqual(c.layers()[1].nameString(), "OSut:K0.023:100")
|
|
408
408
|
self.assertTrue("uo" in specs)
|
|
409
409
|
self.assertAlmostEqual(specs["uo"], 0.214, places=3)
|
|
410
410
|
r = osut.rsi(c, osut.film()["roof"])
|
|
@@ -441,7 +441,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
441
441
|
self.assertTrue(c.layers())
|
|
442
442
|
self.assertEqual(len(c.layers()), 2)
|
|
443
443
|
self.assertEqual(c.layers()[0].nameString(), "OSut.material.015")
|
|
444
|
-
self.assertEqual(c.layers()[1].nameString(), "OSut.
|
|
444
|
+
self.assertEqual(c.layers()[1].nameString(), "OSut:K0.023:100")
|
|
445
445
|
self.assertTrue("uo" in specs)
|
|
446
446
|
self.assertAlmostEqual(specs["uo"], 0.214, places=3)
|
|
447
447
|
r = osut.rsi(c, osut.film()["floor"])
|
|
@@ -462,7 +462,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
462
462
|
self.assertTrue(c.layers())
|
|
463
463
|
self.assertEqual(len(c.layers()), 3)
|
|
464
464
|
self.assertEqual(c.layers()[0].nameString(), "OSut.material.015")
|
|
465
|
-
self.assertEqual(c.layers()[1].nameString(), "OSut.
|
|
465
|
+
self.assertEqual(c.layers()[1].nameString(), "OSut:K0.024:100")
|
|
466
466
|
self.assertEqual(c.layers()[2].nameString(), "OSut.material.015")
|
|
467
467
|
self.assertTrue("uo" in specs)
|
|
468
468
|
self.assertAlmostEqual(specs["uo"], 0.214, places=3)
|
|
@@ -484,7 +484,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
484
484
|
self.assertTrue(c.layers())
|
|
485
485
|
self.assertEqual(len(c.layers()), 3)
|
|
486
486
|
self.assertEqual(c.layers()[0].nameString(), "OSut.material.015")
|
|
487
|
-
self.assertEqual(c.layers()[1].nameString(), "OSut.
|
|
487
|
+
self.assertEqual(c.layers()[1].nameString(), "OSut:K0.023:100")
|
|
488
488
|
self.assertEqual(c.layers()[2].nameString(), "OSut.concrete.100")
|
|
489
489
|
self.assertTrue("uo" in specs)
|
|
490
490
|
self.assertAlmostEqual(specs["uo"], 0.214, places=3)
|
|
@@ -523,7 +523,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
523
523
|
self.assertTrue(c.layers())
|
|
524
524
|
self.assertEqual(len(c.layers()), 3)
|
|
525
525
|
self.assertEqual(c.layers()[0].nameString(), "OSut.sand.100")
|
|
526
|
-
self.assertEqual(c.layers()[1].nameString(), "OSut.
|
|
526
|
+
self.assertEqual(c.layers()[1].nameString(), "OSut:K0.010:043")
|
|
527
527
|
self.assertEqual(c.layers()[2].nameString(), "OSut.concrete.100")
|
|
528
528
|
self.assertTrue("uo" in specs)
|
|
529
529
|
self.assertAlmostEqual(specs["uo"], 0.214, places=3)
|
|
@@ -561,7 +561,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
561
561
|
self.assertTrue(c.layers())
|
|
562
562
|
self.assertEqual(len(c.layers()), 3)
|
|
563
563
|
self.assertEqual(c.layers()[0].nameString(), "OSut.concrete.200")
|
|
564
|
-
self.assertEqual(c.layers()[1].nameString(), "OSut.
|
|
564
|
+
self.assertEqual(c.layers()[1].nameString(), "OSut:K0.037:075")
|
|
565
565
|
self.assertEqual(c.layers()[2].nameString(), "OSut.drywall.015")
|
|
566
566
|
self.assertTrue("uo" in specs)
|
|
567
567
|
self.assertAlmostEqual(specs["uo"], 0.428, places=3)
|
|
@@ -763,6 +763,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
763
763
|
|
|
764
764
|
def test07_construction_thickness(self):
|
|
765
765
|
o = osut.oslg
|
|
766
|
+
print(o.logs())
|
|
766
767
|
self.assertEqual(o.status(), 0)
|
|
767
768
|
self.assertEqual(o.level(), DBG)
|
|
768
769
|
|
|
@@ -5101,6 +5102,7 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
5101
5102
|
self.assertEqual(o.reset(DBG), DBG)
|
|
5102
5103
|
self.assertEqual(o.level(), DBG)
|
|
5103
5104
|
|
|
5105
|
+
srr = 0.05
|
|
5104
5106
|
version = int("".join(openstudio.openStudioVersion().split(".")))
|
|
5105
5107
|
translator = openstudio.osversion.VersionTranslator()
|
|
5106
5108
|
|
|
@@ -5109,34 +5111,79 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
5109
5111
|
self.assertTrue(model)
|
|
5110
5112
|
model = model.get()
|
|
5111
5113
|
|
|
5112
|
-
|
|
5114
|
+
s = model.getSurfaceByName("Perimeter_ZN_1_ceiling")
|
|
5115
|
+
self.assertTrue(s)
|
|
5116
|
+
s = s.get()
|
|
5117
|
+
self.assertTrue(s.isConstructionDefaulted()) # yet which set?
|
|
5118
|
+
|
|
5119
|
+
type = s.surfaceType()
|
|
5120
|
+
self.assertEqual(type.lower(), "roofceiling")
|
|
5121
|
+
base = s.construction()
|
|
5122
|
+
self.assertTrue(base)
|
|
5123
|
+
base = base.get()
|
|
5124
|
+
|
|
5125
|
+
# Check OpenStudio space-to-building hierarchy.
|
|
5126
|
+
space = s.space()
|
|
5127
|
+
self.assertTrue(space)
|
|
5128
|
+
space = space.get()
|
|
5129
|
+
self.assertFalse(space.defaultConstructionSet())
|
|
5130
|
+
|
|
5131
|
+
spacetype = space.spaceType()
|
|
5132
|
+
self.assertTrue(spacetype)
|
|
5133
|
+
spacetype = spacetype.get()
|
|
5134
|
+
self.assertFalse(spacetype.defaultConstructionSet())
|
|
5135
|
+
|
|
5136
|
+
story = space.buildingStory()
|
|
5137
|
+
self.assertTrue(story)
|
|
5138
|
+
story = story.get()
|
|
5139
|
+
self.assertFalse(story.defaultConstructionSet())
|
|
5140
|
+
|
|
5141
|
+
building = model.getBuilding()
|
|
5142
|
+
self.assertTrue(building.defaultConstructionSet())
|
|
5143
|
+
bset = building.defaultConstructionSet().get()
|
|
5144
|
+
oID = bset.nameString()
|
|
5145
|
+
self.assertEqual(oID, "90.1-2010 - SmOffice - ASHRAE 169-2013-3B")
|
|
5146
|
+
self.assertFalse(osut.holdsConstruction(bset, base, False, False, type))
|
|
5147
|
+
|
|
5148
|
+
# Check for adjacent surface.
|
|
5149
|
+
adjacent = s.adjacentSurface()
|
|
5150
|
+
self.assertTrue(adjacent)
|
|
5151
|
+
adjacent = adjacent.get()
|
|
5152
|
+
atype = adjacent.surfaceType()
|
|
5153
|
+
self.assertEqual(atype.lower(), "floor")
|
|
5154
|
+
|
|
5155
|
+
attic = adjacent.space()
|
|
5156
|
+
self.assertTrue(attic)
|
|
5157
|
+
attic = attic.get()
|
|
5158
|
+
self.assertFalse(attic.defaultConstructionSet())
|
|
5159
|
+
|
|
5160
|
+
spacetype = attic.spaceType()
|
|
5161
|
+
self.assertTrue(spacetype)
|
|
5162
|
+
spacetype = spacetype.get()
|
|
5163
|
+
aset = spacetype.defaultConstructionSet()
|
|
5164
|
+
self.assertTrue(aset)
|
|
5165
|
+
aset = aset.get()
|
|
5166
|
+
aID = aset.nameString()
|
|
5167
|
+
self.assertEqual(aID, "90.1-2010 - - Attic - ASHRAE 169-2013-3B")
|
|
5168
|
+
self.assertTrue(osut.holdsConstruction(aset, base, False, False, atype))
|
|
5169
|
+
|
|
5170
|
+
set = osut.defaultConstructionSet(s)
|
|
5171
|
+
self.assertEqual(set, aset)
|
|
5172
|
+
|
|
5173
|
+
self.assertTrue(bset.defaultInteriorSurfaceConstructions())
|
|
5174
|
+
self.assertTrue(aset.defaultInteriorSurfaceConstructions())
|
|
5175
|
+
ib_set = bset.defaultInteriorSurfaceConstructions().get()
|
|
5176
|
+
ia_set = aset.defaultInteriorSurfaceConstructions().get()
|
|
5177
|
+
self.assertTrue(ib_set.wallConstruction())
|
|
5178
|
+
self.assertFalse(ia_set.wallConstruction())
|
|
5179
|
+
ib_wall = ib_set.wallConstruction().get().to_LayeredConstruction()
|
|
5180
|
+
self.assertTrue(ib_wall)
|
|
5181
|
+
ib_wall = ib_wall.get()
|
|
5182
|
+
self.assertAlmostEqual(osut.rsi(ib_wall, 0.150), 0.31, places=2)
|
|
5183
|
+
|
|
5113
5184
|
core = []
|
|
5114
5185
|
attic = []
|
|
5115
5186
|
|
|
5116
|
-
# Fetch default construction sets.
|
|
5117
|
-
oID = "90.1-2010 - SmOffice - ASHRAE 169-2013-3B" # building
|
|
5118
|
-
aID = "90.1-2010 - - Attic - ASHRAE 169-2013-3B" # attic spacetype level
|
|
5119
|
-
o_set = model.getDefaultConstructionSetByName(oID)
|
|
5120
|
-
a_set = model.getDefaultConstructionSetByName(oID)
|
|
5121
|
-
self.assertTrue(o_set)
|
|
5122
|
-
self.assertTrue(a_set)
|
|
5123
|
-
o_set = o_set.get()
|
|
5124
|
-
a_set = a_set.get()
|
|
5125
|
-
self.assertTrue(o_set.defaultInteriorSurfaceConstructions())
|
|
5126
|
-
self.assertTrue(a_set.defaultInteriorSurfaceConstructions())
|
|
5127
|
-
io_set = o_set.defaultInteriorSurfaceConstructions().get()
|
|
5128
|
-
ia_set = a_set.defaultInteriorSurfaceConstructions().get()
|
|
5129
|
-
self.assertTrue(io_set.wallConstruction())
|
|
5130
|
-
self.assertTrue(ia_set.wallConstruction())
|
|
5131
|
-
io_wall = io_set.wallConstruction().get().to_LayeredConstruction()
|
|
5132
|
-
ia_wall = ia_set.wallConstruction().get().to_LayeredConstruction()
|
|
5133
|
-
self.assertTrue(io_wall)
|
|
5134
|
-
self.assertTrue(ia_wall)
|
|
5135
|
-
io_wall = io_wall.get()
|
|
5136
|
-
ia_wall = ia_wall.get()
|
|
5137
|
-
self.assertEqual(io_wall, ia_wall) # 2x drywall layers
|
|
5138
|
-
self.assertAlmostEqual(osut.rsi(io_wall, 0.150), 0.31, places=2)
|
|
5139
|
-
|
|
5140
5187
|
for space in model.getSpaces():
|
|
5141
5188
|
ide = space.nameString()
|
|
5142
5189
|
|
|
@@ -5897,6 +5944,33 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
5897
5944
|
self.assertEqual(o.level(), DBG)
|
|
5898
5945
|
translator = openstudio.osversion.VersionTranslator()
|
|
5899
5946
|
|
|
5947
|
+
# Basic test: 'deep' space (vs X-axis).
|
|
5948
|
+
vtx = openstudio.Point3dVector()
|
|
5949
|
+
vtx.append(openstudio.Point3d(2,9,1))
|
|
5950
|
+
vtx.append(openstudio.Point3d(2,1,1))
|
|
5951
|
+
vtx.append(openstudio.Point3d(1,1,1))
|
|
5952
|
+
vtx.append(openstudio.Point3d(1,9,1))
|
|
5953
|
+
|
|
5954
|
+
model = openstudio.model.Model()
|
|
5955
|
+
space = openstudio.model.Space(model)
|
|
5956
|
+
floor = openstudio.model.Surface(vtx, model)
|
|
5957
|
+
floor.setSpace(space)
|
|
5958
|
+
self.assertAlmostEqual(osut.spaceWidth(space),1,3)
|
|
5959
|
+
|
|
5960
|
+
# Basic test: 'narrow' space (vs X-axis).
|
|
5961
|
+
vtx = openstudio.Point3dVector()
|
|
5962
|
+
vtx.append(openstudio.Point3d(9,2,1))
|
|
5963
|
+
vtx.append(openstudio.Point3d(9,1,1))
|
|
5964
|
+
vtx.append(openstudio.Point3d(1,1,1))
|
|
5965
|
+
vtx.append(openstudio.Point3d(1,2,1))
|
|
5966
|
+
|
|
5967
|
+
model = openstudio.model.Model()
|
|
5968
|
+
space = openstudio.model.Space(model)
|
|
5969
|
+
floor = openstudio.model.Surface(vtx, model)
|
|
5970
|
+
floor.setSpace(space)
|
|
5971
|
+
self.assertAlmostEqual(osut.spaceWidth(space),1,3)
|
|
5972
|
+
|
|
5973
|
+
# --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
|
|
5900
5974
|
path = openstudio.path("./tests/files/osms/in/warehouse.osm")
|
|
5901
5975
|
model = translator.loadModel(path)
|
|
5902
5976
|
self.assertTrue(model)
|
|
@@ -5976,4 +6050,4 @@ class TestOSutModuleMethods(unittest.TestCase):
|
|
|
5976
6050
|
self.assertEqual(o.status(), 0)
|
|
5977
6051
|
|
|
5978
6052
|
if __name__ == "__main__":
|
|
5979
|
-
unittest.main()
|
|
6053
|
+
unittest.main(failfast=True)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|