tbd 3.5.2 → 3.6.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05fd880203531a590b7200877de77c8128a19cd1576430fc19b06c2fa6fa5c9a
4
- data.tar.gz: 5359fb5300c59237c5f3c29e7d8dbe4e961ebedeb5e1b8a7b693ea7e7525c8d1
3
+ metadata.gz: 6b9460ab560b9bdac3d2f291a4ca25bb1a84c1e0d54c8cc89ad6d332de741f33
4
+ data.tar.gz: fa685b2b11943a07aa8baae1dcec90be333a5bb0d33f091e2ea80414556ac1e1
5
5
  SHA512:
6
- metadata.gz: 7a16de918bbf66ee2306dab6459db400af37fb5734f7a8e9203dbb934252cb9f27aa084149790a9b8349de67e9d46381f8460b32ef1432d938ec3e06644136f0
7
- data.tar.gz: d40f3b5d24e7450f7695c0d8d68bd5a463efeec002b399a6a181a0b1c936f6608f81c7556365a79e4d7434785b4c9bac1046255700772ffc07667c2baa6a7403
6
+ metadata.gz: fa07d25024543f65b3d57b235ef451a18c8f0ca20d85c803d2aa7fb7df635734f7c84ce4224e0ffa8c38294176a6d6cce0dcbaadc20f4c021632dcf0c758d22a
7
+ data.tar.gz: 5220cf57a68114d592a82a2d3516fcc01cdb9b9281ea0e5665077f25119cbf185b5f2b40b1555aedbb37e2d5a75f4bc41e95a1909d990a3998a2bdd6fab06e7f
@@ -3,8 +3,8 @@
3
3
  <schema_version>3.1</schema_version>
4
4
  <name>tbd_measure</name>
5
5
  <uid>8890787b-8c25-4dc8-8641-b6be1b6c2357</uid>
6
- <version_id>833dbf17-e51f-43c7-9c8b-a79ef0e6bd3b</version_id>
7
- <version_modified>2026-02-03T13:53:54Z</version_modified>
6
+ <version_id>51c8811e-5901-4d36-a106-9bd4e377d0bb</version_id>
7
+ <version_modified>2026-08-27T12:41:28Z</version_modified>
8
8
  <xml_checksum>99772807</xml_checksum>
9
9
  <class_name>TBDMeasure</class_name>
10
10
  <display_name>Thermal Bridging and Derating - TBD</display_name>
@@ -499,7 +499,7 @@
499
499
  <filename>geo.rb</filename>
500
500
  <filetype>rb</filetype>
501
501
  <usage_type>resource</usage_type>
502
- <checksum>9CA80CEB</checksum>
502
+ <checksum>16067F9B</checksum>
503
503
  </file>
504
504
  <file>
505
505
  <filename>geometry.rb</filename>
@@ -523,7 +523,7 @@
523
523
  <filename>psi.rb</filename>
524
524
  <filetype>rb</filetype>
525
525
  <usage_type>resource</usage_type>
526
- <checksum>B9FB5E02</checksum>
526
+ <checksum>7AE7FE72</checksum>
527
527
  </file>
528
528
  <file>
529
529
  <filename>tbd.rb</filename>
@@ -541,13 +541,13 @@
541
541
  <filename>ua.rb</filename>
542
542
  <filetype>rb</filetype>
543
543
  <usage_type>resource</usage_type>
544
- <checksum>D3A2A391</checksum>
544
+ <checksum>666C0F59</checksum>
545
545
  </file>
546
546
  <file>
547
547
  <filename>utils.rb</filename>
548
548
  <filetype>rb</filetype>
549
549
  <usage_type>resource</usage_type>
550
- <checksum>118F3A32</checksum>
550
+ <checksum>61243A64</checksum>
551
551
  </file>
552
552
  <file>
553
553
  <filename>version.rb</filename>
@@ -38,7 +38,6 @@ module TBD
38
38
  a = false
39
39
  return mismatch("e1", e1, Hash, mth, DBG, a) unless e1.is_a?(Hash)
40
40
  return mismatch("e2", e2, Hash, mth, DBG, a) unless e2.is_a?(Hash)
41
- return mismatch("e2", e2, Hash, mth, DBG, a) unless e2.is_a?(Hash)
42
41
 
43
42
  return hashkey("e1", e1, :v0, mth, DBG, a) unless e1.key?(:v0)
44
43
  return hashkey("e1", e1, :v1, mth, DBG, a) unless e1.key?(:v1)
@@ -299,14 +298,16 @@ module TBD
299
298
  return invalid("#{nom} normal", mth, 0, ERR) unless n
300
299
 
301
300
  type = surface.surfaceType.downcase
302
- facing = surface.outsideBoundaryCondition
301
+ facing = surface.outsideBoundaryCondition.downcase
302
+ interz = false
303
303
  setpts = setpoints(space)
304
304
 
305
- if facing.downcase == "surface"
306
- empty = surface.adjacentSurface.empty?
307
- return invalid("#{nom}: adjacent surface", mth, 0, ERR) if empty
305
+ if facing == "surface"
306
+ adj = surface.adjacentSurface
307
+ return invalid("#{nom}: adjacent surface", mth, 0, ERR) if adj.empty?
308
308
 
309
- facing = surface.adjacentSurface.get.nameString
309
+ facing = adj.get.nameString
310
+ interz = true
310
311
  end
311
312
 
312
313
  unless surface.construction.empty?
@@ -315,8 +316,9 @@ module TBD
315
316
  unless lc.empty?
316
317
  lc = lc.get
317
318
  lyr = insulatingLayer(lc)
319
+ idx = lyr[:index]
318
320
 
319
- if lyr[:index].is_a?(Integer) && lyr[:index].between?(0, lc.numLayers - 1)
321
+ if idx.is_a?(Integer) && idx.between?(0, lc.numLayers - 1)
320
322
  surf[:construction] = lc
321
323
  # index: ... of layer/material (to derate) within construction
322
324
  # ltype: either :massless (RSi) or :standard (k + d)
@@ -358,8 +360,14 @@ module TBD
358
360
  surf[:story ] = story.get unless story.empty?
359
361
  surf[:n ] = n
360
362
  surf[:gross ] = surface.grossArea
361
- surf[:filmRSI ] = surface.filmResistance
362
363
  surf[:spandrel ] = spandrel?(surface)
364
+ surf[:filmRSI ] = surface.filmResistance
365
+
366
+ if interz
367
+ typ = :ceiling # interzone roof or ceiling
368
+ typ = :partition if surf[:type] == :wall
369
+ surf[:filmRSI] = TBD.filmResistances(typ, surface.tilt)
370
+ end
363
371
 
364
372
  surface.subSurfaces.sort_by { |s| s.nameString }.each do |s|
365
373
  next if poly(s).empty?
@@ -508,7 +516,7 @@ module TBD
508
516
  end
509
517
 
510
518
  unless u.is_a?(Numeric)
511
- r = rsi(c, surface.filmResistance)
519
+ r = rsi(c, surf[:filmRSI])
512
520
 
513
521
  if r < TOL
514
522
  log(ERR, "Skipping '#{id}': U-factor unavailable (#{mth})")
@@ -635,8 +643,8 @@ module TBD
635
643
 
636
644
  valid1 = s1[:angle].is_a?(Numeric)
637
645
  valid2 = s2[:angle].is_a?(Numeric)
638
- return mismatch("s1 angle", s1[:angle], Numeric, DBG, false) unless valid1
639
- return mismatch("s1 angle", s1[:angle], Numeric, DBG, false) unless valid2
646
+ return mismatch("s1 angle", s1[:angle], Numeric, mth, DBG, false) unless valid1
647
+ return mismatch("s2 angle", s2[:angle], Numeric, mth, DBG, false) unless valid2
640
648
 
641
649
  angle = 0
642
650
  angle = s2[:angle] - s1[:angle] if s2[:angle] > s1[:angle]
@@ -678,8 +686,8 @@ module TBD
678
686
 
679
687
  valid1 = s1[:angle].is_a?(Numeric)
680
688
  valid2 = s2[:angle].is_a?(Numeric)
681
- return mismatch("s1 angle", s1[:angle], Numeric, DBG, false) unless valid1
682
- return mismatch("s1 angle", s1[:angle], Numeric, DBG, false) unless valid2
689
+ return mismatch("s1 angle", s1[:angle], Numeric, mth, DBG, false) unless valid1
690
+ return mismatch("s2 angle", s2[:angle], Numeric, mth, DBG, false) unless valid2
683
691
 
684
692
  angle = 0
685
693
  angle = s2[:angle] - s1[:angle] if s2[:angle] > s1[:angle]
@@ -752,8 +760,8 @@ module TBD
752
760
  # boundary conditions.
753
761
  #
754
762
  # @param model [OpenStudio::Model::Model] a model
755
- # @param floors [Hash] TBD floors
756
763
  # @param walls [Hash] TBD walls
764
+ # @param floors [Hash] TBD floors
757
765
  # @param edges [Hash] TBD edges (many linking floors & walls
758
766
  #
759
767
  # @return [Bool] true if Kiva foundations are successfully generated
@@ -831,7 +839,7 @@ module TBD
831
839
  edge[:surfaces].keys.each do |id|
832
840
  next unless floors.key?(id)
833
841
 
834
- next unless floors[id][:boundary].downcase == "foundation"
842
+ next unless floors[id][:boundary] == "foundation"
835
843
  next if floors[id].key?(:kiva)
836
844
 
837
845
  # Initially set as slab-on-grade. Track 'exposed foundation perimeter'.
@@ -845,7 +853,7 @@ module TBD
845
853
  edge[:surfaces].keys.each do |i|
846
854
  next if i == id
847
855
  next unless walls.key?(i)
848
- next unless walls[i][:boundary].downcase == "foundation"
856
+ next unless walls[i][:boundary] == "foundation"
849
857
  next if walls[i].key?(:kiva)
850
858
 
851
859
  floors[id][:kiva ] = :basement
@@ -857,7 +865,7 @@ module TBD
857
865
  edge[:surfaces].keys.each do |i|
858
866
  next if i == id
859
867
  next unless walls.key?(i)
860
- next unless walls[i][:boundary].downcase == "outdoors"
868
+ next unless walls[i][:boundary] == "outdoors"
861
869
 
862
870
  floors[id][:exposed] += edge[:length]
863
871
  end
@@ -872,7 +880,7 @@ module TBD
872
880
  e[:surfaces].keys.each do |ii|
873
881
  next if i == ii
874
882
  next unless walls.key?(ii)
875
- next unless walls[ii][:boundary].downcase == "foundation"
883
+ next unless walls[ii][:boundary] == "foundation"
876
884
  next if walls[ii].key?(:kiva)
877
885
 
878
886
  floors[id][:kiva ] = :basement
@@ -883,7 +891,7 @@ module TBD
883
891
  e[:surfaces].keys.each do |ii|
884
892
  next if i == ii
885
893
  next unless walls.key?(ii)
886
- next unless walls[ii][:boundary].downcase == "outdoors"
894
+ next unless walls[ii][:boundary] == "outdoors"
887
895
 
888
896
  floors[id][:exposed] += e[:length]
889
897
  end
@@ -542,7 +542,7 @@ module TBD
542
542
  h[:partyconcave ] = @set[id].key?(:partyconcave)
543
543
  h[:partyconvex ] = @set[id].key?(:partyconvex)
544
544
  h[:parapet ] = @set[id].key?(:parapet)
545
- h[:partyconcave ] = @set[id].key?(:parapetconcave)
545
+ h[:parapetconcave ] = @set[id].key?(:parapetconcave)
546
546
  h[:parapetconvex ] = @set[id].key?(:parapetconvex)
547
547
  h[:roof ] = @set[id].key?(:roof)
548
548
  h[:roofconcave ] = @set[id].key?(:roofconcave)
@@ -557,10 +557,10 @@ module TBD
557
557
  h[:balconyconcave ] = @set[id].key?(:balconyconcave)
558
558
  h[:balconyconvex ] = @set[id].key?(:balconyconvex)
559
559
  h[:balconysill ] = @set[id].key?(:balconysill)
560
- h[:balconysillconcave ] = @set[id].key?(:balconysillconvex)
560
+ h[:balconysillconcave ] = @set[id].key?(:balconysillconcave)
561
561
  h[:balconysillconvex ] = @set[id].key?(:balconysillconvex)
562
562
  h[:balconydoorsill ] = @set[id].key?(:balconydoorsill)
563
- h[:balconydoorsillconcave] = @set[id].key?(:balconydoorsillconvex)
563
+ h[:balconydoorsillconcave] = @set[id].key?(:balconydoorsillconcave)
564
564
  h[:balconydoorsillconvex ] = @set[id].key?(:balconydoorsillconvex)
565
565
  h[:rimjoist ] = @set[id].key?(:rimjoist)
566
566
  h[:rimjoistconcave ] = @set[id].key?(:rimjoistconcave)
@@ -572,10 +572,10 @@ module TBD
572
572
  v[:head ] = 0; v[:headconcave ] = 0; v[:headconvex ] = 0
573
573
  v[:sill ] = 0; v[:sillconcave ] = 0; v[:sillconvex ] = 0
574
574
  v[:jamb ] = 0; v[:jambconcave ] = 0; v[:jambconvex ] = 0
575
- v[:doorhead ] = 0; v[:doorheadconcave ] = 0; v[:doorconvex ] = 0
575
+ v[:doorhead ] = 0; v[:doorheadconcave ] = 0; v[:doorheadconvex ] = 0
576
576
  v[:doorsill ] = 0; v[:doorsillconcave ] = 0; v[:doorsillconvex ] = 0
577
577
  v[:doorjamb ] = 0; v[:doorjambconcave ] = 0; v[:doorjambconvex ] = 0
578
- v[:skylighthead ] = 0; v[:skylightheadconcave ] = 0; v[:skylightconvex ] = 0
578
+ v[:skylighthead ] = 0; v[:skylightheadconcave ] = 0; v[:skylightheadconvex ] = 0
579
579
  v[:skylightsill ] = 0; v[:skylightsillconcave ] = 0; v[:skylightsillconvex ] = 0
580
580
  v[:skylightjamb ] = 0; v[:skylightjambconcave ] = 0; v[:skylightjambconvex ] = 0
581
581
  v[:spandrel ] = 0; v[:spandrelconcave ] = 0; v[:spandrelconvex ] = 0
@@ -712,7 +712,7 @@ module TBD
712
712
  v[:roofconcave ] = @set[id][:parapet ] if h[:parapet ]
713
713
  v[:roofconvex ] = @set[id][:parapet ] if h[:parapet ]
714
714
  v[:roofconcave ] = @set[id][:parapetconcave ] if h[:parapetconcave ]
715
- v[:roofconvex ] = @set[id][:parapetxonvex ] if h[:parapetconvex ]
715
+ v[:roofconvex ] = @set[id][:parapetconvex ] if h[:parapetconvex ]
716
716
  v[:roof ] = @set[id][:roof ] if h[:roof ]
717
717
  v[:roofconcave ] = @set[id][:roof ] if h[:roof ]
718
718
  v[:roofconvex ] = @set[id][:roof ] if h[:roof ]
@@ -758,12 +758,12 @@ module TBD
758
758
  v[:balconysillconcave ] = @set[id][:balcony ] if h[:balcony ]
759
759
  v[:balconysillconvex ] = @set[id][:balcony ] if h[:balcony ]
760
760
  v[:balconysillconcave ] = @set[id][:balconyconcave ] if h[:balconyconcave ]
761
- v[:balconysillconvex ] = @set[id][:balconyconvex ] if h[:balconycinvex ]
761
+ v[:balconysillconvex ] = @set[id][:balconyconvex ] if h[:balconyconvex ]
762
762
  v[:balconydoorsill ] = @set[id][:balcony ] if h[:balcony ]
763
763
  v[:balconydoorsillconcave] = @set[id][:balcony ] if h[:balcony ]
764
764
  v[:balconydoorsillconvex ] = @set[id][:balcony ] if h[:balcony ]
765
765
  v[:balconydoorsillconcave] = @set[id][:balconyconcave ] if h[:balconyconcave ]
766
- v[:balconydoorsillconvex ] = @set[id][:balconyconvex ] if h[:balconycinvex ]
766
+ v[:balconydoorsillconvex ] = @set[id][:balconyconvex ] if h[:balconyconvex ]
767
767
  v[:balconysill ] = @set[id][:balconysill ] if h[:balconysill ]
768
768
  v[:balconysillconcave ] = @set[id][:balconysill ] if h[:balconysill ]
769
769
  v[:balconysillconvex ] = @set[id][:balconysill ] if h[:balconysill ]
@@ -786,10 +786,10 @@ module TBD
786
786
  v[:rimjoistconvex ] = @set[id][:rimjoistconvex ] if h[:rimjoistconvex ]
787
787
 
788
788
  max = [v[:parapetconcave], v[:parapetconvex]].max
789
- v[:parapet] = max unless @has[:parapet]
789
+ v[:parapet] = max unless h[:parapet]
790
790
 
791
791
  max = [v[:roofconcave], v[:roofconvex]].max
792
- v[:roof] = max unless @has[:roof]
792
+ v[:roof] = max unless h[:roof]
793
793
 
794
794
  @val[id] = v
795
795
 
@@ -982,7 +982,7 @@ module TBD
982
982
  mth = "TBD::#{__callee__}"
983
983
  sh = { has: {}, val: {} }
984
984
  id = trim(id)
985
- return mismatch("set ID", id, String, mth, ERR, a) if id.empty?
985
+ return mismatch("set ID", id, String, mth, ERR, sh) if id.empty?
986
986
  return hashkey(id, @set , id, mth, ERR, sh) unless @set.key?(id)
987
987
  return hashkey(id, @has , id, mth, ERR, sh) unless @has.key?(id)
988
988
  return hashkey(id, @val , id, mth, ERR, sh) unless @val.key?(id)
@@ -1424,8 +1424,10 @@ module TBD
1424
1424
  m = m.clone(model).to_MasslessOpaqueMaterial.get
1425
1425
  m.setName("#{id} #{up}m tbd")
1426
1426
 
1427
- de_r = RMIN unless de_r > RMIN
1428
- loss = (de_u - 1 / de_r) * net unless de_r > RMIN
1427
+ if de_r < RMIN
1428
+ de_r = RMIN
1429
+ loss = (de_u - 1 / de_r) * net
1430
+ end
1429
1431
 
1430
1432
  unless m.setThermalResistance(de_r)
1431
1433
  return invalid("Can't derate #{id}: RSi#{de_r.round(2)}", mth)
@@ -1555,7 +1557,7 @@ module TBD
1555
1557
  next unless surface[:conditioned]
1556
1558
  next if surface[:ground ]
1557
1559
 
1558
- unless surface[:boundary].downcase == "outdoors"
1560
+ unless surface[:boundary] == "outdoors"
1559
1561
  next unless tbd[:surfaces].key?(surface[:boundary])
1560
1562
  next if tbd[:surfaces][surface[:boundary]][:conditioned]
1561
1563
  end
@@ -1734,9 +1736,9 @@ module TBD
1734
1736
  next unless point_V_mag > TOL
1735
1737
  next unless point_V_mag > farthest_mag
1736
1738
 
1737
- farthest = point
1738
- farthest_V = origin_point_V
1739
- fathest_mag = point_V_mag
1739
+ farthest = point
1740
+ farthest_V = origin_point_V
1741
+ farthest_mag = point_V_mag
1740
1742
  end
1741
1743
 
1742
1744
  angle = reference_V.angle(farthest_V)
@@ -2202,7 +2204,7 @@ module TBD
2202
2204
  next if holes.key?(i)
2203
2205
  next if shades.key?(i)
2204
2206
 
2205
- facing = tbd[:surfaces][i][:boundary].downcase
2207
+ facing = tbd[:surfaces][i][:boundary]
2206
2208
  next unless facing == "othersidecoefficients"
2207
2209
 
2208
2210
  s1 = edge[:surfaces][id]
@@ -2971,6 +2973,7 @@ module TBD
2971
2973
  # derate a construction/material pair having " tbd" in their OpenStudio name.
2972
2974
  tbd[:surfaces].each do |id, surface|
2973
2975
  next unless surface.key?(:construction)
2976
+ next unless surface.key?(:filmRSI)
2974
2977
  next unless surface.key?(:index)
2975
2978
  next unless surface.key?(:ltype)
2976
2979
  next unless surface.key?(:r)
@@ -2981,8 +2984,7 @@ module TBD
2981
2984
  s = model.getSurfaceByName(id)
2982
2985
  next if s.empty?
2983
2986
 
2984
- s = s.get
2985
-
2987
+ s = s.get
2986
2988
  index = surface[:index ]
2987
2989
  current_c = surface[:construction]
2988
2990
  c = current_c.clone(model).to_LayeredConstruction.get
@@ -2995,7 +2997,7 @@ module TBD
2995
2997
  if m
2996
2998
  c.setLayer(index, m)
2997
2999
  c.setName("#{id} c tbd")
2998
- current_R = rsi(current_c, s.filmResistance)
3000
+ current_R = rsi(current_c, surface[:filmRSI])
2999
3001
 
3000
3002
  # In principle, the derated "ratio" could be calculated simply by
3001
3003
  # accessing a surface's uFactor. Yet air layers within constructions
@@ -3035,7 +3037,7 @@ module TBD
3035
3037
 
3036
3038
  # Compute updated RSi value from layers.
3037
3039
  updated_c = s.construction.get.to_LayeredConstruction.get
3038
- updated_R = rsi(updated_c, s.filmResistance)
3040
+ updated_R = rsi(updated_c, surface[:filmRSI])
3039
3041
  ratio = -(current_R - updated_R) * 100 / current_R
3040
3042
 
3041
3043
  surface[:ratio] = ratio if ratio.abs > TOL
@@ -3047,14 +3049,10 @@ module TBD
3047
3049
  tbd[:surfaces].each do |id, surface|
3048
3050
  next unless surface[:deratable]
3049
3051
  next unless surface.key?(:construction)
3052
+ next unless surface.key?(:filmRSI)
3050
3053
  next if surface.key?(:u)
3051
3054
 
3052
- s = model.getSurfaceByName(id)
3053
- msg = "Skipping missing surface '#{id}' (#{mth})"
3054
- log(ERR, msg) if s.empty?
3055
- next if s.empty?
3056
-
3057
- surface[:u] = 1.0 / rsi(surface[:construction], s.get.filmResistance)
3055
+ surface[:u] = 1.0 / rsi(surface[:construction], surface[:filmRSI])
3058
3056
  end
3059
3057
 
3060
3058
  json[:io][:edges] = []
@@ -3204,8 +3202,8 @@ module TBD
3204
3202
 
3205
3203
  uo = format("%.3f", g[:uo])
3206
3204
  ut = format("%.3f", g[:ut])
3207
- output = "An initial #{label.to_s} Uo of #{uo} W/m2•K is required to " \
3208
- "achieve an overall Ut of #{ut} W/m2•K for #{g[:op]}"
3205
+ output = "An area-weighted #{label.to_s} Uo of #{uo} W/m2•K is " \
3206
+ "required to meet an overall Ut of #{ut} W/m2•K for #{g[:op]}"
3209
3207
  u_t << output
3210
3208
  runner.registerInfo(output)
3211
3209
  end