diff --git a/LICENSE b/LICENSE index 781b8cd..815defb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2022-2025, Denis Bourgeois +Copyright (c) 2022-2026, Denis Bourgeois All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/lib/osut.rb b/lib/osut.rb index 7561fec..b0ede77 100644 --- a/lib/osut.rb +++ b/lib/osut.rb @@ -1,6 +1,6 @@ # BSD 3-Clause License # -# Copyright (c) 2022-2025, Denis Bourgeois +# Copyright (c) 2022-2026, Denis Bourgeois # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/lib/osut/utils.rb b/lib/osut/utils.rb index 77d8014..09bb951 100644 --- a/lib/osut/utils.rb +++ b/lib/osut/utils.rb @@ -1,6 +1,6 @@ # BSD 3-Clause License # -# Copyright (c) 2022-2025, Denis Bourgeois +# Copyright (c) 2022-2026, Denis Bourgeois # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -530,7 +530,7 @@ def resetUo(lc = nil, film = nil, index = nil, uo = nil, uniq = false) mt.setName(id) unless mt.setThermalResistance(r) - return invalid("Failed #{id}: RSi#{de_r.round(2)}", mth) + return invalid("Failed #{id}: RSi#{r.round(2)}", mth) end lc.setLayer(index, mt) @@ -546,7 +546,7 @@ def resetUo(lc = nil, film = nil, index = nil, uo = nil, uniq = false) k = (m.thickness / (r + dR)).clamp(KMIN, KMAX) d = (k * (r + dR)).clamp(DMIN, DMAX) r = d / k - id = "OSUT:K#{format('%4.3f', k)}:#{format('%03d', d*1000)[-3..-1]}" + id = "OSut:K#{format('%4.3f', k)}:#{format('%03d', d*1000)[-3..-1]}" mt = lc.model.getStandardOpaqueMaterialByName(id) # Existing material? @@ -928,7 +928,6 @@ def genConstruction(model = nil, specs = {}) if u and a[:glazing].empty? ro = 1 / u - film - if ro > RMIN if specs[:type] == :door # 1x layer, adjust conductivity layer = c.getLayer(0).to_StandardOpaqueMaterial @@ -944,27 +943,7 @@ def genConstruction(model = nil, specs = {}) return invalid("#{id} construction", mth, 0) if lyr[:r ].to_i.zero? index = lyr[:index] - layer = c.getLayer(index).to_StandardOpaqueMaterial - return invalid("#{id} material @#{index}", mth, 0) if layer.empty? - - layer = layer.get - - k = (layer.thickness / (ro - rsi(c) + lyr[:r])).clamp(KMIN, KMAX) - d = (k * (ro - rsi(c) + lyr[:r])).clamp(DMIN, DMAX) - - nom = "OSut:" - nom += layer.nameString.gsub(/[^a-z]/i, "").gsub("OSut", "") - nom += ":K#{format('%4.3f', k)}:#{format('%03d', d*1000)[-3..-1]}" - - lyr = model.getStandardOpaqueMaterialByName(nom) - - if lyr.empty? - layer.setName(nom) - layer.setConductivity(k) - layer.setThickness(d) - else - c.setLayer(index, lyr.get) - end + resetUo(c, film, index, u) end end end diff --git a/lib/osut/version.rb b/lib/osut/version.rb index eb36a41..2c1149c 100644 --- a/lib/osut/version.rb +++ b/lib/osut/version.rb @@ -1,6 +1,6 @@ # BSD 3-Clause License # -# Copyright (c) 2022-2025, Denis Bourgeois +# Copyright (c) 2022-2026, Denis Bourgeois # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -29,5 +29,5 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. module OSut - VERSION = "0.8.0".freeze + VERSION = "0.8.1".freeze end diff --git a/spec/osut_tests_spec.rb b/spec/osut_tests_spec.rb index df34b9e..8d4a243 100644 --- a/spec/osut_tests_spec.rb +++ b/spec/osut_tests_spec.rb @@ -154,6 +154,7 @@ expect(u).to be_within(TOL).of(uo2) # Insulated, unfinished outdoor-facing plenum roof (polyiso above 4" slab). + model = OpenStudio::Model::Model.new specs = {type: :roof, uo: uo2, frame: :medium, finish: :medium} surface = cls1.genConstruction(model, specs) expect(surface).to_not be_nil @@ -161,10 +162,11 @@ expect(surface.layers.size).to eq(3) u = 1 / cls1.rsi(surface, film[:roof]) expect(u).to be_within(TOL).of(uo2) - expect(surface.layers[1].nameString).to eq("OSut:polyiso:K0.023:100") + expect(surface.layers[1].nameString).to eq("OSut:K0.023:100") expect(surface.layers[2].nameString).to eq("OSut:concrete:100") # Roof above conditioned parking garage (polyiso under 8" slab). + model = OpenStudio::Model::Model.new specs = {type: :roof, uo: uo2, clad: :heavy, frame: :medium, finish: :none} surface = cls1.genConstruction(model, specs) expect(surface).to_not be_nil @@ -173,9 +175,10 @@ u = 1 / cls1.rsi(surface, film[:roof]) expect(u).to be_within(TOL).of(uo2) expect(surface.layers[0].nameString).to eq("OSut:concrete:200") - expect(surface.layers[1].nameString).to eq("OSut:polyiso:K0.023:100") + expect(surface.layers[1].nameString).to eq("OSut:K0.023:100") # Uninsulated plenum ceiling tiles (alternative :shading). + model = OpenStudio::Model::Model.new specs = {type: :roof, uo: nil, clad: :none, finish: :none} surface = cls1.genConstruction(model, specs) expect(surface).to_not be_nil @@ -185,6 +188,7 @@ expect(u).to be_within(TOL).of(uo6) # Unfinished, insulated, framed attic floor (blown cellulose). + model = OpenStudio::Model::Model.new specs = {type: :floor, uo: uo2, frame: :heavy, finish: :none} surface = cls1.genConstruction(model, specs) expect(surface).to_not be_nil @@ -192,9 +196,10 @@ expect(surface.layers.size).to eq(2) u = 1 / cls1.rsi(surface, film[:floor]) expect(u).to be_within(TOL).of(uo2) - expect(surface.layers[1].nameString).to eq("OSut:cellulose:K0.023:100") + expect(surface.layers[1].nameString).to eq("OSut:K0.023:100") # Finished, insulated exposed floor (e.g. wood-framed, residential). + model = OpenStudio::Model::Model.new specs = {type: :floor, uo: uo2} surface = cls1.genConstruction(model, specs) expect(surface).to_not be_nil @@ -202,9 +207,10 @@ expect(surface.layers.size).to eq(3) u = 1 / cls1.rsi(surface, film[:floor]) expect(u).to be_within(TOL).of(uo2) - expect(surface.layers[1].nameString).to eq("OSut:mineral:K0.024:100") + expect(surface.layers[1].nameString).to eq("OSut:K0.024:100") # Finished, insulated exposed floor (e.g. 4" slab, steel web joists). + model = OpenStudio::Model::Model.new specs = {type: :floor, uo: uo2, finish: :medium} surface = cls1.genConstruction(model, specs) expect(surface).to_not be_nil @@ -212,10 +218,11 @@ expect(surface.layers.size).to eq(3) u = 1 / cls1.rsi(surface, film[:floor]) expect(u).to be_within(TOL).of(uo2) - expect(surface.layers[1].nameString).to eq("OSut:mineral:K0.023:100") + expect(surface.layers[1].nameString).to eq("OSut:K0.023:100") expect(surface.layers[2].nameString).to eq("OSut:concrete:100") # Uninsulated slab-on-grade. + model = OpenStudio::Model::Model.new specs = {type: :slab, frame: :none, finish: :none} surface = cls1::genConstruction(model, specs) expect(surface).to_not be_nil @@ -225,6 +232,7 @@ expect(surface.layers[1].nameString).to eq("OSut:concrete:100") # Insulated slab-on-grade. + model = OpenStudio::Model::Model.new specs = {type: :slab, uo: uo2, finish: :none} surface = cls1::genConstruction(model, specs) expect(surface).to_not be_nil @@ -233,7 +241,7 @@ u = 1 / cls1::rsi(surface, film[:slab]) expect(u).to be_within(TOL).of(uo2) expect(surface.layers[0].nameString).to eq("OSut:sand:100") - expect(surface.layers[1].nameString).to eq("OSut:polyiso:K0.010:043") + expect(surface.layers[1].nameString).to eq("OSut:K0.010:043") expect(surface.layers[2].nameString).to eq("OSut:concrete:100") # 8" uninsulated basement wall. @@ -247,6 +255,7 @@ expect(u).to be_within(TOL).of(uo7) # 8" interior-insulated, finished basement wall. + model = OpenStudio::Model::Model.new specs = {type: :basement, uo: 2 * uo2, clad: :none} surface = cls1::genConstruction(model, specs) expect(surface).to_not be_nil @@ -255,7 +264,7 @@ u = 1 / cls1::rsi(surface, film[:basement]) expect(u).to be_within(TOL).of(2 * uo2) expect(surface.layers[0].nameString).to eq("OSut:concrete:200") - expect(surface.layers[1].nameString).to eq("OSut:mineral:K0.037:075") + expect(surface.layers[1].nameString).to eq("OSut:K0.037:075") expect(surface.layers[2].nameString).to eq("OSut:drywall:015") # Standard, insulated steel door (default Uo = 1.8 W/K•m). @@ -291,7 +300,7 @@ u = 1 / cls1::rsi(surface) expect(u).to be_within(TOL).of(uo9) - # Invalid Uo (here, skylights and windows inherit default Uo values) + # Invalid Uo (here, skylights and windows inherit default Uo values). specs = {type: :skylight, uo: nil} surface = cls1::genConstruction(model, specs) expect(surface).to be_a(OpenStudio::Model::LayeredConstruction) @@ -299,7 +308,7 @@ u = 1 / cls1::rsi(surface) expect(u).to be_within(TOL).of(uo[:skylight]) - # Invalid Uo (here, Uo-adjustments are ignored altogether) + # Invalid Uo (here, Uo-adjustments are ignored altogether). specs = {type: :wall, uo: nil} surface = cls1::genConstruction(model, specs) expect(surface).to be_a(OpenStudio::Model::LayeredConstruction)