openstudio-standards 0.8.5 → 0.8.7

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.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/data/standards/test_performance_expected_dd_results.csv +90 -90
  3. data/lib/openstudio-standards/btap/activity.rb +858 -61
  4. data/lib/openstudio-standards/btap/attributes.rb +297 -103
  5. data/lib/openstudio-standards/btap/bridging.rb +1335 -593
  6. data/lib/openstudio-standards/btap/btap.rb +60 -181
  7. data/lib/openstudio-standards/btap/carbon/btap_carbon.rb +199 -142
  8. data/lib/openstudio-standards/btap/common/constructions.json +1275 -0
  9. data/lib/openstudio-standards/btap/common/costs.csv +1969 -0
  10. data/lib/openstudio-standards/btap/common/costs_local_factors.csv +2315 -0
  11. data/lib/openstudio-standards/btap/common/materials_glazing.csv +61 -0
  12. data/lib/openstudio-standards/btap/{common_resources → common}/materials_hvac.csv +1685 -1685
  13. data/lib/openstudio-standards/btap/{common_resources → common}/materials_lighting.csv +266 -266
  14. data/lib/openstudio-standards/btap/common/materials_opaque.csv +214 -0
  15. data/lib/openstudio-standards/btap/common/necb_building_types.csv +35 -0
  16. data/lib/openstudio-standards/btap/common/necb_space_types.csv +110 -0
  17. data/lib/openstudio-standards/btap/common/thermal_bridging.csv +73 -0
  18. data/lib/openstudio-standards/btap/costing/btap_costing.rb +346 -429
  19. data/lib/openstudio-standards/btap/costing/database.rb +104 -0
  20. data/lib/openstudio-standards/btap/costing/daylighting_sensor_control_costing.rb +356 -344
  21. data/lib/openstudio-standards/btap/costing/dcv_costing.rb +282 -296
  22. data/lib/openstudio-standards/btap/costing/envelope_costing.rb +179 -192
  23. data/lib/openstudio-standards/btap/costing/heating_cooling_costing.rb +2477 -2316
  24. data/lib/openstudio-standards/btap/costing/led_lighting_costing.rb +127 -142
  25. data/lib/openstudio-standards/btap/costing/lighting_costing.rb +216 -198
  26. data/lib/openstudio-standards/btap/costing/nv_costing.rb +522 -523
  27. data/lib/openstudio-standards/btap/costing/pv_ground_costing.rb +649 -649
  28. data/lib/openstudio-standards/btap/costing/shw_costing.rb +626 -625
  29. data/lib/openstudio-standards/btap/costing/thermal_bridging_costing.rb +72 -0
  30. data/lib/openstudio-standards/btap/costing/ventilation_costing.rb +2363 -2361
  31. data/lib/openstudio-standards/btap/deprecated.rb +1033 -0
  32. data/lib/openstudio-standards/btap/envelope.rb +313 -572
  33. data/lib/openstudio-standards/btap/fileio.rb +152 -1070
  34. data/lib/openstudio-standards/btap/geometry.rb +486 -766
  35. data/lib/openstudio-standards/btap/linear_regression.rb +130 -0
  36. data/lib/openstudio-standards/btap/paths.rb +46 -0
  37. data/lib/openstudio-standards/btap/qaqc/analysis.rb +163 -0
  38. data/lib/openstudio-standards/btap/qaqc/data.rb +2293 -0
  39. data/lib/openstudio-standards/btap/qaqc/datapoint.rb +641 -0
  40. data/lib/openstudio-standards/btap/schedules.rb +11 -611
  41. data/lib/openstudio-standards/btap/structure.rb +574 -189
  42. data/lib/openstudio-standards/constructions/materials/information.rb +1 -1
  43. data/lib/openstudio-standards/create_typical/create_typical.rb +1 -1
  44. data/lib/openstudio-standards/exterior_lighting/create.rb +135 -85
  45. data/lib/openstudio-standards/exterior_lighting/data/typical_exterior_lighting.json +20 -0
  46. data/lib/openstudio-standards/exterior_lighting/information.rb +23 -2
  47. data/lib/openstudio-standards/geometry/create.rb +7 -3
  48. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Model.rb +3 -2
  49. data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Model.rb +3 -2
  50. data/lib/openstudio-standards/prototypes/common/data/thermostat_schedule_lookup.json +84 -84
  51. data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +4 -4
  52. data/lib/openstudio-standards/refrigeration/create_walkin.rb +45 -5
  53. data/lib/openstudio-standards/refrigeration/data/refrigerated_walkins.csv +75 -75
  54. data/lib/openstudio-standards/schedules/parametric.rb +6 -0
  55. data/lib/openstudio-standards/service_water_heating/create_typical.rb +10 -3
  56. data/lib/openstudio-standards/service_water_heating/create_water_heating_loop.rb +30 -14
  57. data/lib/openstudio-standards/service_water_heating/information.rb +4 -1
  58. data/lib/openstudio-standards/sql_file/unmet_hours.rb +2 -1
  59. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +3 -1
  60. data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +3 -1
  61. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.boilers.json +12 -0
  62. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.construction_properties.json +18432 -3072
  63. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.boilers.json +26 -0
  64. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.construction_properties.json +8532 -1422
  65. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.boilers.json +26 -0
  66. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.construction_properties.json +8532 -1422
  67. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.boilers.json +16 -0
  68. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.computer_room_acs.json +30 -30
  69. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.construction_properties.json +7560 -1260
  70. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.PumpVariableSpeed.rb +1 -2
  71. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.boilers.json +16 -0
  72. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.construction_properties.json +7560 -1260
  73. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirLoopHVAC.rb +3 -3
  74. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.PumpVariableSpeed.rb +1 -2
  75. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.boilers.json +22 -0
  76. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.construction_properties.json +7236 -1206
  77. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.furnaces.json +223 -19
  78. data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.schedules.json +37 -1
  79. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.boilers.json +3 -0
  80. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.construction_properties.json +6900 -1150
  81. data/lib/openstudio-standards/standards/cbes/data/cbes.schedules.json +1 -1
  82. data/lib/openstudio-standards/standards/deer/data/deer.schedules.json +1 -1
  83. data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/data/surface_thermal_transmittance.json +76 -40
  84. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/surface_thermal_transmittance.json +76 -40
  85. data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +6 -4
  86. data/lib/openstudio-standards/standards/necb/NECB2011/NECB2011_QAQC.json +2988 -0
  87. data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +25 -3
  88. data/lib/openstudio-standards/standards/necb/NECB2011/building_envelope.rb +672 -534
  89. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/Hospital.osm +1791 -1792
  90. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPMultiTower.osm +7 -1
  91. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPTownHouse.osm +7 -1
  92. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LargeHotel.osm +5 -6
  93. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LargeOffice.osm +8 -9
  94. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernEducation.osm +10 -4
  95. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernHealthCare.osm +14 -15
  96. data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/Outpatient.osm +7 -1
  97. data/lib/openstudio-standards/standards/necb/NECB2011/data/surface_thermal_transmittance.json +76 -40
  98. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +14 -6
  99. data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +542 -130
  100. data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +30 -63
  101. data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +7 -2
  102. data/lib/openstudio-standards/standards/necb/NECB2015/data/surface_thermal_transmittance.json +90 -0
  103. data/lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb +8 -6
  104. data/lib/openstudio-standards/standards/necb/NECB2017/data/surface_thermal_transmittance.json +76 -40
  105. data/lib/openstudio-standards/standards/necb/NECB2017/necb_2017.rb +2 -1
  106. data/lib/openstudio-standards/standards/necb/NECB2020/building_envelope.rb +0 -117
  107. data/lib/openstudio-standards/standards/necb/NECB2020/data/surface_thermal_transmittance.json +76 -45
  108. data/lib/openstudio-standards/standards/necb/NECB2020/necb_2020.rb +218 -0
  109. data/lib/openstudio-standards/standards/necb/common/construction_defaults.osm +12 -7
  110. data/lib/openstudio-standards/standards/standard.rb +1 -1
  111. data/lib/openstudio-standards/version.rb +1 -1
  112. data/lib/openstudio-standards.rb +9 -4
  113. metadata +59 -66
  114. data/data/inventory/thermal_bridging.csv +0 -90
  115. data/data/standards/OpenStudio_Standards-ashrae_90_1-ALL-comstock(space_types).xlsx +0 -0
  116. data/data/standards/openstudio_standards_duplicates_log.csv +0 -7962
  117. data/lib/openstudio-standards/btap/NECB_building_types.csv +0 -35
  118. data/lib/openstudio-standards/btap/NECB_space_types.csv +0 -109
  119. data/lib/openstudio-standards/btap/WeatherData1.json +0 -2110
  120. data/lib/openstudio-standards/btap/WeatherData1.xlsx +0 -0
  121. data/lib/openstudio-standards/btap/btap_result.rb +0 -1144
  122. data/lib/openstudio-standards/btap/btap_test_helper.rb +0 -86
  123. data/lib/openstudio-standards/btap/common_paths.rb +0 -81
  124. data/lib/openstudio-standards/btap/common_resources/ConstructionProperties.csv +0 -52
  125. data/lib/openstudio-standards/btap/common_resources/Constructions.csv +0 -37
  126. data/lib/openstudio-standards/btap/common_resources/construction_sets.csv +0 -1270
  127. data/lib/openstudio-standards/btap/common_resources/constructions_glazing.csv +0 -121
  128. data/lib/openstudio-standards/btap/common_resources/constructions_opaque.csv +0 -2256
  129. data/lib/openstudio-standards/btap/common_resources/costs.csv +0 -1897
  130. data/lib/openstudio-standards/btap/common_resources/costs_local_factors.csv +0 -2315
  131. data/lib/openstudio-standards/btap/common_resources/materials_glazing.csv +0 -35
  132. data/lib/openstudio-standards/btap/common_resources/materials_opaque.csv +0 -164
  133. data/lib/openstudio-standards/btap/costing/btap_measure_helper.rb +0 -359
  134. data/lib/openstudio-standards/btap/costing/btap_workflow.rb +0 -117
  135. data/lib/openstudio-standards/btap/costing/copy_test_results_files_to_expected_results.rb +0 -11
  136. data/lib/openstudio-standards/btap/costing/cost_building_from_file.rb +0 -136
  137. data/lib/openstudio-standards/btap/costing/costing_database_wrapper.rb +0 -173
  138. data/lib/openstudio-standards/btap/costing/dummy.epw +0 -8768
  139. data/lib/openstudio-standards/btap/costing/dummy.osm +0 -5320
  140. data/lib/openstudio-standards/btap/costing/neb_end_use_prices.csv +0 -42
  141. data/lib/openstudio-standards/btap/costing/necb_2011_spacetype_info.csv +0 -225
  142. data/lib/openstudio-standards/btap/costing/necb_reference_runs.csv +0 -28705
  143. data/lib/openstudio-standards/btap/costing/parallel_tests.rb +0 -92
  144. data/lib/openstudio-standards/btap/costing/test_list.txt +0 -15
  145. data/lib/openstudio-standards/btap/costing/test_run_all_test_locally.rb +0 -27
  146. data/lib/openstudio-standards/btap/costing/test_run_costing_tests.rb +0 -80
  147. data/lib/openstudio-standards/btap/necb_2011_spacetype_info.csv +0 -225
  148. data/lib/openstudio-standards/btap/utilities/Add_template_field_to_json.rb +0 -22
  149. data/lib/openstudio-standards/btap/utilities/convert_surfaces_to_adiabatic_necb_8426.rb +0 -204
  150. data/lib/openstudio-standards/btap/utilities/generate_space_types.rb +0 -8
  151. data/lib/openstudio-standards/btap/utilities/necb_to_epw_map.rb +0 -50
  152. data/lib/openstudio-standards/btap/utilities/os_sim_extract.rb +0 -48
  153. data/lib/openstudio-standards/btap/utilities/rename_surfaces.rb +0 -24
  154. data/lib/openstudio-standards/btap/utilities/round_surf_coords.rb +0 -32
  155. data/lib/openstudio-standards/btap/utilities/sched_create.rb +0 -145
  156. data/lib/openstudio-standards/btap/utilities/set_mult_to_adiabatic.rb +0 -53
  157. data/lib/openstudio-standards/btap/utilities/space_type.rb +0 -78
  158. data/lib/openstudio-standards/btap/utilities/weatherData1_xlsx_to_json.rb +0 -56
  159. data/lib/openstudio-standards/btap/vintagizer.rb +0 -161
  160. data/lib/openstudio-standards/btap/visualization.rb +0 -72
  161. data/lib/openstudio-standards/standards/necb/NECB2011/data/necb_2011_spacetype_info.csv +0 -225
  162. data/lib/openstudio-standards/standards/necb/common/btap_analysis.rb +0 -79
  163. data/lib/openstudio-standards/standards/necb/common/btap_data.rb +0 -2656
  164. data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +0 -653
  165. data/lib/openstudio-standards/standards/necb/common/necb_reference_runs.csv +0 -28705
  166. data/lib/openstudio-standards/standards/necb/common/utility_pricing_2025-02-20.csv +0 -92
  167. /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_frame.csv +0 -0
  168. /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_glazing.csv +0 -0
  169. /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_opaque.csv +0 -0
  170. /data/lib/openstudio-standards/btap/{common_resources → common}/hvac_vent_ahu.csv +0 -0
  171. /data/lib/openstudio-standards/btap/{common_resources → common}/lighting.csv +0 -0
  172. /data/lib/openstudio-standards/btap/{common_resources → common}/lighting_sets.csv +0 -0
  173. /data/lib/openstudio-standards/btap/{common_resources → common}/locations.csv +0 -0
  174. /data/lib/openstudio-standards/btap/{costing → common}/mech_sizing.json +0 -0
@@ -294,333 +294,201 @@ class NECB2011
294
294
 
295
295
  ##
296
296
  # Returns NECB-required U-factor, based on surface type, outside boundary
297
- # condition, heating-degree-days (18C) and NECB edition (template). The bulk
298
- # of this should be a CSV file.
297
+ # condition and heating-degree-days (18C).
299
298
  #
300
- # @author denis@rd2.ca
299
+ # @author nicholas.pneumaticos@nrcan-rncan.gc.ca
301
300
  #
302
301
  # @param stype [#to_s] surface type, e.g. "roofceiling"
303
- # @param condition [#to_s] outside boundary condition, e.g. "outdoors"
302
+ # @param bc [#to_s] outside boundary condition, e.g. "outdoors"
304
303
  # @param hdd [#to_f] heating-degree-days 18C
305
304
  #
306
305
  # @return [Float] required U-factor, defaults to 0.110 W/m2.K.
307
306
  def max_u_necb(stype = "roofceiling", condition = "outdoors", hdd = 8000)
308
- hdd = hdd.respond_to?(:to_f) ? hdd.to_f : 8000
309
-
310
- # Admissible surface types.
311
- stypes = ["wall", "roofceiling", "floor", "window", "skylight", "door"]
312
- stype = stype.respond_to?(:to_s) ? stype.to_s.downcase : "roofceiling"
313
- stype = stypes.include?(stype) ? stype : "roofceiling"
314
307
 
315
- # Admissible outside boundary conditions.
316
- conditions = ["outdoors", "ground"]
317
- condition = condition.respond_to?(:to_s) ? condition.to_s.downcase : "outdoors"
318
- condition = conditions.include?(condition) ? condition : "outdoors"
308
+ # Return required U-factor if provided HDD < stored HDD.
309
+ @standards_data["surface_thermal_transmittance"][condition][stype].transform_keys(&:to_i).each { |hdd18, u|
310
+ return u if hdd < hdd18 }
311
+ return 0.110
312
+ end
319
313
 
320
- templates = ["NECB2011", "NECB2015", "NECB2017", "NECB2020"]
314
+ ##
315
+ # Returns a layered construction's area-weighted surface air film resistances.
316
+ # Based on surface's 'netArea' (i.e. no validation wrt Frame & Dividers).
317
+ #
318
+ # @author denis@rd2.ca
319
+ #
320
+ # @param [OpenStudio::Model::LayeredConstruction] a construction
321
+ #
322
+ # @return [Float] area-weighted surface air film resistances (0 if error)
323
+ def filmR(construction = nil)
324
+ return 0 unless construction.is_a?(OpenStudio::Model::LayeredConstruction)
325
+
326
+ # Tally:
327
+ # - areas of each surface referencing the construction
328
+ # - inverse of each surface air film resistances (similar to UA)
329
+ area = 0
330
+ filmA = 0
331
+
332
+ construction.model.getSurfaces.each do |surface|
333
+ tp = surface.surfaceType.downcase
334
+ bc = surface.outsideBoundaryCondition.downcase
335
+ fR = surface.filmResistance
336
+ m2 = surface.netArea
337
+ lc = surface.construction
338
+ next if lc.empty?
339
+
340
+ lc = lc.get.to_LayeredConstruction
341
+ next if lc.empty?
342
+
343
+ lc = lc.get
344
+ next unless lc == construction
345
+ next unless lc.getNetArea.round > 0
346
+
347
+ # Reset surface air film resistance if interzone.
348
+ if bc == "surface"
349
+ typ = tp == "wall" ? :partition : :ceiling
350
+ fR = TBD.filmResistances(typ, surface.tilt)
351
+ end
321
352
 
322
- data = {}
353
+ area += m2
354
+ filmA += m2 / fR
355
+ end
323
356
 
324
- # Initialize data.
325
- templates.each do |tp|
326
- data[tp] = {}
357
+ filmA > 0 ? area / filmA : 0
358
+ end
327
359
 
328
- conditions.each do |cd|
329
- data[tp][cd] = {}
360
+ ##
361
+ # Hard-sets basement floor constructions. Ground-facing floors in full-height
362
+ # basement spaces are outside the scope of the NECBs. A hard set avoids
363
+ # inheritance conflicts with BTAP default construction sets.
364
+ #
365
+ # @author denis@rd2.ca
366
+ #
367
+ # @param model [OpenStudio::Model::Model] a model
368
+ #
369
+ # @return [Array] collection of (uninsulated) basement floors
370
+ def set_basement_floor_construction(model = nil)
371
+ lc = nil
372
+ flrs = []
373
+ return flrs unless model.is_a?(OpenStudio::Model::Model)
330
374
 
331
- stypes.each { |st| data[tp][cd][st] = {} }
375
+ model.getSpaces.each do |space|
376
+ floors = TBD.facets(space, "all", "floor")
377
+ floors = floors.select { |floor| floor.isGroundSurface }
378
+ next if floors.empty?
379
+
380
+ walls = TBD.facets(space, "all", "wall")
381
+ next unless walls.any? { |wall| wall.isGroundSurface }
382
+
383
+ if lc.nil?
384
+ specs = {}
385
+ specs[:type ] = :slab
386
+ specs[:frame] = :none
387
+ specs[:uo ] = nil
388
+ lc = TBD.genConstruction(model, specs)
332
389
  end
333
- end
334
390
 
335
- # From NECB Part 3 tables. Moving away from BTAP formulas. Should be CSV.
336
- data["NECB2011"]["outdoors"]["wall" ][3000] = 0.315
337
- data["NECB2011"]["outdoors"]["wall" ][4000] = 0.278
338
- data["NECB2011"]["outdoors"]["wall" ][5000] = 0.247
339
- data["NECB2011"]["outdoors"]["wall" ][6000] = 0.210
340
- data["NECB2011"]["outdoors"]["wall" ][7000] = 0.210
341
- data["NECB2011"]["outdoors"]["wall" ][9999] = 0.183
342
- data["NECB2011"]["outdoors"]["roofceiling"][3000] = 0.227
343
- data["NECB2011"]["outdoors"]["roofceiling"][4000] = 0.183
344
- data["NECB2011"]["outdoors"]["roofceiling"][5000] = 0.183
345
- data["NECB2011"]["outdoors"]["roofceiling"][6000] = 0.162
346
- data["NECB2011"]["outdoors"]["roofceiling"][7000] = 0.162
347
- data["NECB2011"]["outdoors"]["roofceiling"][9999] = 0.142
348
- data["NECB2011"]["outdoors"]["floor" ][3000] = 0.227
349
- data["NECB2011"]["outdoors"]["floor" ][4000] = 0.183
350
- data["NECB2011"]["outdoors"]["floor" ][5000] = 0.183
351
- data["NECB2011"]["outdoors"]["floor" ][6000] = 0.162
352
- data["NECB2011"]["outdoors"]["floor" ][7000] = 0.162
353
- data["NECB2011"]["outdoors"]["floor" ][9999] = 0.142
354
- data["NECB2011"]["outdoors"]["window" ][3000] = 2.400
355
- data["NECB2011"]["outdoors"]["window" ][4000] = 2.200
356
- data["NECB2011"]["outdoors"]["window" ][5000] = 2.200
357
- data["NECB2011"]["outdoors"]["window" ][6000] = 2.200
358
- data["NECB2011"]["outdoors"]["window" ][7000] = 2.200
359
- data["NECB2011"]["outdoors"]["window" ][9999] = 1.600
360
- data["NECB2011"]["outdoors"]["skylight" ][3000] = 2.400
361
- data["NECB2011"]["outdoors"]["skylight" ][4000] = 2.200
362
- data["NECB2011"]["outdoors"]["skylight" ][5000] = 2.200
363
- data["NECB2011"]["outdoors"]["skylight" ][6000] = 2.200
364
- data["NECB2011"]["outdoors"]["skylight" ][7000] = 2.200
365
- data["NECB2011"]["outdoors"]["skylight" ][9999] = 1.600
366
- data["NECB2011"]["outdoors"]["door" ][3000] = 2.400
367
- data["NECB2011"]["outdoors"]["door" ][4000] = 2.200
368
- data["NECB2011"]["outdoors"]["door" ][5000] = 2.200
369
- data["NECB2011"]["outdoors"]["door" ][6000] = 2.200
370
- data["NECB2011"]["outdoors"]["door" ][7000] = 2.200
371
- data["NECB2011"]["outdoors"]["door" ][9999] = 1.600
372
- data["NECB2011"]["ground" ]["wall" ][3000] = 0.568
373
- data["NECB2011"]["ground" ]["wall" ][4000] = 0.379
374
- data["NECB2011"]["ground" ]["wall" ][5000] = 0.284
375
- data["NECB2011"]["ground" ]["wall" ][6000] = 0.284
376
- data["NECB2011"]["ground" ]["wall" ][7000] = 0.284
377
- data["NECB2011"]["ground" ]["wall" ][9999] = 0.210
378
- data["NECB2011"]["ground" ]["roofceiling"][3000] = 0.568
379
- data["NECB2011"]["ground" ]["roofceiling"][4000] = 0.379
380
- data["NECB2011"]["ground" ]["roofceiling"][5000] = 0.284
381
- data["NECB2011"]["ground" ]["roofceiling"][6000] = 0.284
382
- data["NECB2011"]["ground" ]["roofceiling"][7000] = 0.284
383
- data["NECB2011"]["ground" ]["roofceiling"][9999] = 0.210
384
- data["NECB2011"]["ground" ]["floor" ][3000] = 0.757
385
- data["NECB2011"]["ground" ]["floor" ][4000] = 0.757
386
- data["NECB2011"]["ground" ]["floor" ][5000] = 0.757
387
- data["NECB2011"]["ground" ]["floor" ][6000] = 0.757
388
- data["NECB2011"]["ground" ]["floor" ][7000] = 0.757
389
- data["NECB2011"]["ground" ]["floor" ][9999] = 0.379
390
-
391
- data["NECB2015"]["outdoors"]["wall" ][3000] = 0.315
392
- data["NECB2015"]["outdoors"]["wall" ][4000] = 0.278
393
- data["NECB2015"]["outdoors"]["wall" ][5000] = 0.247
394
- data["NECB2015"]["outdoors"]["wall" ][6000] = 0.210
395
- data["NECB2015"]["outdoors"]["wall" ][7000] = 0.210
396
- data["NECB2015"]["outdoors"]["wall" ][9999] = 0.183
397
- data["NECB2015"]["outdoors"]["roofceiling"][3000] = 0.227
398
- data["NECB2015"]["outdoors"]["roofceiling"][4000] = 0.183
399
- data["NECB2015"]["outdoors"]["roofceiling"][5000] = 0.183
400
- data["NECB2015"]["outdoors"]["roofceiling"][6000] = 0.162
401
- data["NECB2015"]["outdoors"]["roofceiling"][7000] = 0.162
402
- data["NECB2015"]["outdoors"]["roofceiling"][9999] = 0.142
403
- data["NECB2015"]["outdoors"]["floor" ][3000] = 0.227
404
- data["NECB2015"]["outdoors"]["floor" ][4000] = 0.183
405
- data["NECB2015"]["outdoors"]["floor" ][5000] = 0.183
406
- data["NECB2015"]["outdoors"]["floor" ][6000] = 0.162
407
- data["NECB2015"]["outdoors"]["floor" ][7000] = 0.162
408
- data["NECB2015"]["outdoors"]["floor" ][9999] = 0.142
409
- data["NECB2015"]["outdoors"]["window" ][3000] = 2.400
410
- data["NECB2015"]["outdoors"]["window" ][4000] = 2.200
411
- data["NECB2015"]["outdoors"]["window" ][5000] = 2.200
412
- data["NECB2015"]["outdoors"]["window" ][6000] = 2.200
413
- data["NECB2015"]["outdoors"]["window" ][7000] = 2.200
414
- data["NECB2015"]["outdoors"]["window" ][9999] = 1.600
415
- data["NECB2015"]["outdoors"]["skylight" ][3000] = 2.400
416
- data["NECB2015"]["outdoors"]["skylight" ][4000] = 2.200
417
- data["NECB2015"]["outdoors"]["skylight" ][5000] = 2.200
418
- data["NECB2015"]["outdoors"]["skylight" ][6000] = 2.200
419
- data["NECB2015"]["outdoors"]["skylight" ][7000] = 2.200
420
- data["NECB2015"]["outdoors"]["skylight" ][9999] = 1.600
421
- data["NECB2015"]["outdoors"]["door" ][3000] = 2.400
422
- data["NECB2015"]["outdoors"]["door" ][4000] = 2.200
423
- data["NECB2015"]["outdoors"]["door" ][5000] = 2.200
424
- data["NECB2015"]["outdoors"]["door" ][6000] = 2.200
425
- data["NECB2015"]["outdoors"]["door" ][7000] = 2.200
426
- data["NECB2015"]["outdoors"]["door" ][9999] = 1.600
427
- data["NECB2015"]["ground" ]["wall" ][3000] = 0.568
428
- data["NECB2015"]["ground" ]["wall" ][4000] = 0.379
429
- data["NECB2015"]["ground" ]["wall" ][5000] = 0.284
430
- data["NECB2015"]["ground" ]["wall" ][6000] = 0.284
431
- data["NECB2015"]["ground" ]["wall" ][7000] = 0.284
432
- data["NECB2015"]["ground" ]["wall" ][9999] = 0.210
433
- data["NECB2015"]["ground" ]["roofceiling"][3000] = 0.568
434
- data["NECB2015"]["ground" ]["roofceiling"][4000] = 0.379
435
- data["NECB2015"]["ground" ]["roofceiling"][5000] = 0.284
436
- data["NECB2015"]["ground" ]["roofceiling"][6000] = 0.284
437
- data["NECB2015"]["ground" ]["roofceiling"][7000] = 0.284
438
- data["NECB2015"]["ground" ]["roofceiling"][9999] = 0.210
439
- data["NECB2015"]["ground" ]["floor" ][3000] = 0.757
440
- data["NECB2015"]["ground" ]["floor" ][4000] = 0.757
441
- data["NECB2015"]["ground" ]["floor" ][5000] = 0.757
442
- data["NECB2015"]["ground" ]["floor" ][6000] = 0.757
443
- data["NECB2015"]["ground" ]["floor" ][7000] = 0.757
444
- data["NECB2015"]["ground" ]["floor" ][9999] = 0.379
445
-
446
- data["NECB2017"]["outdoors"]["wall" ][3000] = 0.315
447
- data["NECB2017"]["outdoors"]["wall" ][4000] = 0.278
448
- data["NECB2017"]["outdoors"]["wall" ][5000] = 0.247
449
- data["NECB2017"]["outdoors"]["wall" ][6000] = 0.210
450
- data["NECB2017"]["outdoors"]["wall" ][7000] = 0.210
451
- data["NECB2017"]["outdoors"]["wall" ][9999] = 0.183
452
- data["NECB2017"]["outdoors"]["roofceiling"][3000] = 0.193
453
- data["NECB2017"]["outdoors"]["roofceiling"][4000] = 0.156
454
- data["NECB2017"]["outdoors"]["roofceiling"][5000] = 0.156
455
- data["NECB2017"]["outdoors"]["roofceiling"][6000] = 0.138
456
- data["NECB2017"]["outdoors"]["roofceiling"][7000] = 0.138
457
- data["NECB2017"]["outdoors"]["roofceiling"][9999] = 0.121
458
- data["NECB2017"]["outdoors"]["floor" ][3000] = 0.227
459
- data["NECB2017"]["outdoors"]["floor" ][4000] = 0.183
460
- data["NECB2017"]["outdoors"]["floor" ][5000] = 0.183
461
- data["NECB2017"]["outdoors"]["floor" ][6000] = 0.162
462
- data["NECB2017"]["outdoors"]["floor" ][7000] = 0.162
463
- data["NECB2017"]["outdoors"]["floor" ][9999] = 0.142
464
- data["NECB2017"]["outdoors"]["window" ][3000] = 2.100
465
- data["NECB2017"]["outdoors"]["window" ][4000] = 1.900
466
- data["NECB2017"]["outdoors"]["window" ][5000] = 1.900
467
- data["NECB2017"]["outdoors"]["window" ][6000] = 1.900
468
- data["NECB2017"]["outdoors"]["window" ][7000] = 1.900
469
- data["NECB2017"]["outdoors"]["window" ][9999] = 1.400
470
- data["NECB2017"]["outdoors"]["skylight" ][3000] = 2.100
471
- data["NECB2017"]["outdoors"]["skylight" ][4000] = 1.900
472
- data["NECB2017"]["outdoors"]["skylight" ][5000] = 1.900
473
- data["NECB2017"]["outdoors"]["skylight" ][6000] = 1.900
474
- data["NECB2017"]["outdoors"]["skylight" ][7000] = 1.900
475
- data["NECB2017"]["outdoors"]["skylight" ][9999] = 1.400
476
- data["NECB2017"]["outdoors"]["door" ][3000] = 2.100
477
- data["NECB2017"]["outdoors"]["door" ][4000] = 1.900
478
- data["NECB2017"]["outdoors"]["door" ][5000] = 1.900
479
- data["NECB2017"]["outdoors"]["door" ][6000] = 1.900
480
- data["NECB2017"]["outdoors"]["door" ][7000] = 1.900
481
- data["NECB2017"]["outdoors"]["door" ][9999] = 1.400
482
- data["NECB2017"]["ground" ]["wall" ][3000] = 0.568
483
- data["NECB2017"]["ground" ]["wall" ][4000] = 0.379
484
- data["NECB2017"]["ground" ]["wall" ][5000] = 0.284
485
- data["NECB2017"]["ground" ]["wall" ][6000] = 0.284
486
- data["NECB2017"]["ground" ]["wall" ][7000] = 0.284
487
- data["NECB2017"]["ground" ]["wall" ][9999] = 0.210
488
- data["NECB2017"]["ground" ]["roofceiling"][3000] = 0.568
489
- data["NECB2017"]["ground" ]["roofceiling"][4000] = 0.379
490
- data["NECB2017"]["ground" ]["roofceiling"][5000] = 0.284
491
- data["NECB2017"]["ground" ]["roofceiling"][6000] = 0.284
492
- data["NECB2017"]["ground" ]["roofceiling"][7000] = 0.284
493
- data["NECB2017"]["ground" ]["roofceiling"][9999] = 0.210
494
- data["NECB2017"]["ground" ]["floor" ][3000] = 0.757
495
- data["NECB2017"]["ground" ]["floor" ][4000] = 0.757
496
- data["NECB2017"]["ground" ]["floor" ][5000] = 0.757
497
- data["NECB2017"]["ground" ]["floor" ][6000] = 0.757
498
- data["NECB2017"]["ground" ]["floor" ][7000] = 0.757
499
- data["NECB2017"]["ground" ]["floor" ][9999] = 0.379
500
-
501
- data["NECB2020"]["outdoors"]["wall" ][3000] = 0.290
502
- data["NECB2020"]["outdoors"]["wall" ][4000] = 0.265
503
- data["NECB2020"]["outdoors"]["wall" ][5000] = 0.240
504
- data["NECB2020"]["outdoors"]["wall" ][6000] = 0.215
505
- data["NECB2020"]["outdoors"]["wall" ][7000] = 0.190
506
- data["NECB2020"]["outdoors"]["wall" ][9999] = 0.165
507
- data["NECB2020"]["outdoors"]["roofceiling"][3000] = 0.164
508
- data["NECB2020"]["outdoors"]["roofceiling"][4000] = 0.156
509
- data["NECB2020"]["outdoors"]["roofceiling"][5000] = 0.138
510
- data["NECB2020"]["outdoors"]["roofceiling"][6000] = 0.121
511
- data["NECB2020"]["outdoors"]["roofceiling"][7000] = 0.117
512
- data["NECB2020"]["outdoors"]["roofceiling"][9999] = 0.110
513
- data["NECB2020"]["outdoors"]["floor" ][3000] = 0.193
514
- data["NECB2020"]["outdoors"]["floor" ][4000] = 0.175
515
- data["NECB2020"]["outdoors"]["floor" ][5000] = 0.156
516
- data["NECB2020"]["outdoors"]["floor" ][6000] = 0.138
517
- data["NECB2020"]["outdoors"]["floor" ][7000] = 0.121
518
- data["NECB2020"]["outdoors"]["floor" ][9999] = 0.117
519
- data["NECB2020"]["outdoors"]["window" ][3000] = 1.900
520
- data["NECB2020"]["outdoors"]["window" ][4000] = 1.900
521
- data["NECB2020"]["outdoors"]["window" ][5000] = 1.730
522
- data["NECB2020"]["outdoors"]["window" ][6000] = 1.730
523
- data["NECB2020"]["outdoors"]["window" ][7000] = 1.440
524
- data["NECB2020"]["outdoors"]["window" ][9999] = 1.440
525
- data["NECB2020"]["outdoors"]["skylight" ][3000] = 2.690
526
- data["NECB2020"]["outdoors"]["skylight" ][4000] = 2.690
527
- data["NECB2020"]["outdoors"]["skylight" ][5000] = 2.410
528
- data["NECB2020"]["outdoors"]["skylight" ][6000] = 2.410
529
- data["NECB2020"]["outdoors"]["skylight" ][7000] = 2.010
530
- data["NECB2020"]["outdoors"]["skylight" ][9999] = 2.010
531
- data["NECB2020"]["outdoors"]["door" ][3000] = 2.120
532
- data["NECB2020"]["outdoors"]["door" ][4000] = 1.900
533
- data["NECB2020"]["outdoors"]["door" ][5000] = 1.900
534
- data["NECB2020"]["outdoors"]["door" ][6000] = 1.900
535
- data["NECB2020"]["outdoors"]["door" ][7000] = 1.900
536
- data["NECB2020"]["outdoors"]["door" ][9999] = 1.440
537
- data["NECB2020"]["ground" ]["wall" ][3000] = 0.568
538
- data["NECB2020"]["ground" ]["wall" ][4000] = 0.379
539
- data["NECB2020"]["ground" ]["wall" ][5000] = 0.284
540
- data["NECB2020"]["ground" ]["wall" ][6000] = 0.284
541
- data["NECB2020"]["ground" ]["wall" ][7000] = 0.284
542
- data["NECB2020"]["ground" ]["wall" ][9999] = 0.210
543
- data["NECB2020"]["ground" ]["roofceiling"][3000] = 0.568
544
- data["NECB2020"]["ground" ]["roofceiling"][4000] = 0.379
545
- data["NECB2020"]["ground" ]["roofceiling"][5000] = 0.284
546
- data["NECB2020"]["ground" ]["roofceiling"][6000] = 0.284
547
- data["NECB2020"]["ground" ]["roofceiling"][7000] = 0.284
548
- data["NECB2020"]["ground" ]["roofceiling"][9999] = 0.210
549
- data["NECB2020"]["ground" ]["floor" ][3000] = 0.757
550
- data["NECB2020"]["ground" ]["floor" ][4000] = 0.757
551
- data["NECB2020"]["ground" ]["floor" ][5000] = 0.757
552
- data["NECB2020"]["ground" ]["floor" ][6000] = 0.757
553
- data["NECB2020"]["ground" ]["floor" ][7000] = 0.757
554
- data["NECB2020"]["ground" ]["floor" ][9999] = 0.379
391
+ floors.each { |floor| floor.setConstruction(lc) }
555
392
 
556
- # Return required U-factor if provided HDD < stored HDD.
557
- data[@template][condition][stype].each { |hdd18, u| return u if hdd < hdd18 }
393
+ flrs += floors
394
+ end
558
395
 
559
- 0.110
396
+ flrs
560
397
  end
561
398
 
562
399
  ##
563
- # Adds default construction sets, based on building 'category' & 'structure'
564
- # selections. This is an alternative method to 'model_apply_construction'
565
- # & 'apply_standard_construction_properties' methods.
400
+ # Adds default construction sets to the building (or to selected spaces). The
401
+ # solution is an alternative option to BTAP's 'model_apply_construction' &
402
+ # 'apply_standard_construction_properties'. Parameters are based on previously
403
+ # set 'category' & 'structure' parameters. Constructions that are part of
404
+ # the building envelope inherit the AdditionalProperty "btap_uo" (usually the
405
+ # NECB-required clear-field Uo factor), and the AdditionalProperty "btap_id"
406
+ # (usually the BTAP costed construction identifier). Both "btap_uo"/"btap_id"
407
+ # may be reset when uprating (per NECB 2017/2025) - see btap/bridging.rb
566
408
  #
567
409
  # @author denis@rd2.ca
568
410
  #
569
- # @param model [OpenStudio::Model::Model] a model
570
- # @param necb_hdd [Boolean] whether to rely on BTAP to set HDD (vs stat file)
571
- # @param a [Hash] optional U & SHGC overrides
572
- # @option a [Hash] eWallU exposed wall Uo (or Ut)
573
- # @option a [Hash] eFloorU exposed floor Uo (or Ut)
574
- # @option a [Hash] eRoofU exposed roof Uo (or Ut)
575
- # @option a [Hash] gWallU ground wall Uo (or Ut)
576
- # @option a [Hash] gFloorU ground floor Uo (or Ut)
577
- # @option a [Hash] gRoofU ground roof Uo (or Ut)
578
- # @option a [Hash] doorU opaque door U
579
- # @option a [Hash] fenU fenestration U (e.g. fixe, operable, glass door)
580
- # @option a [Hash] skyU skylight U
581
- # @option a [Hash] doorSHGC opaque door SHGC
582
- # @option a [Hash] fenSHGC fenestration SHGC
583
- # @option a [Hash] skySHGC skylight SHGC
411
+ # @param [Array<OpenStudio::Model::Space>] spaces
412
+ # @param [Boolean] bldg true if assigned to building (not individual spaces)
413
+ # @param [Boolean] hdd whether to rely on BTAP in setting HDD (vs stat file)
414
+ # @param [Hash] a optional parameters, e.g. U-factors
415
+ # @option a [String] :category ("public")
416
+ # @option a [Symbol] :structure (:concrete)
417
+ # @option a [Symbol] :framing (:steel)
418
+ # @option a [Symbol] :cladding (:heavy)
419
+ # @option a [Symbol] :finish (:light)
420
+ # @option a [Numeric] :eWallU exposed wall Uo (or Ut)
421
+ # @option a [Numeric] :eFloorU exposed floor Uo (or Ut)
422
+ # @option a [Numeric] :eRoofU exposed roof Uo (or Ut)
423
+ # @option a [Numeric] :gWallU ground wall Uo (or Ut)
424
+ # @option a [Numeric] :gFloorU ground floor Uo (or Ut)
425
+ # @option a [Numeric] :gRoofU ground roof Uo (or Ut)
426
+ # @option a [Numeric] :doorU opaque door U
427
+ # @option a [Numeric] :fenU fenestration U e.g. fixed/operable, glass door
428
+ # @option a [Numeric] :skyU skylight U
429
+ # @option a [Numeric] :fenSHGC fenestration solar heat gain coefficient
430
+ # @option a [Numeric] :skySHGC skylight solar heat gain coefficient
584
431
  #
585
432
  # @return [Boolean] whether default constructions were successfully added.
586
- def add_construction_sets(model, necb_hdd, a)
587
- return false unless model.is_a?(OpenStudio::Model::Model)
433
+ def add_construction_sets(spaces = [], bldg = true, hdd = true, a = {})
434
+ bldg = true unless bldg == false
435
+ hdd = true unless hdd == false
436
+ out = "outdoors"
437
+ gnd = "ground"
588
438
  return false unless a.is_a?(Hash)
589
439
 
590
- btp = BTAP::Resources::Envelope::Constructions # alias
591
- necb_hdd = true unless [true, false].include?(necb_hdd)
440
+ # Accept a single 'OpenStudio::Model::Space' (vs an array of spaces).
441
+ if spaces.respond_to?(:spaceType) || spaces.respond_to?(:to_a)
442
+ spaces = [spaces] if spaces.respond_to?(:spaceType)
443
+ return false if spaces.empty?
444
+ else
445
+ return false
446
+ end
447
+
448
+ spaces.each { |sp| return false unless sp.respond_to?(:spaceType) }
592
449
 
593
- # Validate argh options (limited to either U or SHGC)
450
+ # Rudimentary parameter validation.
594
451
  a.each do |k, v|
595
- return false unless v.is_a?(Numeric)
596
- return false unless v.round(3) > 0
452
+ if v.is_a?(Numeric)
453
+ return false unless v.round(3) > 0
597
454
 
598
- if k.to_s[-1].downcase == "u"
599
- return false unless v.between?(btp::uMIN, btp::uMAX)
455
+ if k.to_s[-1].downcase == "u"
456
+ return false unless v.between?(TBD::UMIN, TBD::UMAX)
457
+ else
458
+ return false unless v.between?(0.05, 0.95)
459
+ end
600
460
  else
601
- return false unless v.between?(0.05, 0.95)
461
+ return false unless k.respond_to?(:to_sym)
602
462
  end
603
463
  end
604
464
 
605
- tag = "space_conditioning_category"
606
- bldg = model.getBuilding
607
- hdd = get_necb_hdd18(model: model, necb_hdd: necb_hdd)
608
-
609
- # Reset constructions.
610
- model.getPlanarSurfaces.sort.each(&:resetConstruction)
611
-
612
- # Fetch NECB-required U-factors (or provided as arguments).
613
- eWallU = a[:eWallU ] ? a[:eWallU ] : max_u_necb("wall", "outdoors", hdd)
614
- eRoofU = a[:eRoofU ] ? a[:eRoofU ] : max_u_necb("roofceiling", "outdoors", hdd)
615
- eFloorU = a[:eFloorU] ? a[:eFloorU] : max_u_necb("floor", "outdoors", hdd)
616
- gWallU = a[:gWallU ] ? a[:gWallU ] : max_u_necb("wall", "ground", hdd)
617
- gFloorU = a[:gFloorU] ? a[:gFloorU] : max_u_necb("floor", "ground", hdd)
618
- gRoofU = a[:gRoofU ] ? a[:gRoofU ] : max_u_necb("roofceiling", "ground", hdd)
619
- doorU = a[:doorU ] ? a[:doorU ] : max_u_necb("door", "outdoors", hdd)
620
- fenU = a[:fenU ] ? a[:fenU ] : max_u_necb("window", "outdoors", hdd)
621
- skyU = a[:skyU ] ? a[:skyU ] : max_u_necb("skylight", "outdoors", hdd)
622
-
623
- # FYI: Excerpt of the 'SimpleGlazing' material generated using BTAP:
465
+ # Fetch OpenStudio model & site/climate HDD.
466
+ model = spaces.first.model
467
+ hdd = get_necb_hdd18(model: model, necb_hdd: hdd)
468
+
469
+ # Filling in the blanks: STRUCTURE-based parameters.
470
+ ctg = a[:category ] ? a[:category ] : "commercial"
471
+ stc = a[:structure] ? a[:structure] : :steel
472
+ frm = a[:framing ] ? a[:framing ] : :steel
473
+ cld = a[:cladding ] ? a[:cladding ] : :light
474
+ fsh = a[:finish ] ? a[:finish ] : :light
475
+
476
+ # Filling in the blanks: U-factors.
477
+ eWallU = a[:eWallU ] ? a[:eWallU ] : max_u_necb("wall", out, hdd)
478
+ eRoofU = a[:eRoofU ] ? a[:eRoofU ] : max_u_necb("roofceiling", out, hdd)
479
+ eFloorU = a[:eFloorU] ? a[:eFloorU] : max_u_necb("floor", out, hdd)
480
+ gWallU = a[:gWallU ] ? a[:gWallU ] : max_u_necb("wall", gnd, hdd)
481
+ gFloorU = a[:gFloorU] ? a[:gFloorU] : max_u_necb("floor", gnd, hdd)
482
+ gRoofU = a[:gRoofU ] ? a[:gRoofU ] : max_u_necb("roofceiling", gnd, hdd)
483
+ doorU = a[:doorU ] ? a[:doorU ] : max_u_necb("door", out, hdd)
484
+ fenU = a[:fenU ] ? a[:fenU ] : max_u_necb("window", out, hdd)
485
+ skyU = a[:skyU ] ? a[:skyU ] : max_u_necb("skylight", out, hdd)
486
+
487
+ # Filling in the blanks: solar heat gain coefficients.
488
+ fenSHGC = a[:fenSHGC] ? a[:fenSHGC] : 0.60
489
+ skySHGC = a[:skySHGC] ? a[:skySHGC] : 0.60
490
+ #
491
+ # FYI: Excerpt of the 'SimpleGlazing' material, generated by BTAP:
624
492
  #
625
493
  # SimpleGlazing:U=0.220 SHGC=0.600, !- Name
626
494
  # 2.2, !- U-Factor {W/m2-K}
@@ -628,192 +496,369 @@ class NECB2011
628
496
  # 0.21; !- Visible Transmittance
629
497
  #
630
498
  # 1. Identifier 'U=0.220' for an NFRC-rated U-factor of 2.2 W/m2.K ?
631
- # 2. VT is almost always higher than SHGC - not the other way around. VT
632
- # should be set here based on a reasonable LSG ratio:
499
+ # 2. VT is almost always higher than SHGC - not the other way around.
500
+ # VT should be set here based on a reasonable LSG ratio:
633
501
  # - eta-publications.lbl.gov/sites/default/files/femp-spec-sel-low-e.pdf
634
- # - www.wbdg.org/resources/windows-and-glazing
635
502
  #
636
503
  # ... for the moment, sticking to SHGC 60%, yet keeping default VT.
637
- doorSHGC = a[:doorSHGC] ? a[:doorSHGC] : 0.60
638
- fenSHGC = a[:fenSHGC ] ? a[:fenSHGC ] : 0.60
639
- skySHGC = a[:skySHGC ] ? a[:skySHGC ] : 0.60
640
-
641
- # Fetch corresponding BTAP structure parameters.
642
- category = @structure.category
643
- structure = @structure.structure
644
- framing = @structure.framing
645
- cladding = @structure.cladding
646
- finish = @structure.finish
647
-
648
- # Uninsulated slab-on-grade, except if HDD > 6999 (Uo = 0.379 W/m2.K).
649
- # If HDD < 7000, slab-on-grade insulation is instead only required along
650
- # perimeter. Perimeter insulation requires special treatment, à la KIVA. The
651
- # vast majority of models do not have full-height basements. Exceptions:
652
- # - LargeOffice
653
- # - LargeHotel
654
- # - Hospital
655
- #
656
- # The solution is temporarily OK, yet a more nuanced treatment is required
657
- # for full-height basement cases. This would likely require a space-by-space
658
- # treatment, based on Z-axis grade-vs-floor height difference - @todo.
659
- specs = {}
660
- specs[:type ] = :slab
661
- specs[:uo ] = nil
662
- specs[:uo ] = gFloorU if hdd > 6999
663
- specs[:frame ] = :none unless hdd > 6999
664
- specs[:finish] = :none if category == "robust"
665
- specs[:finish] = :none if category == "industry"
666
- gFloor = TBD.genConstruction(model, specs)
667
- insulation = TBD.insulatingLayer(gFloor)
668
-
669
- # Ensure insulating layer uniqueness for each insulated construction.
670
- lyr = TBD.insulatingLayer(gFloor)
671
- TBD.assignUniqueMaterial(gFloor, lyr[:index]) if lyr[:index]
672
-
673
- # Insulated basement wall. A more nuanced treatment is necessary for
674
- # multiple basement stories - no insulation required below 2.4m from grade.
675
- specs = {}
676
- specs[:type ] = :basement
677
- specs[:uo ] = gWallU
678
- gWall = TBD.genConstruction(model, specs)
679
-
680
- lyr = TBD.insulatingLayer(gWall)
681
- TBD.assignUniqueMaterial(gWall, lyr[:index]) if lyr[:index]
682
-
683
- # Insulated basement roof. Again, a more nuanced approach is necessary if
684
- # the basement roof is below 1.2m from grade (e.g. a tunnel).
685
- specs = {}
686
- specs[:type ] = :roof
687
- specs[:uo ] = gRoofU
688
- specs[:frame ] = :medium
689
- specs[:finish] = :heavy
690
- gRoof = TBD.genConstruction(model, specs)
691
-
692
- lyr = TBD.insulatingLayer(gRoof)
693
- TBD.assignUniqueMaterial(gRoof, lyr[:index]) if lyr[:index]
694
504
 
695
505
  # Outdoor-facing wall.
696
506
  specs = {}
697
507
  specs[:type ] = :wall
698
508
  specs[:uo ] = eWallU
699
509
  specs[:frame ] = :medium
700
- specs[:clad ] = :heavy if category == "robust"
701
- specs[:finish] = :medium if category == "robust"
702
- specs[:finish] = :medium if framing == :cmu
703
- eWall = TBD.genConstruction(model, specs)
510
+ specs[:clad ] = :heavy if ctg == "robust"
511
+ specs[:finish] = :medium if ctg == "robust"
512
+ specs[:finish] = :medium if frm == :cmu
513
+ eWall = TBD.genConstruction(model, specs)
704
514
 
515
+ # Ensure insulating layer uniqueness for each insulated construction.
705
516
  lyr = TBD.insulatingLayer(eWall)
706
517
  TBD.assignUniqueMaterial(eWall, lyr[:index]) if lyr[:index]
707
518
 
519
+ # Argument hash to identify BTAP costed assembly.
520
+ argh = {}
521
+ argh[:framing ] = frm
522
+ argh[:cladding] = cld
523
+ argh[:finish ] = fsh
524
+ argh[:perform ] = :lp
525
+ argh[:stype ] = :walls
526
+ argh[:uo ] = eWallU
527
+ id = BTAP::Bridging.costed_assembly(argh)
528
+
529
+ eWall.additionalProperties.setFeature("btap_uo", eWallU)
530
+ eWall.additionalProperties.setFeature("btap_ut", eWallU)
531
+ eWall.additionalProperties.setFeature("btap_id", id)
532
+ eWall.additionalProperties.setFeature("btap_type", "walls")
533
+
534
+ # Add default exterior wall construction properties to building or spaces.
535
+ if bldg
536
+ model.getBuilding.additionalProperties.setFeature("btap_uo", eWallU)
537
+ model.getBuilding.additionalProperties.setFeature("btap_ut", eWallU)
538
+ model.getBuilding.additionalProperties.setFeature("btap_id", id)
539
+ model.getBuilding.additionalProperties.setFeature("btap_type", "walls")
540
+ else
541
+ spaces.each do |sp|
542
+ sp.additionalProperties.setFeature("btap_uo", eWallU)
543
+ sp.additionalProperties.setFeature("btap_ut", eWallU)
544
+ sp.additionalProperties.setFeature("btap_id", id)
545
+ sp.additionalProperties.setFeature("btap_type", "walls")
546
+ end
547
+ end
548
+
708
549
  # Outdoor-facing roof.
709
550
  specs = {}
710
551
  specs[:type ] = :roof
711
552
  specs[:uo ] = eRoofU
712
- specs[:clad ] = :medium if category == "housing" && structure == :concrete
713
- specs[:clad ] = :medium if category == "lodging" && structure == :concrete
553
+ specs[:clad ] = :medium if ctg == "housing" && stc == :concrete
554
+ specs[:clad ] = :medium if ctg == "lodging" && stc == :concrete
714
555
  specs[:frame ] = :medium
715
- specs[:frame ] = :heavy if framing == :wood
716
- specs[:finish] = :medium if category == "robust"
717
- specs[:finish] = :heavy if category == "housing" && structure == :concrete
718
- specs[:finish] = :heavy if category == "lodging" && structure == :concrete
719
- eRoof = TBD.genConstruction(model, specs)
556
+ specs[:frame ] = :heavy if frm == :wood
557
+ specs[:finish] = :medium if ctg == "robust"
558
+ specs[:finish] = :heavy if ctg == "housing" && stc == :concrete
559
+ specs[:finish] = :heavy if ctg == "lodging" && stc == :concrete
560
+ eRoof = TBD.genConstruction(model, specs)
720
561
 
562
+ # Ensure insulating layer uniqueness for each insulated construction.
721
563
  lyr = TBD.insulatingLayer(eRoof)
722
564
  TBD.assignUniqueMaterial(eRoof, lyr[:index]) if lyr[:index]
723
565
 
566
+ argh[:perform] = :lp
567
+ argh[:stype ] = :roofs
568
+ argh[:uo ] = eRoofU
569
+ id = BTAP::Bridging.costed_assembly(argh)
570
+
571
+ eRoof.additionalProperties.setFeature("btap_uo", eRoofU)
572
+ eRoof.additionalProperties.setFeature("btap_ut", eRoofU)
573
+ eRoof.additionalProperties.setFeature("btap_id", id)
574
+ eRoof.additionalProperties.setFeature("btap_type", "roofs")
575
+
724
576
  # Outdoor-facing floor.
725
- specs = {}
726
- specs[:type ] = :floor
727
- specs[:uo ] = eFloorU
728
- specs[:finish] = :medium unless framing == :wood
729
- specs[:finish] = :heavy if category == "housing" && structure == :concrete
730
- specs[:finish] = :heavy if category == "lodging" && structure == :concrete
731
- eFloor = TBD.genConstruction(model, specs)
577
+ specs = {}
578
+ specs[:type ] = :floor
579
+ specs[:uo ] = eFloorU
580
+ specs[:finish ] = :medium unless frm == :wood
581
+ specs[:finish ] = :heavy if ctg == "housing" && stc == :concrete
582
+ specs[:finish ] = :heavy if ctg == "lodging" && stc == :concrete
583
+ eFloor = TBD.genConstruction(model, specs)
732
584
 
585
+ # Ensure insulating layer uniqueness for each insulated construction.
733
586
  lyr = TBD.insulatingLayer(eFloor)
734
587
  TBD.assignUniqueMaterial(eFloor, lyr[:index]) if lyr[:index]
735
588
 
736
- # Outdoor-facing, opaque door.
737
- specs = {}
738
- specs[:type ] = :door
739
- specs[:uo ] = doorU
740
- door = TBD.genConstruction(model, specs)
589
+ argh[:perform ] = :lp
590
+ argh[:stype ] = :floors
591
+ id = BTAP::Bridging.costed_assembly(argh)
741
592
 
742
- # Outdoor-facing, vertical fenestration.
743
- specs = {}
744
- specs[:type ] = :window
745
- specs[:uo ] = fenU
746
- specs[:shgc ] = fenSHGC
747
- fen = TBD.genConstruction(model, specs)
593
+ eFloor.additionalProperties.setFeature("btap_uo", eFloorU)
594
+ eFloor.additionalProperties.setFeature("btap_ut", eFloorU)
595
+ eFloor.additionalProperties.setFeature("btap_id", id)
596
+ eFloor.additionalProperties.setFeature("btap_type", "floors")
748
597
 
749
- # Outdoor-facing, horizontal skylight.
750
- specs = {}
751
- specs[:type ] = :skylight
752
- specs[:uo ] = skyU
753
- specs[:shgc ] = skySHGC
754
- sky = TBD.genConstruction(model, specs)
598
+ extSPACE = OpenStudio::Model::DefaultSurfaceConstructions.new(model)
599
+ extSPACE.setName("BTAP exterior constructions")
600
+ extSPACE.setWallConstruction(eWall)
601
+ extSPACE.setFloorConstruction(eFloor)
602
+ extSPACE.setRoofCeilingConstruction(eRoof)
755
603
 
756
- # Interzone/partition wall.
757
- specs = {}
758
- specs[:type ] = :partition
759
- iWall = TBD.genConstruction(model, specs)
604
+ setSPACE = OpenStudio::Model::DefaultConstructionSet.new(model)
605
+ setSPACE.setName("BTAP construction set")
606
+ setSPACE.setDefaultExteriorSurfaceConstructions(extSPACE)
760
607
 
761
- # Interzone roof/ceiling & floor.
762
- specs = {}
763
- specs[:type ] = :partition
764
- specs[:frame ] = :medium unless framing == :wood
765
- specs[:frame ] = :heavy if category == "housing" && structure == :concrete
766
- specs[:frame ] = :heavy if category == "lodging" && structure == :concrete
767
- specs[:frame ] = :heavy if category == "robust"
768
- specs[:clad ] = :none if category == "robust"
769
- specs[:finish] = :none if category == "robust"
770
- iRoof = TBD.genConstruction(model, specs)
771
- iFloor = TBD.genConstruction(model, specs)
772
-
773
- # Shading material.
774
- specs = {type: :shading}
775
- shading = TBD.genConstruction(model, specs)
776
-
777
- # Building-wide, default constructions.
778
- intBLDG = OpenStudio::Model::DefaultSurfaceConstructions.new(model)
779
- solBLDG = OpenStudio::Model::DefaultSurfaceConstructions.new(model)
780
- extBLDG = OpenStudio::Model::DefaultSurfaceConstructions.new(model)
781
- subBLDG = OpenStudio::Model::DefaultSubSurfaceConstructions.new(model)
782
- intBLDG.setName("BTAP interior constructions BLDG")
783
- solBLDG.setName("BTAP ground constructions BLDG")
784
- extBLDG.setName("BTAP exterior constructions BLDG")
785
- subBLDG.setName("BTAP subsurface constructions BLDG")
786
- intBLDG.setWallConstruction(iWall)
787
- intBLDG.setFloorConstruction(iFloor)
788
- intBLDG.setRoofCeilingConstruction(iRoof)
789
- solBLDG.setWallConstruction(gWall)
790
- solBLDG.setFloorConstruction(gFloor)
791
- solBLDG.setRoofCeilingConstruction(gRoof)
792
- extBLDG.setWallConstruction(eWall)
793
- extBLDG.setFloorConstruction(eFloor)
794
- extBLDG.setRoofCeilingConstruction(eRoof)
795
- subBLDG.setFixedWindowConstruction(fen)
796
- subBLDG.setOperableWindowConstruction(fen)
797
- subBLDG.setGlassDoorConstruction(fen)
798
- subBLDG.setSkylightConstruction(sky)
799
- subBLDG.setTubularDaylightDomeConstruction(sky)
800
- subBLDG.setTubularDaylightDiffuserConstruction(sky)
801
- subBLDG.setDoorConstruction(door)
802
- subBLDG.setOverheadDoorConstruction(door)
803
-
804
- setBLDG = OpenStudio::Model::DefaultConstructionSet.new(model)
805
- setBLDG.setName("BTAP construction set BLDG")
806
- setBLDG.setDefaultInteriorSurfaceConstructions(intBLDG)
807
- setBLDG.setDefaultGroundContactSurfaceConstructions(solBLDG)
808
- setBLDG.setDefaultExteriorSurfaceConstructions(extBLDG)
809
- setBLDG.setDefaultExteriorSubSurfaceConstructions(subBLDG)
810
- setBLDG.setInteriorPartitionConstruction(iWall)
811
- setBLDG.setSpaceShadingConstruction(shading)
812
- setBLDG.setBuildingShadingConstruction(shading)
813
- setBLDG.setSiteShadingConstruction(shading)
814
- setBLDG.setAdiabaticSurfaceConstruction(iWall)
815
-
816
- bldg.setDefaultConstructionSet(setBLDG)
608
+ # Uninsulated slab-on-grade, except if HDD > 6999 (Uo = 0.379 W/m2.K).
609
+ # If HDD < 7000, slab-on-grade insulation is instead only required along
610
+ # perimeter. Perimeter insulation requires special treatment, à la KIVA. The
611
+ # vast majority of models do not have full-height basements. Exceptions:
612
+ # - LargeOffice
613
+ # - LargeHotel
614
+ # - Hospital
615
+ #
616
+ # The solution is temporarily OK, yet a more nuanced treatment is required
617
+ # for full-height basement cases. This would likely require a space-by-space
618
+ # treatment, based on Z-axis grade-vs-floor height difference - @todo.
619
+ #
620
+ # Ground-facing constructions are restricted to a building's default
621
+ # construction set - not customized spaces'.
622
+ if bldg
623
+ specs = {}
624
+ specs[:type ] = :slab
625
+ specs[:uo ] = nil
626
+ specs[:uo ] = gFloorU if hdd > 6999
627
+ specs[:frame ] = :none unless hdd > 6999
628
+ specs[:finish] = :none if ctg == "robust"
629
+ specs[:finish] = :none if ctg == "industry"
630
+ gFloor = TBD.genConstruction(model, specs)
631
+
632
+ # Ensure insulating layer uniqueness for each insulated construction.
633
+ if hdd > 6999
634
+ lyr = TBD.insulatingLayer(gFloor)
635
+ TBD.assignUniqueMaterial(gFloor, lyr[:index]) if lyr[:index]
636
+ end
637
+
638
+ # @todo: an alternative key is required to switch between insulated vs
639
+ # uninsulated ground-facing constructions.
640
+ id = BTAP::Attributes.surface_types_to_assembly_names["GroundContactFloor"]
641
+
642
+ gFloor.additionalProperties.setFeature("btap_uo", gFloorU)
643
+ gFloor.additionalProperties.setFeature("btap_ut", gFloorU)
644
+ gFloor.additionalProperties.setFeature("btap_id", id)
645
+ gFloor.additionalProperties.setFeature("btap_type", "gfloors")
646
+
647
+ # Insulated basement wall. A more nuanced treatment is necessary for
648
+ # multiple basement stories - no insulation required below 2.4m from grade.
649
+ specs = {}
650
+ specs[:type ] = :basement
651
+ specs[:uo ] = gWallU
652
+ gWall = TBD.genConstruction(model, specs)
653
+
654
+ # Ensure insulating layer uniqueness for each insulated construction.
655
+ lyr = TBD.insulatingLayer(gWall)
656
+ TBD.assignUniqueMaterial(gWall, lyr[:index]) if lyr[:index]
657
+
658
+ id = BTAP::Attributes.surface_types_to_assembly_names["GroundContactWall"]
659
+
660
+ gWall.additionalProperties.setFeature("btap_uo", gWallU)
661
+ gWall.additionalProperties.setFeature("btap_ut", gWallU)
662
+ gWall.additionalProperties.setFeature("btap_id", id)
663
+ gWall.additionalProperties.setFeature("btap_type", "gwalls")
664
+
665
+ # Insulated basement roof. Again, a more nuanced approach is necessary if
666
+ # the basement roof is below 1.2m from grade (e.g. a tunnel).
667
+ specs = {}
668
+ specs[:type ] = :roof
669
+ specs[:uo ] = gRoofU
670
+ specs[:frame ] = :medium
671
+ specs[:finish] = :heavy
672
+ gRoof = TBD.genConstruction(model, specs)
673
+
674
+ # Ensure insulating layer uniqueness for each insulated construction.
675
+ lyr = TBD.insulatingLayer(gRoof)
676
+ TBD.assignUniqueMaterial(gRoof, lyr[:index]) if lyr[:index]
677
+
678
+ id = BTAP::Attributes.surface_types_to_assembly_names["GroundContactRoof"]
679
+
680
+ gRoof.additionalProperties.setFeature("btap_uo", gRoofU)
681
+ gRoof.additionalProperties.setFeature("btap_ut", gRoofU)
682
+ gRoof.additionalProperties.setFeature("btap_id", id)
683
+ gRoof.additionalProperties.setFeature("btap_type", "groofs")
684
+
685
+ # Shading.
686
+ specs = {}
687
+ specs[:type] = :shading
688
+ shading = TBD.genConstruction(model, specs)
689
+
690
+ # Outdoor-facing doors.
691
+ specs = {}
692
+ specs[:type] = :door
693
+ specs[:uo ] = doorU
694
+ eDoor = TBD.genConstruction(model, specs)
695
+
696
+ id = BTAP::Attributes.surface_types_to_assembly_names["ExteriorDoor"]
697
+
698
+ eDoor.additionalProperties.setFeature("btap_uo", doorU)
699
+ eDoor.additionalProperties.setFeature("btap_ut", doorU)
700
+ eDoor.additionalProperties.setFeature("btap_id", id)
701
+ eDoor.additionalProperties.setFeature("btap_type", "doors")
702
+
703
+ # Outdoor-facing, overhead doors.
704
+ specs = {}
705
+ specs[:type] = :door
706
+ specs[:uo ] = doorU
707
+ oDoor = TBD.genConstruction(model, specs)
708
+
709
+ id = BTAP::Attributes.surface_types_to_assembly_names["ExteriorOverheadDoor"]
710
+
711
+ oDoor.additionalProperties.setFeature("btap_uo", doorU)
712
+ oDoor.additionalProperties.setFeature("btap_ut", doorU)
713
+ oDoor.additionalProperties.setFeature("btap_id", id)
714
+ oDoor.additionalProperties.setFeature("btap_type", "odoors")
715
+
716
+ # Outdoor-facing, fixed window.
717
+ specs = {}
718
+ specs[:type] = :window
719
+ specs[:uo ] = fenU
720
+ specs[:shgc] = fenSHGC
721
+ fWindow = TBD.genConstruction(model, specs)
722
+
723
+ id = BTAP::Attributes.surface_types_to_assembly_names["ExteriorFixedWindow"]
724
+
725
+ fWindow.additionalProperties.setFeature("btap_uo", fenU)
726
+ fWindow.additionalProperties.setFeature("btap_ut", fenU)
727
+ fWindow.additionalProperties.setFeature("btap_id", id)
728
+ fWindow.additionalProperties.setFeature("btap_type", "windows")
729
+
730
+ # Outdoor-facing, operable window.
731
+ specs = {}
732
+ specs[:type] = :window
733
+ specs[:uo ] = fenU
734
+ specs[:shgc] = fenSHGC
735
+ oWindow = TBD.genConstruction(model, specs)
736
+
737
+ id = BTAP::Attributes.surface_types_to_assembly_names["ExteriorOperableWindow"]
738
+
739
+ oWindow.additionalProperties.setFeature("btap_uo", fenU)
740
+ oWindow.additionalProperties.setFeature("btap_ut", fenU)
741
+ oWindow.additionalProperties.setFeature("btap_id", id)
742
+ oWindow.additionalProperties.setFeature("btap_type", "owindows")
743
+
744
+ # Outdoor-facing, glass door.
745
+ specs = {}
746
+ specs[:type] = :window
747
+ specs[:uo ] = fenU
748
+ specs[:shgc] = fenSHGC
749
+ gDoor = TBD.genConstruction(model, specs)
750
+
751
+ id = BTAP::Attributes.surface_types_to_assembly_names["ExteriorGlassDoor"]
752
+
753
+ gDoor.additionalProperties.setFeature("btap_uo", fenU)
754
+ gDoor.additionalProperties.setFeature("btap_ut", fenU)
755
+ gDoor.additionalProperties.setFeature("btap_id", id)
756
+ gDoor.additionalProperties.setFeature("btap_type", "gdoors")
757
+
758
+ # Outdoor-facing, horizontal skylight.
759
+ specs = {}
760
+ specs[:type] = :skylight
761
+ specs[:uo ] = skyU
762
+ specs[:shgc] = skySHGC
763
+ sky = TBD.genConstruction(model, specs)
764
+
765
+ id = BTAP::Attributes.surface_types_to_assembly_names["ExteriorSkylight"]
766
+
767
+ sky.additionalProperties.setFeature("btap_uo", skyU)
768
+ sky.additionalProperties.setFeature("btap_ut", skyU)
769
+ sky.additionalProperties.setFeature("btap_id", id)
770
+ sky.additionalProperties.setFeature("btap_type", "skylights")
771
+
772
+ # Outdoor-facing, tubular daylight dome.
773
+ specs = {}
774
+ specs[:type] = :skylight
775
+ specs[:uo ] = skyU
776
+ specs[:shgc] = skySHGC
777
+ dome = TBD.genConstruction(model, specs)
778
+
779
+ id = BTAP::Attributes.surface_types_to_assembly_names["ExteriorTubularDaylightDome"]
780
+
781
+ dome.additionalProperties.setFeature("btap_uo", skyU)
782
+ dome.additionalProperties.setFeature("btap_ut", skyU)
783
+ dome.additionalProperties.setFeature("btap_id", id)
784
+ dome.additionalProperties.setFeature("btap_type", "domes")
785
+
786
+ # Tubular daylight diffuser.
787
+ specs = {}
788
+ specs[:type] = :skylight
789
+ specs[:uo ] = skyU
790
+ specs[:shgc] = skySHGC
791
+ diffuser = TBD.genConstruction(model, specs)
792
+
793
+ id = BTAP::Attributes.surface_types_to_assembly_names["ExteriorTubularDaylightDiffuser"]
794
+
795
+ diffuser.additionalProperties.setFeature("btap_uo", skyU)
796
+ diffuser.additionalProperties.setFeature("btap_ut", skyU)
797
+ diffuser.additionalProperties.setFeature("btap_id", id)
798
+ diffuser.additionalProperties.setFeature("btap_type", "diffusers")
799
+
800
+ # Interzone/partition wall.
801
+ specs = {}
802
+ specs[:type ] = :partition
803
+ specs[:clad ] = :none if frm == :cmu
804
+ specs[:finish] = :none if frm == :cmu
805
+ specs[:frame ] = :medium if frm == :cmu
806
+ iWall = TBD.genConstruction(model, specs)
807
+
808
+ # Interzone roof/ceiling & floor.
809
+ specs = {}
810
+ specs[:type ] = :partition
811
+ specs[:frame ] = :medium unless frm == :wood
812
+ specs[:frame ] = :heavy if ctg == "housing" && stc == :concrete
813
+ specs[:frame ] = :heavy if ctg == "lodging" && stc == :concrete
814
+ specs[:frame ] = :heavy if ctg == "robust"
815
+ specs[:clad ] = :none if ctg == "robust"
816
+ specs[:finish] = :none if ctg == "robust"
817
+ iRoof = TBD.genConstruction(model, specs)
818
+ iFloor = TBD.genConstruction(model, specs)
819
+
820
+ solSPACE = OpenStudio::Model::DefaultSurfaceConstructions.new(model)
821
+ intSPACE = OpenStudio::Model::DefaultSurfaceConstructions.new(model)
822
+ subSPACE = OpenStudio::Model::DefaultSubSurfaceConstructions.new(model)
823
+ solSPACE.setName("BTAP ground constructions BLDG")
824
+ intSPACE.setName("BTAP interior constructions BLDG")
825
+ subSPACE.setName("BTAP subsurface constructions BLDG")
826
+ extSPACE.setName("BTAP exterior constructions BLDG")
827
+ solSPACE.setWallConstruction(gWall)
828
+ solSPACE.setFloorConstruction(gFloor)
829
+ solSPACE.setRoofCeilingConstruction(gRoof)
830
+ intSPACE.setWallConstruction(iWall)
831
+ intSPACE.setFloorConstruction(iFloor)
832
+ intSPACE.setRoofCeilingConstruction(iRoof)
833
+ subSPACE.setFixedWindowConstruction(fWindow)
834
+ subSPACE.setOperableWindowConstruction(oWindow)
835
+ subSPACE.setGlassDoorConstruction(gDoor)
836
+ subSPACE.setSkylightConstruction(sky)
837
+ subSPACE.setTubularDaylightDomeConstruction(dome)
838
+ subSPACE.setTubularDaylightDiffuserConstruction(diffuser)
839
+ subSPACE.setDoorConstruction(eDoor)
840
+ subSPACE.setOverheadDoorConstruction(oDoor)
841
+
842
+ setSPACE.setName("BTAP construction set BLDG")
843
+ setSPACE.setDefaultGroundContactSurfaceConstructions(solSPACE)
844
+ setSPACE.setSpaceShadingConstruction(shading)
845
+ setSPACE.setBuildingShadingConstruction(shading)
846
+ setSPACE.setSiteShadingConstruction(shading)
847
+ setSPACE.setDefaultExteriorSubSurfaceConstructions(subSPACE)
848
+ setSPACE.setDefaultInteriorSurfaceConstructions(intSPACE)
849
+ setSPACE.setAdiabaticSurfaceConstruction(iWall)
850
+ setSPACE.setInteriorPartitionConstruction(iWall)
851
+
852
+ model.getSurfaces.each do |surface|
853
+ next unless surface.outsideBoundaryCondition.downcase == "adiabatic"
854
+
855
+ if surface.surfaceType.downcase == "wall"
856
+ surface.setConstruction(iWall)
857
+ else
858
+ surface.setConstruction(iFloor)
859
+ end
860
+ end
861
+ end
817
862
 
818
863
  # Unconditioned, unoccupied spaces (e.g. attics) inherit their own
819
864
  # default construction set. Indirectly-conditioned, unoccupied spaces
@@ -821,14 +866,22 @@ class NECB2011
821
866
  attics = []
822
867
  plenums = []
823
868
 
824
- model.getSpaces.each do |space|
825
- prop = space.additionalProperties.getFeatureAsString(tag)
826
- next if prop.empty?
869
+ spaces.each do |space|
827
870
  next if space.partofTotalFloorArea
828
871
 
829
- prop = prop.get.downcase
830
- attics << space if prop == "unconditioned"
831
- plenums << space if prop == "nonresconditioned"
872
+ group = TBD.unconditioned?(space) ? attics : plenums
873
+ group << space
874
+ end
875
+
876
+ if bldg
877
+ model.getBuilding.setDefaultConstructionSet(setSPACE)
878
+ else
879
+ spaces.each do |space|
880
+ next if attics.include?(space)
881
+ next if plenums.include?(space)
882
+
883
+ space.setDefaultConstructionSet(setSPACE)
884
+ end
832
885
  end
833
886
 
834
887
  # None of the outdoor-facing surfaces of attics are required to be
@@ -873,37 +926,83 @@ class NECB2011
873
926
  specs[:finish] = :none
874
927
  eAtticFloor = TBD.genConstruction(model, specs)
875
928
 
876
- specs = {}
877
- specs[:type ] = :partition
878
- specs[:uo ] = eWallU
879
- iAtticWall = TBD.genConstruction(model, specs)
929
+ specs = {}
930
+ specs[:type ] = :partition
931
+ specs[:uo ] = eWallU
932
+ iAtticWall = TBD.genConstruction(model, specs)
880
933
 
881
934
  lyr = TBD.insulatingLayer(iAtticWall)
882
935
  TBD.assignUniqueMaterial(iAtticWall, lyr[:index]) if lyr[:index]
883
936
 
937
+ argh[:perform ] = :lp
938
+ argh[:stype ] = :walls
939
+ argh[:uo ] = eWallU
940
+ id = BTAP::Bridging.costed_assembly(argh)
941
+
942
+ iAtticWall.additionalProperties.setFeature("btap_uo", eWallU)
943
+ iAtticWall.additionalProperties.setFeature("btap_ut", eWallU)
944
+ iAtticWall.additionalProperties.setFeature("btap_id", id)
945
+ iAtticWall.additionalProperties.setFeature("btap_type", "iwalls")
946
+
947
+ # Add default exterior wall construction properties to building or spaces.
948
+ attics.each do |sp|
949
+ sp.additionalProperties.setFeature("btap_uo", eWallU)
950
+ sp.additionalProperties.setFeature("btap_ut", eWallU)
951
+ sp.additionalProperties.setFeature("btap_id", id)
952
+ sp.additionalProperties.setFeature("btap_type", "iwalls")
953
+ end
954
+
955
+ # Interzone (insulated) attic 'floors': insulation levels should match
956
+ # 'exposed roof' presciptive requirements of CONDITIONED spaces below.
884
957
  specs = {}
885
- specs[:type ] = :floor
886
- specs[:uo ] = eFloorU
887
- specs[:frame ] = :heavy
888
- specs[:finish] = :none
889
- specs[:finish] = :heavy if structure == :concrete
890
- iAtticFloor = TBD.genConstruction(model, specs)
958
+ specs[:type ] = :partition
959
+ specs[:uo ] = eRoofU
960
+ specs[:frame ] = :medium unless frm == :wood
961
+ specs[:frame ] = :heavy if ctg == "housing" && stc == :concrete
962
+ specs[:frame ] = :heavy if ctg == "lodging" && stc == :concrete
963
+ specs[:frame ] = :heavy if ctg == "robust"
964
+ specs[:clad ] = :none if ctg == "robust"
965
+ specs[:finish] = :none if ctg == "robust"
966
+ iAtticFloor = TBD.genConstruction(model, specs)
891
967
 
892
968
  lyr = TBD.insulatingLayer(iAtticFloor)
893
969
  TBD.assignUniqueMaterial(iAtticFloor, lyr[:index]) if lyr[:index]
894
970
 
971
+ argh[:perform] = :lp
972
+ argh[:stype ] = :roofs
973
+ id = BTAP::Bridging.costed_assembly(argh)
974
+
975
+ iAtticFloor.additionalProperties.setFeature("btap_uo", eRoofU)
976
+ iAtticFloor.additionalProperties.setFeature("btap_ut", eRoofU)
977
+ iAtticFloor.additionalProperties.setFeature("btap_id", id)
978
+ iAtticFloor.additionalProperties.setFeature("btap_type", "iroofs")
979
+
980
+ # Interzone (insulated) attic 'roofs' may be suitable for UNCONDITIONED
981
+ # crawlspaces (with CONDITIONED spaces above). Insulation levels should
982
+ # match 'exposed floor' presciptive requirements.
895
983
  specs = {}
896
- specs[:type ] = :floor
897
- specs[:uo ] = eRoofU
898
- specs[:frame ] = :light
899
- specs[:frame ] = :heavy if framing == :wood
900
- specs[:clad ] = :none
901
- specs[:clad ] = :heavy if category == "robust"
902
- iAtticRoof = TBD.genConstruction(model, specs)
984
+ specs[:type ] = :partition
985
+ specs[:uo ] = eFloorU
986
+ specs[:frame ] = :medium unless frm == :wood
987
+ specs[:frame ] = :heavy if ctg == "housing" && stc == :concrete
988
+ specs[:frame ] = :heavy if ctg == "lodging" && stc == :concrete
989
+ specs[:frame ] = :heavy if ctg == "robust"
990
+ specs[:clad ] = :none if ctg == "robust"
991
+ specs[:finish] = :none if ctg == "robust"
992
+ iAtticRoof = TBD.genConstruction(model, specs)
903
993
 
904
994
  lyr = TBD.insulatingLayer(iAtticRoof)
905
995
  TBD.assignUniqueMaterial(iAtticRoof, lyr[:index]) if lyr[:index]
906
996
 
997
+ argh[:perform] = :lp
998
+ argh[:stype ] = :floors
999
+ id = BTAP::Bridging.costed_assembly(argh)
1000
+
1001
+ iAtticRoof.additionalProperties.setFeature("btap_uo", eFloorU)
1002
+ iAtticRoof.additionalProperties.setFeature("btap_ut", eFloorU)
1003
+ iAtticRoof.additionalProperties.setFeature("btap_id", id)
1004
+ iAtticRoof.additionalProperties.setFeature("btap_type", "ifloors")
1005
+
907
1006
  intATTIC = OpenStudio::Model::DefaultSurfaceConstructions.new(model)
908
1007
  solATTIC = OpenStudio::Model::DefaultSurfaceConstructions.new(model)
909
1008
  extATTIC = OpenStudio::Model::DefaultSurfaceConstructions.new(model)
@@ -933,7 +1032,7 @@ class NECB2011
933
1032
  # Treat interzone 'plenum' floors as uninsulated ceiling tiles.
934
1033
  unless plenums.empty?
935
1034
  specs = {}
936
- specs[:type ] = :partition
1035
+ specs[:type ] = :ceiling
937
1036
  specs[:uo ] = nil
938
1037
  specs[:clad ] = :none
939
1038
  specs[:finish] = :none
@@ -958,10 +1057,6 @@ class NECB2011
958
1057
  # - check if insulated when required
959
1058
  # - ensure uninsulated assemblies unless required
960
1059
  # - hard assign constructions if either case
961
- #
962
- # Future upgrades could include adding story- or space-specific default
963
- # construction sets (e.g. CMU walls of a school gym in an otherwise
964
- # steel-framed school). @todo
965
1060
 
966
1061
  true
967
1062
  end
@@ -977,38 +1072,47 @@ class NECB2011
977
1072
 
978
1073
  def apply_standard_construction_properties(model:,
979
1074
  runner: nil,
980
- # ext surfaces
1075
+
1076
+ # Exterior surfaces
981
1077
  ext_wall_cond: nil,
982
1078
  ext_floor_cond: nil,
983
1079
  ext_roof_cond: nil,
984
- # ground surfaces
1080
+
1081
+ # Ground surfaces
985
1082
  ground_wall_cond: nil,
986
1083
  ground_floor_cond: nil,
987
1084
  ground_roof_cond: nil,
988
- # fixed Windows
1085
+
1086
+ # Fixed windows
989
1087
  fixed_window_cond: nil,
990
1088
  fixed_wind_solar_trans: nil,
991
1089
  fixed_wind_vis_trans: nil,
992
- # operable windows
1090
+
1091
+ # Operable windows
993
1092
  operable_wind_solar_trans: nil,
994
1093
  operable_window_cond: nil,
995
1094
  operable_wind_vis_trans: nil,
996
- # glass doors
1095
+
1096
+ # Glass doors
997
1097
  glass_door_cond: nil,
998
1098
  glass_door_solar_trans: nil,
999
1099
  glass_door_vis_trans: nil,
1000
- # opaque doors
1100
+
1101
+ # Opaque doors
1001
1102
  door_construction_cond: nil,
1002
1103
  overhead_door_cond: nil,
1003
- # skylights
1104
+
1105
+ # Skylights
1004
1106
  skylight_cond: nil,
1005
1107
  skylight_solar_trans: nil,
1006
1108
  skylight_vis_trans: nil,
1007
- # tubular daylight dome
1109
+
1110
+ # Tubular daylight domes
1008
1111
  tubular_daylight_dome_cond: nil,
1009
1112
  tubular_daylight_dome_solar_trans: nil,
1010
1113
  tubular_daylight_dome_vis_trans: nil,
1011
- # tubular daylight diffuser
1114
+
1115
+ # Tubular daylight diffusers
1012
1116
  tubular_daylight_diffuser_cond: nil,
1013
1117
  tubular_daylight_diffuser_solar_trans: nil,
1014
1118
  tubular_daylight_diffuser_vis_trans: nil,
@@ -1021,12 +1125,12 @@ class NECB2011
1021
1125
  BTAP.runner_register('Error', 'Weather file is not defined. Please ensure the weather file is defined and exists.', runner)
1022
1126
  return false
1023
1127
  end
1024
-
1025
- # hdd required in scope for eval function.
1026
1128
  hdd = get_necb_hdd18(model: model, necb_hdd: necb_hdd)
1027
- # Lambdas are preferred over methods in methods for small utility methods.
1028
- correct_cond = lambda do |conductivity, surface_type|
1029
- return conductivity.nil? || conductivity.to_f <= 0.0 || conductivity == 'NECB_Default' ? eval(model_find_objects(@standards_data['surface_thermal_transmittance'], surface_type)[0]['formula']) : conductivity.to_f
1129
+ correct_cond = lambda do |conductivity, surface_type, boundary_condition|
1130
+ return conductivity.nil? ||
1131
+ conductivity.to_f <= 0.0 ||
1132
+ conductivity == 'NECB_Default' ?
1133
+ max_u_necb(surface_type, boundary_condition, hdd) : conductivity.to_f
1030
1134
  end
1031
1135
 
1032
1136
  # Converts trans and vis to nil if requesting default.. or casts the string to a float.
@@ -1034,45 +1138,54 @@ class NECB2011
1034
1138
  return value.nil? || value.to_f <= 0.0 || value == 'NECB_Default' ? nil : value.to_f
1035
1139
  end
1036
1140
 
1037
- BTAP::Resources::Envelope::ConstructionSets.customize_default_surface_construction_set!(model: model,
1038
- name: "#{default_surface_construction_set.name.get} at hdd = #{get_necb_hdd18(model: model, necb_hdd: necb_hdd)}",
1039
- default_surface_construction_set: default_surface_construction_set,
1040
- # ext surfaces
1041
- ext_wall_cond: correct_cond.call(ext_wall_cond, 'boundary_condition' => 'Outdoors', 'surface' => 'Wall'),
1042
- ext_floor_cond: correct_cond.call(ext_floor_cond, 'boundary_condition' => 'Outdoors', 'surface' => 'Floor'),
1043
- ext_roof_cond: correct_cond.call(ext_roof_cond, 'boundary_condition' => 'Outdoors', 'surface' => 'RoofCeiling'),
1044
- # ground surfaces
1045
- ground_wall_cond: correct_cond.call(ground_wall_cond, 'boundary_condition' => 'Ground', 'surface' => 'Wall'),
1046
- ground_floor_cond: correct_cond.call(ground_floor_cond, 'boundary_condition' => 'Ground', 'surface' => 'Floor'),
1047
- ground_roof_cond: correct_cond.call(ground_roof_cond, 'boundary_condition' => 'Ground', 'surface' => 'RoofCeiling'),
1048
- # fixed Windows
1049
- fixed_window_cond: correct_cond.call(fixed_window_cond, 'boundary_condition' => 'Outdoors', 'surface' => 'Window'),
1050
- fixed_wind_solar_trans: correct_vis_trans.call(fixed_wind_solar_trans),
1051
- fixed_wind_vis_trans: correct_vis_trans.call(fixed_wind_vis_trans),
1052
- # operable windows
1053
- operable_wind_solar_trans: correct_vis_trans.call(operable_wind_solar_trans),
1054
- operable_window_cond: correct_cond.call(fixed_window_cond, 'boundary_condition' => 'Outdoors', 'surface' => 'Window'),
1055
- operable_wind_vis_trans: correct_vis_trans.call(operable_wind_vis_trans),
1056
- # glass doors
1057
- glass_door_cond: correct_cond.call(glass_door_cond, 'boundary_condition' => 'Outdoors', 'surface' => 'Window'),
1058
- glass_door_solar_trans: correct_vis_trans.call(glass_door_solar_trans),
1059
- glass_door_vis_trans: correct_vis_trans.call(glass_door_vis_trans),
1060
- # opaque doors
1061
- door_construction_cond: correct_cond.call(door_construction_cond, 'boundary_condition' => 'Outdoors', 'surface' => 'Door'),
1062
- overhead_door_cond: correct_cond.call(overhead_door_cond, 'boundary_condition' => 'Outdoors', 'surface' => 'Door'),
1063
- # skylights
1064
- skylight_cond: correct_cond.call(skylight_cond, 'boundary_condition' => 'Outdoors', 'surface' => 'Window'),
1065
- skylight_solar_trans: correct_vis_trans.call(skylight_solar_trans),
1066
- skylight_vis_trans: correct_vis_trans.call(skylight_vis_trans),
1067
- # tubular daylight dome
1068
- tubular_daylight_dome_cond: correct_cond.call(skylight_cond, 'boundary_condition' => 'Outdoors', 'surface' => 'Window'),
1069
- tubular_daylight_dome_solar_trans: correct_vis_trans.call(tubular_daylight_dome_solar_trans),
1070
- tubular_daylight_dome_vis_trans: correct_vis_trans.call(tubular_daylight_dome_vis_trans),
1071
- # tubular daylight diffuser
1072
- tubular_daylight_diffuser_cond: correct_cond.call(skylight_cond, 'boundary_condition' => 'Outdoors', 'surface' => 'Window'),
1073
- tubular_daylight_diffuser_solar_trans: correct_vis_trans.call(tubular_daylight_diffuser_solar_trans),
1074
- tubular_daylight_diffuser_vis_trans: correct_vis_trans.call(tubular_daylight_diffuser_vis_trans))
1141
+ BTAP::Resources::Envelope::ConstructionSets.customize_default_surface_construction_set!(
1142
+ model: model,
1143
+ name: "#{default_surface_construction_set.name.get} at hdd = #{hdd}",
1144
+ default_surface_construction_set: default_surface_construction_set,
1145
+
1146
+ # Exterior surfaces
1147
+ ext_wall_cond: correct_cond.call(ext_wall_cond, 'wall', 'outdoors'),
1148
+ ext_floor_cond: correct_cond.call(ext_floor_cond, 'floor', 'outdoors'),
1149
+ ext_roof_cond: correct_cond.call(ext_roof_cond, 'roofceiling', 'outdoors'),
1150
+
1151
+ # Ground surfaces
1152
+ ground_wall_cond: correct_cond.call(ground_wall_cond, 'wall', 'ground'),
1153
+ ground_floor_cond: correct_cond.call(ground_floor_cond, 'floor', 'ground'),
1154
+ ground_roof_cond: correct_cond.call(ground_roof_cond, 'roofceiling', 'ground'),
1155
+ fixed_window_cond: correct_cond.call(fixed_window_cond, 'window', 'outdoors'),
1156
+ fixed_wind_solar_trans: correct_vis_trans.call(fixed_wind_solar_trans),
1157
+ fixed_wind_vis_trans: correct_vis_trans.call(fixed_wind_vis_trans),
1158
+
1159
+ # Operable windows
1160
+ operable_wind_solar_trans: correct_vis_trans.call(operable_wind_solar_trans),
1161
+ operable_window_cond: correct_cond.call(fixed_window_cond, 'window', 'outdoors'),
1162
+ operable_wind_vis_trans: correct_vis_trans.call(operable_wind_vis_trans),
1163
+
1164
+ # Glass doors
1165
+ glass_door_cond: correct_cond.call(glass_door_cond, 'window', 'outdoors'),
1166
+ glass_door_solar_trans: correct_vis_trans.call(glass_door_solar_trans),
1167
+ glass_door_vis_trans: correct_vis_trans.call(glass_door_vis_trans),
1168
+
1169
+ # Opaque doors
1170
+ door_construction_cond: correct_cond.call(door_construction_cond, 'door', 'outdoors'),
1171
+ overhead_door_cond: correct_cond.call(overhead_door_cond, 'door', 'outdoors'),
1172
+
1173
+ # Skylights
1174
+ skylight_cond: correct_cond.call(skylight_cond, 'window', 'outdoors'),
1175
+ skylight_solar_trans: correct_vis_trans.call(skylight_solar_trans),
1176
+ skylight_vis_trans: correct_vis_trans.call(skylight_vis_trans),
1177
+
1178
+ # Tubular daylight domes
1179
+ tubular_daylight_dome_cond: correct_cond.call(skylight_cond, 'window', 'outdoors'),
1180
+ tubular_daylight_dome_solar_trans: correct_vis_trans.call(tubular_daylight_dome_solar_trans),
1181
+ tubular_daylight_dome_vis_trans: correct_vis_trans.call(tubular_daylight_dome_vis_trans),
1182
+
1183
+ # Tubular daylight diffusers
1184
+ tubular_daylight_diffuser_cond: correct_cond.call(skylight_cond, 'window', 'outdoors'),
1185
+ tubular_daylight_diffuser_solar_trans: correct_vis_trans.call(tubular_daylight_diffuser_solar_trans),
1186
+ tubular_daylight_diffuser_vis_trans: correct_vis_trans.call(tubular_daylight_diffuser_vis_trans))
1075
1187
  end
1188
+
1076
1189
  # sets all surfaces to use default constructions sets except adiabatic, where it does a hard assignment of the interior wall construction type.
1077
1190
  model.getPlanarSurfaces.sort.each(&:resetConstruction)
1078
1191
  # if the default construction set is defined..try to assign the interior wall to the adiabatic surfaces
@@ -1216,10 +1329,13 @@ class NECB2011
1216
1329
  end
1217
1330
 
1218
1331
  def assign_contruction_to_adiabatic_surfaces(model)
1219
- cp02_carpet_pad = OpenStudio::Model::MasslessOpaqueMaterial.new(model)
1332
+ cp02_carpet_pad = OpenStudio::Model::StandardOpaqueMaterial.new(model)
1220
1333
  cp02_carpet_pad.setName('CP02 CARPET PAD')
1221
1334
  cp02_carpet_pad.setRoughness('VeryRough')
1222
- cp02_carpet_pad.setThermalResistance(0.21648)
1335
+ cp02_carpet_pad.setThickness(0.01)
1336
+ cp02_carpet_pad.setConductivity(0.06)
1337
+ cp02_carpet_pad.setDensity(200)
1338
+ cp02_carpet_pad.setSpecificHeat(1360)
1223
1339
  cp02_carpet_pad.setThermalAbsorptance(0.9)
1224
1340
  cp02_carpet_pad.setSolarAbsorptance(0.7)
1225
1341
  cp02_carpet_pad.setVisibleAbsorptance(0.8)
@@ -1232,13 +1348,16 @@ class NECB2011
1232
1348
  normalweight_concrete_floor.setDensity(2322)
1233
1349
  normalweight_concrete_floor.setSpecificHeat(832)
1234
1350
 
1235
- nonres_floor_insulation = OpenStudio::Model::MasslessOpaqueMaterial.new(model)
1351
+ nonres_floor_insulation = OpenStudio::Model::StandardOpaqueMaterial.new(model)
1236
1352
  nonres_floor_insulation.setName('Nonres_Floor_Insulation')
1237
1353
  nonres_floor_insulation.setRoughness('MediumSmooth')
1238
- nonres_floor_insulation.setThermalResistance(2.88291975297193)
1354
+ nonres_floor_insulation.setThickness(0.083)
1355
+ nonres_floor_insulation.setConductivity(0.029)
1356
+ nonres_floor_insulation.setDensity(29)
1357
+ nonres_floor_insulation.setSpecificHeat(1210)
1239
1358
  nonres_floor_insulation.setThermalAbsorptance(0.9)
1240
1359
  nonres_floor_insulation.setSolarAbsorptance(0.7)
1241
- nonres_floor_insulation.setVisibleAbsorptance(0.7)
1360
+ nonres_floor_insulation.setVisibleAbsorptance(0.8)
1242
1361
 
1243
1362
  floor_adiabatic_construction = OpenStudio::Model::Construction.new(model)
1244
1363
  floor_adiabatic_construction.setName('Floor Adiabatic construction')
@@ -1416,8 +1535,27 @@ class NECB2011
1416
1535
  # like exterior walls). The method returns a building 'gross roof area' (see attr_reader :osut), which
1417
1536
  # excludes the area of attic roof overhangs.
1418
1537
  def apply_max_srr_nrcan(model:, srr_lim:, srr_opt: '')
1538
+ # Check if default construction set exists
1539
+ unless model.getBuilding.defaultConstructionSet.is_initialized
1540
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.Model', 'No default construction set defined. Cannot apply SRR.')
1541
+ return false
1542
+ end
1543
+
1419
1544
  construct_set = model.getBuilding.defaultConstructionSet.get
1420
- skylight_construct_set = construct_set.defaultExteriorSubSurfaceConstructions.get.skylightConstruction.get
1545
+
1546
+ # Check if skylight construction exists
1547
+ unless construct_set.defaultExteriorSubSurfaceConstructions.is_initialized
1548
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.Model', 'No default exterior subsurface constructions defined. Cannot apply SRR.')
1549
+ return false
1550
+ end
1551
+
1552
+ ext_subsurface = construct_set.defaultExteriorSubSurfaceConstructions.get
1553
+ unless ext_subsurface.skylightConstruction.is_initialized
1554
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.Model', 'No skylight construction defined. Cannot apply SRR.')
1555
+ return false
1556
+ end
1557
+
1558
+ skylight_construct_set = ext_subsurface.skylightConstruction.get
1421
1559
 
1422
1560
  unless srr_opt.to_s.downcase == 'osut' # OPTION A
1423
1561
  # First determine which roof surfaces are adjacent to heated spaces (both plenum and non-plenum).