openstudio-standards 0.2.17.rc1 → 0.2.17.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) 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.SizingSystem.rb +9 -3
  11. data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +50 -22
  12. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +15 -1
  13. data/lib/openstudio-standards/standards/Standards.Construction.rb +1 -1
  14. data/lib/openstudio-standards/standards/Standards.Model.rb +18 -18
  15. data/lib/openstudio-standards/standards/Standards.PlanarSurface.rb +1 -1
  16. data/lib/openstudio-standards/standards/Standards.ZoneHVACComponent.rb +3 -2
  17. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirLoopHVAC.rb +43 -40
  18. data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.ZoneHVACComponent.rb +2 -1
  19. data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.entryways.json +8 -8
  20. data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.parking.json +2 -2
  21. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/doe_ref_1980_2004.AirLoopHVAC.rb +11 -0
  22. data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/doe_ref_pre_1980.AirLoopHVAC.rb +11 -0
  23. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb +1 -1
  24. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +9 -9
  25. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlanarSurface.rb +1 -1
  26. data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb +5 -1
  27. data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_6.rb +5 -1
  28. data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +8 -4
  29. data/lib/openstudio-standards/standards/necb/ECMS/nv.rb +8 -2
  30. data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +7 -3
  31. data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +4 -4
  32. data/lib/openstudio-standards/version.rb +1 -1
  33. 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
 
@@ -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
@@ -5080,7 +5104,11 @@ class Standard
5080
5104
  name: "#{air_loop.name} heating coil",
5081
5105
  type: 'Residential Central Air Source HP',
5082
5106
  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)
5107
+ if model.version < OpenStudio::VersionString.new('3.5.0')
5108
+ htg_coil.setRatedSupplyFanPowerPerVolumeFlowRate(ac_w_per_cfm / OpenStudio.convert(1.0, 'cfm', 'm^3/s').get)
5109
+ else
5110
+ htg_coil.setRatedSupplyFanPowerPerVolumeFlowRate2017(ac_w_per_cfm / OpenStudio.convert(1.0, 'cfm', 'm^3/s').get)
5111
+ end
5084
5112
  htg_coil.setMinimumOutdoorDryBulbTemperatureforCompressorOperation(OpenStudio.convert(min_hp_oat_f, 'F', 'C').get)
5085
5113
  htg_coil.setMaximumOutdoorDryBulbTemperatureforDefrostOperation(OpenStudio.convert(40.0, 'F', 'C').get)
5086
5114
  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)
@@ -19,21 +19,18 @@ class Standard
19
19
  # @note Per 90.1, the Performance Rating Method "does NOT offer an alternative compliance path for minimum standard compliance."
20
20
  # This means you can't use this method for code compliance to get a permit.
21
21
  # @param user_model [OpenStudio::model::Model] User specified OpenStudio model
22
- # @param building_type [String] the building type
23
22
  # @param climate_zone [String] the climate zone
24
23
  # @param hvac_building_type [String] the building type for baseline HVAC system determination (90.1-2016 and onward)
25
24
  # @param wwr_building_type [String] the building type for baseline WWR determination (90.1-2016 and onward)
26
25
  # @param swh_building_type [String] the building type for baseline SWH determination (90.1-2016 and onward)
27
- # @param custom [String] the custom logic that will be applied during baseline creation. Valid choices are 'Xcel Energy CO EDA' or '90.1-2007 with addenda dn'.
28
- # If nothing is specified, no custom logic will be applied; the process will follow the template logic explicitly.
29
- # @param sizing_run_dir [String] the directory where the sizing runs will be performed
26
+ # @param output_dir [String] the directory where the PRM generations will be performed
30
27
  # @param run_all_orients [Boolean] indicate weather a baseline model should be created for all 4 orientations: same as user model, +90 deg, +180 deg, +270 deg
31
28
  # @param debug [Boolean] If true, will report out more detailed debugging output
32
29
  # @return [Bool] returns true if successful, false if not
33
30
 
34
31
  # Method used for 90.1-2016 and onward
35
- def model_create_prm_stable_baseline_building(model, building_type, climate_zone, hvac_building_type, wwr_building_type, swh_building_type, custom = nil, sizing_run_dir = Dir.pwd, run_all_orients = true, unmet_load_hours_check = true, debug = false)
36
- model_create_prm_any_baseline_building(model, building_type, climate_zone, hvac_building_type, wwr_building_type, swh_building_type, true, custom, sizing_run_dir, run_all_orients, unmet_load_hours_check, debug)
32
+ def model_create_prm_stable_baseline_building(model, climate_zone, hvac_building_type, wwr_building_type, swh_building_type, output_dir = Dir.pwd, unmet_load_hours_check = true, debug = false)
33
+ model_create_prm_any_baseline_building(model, '', climate_zone, hvac_building_type, wwr_building_type, swh_building_type, true, false, output_dir, true, unmet_load_hours_check, debug)
37
34
  end
38
35
 
39
36
  # Creates a Performance Rating Method (aka Appendix G aka LEED) baseline building model
@@ -77,6 +74,9 @@ class Standard
77
74
  OpenStudio.logFree(OpenStudio::Error, 'prm.log', "Proposed model unmet load hours exceed 300. Baseline model(s) won't be created.")
78
75
  raise "Proposed model unmet load hours exceed 300. Baseline model(s) won't be created."
79
76
  end
77
+ else
78
+ OpenStudio.logFree(OpenStudio::Error, 'prm.log', "Simulation failed. Check the model to make sure no severe errors.")
79
+ raise "Simulation on proposed model failed. Baseline generation is stopped."
80
80
  end
81
81
  end
82
82
 
@@ -1885,9 +1885,9 @@ class Standard
1885
1885
  # separate the primary zones from the secondary zones.
1886
1886
  # Add the baseline system type to the primary zones
1887
1887
  # and add the suplemental system type to the secondary zones.
1888
- story_zone_lists.each do |zones|
1888
+ story_zone_lists.each do |story_group|
1889
1889
  # Differentiate primary and secondary zones
1890
- pri_sec_zone_lists = model_differentiate_primary_secondary_thermal_zones(model, story_group, zone_fan_scheds)
1890
+ pri_sec_zone_lists = model_differentiate_primary_secondary_thermal_zones(model, story_group)
1891
1891
  # Record the primary zone system types
1892
1892
  pri_sec_zone_lists['primary'].each do |zone|
1893
1893
  zone_to_sys_type[zone] = pri_system_type
@@ -6926,7 +6926,7 @@ class Standard
6926
6926
  # include data source from:
6927
6927
  # 1. user data csv files
6928
6928
  # 2. data from measure and OpenStudio interface
6929
- # @param [Openstudio:model:Model] model
6929
+ # @param [OpenStudio:model:Model] model
6930
6930
  # @param [String] climate_zone
6931
6931
  # @param [String] default_hvac_building_type
6932
6932
  # @param [String] default_wwr_building_type
@@ -6940,7 +6940,7 @@ class Standard
6940
6940
  # Template method for adding a setpoint manager for a coil control logic to a heating coil.
6941
6941
  # ASHRAE 90.1-2019 Appendix G.
6942
6942
  #
6943
- # @param model [OpenStudio::Model::Model] Openstudio model
6943
+ # @param model [OpenStudio::Model::Model] OpenStudio model
6944
6944
  # @param thermalZones Array([OpenStudio::Model::ThermalZone]) thermal zone array
6945
6945
  # @param coil Heating Coils
6946
6946
  # @return [Boolean] true
@@ -6951,7 +6951,7 @@ class Standard
6951
6951
  # Template method for adding zone additional property "zone DCV implemented in user model"
6952
6952
  #
6953
6953
  # @author Xuechen (Jerry) Lei, PNNL
6954
- # @param model [OpenStudio::Model::Model] Openstudio model
6954
+ # @param model [OpenStudio::Model::Model] OpenStudio model
6955
6955
  def model_mark_zone_dcv_existence(model)
6956
6956
  return true
6957
6957
  end
@@ -6960,7 +6960,7 @@ class Standard
6960
6960
  # The default shall be true
6961
6961
  #
6962
6962
  # @param [Boolean] run_all_orients: user inputs to indicate whether it is required to run all orientations
6963
- # @param [OpenStudio::Model::Model] Openstudio model
6963
+ # @param [OpenStudio::Model::Model] OpenStudio model
6964
6964
  def run_all_orientations(run_all_orients, user_model)
6965
6965
  return run_all_orients
6966
6966
  end
@@ -6968,7 +6968,7 @@ class Standard
6968
6968
  # Template method for reading user data and adding to zone additional properties
6969
6969
  #
6970
6970
  # @author Xuechen (Jerry) Lei, PNNL
6971
- # @param model [OpenStudio::Model::Model] Openstudio model
6971
+ # @param model [OpenStudio::Model::Model] OpenStudio model
6972
6972
  def model_add_dcv_user_exception_properties(model)
6973
6973
  return true
6974
6974
  end
@@ -6976,7 +6976,7 @@ class Standard
6976
6976
  # Template method for raising user model DCV warning and errors
6977
6977
  #
6978
6978
  # @author Xuechen (Jerry) Lei, PNNL
6979
- # @param model [OpenStudio::Model::Model] Openstudio model
6979
+ # @param model [OpenStudio::Model::Model] OpenStudio model
6980
6980
  def model_raise_user_model_dcv_errors(model)
6981
6981
  return true
6982
6982
  end
@@ -6984,7 +6984,7 @@ class Standard
6984
6984
  # Template method for adding zone additional property "airloop dcv required by 901" and "zone dcv required by 901"
6985
6985
  #
6986
6986
  # @author Xuechen (Jerry) Lei, PNNL
6987
- # @param model [OpenStudio::Model::Model] Openstudio model
6987
+ # @param model [OpenStudio::Model::Model] OpenStudio model
6988
6988
  def model_add_dcv_requirement_properties(model)
6989
6989
  return true
6990
6990
  end
@@ -6993,7 +6993,7 @@ class Standard
6993
6993
  # Zone additional property 'apxg no need to have DCV' added
6994
6994
  #
6995
6995
  # @author Xuechen (Jerry) Lei, PNNL
6996
- # @param model [OpenStudio::Model::Model] Openstudio model
6996
+ # @param model [OpenStudio::Model::Model] OpenStudio model
6997
6997
  def model_add_apxg_dcv_properties(model)
6998
6998
  return true
6999
6999
  end
@@ -7001,14 +7001,14 @@ class Standard
7001
7001
  # Template method for setting DCV in baseline HVAC system if required
7002
7002
  #
7003
7003
  # @author Xuechen (Jerry) Lei, PNNL
7004
- # @param model [OpenStudio::Model::Model] Openstudio model
7004
+ # @param model [OpenStudio::Model::Model] OpenStudio model
7005
7005
  def model_set_baseline_demand_control_ventilation(model, climate_zone)
7006
7006
  return true
7007
7007
  end
7008
7008
 
7009
7009
  # Identify the return air type associated with each thermal zone
7010
7010
  #
7011
- # @param model [OpenStudio::Model::Model] Openstudio model object
7011
+ # @param model [OpenStudio::Model::Model] OpenStudio model object
7012
7012
  def model_identify_return_air_type(model)
7013
7013
  # air-loop based system
7014
7014
  model.getThermalZones.each do |zone|
@@ -7,7 +7,7 @@ class Standard
7
7
  # create a construction that meets those properties and assign it to this surface.
8
8
  # 90.1-2007, 90.1-2010, 90.1-2013
9
9
  #
10
- # @param planar_surface [Openstudio::Model:PlanarSurface] surface object
10
+ # @param planar_surface [OpenStudio::Model:PlanarSurface] surface object
11
11
  # @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A'
12
12
  # @param previous_construction_map [Hash] a hash where the keys are an array of inputs
13
13
  # [template, climate_zone, intended_surface_type, standards_construction_type, occ_type]
@@ -144,6 +144,7 @@ class Standard
144
144
  # Zone HVAC operating schedule if providing ventilation
145
145
  # Zone HVAC components return an OptionalSchedule object for supplyAirFanOperatingModeSchedule
146
146
  # except for ZoneHVACTerminalUnitVariableRefrigerantFlow which returns a Schedule
147
+ # and starting at 3.5.0, PTAC / PTHP also return a Schedule, optional before that
147
148
  existing_sch = nil
148
149
  if zone_hvac_component.to_ZoneHVACFourPipeFanCoil.is_initialized
149
150
  zone_hvac_component = zone_hvac_component.to_ZoneHVACFourPipeFanCoil.get
@@ -161,7 +162,7 @@ class Standard
161
162
  ventilation = true if oa_rate > 0.0
162
163
  end
163
164
  ventilation = true if zone_hvac_component.isOutdoorAirFlowRateWhenNoCoolingorHeatingisNeededAutosized
164
- fan_op_sch = zone_hvac_component.supplyAirFanOperatingModeSchedule
165
+ fan_op_sch = OpenStudio::Model::OptionalSchedule.new(zone_hvac_component.supplyAirFanOperatingModeSchedule)
165
166
  existing_sch = fan_op_sch.get if fan_op_sch.is_initialized
166
167
  elsif zone_hvac_component.to_ZoneHVACPackagedTerminalHeatPump.is_initialized
167
168
  zone_hvac_component = zone_hvac_component.to_ZoneHVACPackagedTerminalHeatPump.get
@@ -170,7 +171,7 @@ class Standard
170
171
  ventilation = true if oa_rate > 0.0
171
172
  end
172
173
  ventilation = true if zone_hvac_component.isOutdoorAirFlowRateWhenNoCoolingorHeatingisNeededAutosized
173
- fan_op_sch = zone_hvac_component.supplyAirFanOperatingModeSchedule
174
+ fan_op_sch = OpenStudio::Model::OptionalSchedule.new(zone_hvac_component.supplyAirFanOperatingModeSchedule)
174
175
  existing_sch = fan_op_sch.get if fan_op_sch.is_initialized
175
176
  elsif zone_hvac_component.to_ZoneHVACTerminalUnitVariableRefrigerantFlow.is_initialized
176
177
  zone_hvac_component = zone_hvac_component.to_ZoneHVACTerminalUnitVariableRefrigerantFlow.get