openstudio-standards 0.2.12.rc4 → 0.2.12.rc5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/data/standards/OpenStudio_Standards-ashrae_90_1(space_types).xlsx +0 -0
  3. data/data/standards/OpenStudio_Standards-ashrae_90_1.xlsx +0 -0
  4. data/data/standards/test_performance_expected_dd_results.csv +950 -950
  5. data/lib/openstudio-standards.rb +8 -1
  6. data/lib/openstudio-standards/btap/btap.model.rb +1 -1
  7. data/lib/openstudio-standards/btap/economics.rb +14 -11
  8. data/lib/openstudio-standards/btap/envelope.rb +185 -257
  9. data/lib/openstudio-standards/btap/fileio.rb +1 -0
  10. data/lib/openstudio-standards/btap/geometry.rb +21 -1
  11. data/lib/openstudio-standards/btap/measures.rb +12 -11
  12. data/lib/openstudio-standards/btap/schedules.rb +3 -12
  13. data/lib/openstudio-standards/hvac_sizing/Siz.AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.rb +178 -0
  14. data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingDXMultiSpeed.rb +8 -8
  15. data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +3 -0
  16. data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +3 -3
  17. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +25 -23
  18. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXMultiSpeed.rb +91 -0
  19. data/lib/openstudio-standards/standards/Standards.CoilDX.rb +20 -2
  20. data/lib/openstudio-standards/standards/Standards.CoilHeatingGasMultiStage.rb +39 -0
  21. data/lib/openstudio-standards/standards/Standards.Model.rb +29 -0
  22. data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +37 -4
  23. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.unitary_acs.json +15 -15
  24. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.unitary_acs.json +15 -15
  25. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.unitary_acs.json +5 -5
  26. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.unitary_acs.json +15 -15
  27. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/data/doe_ref_1980_2004.spc_typ.json +5963 -2723
  28. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/data/doe_ref_pre_1980.spc_typ.json +5917 -2697
  29. data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/data/nrel_zne_ready_2017.spc_typ.json +2011 -1112
  30. data/lib/openstudio-standards/standards/ashrae_90_1/ze_aedg_multifamily/data/ze_aedg_multifamily.spc_typ.json +1946 -1106
  31. data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/btap_1980to2010.rb +2 -18
  32. data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/data/space_types.json +1677 -1005
  33. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/btap_pre1980.rb +64 -13
  34. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/building_envelope.rb +31 -19
  35. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/curves.json +75 -0
  36. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/heat_pumps.json +16 -16
  37. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/space_types.json +1677 -1005
  38. data/lib/openstudio-standards/standards/necb/ECMS/data/boiler_set.json +29 -0
  39. data/lib/openstudio-standards/standards/necb/ECMS/data/curves.json +913 -0
  40. data/lib/openstudio-standards/standards/necb/ECMS/data/equip_eff_lim.json +52 -0
  41. data/lib/openstudio-standards/standards/necb/ECMS/data/erv.json +105 -0
  42. data/lib/openstudio-standards/standards/necb/ECMS/data/furnace_set.json +23 -0
  43. data/lib/openstudio-standards/standards/necb/ECMS/data/heat_pumps.json +803 -0
  44. data/lib/openstudio-standards/standards/necb/ECMS/data/heat_pumps_heating.json +787 -0
  45. data/lib/openstudio-standards/standards/necb/ECMS/data/shw_set.json +29 -0
  46. data/lib/openstudio-standards/standards/necb/ECMS/ecms.rb +87 -0
  47. data/lib/openstudio-standards/standards/necb/ECMS/erv.rb +22 -0
  48. data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +1593 -0
  49. data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +68 -33
  50. data/lib/openstudio-standards/standards/necb/NECB2011/beps_compliance_path.rb +24 -13
  51. data/lib/openstudio-standards/standards/necb/NECB2011/building_envelope.rb +104 -99
  52. data/lib/openstudio-standards/standards/necb/NECB2011/data/constants.json +24 -24
  53. data/lib/openstudio-standards/standards/necb/NECB2011/data/curves.json +50 -0
  54. data/lib/openstudio-standards/standards/necb/NECB2011/data/erv.json +31 -0
  55. data/lib/openstudio-standards/standards/necb/NECB2011/data/led_lighting_data.json +2028 -0
  56. data/lib/openstudio-standards/standards/necb/NECB2011/data/space_types.json +1745 -1297
  57. data/lib/openstudio-standards/standards/necb/NECB2011/daylighting_control.md +70 -0
  58. data/lib/openstudio-standards/standards/necb/NECB2011/demand_controlled_ventilation.md +46 -0
  59. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_multi_speed.rb +69 -107
  60. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_single_speed.rb +24 -1
  61. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_multi_speed.rb +139 -141
  62. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_single_speed.rb +24 -0
  63. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +344 -234
  64. data/lib/openstudio-standards/standards/necb/NECB2011/led_lighting.md +51 -0
  65. data/lib/openstudio-standards/standards/necb/NECB2011/lighting.rb +57 -9
  66. data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +1060 -34
  67. data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +9 -1
  68. data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +1 -1
  69. data/lib/openstudio-standards/standards/necb/NECB2015/data/led_lighting_data.json +2883 -0
  70. data/lib/openstudio-standards/standards/necb/NECB2015/data/space_types.json +2554 -1916
  71. data/lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb +32 -1
  72. data/lib/openstudio-standards/standards/necb/NECB2017/data/led_lighting_data.json +2883 -0
  73. data/lib/openstudio-standards/standards/necb/NECB2017/data/space_types.json +2554 -1916
  74. data/lib/openstudio-standards/standards/necb/NECB2017/necb_2017.rb +29 -0
  75. data/lib/openstudio-standards/version.rb +1 -1
  76. metadata +21 -2
@@ -52,7 +52,7 @@ class NECB2011
52
52
  # Some expections are dwelling units wet zone and wild zones. These spaces will have special considerations when autozoning a
53
53
  # building.
54
54
 
55
- def apply_auto_zoning(model:, sizing_run_dir: Dir.pwd)
55
+ def apply_auto_zoning(model:, sizing_run_dir: Dir.pwd, lights_type: 'NECB_Default', lights_scale: 1.0)
56
56
  raise('validation of model failed.') unless validate_initial_model(model)
57
57
 
58
58
  # Check to see if model is using another vintage of spacetypes. If so overwrite the @standards for the object with the
@@ -82,9 +82,9 @@ class NECB2011
82
82
  # Remove any Thermal zones assigned again to start fresh.
83
83
  model.getThermalZones.each(&:remove)
84
84
  self.auto_zone_dwelling_units(model)
85
- self.auto_zone_wet_spaces(model)
85
+ self.auto_zone_wet_spaces(model: model, lights_type: lights_type, lights_scale: lights_scale)
86
86
  self.auto_zone_all_other_spaces(model)
87
- self.auto_zone_wild_spaces(model)
87
+ self.auto_zone_wild_spaces(model: model, lights_type: lights_type, lights_scale: lights_scale)
88
88
  #THis will color the spaces and zones.
89
89
  random = Random.new(1234)
90
90
  #Set ideal hvac in case we want to not implement the hvac yet and still run osm right after this function.
@@ -193,6 +193,7 @@ class NECB2011
193
193
  # set a larger tolerance for unmet hours from default 0.2 to 1.0C
194
194
  model.getOutputControlReportingTolerances.setToleranceforTimeHeatingSetpointNotMet(1.0)
195
195
  model.getOutputControlReportingTolerances.setToleranceforTimeCoolingSetpointNotMet(1.0)
196
+
196
197
  end
197
198
 
198
199
  # Method to store space sizing loads. This is needed because later when the zones are destroyed this information will be lost.
@@ -283,7 +284,8 @@ class NECB2011
283
284
  # Something that the code is silent on are smelly humid areas that should not be on the same system as the rest of the
284
285
  # building.. These are the 'wet' spaces and have been defined as locker and washroom areas.. These will be put under
285
286
  # their own single system 4 system. These will be set to the dominant floor schedule.
286
- def auto_zone_wet_spaces(model)
287
+
288
+ def auto_zone_wet_spaces(model:, lights_type: 'NECB_Default', lights_scale: 1.0)
287
289
  wet_zone_array = Array.new
288
290
  model.getSpaces.select {|space| is_an_necb_wet_space?(space)}.each do |space|
289
291
  #if this space was already assigned to something skip it.
@@ -302,7 +304,8 @@ class NECB2011
302
304
 
303
305
  #this method will determine if the right schedule was used for this wet & wild space if not.. it will reset the space
304
306
  # to use the correct schedule version of the wet and wild space type.
305
- adjust_wildcard_spacetype_schedule(space, dominant_schedule)
307
+ adjust_wildcard_spacetype_schedule(space: space, schedule: dominant_schedule, lights_type: lights_type, lights_scale: lights_scale)
308
+
306
309
  #Find spacetype thermostat and assign it to the zone.
307
310
  thermostat_name = space.spaceType.get.name.get + ' Thermostat'
308
311
  thermostat = model.getThermostatSetpointDualSetpointByName(thermostat_name)
@@ -320,7 +323,7 @@ class NECB2011
320
323
  model.getSpaces.select {|s| is_an_necb_wet_space?(s)}.each do |space_target|
321
324
  if space_target.thermalZone.empty?
322
325
  if are_space_loads_similar?(space_1: space, space_2: space_target) && space.buildingStory().get == space_target.buildingStory().get # added since chris needs zones to not span floors for costing.
323
- adjust_wildcard_spacetype_schedule(space_target, dominant_schedule)
326
+ adjust_wildcard_spacetype_schedule(space_target, dominant_schedule, lights_type, lights_scale, space_height)
324
327
  space_target.setThermalZone(zone)
325
328
  end
326
329
  end
@@ -379,7 +382,7 @@ class NECB2011
379
382
 
380
383
  # This will take all the wildcard spaces and merge them to be supported by a system 4. The control zone will be the
381
384
  # zone that has the largest heating load per area.
382
- def auto_zone_wild_spaces(model)
385
+ def auto_zone_wild_spaces(model:, lights_type: 'NECB_Default', lights_scale: 1.0)
383
386
  other_tz_array = Array.new
384
387
  #iterate through wildcard spaces.
385
388
  model.getSpaces.select {|space| is_an_necb_wildcard_space?(space) and not is_an_necb_wet_space?(space)}.each do |space|
@@ -396,10 +399,13 @@ class NECB2011
396
399
  #Assign space to the new zone.
397
400
  space.setThermalZone(zone)
398
401
 
399
- #lets keep the wild schedules to be the same as what dominate the floor.
402
+ # lets keep the wild schedules to be the same as what dominate the floor.
400
403
  dominant_floor_schedule = determine_dominant_schedule(space.model.getSpaces)
401
404
 
402
- adjust_wildcard_spacetype_schedule(space, dominant_floor_schedule)
405
+ adjust_wildcard_spacetype_schedule(space: space,
406
+ schedule: dominant_floor_schedule,
407
+ lights_type: lights_type,
408
+ lights_scale: lights_scale)
403
409
 
404
410
  # Add a thermostat
405
411
  space_type_name = space.spaceType.get.name.get
@@ -464,7 +470,7 @@ class NECB2011
464
470
  schedule_type = determine_dominant_schedule(space.buildingStory.get.spaces)
465
471
  zone = other_adjacent_spaces.first.thermalZone.get
466
472
  wild_adjacent_spaces.each do |space|
467
- adjust_wildcard_spacetype_schedule(space, schedule_type)
473
+ adjust_wildcard_spacetype_schedule(space, schedule_type, @lights_type, @lights_scale, @space_height)
468
474
  space.setThermalZone(zone)
469
475
  end
470
476
  end
@@ -483,7 +489,7 @@ class NECB2011
483
489
  dominant_floor_schedule = determine_dominant_schedule(space.buildingStory().get.spaces)
484
490
  #this method will determine if the right schedule was used for this wet & wild space if not.. it will reset the space
485
491
  # to use the correct schedule version of the wet and wild space type.
486
- adjust_wildcard_spacetype_schedule(space, dominant_floor_schedule)
492
+ adjust_wildcard_spacetype_schedule(space, dominant_floor_schedule, @lights_type, @lights_scale, @space_height)
487
493
  #Find spacetype thermostat and assign it to the zone.
488
494
  thermostat_name = space.spaceType.get.name.get + ' Thermostat'
489
495
  thermostat = model.getThermostatSetpointDualSetpointByName(thermostat_name)
@@ -502,7 +508,7 @@ class NECB2011
502
508
  if space_target.thermalZone.empty?
503
509
  if are_space_loads_similar?(space_1: space, space_2: space_target) &&
504
510
  space.buildingStory().get == space_target.buildingStory().get # added since chris needs zones to not span floors for costing.
505
- adjust_wildcard_spacetype_schedule(space_target, dominant_floor_schedule)
511
+ adjust_wildcard_spacetype_schedule(space_target, dominant_floor_schedule, @lights_type, @lights_scale, @space_height)
506
512
  space_target.setThermalZone(zone)
507
513
  end
508
514
  end
@@ -708,7 +714,7 @@ class NECB2011
708
714
  end
709
715
 
710
716
  # Set wildcard spactype schedule to NECB letter index.
711
- def adjust_wildcard_spacetype_schedule(space, schedule)
717
+ def adjust_wildcard_spacetype_schedule(space:, schedule:, lights_type: 'NECB_Default', lights_scale: 1.0)
712
718
  if space.spaceType.empty?
713
719
  OpenStudio.logFree(OpenStudio::Error, 'Error: No spacetype assigned for #{space.name.get}. This must be assigned. Aborting.')
714
720
  end
@@ -733,7 +739,7 @@ class NECB2011
733
739
  new_spacetype.setStandardsBuildingType(space.spaceType.get.standardsBuildingType.get)
734
740
  new_spacetype.setStandardsSpaceType(new_spacetype_name)
735
741
  new_spacetype.setName("#{space.spaceType.get.standardsBuildingType.get} #{new_spacetype_name}")
736
- space_type_apply_internal_loads(new_spacetype, true, true, true, true, true, true)
742
+ space_type_apply_internal_loads(space_type: new_spacetype, lights_type: lights_type, lights_scale: lights_scale)
737
743
  space_type_apply_internal_load_schedules(new_spacetype, true, true, true, true, true, true, true)
738
744
  end
739
745
  space.setSpaceType(new_spacetype)
@@ -881,7 +887,8 @@ class NECB2011
881
887
  mau_type: mau_type,
882
888
  mau_heating_coil_type: mau_heating_coil_type,
883
889
  baseboard_type: baseboard_type,
884
- hw_loop: @hw_loop)
890
+ hw_loop: @hw_loop,
891
+ multispeed: false)
885
892
  end
886
893
  when 2
887
894
  group_similar_zones_together(zones).each do |zones|
@@ -894,11 +901,12 @@ class NECB2011
894
901
  end
895
902
  when 3
896
903
  group_similar_zones_together(zones).each do |zones|
897
- add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating_single_speed(model: model,
898
- zones: zones,
899
- heating_coil_type: heating_coil_type_sys3,
900
- baseboard_type: baseboard_type,
901
- hw_loop: @hw_loop)
904
+ add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating(model: model,
905
+ zones: zones,
906
+ heating_coil_type: heating_coil_type_sys3,
907
+ baseboard_type: baseboard_type,
908
+ hw_loop: @hw_loop,
909
+ multispeed: false)
902
910
  end
903
911
  when 4
904
912
  group_similar_zones_together(zones).each do |zones|
@@ -907,6 +915,12 @@ class NECB2011
907
915
  heating_coil_type: heating_coil_type_sys4,
908
916
  baseboard_type: baseboard_type,
909
917
  hw_loop: @hw_loop)
918
+ # add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating(model: model,
919
+ # zones: zones,
920
+ # heating_coil_type: heating_coil_type_sys4,
921
+ # baseboard_type: baseboard_type,
922
+ # hw_loop: @hw_loop,
923
+ # multispeed: false)
910
924
  end
911
925
  when 5
912
926
  group_similar_zones_together(zones).each do |zones|
@@ -1024,7 +1038,8 @@ class NECB2011
1024
1038
  mau_type: mau_type,
1025
1039
  mau_heating_coil_type: mau_heating_coil_type,
1026
1040
  baseboard_type: baseboard_type,
1027
- hw_loop: @hw_loop)
1041
+ hw_loop: @hw_loop,
1042
+ multispeed: false)
1028
1043
  else
1029
1044
  #Create a separate air loop for each unit.
1030
1045
  zones.each do |zone|
@@ -1033,27 +1048,29 @@ class NECB2011
1033
1048
  mau_type: mau_type,
1034
1049
  mau_heating_coil_type: mau_heating_coil_type,
1035
1050
  baseboard_type: baseboard_type,
1036
- hw_loop: @hw_loop)
1051
+ hw_loop: @hw_loop,
1052
+ multispeed: false)
1037
1053
 
1038
1054
  end
1039
1055
  end
1040
1056
 
1041
1057
  when 3
1042
1058
  if dwelling_shared_ahu
1043
- add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating_single_speed(model: model,
1044
- zones: zones,
1045
- heating_coil_type: heating_coil_type_sys3,
1046
- baseboard_type: baseboard_type,
1047
- hw_loop: @hw_loop)
1059
+ add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating(model: model,
1060
+ zones: zones,
1061
+ heating_coil_type: heating_coil_type_sys3,
1062
+ baseboard_type: baseboard_type,
1063
+ hw_loop: @hw_loop,
1064
+ multispeed: false)
1048
1065
  else
1049
1066
  #Create a separate air loop for each unit.
1050
1067
  zones.each do |zone|
1051
- add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating_single_speed(model: model,
1052
- zones: [zone],
1053
- heating_coil_type: heating_coil_type_sys3,
1054
- baseboard_type: baseboard_type,
1055
- hw_loop: @hw_loop)
1056
-
1068
+ add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating(model: model,
1069
+ zones: [zone],
1070
+ heating_coil_type: heating_coil_type_sys3,
1071
+ baseboard_type: baseboard_type,
1072
+ hw_loop: @hw_loop,
1073
+ multispeed: false)
1057
1074
  end
1058
1075
  end
1059
1076
  end
@@ -1079,6 +1096,12 @@ class NECB2011
1079
1096
  heating_coil_type: heating_coil_type_sys4,
1080
1097
  baseboard_type: baseboard_type,
1081
1098
  hw_loop: @hw_loop)
1099
+ # add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating(model: model,
1100
+ # zones: wet_tz,
1101
+ # heating_coil_type: heating_coil_type_sys4,
1102
+ # baseboard_type: baseboard_type,
1103
+ # hw_loop: @hw_loop,
1104
+ # multispeed: false)
1082
1105
  end
1083
1106
  end
1084
1107
 
@@ -1102,6 +1125,12 @@ class NECB2011
1102
1125
  heating_coil_type: heating_coil_type_sys4,
1103
1126
  baseboard_type: baseboard_type,
1104
1127
  hw_loop: @hw_loop)
1128
+ # add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating(model: model,
1129
+ # zones: tz,
1130
+ # heating_coil_type: heating_coil_type_sys4,
1131
+ # baseboard_type: baseboard_type,
1132
+ # hw_loop: @hw_loop,
1133
+ # multispeed: true)
1105
1134
  end
1106
1135
  end
1107
1136
 
@@ -1125,6 +1154,12 @@ class NECB2011
1125
1154
  heating_coil_type: heating_coil_type_sys4,
1126
1155
  baseboard_type: baseboard_type,
1127
1156
  hw_loop: @hw_loop)
1157
+ # add_sys3and8_single_zone_packaged_rooftop_unit_with_baseboard_heating(model: model,
1158
+ # zones: zones,
1159
+ # heating_coil_type: heating_coil_type_sys4,
1160
+ # baseboard_type: baseboard_type,
1161
+ # hw_loop: @hw_loop,
1162
+ # multispeed: true)
1128
1163
  end
1129
1164
  end
1130
1165
 
@@ -14,13 +14,7 @@ class NECB2011
14
14
  space_type.setStandardsBuildingType(spacedata["building_type"])
15
15
  space_type.setName("#{spacedata['building_type']} #{spacedata['space_type']}")
16
16
  # Loads
17
- self.space_type_apply_internal_loads(space_type,
18
- true,
19
- true,
20
- true,
21
- true,
22
- true,
23
- true)
17
+ self.space_type_apply_internal_loads(space_type: space_type)
24
18
 
25
19
  # Schedules
26
20
  self.space_type_apply_internal_load_schedules(space_type,
@@ -36,8 +30,6 @@ class NECB2011
36
30
  end
37
31
 
38
32
 
39
-
40
-
41
33
  # Sets the selected internal loads to standards-based or typical values.
42
34
  # For each category that is selected get all load instances. Remove all
43
35
  # but the first instance if multiple instances. Add a new instance/definition
@@ -55,13 +47,23 @@ class NECB2011
55
47
  # @param set_ventilation [Bool] if true, set the ventilation rates (per-person and per-area)
56
48
  # @param set_infiltration [Bool] if true, set the infiltration rates
57
49
  # @return [Bool] returns true if successful, false if not
58
- def space_type_apply_internal_loads(space_type, set_people, set_lights, set_electric_equipment, set_gas_equipment, set_ventilation, set_infiltration)
50
+ def space_type_apply_internal_loads(space_type:,
51
+ set_people: true,
52
+ set_lights: true,
53
+ set_electric_equipment: true,
54
+ set_gas_equipment: true,
55
+ set_ventilation: true,
56
+ set_infiltration: true,
57
+ lights_type: 'NECB_Default',
58
+ lights_scale: 1.0)
59
+
59
60
  # Skip plenums
60
61
  # Check if the space type name
61
62
  # contains the word plenum.
62
63
  if space_type.name.get.to_s.downcase.include?('plenum')
63
64
  return false
64
65
  end
66
+
65
67
  if space_type.standardsSpaceType.is_initialized
66
68
  if space_type.standardsSpaceType.get.downcase.include?('plenum')
67
69
  return false
@@ -163,7 +165,11 @@ class NECB2011
163
165
  end
164
166
 
165
167
  # Lights
166
- apply_standard_lights(set_lights, space_type, space_type_properties)
168
+ apply_standard_lights(set_lights: set_lights,
169
+ space_type: space_type,
170
+ space_type_properties: space_type_properties,
171
+ lights_type: lights_type,
172
+ lights_scale: lights_scale)
167
173
 
168
174
  # Electric Equipment
169
175
  elec_equip_have_info = false
@@ -266,6 +272,7 @@ class NECB2011
266
272
  ventilation_per_area = space_type_properties['ventilation_per_area'].to_f
267
273
  ventilation_per_person = space_type_properties['ventilation_per_person'].to_f
268
274
  ventilation_ach = space_type_properties['ventilation_air_changes'].to_f
275
+ ventilation_occupancy_per_area = space_type_properties['ventilation_occupancy_rate_people_per_1000ft2'].to_f
269
276
  ventilation_have_info = true unless ventilation_per_area.zero?
270
277
  ventilation_have_info = true unless ventilation_per_person.zero?
271
278
  ventilation_have_info = true unless ventilation_ach.zero?
@@ -290,8 +297,12 @@ class NECB2011
290
297
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.SpaceType', "#{space_type.name} set ventilation per area to #{ventilation_per_area} cfm/ft^2.")
291
298
  end
292
299
  unless ventilation_per_person.zero?
293
- ventilation.setOutdoorAirFlowperPerson(OpenStudio.convert(ventilation_per_person.to_f, 'ft^3/min*person', 'm^3/s*person').get)
294
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.SpaceType', "#{space_type.name} set ventilation per person to #{ventilation_per_person} cfm/person.")
300
+ # For BTAP we often use an occupancy per area rate for ventilation which is different from the one used for
301
+ # everything else. The mod_ventilation_per_person rate adjusts the per person ventilation rate so that the
302
+ # proper ventilation rate is calculated when using the general occupant per area rate.
303
+ mod_ventilation_per_person = ventilation_per_person*ventilation_occupancy_per_area/occupancy_per_area
304
+ ventilation.setOutdoorAirFlowperPerson(OpenStudio.convert(mod_ventilation_per_person.to_f, 'ft^3/min*person', 'm^3/s*person').get)
305
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.SpaceType', "#{space_type.name} set ventilation per person to #{mod_ventilation_per_person} cfm/person.")
295
306
  end
296
307
  unless ventilation_ach.zero?
297
308
  ventilation.setOutdoorAirFlowAirChangesperHour(ventilation_ach)
@@ -1,4 +1,5 @@
1
1
  class NECB2011
2
+
2
3
  # Reduces the WWR to the values specified by the NECB
3
4
  # NECB 3.2.1.4
4
5
  def apply_standard_window_to_wall_ratio(model:, fdwr_set: -1.0)
@@ -141,7 +142,6 @@ class NECB2011
141
142
  red_res = wwr_res > wwr_lim
142
143
  red_sh = wwr_sh > wwr_lim
143
144
 
144
-
145
145
  # puts "Current FDWR is #{fdwr}, must be less than #{fdwr_lim}."
146
146
  # puts "Current subsurf area is #{total_subsurface_m2} and gross surface area is #{total_wall_m2}"
147
147
  # Stop here unless windows / doors need reducing
@@ -271,7 +271,6 @@ class NECB2011
271
271
  srr = ((total_subsurface_m2 / total_roof_m2) * 100.0).round(1)
272
272
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "The skylight to roof ratios (SRRs) are: NonRes: #{srr_nr.round}%, Res: #{srr_res.round}%.")
273
273
 
274
-
275
274
  # Check against SRR limit
276
275
  red_nr = srr_nr > srr_lim
277
276
  red_res = srr_res > srr_lim
@@ -307,8 +306,8 @@ class NECB2011
307
306
  # @param hdd [Float]
308
307
  # @return [Double] a constant float
309
308
  def max_fwdr(hdd)
310
- #get formula from json database.
311
- return eval(self.get_standards_formula('fdwr_formula'))
309
+ # get formula from json database.
310
+ return eval(get_standards_formula('fdwr_formula'))
312
311
  end
313
312
 
314
313
  # Go through the default construction sets and hard-assigned
@@ -322,93 +321,104 @@ class NECB2011
322
321
 
323
322
  def apply_standard_construction_properties(model:,
324
323
  runner: nil,
325
- properties: {
326
- 'outdoors_wall_conductance' => nil,
327
- 'outdoors_floor_conductance' => nil,
328
- 'outdoors_roofceiling_conductance' => nil,
329
- 'ground_wall_conductance' => nil,
330
- 'ground_floor_conductance' => nil,
331
- 'ground_roofceiling_conductance' => nil,
332
- 'outdoors_door_conductance' => nil,
333
- 'outdoors_fixedwindow_conductance' => nil
334
- })
335
-
336
- model.getDefaultConstructionSets.sort.each do |set|
337
- set_construction_set_to_necb!(model: model,
338
- default_surface_construction_set: set,
339
- runner: nil,
340
- properties: properties)
324
+ # ext surfaces
325
+ ext_wall_cond: nil,
326
+ ext_floor_cond: nil,
327
+ ext_roof_cond: nil,
328
+ # ground surfaces
329
+ ground_wall_cond: nil,
330
+ ground_floor_cond: nil,
331
+ ground_roof_cond: nil,
332
+ # fixed Windows
333
+ fixed_window_cond: nil,
334
+ fixed_wind_solar_trans: nil,
335
+ fixed_wind_vis_trans: nil,
336
+ # operable windows
337
+ operable_wind_solar_trans: nil,
338
+ operable_window_cond: nil,
339
+ operable_wind_vis_trans: nil,
340
+ # glass doors
341
+ glass_door_cond: nil,
342
+ glass_door_solar_trans: nil,
343
+ glass_door_vis_trans: nil,
344
+ # opaque doors
345
+ door_construction_cond: nil,
346
+ overhead_door_cond: nil,
347
+ # skylights
348
+ skylight_cond: nil,
349
+ skylight_solar_trans: nil,
350
+ skylight_vis_trans: nil,
351
+ # tubular daylight dome
352
+ tubular_daylight_dome_cond: nil,
353
+ tubular_daylight_dome_solar_trans: nil,
354
+ tubular_daylight_dome_vis_trans: nil,
355
+ # tubular daylight diffuser
356
+ tubular_daylight_diffuser_cond: nil,
357
+ tubular_daylight_diffuser_solar_trans: nil,
358
+ tubular_daylight_diffuser_vis_trans: nil)
359
+
360
+ model.getDefaultConstructionSets.sort.each do |default_surface_construction_set|
361
+ BTAP.runner_register('Info', 'apply_standard_construction_properties', runner)
362
+ if model.weatherFile.empty? || model.weatherFile.get.path.empty? || !File.exist?(model.weatherFile.get.path.get.to_s)
363
+
364
+ BTAP.runner_register('Error', 'Weather file is not defined. Please ensure the weather file is defined and exists.', runner)
365
+ return false
366
+ end
367
+
368
+ # Lambdas are preferred over methods in methods for small utility methods.
369
+ correct_cond = lambda do |conductivity, surface_type|
370
+ # hdd required in scope for eval function.
371
+ hdd = get_necb_hdd18(model)
372
+ return conductivity.nil? || conductvity == 0.0 ? eval(model_find_objects(@standards_data['surface_thermal_transmittance'], surface_type)[0]['formula']) : conductivity
373
+ end
374
+
375
+ BTAP::Resources::Envelope::ConstructionSets.customize_default_surface_construction_set!(model: model,
376
+ name: "#{default_surface_construction_set.name.get} at hdd = #{get_necb_hdd18(model)}",
377
+ default_surface_construction_set: default_surface_construction_set,
378
+ # ext surfaces
379
+ ext_wall_cond: correct_cond.call(ext_wall_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'Wall'}),
380
+ ext_floor_cond: correct_cond.call(ext_floor_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'Floor'}),
381
+ ext_roof_cond: correct_cond.call(ext_roof_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'RoofCeiling'}),
382
+ # ground surfaces
383
+ ground_wall_cond: correct_cond.call(ground_wall_cond, {'boundary_condition' => 'Ground', 'surface' => 'Wall'}),
384
+ ground_floor_cond: correct_cond.call(ground_floor_cond, {'boundary_condition' => 'Ground', 'surface' => 'Floor'}),
385
+ ground_roof_cond: correct_cond.call(ground_roof_cond, {'boundary_condition' => 'Ground', 'surface' => 'RoofCeiling'}),
386
+ # fixed Windows
387
+ fixed_window_cond: correct_cond.call(fixed_window_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'Window'}),
388
+ fixed_wind_solar_trans: fixed_wind_solar_trans,
389
+ fixed_wind_vis_trans: fixed_wind_vis_trans,
390
+ # operable windows
391
+ operable_wind_solar_trans: operable_wind_solar_trans,
392
+ operable_window_cond: correct_cond.call(fixed_window_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'Window'}),
393
+ operable_wind_vis_trans: operable_wind_vis_trans,
394
+ # glass doors
395
+ glass_door_cond: correct_cond.call(glass_door_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'Window'}),
396
+ glass_door_solar_trans: glass_door_solar_trans,
397
+ glass_door_vis_trans: glass_door_vis_trans,
398
+ # opaque doors
399
+ door_construction_cond: correct_cond.call(door_construction_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'Door'}),
400
+ overhead_door_cond: correct_cond.call(overhead_door_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'Door'}),
401
+ # skylights
402
+ skylight_cond: correct_cond.call(skylight_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'Window'}),
403
+ skylight_solar_trans: skylight_solar_trans,
404
+ skylight_vis_trans: skylight_vis_trans,
405
+ # tubular daylight dome
406
+ tubular_daylight_dome_cond: correct_cond.call(skylight_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'Window'}),
407
+ tubular_daylight_dome_solar_trans: tubular_daylight_dome_solar_trans,
408
+ tubular_daylight_dome_vis_trans: tubular_daylight_dome_vis_trans,
409
+ # tubular daylight diffuser
410
+ tubular_daylight_diffuser_cond: correct_cond.call(skylight_cond, {'boundary_condition' => 'Outdoors', 'surface' => 'Window'}),
411
+ tubular_daylight_diffuser_solar_trans: tubular_daylight_diffuser_solar_trans,
412
+ tubular_daylight_diffuser_vis_trans: tubular_daylight_diffuser_vis_trans)
413
+
414
+
341
415
  end
342
416
  # sets all surfaces to use default constructions sets except adiabatic, where it does a hard assignment of the interior wall construction type.
343
417
  model.getPlanarSurfaces.sort.each(&:resetConstruction)
344
418
  # if the default construction set is defined..try to assign the interior wall to the adiabatic surfaces
345
419
  BTAP::Resources::Envelope.assign_interior_surface_construction_to_adiabatic_surfaces(model, nil)
346
- end
420
+ BTAP.runner_register('Info', ' apply_standard_construction_properties was sucessful.', runner)
347
421
 
348
- # this will create a copy and convert all construction sets to NECB reference conductances.
349
- # @author phylroy.lopez@nrcan.gc.ca
350
- # @param model [OpenStudio::model::Model] A model object
351
- # @param default_surface_construction_set [String]
352
- # @return [Boolean] returns true if sucessful, false if not
353
- def set_construction_set_to_necb!(model:,
354
- default_surface_construction_set:,
355
- runner: nil,
356
- properties: {
357
- 'outdoors_wall_conductance' => nil,
358
- 'outdoors_floor_conductance' => nil,
359
- 'outdoors_roofceiling_conductance' => nil,
360
- 'ground_wall_conductance' => nil,
361
- 'ground_floor_conductance' => nil,
362
- 'ground_roofceiling_conductance' => nil,
363
- 'outdoors_door_conductance' => nil,
364
- 'outdoors_fixedwindow_conductance' => nil
365
- })
366
- BTAP.runner_register('Info', 'set_construction_set_to_necb!', runner)
367
- if model.weatherFile.empty? || model.weatherFile.get.path.empty? || !File.exist?(model.weatherFile.get.path.get.to_s)
368
-
369
- BTAP.runner_register('Error', 'Weather file is not defined. Please ensure the weather file is defined and exists.', runner)
370
- return false
371
- end
372
-
373
- #Note:hdd needs to be defined for eval to work on table eval below.
374
- hdd = self.get_necb_hdd18(model)
375
-
376
- old_name = default_surface_construction_set.name.get.to_s
377
- new_name = "#{old_name} at hdd = #{hdd}"
378
- # Get appropriate standards table
379
- standards_table = @standards_data['surface_thermal_transmittance']
380
-
381
- surface_types = [
382
- {'boundary_condition' => 'Outdoors', 'surface' => 'Wall', 'conductance' => properties['outdoors_wall_conductance']},
383
- {'boundary_condition' => 'Outdoors', 'surface' => 'Floor', 'conductance' => properties['outdoors_floor_conductance']},
384
- {'boundary_condition' => 'Outdoors', 'surface' => 'RoofCeiling', 'conductance' => properties['outdoors_roofceiling_conductance']},
385
- {'boundary_condition' => 'Ground', 'surface' => 'Wall', 'conductance' => properties['ground_wall_conductance']},
386
- {'boundary_condition' => 'Ground', 'surface' => 'Floor', 'conductance' => properties['ground_floor_conductance']},
387
- {'boundary_condition' => 'Ground', 'surface' => 'RoofCeiling', 'conductance' => properties['ground_roofceiling_conductance']},
388
- {'boundary_condition' => 'Outdoors', 'surface' => 'Window', 'conductance' => properties['outdoors_fixedwindow_conductance']},
389
- {'boundary_condition' => 'Outdoors', 'surface' => 'Door', 'conductance' => properties['outdoors_door_conductance']}
390
- ]
391
-
392
- surface_types_rsi = {}
393
- surface_types.each do |surface_type|
394
- surface_types_rsi["#{surface_type['boundary_condition'].downcase}_#{surface_type['surface'].downcase}_conductance"] = surface_type['conductance'].nil? ? 1.0 / (eval(self.model_find_objects(standards_table, surface_type)[0]['formula'])) : (1.0 / surface_type['conductance'])
395
- end
396
- puts surface_types_rsi
397
-
398
- # convert conductance values to rsi values. (Note: we should really be only using conductances in)
399
- BTAP::Resources::Envelope::ConstructionSets.customize_default_surface_construction_set_rsi!(model, new_name, default_surface_construction_set,
400
- surface_types_rsi['outdoors_wall_conductance'], surface_types_rsi['outdoors_floor_conductance'], surface_types_rsi['outdoors_roofceiling_conductance'],
401
- surface_types_rsi['ground_wall_conductance'], surface_types_rsi['ground_floor_conductance'], surface_types_rsi['ground_roofceiling_conductance'],
402
- surface_types_rsi['outdoors_window_conductance'], nil, nil,
403
- surface_types_rsi['outdoors_window_conductance'], nil, nil,
404
- surface_types_rsi['outdoors_door_conductance'],
405
- surface_types_rsi['outdoors_door_conductance'], nil, nil,
406
- surface_types_rsi['outdoors_door_conductance'],
407
- surface_types_rsi['outdoors_window_conductance'], nil, nil,
408
- surface_types_rsi['outdoors_window_conductance'], nil, nil,
409
- surface_types_rsi['outdoors_window_conductance'], nil, nil)
410
- BTAP.runner_register('Info', 'set_construction_set_to_necb! was sucessful.', runner)
411
- return true
412
422
  end
413
423
 
414
424
  # Set all external surface conductances to NECB values.
@@ -425,11 +435,11 @@ class NECB2011
425
435
 
426
436
  case surface.surfaceType.downcase
427
437
  when 'wall'
428
- conductance_value = @standards_data['conductances']['Wall'].find {|i| i['hdd'] > hdd}['thermal_transmittance'] * scaling_factor
438
+ conductance_value = @standards_data['conductances']['Wall'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
429
439
  when 'floor'
430
- conductance_value = @standards_data['conductances']['Floor'].find {|i| i['hdd'] > hdd}['thermal_transmittance'] * scaling_factor
440
+ conductance_value = @standards_data['conductances']['Floor'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
431
441
  when 'roofceiling'
432
- conductance_value = @standards_data['conductances']['Roof'].find {|i| i['hdd'] > hdd}['thermal_transmittance'] * scaling_factor
442
+ conductance_value = @standards_data['conductances']['Roof'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
433
443
  end
434
444
  if is_radiant
435
445
  conductance_value *= 0.80
@@ -440,11 +450,11 @@ class NECB2011
440
450
  if surface.outsideBoundaryCondition.downcase =~ /ground/
441
451
  case surface.surfaceType.downcase
442
452
  when 'wall'
443
- conductance_value = @standards_data['conductances']['GroundWall'].find {|i| i['hdd'] > hdd}['thermal_transmittance'] * scaling_factor
453
+ conductance_value = @standards_data['conductances']['GroundWall'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
444
454
  when 'floor'
445
- conductance_value = @standards_data['conductances']['GroundFloor'].find {|i| i['hdd'] > hdd}['thermal_transmittance'] * scaling_factor
455
+ conductance_value = @standards_data['conductances']['GroundFloor'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
446
456
  when 'roofceiling'
447
- conductance_value = @standards_data['conductances']['GroundRoof'].find {|i| i['hdd'] > hdd}['thermal_transmittance'] * scaling_factor
457
+ conductance_value = @standards_data['conductances']['GroundRoof'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
448
458
  end
449
459
  if is_radiant
450
460
  conductance_value *= 0.80
@@ -463,15 +473,14 @@ class NECB2011
463
473
  if subsurface.outsideBoundaryCondition.downcase.match('outdoors')
464
474
  case subsurface.subSurfaceType.downcase
465
475
  when /window/
466
- conductance_value = @standards_data['conductances']['Window'].find {|i| i['hdd'] > hdd}['thermal_transmittance'] * scaling_factor
476
+ conductance_value = @standards_data['conductances']['Window'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
467
477
  when /door/
468
- conductance_value = @standards_data['conductances']['Door'].find {|i| i['hdd'] > hdd}['thermal_transmittance'] * scaling_factor
478
+ conductance_value = @standards_data['conductances']['Door'].find { |i| i['hdd'] > hdd }['thermal_transmittance'] * scaling_factor
469
479
  end
470
480
  subsurface.setRSI(1 / conductance_value)
471
481
  end
472
482
  end
473
483
 
474
-
475
484
  # Adds code-minimum constructions based on the building type
476
485
  # as defined in the OpenStudio_Standards_construction_sets.json file.
477
486
  # Where there is a separate construction set specified for the
@@ -491,7 +500,7 @@ class NECB2011
491
500
  # building types.
492
501
  apply_building_default_constructionset(model)
493
502
  # Make a construction set for each space type, if one is specified
494
- #apply_default_constructionsets_to_spacetypes(climate_zone, model)
503
+ # apply_default_constructionsets_to_spacetypes(climate_zone, model)
495
504
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished applying constructions')
496
505
  return true
497
506
  end
@@ -536,7 +545,6 @@ class NECB2011
536
545
  end
537
546
  end
538
547
 
539
-
540
548
  def model_add_construction_set_from_osm(model:,
541
549
  construction_set_name: 'BTAP-Mass',
542
550
  osm_path: File.absolute_path(File.join(__FILE__, '..', '..', 'common/construction_defaults.osm')))
@@ -552,7 +560,6 @@ class NECB2011
552
560
  return new_construction_set
553
561
  end
554
562
 
555
-
556
563
  def assign_contruction_to_adiabatic_surfaces(model)
557
564
  cp02_carpet_pad = OpenStudio::Model::MasslessOpaqueMaterial.new(model)
558
565
  cp02_carpet_pad.setName('CP02 CARPET PAD')
@@ -678,7 +685,6 @@ class NECB2011
678
685
  construct_set = model.getBuilding.defaultConstructionSet.get
679
686
  fixed_window_construct_set = construct_set.defaultExteriorSubSurfaceConstructions.get.fixedWindowConstruction.get
680
687
 
681
-
682
688
  # IF FDWR is greater than 1 then something is wrong raise an error. If it is less than 0.001 assume all the windows
683
689
  # should go.
684
690
  if fdwr_lim > 1
@@ -738,7 +744,6 @@ class NECB2011
738
744
  return false
739
745
  end
740
746
 
741
-
742
747
  # If the SRR is greater than one something is seriously wrong so raise an error. If it is less than 0.001 assume
743
748
  # all the skylights should go.
744
749
  if srr_lim > 1