Skip to content

Commit 0aa21a6

Browse files
committed
(Better) manages attic interzone constructions
1 parent 158a702 commit 0aa21a6

File tree

2 files changed

+45
-69
lines changed

2 files changed

+45
-69
lines changed

lib/osut/utils.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7267,7 +7267,6 @@ def addSkyLights(spaces = [], opts = {})
72677267
end
72687268
end
72697269

7270-
72717270
# New direct roof loop. No overlaps, so no need for relative space
72727271
# coordinate adjustments.
72737272
rooms.each do |space, room|

spec/osut_tests_spec.rb

Lines changed: 45 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@
425425
expect(cls1.status).to be_zero
426426
expect(cls1.logs).to be_empty
427427
end
428-
428+
429429
it "checks if a set holds a construction" do
430430
translator = OpenStudio::OSVersion::VersionTranslator.new
431431
expect(mod1.clean!).to eq(DBG)
@@ -4450,6 +4450,30 @@ module M
44504450
core = []
44514451
attic = []
44524452

4453+
# Fetch default construction sets.
4454+
oID = "90.1-2010 - SmOffice - ASHRAE 169-2013-3B" # building
4455+
aID = "90.1-2010 - - Attic - ASHRAE 169-2013-3B" # attic spacetype level
4456+
o_set = model.getDefaultConstructionSetByName(oID)
4457+
a_set = model.getDefaultConstructionSetByName(oID)
4458+
expect(o_set).to_not be_empty
4459+
expect(a_set).to_not be_empty
4460+
o_set = o_set.get
4461+
a_set = a_set.get
4462+
expect(o_set.defaultInteriorSurfaceConstructions).to_not be_empty
4463+
expect(a_set.defaultInteriorSurfaceConstructions).to_not be_empty
4464+
io_set = o_set.defaultInteriorSurfaceConstructions.get
4465+
ia_set = a_set.defaultInteriorSurfaceConstructions.get
4466+
expect(io_set.wallConstruction).to_not be_empty
4467+
expect(ia_set.wallConstruction).to_not be_empty
4468+
io_wall = io_set.wallConstruction.get.to_LayeredConstruction
4469+
ia_wall = ia_set.wallConstruction.get.to_LayeredConstruction
4470+
expect(io_wall).to_not be_empty
4471+
expect(ia_wall).to_not be_empty
4472+
io_wall = io_wall.get
4473+
ia_wall = ia_wall.get
4474+
expect(io_wall).to eq(ia_wall) # 2x drywall layers
4475+
expect(mod1.rsi(io_wall, 0.150)).to be_within(TOL).of(0.31)
4476+
44534477
model.getSpaces.each do |space|
44544478
id = space.nameString
44554479

@@ -4480,7 +4504,6 @@ module M
44804504

44814505
# "GROSS ROOF AREA" (GRA), as per 90.1/NECB - excludes roof overhangs (60m2)
44824506
gra1 = mod1.grossRoofArea(model.getSpaces)
4483-
puts mod1.logs unless mod1.status.zero?
44844507
expect(mod1.status).to be_zero
44854508
expect(gra1.round(2)).to eq(538.86)
44864509

@@ -4494,8 +4517,8 @@ module M
44944517
# 2. INDIRECTLY-CONDITIONED (e.g. plenum)
44954518
#
44964519
# For testing purposes, only the core zone is targeted for skylight wells.
4497-
# Context: NECBs and 90.1 require separate SRR% calculations for spaces
4498-
# conditioned differently (SEMI-CONDITIONED vs CONDITIONED).
4520+
# Context: NECBs and 90.1 require separate SRR% calculations for
4521+
# differently conditioned spaces (SEMI-CONDITIONED vs CONDITIONED).
44994522
# See 'addSkyLights' doc.
45004523

45014524
# --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
@@ -4505,13 +4528,10 @@ module M
45054528
# GRA is substantially lower (than previously-calculated gra1). For now,
45064529
# calculated GRA is only valid BEFORE adding skylight wells.
45074530
gra_attic = mod1.grossRoofArea(core)
4508-
expect(mod1.status).to be_zero
45094531
expect(gra_attic.round(2)).to eq(157.77)
45104532

45114533
# The method returns the GRA, calculated BEFORE adding skylights/wells.
45124534
rm2 = mod1.addSkyLights(core, {srr: srr})
4513-
puts mod1.logs unless mod1.status.zero?
4514-
expect(mod1.status).to be_zero
45154535
expect(rm2.round(2)).to eq(gra_attic.round(2))
45164536

45174537
# New core skylight areas. Successfully achieved SRR%.
@@ -4521,44 +4541,11 @@ module M
45214541
ratio = sky_area1 / rm2
45224542
expect(ratio.round(2)).to eq(srr)
45234543

4524-
# Assign insulated constructions to new skylight well walls.
4525-
drywall = OpenStudio::Model::StandardOpaqueMaterial.new(model)
4526-
drywall.setName("drywall")
4527-
expect(drywall.setThickness(0.015))
4528-
expect(drywall.setRoughness("MediumSmooth"))
4529-
expect(drywall.setConductivity(0.160))
4530-
expect(drywall.setDensity(785))
4531-
expect(drywall.setSpecificHeat(1090))
4532-
expect(drywall.setThermalAbsorptance(0.9))
4533-
expect(drywall.setSolarAbsorptance(0.7))
4534-
expect(drywall.setVisibleAbsorptance(0.7))
4535-
4536-
composite = OpenStudio::Model::StandardOpaqueMaterial.new(model)
4537-
composite.setName("composite")
4538-
expect(composite.setThickness(0.100))
4539-
expect(composite.setRoughness("MediumSmooth"))
4540-
expect(composite.setConductivity(0.030))
4541-
expect(composite.setDensity(40))
4542-
expect(composite.setSpecificHeat(960))
4543-
expect(composite.setThermalAbsorptance(0.9))
4544-
expect(composite.setSolarAbsorptance(0.7))
4545-
expect(composite.setVisibleAbsorptance(0.7))
4546-
4547-
layers = OpenStudio::Model::OpaqueMaterialVector.new
4548-
layers << drywall
4549-
layers << composite
4550-
layers << drywall
4551-
construction = OpenStudio::Model::Construction.new(layers)
4552-
expect(mod1.rsi(construction, 0.240)).to be_within(TOL).of(3.76)
4553-
4554-
mod1.facets(attic, "Surface", "Wall").each do |wall|
4555-
expect(wall.setConstruction(construction)).to be true
4556-
adj = wall.adjacentSurface
4557-
expect(adj).to_not be_empty
4558-
adj = adj.get
4559-
expect(wall.setConstruction(construction)).to be true
4560-
expect(adj.setConstruction(construction)).to be true
4561-
end
4544+
# Reset attic default construction set for insulated interzone walls.
4545+
construction = mod1.genConstruction(model, {type: :partition, uo: 0.3})
4546+
expect(mod1.rsi(construction, 0.150)).to be_within(TOL).of(1/0.3)
4547+
expect(ia_set.setWallConstruction(construction)).to be true
4548+
expect(mod1.status).to be_zero
45624549

45634550
file = File.join(__dir__, "files/osms/out/office_attic.osm")
45644551
model.save(file, true)
@@ -4588,21 +4575,18 @@ module M
45884575
expect(mod1.setpoints(attic)[:cooling]).to be_within(TOL).of(23.89)
45894576

45904577
# Here, GRA includes ALL plenum roof surfaces (not just vertically-cast
4591-
# areas onto core ceiling). This will make meeting the SRR% of 5% much
4592-
# harder.
4578+
# areas onto core ceiling). This makes meeting the SRR% of 5% much harder.
45934579
gra_plenum = mod1.grossRoofArea(core)
4594-
expect(mod1.status).to be_zero
45954580
expect(gra_plenum.round(2)).to eq(total.round(2))
45964581

45974582
rm2 = mod1.addSkyLights(core, {srr: srr})
4598-
puts mod1.logs unless mod1.status.zero?
4599-
expect(mod1.status).to be_zero
46004583
expect(rm2.round(2)).to eq(total.round(2))
46014584

4602-
# New core skylight areas. Although the total skylight area is greater than
4603-
# in CASE 1, the method is unable to meet the requested SRR 5%. This is
4585+
# New core skylight areas. The total skylight area is greater than in CASE 1,
4586+
# and the method is unable to meet the requested SRR 5%. This is
46044587
# understandable given the constrained roof/core overlap vs the ~4x greater
4605-
# roof area. A plenum vastly larger than the room(s) it serves is rare.
4588+
# roof area. A plenum vastly larger than the room(s) it serves is rare, but
4589+
# certainly problematic for the application of the NECBs.
46064590
core_skies = mod1.facets(core, "Outdoors", "Skylight")
46074591
sky_area2 = core_skies.sum(&:grossArea)
46084592
expect(sky_area2.round(2)).to eq(8.93)
@@ -4628,32 +4612,29 @@ module M
46284612
core = core.get
46294613
attic = attic.get
46304614

4631-
# Again, tag attic as an INDIRECTLY-CONDITIONED space.
4615+
# Again, tagging attic as an INDIRECTLY-CONDITIONED space.
46324616
key = "indirectlyconditioned"
46334617
val = core.nameString
46344618
expect(attic.additionalProperties.setFeature(key, val)).to be true
46354619
expect(mod1.plenum?(attic)).to be false
46364620
expect(mod1.unconditioned?(attic)).to be false
46374621
expect(mod1.setpoints(attic)[:heating]).to be_within(TOL).of(21.11)
46384622
expect(mod1.setpoints(attic)[:cooling]).to be_within(TOL).of(23.89)
4639-
expect(mod1.status).to be_zero
46404623

46414624
gra_plenum = mod1.grossRoofArea(core)
4642-
expect(mod1.status).to be_zero
46434625
expect(gra_plenum.round(2)).to eq(total.round(2))
46444626

4645-
# Conflicting argument case: Here, the method can only add skylight wells
4646-
# through model "plenums" (in this context, :plenum is an all encompassing
4647-
# keyword for any INDIRECTLY-CONDITIONED, unoccupied space). Yet by passing
4648-
# option "plenum: false", the method is instructed to skip "plenum"
4649-
# skylight wells altogether.
4627+
# Conflicting argument case: Here, skylight wells must traverse plenums (in
4628+
# this context, :plenum is an all encompassing keyword for any INDIRECTLY-
4629+
# CONDITIONED, unoccupied space). Yet by passing option "plenum: false",
4630+
# the method is instructed to skip "plenum" skylight wells altogether.
46504631
rm2 = mod1.addSkyLights(core, {srr: srr, plenum: false})
4651-
expect(mod1.status).to be_zero
46524632
expect(rm2.round(2)).to eq(total.round(2))
46534633

46544634
core_skies = mod1.facets(core, "Outdoors", "Skylight")
46554635
sky_area2 = core_skies.sum(&:grossArea)
46564636
expect(sky_area2.round(2)).to eq(0.00)
4637+
expect(mod1.status).to be_zero
46574638

46584639
# --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
46594640
# SEB case (flat ceiling plenum).
@@ -4687,15 +4668,12 @@ module M
46874668
expect(total.round(2)).to eq(82.21)
46884669

46894670
gra_seb = mod1.grossRoofArea(model.getSpaces)
4690-
expect(mod1.status).to be_zero
46914671
expect(gra_seb.round(2)).to eq(total.round(2))
46924672

46934673
srr = 0.04
46944674

46954675
# The method returns the GRA, calculated BEFORE adding skylights/wells.
46964676
rm2 = mod1.addSkyLights(model.getSpaces, {srr: srr})
4697-
puts mod1.logs unless mod1.status.zero?
4698-
expect(mod1.status).to be_zero
46994677
expect(rm2.round(2)).to eq(gra_seb.round(2))
47004678

47014679
entry_skies = mod1.facets(entry, "Outdoors", "Skylight")
@@ -4717,6 +4695,7 @@ module M
47174695
construction = mod1.genConstruction(model, {type: :skylight, uo: 2.8})
47184696
expect(utility_sky.setConstruction(construction)).to be true
47194697
expect(open_sky.setConstruction(construction)).to be true
4698+
expect(mod1.status).to be_zero
47204699

47214700
file = File.join(__dir__, "files/osms/out/seb_sky.osm")
47224701
model.save(file, true)
@@ -4753,7 +4732,6 @@ module M
47534732

47544733
bulk_roof_m2 = mod1.getRoofs(bulk).sum(&:grossArea)
47554734
fine_roof_m2 = mod1.getRoofs(fine).sum(&:grossArea)
4756-
expect(mod1.status).to be_zero
47574735
expect(gra_bulk.round(2)).to eq(bulk_roof_m2.round(2))
47584736
expect(gra_fine.round(2)).to eq(fine_roof_m2.round(2))
47594737

@@ -4770,14 +4748,13 @@ module M
47704748
opts[:size ] = 2.4
47714749
opts[:clear] = true
47724750
rm2 = mod1.addSkyLights(bulk, opts)
4773-
puts mod1.logs unless mod1.status.zero?
4774-
expect(mod1.status).to be_zero
47754751

47764752
bulk_skies = mod1.facets(bulk, "Outdoors", "Skylight")
47774753
sky_area2 = bulk_skies.sum(&:grossArea)
47784754
expect(sky_area2.round(2)).to eq(128.19)
47794755
ratio2 = sky_area2 / rm2
47804756
expect(ratio2.round(2)).to eq(srr)
4757+
expect(mod1.status).to be_zero
47814758

47824759
file = File.join(__dir__, "files/osms/out/warehouse_sky.osm")
47834760
model.save(file, true)

0 commit comments

Comments
 (0)