openstudio-standards 0.2.17.rc1 → 0.3.0

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/data/standards/OpenStudio_Standards-ashrae_90_1.xlsx +0 -0
  3. data/data/standards/openstudio_standards_duplicates_log.csv +5 -0
  4. data/lib/openstudio-standards/btap/btap_result.rb +138 -138
  5. data/lib/openstudio-standards/btap/economics.rb +58 -53
  6. data/lib/openstudio-standards/btap/envelope.rb +1 -1
  7. data/lib/openstudio-standards/btap/fileio.rb +12 -12
  8. data/lib/openstudio-standards/btap/measures.rb +63 -59
  9. data/lib/openstudio-standards/btap/vintagizer.rb +1 -1
  10. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.exterior_lights.rb +7 -7
  11. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.rb +5 -1
  12. data/lib/openstudio-standards/prototypes/common/objects/Prototype.ServiceWaterHeating.rb +8 -0
  13. data/lib/openstudio-standards/prototypes/common/objects/Prototype.SizingSystem.rb +9 -3
  14. data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +53 -23
  15. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +15 -1
  16. data/lib/openstudio-standards/standards/Standards.Construction.rb +1 -1
  17. data/lib/openstudio-standards/standards/Standards.Model.rb +18 -18
  18. data/lib/openstudio-standards/standards/Standards.PlanarSurface.rb +1 -1
  19. data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +1 -1
  20. data/lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb +5 -5
  21. data/lib/openstudio-standards/standards/Standards.ZoneHVACComponent.rb +3 -2
  22. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirLoopHVAC.rb +43 -40
  23. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.ZoneHVACComponent.rb +2 -1
  24. data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.entryways.json +19 -8
  25. data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.parking.json +13 -4
  26. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/doe_ref_1980_2004.AirLoopHVAC.rb +11 -0
  27. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/doe_ref_pre_1980.AirLoopHVAC.rb +11 -0
  28. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb +1 -1
  29. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +9 -9
  30. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlanarSurface.rb +1 -1
  31. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb +5 -1
  32. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_6.rb +5 -1
  33. data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +8 -4
  34. data/lib/openstudio-standards/standards/necb/ECMS/nv.rb +8 -2
  35. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +7 -3
  36. data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +4 -4
  37. data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +1 -1
  38. data/lib/openstudio-standards/standards/necb/NECB2020/service_water_heating.rb +1 -1
  39. data/lib/openstudio-standards/version.rb +1 -1
  40. data/lib/openstudio-standards/weather/Weather.Model.rb +5 -0
  41. metadata +4 -2
@@ -24,28 +24,28 @@ require "#{File.dirname(__FILE__)}/btap"
24
24
 
25
25
  class OSMArg
26
26
  ARGUMENT_TYPES = [
27
- "BOOL",
28
- "STRING",
29
- "INTEGER",
30
- "FLOAT",
27
+ "BOOL",
28
+ "STRING",
29
+ "INTEGER",
30
+ "FLOAT",
31
31
  "STRINGCHOICE",
32
- "WSCHOICE"
32
+ "WSCHOICE"
33
33
  ]
34
-
35
-
36
-
37
- attr_accessor :runner,
38
- :variable_name,
34
+
35
+
36
+
37
+ attr_accessor :runner,
38
+ :variable_name,
39
39
  :type,
40
- :required,
40
+ :required,
41
41
  :model_dependant,
42
- :display_name,
43
- :default_value,
44
- :min_value,
45
- :max_value,
46
- :string_choice_array,
42
+ :display_name,
43
+ :default_value,
44
+ :min_value,
45
+ :max_value,
46
+ :string_choice_array,
47
47
  :os_object_type
48
-
48
+
49
49
  def self.bool( variable_name,display_name,required,default_value )
50
50
  raise "#{default_value} defaut value is not a bool." unless default_value.is_a?(Bool)
51
51
  default_value.respond_to?(:to_s)
@@ -53,47 +53,47 @@ class OSMArg
53
53
  arg.default_value = default_value
54
54
  return arg
55
55
  end
56
-
56
+
57
57
  def self.string( variable_name,display_name,required,default_value )
58
58
  raise "#{default_value} defaut value is not a string." unless default_value.respond_to?(:to_s)
59
59
  arg = OSMArg.new( "STRING", variable_name, display_name, required)
60
60
  arg.default_value = default_value
61
61
  return arg
62
62
  end
63
-
63
+
64
64
  def self.integer( variable_name,display_name,required,default_value,min_value,max_value )
65
65
  raise "#{default_value} defaut value is not a integer." unless default_value.respond_to?(:to_i)
66
66
  arg = OSMArg.new( "INTEGER", variable_name, display_name, required)
67
67
  arg.default_value = default_value
68
68
  arg.min_value = min_value
69
69
  arg.max_value = max_value
70
- return arg
70
+ return arg
71
71
  end
72
-
72
+
73
73
  def self.float( variable_name, display_name, required,default_value,min_value, max_value )
74
74
  raise "#{default_value} defaut value is not a float." unless default_value.respond_to?(:to_f)
75
75
  arg = OSMArg.new( "INTEGER", variable_name, display_name, required)
76
76
  arg.default_value = default_value
77
77
  arg.min_value = min_value
78
78
  arg.max_value = max_value
79
- return arg
79
+ return arg
80
80
  end
81
-
81
+
82
82
  def self.choice(variable_name,display_name,required,default_value,string_choice_array)
83
- raise "#{default_value} defaut value is not an array." unless default_value.is_a?(Array)
83
+ raise "#{default_value} defaut value is not an array." unless default_value.is_a?(Array)
84
84
  arg = OSMArg.new( "STRINGCHOICE", variable_name, display_name, required)
85
85
  arg.default_value = default_value
86
86
  arg.string_choice_array = string_choice_array
87
87
  return arg
88
88
  end
89
-
89
+
90
90
  def self.wschoice( variable_name, display_name, required, default_value, os_object_type)
91
91
  arg = OSMArg.new( "WSCHOICE", variable_name, display_name, required )
92
92
  arg.default_value = default_value
93
93
  arg.os_object_type = os_object_type
94
- return arg
94
+ return arg
95
95
  end
96
-
96
+
97
97
  def initialize( type, variable_name, display_name, required )
98
98
  self.type = type
99
99
  self.variable_name = variable_name
@@ -106,9 +106,9 @@ class OSMArg
106
106
  self.model_dependant = false
107
107
  end
108
108
  return self
109
- end
109
+ end
110
110
  end
111
-
111
+
112
112
 
113
113
 
114
114
 
@@ -116,10 +116,10 @@ end
116
116
  module BTAP
117
117
  module Measures
118
118
  module OSMeasures
119
-
120
-
121
-
122
-
119
+
120
+
121
+
122
+
123
123
  class BTAPModelUserScript < OpenStudio::Ruleset::ModelUserScript
124
124
  #if and E+ measure replace OpenStudio::Ruleset::ModelUserScript with OpenStudio::Ruleset::WorkspaceUserScript
125
125
  #Array containing information of all inputs required by measure.
@@ -134,8 +134,8 @@ module BTAP
134
134
  "BTAPModelUserScript"
135
135
  OSMArgument.new
136
136
  end
137
-
138
- #this method will output the ruby macro to perform the change.
137
+
138
+ #this method will output the ruby macro to perform the change.
139
139
  def generate_ruby_macro(model,runner)
140
140
  if @file == nil or @file == ""
141
141
  @file = "Enter_Path_To_#{self.class.name}_measure.rb_File!"
@@ -190,8 +190,8 @@ module BTAP
190
190
  if not runner.validateUserArguments(self.arguments(model),user_arguments)
191
191
  return false
192
192
  end
193
-
194
- #Set argument to instance variables.
193
+
194
+ #Set argument to instance variables.
195
195
  self.argument_getter(model, runner,user_arguments)
196
196
  #will run the childs method measure_code
197
197
  result = self.measure_code(model,runner)
@@ -201,7 +201,7 @@ module BTAP
201
201
 
202
202
  def argument_setter(model,args)
203
203
  #***boilerplate code starts. Do not edit...
204
-
204
+
205
205
 
206
206
  #iterate through array of hashes and make arguments based on type and set
207
207
  # max and min values where applicable.
@@ -247,7 +247,7 @@ module BTAP
247
247
  unless @argument_array == nil
248
248
  @argument_array.each do |row|
249
249
  name = row.variable_name
250
-
250
+
251
251
  case row.type
252
252
  when "BOOL"
253
253
  value = runner.getBoolArgumentValue(name, user_arguments)
@@ -269,7 +269,7 @@ module BTAP
269
269
  value = runner.getDoubleArgumentValue(name, user_arguments)
270
270
  instance_variable_set("@#{name}",value)
271
271
  @arg_table << [name,value]
272
-
272
+
273
273
  if ( not row.min_value.nil? and instance_variable_get("@#{name}") < row.min_value ) or ( not row.max_value.nil? and instance_variable_get("@#{name}") > row.max_value )
274
274
  runner.registerError("#{row.display_name} must be greater than or equal to #{row.min_value} and less than or equal to #{row.max_value}. You entered #{instance_variable_get("@#{name}")}.")
275
275
  return false
@@ -288,10 +288,10 @@ module BTAP
288
288
  end #end do
289
289
  end
290
290
  return @arg_table
291
- end
292
-
291
+ end
292
+
293
293
  end
294
- #Measure Template simplified.
294
+ #Measure Template simplified.
295
295
  class TemplateModelMeasure < BTAPModelUserScript
296
296
 
297
297
  def name
@@ -391,14 +391,14 @@ module BTAP
391
391
  def run(model, runner, user_arguments)
392
392
  #run the super
393
393
  parent_method_is_true = super(model, runner, user_arguments)
394
-
395
-
394
+
395
+
396
396
  ###############
397
-
398
- #Set Archetype name in runner.
397
+
398
+ #Set Archetype name in runner.
399
399
  runner.registerValue('archetype_name',@archetype_name)
400
-
401
- #Set path to OSM files.
400
+
401
+ #Set path to OSM files.
402
402
  alternative_model_path = OpenStudio::Path.new("#{File.dirname(__FILE__)}/#{@archetype_name}.osm")
403
403
  #load model and test.
404
404
  translator = OpenStudio::OSVersion::VersionTranslator.new
@@ -561,7 +561,7 @@ module BTAP
561
561
  model = self.load_base_model_building()
562
562
  self.set_weather_file(model)
563
563
  self.set_hourly_output(model)
564
-
564
+
565
565
  model,log = self.apply_ecms(model,@csv_data)
566
566
  BTAP::FileIO::save_osm( model, "#{output_folder}/#{BTAP::FileIO::get_name(model)}.osm") unless output_folder.nil?
567
567
  File.open("#{output_folder}/#{BTAP::FileIO::get_name(model)}.log", 'w') { |file| file.write(log) } unless output_folder.nil?
@@ -621,7 +621,7 @@ module BTAP
621
621
  "cost_per_building"
622
622
  ]
623
623
  self.set_instance_variables( measure_values )
624
-
624
+
625
625
  #cost per building and building area
626
626
  building = model.building.get
627
627
  raise ("you did not enter a cost for measure #{@measure_id}. All measures must have a cost of at least 0.0 . Please add a cost_per_building field.") if @cost_per_building.nil?
@@ -753,7 +753,7 @@ module BTAP
753
753
  @total_building_construction_set_cost
754
754
  )
755
755
 
756
- #Give adiabatic surfaces a construction. Does not matter what. This is a bug in Openstudio that leave these surfaces unassigned by the default construction set.
756
+ #Give adiabatic surfaces a construction. Does not matter what. This is a bug in OpenStudio that leave these surfaces unassigned by the default construction set.
757
757
  all_adiabatic_surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(model.getSurfaces, "Adiabatic")
758
758
  unless all_adiabatic_surfaces.empty?
759
759
  BTAP::Geometry::Surfaces::set_surfaces_construction( all_adiabatic_surfaces, model.building.get.defaultConstructionSet.get.defaultInteriorSurfaceConstructions.get.wallConstruction.get)
@@ -772,7 +772,7 @@ module BTAP
772
772
  "infiltration_flow_per_exterior_area",
773
773
  "infiltration_air_changes_per_hour"
774
774
  ]
775
-
775
+
776
776
  #Set all the above instance variables to the @csv_data values or, if not set or == 'na', to nil.
777
777
  self.set_instance_variables(measure_values)
778
778
 
@@ -811,7 +811,7 @@ module BTAP
811
811
  fan.setMotorEfficiency( @fan_motor_eff ) unless @fan_motor_eff.nil?
812
812
  log << fan.name.get.to_s << ",#{fan.fanEfficiency},#{fan.motorEfficiency}\n"
813
813
  end
814
-
814
+
815
815
  end
816
816
 
817
817
  case @fan_volume_type
@@ -975,7 +975,9 @@ module BTAP
975
975
  model.getCoilCoolingDXSingleSpeeds.sort.each do |cooling_coil|
976
976
  cooling_coil.setRatedCOP( OpenStudio::OptionalDouble.new( @cop ) ) unless @cop.nil?
977
977
  cop = "NA"
978
- cop = cooling_coil.ratedCOP.get unless cooling_coil.ratedCOP.empty?
978
+ # Prior to 3.5.0, it was an optional double, now it's a double
979
+ cop_ = OpenStudio::OptionalDouble.new(cooling_coil.ratedCOP)
980
+ cop = cop_.get unless cop_.empty?
979
981
  log << cooling_coil.name.get.to_s << ",#{cop}\n"
980
982
 
981
983
  end
@@ -987,9 +989,11 @@ module BTAP
987
989
  cooling_coil.setRatedHighSpeedCOP( @cop ) unless @cop.nil?
988
990
  cooling_coil.setRatedLowSpeedCOP( @cop ) unless @cop.nil?
989
991
  cop_high = "NA"
990
- cop_high = cooling_coil.ratedHighSpeedCOP.get unless cooling_coil.ratedHighSpeedCOP.empty?
992
+ cop_ = OpenStudio::OptionalDouble.new(cooling_coil.ratedHighSpeedCOP)
993
+ cop_high = cop_.get unless cop_.empty?
991
994
  cop_low = "NA"
992
- cop_low = cooling_coil.ratedLowSpeedCOP.get unless cooling_coil.ratedLowSpeedCOP.empty?
995
+ cop_ = OpenStudio::OptionalDouble.new(cooling_coil.ratedLowSpeedCOP)
996
+ cop_low = cop_.get unless cop_.empty?
993
997
  log << cooling_coil.name.get.to_s << ",#{cop_high},#{cop_low}\n"
994
998
  end
995
999
  end
@@ -1296,8 +1300,8 @@ module BTAP
1296
1300
  @erv_nominal_electric_power,
1297
1301
  @erv_economizer_lockout.to_bool
1298
1302
  ).each { |erv| log << erv.to_s }
1299
-
1300
-
1303
+
1304
+
1301
1305
  #Add setpoint manager to all OA object in airloops.
1302
1306
  model.getHeatExchangerAirToAirSensibleAndLatents.sort.each do |erv|
1303
1307
 
@@ -99,7 +99,7 @@ class Vintagizer
99
99
  new_construction_set.setName(construction_id)
100
100
  constructions_model.building.get.setDefaultConstructionSet( new_construction_set.clone( constructions_model ).to_DefaultConstructionSet.get )
101
101
 
102
- #Give adiabatic surfaces a construction. Does not matter what. This is a bug in Openstudio that leave these surfaces unassigned by the default construction set.
102
+ #Give adiabatic surfaces a construction. Does not matter what. This is a bug in OpenStudio that leave these surfaces unassigned by the default construction set.
103
103
  all_adiabatic_surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(constructions_model.getSurfaces, "Adiabatic")
104
104
  BTAP::Geometry::Surfaces::set_surfaces_construction( all_adiabatic_surfaces, constructions_model.building.get.defaultConstructionSet.get.defaultInteriorSurfaceConstructions.get.wallConstruction.get)
105
105
 
@@ -59,7 +59,7 @@ class Standard
59
59
  end
60
60
 
61
61
  # add exterior lights for parking area
62
- if area_length_count_hash[:parking_area_and_drives_area] > 0
62
+ if !area_length_count_hash[:parking_area_and_drives_area].nil? && area_length_count_hash[:parking_area_and_drives_area] > 0
63
63
 
64
64
  # lighting values
65
65
  multiplier = area_length_count_hash[:parking_area_and_drives_area] * onsite_parking_fraction
@@ -86,7 +86,7 @@ class Standard
86
86
  end
87
87
 
88
88
  # add exterior lights for facades
89
- if area_length_count_hash[:building_facades] > 0
89
+ if !area_length_count_hash[:building_facades].nil? && area_length_count_hash[:building_facades] > 0
90
90
 
91
91
  # lighting values
92
92
  multiplier = area_length_count_hash[:building_facades]
@@ -113,7 +113,7 @@ class Standard
113
113
  end
114
114
 
115
115
  # add exterior lights for main entries
116
- if area_length_count_hash[:main_entries] > 0
116
+ if !area_length_count_hash[:main_entries].nil? && area_length_count_hash[:main_entries] > 0
117
117
 
118
118
  # lighting values
119
119
  multiplier = area_length_count_hash[:main_entries]
@@ -140,7 +140,7 @@ class Standard
140
140
  end
141
141
 
142
142
  # add exterior lights for other doors
143
- if area_length_count_hash[:other_doors] > 0
143
+ if !area_length_count_hash[:other_doors].nil? && area_length_count_hash[:other_doors] > 0
144
144
 
145
145
  # lighting values
146
146
  multiplier = area_length_count_hash[:other_doors]
@@ -167,7 +167,7 @@ class Standard
167
167
  end
168
168
 
169
169
  # add exterior lights for entry canopies
170
- if area_length_count_hash[:canopy_entry_area] > 0
170
+ if !area_length_count_hash[:canopy_entry_area].nil? && area_length_count_hash[:canopy_entry_area] > 0
171
171
 
172
172
  # lighting values
173
173
  multiplier = area_length_count_hash[:canopy_entry_area]
@@ -194,7 +194,7 @@ class Standard
194
194
  end
195
195
 
196
196
  # add exterior lights for emergency canopies
197
- if area_length_count_hash[:canopy_emergency_area] > 0
197
+ if !area_length_count_hash[:canopy_emergency_area].nil? && area_length_count_hash[:canopy_emergency_area] > 0
198
198
 
199
199
  # lighting values
200
200
  multiplier = area_length_count_hash[:canopy_emergency_area]
@@ -221,7 +221,7 @@ class Standard
221
221
  end
222
222
 
223
223
  # add exterior lights for drive through windows
224
- if area_length_count_hash[:drive_through_windows] > 0
224
+ if !area_length_count_hash[:drive_through_windows].nil? && area_length_count_hash[:drive_through_windows] > 0
225
225
 
226
226
  # lighting values
227
227
  multiplier = area_length_count_hash[:drive_through_windows]
@@ -2721,7 +2721,11 @@ Standard.class_eval do
2721
2721
  end
2722
2722
  end
2723
2723
  end
2724
- return window_area / wall_area * 100 if wwr
2724
+
2725
+ # check wall area is non-zero
2726
+ if wwr && wall_area > 0
2727
+ return window_area / wall_area * 100
2728
+ end
2725
2729
 
2726
2730
  # else
2727
2731
  return window_area
@@ -546,6 +546,14 @@ class Standard
546
546
  default_water_heater_ambient_temp_sch = model_add_constant_schedule_ruleset(model,
547
547
  OpenStudio.convert(70.0, 'F', 'C').get,
548
548
  name = 'Water Heater Ambient Temp Schedule - 70F')
549
+ if temp_sch_type_limits.nil?
550
+ temp_sch_type_limits = model_add_schedule_type_limits(model,
551
+ name: 'Temperature Schedule Type Limits',
552
+ lower_limit_value: 0.0,
553
+ upper_limit_value: 100.0,
554
+ numeric_type: 'Continuous',
555
+ unit_type: 'Temperature')
556
+ end
549
557
  default_water_heater_ambient_temp_sch.setScheduleTypeLimits(temp_sch_type_limits)
550
558
  tank.setAmbientTemperatureIndicator('Schedule')
551
559
  tank.setAmbientTemperatureSchedule(default_water_heater_ambient_temp_sch)
@@ -57,14 +57,20 @@ class Standard
57
57
  end
58
58
 
59
59
  sizing_system = air_loop_hvac.sizingSystem
60
- sizing_system.setSystemOutdoorAirMethod('VentilationRateProcedure')
61
- # Set the minimum zone ventilation efficiency to be 0.6
60
+ if air_loop_hvac.model.version < OpenStudio::VersionString.new('3.3.0')
61
+ sizing_system.setSystemOutdoorAirMethod('VentilationRateProcedure')
62
+ else
63
+ sizing_system.setSystemOutdoorAirMethod('Standard62.1VentilationRateProcedure')
64
+ end
65
+
66
+ # Set the minimum zone ventilation efficiency
67
+ min_ventilation_efficiency = air_loop_hvac_minimum_zone_ventilation_efficiency(air_loop_hvac)
62
68
  air_loop_hvac.thermalZones.sort.each do |zone|
63
69
  sizing_zone = zone.sizingZone
64
70
  if air_loop_hvac.model.version < OpenStudio::VersionString.new('3.0.0')
65
71
  OpenStudio.logFree(OpenStudio::Warn, 'openstudio.prototype.SizingSystem', "The design minimum zone ventilation efficiency cannot be set for #{sizing_system.name}. It can only be set OpenStudio 3.0.0 and later.")
66
72
  else
67
- sizing_zone.setDesignMinimumZoneVentilationEfficiency(0.6)
73
+ sizing_zone.setDesignMinimumZoneVentilationEfficiency(min_ventilation_efficiency)
68
74
  end
69
75
  end
70
76
 
@@ -1757,13 +1757,21 @@ class Standard
1757
1757
  # set air loop availability controls and night cycle manager, after oa system added
1758
1758
  air_loop.setAvailabilitySchedule(hvac_op_sch)
1759
1759
  air_loop.setNightCycleControlType('CycleOnAny')
1760
- avail_mgr = air_loop.availabilityManager
1761
- if avail_mgr.is_initialized
1762
- avail_mgr = avail_mgr.get
1763
- if avail_mgr.to_AvailabilityManagerNightCycle.is_initialized
1764
- avail_mgr = avail_mgr.to_AvailabilityManagerNightCycle.get
1765
- avail_mgr.setCyclingRunTime(1800)
1766
- end
1760
+
1761
+ if model.version < OpenStudio::VersionString.new('3.5.0')
1762
+ avail_mgr = air_loop.availabilityManager
1763
+ if avail_mgr.is_initialized
1764
+ avail_mgr = avail_mgr.get
1765
+ else
1766
+ avail_mgr = nil
1767
+ end
1768
+ else
1769
+ avail_mgr = air_loop.availabilityManagers[0]
1770
+ end
1771
+
1772
+ if !avail_mgr.nil? && avail_mgr.to_AvailabilityManagerNightCycle.is_initialized
1773
+ avail_mgr = avail_mgr.to_AvailabilityManagerNightCycle.get
1774
+ avail_mgr.setCyclingRunTime(1800)
1767
1775
  end
1768
1776
 
1769
1777
  # hook the VAV system to each zone
@@ -2113,13 +2121,21 @@ class Standard
2113
2121
  # set air loop availability controls and night cycle manager, after oa system added
2114
2122
  air_loop.setAvailabilitySchedule(hvac_op_sch)
2115
2123
  air_loop.setNightCycleControlType('CycleOnAny')
2116
- avail_mgr = air_loop.availabilityManager
2117
- if avail_mgr.is_initialized
2118
- avail_mgr = avail_mgr.get
2119
- if avail_mgr.to_AvailabilityManagerNightCycle.is_initialized
2120
- avail_mgr = avail_mgr.to_AvailabilityManagerNightCycle.get
2121
- avail_mgr.setCyclingRunTime(1800)
2122
- end
2124
+
2125
+ if model.version < OpenStudio::VersionString.new('3.5.0')
2126
+ avail_mgr = air_loop.availabilityManager
2127
+ if avail_mgr.is_initialized
2128
+ avail_mgr = avail_mgr.get
2129
+ else
2130
+ avail_mgr = nil
2131
+ end
2132
+ else
2133
+ avail_mgr = air_loop.availabilityManagers[0]
2134
+ end
2135
+
2136
+ if !avail_mgr.nil? && avail_mgr.to_AvailabilityManagerNightCycle.is_initialized
2137
+ avail_mgr = avail_mgr.to_AvailabilityManagerNightCycle.get
2138
+ avail_mgr.setCyclingRunTime(1800)
2123
2139
  end
2124
2140
 
2125
2141
  # attach the VAV system to each zone
@@ -2727,13 +2743,21 @@ class Standard
2727
2743
  # set air loop availability controls and night cycle manager, after oa system added
2728
2744
  air_loop.setAvailabilitySchedule(hvac_op_sch)
2729
2745
  air_loop.setNightCycleControlType('CycleOnAny')
2730
- avail_mgr = air_loop.availabilityManager
2731
- if avail_mgr.is_initialized
2732
- avail_mgr = avail_mgr.get
2733
- if avail_mgr.to_AvailabilityManagerNightCycle.is_initialized
2734
- avail_mgr = avail_mgr.to_AvailabilityManagerNightCycle.get
2735
- avail_mgr.setCyclingRunTime(1800)
2736
- end
2746
+
2747
+ if model.version < OpenStudio::VersionString.new('3.5.0')
2748
+ avail_mgr = air_loop.availabilityManager
2749
+ if avail_mgr.is_initialized
2750
+ avail_mgr = avail_mgr.get
2751
+ else
2752
+ avail_mgr = nil
2753
+ end
2754
+ else
2755
+ avail_mgr = air_loop.availabilityManagers[0]
2756
+ end
2757
+
2758
+ if !avail_mgr.nil? && avail_mgr.to_AvailabilityManagerNightCycle.is_initialized
2759
+ avail_mgr = avail_mgr.to_AvailabilityManagerNightCycle.get
2760
+ avail_mgr.setCyclingRunTime(1800)
2737
2761
  end
2738
2762
 
2739
2763
  # create a diffuser and attach the zone/diffuser pair to the air loop
@@ -3240,7 +3264,9 @@ class Standard
3240
3264
  # To solve the issue, add economizer here for cold climates
3241
3265
  # select the climate zones with winter design temperature lower than -20C (for safer)
3242
3266
  cold_climates = ['ASHRAE 169-2006-6A', 'ASHRAE 169-2006-6B', 'ASHRAE 169-2006-7A',
3243
- 'ASHRAE 169-2006-7B', 'ASHRAE 169-2006-8A', 'ASHRAE 169-2006-8B']
3267
+ 'ASHRAE 169-2006-7B', 'ASHRAE 169-2006-8A', 'ASHRAE 169-2006-8B',
3268
+ 'ASHRAE 169-2013-6A', 'ASHRAE 169-2013-6B', 'ASHRAE 169-2013-7A',
3269
+ 'ASHRAE 169-2013-7B', 'ASHRAE 169-2013-8A', 'ASHRAE 169-2013-8B']
3244
3270
  if cold_climates.include? climate_zone
3245
3271
  # Determine the economizer type in the prototype buildings, which depends on climate zone.
3246
3272
  economizer_type = model_economizer_type(model, climate_zone)
@@ -5080,7 +5106,11 @@ class Standard
5080
5106
  name: "#{air_loop.name} heating coil",
5081
5107
  type: 'Residential Central Air Source HP',
5082
5108
  cop: hspf_to_cop_heating_no_fan(hspf))
5083
- htg_coil.setRatedSupplyFanPowerPerVolumeFlowRate(ac_w_per_cfm / OpenStudio.convert(1.0, 'cfm', 'm^3/s').get)
5109
+ if model.version < OpenStudio::VersionString.new('3.5.0')
5110
+ htg_coil.setRatedSupplyFanPowerPerVolumeFlowRate(ac_w_per_cfm / OpenStudio.convert(1.0, 'cfm', 'm^3/s').get)
5111
+ else
5112
+ htg_coil.setRatedSupplyFanPowerPerVolumeFlowRate2017(ac_w_per_cfm / OpenStudio.convert(1.0, 'cfm', 'm^3/s').get)
5113
+ end
5084
5114
  htg_coil.setMinimumOutdoorDryBulbTemperatureforCompressorOperation(OpenStudio.convert(min_hp_oat_f, 'F', 'C').get)
5085
5115
  htg_coil.setMaximumOutdoorDryBulbTemperatureforDefrostOperation(OpenStudio.convert(40.0, 'F', 'C').get)
5086
5116
  htg_coil.setCrankcaseHeaterCapacity(crank_case_heat_w)
@@ -1895,7 +1895,11 @@ class Standard
1895
1895
  oa_system = air_loop_hvac.airLoopHVACOutdoorAirSystem.get
1896
1896
  controller_oa = oa_system.getControllerOutdoorAir
1897
1897
  controller_mv = controller_oa.controllerMechanicalVentilation
1898
- controller_mv.setSystemOutdoorAirMethod('VentilationRateProcedure')
1898
+ if air_loop_hvac.model.version < OpenStudio::VersionString.new('3.3.0')
1899
+ controller_mv.setSystemOutdoorAirMethod('VentilationRateProcedure')
1900
+ else
1901
+ controller_mv.setSystemOutdoorAirMethod('Standard62.1VentilationRateProcedureWithLimit')
1902
+ end
1899
1903
  # Change the min flow rate in the controller outdoor air
1900
1904
  controller_oa.setMinimumOutdoorAirFlowRate(0.0)
1901
1905
  else
@@ -1924,6 +1928,16 @@ class Standard
1924
1928
  end
1925
1929
  end
1926
1930
 
1931
+ # Determine minimum ventilation efficiency for zones.
1932
+ # This is used to decrease the overall system minimum OA flow rate
1933
+ # such that a few zones do not drive the overall system OA flow rate too
1934
+ # high.
1935
+ def air_loop_hvac_minimum_zone_ventilation_efficiency(air_loop_hvac)
1936
+ min_ventilation_efficiency = 0.6
1937
+
1938
+ return min_ventilation_efficiency
1939
+ end
1940
+
1927
1941
  # Set the minimum VAV damper positions.
1928
1942
  #
1929
1943
  # @param air_loop_hvac [OpenStudio::Model::AirLoopHVAC] air loop
@@ -529,7 +529,7 @@ class Standard
529
529
  # Calculate the fenestration U-Factor base on the glass, frame,
530
530
  # and divider performance and area calculated by EnergyPlus.
531
531
  #
532
- # @param [OpenStudio:Model:Construction] Openstudio Construction object
532
+ # @param [OpenStudio:Model:Construction] OpenStudio Construction object
533
533
  #
534
534
  # @return [Double] the U-Factor in W/m^2*K
535
535
  def construction_calculated_fenestration_u_factor_w_frame(construction)