Conversation
| a[:compo ][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}" | ||
| when :window | ||
| a[:glazing][:u ] = specs[:uo ] | ||
| a[:glazing][:u ] = u ? u : @@uo[:window] |
There was a problem hiding this comment.
A user could set a glazing assembly's specs["uo"] to nil. This is caught and reset here.
| if u and unglazed | ||
| ro = 1 / u - film | ||
|
|
||
| if ro > 0 |
There was a problem hiding this comment.
For opaque construction, adjusting insulating layer thickness (to meet a requested assembly Uo factor) is skipped entirely if the requested Uo isn't:
- Numeric
- within postulated (acceptable) range
| expect(surface).to be_a(OpenStudio::Model::LayeredConstruction) | ||
| expect(surface.layers.size).to eq(1) | ||
| u = 1 / cls1::rsi(surface) | ||
| expect(u).to be_within(TOL).of(uo[:skylight]) |
There was a problem hiding this comment.
In the case of fenestrated assemblies, an invalid Uo request is ignored and the glazing assembly inherits a default OSut Uo (here 3.5 W/m2.K for a skylight).
| m1 = "#{id}:spandrel" | ||
| m2 = "#{id}:spandrel:boolean" | ||
| return mismatch(id, s, cl, mth) unless s.is_a?(cl) | ||
| return mismatch(id, s, cl, mth, false) unless s.is_a?(cl) |
|
|
||
| id = s.nameString | ||
| return mismatch(id, s, cl, mth, false) unless s.is_a?(cl) | ||
| return mismatch(id, s, cl, mth, DBG, false) unless s.is_a?(cl) |
|
|
||
| values.each do |value| | ||
| if value.respond_to?(:to_f) | ||
| vals << value.to_f |
There was a problem hiding this comment.
Validate time series data for scheduled temperatures: Log + skip if invalid, then move on.
| res[:spt] = max unless res[:spt] | ||
| res[:spt] = max if res[:spt] < max | ||
| end | ||
| end |
There was a problem hiding this comment.
Safe (?) to now check for ScheduleInterval classes.
| # @return [nil] if invalid input (see logs) | ||
| def trueNormal(s = nil, r = 0) | ||
| mth = "TBD::#{__callee__}" | ||
| mth = "OSut::#{__callee__}" |
|
|
||
| # Once joined, re-adjust Z-axis coordinates. | ||
| unless z.zero? | ||
| unless z.round(2) == 0.00 |
There was a problem hiding this comment.
z is a float - not an integer.
| start = model.getYearDescription.makeDate(1, 1) | ||
| inter = OpenStudio::Time.new(0, 1, 0, 0) | ||
| values = OpenStudio.createVector(Array.new(8760, 22.78)) | ||
| series = OpenStudio::TimeSeries.new(start, inter, values, "") |
There was a problem hiding this comment.
OSut enabled ScheduleFixedInterval checks, e.g.:
- min/max setpoint temperatures
- is space UNCONDITIONED, etc.
Yet no unit test had been in place.
lib/osut/utils.rb
Outdated
| return pts if pts.size < 3 | ||
| return mismatch("n collinears", n, Integer, mth, DBG, v) unless ok | ||
| return invalid("+n collinears", mth, 0, ERR, v) if n > pts.size | ||
| return invalid("-n collinears", mth, 0, ERR, v) if n < 0 && n.abs > pts.size |
There was a problem hiding this comment.
Checks range of n number of points - harmonized with pyOSut.
| a2 = flatten(a2).to_a if flat | ||
| cw2 = clockwise?(a2) | ||
| a2 = a2.reverse if cw2 | ||
| return invalid("points 2", mth, 2, DBG, face) unless xyz?(a2, :z) |
There was a problem hiding this comment.
Eliminates redundancies between aligned vs non-aligned cases, harmonized with pyOSut.
| return face if p1.empty? | ||
| return face if p2.empty? | ||
| return mismatch("ray", ray, cl, mth) unless ray.is_a?(cl) | ||
| return mismatch("ray", ray, cl, mth, face) unless ray.is_a?(cl) |
There was a problem hiding this comment.
Fixes (wrong) return value.
| # @param [Set<OpenStudio::Point3d>] a triad (3D points) | ||
| # | ||
| # @return [Set<OpenStudio::Point3D>] a rectangular ULC box (see logs if empty) | ||
| # @return [Set<OpenStudio::Point3D>] a rectangular BLC box (see logs if empty) |
There was a problem hiding this comment.
Fixes (incorrect) vertex sequencing (documentation issue).
| next if same?(p1, sg.last) | ||
| next if same?(p2, sg.first) | ||
| next if same?(p2, sg.first) | ||
| next if same?(p2, sg.last) |
There was a problem hiding this comment.
Fixes redundant check - brings in correct check.
| id = "plate # #{i+1} (index #{i})" | ||
|
|
||
| return mismatch(id, plt, cl1, mth, DBG, slb) unless plt.is_a?(cl2) | ||
| return mismatch(id, plt, cl2, mth, DBG, slb) unless plt.is_a?(cl2) |
There was a problem hiding this comment.
Fixes incorrect class check. No unit test had been written to stress-test this, so never got caught.
| elsif fpm2.keys.include?("strips") | ||
| pattern = "strips" | ||
| else fpm2.keys.include?("strip") | ||
| else # fpm2.keys.include?("strip") |
There was a problem hiding this comment.
Ruby ignores anything following an else, so the hash key check is ignored. Keeping as comment.
| # Original polygon remains unaltered. | ||
| # vtx2 = mod1.poly(vtx) | ||
| # expect(mod1.same?(vtx, vtx2)).to be true | ||
| # expect(mod1.status).to eq(0) |
| slab = mod1.genSlab(plates, z0) | ||
| expect(mod1.debug?).to be true | ||
| expect(mod1.logs.size).to eq(1) | ||
| expect(mod1.logs.first[:message]).to include("String? expecting Hash") |
There was a problem hiding this comment.
New stress-test when requested floor plates (input) aren't hashes.
| return pts | ||
| elsif pts.is_a?(OpenStudio::Model::PlanarSurface) | ||
| pts.vertices.each { |pt| v << OpenStudio::Point3d.new(pt.x, pt.y, pt.z) } | ||
| return v |
There was a problem hiding this comment.
This would otherwise return an Array.
| return v if pts.empty? | ||
| return mismatch("n unique points", n, Integer, mth, DBG, v) unless ok | ||
|
|
||
| if n.is_a?(Numeric) |
There was a problem hiding this comment.
Safer to check for Numeric than respond_to?(:to_i). Non-numeric strings respond_to?(:to_i), for instance.
| a = sg.first | ||
| b = sg.last | ||
| a = sg[ 0] | ||
| b = sg[-1] |
There was a problem hiding this comment.
Safer. An admissible input segment could be an OpenStudio::Point3dVector (which would crash with a call to .last.
| end | ||
|
|
||
| if holds?(a, pts[0]) | ||
| if a.include?(pts[0]) |
| sg0 = sg.to_a | ||
| sgX = sX[j].to_a | ||
| sg0 = sg | ||
| sgX = sX[j] |
There was a problem hiding this comment.
As each returned item from an OpenStudio::Point3dVectorVector is an Array in Ruby (and not an OpenStudio::Point3dVector), there would be no point in further converting an Array to an Array.
|
|
||
| # Stress test 'to_p3Dv'. 4 valid input cases. | ||
| # Valid case #1: a single Point3d. | ||
| vtx = mod1.to_p3Dv(p0) |
There was a problem hiding this comment.
All 4 valid to_p3Dv use cases systematically return an OpenStudio::Point3dVector (and not occasionally an Array).
| # @return [false] if invalid input (see logs) | ||
| def segment?(pts = nil) | ||
| pts = to_p3Dv(pts) | ||
| return false if pts.empty? |
| return empty("segments", mth, DBG, false) if sgs.empty? | ||
| return mismatch("point", p0, cl, mth, DBG, false) unless p0.is_a?(cl1) | ||
| return empty("segments", mth, DBG, false) if sgs.empty? | ||
| return mismatch("point", p0, cl1, mth, DBG, false) unless p0.is_a?(cl1) |
There was a problem hiding this comment.
Oops - no cl variable. Clearly untested.
| str2 = str1 + " #{tag.to_s}" | ||
| next if st.key?(:void) && st[:void] | ||
| return mismatch(str1, st, Hash, mth, DBG, a) unless st.respond_to?(:key?) | ||
| next if st.key?(:void) && st[:void] |
There was a problem hiding this comment.
Hmm. Better to test for a Hash before attempting to access a key:value pair.
| return mismatch(str, ld, Hash, mth, DBG, a) unless ld.is_a?(Hash) | ||
| return hashkey( str, ld, s, mth, DBG, a) unless ld.key?(s) | ||
| return mismatch(str, ld[s], cl, mth, DBG, a) unless ld[s].is_a?(cl) | ||
| return mismatch(str2, ld, Hash, mth, DBG, a) unless ld.is_a?(Hash) |
| # previously-added leader lines. | ||
| # | ||
| # @todo: revise approach for attics ONCE skylight wells have been added. | ||
| olap = nil |
| w = opts[:size].to_f | ||
| w2 = w * w | ||
| return invalid(size, mth, 0, ERR, []) if w.round(2) < gap4 | ||
| return invalid("size", mth, 0, ERR, []) if w.round(2) < gap4 |
There was a problem hiding this comment.
No variable size - clearly a typo.
| spaces = spaces.reject { |sp| sp.floorArea < 4 * w2 } | ||
| spaces = spaces.sort_by(&:floorArea).reverse | ||
| return empty("spaces", mth, WRN, 0) if spaces.empty? | ||
| return empty("spaces", mth, WRN, []) if spaces.empty? |
| frame = nil if f.frameWidth.round(2) < 0 | ||
| frame = nil if f.frameWidth.round(2) > gap | ||
| frame = nil if frame.frameWidth.round(2) < 0 | ||
| frame = nil if frame.frameWidth.round(2) > gap |
| when :sloped then filters.map! { |f| f.include?("c") ? f.delete("c") : f } | ||
| when :plenum then filters.map! { |f| f.include?("d") ? f.delete("d") : f } | ||
| when :attic then filters.map! { |f| f.include?("e") ? f.delete("e") : f } | ||
| when :sidelit then filters.map! { |fl| fl.include?("b") ? fl.delete("b") : fl } |
There was a problem hiding this comment.
f already used (designates frame width): use fl instead.
spec/osut_tests_spec.rb
Outdated
| expect(mod1.same?(collinears[1], p1)).to be true | ||
|
|
||
| # Ignore n request when n.abs > number of actual collinears. | ||
| collinears = mod1.getCollinears([p0, p1, p2, p3, p8], 6) |
There was a problem hiding this comment.
Harmonized tests with pyOSut.
| # | ||
| # @return [OpenStudio::Point3dVector] unique points (see logs) | ||
| def getUniques(pts = nil, n = 0) | ||
| def uniques(pts = nil, n = 0) |
There was a problem hiding this comment.
As per pyOSut convention, getter functions drop the get prefix.
| # function can be time consuming for very convoluted spaces (e.g. long | ||
| # corridors with multiple concavities). | ||
| expect(mod1.spaceHeight(fine)).to be_within(TOL).of(8.53) | ||
| expect(mod1.spaceWidth(fine)).to be_within(TOL).of(21.33) |
There was a problem hiding this comment.
The value returned by spaceHeight (8.53 m) corresponds to the tallest floor-to-ceiling distance (along Z-axis).
The floor section circumscribed (and crisscrossed) with red dotted lines corresponds to the largest bounded box that fits in the (large) L-shaped floor surface. The length of the narrowest edge of this bounded box (21.33 m) is what spaceWidth returns.
| res = realignedFace(polyg.to_a.reverse) | ||
| return 0 if res[:box].nil? | ||
|
|
||
| height(res[:box]) |
There was a problem hiding this comment.
Forgot to add the key piece (bounding box from realignFace).
| expect(mod1.alignedWidth(floor)).to be_within(TOL).of(8.22) | ||
| expect(mod1.spaceHeight(openarea)).to be_within(TOL).of(3.96) | ||
| expect(mod1.spaceWidth(openarea)).to be_within(TOL).of(7.90) | ||
| expect(mod1.spaceWidth(openarea)).to be_within(TOL).of(3.77) |
There was a problem hiding this comment.
- in red: full height of space, including skylight wells
- in green: width of bounding box of space floor(s), outline is very approximate
- in blue: width of largest bounded box that can fit within grouped floor surfaces
The latter is retained here as the most adequate measure of what could be considered a room's width, e.g. for LPD adjustment calculations.
Related to this pyOSut PR.
Around 40-odd typos (and other oddities) were identified in this Ruby implementation of OSut, while developing a Python counterpart, pyOSut. In some cases, these are simple fixes (no impact on the Python implementation). In other cases (like this first commit), they reveal weaknesses (to fix), such as not adequately catching bad user input. Over the next day or so, a number of such fixes are expected to be introduced, before re-releasing an upcoming OSut v0.6.1.