openstudio-standards 0.2.3 → 0.2.4

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/data/geometry/ASHRAE90120042007LargeHotel.osm +55 -55
  3. data/data/geometry/ASHRAE9012010LargeHotel.osm +56 -56
  4. data/data/geometry/ASHRAE9012010SuperMarket.osm +153 -153
  5. data/data/geometry/ASHRAE9012013Hospital.osm +815 -874
  6. data/data/geometry/ASHRAE9012013LargeHotel.osm +56 -56
  7. data/data/geometry/ASHRAE9012013LargeOffice.osm +12 -3
  8. data/data/geometry/ASHRAE9012013MediumOffice.osm +8 -16
  9. data/data/geometry/ASHRAE9012013MidriseApartment.osm +792 -792
  10. data/data/geometry/ASHRAE9012013SuperMarket.osm +152 -152
  11. data/data/geometry/ASHRAEHospital.osm +815 -874
  12. data/data/geometry/ASHRAELargeOffice.osm +58 -49
  13. data/data/geometry/ASHRAEMediumOffice.osm +12 -3
  14. data/data/geometry/ASHRAEMidriseApartment.osm +792 -792
  15. data/data/geometry/ASHRAESmallOffice.osm +4 -4
  16. data/data/geometry/ASHRAESuperMarket.osm +152 -152
  17. data/data/geometry/DOERefLargeOffice.osm +38 -29
  18. data/data/geometry/DOERefMidriseApartment.osm +792 -792
  19. data/data/geometry/DOERefPre1980SmallOffice.osm +4 -4
  20. data/data/geometry/DOERefSmallHotel.osm +4 -4
  21. data/data/geometry/DOERefWarehouse.osm +80 -30
  22. data/data/standards/OpenStudio_Standards.xlsx +0 -0
  23. data/data/standards/OpenStudio_Standards_construction_sets.json +582 -238
  24. data/data/standards/OpenStudio_Standards_constructions.json +14 -14
  25. data/data/standards/OpenStudio_Standards_hvac_inference.json +741 -0
  26. data/data/standards/OpenStudio_Standards_prototype_inputs.json +12 -12
  27. data/data/standards/OpenStudio_Standards_schedules.json +1479 -622
  28. data/data/standards/OpenStudio_Standards_size_category.json +67 -0
  29. data/data/standards/OpenStudio_Standards_space_types.json +2640 -2032
  30. data/lib/openstudio-standards.rb +1 -0
  31. data/lib/openstudio-standards/btap/btap.rb +0 -1
  32. data/lib/openstudio-standards/btap/simmanager.rb +3 -10
  33. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.LargeOffice.rb +24 -0
  34. data/lib/openstudio-standards/prototypes/common/buildings/Prototype.MediumOffice.rb +29 -4
  35. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.elevators.rb +1 -1
  36. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.hvac.rb +68 -3
  37. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.rb +1 -1
  38. data/lib/openstudio-standards/prototypes/common/objects/Prototype.SizingSystem.rb +36 -0
  39. data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +743 -730
  40. data/lib/openstudio-standards/prototypes/common/objects/Prototype.utilities.rb +7 -2
  41. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +1 -1
  42. data/lib/openstudio-standards/standards/Standards.Model.rb +95 -170
  43. data/lib/openstudio-standards/standards/Standards.Space.rb +1 -1
  44. data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/nrel_zne_ready_2017.AirLoopHVAC.rb +34 -1
  45. data/lib/openstudio-standards/standards/standard.rb +2 -0
  46. data/lib/openstudio-standards/version.rb +1 -1
  47. metadata +5 -2
@@ -253,6 +253,7 @@ module OpenstudioStandards
253
253
  require_relative "#{proto}/common/objects/Prototype.Model.swh"
254
254
  require_relative "#{proto}/common/objects/Prototype.refrigeration"
255
255
  require_relative "#{proto}/common/objects/Prototype.ServiceWaterHeating"
256
+ require_relative "#{proto}/common/objects/Prototype.SizingSystem"
256
257
  require_relative "#{proto}/common/objects/Prototype.utilities"
257
258
  # 90.1-2004
258
259
  require_relative "#{proto}/ashrae_90_1/ashrae_90_1_2004/ashrae_90_1_2004.AirTerminalSingleDuctVAVReheat"
@@ -18,7 +18,6 @@
18
18
  # **********************************************************************/
19
19
 
20
20
 
21
- require 'openstudio/energyplus/find_energyplus'
22
21
  require 'fileutils'
23
22
  require 'singleton'
24
23
  require 'find'
@@ -101,12 +101,10 @@ module BTAP
101
101
 
102
102
 
103
103
  def getPaths
104
- # Find EnergyPlus on this computer.
105
- @ep_hash = OpenStudio::EnergyPlus::find_energyplus(BTAP::ENERGY_PLUS_MAJOR_VERSION,BTAP::ENERGY_PLUS_MINOR_VERSION)
106
104
  #set the Energyplus.exe path variable
107
- @ep_path = OpenStudio::Path.new( @ep_hash[:energyplus_exe].to_s)
105
+ @ep_path = OpenStudio.getEnergyPlusExecutable
108
106
  #set the root folder for E+
109
- @ep_parent_path = @ep_path.parent_path();
107
+ @ep_parent_path = OpenStudio.getEnergyPlusDirectory
110
108
 
111
109
  #find IDD path
112
110
  idd_path = @ep_parent_path.to_s + "/Energy+.idd"
@@ -146,12 +144,7 @@ module BTAP
146
144
  #@author Phylroy A. Lopez
147
145
  #@return [String] a simple string of the epw file path, remember to escape the slashes..(i.e. // not / )
148
146
  def self.find_energyplus_folder()
149
- # Find EnergyPlus on this computer.
150
- ep_hash = OpenStudio::EnergyPlus::find_energyplus(BTAP::ENERGY_PLUS_MAJOR_VERSION,BTAP::ENERGY_PLUS_MINOR_VERSION)
151
- #set the Energyplus.exe path variable
152
- ep_path = OpenStudio::Path.new( ep_hash[:energyplus_exe].to_s)
153
- #set the root folder for E+
154
- return ep_path.parent_path();
147
+ return OpenStudio.getEnergyPlusDirectory.to_s
155
148
  end
156
149
 
157
150
  #This method finds the eReadVarsESO.exe and returns the path string.
@@ -75,6 +75,30 @@ module LargeOffice
75
75
  end
76
76
  end
77
77
 
78
+ # set infiltration schedule for plenums
79
+ # @todo remove once infil_sch in Standards.Space pulls from default building infiltration schedule
80
+ model.getSpaces.each do |space|
81
+ next unless space.name.get.to_s.include? 'Plenum'
82
+ # add infiltration if DOE Ref vintage
83
+ if template == 'DOE Ref 1980-2004' || template == 'DOE Ref Pre-1980'
84
+ # Create an infiltration rate object for this space
85
+ infiltration = OpenStudio::Model::SpaceInfiltrationDesignFlowRate.new(space.model)
86
+ infiltration.setName("#{space.name} Infiltration")
87
+ all_ext_infil_m3_per_s_per_m2 = OpenStudio.convert(0.2232, 'ft^3/min*ft^2', 'm^3/s*m^2').get
88
+ infiltration.setFlowperExteriorSurfaceArea(all_ext_infil_m3_per_s_per_m2)
89
+ infiltration.setSchedule(model_add_schedule(model, 'Large Office Infil Quarter On'))
90
+ infiltration.setConstantTermCoefficient(1.0)
91
+ infiltration.setTemperatureTermCoefficient(0.0)
92
+ infiltration.setVelocityTermCoefficient(0.0)
93
+ infiltration.setVelocitySquaredTermCoefficient(0.0)
94
+ infiltration.setSpace(space)
95
+ else
96
+ space.spaceInfiltrationDesignFlowRates.each do |infiltration_object|
97
+ infiltration_object.setSchedule(model_add_schedule(model, 'OfficeLarge INFIL_SCH_PNNL'))
98
+ end
99
+ end
100
+ end
101
+
78
102
  return true
79
103
  end
80
104
 
@@ -25,6 +25,30 @@ module MediumOffice
25
25
  add_door_infiltration(climate_zone, model)
26
26
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Added door infiltration')
27
27
 
28
+ # set infiltration schedule for plenums
29
+ # @todo remove once infil_sch in Standards.Space pulls from default building infiltration schedule
30
+ model.getSpaces.each do |space|
31
+ next unless space.name.get.to_s.include? 'Plenum'
32
+ # add infiltration if DOE Ref vintage
33
+ if template == 'DOE Ref 1980-2004' || template == 'DOE Ref Pre-1980'
34
+ # Create an infiltration rate object for this space
35
+ infiltration = OpenStudio::Model::SpaceInfiltrationDesignFlowRate.new(space.model)
36
+ infiltration.setName("#{space.name} Infiltration")
37
+ all_ext_infil_m3_per_s_per_m2 = OpenStudio.convert(0.2232, 'ft^3/min*ft^2', 'm^3/s*m^2').get
38
+ infiltration.setFlowperExteriorSurfaceArea(all_ext_infil_m3_per_s_per_m2)
39
+ infiltration.setSchedule(model_add_schedule(model, 'Medium Office Infil Quarter On'))
40
+ infiltration.setConstantTermCoefficient(1.0)
41
+ infiltration.setTemperatureTermCoefficient(0.0)
42
+ infiltration.setVelocityTermCoefficient(0.0)
43
+ infiltration.setVelocitySquaredTermCoefficient(0.0)
44
+ infiltration.setSpace(space)
45
+ else
46
+ space.spaceInfiltrationDesignFlowRates.each do |infiltration_object|
47
+ infiltration_object.setSchedule(model_add_schedule(model, 'OfficeMedium INFIL_SCH_PNNL'))
48
+ end
49
+ end
50
+ end
51
+
28
52
  return true
29
53
  end
30
54
 
@@ -59,10 +83,11 @@ module MediumOffice
59
83
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Adjusting daylight sensor positions and fractions')
60
84
 
61
85
  adjustments = [
62
- { 'stds_spc_type' => 'WholeBuilding - Md Office',
63
- 'sensor_1_frac' => 0.3835,
64
- 'sensor_2_frac' => 0.1395,
65
- }
86
+ {
87
+ 'stds_spc_type' => 'WholeBuilding - Md Office',
88
+ 'sensor_1_frac' => 0.3835,
89
+ 'sensor_2_frac' => 0.1395
90
+ }
66
91
  ]
67
92
 
68
93
  # Adjust daylight sensors in each space
@@ -304,7 +304,7 @@ class Standard
304
304
  'building_type' => building_type
305
305
  }
306
306
 
307
- prototype_input = model_find_object(standards_data['prototype_inputs'], search_criteria, nil)
307
+ prototype_input = model_find_object(standards_data['prototype_inputs'], search_criteria)
308
308
  if prototype_input.nil?
309
309
  OpenStudio.logFree(OpenStudio::Error, 'openstudio.prototype.elevators', "Could not find prototype inputs for #{search_criteria}, cannot add elevators.")
310
310
  return nil
@@ -263,9 +263,9 @@ class Standard
263
263
  fan_type: system['fan_type'])
264
264
 
265
265
  when 'PTHP'
266
- model_add_pthp(model,
267
- thermal_zones,
268
- fan_type: system['fan_type'])
266
+ model_add_pthp(model,
267
+ thermal_zones,
268
+ fan_type: system['fan_type'])
269
269
 
270
270
  when 'Exhaust Fan'
271
271
  model_add_exhaust_fan(model,
@@ -365,6 +365,71 @@ class Standard
365
365
  return true
366
366
  end # add hvac
367
367
 
368
+ # Determine the typical system type given the inputs.
369
+ #
370
+ # @param area_type [String] Valid choices are residential and nonresidential
371
+ # @param delivery_type [String] Conditioning delivery type. Valid choices are air and hydronic
372
+ # @param heating_source [String] Valid choices are Electricity, NaturalGas, DistrictHeating, DistrictAmbient
373
+ # @param cooling_source [String] Valid choices are Electricity, DistrictCooling, DistrictAmbient
374
+ # @param area_m2 [Double] Area in m^2
375
+ # @param num_stories [Integer] Number of stories
376
+ # @return [Array] An array containing the system type, central heating fuel, zone heating fuel, and cooling fuel
377
+ def model_typical_hvac_system_type(model,
378
+ climate_zone,
379
+ area_type,
380
+ delivery_type,
381
+ heating_source,
382
+ cooling_source,
383
+ area_m2,
384
+ num_stories)
385
+
386
+ # Convert area to ft^2
387
+ area_ft2 = OpenStudio.convert(area_m2, 'm^2', 'ft^2').get
388
+
389
+ case area_type
390
+ when 'residential'
391
+ area_type = 'Residential'
392
+ when 'nonresidential', 'retail', 'publicassembly', 'heatedonly'
393
+ area_type = 'Nonresidential'
394
+ else
395
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model', "area_type '#{area_type}' invalid or missing.")
396
+ return nil
397
+ end
398
+
399
+ # lookup size category
400
+ search_criteria = {}
401
+ search_criteria['template'] = template
402
+ search_criteria['building_category'] = area_type
403
+ size_data = model_find_object(standards_data['size_category'], search_criteria, nil, nil, area_ft2, num_stories)
404
+ if size_data.nil?
405
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model', "Unable to find size category for #{search_criteria}.")
406
+ return nil
407
+ end
408
+
409
+ # lookup infered HVAC system type
410
+ search_criteria = {}
411
+ search_criteria['template'] = template
412
+ search_criteria['size_category'] = size_data['size_category']
413
+ search_criteria['heating_source'] = heating_source
414
+ search_criteria['cooling_source'] = cooling_source
415
+ search_criteria['delivery_type'] = delivery_type
416
+ hvac_data = model_find_object(standards_data['hvac_inference'], search_criteria)
417
+
418
+ # return system type inputs with format [type, central_heating_fuel, zone_heating_fuel, cooling_fuel]
419
+ if hvac_data.nil? || hvac_data.empty?
420
+ system_type_inputs = [nil, nil, nil, nil]
421
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Model', "Could not determine system type for #{area_type} building of size #{area_ft2.round} ft^2 and #{num_stories} stories, and lookups #{search_criteria}.")
422
+ else
423
+ system_type_inputs = [hvac_data['hvac_system_type'], hvac_data['central_heating_fuel'], hvac_data['zone_heating_fuel'], hvac_data['cooling_fuel']]
424
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "System type is #{system_type_inputs[0]} for #{area_type} building of size #{area_ft2.round} ft^2 and #{num_stories} stories, and lookups #{search_criteria}.")
425
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "--- #{system_type_inputs[1]} for main heating") unless system_type_inputs[1].nil?
426
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "--- #{system_type_inputs[2]} for zone heat/reheat") unless system_type_inputs[2].nil?
427
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "--- #{system_type_inputs[3]} for cooling") unless system_type_inputs[3].nil?
428
+ end
429
+
430
+ return system_type_inputs
431
+ end
432
+
368
433
  private
369
434
 
370
435
  def model_get_zones_from_spaces_on_system(model, system)
@@ -435,7 +435,7 @@ Standard.class_eval do
435
435
  adj_space = adj_surface.space.get
436
436
  if adj_space.spaceType.is_initialized && adj_space.spaceType.get.standardsSpaceType.is_initialized
437
437
  adj_std_space_type = adj_space.spaceType.get.standardsSpaceType.get
438
- if adj_std_space_type == 'Plenum'
438
+ if adj_std_space_type.downcase == 'plenum'
439
439
  plenum_construction = adj_surface.construction
440
440
  if plenum_construction.is_initialized
441
441
  plenum_construction = plenum_construction.get
@@ -0,0 +1,36 @@
1
+ class Standard
2
+ # @!group Sizing System
3
+
4
+ # Prototype SizingSystem object
5
+ #
6
+ # @param air_loop_hvac [<OpenStudio::Model::AirLoopHVAC>] air loop to set sizing system properties
7
+ # @param dsgn_temps [Hash] a hash of design temperature lookups from standard_design_sizing_temperatures
8
+ def adjust_sizing_system(air_loop_hvac,
9
+ dsgn_temps,
10
+ type_of_load_sizing: 'Sensible',
11
+ min_sys_airflow_ratio: 0.3,
12
+ sizing_option: 'Coincident')
13
+
14
+ # adjust sizing system defaults
15
+ sizing_system = air_loop_hvac.sizingSystem
16
+ sizing_system.setTypeofLoadtoSizeOn(type_of_load_sizing)
17
+ sizing_system.autosizeDesignOutdoorAirFlowRate
18
+ sizing_system.setPreheatDesignTemperature(dsgn_temps['prehtg_dsgn_sup_air_temp_c'])
19
+ sizing_system.setPrecoolDesignTemperature(dsgn_temps['preclg_dsgn_sup_air_temp_c'])
20
+ sizing_system.setCentralCoolingDesignSupplyAirTemperature(dsgn_temps['clg_dsgn_sup_air_temp_c'])
21
+ sizing_system.setCentralHeatingDesignSupplyAirTemperature(dsgn_temps['htg_dsgn_sup_air_temp_c'])
22
+ sizing_system.setPreheatDesignHumidityRatio(0.008)
23
+ sizing_system.setPrecoolDesignHumidityRatio(0.008)
24
+ sizing_system.setCentralCoolingDesignSupplyAirHumidityRatio(0.0085)
25
+ sizing_system.setCentralHeatingDesignSupplyAirHumidityRatio(0.0080)
26
+ sizing_system.setMinimumSystemAirFlowRatio(min_sys_airflow_ratio)
27
+ sizing_system.setSizingOption(sizing_option)
28
+ sizing_system.setAllOutdoorAirinCooling(false)
29
+ sizing_system.setAllOutdoorAirinHeating(false)
30
+ sizing_system.setSystemOutdoorAirMethod('ZoneSum')
31
+ sizing_system.setCoolingDesignAirFlowMethod('DesignDay')
32
+ sizing_system.setHeatingDesignAirFlowMethod('DesignDay')
33
+
34
+ return sizing_system
35
+ end
36
+ end
@@ -1,6 +1,26 @@
1
1
  class Standard
2
2
  # @!group hvac_systems
3
3
 
4
+ # Returns standard design sizing temperatures
5
+
6
+ # @return [Hash] Hash of design sizing temperature lookups
7
+ def standard_design_sizing_temperatures
8
+ dsgn_temps = {}
9
+ dsgn_temps['prehtg_dsgn_sup_air_temp_f'] = 45.0
10
+ dsgn_temps['preclg_dsgn_sup_air_temp_f'] = 55.0
11
+ dsgn_temps['htg_dsgn_sup_air_temp_f'] = 55.0
12
+ dsgn_temps['clg_dsgn_sup_air_temp_f'] = 55.0
13
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_f'] = 104.0
14
+ dsgn_temps['zn_clg_dsgn_sup_air_temp_f'] = 55.0
15
+ dsgn_temps['prehtg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['prehtg_dsgn_sup_air_temp_f'], 'F', 'C').get
16
+ dsgn_temps['preclg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['preclg_dsgn_sup_air_temp_f'], 'F', 'C').get
17
+ dsgn_temps['htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['htg_dsgn_sup_air_temp_f'], 'F', 'C').get
18
+ dsgn_temps['clg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['clg_dsgn_sup_air_temp_f'], 'F', 'C').get
19
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_htg_dsgn_sup_air_temp_f'], 'F', 'C').get
20
+ dsgn_temps['zn_clg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_clg_dsgn_sup_air_temp_f'], 'F', 'C').get
21
+ return dsgn_temps
22
+ end
23
+
4
24
  # Creates a hot water loop with a boiler, district heating, or a
5
25
  # water-to-water heat pump and adds it to the model.
6
26
  #
@@ -113,7 +133,7 @@ class Standard
113
133
  end
114
134
 
115
135
  if boiler_out_temp_lmt.nil?
116
- out_temp_lmt = OpenStudio.convert(203, 'F', 'C').get
136
+ out_temp_lmt = OpenStudio.convert(203.0, 'F', 'C').get
117
137
  else
118
138
  out_temp_lmt = boiler_out_temp_lmt
119
139
  end
@@ -130,7 +150,7 @@ class Standard
130
150
  sizing_factor: boiler_sizing_factor)
131
151
 
132
152
  # TODO: Yixing. Adding temperature setpoint controller at boiler outlet causes simulation errors
133
- # boiler_stpt_manager = OpenStudio::Model::SetpointManagerScheduled.new(self,hw_temp_sch)
153
+ # boiler_stpt_manager = OpenStudio::Model::SetpointManagerScheduled.new(self, hw_temp_sch)
134
154
  # boiler_stpt_manager.setName("Boiler outlet setpoint manager")
135
155
  # boiler_stpt_manager.addToNode(boiler.outletModelObject.get.to_Node.get)
136
156
  else
@@ -688,12 +708,15 @@ class Standard
688
708
  loop_stpt_manager.addToNode(ground_hx_loop.supplyOutletNode)
689
709
 
690
710
  # sensor to read supply inlet temperature
691
- inlet_temp_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'System Node Temperature')
711
+ inlet_temp_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model,
712
+ 'System Node Temperature')
692
713
  inlet_temp_sensor.setName("#{ground_hx.name.to_s.gsub(/[ +-.]/,'_')} Inlet Temp Sensor")
693
714
  inlet_temp_sensor.setKeyName(ground_hx_loop.supplyInletNode.handle.to_s)
694
715
 
695
716
  # actuator to set supply outlet temperature
696
- outlet_temp_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(hx_temp_sch, 'Schedule:Constant', 'Schedule Value')
717
+ outlet_temp_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(hx_temp_sch,
718
+ 'Schedule:Constant',
719
+ 'Schedule Value')
697
720
  outlet_temp_actuator.setName("#{ground_hx.name} Outlet Temp Actuator")
698
721
 
699
722
  # program to control outlet temperature
@@ -747,17 +770,16 @@ class Standard
747
770
  amb_temp_sizing_c = OpenStudio.convert(amb_temp_sizing_f, 'F', 'C').get
748
771
  amb_delta_t_k = OpenStudio.convert(amb_delta_t_r, 'R', 'K').get
749
772
 
750
- amb_high_temp_sch = OpenStudio::Model::ScheduleRuleset.new(model)
751
- amb_high_temp_sch.setName("Ambient Loop High Temp - #{amb_high_temp_f}F")
752
- amb_high_temp_sch.defaultDaySchedule.setName("Ambient Loop High Temp - #{amb_high_temp_f}F Default")
753
- amb_high_temp_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), amb_high_temp_c)
773
+ amb_high_temp_sch = model_add_constant_schedule_ruleset(model,
774
+ amb_high_temp_c,
775
+ name = "Ambient Loop High Temp - #{amb_high_temp_f}F")
754
776
 
755
- amb_low_temp_sch = OpenStudio::Model::ScheduleRuleset.new(model)
756
- amb_low_temp_sch.setName("Ambient Loop Low Temp - #{amb_low_temp_f}F")
757
- amb_low_temp_sch.defaultDaySchedule.setName("Ambient Loop Low Temp - #{amb_low_temp_f}F Default")
758
- amb_low_temp_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), amb_low_temp_c)
777
+ amb_low_temp_sch = model_add_constant_schedule_ruleset(model,
778
+ amb_low_temp_c,
779
+ name = "Ambient Loop Low Temp - #{amb_low_temp_f}F")
759
780
 
760
781
  amb_stpt_manager = OpenStudio::Model::SetpointManagerScheduledDualSetpoint.new(model)
782
+ amb_stpt_manager.setName("#{ambient_loop.name} Supply Water Setpoint Manager")
761
783
  amb_stpt_manager.setHighSetpointSchedule(amb_high_temp_sch)
762
784
  amb_stpt_manager.setLowSetpointSchedule(amb_low_temp_sch)
763
785
  amb_stpt_manager.addToNode(ambient_loop.supplyOutletNode)
@@ -894,7 +916,10 @@ class Standard
894
916
  sizing_system.setCentralHeatingDesignSupplyAirTemperature(htg_dsgn_sup_air_temp_c)
895
917
 
896
918
  # create supply fan
897
- supply_fan = create_fan_by_name(model, 'Constant_DOAS_Fan', fan_name: 'DOAS Supply Fan', end_use_subcategory: 'DOAS Fans')
919
+ supply_fan = create_fan_by_name(model,
920
+ 'Constant_DOAS_Fan',
921
+ fan_name: 'DOAS Supply Fan',
922
+ end_use_subcategory: 'DOAS Fans')
898
923
  supply_fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
899
924
  supply_fan.setMaximumFlowRate(OpenStudio.convert(fan_maximum_flow_rate, 'cfm', 'm^3/s').get) unless fan_maximum_flow_rate.nil?
900
925
  supply_fan.addToNode(air_loop.supplyInletNode)
@@ -1019,11 +1044,11 @@ class Standard
1019
1044
  air_loop.addBranchForZone(zone, air_terminal.to_StraightComponent)
1020
1045
 
1021
1046
  # DOAS sizing
1022
- zone_sizing = zone.sizingZone
1023
- zone_sizing.setAccountforDedicatedOutdoorAirSystem(true)
1024
- zone_sizing.setDedicatedOutdoorAirSystemControlStrategy('ColdSupplyAir')
1025
- zone_sizing.setDedicatedOutdoorAirLowSetpointTemperatureforDesign(clg_dsgn_sup_air_temp_c)
1026
- zone_sizing.setDedicatedOutdoorAirHighSetpointTemperatureforDesign(htg_dsgn_sup_air_temp_c)
1047
+ sizing_zone = zone.sizingZone
1048
+ sizing_zone.setAccountforDedicatedOutdoorAirSystem(true)
1049
+ sizing_zone.setDedicatedOutdoorAirSystemControlStrategy('ColdSupplyAir')
1050
+ sizing_zone.setDedicatedOutdoorAirLowSetpointTemperatureforDesign(clg_dsgn_sup_air_temp_c)
1051
+ sizing_zone.setDedicatedOutdoorAirHighSetpointTemperatureforDesign(htg_dsgn_sup_air_temp_c)
1027
1052
  end
1028
1053
 
1029
1054
  return air_loop
@@ -1120,9 +1145,15 @@ class Standard
1120
1145
  sizing_system.setCentralHeatingDesignSupplyAirTemperature(htg_dsgn_sup_air_temp_c)
1121
1146
 
1122
1147
  if doas_type == 'DOASCV'
1123
- supply_fan = create_fan_by_name(model, 'Constant_DOAS_Fan', fan_name: 'DOAS Supply Fan', end_use_subcategory: 'DOAS Fans')
1148
+ supply_fan = create_fan_by_name(model,
1149
+ 'Constant_DOAS_Fan',
1150
+ fan_name: 'DOAS Supply Fan',
1151
+ end_use_subcategory: 'DOAS Fans')
1124
1152
  else # 'DOASVAV'
1125
- supply_fan = create_fan_by_name(model, 'Variable_DOAS_Fan', fan_name: 'DOAS Supply Fan', end_use_subcategory: 'DOAS Fans')
1153
+ supply_fan = create_fan_by_name(model,
1154
+ 'Variable_DOAS_Fan',
1155
+ fan_name: 'DOAS Supply Fan',
1156
+ end_use_subcategory: 'DOAS Fans')
1126
1157
  end
1127
1158
  supply_fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
1128
1159
  supply_fan.setMaximumFlowRate(OpenStudio.convert(fan_maximum_flow_rate, 'cfm', 'm^3/s').get) unless fan_maximum_flow_rate.nil?
@@ -1209,9 +1240,15 @@ class Standard
1209
1240
  # create an exhaust fan
1210
1241
  if include_exhaust_fan
1211
1242
  if doas_type == 'DOASCV'
1212
- exhaust_fan = create_fan_by_name(model, 'Constant_DOAS_Fan', fan_name: 'DOAS Exhaust Fan', end_use_subcategory: 'DOAS Fans')
1243
+ exhaust_fan = create_fan_by_name(model,
1244
+ 'Constant_DOAS_Fan',
1245
+ fan_name: 'DOAS Exhaust Fan',
1246
+ end_use_subcategory: 'DOAS Fans')
1213
1247
  else # 'DOASVAV'
1214
- exhaust_fan = create_fan_by_name(model, 'Variable_DOAS_Fan', fan_name: 'DOAS Exhaust Fan', end_use_subcategory: 'DOAS Fans')
1248
+ exhaust_fan = create_fan_by_name(model,
1249
+ 'Variable_DOAS_Fan',
1250
+ fan_name: 'DOAS Exhaust Fan',
1251
+ end_use_subcategory: 'DOAS Fans')
1215
1252
  end
1216
1253
  # set pressure rise 0.5 inH2O lower than supply fan, 0.5 inH2O minimum
1217
1254
  exhaust_fan_pressure_rise = supply_fan.pressureRise - OpenStudio.convert(0.5, 'inH_{2}O', 'Pa').get
@@ -1293,11 +1330,11 @@ class Standard
1293
1330
  air_loop.addBranchForZone(zone, air_terminal.to_StraightComponent)
1294
1331
 
1295
1332
  # DOAS sizing
1296
- zone_sizing = zone.sizingZone
1297
- zone_sizing.setAccountforDedicatedOutdoorAirSystem(true)
1298
- zone_sizing.setDedicatedOutdoorAirSystemControlStrategy(doas_control_strategy)
1299
- zone_sizing.setDedicatedOutdoorAirLowSetpointTemperatureforDesign(clg_dsgn_sup_air_temp_c)
1300
- zone_sizing.setDedicatedOutdoorAirHighSetpointTemperatureforDesign(htg_dsgn_sup_air_temp_c)
1333
+ sizing_zone = zone.sizingZone
1334
+ sizing_zone.setAccountforDedicatedOutdoorAirSystem(true)
1335
+ sizing_zone.setDedicatedOutdoorAirSystemControlStrategy(doas_control_strategy)
1336
+ sizing_zone.setDedicatedOutdoorAirLowSetpointTemperatureforDesign(clg_dsgn_sup_air_temp_c)
1337
+ sizing_zone.setDedicatedOutdoorAirHighSetpointTemperatureforDesign(htg_dsgn_sup_air_temp_c)
1301
1338
  end
1302
1339
 
1303
1340
  return air_loop
@@ -1337,12 +1374,20 @@ class Standard
1337
1374
  econo_ctrl_mthd: nil)
1338
1375
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Adding VAV system for #{thermal_zones.size} zones.")
1339
1376
 
1377
+ # create air handler
1378
+ air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
1379
+ if system_name.nil?
1380
+ air_loop.setName("#{thermal_zones.size} Zone VAV")
1381
+ else
1382
+ air_loop.setName(system_name)
1383
+ end
1384
+
1340
1385
  # hvac operation schedule
1341
- hvac_op_sch = if hvac_op_sch.nil?
1342
- model.alwaysOnDiscreteSchedule
1343
- else
1344
- model_add_schedule(model, hvac_op_sch)
1345
- end
1386
+ if hvac_op_sch.nil?
1387
+ hvac_op_sch = model.alwaysOnDiscreteSchedule
1388
+ else
1389
+ hvac_op_sch = model_add_schedule(model, hvac_op_sch)
1390
+ end
1346
1391
 
1347
1392
  # oa damper schedule
1348
1393
  if oa_damper_sch.nil?
@@ -1351,63 +1396,28 @@ class Standard
1351
1396
  oa_damper_sch = model_add_schedule(model, oa_damper_sch)
1352
1397
  end
1353
1398
 
1354
- # control temps used across all air handlers
1399
+ # default design temperatures and settings used across all air loops
1400
+ dsgn_temps = standard_design_sizing_temperatures
1401
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps)
1402
+ sizing_system.setMinimumSystemAirFlowRatio(min_sys_airflow_ratio) unless min_sys_airflow_ratio.nil?
1403
+ sizing_system.setSizingOption(vav_sizing_option) unless vav_sizing_option.nil?
1355
1404
  unless hot_water_loop.nil?
1356
1405
  hw_temp_c = hot_water_loop.sizingPlant.designLoopExitTemperature
1357
1406
  hw_delta_t_k = hot_water_loop.sizingPlant.loopDesignTemperatureDifference
1358
1407
  end
1359
- clg_sa_temp_f = 55.04
1360
- prehtg_sa_temp_f = 44.6
1361
- preclg_sa_temp_f = 55.04
1362
- htg_sa_temp_f = 55.04
1363
- zone_htg_sa_temp_f = 104.0
1364
- rht_sa_temp_f = 104.0
1365
- clg_sa_temp_c = OpenStudio.convert(clg_sa_temp_f, 'F', 'C').get
1366
- prehtg_sa_temp_c = OpenStudio.convert(prehtg_sa_temp_f, 'F', 'C').get
1367
- preclg_sa_temp_c = OpenStudio.convert(preclg_sa_temp_f, 'F', 'C').get
1368
- htg_sa_temp_c = OpenStudio.convert(htg_sa_temp_f, 'F', 'C').get
1369
- rht_sa_temp_c = OpenStudio.convert(rht_sa_temp_f, 'F', 'C').get
1370
- zone_htg_sa_temp_c = OpenStudio.convert(zone_htg_sa_temp_f, 'F', 'C').get
1371
- sa_temp_sch = OpenStudio::Model::ScheduleRuleset.new(model)
1372
- sa_temp_sch.setName("Supply Air Temp - #{clg_sa_temp_f}F")
1373
- sa_temp_sch.defaultDaySchedule.setName("Supply Air Temp - #{clg_sa_temp_f}F Default")
1374
- sa_temp_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), clg_sa_temp_c)
1375
-
1376
- # create air handler
1377
- air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
1378
- if system_name.nil?
1379
- air_loop.setName("#{thermal_zones.size} Zone VAV")
1380
- else
1381
- air_loop.setName(system_name)
1382
- end
1383
1408
 
1409
+ # air handler controls
1410
+ sa_temp_sch = model_add_constant_schedule_ruleset(model,
1411
+ dsgn_temps['clg_dsgn_sup_air_temp_c'],
1412
+ name = "Supply Air Temp - #{dsgn_temps['clg_dsgn_sup_air_temp_f']}F")
1384
1413
  sa_stpt_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, sa_temp_sch)
1385
- sa_stpt_manager.setName("#{thermal_zones.size} Zone VAV supply air setpoint manager")
1414
+ sa_stpt_manager.setName("#{air_loop.name} Supply Air Setpoint Manager")
1386
1415
  sa_stpt_manager.addToNode(air_loop.supplyOutletNode)
1387
1416
 
1388
- # air handler controls
1389
- sizing_system = air_loop.sizingSystem
1390
- if min_sys_airflow_ratio.nil?
1391
- sizing_system.setMinimumSystemAirFlowRatio(0.3)
1392
- else
1393
- sizing_system.setMinimumSystemAirFlowRatio(min_sys_airflow_ratio)
1394
- end
1395
- # sizing_system.setPreheatDesignTemperature(htg_oa_tdb_c)
1396
- sizing_system.setPrecoolDesignTemperature(preclg_sa_temp_c)
1397
- sizing_system.setCentralCoolingDesignSupplyAirTemperature(clg_sa_temp_c)
1398
- sizing_system.setCentralHeatingDesignSupplyAirTemperature(htg_sa_temp_c)
1399
- if vav_sizing_option.nil?
1400
- sizing_system.setSizingOption('Coincident')
1401
- else
1402
- sizing_system.setSizingOption(vav_sizing_option) unless vav_sizing_option.nil?
1403
- end
1404
- sizing_system.setAllOutdoorAirinCooling(false)
1405
- sizing_system.setAllOutdoorAirinHeating(false)
1406
- sizing_system.setSystemOutdoorAirMethod('ZoneSum')
1407
-
1408
1417
  # create fan
1409
1418
  # @type [OpenStudio::Model::FanVariableVolume] fan
1410
- fan = create_fan_by_name(model, 'VAV_System_Fan',
1419
+ fan = create_fan_by_name(model,
1420
+ 'VAV_System_Fan',
1411
1421
  fan_name: "#{air_loop.name} Fan",
1412
1422
  fan_efficiency: fan_efficiency,
1413
1423
  pressure_rise: fan_pressure_rise,
@@ -1428,8 +1438,8 @@ class Standard
1428
1438
  name: "#{air_loop.name} Main Htg Coil",
1429
1439
  rated_inlet_water_temperature: hw_temp_c,
1430
1440
  rated_outlet_water_temperature: (hw_temp_c - hw_delta_t_k),
1431
- rated_inlet_air_temperature: prehtg_sa_temp_c,
1432
- rated_outlet_air_temperature: htg_sa_temp_c)
1441
+ rated_inlet_air_temperature: dsgn_temps['prehtg_dsgn_sup_air_temp_c'],
1442
+ rated_outlet_air_temperature: dsgn_temps['htg_dsgn_sup_air_temp_c'])
1433
1443
  end
1434
1444
 
1435
1445
  # create cooling coil
@@ -1478,41 +1488,57 @@ class Standard
1478
1488
 
1479
1489
  # create reheat coil
1480
1490
  case reheat_type
1481
- when 'NaturalGas'
1482
- rht_coil = create_coil_heating_gas(model, name: "#{zone.name} Gas Reheat Coil")
1491
+ when 'NaturalGas', 'Gas'
1492
+ rht_coil = create_coil_heating_gas(model,
1493
+ name: "#{zone.name} Gas Reheat Coil")
1483
1494
  when 'Electricity'
1484
- rht_coil = create_coil_heating_electric(model, name: "#{zone.name} Electric Reheat Coil")
1495
+ rht_coil = create_coil_heating_electric(model,
1496
+ name: "#{zone.name} Electric Reheat Coil")
1485
1497
  when 'Water'
1486
1498
  rht_coil = create_coil_heating_water(model,
1487
1499
  hot_water_loop,
1488
1500
  name: "#{zone.name} Reheat Coil",
1489
1501
  rated_inlet_water_temperature: hw_temp_c,
1490
1502
  rated_outlet_water_temperature: (hw_temp_c - hw_delta_t_k),
1491
- rated_inlet_air_temperature: htg_sa_temp_c,
1492
- rated_outlet_air_temperature: rht_sa_temp_c)
1503
+ rated_inlet_air_temperature: dsgn_temps['htg_dsgn_sup_air_temp_c'],
1504
+ rated_outlet_air_temperature: dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
1493
1505
  else
1494
- # Zero-capacity, always-off electric heating coil
1495
- rht_coil = create_coil_heating_electric(model,
1496
- name: "#{zone.name} No Reheat",
1497
- schedule: model.alwaysOffDiscreteSchedule,
1498
- nominal_capacity: 0.0)
1506
+ # no reheat
1507
+ OpenStudio.logFree(OpenStudio::Debug, 'openstudio.Model.Model', "No reheat coil for terminal in #{zone.name}")
1499
1508
  end
1500
1509
 
1501
- # create vav terminal
1502
- terminal = OpenStudio::Model::AirTerminalSingleDuctVAVReheat.new(model, model.alwaysOnDiscreteSchedule, rht_coil)
1503
- terminal.setName("#{zone.name} VAV Terminal")
1504
- terminal.setZoneMinimumAirFlowMethod('Constant')
1505
- air_terminal_single_duct_vav_reheat_apply_initial_prototype_damper_position(terminal, thermal_zone_outdoor_airflow_rate_per_area(zone))
1506
- terminal.setMaximumFlowFractionDuringReheat(0.5)
1507
- terminal.setMaximumReheatAirTemperature(rht_sa_temp_c)
1508
- air_loop.addBranchForZone(zone, terminal.to_StraightComponent)
1509
-
1510
- # zone sizing
1511
- sizing_zone = zone.sizingZone
1512
- sizing_zone.setCoolingDesignAirFlowMethod('DesignDayWithLimit')
1513
- sizing_zone.setHeatingDesignAirFlowMethod('DesignDay')
1514
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(clg_sa_temp_c)
1515
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(zone_htg_sa_temp_c)
1510
+ # set zone reheat temperatures depending on reheat
1511
+ case reheat_type
1512
+ when 'NaturalGas', 'Gas', 'Electricity', 'Water'
1513
+ # create vav terminal
1514
+ terminal = OpenStudio::Model::AirTerminalSingleDuctVAVReheat.new(model, model.alwaysOnDiscreteSchedule, rht_coil)
1515
+ terminal.setName("#{zone.name} VAV Terminal")
1516
+ terminal.setZoneMinimumAirFlowMethod('Constant')
1517
+ air_terminal_single_duct_vav_reheat_apply_initial_prototype_damper_position(terminal, thermal_zone_outdoor_airflow_rate_per_area(zone))
1518
+ terminal.setMaximumFlowFractionDuringReheat(0.5)
1519
+ terminal.setMaximumReheatAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
1520
+ air_loop.addBranchForZone(zone, terminal.to_StraightComponent)
1521
+
1522
+ # zone sizing
1523
+ sizing_zone = zone.sizingZone
1524
+ sizing_zone.setCoolingDesignAirFlowMethod('DesignDayWithLimit')
1525
+ sizing_zone.setHeatingDesignAirFlowMethod('DesignDay')
1526
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
1527
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
1528
+ else
1529
+ # no reheat
1530
+ # create vav terminal
1531
+ terminal = OpenStudio::Model::AirTerminalSingleDuctVAVNoReheat.new(model, model.alwaysOnDiscreteSchedule)
1532
+ terminal.setName("#{zone.name} VAV Terminal")
1533
+ terminal.setZoneMinimumAirFlowInputMethod('Constant')
1534
+ air_terminal_single_duct_vav_reheat_apply_initial_prototype_damper_position(terminal, thermal_zone_outdoor_airflow_rate_per_area(zone))
1535
+ air_loop.addBranchForZone(zone, terminal.to_StraightComponent)
1536
+
1537
+ # zone sizing
1538
+ sizing_zone = zone.sizingZone
1539
+ sizing_zone.setCoolingDesignAirFlowMethod('DesignDayWithLimit')
1540
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
1541
+ end
1516
1542
 
1517
1543
  unless return_plenum.nil?
1518
1544
  zone.setReturnPlenum(return_plenum)
@@ -1547,6 +1573,14 @@ class Standard
1547
1573
  fan_pressure_rise: 4.0)
1548
1574
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Adding VAV with PFP Boxes and Reheat system for #{thermal_zones.size} zones.")
1549
1575
 
1576
+ # create air handler
1577
+ air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
1578
+ if system_name.nil?
1579
+ air_loop.setName("#{thermal_zones.size} Zone VAV with PFP Boxes and Reheat")
1580
+ else
1581
+ air_loop.setName(system_name)
1582
+ end
1583
+
1550
1584
  # hvac operation schedule
1551
1585
  if hvac_op_sch.nil?
1552
1586
  hvac_op_sch = model.alwaysOnDiscreteSchedule
@@ -1561,50 +1595,22 @@ class Standard
1561
1595
  oa_damper_sch = model_add_schedule(model, oa_damper_sch)
1562
1596
  end
1563
1597
 
1564
- # control temps used across all air handlers
1565
- clg_sa_temp_f = 55.04 # Central deck clg temp 55F
1566
- prehtg_sa_temp_f = 44.6 # Preheat to 44.6F
1567
- preclg_sa_temp_f = 55.04 # Precool to 55F
1568
- htg_sa_temp_f = 55.04 # Central deck htg temp 55F
1569
- rht_sa_temp_f = 104 # VAV box reheat to 104F
1570
- zone_htg_sa_temp_f = 104 # Zone heating design supply air temperature to 104 F
1571
- clg_sa_temp_c = OpenStudio.convert(clg_sa_temp_f, 'F', 'C').get
1572
- prehtg_sa_temp_c = OpenStudio.convert(prehtg_sa_temp_f, 'F', 'C').get
1573
- preclg_sa_temp_c = OpenStudio.convert(preclg_sa_temp_f, 'F', 'C').get
1574
- htg_sa_temp_c = OpenStudio.convert(htg_sa_temp_f, 'F', 'C').get
1575
- rht_sa_temp_c = OpenStudio.convert(rht_sa_temp_f, 'F', 'C').get
1576
- zone_htg_sa_temp_c = OpenStudio.convert(zone_htg_sa_temp_f, 'F', 'C').get
1577
- sa_temp_sch = OpenStudio::Model::ScheduleRuleset.new(model)
1578
- sa_temp_sch.setName("Supply Air Temp - #{clg_sa_temp_f}F")
1579
- sa_temp_sch.defaultDaySchedule.setName("Supply Air Temp - #{clg_sa_temp_f}F Default")
1580
- sa_temp_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), clg_sa_temp_c)
1581
-
1582
- # create air handler
1583
- air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
1584
- if system_name.nil?
1585
- air_loop.setName("#{thermal_zones.size} Zone VAV with PFP Boxes and Reheat")
1586
- else
1587
- air_loop.setName(system_name)
1588
- end
1598
+ # default design temperatures and settings used across all air loops
1599
+ dsgn_temps = standard_design_sizing_temperatures
1600
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps)
1589
1601
 
1602
+ # air handler controls
1603
+ sa_temp_sch = model_add_constant_schedule_ruleset(model,
1604
+ dsgn_temps['clg_dsgn_sup_air_temp_c'],
1605
+ name = "Supply Air Temp - #{dsgn_temps['clg_dsgn_sup_air_temp_f']}F")
1590
1606
  sa_stpt_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, sa_temp_sch)
1591
- sa_stpt_manager.setName("#{thermal_zones.size} Zone VAV supply air setpoint manager")
1607
+ sa_stpt_manager.setName("#{air_loop.name} Supply Air Setpoint Manager")
1592
1608
  sa_stpt_manager.addToNode(air_loop.supplyOutletNode)
1593
1609
 
1594
- # air handler controls
1595
- sizing_system = air_loop.sizingSystem
1596
- sizing_system.setPreheatDesignTemperature(prehtg_sa_temp_c)
1597
- sizing_system.setPrecoolDesignTemperature(preclg_sa_temp_c)
1598
- sizing_system.setCentralCoolingDesignSupplyAirTemperature(clg_sa_temp_c)
1599
- sizing_system.setCentralHeatingDesignSupplyAirTemperature(htg_sa_temp_c)
1600
- sizing_system.setSizingOption('Coincident')
1601
- sizing_system.setAllOutdoorAirinCooling(false)
1602
- sizing_system.setAllOutdoorAirinHeating(false)
1603
- sizing_system.setSystemOutdoorAirMethod('ZoneSum')
1604
-
1605
1610
  # create fan
1606
1611
  # @type [OpenStudio::Model::FanVariableVolume] fan
1607
- fan = create_fan_by_name(model, 'VAV_System_Fan',
1612
+ fan = create_fan_by_name(model,
1613
+ 'VAV_System_Fan',
1608
1614
  fan_name: "#{air_loop.name} Fan",
1609
1615
  fan_efficiency: fan_efficiency,
1610
1616
  pressure_rise: fan_pressure_rise,
@@ -1647,11 +1653,14 @@ class Standard
1647
1653
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Adding VAV with PFP Boxes and Reheat system terminal for #{zone.name}.")
1648
1654
 
1649
1655
  # create reheat coil
1650
- rht_coil = create_coil_heating_electric(model, name: "#{zone.name} Electric Reheat Coil")
1656
+ rht_coil = create_coil_heating_electric(model,
1657
+ name: "#{zone.name} Electric Reheat Coil")
1651
1658
 
1652
1659
  # create terminal fan
1653
1660
  # @type [OpenStudio::Model::FanConstantVolume] pfp_fan
1654
- pfp_fan = create_fan_by_name(model, 'PFP_Fan', fan_name: "#{zone.name} PFP Term Fan")
1661
+ pfp_fan = create_fan_by_name(model,
1662
+ 'PFP_Fan',
1663
+ fan_name: "#{zone.name} PFP Term Fan")
1655
1664
  pfp_fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
1656
1665
 
1657
1666
  # create parallel fan powered terminal
@@ -1666,9 +1675,8 @@ class Standard
1666
1675
  sizing_zone = zone.sizingZone
1667
1676
  sizing_zone.setCoolingDesignAirFlowMethod('DesignDay')
1668
1677
  sizing_zone.setHeatingDesignAirFlowMethod('DesignDay')
1669
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(clg_sa_temp_c)
1670
- # sizing_zone.setZoneHeatingDesignSupplyAirTemperature(rht_sa_temp_c)
1671
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(zone_htg_sa_temp_c)
1678
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
1679
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
1672
1680
  end
1673
1681
 
1674
1682
  return air_loop
@@ -1696,6 +1704,14 @@ class Standard
1696
1704
  oa_damper_sch: nil)
1697
1705
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Adding Packaged VAV for #{thermal_zones.size} zones.")
1698
1706
 
1707
+ # create air handler
1708
+ air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
1709
+ if system_name.nil?
1710
+ air_loop.setName("#{thermal_zones.size} Zone PVAV")
1711
+ else
1712
+ air_loop.setName(system_name)
1713
+ end
1714
+
1699
1715
  # hvac operation schedule
1700
1716
  if hvac_op_sch.nil?
1701
1717
  hvac_op_sch = model.alwaysOnDiscreteSchedule
@@ -1710,62 +1726,32 @@ class Standard
1710
1726
  oa_damper_sch = model_add_schedule(model, oa_damper_sch)
1711
1727
  end
1712
1728
 
1713
- # control temps used across all air handlers
1729
+ # default design temperatures used across all air loops
1730
+ dsgn_temps = standard_design_sizing_temperatures
1714
1731
  unless hot_water_loop.nil?
1715
1732
  hw_temp_c = hot_water_loop.sizingPlant.designLoopExitTemperature
1716
1733
  hw_delta_t_k = hot_water_loop.sizingPlant.loopDesignTemperatureDifference
1717
1734
  end
1718
- sys_dsn_prhtg_temp_f = 44.6 # Design central deck to preheat to 44.6F
1719
- sys_dsn_clg_sa_temp_f = 55 # Design central deck to cool to 55F
1720
- sys_dsn_htg_sa_temp_f = 55 # Central heat to 55F
1721
- zn_dsn_clg_sa_temp_f = 55 # Design VAV box for 55F from central deck
1722
- zn_dsn_htg_sa_temp_f = 122 # Design VAV box to reheat to 122F
1723
- rht_rated_air_in_temp_f = 55 # Reheat coils designed to receive 55F
1724
- rht_rated_air_out_temp_f = 122 # Reheat coils designed to supply 122F
1725
- clg_sa_temp_f = 55 # Central deck clg temp operates at 55F
1726
- sys_dsn_prhtg_temp_c = OpenStudio.convert(sys_dsn_prhtg_temp_f, 'F', 'C').get
1727
- sys_dsn_clg_sa_temp_c = OpenStudio.convert(sys_dsn_clg_sa_temp_f, 'F', 'C').get
1728
- sys_dsn_htg_sa_temp_c = OpenStudio.convert(sys_dsn_htg_sa_temp_f, 'F', 'C').get
1729
- zn_dsn_clg_sa_temp_c = OpenStudio.convert(zn_dsn_clg_sa_temp_f, 'F', 'C').get
1730
- zn_dsn_htg_sa_temp_c = OpenStudio.convert(zn_dsn_htg_sa_temp_f, 'F', 'C').get
1731
- rht_rated_air_in_temp_c = OpenStudio.convert(rht_rated_air_in_temp_f, 'F', 'C').get
1732
- rht_rated_air_out_temp_c = OpenStudio.convert(rht_rated_air_out_temp_f, 'F', 'C').get
1733
- clg_sa_temp_c = OpenStudio.convert(clg_sa_temp_f, 'F', 'C').get
1734
- sa_temp_sch = OpenStudio::Model::ScheduleRuleset.new(model)
1735
- sa_temp_sch.setName("Supply Air Temp - #{clg_sa_temp_f.round(0)}F")
1736
- sa_temp_sch.defaultDaySchedule.setName("Supply Air Temp - #{clg_sa_temp_f.round(0)}F Default")
1737
- sa_temp_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), clg_sa_temp_c)
1738
1735
 
1739
- # create air handler
1740
- air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
1741
- if system_name.nil?
1742
- air_loop.setName("#{thermal_zones.size} Zone PVAV")
1743
- else
1744
- air_loop.setName(system_name)
1745
- end
1736
+ # adjusted zone design heating temperature for pvav
1737
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_f'] = 122.0
1738
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_htg_dsgn_sup_air_temp_f'], 'F', 'C').get
1746
1739
 
1747
- # set air handler controls
1748
- stpt_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, sa_temp_sch)
1749
- stpt_manager.addToNode(air_loop.supplyOutletNode)
1750
- sizing_system = air_loop.sizingSystem
1751
- # sizing_system.setPreheatDesignTemperature(sys_dsn_prhtg_temp_c)
1752
- sizing_system.setCentralCoolingDesignSupplyAirTemperature(sys_dsn_clg_sa_temp_c)
1753
- sizing_system.setCentralHeatingDesignSupplyAirTemperature(sys_dsn_htg_sa_temp_c)
1754
- sizing_system.setSizingOption('Coincident')
1755
- sizing_system.setAllOutdoorAirinCooling(false)
1756
- sizing_system.setAllOutdoorAirinHeating(false)
1757
- air_loop.setNightCycleControlType('CycleOnAny')
1758
- avail_mgr = air_loop.availabilityManager
1759
- if avail_mgr.is_initialized
1760
- avail_mgr = avail_mgr.get
1761
- if avail_mgr.to_AvailabilityManagerNightCycle.is_initialized
1762
- avail_mgr = avail_mgr.to_AvailabilityManagerNightCycle.get
1763
- avail_mgr.setCyclingRunTime(1800)
1764
- end
1765
- end
1740
+ # default design settings used across all air loops
1741
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps)
1742
+
1743
+ # air handler controls
1744
+ sa_temp_sch = model_add_constant_schedule_ruleset(model,
1745
+ dsgn_temps['clg_dsgn_sup_air_temp_c'],
1746
+ name = "Supply Air Temp - #{dsgn_temps['clg_dsgn_sup_air_temp_f']}F")
1747
+ sa_stpt_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, sa_temp_sch)
1748
+ sa_stpt_manager.setName("#{air_loop.name} Supply Air Setpoint Manager")
1749
+ sa_stpt_manager.addToNode(air_loop.supplyOutletNode)
1766
1750
 
1767
1751
  # create fan
1768
- fan = create_fan_by_name(model, 'VAV_default', fan_name: "#{air_loop.name} Fan")
1752
+ fan = create_fan_by_name(model,
1753
+ 'VAV_default',
1754
+ fan_name: "#{air_loop.name} Fan")
1769
1755
  fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
1770
1756
  fan.addToNode(air_loop.supplyInletNode)
1771
1757
 
@@ -1781,8 +1767,8 @@ class Standard
1781
1767
  name: "#{air_loop.name} Main Htg Coil",
1782
1768
  rated_inlet_water_temperature: hw_temp_c,
1783
1769
  rated_outlet_water_temperature: (hw_temp_c - hw_delta_t_k),
1784
- rated_inlet_air_temperature: sys_dsn_prhtg_temp_c,
1785
- rated_outlet_air_temperature: sys_dsn_htg_sa_temp_c)
1770
+ rated_inlet_air_temperature: dsgn_temps['prehtg_dsgn_sup_air_temp_c'],
1771
+ rated_outlet_air_temperature: dsgn_temps['htg_dsgn_sup_air_temp_c'])
1786
1772
  end
1787
1773
 
1788
1774
  # create cooling coil
@@ -1814,6 +1800,14 @@ class Standard
1814
1800
  # set air loop availability controls and night cycle manager, after oa system added
1815
1801
  air_loop.setAvailabilitySchedule(hvac_op_sch)
1816
1802
  air_loop.setNightCycleControlType('CycleOnAny')
1803
+ avail_mgr = air_loop.availabilityManager
1804
+ if avail_mgr.is_initialized
1805
+ avail_mgr = avail_mgr.get
1806
+ if avail_mgr.to_AvailabilityManagerNightCycle.is_initialized
1807
+ avail_mgr = avail_mgr.to_AvailabilityManagerNightCycle.get
1808
+ avail_mgr.setCyclingRunTime(1800)
1809
+ end
1810
+ end
1817
1811
 
1818
1812
  # attach the VAV system to each zone
1819
1813
  thermal_zones.each do |zone|
@@ -1821,22 +1815,23 @@ class Standard
1821
1815
 
1822
1816
  # create reheat coil
1823
1817
  if electric_reheat || hot_water_loop.nil?
1824
- rht_coil = create_coil_heating_electric(model, name: "#{zone.name} Electric Reheat Coil")
1818
+ rht_coil = create_coil_heating_electric(model,
1819
+ name: "#{zone.name} Electric Reheat Coil")
1825
1820
  else
1826
1821
  rht_coil = create_coil_heating_water(model,
1827
1822
  hot_water_loop,
1828
1823
  name: "#{zone.name} Reheat Coil",
1829
1824
  rated_inlet_water_temperature: hw_temp_c,
1830
1825
  rated_outlet_water_temperature: (hw_temp_c - hw_delta_t_k),
1831
- rated_inlet_air_temperature: rht_rated_air_in_temp_c,
1832
- rated_outlet_air_temperature: rht_rated_air_out_temp_c)
1826
+ rated_inlet_air_temperature: dsgn_temps['htg_dsgn_sup_air_temp_c'],
1827
+ rated_outlet_air_temperature: dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
1833
1828
  end
1834
1829
 
1835
1830
  # create VAV terminal
1836
1831
  terminal = OpenStudio::Model::AirTerminalSingleDuctVAVReheat.new(model, model.alwaysOnDiscreteSchedule, rht_coil)
1837
1832
  terminal.setName("#{zone.name} VAV Terminal")
1838
1833
  terminal.setZoneMinimumAirFlowMethod('Constant')
1839
- terminal.setMaximumReheatAirTemperature(rht_rated_air_out_temp_c)
1834
+ terminal.setMaximumReheatAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
1840
1835
  air_terminal_single_duct_vav_reheat_apply_initial_prototype_damper_position(terminal, thermal_zone_outdoor_airflow_rate_per_area(zone))
1841
1836
  air_loop.addBranchForZone(zone, terminal.to_StraightComponent)
1842
1837
 
@@ -1846,8 +1841,8 @@ class Standard
1846
1841
 
1847
1842
  # zone sizing
1848
1843
  sizing_zone = zone.sizingZone
1849
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(zn_dsn_clg_sa_temp_c)
1850
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(zn_dsn_htg_sa_temp_c)
1844
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
1845
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
1851
1846
  end
1852
1847
 
1853
1848
  # set the damper action based on the template
@@ -1878,6 +1873,14 @@ class Standard
1878
1873
  fan_pressure_rise: 4.0)
1879
1874
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Adding PVAV with PFP Boxes and Reheat system for #{thermal_zones.size} zones.")
1880
1875
 
1876
+ # create air handler
1877
+ air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
1878
+ if system_name.nil?
1879
+ air_loop.setName("#{thermal_zones.size} Zone VAV with PFP Boxes and Reheat")
1880
+ else
1881
+ air_loop.setName(system_name)
1882
+ end
1883
+
1881
1884
  # hvac operation schedule
1882
1885
  if hvac_op_sch.nil?
1883
1886
  hvac_op_sch = model.alwaysOnDiscreteSchedule
@@ -1892,47 +1895,18 @@ class Standard
1892
1895
  oa_damper_sch = model_add_schedule(model, oa_damper_sch)
1893
1896
  end
1894
1897
 
1895
- # control temps used across all air handlers
1896
- clg_sa_temp_f = 55.04 # Central deck clg temp 55F
1897
- prehtg_sa_temp_f = 44.6 # Preheat to 44.6F
1898
- preclg_sa_temp_f = 55.04 # Precool to 55F
1899
- htg_sa_temp_f = 55.04 # Central deck htg temp 55F
1900
- rht_sa_temp_f = 104 # VAV box reheat to 104F
1901
- zone_htg_sa_temp_f = 104 # Zone heating design supply air temperature to 104 F
1902
- clg_sa_temp_c = OpenStudio.convert(clg_sa_temp_f, 'F', 'C').get
1903
- prehtg_sa_temp_c = OpenStudio.convert(prehtg_sa_temp_f, 'F', 'C').get
1904
- preclg_sa_temp_c = OpenStudio.convert(preclg_sa_temp_f, 'F', 'C').get
1905
- htg_sa_temp_c = OpenStudio.convert(htg_sa_temp_f, 'F', 'C').get
1906
- rht_sa_temp_c = OpenStudio.convert(rht_sa_temp_f, 'F', 'C').get
1907
- zone_htg_sa_temp_c = OpenStudio.convert(zone_htg_sa_temp_f, 'F', 'C').get
1908
- sa_temp_sch = OpenStudio::Model::ScheduleRuleset.new(model)
1909
- sa_temp_sch.setName("Supply Air Temp #{clg_sa_temp_f}F")
1910
- sa_temp_sch.defaultDaySchedule.setName("Supply Air Temp #{clg_sa_temp_f}F Default")
1911
- sa_temp_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), clg_sa_temp_c)
1912
-
1913
- # create air handler
1914
- air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
1915
- if system_name.nil?
1916
- air_loop.setName("#{thermal_zones.size} Zone VAV with PFP Boxes and Reheat")
1917
- else
1918
- air_loop.setName(system_name)
1919
- end
1898
+ # default design temperatures and settings used across all air loops
1899
+ dsgn_temps = standard_design_sizing_temperatures
1900
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps)
1920
1901
 
1902
+ # air handler controls
1903
+ sa_temp_sch = model_add_constant_schedule_ruleset(model,
1904
+ dsgn_temps['clg_dsgn_sup_air_temp_c'],
1905
+ name = "Supply Air Temp - #{dsgn_temps['clg_dsgn_sup_air_temp_f']}F")
1921
1906
  sa_stpt_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, sa_temp_sch)
1922
- sa_stpt_manager.setName("#{thermal_zones.size} Zone VAV Supply Air Setpoint Manager")
1907
+ sa_stpt_manager.setName("#{air_loop.name} Supply Air Setpoint Manager")
1923
1908
  sa_stpt_manager.addToNode(air_loop.supplyOutletNode)
1924
1909
 
1925
- # set air handler controls
1926
- sizing_system = air_loop.sizingSystem
1927
- sizing_system.setPreheatDesignTemperature(prehtg_sa_temp_c)
1928
- sizing_system.setPrecoolDesignTemperature(preclg_sa_temp_c)
1929
- sizing_system.setCentralCoolingDesignSupplyAirTemperature(clg_sa_temp_c)
1930
- sizing_system.setCentralHeatingDesignSupplyAirTemperature(htg_sa_temp_c)
1931
- sizing_system.setSizingOption('Coincident')
1932
- sizing_system.setAllOutdoorAirinCooling(false)
1933
- sizing_system.setAllOutdoorAirinHeating(false)
1934
- sizing_system.setSystemOutdoorAirMethod('ZoneSum')
1935
-
1936
1910
  # create fan
1937
1911
  # @type [OpenStudio::Model::FanVariableVolume] fan
1938
1912
  fan = create_fan_by_name(model,
@@ -1986,11 +1960,14 @@ class Standard
1986
1960
  OpenStudio.logFree(OpenStudio::Debug, 'openstudio.Model.Model', "Adding PVAV PFP Box to zone #{zone.name}")
1987
1961
 
1988
1962
  # create electric reheat coil
1989
- rht_coil = create_coil_heating_electric(model, name: "#{zone.name} Electric Reheat Coil")
1963
+ rht_coil = create_coil_heating_electric(model,
1964
+ name: "#{zone.name} Electric Reheat Coil")
1990
1965
 
1991
1966
  # create terminal fan
1992
1967
  # @type [OpenStudio::Model::FanConstantVolume] pfp_fan
1993
- pfp_fan = create_fan_by_name(model, 'PFP_Fan', fan_name: "#{zone.name} PFP Term Fan")
1968
+ pfp_fan = create_fan_by_name(model,
1969
+ 'PFP_Fan',
1970
+ fan_name: "#{zone.name} PFP Term Fan")
1994
1971
  pfp_fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
1995
1972
 
1996
1973
  # parallel fan powered terminal
@@ -2005,8 +1982,8 @@ class Standard
2005
1982
  sizing_zone = zone.sizingZone
2006
1983
  sizing_zone.setCoolingDesignAirFlowMethod('DesignDay')
2007
1984
  sizing_zone.setHeatingDesignAirFlowMethod('DesignDay')
2008
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(clg_sa_temp_c)
2009
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(zone_htg_sa_temp_c)
1985
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
1986
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2010
1987
  end
2011
1988
 
2012
1989
  return air_loop
@@ -2036,6 +2013,14 @@ class Standard
2036
2013
  fan_pressure_rise: 4.0)
2037
2014
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Adding CAV for #{thermal_zones.size} zones.")
2038
2015
 
2016
+ # create air handler
2017
+ air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
2018
+ if system_name.nil?
2019
+ air_loop.setName("#{thermal_zones.size} Zone CAV")
2020
+ else
2021
+ air_loop.setName(system_name)
2022
+ end
2023
+
2039
2024
  # hvac operation schedule
2040
2025
  if hvac_op_sch.nil?
2041
2026
  hvac_op_sch = model.alwaysOnDiscreteSchedule
@@ -2050,54 +2035,30 @@ class Standard
2050
2035
  oa_damper_sch = model_add_schedule(model, oa_damper_sch)
2051
2036
  end
2052
2037
 
2053
- # air handler hot water temperatures
2038
+ # default design temperatures used across all air loops
2039
+ dsgn_temps = standard_design_sizing_temperatures
2054
2040
  unless hot_water_loop.nil?
2055
2041
  hw_temp_c = hot_water_loop.sizingPlant.designLoopExitTemperature
2056
2042
  hw_delta_t_k = hot_water_loop.sizingPlant.loopDesignTemperatureDifference
2057
2043
  end
2058
- clg_sa_temp_f = 55.04
2059
- prehtg_sa_temp_f = 44.6
2060
- preclg_sa_temp_f = 55.04
2061
- htg_sa_temp_f = 62.06
2062
- rht_sa_temp_f = 122.0
2063
- zone_htg_sa_temp_f = 122.0
2064
- clg_sa_temp_c = OpenStudio.convert(clg_sa_temp_f, 'F', 'C').get
2065
- prehtg_sa_temp_c = OpenStudio.convert(prehtg_sa_temp_f, 'F', 'C').get
2066
- preclg_sa_temp_c = OpenStudio.convert(preclg_sa_temp_f, 'F', 'C').get
2067
- htg_sa_temp_c = OpenStudio.convert(htg_sa_temp_f, 'F', 'C').get
2068
- rht_sa_temp_c = OpenStudio.convert(rht_sa_temp_f, 'F', 'C').get
2069
- zone_htg_sa_temp_c = OpenStudio.convert(zone_htg_sa_temp_f, 'F', 'C').get
2070
2044
 
2071
- # create air handler
2072
- air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
2073
- if system_name.nil?
2074
- air_loop.setName("#{thermal_zones.size} Zone CAV")
2075
- else
2076
- air_loop.setName(system_name)
2077
- end
2045
+ # adjusted design heating temperature for cav
2046
+ dsgn_temps['htg_dsgn_sup_air_temp_f'] = 62.0
2047
+ dsgn_temps['htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['htg_dsgn_sup_air_temp_f'], 'F', 'C').get
2048
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_f'] = 122.0
2049
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_htg_dsgn_sup_air_temp_f'], 'F', 'C').get
2078
2050
 
2079
- # set air handler supply air setpoint
2080
- sa_temp_sch = OpenStudio::Model::ScheduleRuleset.new(model)
2081
- sa_temp_sch.setName("Supply Air Temp - #{clg_sa_temp_f}F")
2082
- sa_temp_sch.defaultDaySchedule.setName("Supply Air Temp - #{clg_sa_temp_f}F Default")
2083
- sa_temp_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), clg_sa_temp_c)
2051
+ # default design settings used across all air loops
2052
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps, min_sys_airflow_ratio: 1.0)
2084
2053
 
2054
+ # air handler controls
2055
+ sa_temp_sch = model_add_constant_schedule_ruleset(model,
2056
+ dsgn_temps['clg_dsgn_sup_air_temp_c'],
2057
+ name = "Supply Air Temp - #{dsgn_temps['clg_dsgn_sup_air_temp_f']}F")
2085
2058
  sa_stpt_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, sa_temp_sch)
2086
- sa_stpt_manager.setName("#{air_loop.name} supply air setpoint manager")
2059
+ sa_stpt_manager.setName("#{air_loop.name} Supply Air Setpoint Manager")
2087
2060
  sa_stpt_manager.addToNode(air_loop.supplyOutletNode)
2088
2061
 
2089
- # set air handler sizing
2090
- sizing_system = air_loop.sizingSystem
2091
- sizing_system.setMinimumSystemAirFlowRatio(1.0)
2092
- sizing_system.setPreheatDesignTemperature(prehtg_sa_temp_c)
2093
- sizing_system.setPrecoolDesignTemperature(preclg_sa_temp_c)
2094
- sizing_system.setCentralCoolingDesignSupplyAirTemperature(clg_sa_temp_c)
2095
- sizing_system.setCentralHeatingDesignSupplyAirTemperature(htg_sa_temp_c)
2096
- sizing_system.setSizingOption('Coincident')
2097
- sizing_system.setAllOutdoorAirinCooling(false)
2098
- sizing_system.setAllOutdoorAirinHeating(false)
2099
- sizing_system.setSystemOutdoorAirMethod('ZoneSum')
2100
-
2101
2062
  # create fan
2102
2063
  fan = create_fan_by_name(model,
2103
2064
  'Packaged_RTU_SZ_AC_CAV_Fan',
@@ -2116,8 +2077,8 @@ class Standard
2116
2077
  name: "#{air_loop.name} Main Htg Coil",
2117
2078
  rated_inlet_water_temperature: hw_temp_c,
2118
2079
  rated_outlet_water_temperature: (hw_temp_c - hw_delta_t_k),
2119
- rated_inlet_air_temperature: prehtg_sa_temp_c,
2120
- rated_outlet_air_temperature: htg_sa_temp_c)
2080
+ rated_inlet_air_temperature: dsgn_temps['prehtg_dsgn_sup_air_temp_c'],
2081
+ rated_outlet_air_temperature: dsgn_temps['htg_dsgn_sup_air_temp_c'])
2121
2082
 
2122
2083
  # create cooling coil
2123
2084
  if chilled_water_loop.nil?
@@ -2160,8 +2121,8 @@ class Standard
2160
2121
  name: "#{zone.name} Reheat Coil",
2161
2122
  rated_inlet_water_temperature: hw_temp_c,
2162
2123
  rated_outlet_water_temperature: (hw_temp_c - hw_delta_t_k),
2163
- rated_inlet_air_temperature: htg_sa_temp_c,
2164
- rated_outlet_air_temperature: rht_sa_temp_c)
2124
+ rated_inlet_air_temperature: dsgn_temps['htg_dsgn_sup_air_temp_c'],
2125
+ rated_outlet_air_temperature: dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2165
2126
  # VAV terminal
2166
2127
  terminal = OpenStudio::Model::AirTerminalSingleDuctVAVReheat.new(model, model.alwaysOnDiscreteSchedule, rht_coil)
2167
2128
  terminal.setName("#{zone.name} VAV Terminal")
@@ -2169,16 +2130,15 @@ class Standard
2169
2130
  air_terminal_single_duct_vav_reheat_apply_initial_prototype_damper_position(terminal, thermal_zone_outdoor_airflow_rate_per_area(zone))
2170
2131
  terminal.setMaximumFlowPerZoneFloorAreaDuringReheat(0.0)
2171
2132
  terminal.setMaximumFlowFractionDuringReheat(0.5)
2172
- terminal.setMaximumReheatAirTemperature(rht_sa_temp_c)
2133
+ terminal.setMaximumReheatAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2173
2134
  air_loop.addBranchForZone(zone, terminal.to_StraightComponent)
2174
2135
 
2175
2136
  # zone sizing
2176
2137
  sizing_zone = zone.sizingZone
2177
2138
  sizing_zone.setCoolingDesignAirFlowMethod('DesignDayWithLimit')
2178
2139
  sizing_zone.setHeatingDesignAirFlowMethod('DesignDay')
2179
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(clg_sa_temp_c)
2180
- # sizing_zone.setZoneHeatingDesignSupplyAirTemperature(rht_sa_temp_c)
2181
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(zone_htg_sa_temp_c)
2140
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
2141
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2182
2142
  end
2183
2143
 
2184
2144
  # Set the damper action based on the template.
@@ -2240,42 +2200,49 @@ class Standard
2240
2200
  air_loop.setName("#{zone.name} #{system_name}")
2241
2201
  end
2242
2202
 
2243
- # adjust system sizing for a constant volume system with no VAV terminals
2244
- air_loop_sizing = air_loop.sizingSystem
2245
- air_loop_sizing.setTypeofLoadtoSizeOn('Sensible')
2246
- air_loop_sizing.autosizeDesignOutdoorAirFlowRate
2247
- air_loop_sizing.setMinimumSystemAirFlowRatio(1.0)
2248
- air_loop_sizing.setPreheatDesignTemperature(7.0)
2249
- air_loop_sizing.setPreheatDesignHumidityRatio(0.008)
2250
- air_loop_sizing.setPrecoolDesignTemperature(12.8)
2251
- air_loop_sizing.setPrecoolDesignHumidityRatio(0.008)
2252
- air_loop_sizing.setCentralCoolingDesignSupplyAirTemperature(12.8)
2253
- air_loop_sizing.setCentralHeatingDesignSupplyAirTemperature(40.0)
2254
- air_loop_sizing.setSizingOption('Coincident')
2255
- air_loop_sizing.setAllOutdoorAirinCooling(false)
2256
- air_loop_sizing.setAllOutdoorAirinHeating(false)
2257
- air_loop_sizing.setCentralCoolingDesignSupplyAirHumidityRatio(0.0085)
2258
- air_loop_sizing.setCentralHeatingDesignSupplyAirHumidityRatio(0.0080)
2259
- air_loop_sizing.setCoolingDesignAirFlowMethod('DesignDay')
2260
- air_loop_sizing.setCoolingDesignAirFlowRate(0.0)
2261
- air_loop_sizing.setHeatingDesignAirFlowMethod('DesignDay')
2262
- air_loop_sizing.setHeatingDesignAirFlowRate(0.0)
2263
- air_loop_sizing.setSystemOutdoorAirMethod('ZoneSum')
2203
+ # default design temperatures and settings used across all air loops
2204
+ dsgn_temps = standard_design_sizing_temperatures
2205
+ unless hot_water_loop.nil?
2206
+ hw_temp_c = hot_water_loop.sizingPlant.designLoopExitTemperature
2207
+ hw_delta_t_k = hot_water_loop.sizingPlant.loopDesignTemperatureDifference
2208
+ end
2209
+
2210
+ # adjusted design heating temperature for psz_ac
2211
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_f'] = 122.0
2212
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_htg_dsgn_sup_air_temp_f'], 'F', 'C').get
2213
+ dsgn_temps['htg_dsgn_sup_air_temp_f'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_f']
2214
+ dsgn_temps['htg_dsgn_sup_air_temp_c'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_c']
2215
+
2216
+ # default design settings used across all air loops
2217
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps, min_sys_airflow_ratio: 1.0)
2218
+
2219
+ # air handler controls
2220
+ # add a setpoint manager single zone reheat to control the supply air temperature
2221
+ setpoint_mgr_single_zone_reheat = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model)
2222
+ setpoint_mgr_single_zone_reheat.setName("#{zone.name} Setpoint Manager SZ Reheat")
2223
+ setpoint_mgr_single_zone_reheat.setControlZone(zone)
2224
+ setpoint_mgr_single_zone_reheat.setMinimumSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
2225
+ setpoint_mgr_single_zone_reheat.setMaximumSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2226
+ setpoint_mgr_single_zone_reheat.addToNode(air_loop.supplyOutletNode)
2264
2227
 
2265
2228
  # zone sizing
2266
2229
  sizing_zone = zone.sizingZone
2267
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(12.8)
2268
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(40.0)
2230
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
2231
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2269
2232
 
2270
2233
  # create fan
2271
2234
  # ConstantVolume: Packaged Rooftop Single Zone Air conditioner
2272
2235
  # Cycling: Unitary System
2273
2236
  # CyclingHeatPump: Unitary Heat Pump system
2274
2237
  if fan_type == 'ConstantVolume'
2275
- fan = create_fan_by_name(model, 'Packaged_RTU_SZ_AC_CAV_Fan', fan_name: "#{air_loop.name} Fan")
2238
+ fan = create_fan_by_name(model,
2239
+ 'Packaged_RTU_SZ_AC_CAV_Fan',
2240
+ fan_name: "#{air_loop.name} Fan")
2276
2241
  fan.setAvailabilitySchedule(hvac_op_sch)
2277
2242
  elsif fan_type == 'Cycling'
2278
- fan = create_fan_by_name(model, 'Packaged_RTU_SZ_AC_Cycling_Fan', fan_name: "#{air_loop.name} Fan")
2243
+ fan = create_fan_by_name(model,
2244
+ 'Packaged_RTU_SZ_AC_Cycling_Fan',
2245
+ fan_name: "#{air_loop.name} Fan")
2279
2246
  fan.setAvailabilitySchedule(hvac_op_sch)
2280
2247
  else
2281
2248
  OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model', "Fan type '#{fan_type}' not recognized, cannot add PSZ-AC.")
@@ -2285,31 +2252,34 @@ class Standard
2285
2252
  # create heating coil
2286
2253
  case heating_type
2287
2254
  when 'NaturalGas', 'Gas'
2288
- htg_coil = create_coil_heating_gas(model, name: "#{air_loop.name} Gas Htg Coil")
2255
+ htg_coil = create_coil_heating_gas(model,
2256
+ name: "#{air_loop.name} Gas Htg Coil")
2289
2257
  when 'Water'
2290
2258
  if hot_water_loop.nil?
2291
2259
  OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', 'No hot water plant loop supplied')
2292
2260
  return false
2293
2261
  end
2294
- hw_temp_c = hot_water_loop.sizingPlant.designLoopExitTemperature
2295
- hw_delta_t_k = hot_water_loop.sizingPlant.loopDesignTemperatureDifference
2296
- prehtg_sa_temp_c = OpenStudio.convert(44.6, 'F', 'C').get
2297
- htg_sa_temp_c = OpenStudio.convert(55.0, 'F', 'C').get
2298
2262
  htg_coil = create_coil_heating_water(model,
2299
2263
  hot_water_loop,
2300
2264
  name: "#{air_loop.name} Water Htg Coil",
2301
2265
  rated_inlet_water_temperature: hw_temp_c,
2302
2266
  rated_outlet_water_temperature: (hw_temp_c - hw_delta_t_k),
2303
- rated_inlet_air_temperature: prehtg_sa_temp_c,
2304
- rated_outlet_air_temperature: htg_sa_temp_c)
2267
+ rated_inlet_air_temperature: dsgn_temps['prehtg_dsgn_sup_air_temp_c'],
2268
+ rated_outlet_air_temperature: dsgn_temps['htg_dsgn_sup_air_temp_c'])
2305
2269
  when 'Single Speed Heat Pump'
2306
- htg_coil = create_coil_heating_dx_single_speed(model, name: "#{zone.name} HP Htg Coil", type: 'PSZ-AC', cop: 3.3)
2270
+ htg_coil = create_coil_heating_dx_single_speed(model,
2271
+ name: "#{zone.name} HP Htg Coil",
2272
+ type: 'PSZ-AC',
2273
+ cop: 3.3)
2307
2274
  when 'Water To Air Heat Pump'
2308
- htg_coil = create_coil_heating_water_to_air_heat_pump_equation_fit(model, hot_water_loop, name: "#{air_loop.name} Water-to-Air HP Htg Coil")
2275
+ htg_coil = create_coil_heating_water_to_air_heat_pump_equation_fit(model,
2276
+ hot_water_loop,
2277
+ name: "#{air_loop.name} Water-to-Air HP Htg Coil")
2309
2278
  when 'Electricity', 'Electric'
2310
- htg_coil = create_coil_heating_electric(model, name: "#{air_loop.name} Electric Htg Coil")
2279
+ htg_coil = create_coil_heating_electric(model,
2280
+ name: "#{air_loop.name} Electric Htg Coil")
2311
2281
  else
2312
- # Zero-capacity, always-off electric heating coil
2282
+ # zero-capacity, always-off electric heating coil
2313
2283
  htg_coil = create_coil_heating_electric(model,
2314
2284
  name: "#{air_loop.name} No Heat",
2315
2285
  schedule: model.alwaysOffDiscreteSchedule,
@@ -2319,9 +2289,11 @@ class Standard
2319
2289
  # create supplemental heating coil
2320
2290
  case supplemental_heating_type
2321
2291
  when 'Electricity', 'Electric'
2322
- supplemental_htg_coil = create_coil_heating_electric(model, name: "#{air_loop.name} Electric Backup Htg Coil")
2292
+ supplemental_htg_coil = create_coil_heating_electric(model,
2293
+ name: "#{air_loop.name} Electric Backup Htg Coil")
2323
2294
  when 'NaturalGas', 'Gas'
2324
- supplemental_htg_coil = create_coil_heating_gas(model, name: "#{air_loop.name} Gas Backup Htg Coil")
2295
+ supplemental_htg_coil = create_coil_heating_gas(model,
2296
+ name: "#{air_loop.name} Gas Backup Htg Coil")
2325
2297
  else
2326
2298
  # Zero-capacity, always-off electric heating coil
2327
2299
  supplemental_htg_coil = create_coil_heating_electric(model,
@@ -2337,9 +2309,12 @@ class Standard
2337
2309
  OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', 'No chilled water plant loop supplied')
2338
2310
  return false
2339
2311
  end
2340
- clg_coil = create_coil_cooling_water(model, chilled_water_loop, name: "#{air_loop.name} Water Clg Coil")
2312
+ clg_coil = create_coil_cooling_water(model,
2313
+ chilled_water_loop,
2314
+ name: "#{air_loop.name} Water Clg Coil")
2341
2315
  when 'Two Speed DX AC'
2342
- clg_coil = create_coil_cooling_dx_two_speed(model, name: "#{air_loop.name} 2spd DX AC Clg Coil")
2316
+ clg_coil = create_coil_cooling_dx_two_speed(model,
2317
+ name: "#{air_loop.name} 2spd DX AC Clg Coil")
2343
2318
  when 'Single Speed DX AC'
2344
2319
  clg_coil = create_coil_cooling_dx_single_speed(model,
2345
2320
  name: "#{air_loop.name} 1spd DX AC Clg Coil",
@@ -2357,16 +2332,13 @@ class Standard
2357
2332
  OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', 'No chilled water plant loop supplied')
2358
2333
  return false
2359
2334
  end
2360
- clg_coil = create_coil_cooling_water_to_air_heat_pump_equation_fit(model, chilled_water_loop, name: "#{air_loop.name} Water-to-Air HP Clg Coil")
2335
+ clg_coil = create_coil_cooling_water_to_air_heat_pump_equation_fit(model,
2336
+ chilled_water_loop,
2337
+ name: "#{air_loop.name} Water-to-Air HP Clg Coil")
2361
2338
  else
2362
2339
  clg_coil = nil
2363
2340
  end
2364
2341
 
2365
- # add a setpoint manager single zone reheat to control the supply air temperature
2366
- setpoint_mgr_single_zone_reheat = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model)
2367
- setpoint_mgr_single_zone_reheat.setControlZone(zone)
2368
- setpoint_mgr_single_zone_reheat.addToNode(air_loop.supplyOutletNode)
2369
-
2370
2342
  # wrap coils in a unitary system if cycling, or not if constant volume
2371
2343
  if fan_type == 'Cycling'
2372
2344
  if heating_type == 'Water To Air Heat Pump'
@@ -2378,14 +2350,13 @@ class Standard
2378
2350
  unitary_system.setSupplementalHeatingCoil(supplemental_htg_coil) unless supplemental_htg_coil.nil?
2379
2351
  unitary_system.setName("#{zone.name} Unitary HP")
2380
2352
  unitary_system.setControllingZoneorThermostatLocation(zone)
2381
- unitary_system.setMaximumSupplyAirTemperature(50.0)
2353
+ unitary_system.setMaximumSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2382
2354
  unitary_system.setFanPlacement('BlowThrough')
2383
2355
  unitary_system.setSupplyAirFlowRateMethodDuringCoolingOperation('SupplyAirFlowRate')
2384
2356
  unitary_system.setSupplyAirFlowRateMethodDuringHeatingOperation('SupplyAirFlowRate')
2385
2357
  unitary_system.setSupplyAirFlowRateMethodWhenNoCoolingorHeatingisRequired('SupplyAirFlowRate')
2386
2358
  unitary_system.setSupplyAirFanOperatingModeSchedule(model.alwaysOnDiscreteSchedule)
2387
2359
  unitary_system.addToNode(air_loop.supplyInletNode)
2388
- setpoint_mgr_single_zone_reheat.setMaximumSupplyAirTemperature(50.0)
2389
2360
  else
2390
2361
  # CyclingHeatPump: Unitary Heat Pump system
2391
2362
  unitary_system = OpenStudio::Model::AirLoopHVACUnitaryHeatPumpAirToAir.new(model,
@@ -2400,8 +2371,6 @@ class Standard
2400
2371
  unitary_system.setFanPlacement(fan_location)
2401
2372
  unitary_system.setSupplyAirFanOperatingModeSchedule(hvac_op_sch)
2402
2373
  unitary_system.addToNode(air_loop.supplyInletNode)
2403
- setpoint_mgr_single_zone_reheat.setMinimumSupplyAirTemperature(OpenStudio.convert(55.0, 'F', 'C').get)
2404
- setpoint_mgr_single_zone_reheat.setMaximumSupplyAirTemperature(OpenStudio.convert(104.0, 'F', 'C').get)
2405
2374
  end
2406
2375
  else
2407
2376
  # ConstantVolume: Packaged Rooftop Single Zone Air conditioner
@@ -2427,8 +2396,6 @@ class Standard
2427
2396
  OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', 'Invalid fan location')
2428
2397
  return false
2429
2398
  end
2430
- setpoint_mgr_single_zone_reheat.setMinimumSupplyAirTemperature(OpenStudio.convert(50.0, 'F', 'C').get)
2431
- setpoint_mgr_single_zone_reheat.setMaximumSupplyAirTemperature(OpenStudio.convert(122.0, 'F', 'C').get)
2432
2399
  end
2433
2400
 
2434
2401
  # add the OA system
@@ -2508,36 +2475,29 @@ class Standard
2508
2475
  air_loop.setName("#{zone.name} #{system_name}")
2509
2476
  end
2510
2477
 
2511
- # adjust system sizing
2512
- air_loop_sizing = air_loop.sizingSystem
2513
- air_loop_sizing.setTypeofLoadtoSizeOn('Sensible')
2514
- air_loop_sizing.autosizeDesignOutdoorAirFlowRate
2515
- air_loop_sizing.setMinimumSystemAirFlowRatio(0.0)
2516
- air_loop_sizing.setPreheatDesignTemperature(7.0)
2517
- air_loop_sizing.setPreheatDesignHumidityRatio(0.008)
2518
- air_loop_sizing.setPrecoolDesignTemperature(12.8)
2519
- air_loop_sizing.setPrecoolDesignHumidityRatio(0.008)
2520
- air_loop_sizing.setCentralCoolingDesignSupplyAirTemperature(12.8)
2521
- air_loop_sizing.setCentralHeatingDesignSupplyAirTemperature(40.0)
2522
- air_loop_sizing.setSizingOption('Coincident')
2523
- air_loop_sizing.setAllOutdoorAirinCooling(false)
2524
- air_loop_sizing.setAllOutdoorAirinHeating(false)
2525
- air_loop_sizing.setCentralCoolingDesignSupplyAirHumidityRatio(0.0085)
2526
- air_loop_sizing.setCentralHeatingDesignSupplyAirHumidityRatio(0.0080)
2527
- air_loop_sizing.setCoolingDesignAirFlowMethod('DesignDay')
2528
- air_loop_sizing.setCoolingDesignAirFlowRate(0.0)
2529
- air_loop_sizing.setHeatingDesignAirFlowMethod('DesignDay')
2530
- air_loop_sizing.setHeatingDesignAirFlowRate(0.0)
2531
- air_loop_sizing.setSystemOutdoorAirMethod('ZoneSum')
2478
+ # default design temperatures used across all air loops
2479
+ dsgn_temps = standard_design_sizing_temperatures
2532
2480
 
2533
- # zone sizing
2534
- sizing_zone = zone.sizingZone
2535
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(14.0)
2536
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(40.0)
2481
+ # adjusted zone design heating temperature for psz_vav
2482
+ dsgn_temps['htg_dsgn_sup_air_temp_f'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_f']
2483
+ dsgn_temps['htg_dsgn_sup_air_temp_c'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_c']
2484
+
2485
+ # default design settings used across all air loops
2486
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps)
2537
2487
 
2488
+ # air handler controls
2538
2489
  # add a setpoint manager single zone reheat to control the supply air temperature
2539
2490
  setpoint_mgr_single_zone_reheat = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model)
2491
+ setpoint_mgr_single_zone_reheat.setName("#{zone.name} Setpoint Manager SZ Reheat")
2540
2492
  setpoint_mgr_single_zone_reheat.setControlZone(zone)
2493
+ setpoint_mgr_single_zone_reheat.setMinimumSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
2494
+ setpoint_mgr_single_zone_reheat.setMaximumSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2495
+ setpoint_mgr_single_zone_reheat.addToNode(air_loop.supplyOutletNode)
2496
+
2497
+ # zone sizing
2498
+ sizing_zone = zone.sizingZone
2499
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
2500
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2541
2501
 
2542
2502
  # create fan
2543
2503
  # @type [OpenStudio::Model::FanVariableVolume] fan
@@ -2550,9 +2510,11 @@ class Standard
2550
2510
  # create heating coil
2551
2511
  case heating_type
2552
2512
  when 'NaturalGas', 'Gas'
2553
- htg_coil = create_coil_heating_gas(model, name: "#{air_loop.name} Gas Htg Coil")
2513
+ htg_coil = create_coil_heating_gas(model,
2514
+ name: "#{air_loop.name} Gas Htg Coil")
2554
2515
  when 'Electricity', 'Electric'
2555
- htg_coil = create_coil_heating_electric(model, name: "#{air_loop.name} Electric Htg Coil")
2516
+ htg_coil = create_coil_heating_electric(model,
2517
+ name: "#{air_loop.name} Electric Htg Coil")
2556
2518
  else
2557
2519
  # Zero-capacity, always-off electric heating coil
2558
2520
  htg_coil = create_coil_heating_electric(model,
@@ -2564,9 +2526,11 @@ class Standard
2564
2526
  # create supplemental heating coil
2565
2527
  case supplemental_heating_type
2566
2528
  when 'Electricity', 'Electric'
2567
- supplemental_htg_coil = create_coil_heating_electric(model, name: "#{air_loop.name} Electric Backup Htg Coil")
2529
+ supplemental_htg_coil = create_coil_heating_electric(model,
2530
+ name: "#{air_loop.name} Electric Backup Htg Coil")
2568
2531
  when 'NaturalGas', 'Gas'
2569
- supplemental_htg_coil = create_coil_heating_gas(model, name: "#{air_loop.name} Gas Backup Htg Coil")
2532
+ supplemental_htg_coil = create_coil_heating_gas(model,
2533
+ name: "#{air_loop.name} Gas Backup Htg Coil")
2570
2534
  else
2571
2535
  # zero-capacity, always-off electric heating coil
2572
2536
  supplemental_htg_coil = create_coil_heating_electric(model,
@@ -2578,7 +2542,7 @@ class Standard
2578
2542
  # create cooling coil
2579
2543
  clg_coil = OpenStudio::Model::CoilCoolingDXVariableSpeed.new(model)
2580
2544
  clg_coil.setName("#{air_loop.name} Var spd DX AC Clg Coil")
2581
- clg_coil.setBasinHeaterCapacity(10)
2545
+ clg_coil.setBasinHeaterCapacity(10.0)
2582
2546
  clg_coil.setBasinHeaterSetpointTemperature(2.0)
2583
2547
  # first speed level
2584
2548
  clg_spd_1 = OpenStudio::Model::CoilCoolingDXVariableSpeedSpeedData.new(model)
@@ -2597,7 +2561,7 @@ class Standard
2597
2561
  unitary_system.setName("#{zone.name} Unitary PSZ-VAV")
2598
2562
  unitary_system.setString(2, 'SingleZoneVAV') # TODO: add setControlType() method
2599
2563
  unitary_system.setControllingZoneorThermostatLocation(zone)
2600
- unitary_system.setMaximumSupplyAirTemperature(50)
2564
+ unitary_system.setMaximumSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2601
2565
  unitary_system.setFanPlacement('BlowThrough')
2602
2566
  unitary_system.setSupplyAirFlowRateMethodDuringCoolingOperation('SupplyAirFlowRate')
2603
2567
  unitary_system.setSupplyAirFlowRateMethodDuringHeatingOperation('SupplyAirFlowRate')
@@ -2694,46 +2658,36 @@ class Standard
2694
2658
  air_loop.setName("#{zone.name} #{system_name}")
2695
2659
  end
2696
2660
 
2697
- # adjust system sizing for a constant volume system with no VAV terminals
2698
- air_loop_sizing = air_loop.sizingSystem
2699
- air_loop_sizing.setTypeofLoadtoSizeOn('Sensible')
2700
- air_loop_sizing.autosizeDesignOutdoorAirFlowRate
2701
- air_loop_sizing.setMinimumSystemAirFlowRatio(1.0)
2702
- air_loop_sizing.setPreheatDesignTemperature(7.0)
2703
- air_loop_sizing.setPreheatDesignHumidityRatio(0.008)
2704
- air_loop_sizing.setPrecoolDesignTemperature(12.8)
2705
- air_loop_sizing.setPrecoolDesignHumidityRatio(0.008)
2706
- air_loop_sizing.setCentralCoolingDesignSupplyAirTemperature(12.8)
2707
- air_loop_sizing.setCentralHeatingDesignSupplyAirTemperature(40.0)
2708
- air_loop_sizing.setSizingOption('Coincident')
2709
- air_loop_sizing.setAllOutdoorAirinCooling(false)
2710
- air_loop_sizing.setAllOutdoorAirinHeating(false)
2711
- air_loop_sizing.setCentralCoolingDesignSupplyAirHumidityRatio(0.0085)
2712
- air_loop_sizing.setCentralHeatingDesignSupplyAirHumidityRatio(0.0080)
2713
- air_loop_sizing.setCoolingDesignAirFlowMethod('DesignDay')
2714
- air_loop_sizing.setCoolingDesignAirFlowRate(0.0)
2715
- air_loop_sizing.setHeatingDesignAirFlowMethod('DesignDay')
2716
- air_loop_sizing.setHeatingDesignAirFlowRate(0.0)
2717
- air_loop_sizing.setSystemOutdoorAirMethod('ZoneSum')
2661
+ # default design temperatures across all air loops
2662
+ dsgn_temps = standard_design_sizing_temperatures
2663
+ unless hot_water_loop.nil?
2664
+ hw_temp_c = hot_water_loop.sizingPlant.designLoopExitTemperature
2665
+ hw_delta_t_k = hot_water_loop.sizingPlant.loopDesignTemperatureDifference
2666
+ end
2667
+
2668
+ # adjusted zone design heating temperature for data center psz_ac
2669
+ dsgn_temps['htg_dsgn_sup_air_temp_f'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_f']
2670
+ dsgn_temps['htg_dsgn_sup_air_temp_c'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_c']
2671
+
2672
+ # default design settings used across all air loops
2673
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps, min_sys_airflow_ratio: 1.0)
2674
+
2675
+ # air handler controls
2676
+ # add a setpoint manager single zone reheat to control the supply air temperature
2677
+ setpoint_mgr_single_zone_reheat = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model)
2678
+ setpoint_mgr_single_zone_reheat.setName("#{zone.name} Setpoint Manager SZ Reheat")
2679
+ setpoint_mgr_single_zone_reheat.setControlZone(zone)
2680
+ setpoint_mgr_single_zone_reheat.setMinimumSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
2681
+ setpoint_mgr_single_zone_reheat.setMaximumSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2682
+ setpoint_mgr_single_zone_reheat.addToNode(air_loop.supplyOutletNode)
2718
2683
 
2719
2684
  # zone sizing
2720
2685
  sizing_zone = zone.sizingZone
2721
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(12.8)
2722
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(40.0)
2686
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
2687
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2723
2688
 
2724
2689
  # add the components to the air loop in order from closest to zone to furthest from zone
2725
2690
  if main_data_center
2726
-
2727
- # control temps used across all air handlers
2728
- unless hot_water_loop.nil?
2729
- hw_temp_c = hot_water_loop.sizingPlant.designLoopExitTemperature
2730
- hw_delta_t_k = hot_water_loop.sizingPlant.loopDesignTemperatureDifference
2731
- end
2732
- prehtg_sa_temp_f = 44.6 # Preheat to 44.6F
2733
- htg_sa_temp_f = 55.0 # Central deck htg temp 55F
2734
- prehtg_sa_temp_c = OpenStudio.convert(prehtg_sa_temp_f, 'F', 'C').get
2735
- htg_sa_temp_c = OpenStudio.convert(htg_sa_temp_f, 'F', 'C').get
2736
-
2737
2691
  # extra water heating coil
2738
2692
  create_coil_heating_water(model,
2739
2693
  hot_water_loop,
@@ -2741,8 +2695,9 @@ class Standard
2741
2695
  name: "#{air_loop.name} Water Htg Coil",
2742
2696
  rated_inlet_water_temperature: hw_temp_c,
2743
2697
  rated_outlet_water_temperature: (hw_temp_c - hw_delta_t_k),
2744
- rated_inlet_air_temperature: prehtg_sa_temp_c,
2745
- rated_outlet_air_temperature: htg_sa_temp_c)
2698
+ rated_inlet_air_temperature: dsgn_temps['prehtg_dsgn_sup_air_temp_c'],
2699
+ rated_outlet_air_temperature: dsgn_temps['htg_dsgn_sup_air_temp_c'])
2700
+
2746
2701
  # extra electric heating coil
2747
2702
  create_coil_heating_electric(model,
2748
2703
  air_loop_node: air_loop.supplyInletNode,
@@ -2764,13 +2719,20 @@ class Standard
2764
2719
 
2765
2720
  # create fan
2766
2721
  # @type [OpenStudio::Model::FanConstantVolume]
2767
- fan = create_fan_by_name(model, 'Packaged_RTU_SZ_AC_Cycling_Fan', fan_name: "#{air_loop.name} Fan")
2722
+ fan = create_fan_by_name(model,
2723
+ 'Packaged_RTU_SZ_AC_Cycling_Fan',
2724
+ fan_name: "#{air_loop.name} Fan")
2768
2725
  fan.setAvailabilitySchedule(hvac_op_sch)
2769
2726
 
2770
2727
  # create heating and cooling coils
2771
- htg_coil = create_coil_heating_water_to_air_heat_pump_equation_fit(model, heat_pump_loop, name: "#{air_loop.name} Water-to-Air HP Htg Coil")
2772
- clg_coil = create_coil_cooling_water_to_air_heat_pump_equation_fit(model, heat_pump_loop, name: "#{air_loop.name} Water-to-Air HP Clg Coil")
2773
- supplemental_htg_coil = create_coil_heating_electric(model, name: "#{air_loop.name} Electric Backup Htg Coil")
2728
+ htg_coil = create_coil_heating_water_to_air_heat_pump_equation_fit(model,
2729
+ heat_pump_loop,
2730
+ name: "#{air_loop.name} Water-to-Air HP Htg Coil")
2731
+ clg_coil = create_coil_cooling_water_to_air_heat_pump_equation_fit(model,
2732
+ heat_pump_loop,
2733
+ name: "#{air_loop.name} Water-to-Air HP Clg Coil")
2734
+ supplemental_htg_coil = create_coil_heating_electric(model,
2735
+ name: "#{air_loop.name} Electric Backup Htg Coil")
2774
2736
 
2775
2737
  # wrap fan and coils in a unitary system object
2776
2738
  unitary_system = OpenStudio::Model::AirLoopHVACUnitarySystem.new(model)
@@ -2796,13 +2758,6 @@ class Standard
2796
2758
  oa_system.setName("#{air_loop.name} OA System")
2797
2759
  oa_system.addToNode(air_loop.supplyInletNode)
2798
2760
 
2799
- # add a setpoint manager single zone reheat to control the supply air temperature
2800
- setpoint_mgr_single_zone_reheat = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model)
2801
- setpoint_mgr_single_zone_reheat.setControlZone(zone)
2802
- setpoint_mgr_single_zone_reheat.setMinimumSupplyAirTemperature(OpenStudio.convert(55.0, 'F', 'C').get)
2803
- setpoint_mgr_single_zone_reheat.setMaximumSupplyAirTemperature(OpenStudio.convert(104.0, 'F', 'C').get)
2804
- setpoint_mgr_single_zone_reheat.addToNode(air_loop.supplyOutletNode)
2805
-
2806
2761
  # set air loop availability controls and night cycle manager, after oa system added
2807
2762
  air_loop.setAvailabilitySchedule(hvac_op_sch)
2808
2763
  air_loop.setNightCycleControlType('CycleOnAny')
@@ -2839,6 +2794,11 @@ class Standard
2839
2794
  oa_damper_sch: nil,
2840
2795
  econ_max_oa_frac_sch: nil)
2841
2796
 
2797
+ # create a split AC for each group of thermal zones
2798
+ air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
2799
+ thermal_zones_name = (thermal_zones.map { |z| z.name }).join(' - ')
2800
+ air_loop.setName("#{thermal_zones_name} SAC")
2801
+
2842
2802
  # hvac operation schedule
2843
2803
  if hvac_op_sch.nil?
2844
2804
  hvac_op_sch = model.alwaysOnDiscreteSchedule
@@ -2853,33 +2813,26 @@ class Standard
2853
2813
  oa_damper_sch = model_add_schedule(model, oa_damper_sch)
2854
2814
  end
2855
2815
 
2856
- # create a split AC for each group of thermal zones
2857
- air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
2858
- air_loop.setAvailabilitySchedule(hvac_op_sch)
2859
- thermal_zones_name = (thermal_zones.map { |z| z.name }).join(' - ')
2860
- air_loop.setName("#{thermal_zones_name} SAC")
2816
+ # default design temperatures used across all air loops
2817
+ dsgn_temps = standard_design_sizing_temperatures
2818
+
2819
+ # adjusted zone design heating temperature for split_ac
2820
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_f'] = 122.0
2821
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_htg_dsgn_sup_air_temp_f'], 'F', 'C').get
2822
+ dsgn_temps['htg_dsgn_sup_air_temp_f'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_f']
2823
+ dsgn_temps['htg_dsgn_sup_air_temp_c'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_c']
2861
2824
 
2862
- # adjust system sizing for a constant volume system with no VAV terminals
2863
- air_loop_sizing = air_loop.sizingSystem
2864
- air_loop_sizing.setTypeofLoadtoSizeOn('Sensible')
2865
- air_loop_sizing.autosizeDesignOutdoorAirFlowRate
2866
- air_loop_sizing.setMinimumSystemAirFlowRatio(1.0)
2867
- air_loop_sizing.setPreheatDesignTemperature(7.0)
2868
- air_loop_sizing.setPreheatDesignHumidityRatio(0.008)
2869
- air_loop_sizing.setPrecoolDesignTemperature(11.0)
2870
- air_loop_sizing.setPrecoolDesignHumidityRatio(0.008)
2871
- air_loop_sizing.setCentralCoolingDesignSupplyAirTemperature(12.0)
2872
- air_loop_sizing.setCentralHeatingDesignSupplyAirTemperature(50.0)
2873
- air_loop_sizing.setSizingOption('NonCoincident')
2874
- air_loop_sizing.setAllOutdoorAirinCooling(false)
2875
- air_loop_sizing.setAllOutdoorAirinHeating(false)
2876
- air_loop_sizing.setCentralCoolingDesignSupplyAirHumidityRatio(0.008)
2877
- air_loop_sizing.setCentralHeatingDesignSupplyAirHumidityRatio(0.0080)
2878
- air_loop_sizing.setCoolingDesignAirFlowMethod('DesignDay')
2879
- air_loop_sizing.setCoolingDesignAirFlowRate(0.0)
2880
- air_loop_sizing.setHeatingDesignAirFlowMethod('DesignDay')
2881
- air_loop_sizing.setHeatingDesignAirFlowRate(0.0)
2882
- air_loop_sizing.setSystemOutdoorAirMethod('ZoneSum')
2825
+ # default design settings used across all air loops
2826
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps, min_sys_airflow_ratio: 1.0, sizing_option: 'NonCoincident')
2827
+
2828
+ # air handler controls
2829
+ # add a setpoint manager single zone reheat to control the supply air temperature
2830
+ setpoint_mgr_single_zone_reheat = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model)
2831
+ setpoint_mgr_single_zone_reheat.setName("#{air_loop.name} Setpoint Manager SZ Reheat")
2832
+ setpoint_mgr_single_zone_reheat.setControlZone(thermal_zones[0])
2833
+ setpoint_mgr_single_zone_reheat.setMinimumSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
2834
+ setpoint_mgr_single_zone_reheat.setMaximumSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2835
+ setpoint_mgr_single_zone_reheat.addToNode(air_loop.supplyOutletNode)
2883
2836
 
2884
2837
  # add the components to the air loop in order from closest to zone to furthest from zone
2885
2838
  # create fan
@@ -2957,14 +2910,8 @@ class Standard
2957
2910
  oa_system.setName("#{air_loop.name} OA System")
2958
2911
  oa_system.addToNode(air_loop.supplyInletNode)
2959
2912
 
2960
- # add a setpoint manager single zone reheat to control the supply air temperature
2961
- setpoint_mgr_single_zone_reheat = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model)
2962
- setpoint_mgr_single_zone_reheat.setName("#{air_loop.name} Setpoint Manager SZ Reheat")
2963
- control_zone = thermal_zones[0]
2964
- setpoint_mgr_single_zone_reheat.setControlZone(control_zone)
2965
- setpoint_mgr_single_zone_reheat.setMinimumSupplyAirTemperature(OpenStudio.convert(55.4, 'F', 'C').get)
2966
- setpoint_mgr_single_zone_reheat.setMaximumSupplyAirTemperature(OpenStudio.convert(113.0, 'F', 'C').get)
2967
- setpoint_mgr_single_zone_reheat.addToNode(air_loop.supplyOutletNode)
2913
+ # set air loop availability controls after oa system added
2914
+ air_loop.setAvailabilitySchedule(hvac_op_sch)
2968
2915
 
2969
2916
  # create a diffuser and attach the zone/diffuser pair to the air loop
2970
2917
  thermal_zones.each do |zone|
@@ -2976,8 +2923,8 @@ class Standard
2976
2923
 
2977
2924
  # zone sizing
2978
2925
  sizing_zone = zone.sizingZone
2979
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(14.0)
2980
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(50.0)
2926
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
2927
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
2981
2928
  sizing_zone.setZoneCoolingDesignSupplyAirHumidityRatio(0.008)
2982
2929
  sizing_zone.setZoneHeatingDesignSupplyAirHumidityRatio(0.008)
2983
2930
  end
@@ -3000,6 +2947,19 @@ class Standard
3000
2947
  hot_water_loop: nil,
3001
2948
  fan_type: 'ConstantVolume')
3002
2949
 
2950
+ # default design temperatures used across all air loops
2951
+ dsgn_temps = standard_design_sizing_temperatures
2952
+ unless hot_water_loop.nil?
2953
+ hw_temp_c = hot_water_loop.sizingPlant.designLoopExitTemperature
2954
+ hw_delta_t_k = hot_water_loop.sizingPlant.loopDesignTemperatureDifference
2955
+ end
2956
+
2957
+ # adjusted zone design temperatures for ptac
2958
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_f'] = 122.0
2959
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_htg_dsgn_sup_air_temp_f'], 'F', 'C').get
2960
+ dsgn_temps['zn_clg_dsgn_sup_air_temp_f'] = 57.0
2961
+ dsgn_temps['zn_clg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_clg_dsgn_sup_air_temp_f'], 'F', 'C').get
2962
+
3003
2963
  # make a PTAC for each zone
3004
2964
  ptacs = []
3005
2965
  thermal_zones.each do |zone|
@@ -3007,17 +2967,21 @@ class Standard
3007
2967
 
3008
2968
  # zone sizing
3009
2969
  sizing_zone = zone.sizingZone
3010
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(14)
3011
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(50.0)
2970
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
2971
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
3012
2972
  sizing_zone.setZoneCoolingDesignSupplyAirHumidityRatio(0.008)
3013
2973
  sizing_zone.setZoneHeatingDesignSupplyAirHumidityRatio(0.008)
3014
2974
 
3015
2975
  # add fan
3016
2976
  if fan_type == 'ConstantVolume'
3017
- fan = create_fan_by_name(model, 'PTAC_CAV_Fan', fan_name: "#{zone.name} PTAC Fan")
2977
+ fan = create_fan_by_name(model,
2978
+ 'PTAC_CAV_Fan',
2979
+ fan_name: "#{zone.name} PTAC Fan")
3018
2980
  fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3019
2981
  elsif fan_type == 'Cycling'
3020
- fan = create_fan_by_name(model, 'PTAC_Cycling_Fan', fan_name: "#{zone.name} PTAC Fan")
2982
+ fan = create_fan_by_name(model,
2983
+ 'PTAC_Cycling_Fan',
2984
+ fan_name: "#{zone.name} PTAC Fan")
3021
2985
  fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3022
2986
  else
3023
2987
  OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "ptac_fan_type of #{fan_type} is not recognized.")
@@ -3026,9 +2990,11 @@ class Standard
3026
2990
  # add heating coil
3027
2991
  case heating_type
3028
2992
  when 'NaturalGas', 'Gas'
3029
- htg_coil = create_coil_heating_gas(model, name: "#{zone.name} PTAC Gas Htg Coil")
2993
+ htg_coil = create_coil_heating_gas(model,
2994
+ name: "#{zone.name} PTAC Gas Htg Coil")
3030
2995
  when 'Electricity', 'Electric'
3031
- htg_coil = create_coil_heating_electric(model, name: "#{zone.name} PTAC Electric Htg Coil")
2996
+ htg_coil = create_coil_heating_electric(model,
2997
+ name: "#{zone.name} PTAC Electric Htg Coil")
3032
2998
  when nil
3033
2999
  htg_coil = create_coil_heating_electric(model,
3034
3000
  name: "#{zone.name} PTAC No Heat",
@@ -3039,8 +3005,6 @@ class Standard
3039
3005
  OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', 'No hot water plant loop supplied')
3040
3006
  return false
3041
3007
  end
3042
- hw_temp_c = hot_water_loop.sizingPlant.designLoopExitTemperature
3043
- hw_delta_t_k = hot_water_loop.sizingPlant.loopDesignTemperatureDifference
3044
3008
  htg_coil = create_coil_heating_water(model,
3045
3009
  hot_water_loop,
3046
3010
  name: "#{hot_water_loop.name} Water Htg Coil",
@@ -3052,9 +3016,12 @@ class Standard
3052
3016
 
3053
3017
  # add cooling coil
3054
3018
  if cooling_type == 'Two Speed DX AC'
3055
- clg_coil = create_coil_cooling_dx_two_speed(model, name: "#{zone.name} PTAC 2spd DX AC Clg Coil")
3019
+ clg_coil = create_coil_cooling_dx_two_speed(model,
3020
+ name: "#{zone.name} PTAC 2spd DX AC Clg Coil")
3056
3021
  elsif cooling_type == 'Single Speed DX AC'
3057
- clg_coil = create_coil_cooling_dx_single_speed(model, name: "#{zone.name} PTAC 1spd DX AC Clg Coil", type: 'PTAC')
3022
+ clg_coil = create_coil_cooling_dx_single_speed(model,
3023
+ name: "#{zone.name} PTAC 1spd DX AC Clg Coil",
3024
+ type: 'PTAC')
3058
3025
  else
3059
3026
  OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "ptac_cooling_type of #{cooling_type} is not recognized.")
3060
3027
  end
@@ -3087,6 +3054,16 @@ class Standard
3087
3054
  def model_add_pthp(model,
3088
3055
  thermal_zones,
3089
3056
  fan_type: 'Cycling')
3057
+
3058
+ # default design temperatures used across all air loops
3059
+ dsgn_temps = standard_design_sizing_temperatures
3060
+
3061
+ # adjusted zone design temperatures for pthp
3062
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_f'] = 122.0
3063
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_htg_dsgn_sup_air_temp_f'], 'F', 'C').get
3064
+ dsgn_temps['zn_clg_dsgn_sup_air_temp_f'] = 57.0
3065
+ dsgn_temps['zn_clg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_clg_dsgn_sup_air_temp_f'], 'F', 'C').get
3066
+
3090
3067
  # make a PTHP for each zone
3091
3068
  pthps = []
3092
3069
  thermal_zones.each do |zone|
@@ -3094,17 +3071,21 @@ class Standard
3094
3071
 
3095
3072
  # zone sizing
3096
3073
  sizing_zone = zone.sizingZone
3097
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(14.0)
3098
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(50.0)
3074
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
3075
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
3099
3076
  sizing_zone.setZoneCoolingDesignSupplyAirHumidityRatio(0.008)
3100
3077
  sizing_zone.setZoneHeatingDesignSupplyAirHumidityRatio(0.008)
3101
3078
 
3102
3079
  # add fan
3103
3080
  if fan_type == 'ConstantVolume'
3104
- fan = create_fan_by_name(model, 'PTAC_CAV_Fan', fan_name: "#{zone.name} PTAC Fan")
3081
+ fan = create_fan_by_name(model,
3082
+ 'PTAC_CAV_Fan',
3083
+ fan_name: "#{zone.name} PTAC Fan")
3105
3084
  fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3106
3085
  elsif fan_type == 'Cycling'
3107
- fan = create_fan_by_name(model, 'PTAC_Cycling_Fan', fan_name: "#{zone.name} PTAC Fan")
3086
+ fan = create_fan_by_name(model,
3087
+ 'PTAC_Cycling_Fan',
3088
+ fan_name: "#{zone.name} PTAC Fan")
3108
3089
  fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3109
3090
  else
3110
3091
  OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "PTHP fan_type of #{fan_type} is not recognized.")
@@ -3112,11 +3093,15 @@ class Standard
3112
3093
  end
3113
3094
 
3114
3095
  # add heating coil
3115
- htg_coil = create_coil_heating_dx_single_speed(model, name: "#{zone.name} PTHP Htg Coil")
3096
+ htg_coil = create_coil_heating_dx_single_speed(model,
3097
+ name: "#{zone.name} PTHP Htg Coil")
3116
3098
  # add cooling coil
3117
- clg_coil = create_coil_cooling_dx_single_speed(model, name: "#{zone.name} PTHP Clg Coil", type: 'Heat Pump')
3099
+ clg_coil = create_coil_cooling_dx_single_speed(model,
3100
+ name: "#{zone.name} PTHP Clg Coil",
3101
+ type: 'Heat Pump')
3118
3102
  # supplemental heating coil
3119
- supplemental_htg_coil = create_coil_heating_electric(model, name: "#{zone.name} PTHP Supplemental Htg Coil")
3103
+ supplemental_htg_coil = create_coil_heating_electric(model,
3104
+ name: "#{zone.name} PTHP Supplemental Htg Coil")
3120
3105
  # wrap coils in a PTHP system
3121
3106
  pthp_system = OpenStudio::Model::ZoneHVACPackagedTerminalHeatPump.new(model,
3122
3107
  model.alwaysOnDiscreteSchedule,
@@ -3161,7 +3146,7 @@ class Standard
3161
3146
  rated_inlet_water_temperature: 180.0,
3162
3147
  rated_outlet_water_temperature: 160.0,
3163
3148
  rated_inlet_air_temperature: 60.0,
3164
- rated_outlet_air_temperature: 100.0)
3149
+ rated_outlet_air_temperature: 104.0)
3165
3150
 
3166
3151
  # hvac operation schedule
3167
3152
  if hvac_op_sch.nil?
@@ -3174,6 +3159,13 @@ class Standard
3174
3159
  fan_control_type = 'ConstantVolume' if fan_control_type.nil?
3175
3160
  fan_pressure_rise = 0.2 if fan_pressure_rise.nil?
3176
3161
 
3162
+ # default design temperatures used across all air loops
3163
+ dsgn_temps = standard_design_sizing_temperatures
3164
+
3165
+ # adjusted zone design heating temperature for unit heater
3166
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_f'] = 122.0
3167
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_htg_dsgn_sup_air_temp_f'], 'F', 'C').get
3168
+
3177
3169
  # make a unit heater for each zone
3178
3170
  unit_heaters = []
3179
3171
  thermal_zones.each do |zone|
@@ -3181,10 +3173,7 @@ class Standard
3181
3173
 
3182
3174
  # zone sizing
3183
3175
  sizing_zone = zone.sizingZone
3184
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(14.0)
3185
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(50.0)
3186
- sizing_zone.setZoneCoolingDesignSupplyAirHumidityRatio(0.008)
3187
- sizing_zone.setZoneHeatingDesignSupplyAirHumidityRatio(0.008)
3176
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
3188
3177
 
3189
3178
  # add fan
3190
3179
  fan = create_fan_by_name(model,
@@ -3195,9 +3184,13 @@ class Standard
3195
3184
 
3196
3185
  # add heating coil
3197
3186
  if heating_type == 'NaturalGas' || heating_type == 'Gas'
3198
- htg_coil = create_coil_heating_gas(model, name: "#{zone.name} UnitHeater Gas Htg Coil", schedule: hvac_op_sch)
3187
+ htg_coil = create_coil_heating_gas(model,
3188
+ name: "#{zone.name} UnitHeater Gas Htg Coil",
3189
+ schedule: hvac_op_sch)
3199
3190
  elsif heating_type == 'Electricity' || heating_type == 'Electric'
3200
- htg_coil = create_coil_heating_electric(model, name: "#{zone.name} UnitHeater Electric Htg Coil", schedule: hvac_op_sch)
3191
+ htg_coil = create_coil_heating_electric(model,
3192
+ name: "#{zone.name} UnitHeater Electric Htg Coil",
3193
+ schedule: hvac_op_sch)
3201
3194
  elsif heating_type == 'DistrictHeating' && !hot_water_loop.nil?
3202
3195
  # control temperature for hot water loop
3203
3196
  if rated_inlet_water_temperature.nil?
@@ -3216,7 +3209,7 @@ class Standard
3216
3209
  rated_inlet_air_temperature_c = OpenStudio.convert(rated_inlet_air_temperature, 'F', 'C').get
3217
3210
  end
3218
3211
  if rated_outlet_air_temperature.nil?
3219
- rated_outlet_air_temperature_c = OpenStudio.convert(100.0, 'F', 'C').get
3212
+ rated_outlet_air_temperature_c = OpenStudio.convert(104.0, 'F', 'C').get
3220
3213
  else
3221
3214
  rated_outlet_air_temperature_c = OpenStudio.convert(rated_outlet_air_temperature, 'F', 'C').get
3222
3215
  end
@@ -3233,8 +3226,11 @@ class Standard
3233
3226
  end
3234
3227
 
3235
3228
  # create unit heater
3236
- unit_heater = OpenStudio::Model::ZoneHVACUnitHeater.new(model, hvac_op_sch, fan, htg_coil)
3237
- unit_heater.setName("#{zone.name} UnitHeater")
3229
+ unit_heater = OpenStudio::Model::ZoneHVACUnitHeater.new(model,
3230
+ hvac_op_sch,
3231
+ fan,
3232
+ htg_coil)
3233
+ unit_heater.setName("#{zone.name} Unit Heater")
3238
3234
  unit_heater.setFanControlType(fan_control_type)
3239
3235
  unit_heater.addToThermalZone(zone)
3240
3236
  unit_heaters << unit_heater
@@ -3300,19 +3296,16 @@ class Standard
3300
3296
  OpenStudio.logFree(OpenStudio::Debug, 'openstudio.Model.Model', "---#{zone.name}")
3301
3297
  end
3302
3298
 
3303
- # Evap cooler control temperatures
3304
- min_sa_temp_f = 55
3305
- clg_sa_temp_f = 70
3306
- max_sa_temp_f = 78
3307
- htg_sa_temp_f = 122 # Not used
3308
-
3309
- min_sa_temp_c = OpenStudio.convert(min_sa_temp_f, 'F', 'C').get
3310
- clg_sa_temp_c = OpenStudio.convert(clg_sa_temp_f, 'F', 'C').get
3311
- max_sa_temp_c = OpenStudio.convert(max_sa_temp_f, 'F', 'C').get
3312
- htg_sa_temp_c = OpenStudio.convert(htg_sa_temp_f, 'F', 'C').get
3299
+ # default design temperatures used across all air loops
3300
+ dsgn_temps = standard_design_sizing_temperatures
3313
3301
 
3314
- approach_r = 3 # WetBulb approach
3315
- approach_k = OpenStudio.convert(approach_r, 'R', 'K').get
3302
+ # adjusted design temperatures for evap cooler
3303
+ dsgn_temps['clg_dsgn_sup_air_temp_f'] = 70.0
3304
+ dsgn_temps['clg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['clg_dsgn_sup_air_temp_f'], 'F', 'C').get
3305
+ dsgn_temps['max_clg_dsgn_sup_air_temp_f'] = 78.0
3306
+ dsgn_temps['max_clg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['max_clg_dsgn_sup_air_temp_f'], 'F', 'C').get
3307
+ dsgn_temps['approach_r'] = 3.0 # wetbulb approach temperature
3308
+ dsgn_temps['approach_k'] = OpenStudio.convert(dsgn_temps['approach_r'], 'R', 'K').get
3316
3309
 
3317
3310
  # EMS programs
3318
3311
  programs = []
@@ -3326,6 +3319,19 @@ class Standard
3326
3319
  air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
3327
3320
  air_loop.setName("#{zone_name_clean} Evaporative Cooler")
3328
3321
 
3322
+ # default design settings used across all air loops
3323
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps)
3324
+
3325
+ # air handler controls
3326
+ # setpoint follows OAT WetBulb
3327
+ evap_stpt_manager = OpenStudio::Model::SetpointManagerFollowOutdoorAirTemperature.new(model)
3328
+ evap_stpt_manager.setName("#{dsgn_temps['approach_r']} F above OATwb")
3329
+ evap_stpt_manager.setReferenceTemperatureType('OutdoorAirWetBulb')
3330
+ evap_stpt_manager.setMaximumSetpointTemperature(dsgn_temps['max_clg_dsgn_sup_air_temp_c'])
3331
+ evap_stpt_manager.setMinimumSetpointTemperature(dsgn_temps['clg_dsgn_sup_air_temp_c'])
3332
+ evap_stpt_manager.setOffsetTemperatureDifference(dsgn_temps['approach_k'])
3333
+ evap_stpt_manager.addToNode(air_loop.supplyOutletNode)
3334
+
3329
3335
  # Schedule to control the airloop availability
3330
3336
  air_loop_avail_sch = OpenStudio::Model::ScheduleConstant.new(model)
3331
3337
  air_loop_avail_sch.setName("#{air_loop.name} Availability Sch")
@@ -3336,12 +3342,15 @@ class Standard
3336
3342
  # Without this EMS, the airloop runs 24/7-365 even when there is no load in the zone.
3337
3343
 
3338
3344
  # Create a sensor to read the zone load
3339
- zn_load_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Predicted Sensible Load to Cooling Setpoint Heat Transfer Rate')
3345
+ zn_load_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model,
3346
+ 'Zone Predicted Sensible Load to Cooling Setpoint Heat Transfer Rate')
3340
3347
  zn_load_sensor.setName("#{zone_name_clean.to_s.gsub(/[ +-.]/,'_')} Clg Load Sensor")
3341
3348
  zn_load_sensor.setKeyName(zone.handle.to_s)
3342
3349
 
3343
3350
  # Create an actuator to set the airloop availability
3344
- air_loop_avail_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(air_loop_avail_sch, 'Schedule:Constant', 'Schedule Value')
3351
+ air_loop_avail_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(air_loop_avail_sch,
3352
+ 'Schedule:Constant',
3353
+ 'Schedule Value')
3345
3354
  air_loop_avail_actuator.setName("#{air_loop.name.to_s.gsub(/[ +-.]/,'_')} Availability Actuator")
3346
3355
 
3347
3356
  # Create a program to turn on Evap Cooler if
@@ -3360,23 +3369,6 @@ class Standard
3360
3369
 
3361
3370
  programs << avail_program
3362
3371
 
3363
- # Setpoint follows OAT WetBulb
3364
- evap_stpt_manager = OpenStudio::Model::SetpointManagerFollowOutdoorAirTemperature.new(model)
3365
- evap_stpt_manager.setName("#{approach_r} F above OATwb")
3366
- evap_stpt_manager.setReferenceTemperatureType('OutdoorAirWetBulb')
3367
- evap_stpt_manager.setMaximumSetpointTemperature(max_sa_temp_c)
3368
- evap_stpt_manager.setMinimumSetpointTemperature(min_sa_temp_c)
3369
- evap_stpt_manager.setOffsetTemperatureDifference(approach_k)
3370
- evap_stpt_manager.addToNode(air_loop.supplyOutletNode)
3371
-
3372
- # Air handler sizing
3373
- sizing_system = air_loop.sizingSystem
3374
- sizing_system.setCentralCoolingDesignSupplyAirTemperature(clg_sa_temp_c)
3375
- sizing_system.setCentralHeatingDesignSupplyAirTemperature(htg_sa_temp_c)
3376
- sizing_system.setAllOutdoorAirinCooling(true)
3377
- sizing_system.setAllOutdoorAirinHeating(true)
3378
- sizing_system.setSystemOutdoorAirMethod('ZoneSum')
3379
-
3380
3372
  # Direct Evap Cooler
3381
3373
  # TODO: better assumptions for evap cooler performance and fan pressure rise
3382
3374
  evap = OpenStudio::Model::EvaporativeCoolerDirectResearchSpecial.new(model, model.alwaysOnDiscreteSchedule)
@@ -3385,7 +3377,9 @@ class Standard
3385
3377
  evap.addToNode(air_loop.supplyInletNode)
3386
3378
 
3387
3379
  # Fan (cycling), must be inside unitary system to cycle on airloop
3388
- fan = create_fan_by_name(model, 'Evap_Cooler_Supply_Fan', fan_name: "#{zone.name} Evap Cooler Supply Fan")
3380
+ fan = create_fan_by_name(model,
3381
+ 'Evap_Cooler_Supply_Fan',
3382
+ fan_name: "#{zone.name} Evap Cooler Supply Fan")
3389
3383
  fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3390
3384
 
3391
3385
  # Dummy zero-capacity cooling coil
@@ -3397,7 +3391,7 @@ class Standard
3397
3391
  unitary_system.setSupplyFan(fan)
3398
3392
  unitary_system.setCoolingCoil(clg_coil)
3399
3393
  unitary_system.setControllingZoneorThermostatLocation(zone)
3400
- unitary_system.setMaximumSupplyAirTemperature(50)
3394
+ unitary_system.setMaximumSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
3401
3395
  unitary_system.setFanPlacement('BlowThrough')
3402
3396
  unitary_system.setSupplyAirFlowRateMethodDuringCoolingOperation('SupplyAirFlowRate')
3403
3397
  unitary_system.setSupplyAirFlowRateMethodDuringHeatingOperation('SupplyAirFlowRate')
@@ -3429,9 +3423,7 @@ class Standard
3429
3423
 
3430
3424
  sizing_zone = zone.sizingZone
3431
3425
  sizing_zone.setCoolingDesignAirFlowMethod('DesignDay')
3432
- sizing_zone.setHeatingDesignAirFlowMethod('DesignDay')
3433
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(clg_sa_temp_c)
3434
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(htg_sa_temp_c)
3426
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
3435
3427
 
3436
3428
  evap_coolers << air_loop
3437
3429
  end
@@ -3493,9 +3485,9 @@ class Standard
3493
3485
  vrf_outdoor_unit = create_air_conditioner_variable_refrigerant_flow(model,
3494
3486
  name: "#{thermal_zones.size} Zone VRF System",
3495
3487
  master_zone: master_zone)
3496
- # fan coil supply air temps used across all zones
3497
- zn_dsn_clg_sa_temp_c = OpenStudio.convert(55.0, 'F', 'C').get
3498
- zn_dsn_htg_sa_temp_c = OpenStudio.convert(104.0, 'F', 'C').get
3488
+
3489
+ # default design temperatures used across all air loops
3490
+ dsgn_temps = standard_design_sizing_temperatures
3499
3491
 
3500
3492
  vrfs = []
3501
3493
  thermal_zones.each do |zone|
@@ -3503,8 +3495,8 @@ class Standard
3503
3495
 
3504
3496
  # zone sizing
3505
3497
  sizing_zone = zone.sizingZone
3506
- sizing_zone.setZoneCoolingDesignSupplyAirTemperature(zn_dsn_clg_sa_temp_c)
3507
- sizing_zone.setZoneHeatingDesignSupplyAirTemperature(zn_dsn_htg_sa_temp_c)
3498
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
3499
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
3508
3500
 
3509
3501
  # add vrf terminal unit
3510
3502
  vrf_terminal_unit = OpenStudio::Model::ZoneHVACTerminalUnitVariableRefrigerantFlow.new(model)
@@ -3513,15 +3505,15 @@ class Standard
3513
3505
  vrf_terminal_unit.setTerminalUnitAvailabilityschedule(model.alwaysOnDiscreteSchedule)
3514
3506
 
3515
3507
  # no outdoor air assumed
3516
- vrf_terminal_unit.setOutdoorAirFlowRateDuringCoolingOperation(0)
3517
- vrf_terminal_unit.setOutdoorAirFlowRateDuringHeatingOperation(0)
3518
- vrf_terminal_unit.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(0)
3508
+ vrf_terminal_unit.setOutdoorAirFlowRateDuringCoolingOperation(0.0)
3509
+ vrf_terminal_unit.setOutdoorAirFlowRateDuringHeatingOperation(0.0)
3510
+ vrf_terminal_unit.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(0.0)
3519
3511
 
3520
3512
  # set fan variables
3521
3513
  # always off denotes cycling fan
3522
3514
  vrf_terminal_unit.setSupplyAirFanOperatingModeSchedule(model.alwaysOffDiscreteSchedule)
3523
3515
  vrf_fan = vrf_terminal_unit.supplyAirFan.to_FanOnOff.get
3524
- vrf_fan.setPressureRise(300)
3516
+ vrf_fan.setPressureRise(300.0)
3525
3517
  vrf_fan.setMotorEfficiency(0.8)
3526
3518
  vrf_fan.setFanEfficiency(0.6)
3527
3519
  vrf_fan.setName("#{zone.name} VRF Unit Cycling Fan")
@@ -3548,17 +3540,16 @@ class Standard
3548
3540
  hot_water_loop: nil,
3549
3541
  ventilation: false)
3550
3542
 
3551
- # fan coil supply air temps used across all zones
3552
- zn_dsn_clg_sa_temp_c = OpenStudio.convert(55.0, 'F', 'C').get
3553
- zn_dsn_htg_sa_temp_c = OpenStudio.convert(104.0, 'F', 'C').get
3543
+ # default design temperatures used across all air loops
3544
+ dsgn_temps = standard_design_sizing_temperatures
3554
3545
 
3555
3546
  # make a fan coil unit for each zone
3556
3547
  fcus = []
3557
3548
  thermal_zones.each do |zone|
3558
3549
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Adding fan coil for #{zone.name}.")
3559
- zone_sizing = zone.sizingZone
3560
- zone_sizing.setZoneCoolingDesignSupplyAirTemperature(zn_dsn_clg_sa_temp_c)
3561
- zone_sizing.setZoneHeatingDesignSupplyAirTemperature(zn_dsn_htg_sa_temp_c)
3550
+ sizing_zone = zone.sizingZone
3551
+ sizing_zone.setZoneCoolingDesignSupplyAirTemperature(dsgn_temps['zn_clg_dsgn_sup_air_temp_c'])
3552
+ sizing_zone.setZoneHeatingDesignSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
3562
3553
 
3563
3554
  if chilled_water_loop
3564
3555
  fcu_clg_coil = create_coil_cooling_water(model,
@@ -3573,7 +3564,7 @@ class Standard
3573
3564
  fcu_htg_coil = create_coil_heating_water(model,
3574
3565
  hot_water_loop,
3575
3566
  name: "#{zone.name} FCU Heating Coil",
3576
- rated_outlet_air_temperature: zn_dsn_htg_sa_temp_c)
3567
+ rated_outlet_air_temperature: dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
3577
3568
  else
3578
3569
  # Zero-capacity, always-off electric heating coil
3579
3570
  fcu_htg_coil = create_coil_heating_electric(model,
@@ -3645,7 +3636,11 @@ class Standard
3645
3636
  name: "#{zone.name} Window AC Always Off Htg Coil",
3646
3637
  schedule: model.alwaysOffDiscreteSchedule,
3647
3638
  nominal_capacity: 0)
3648
- ptac = OpenStudio::Model::ZoneHVACPackagedTerminalAirConditioner.new(model, model.alwaysOnDiscreteSchedule, fan, htg_coil, clg_coil)
3639
+ ptac = OpenStudio::Model::ZoneHVACPackagedTerminalAirConditioner.new(model,
3640
+ model.alwaysOnDiscreteSchedule,
3641
+ fan,
3642
+ htg_coil,
3643
+ clg_coil)
3649
3644
  ptac.setName("#{zone.name} Window AC")
3650
3645
  ptac.setSupplyAirFanOperatingModeSchedule(model.alwaysOffDiscreteSchedule)
3651
3646
  ptac.addToThermalZone(zone)
@@ -3697,6 +3692,21 @@ class Standard
3697
3692
  air_loop.setName("#{zone.name} #{equip_name}")
3698
3693
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Adding furnace AC for #{zone.name}.")
3699
3694
 
3695
+
3696
+ # default design temperatures across all air loops
3697
+ dsgn_temps = standard_design_sizing_temperatures
3698
+
3699
+ # adjusted temperatures for furnace_central_ac
3700
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_f'] = 122.0
3701
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_htg_dsgn_sup_air_temp_f'], 'F', 'C').get
3702
+ dsgn_temps['htg_dsgn_sup_air_temp_f'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_f']
3703
+ dsgn_temps['htg_dsgn_sup_air_temp_c'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_c']
3704
+
3705
+ # default design settings used across all air loops
3706
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps, sizing_option: 'NonCoincident')
3707
+ sizing_system.setAllOutdoorAirinCooling(true)
3708
+ sizing_system.setAllOutdoorAirinHeating(true)
3709
+
3700
3710
  # create heating coil
3701
3711
  htg_coil = nil
3702
3712
  if heating
@@ -3726,7 +3736,7 @@ class Standard
3726
3736
  # create fan
3727
3737
  fan = create_fan_by_name(model,
3728
3738
  'Residential_HVAC_Fan',
3729
- fan_name: "#{air_loop.name} supply fan",
3739
+ fan_name: "#{air_loop.name} Supply Fan",
3730
3740
  end_use_subcategory: 'Residential HVAC Fans')
3731
3741
  fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3732
3742
 
@@ -3743,9 +3753,9 @@ class Standard
3743
3753
 
3744
3754
  # create unitary system (holds the coils and fan)
3745
3755
  unitary = OpenStudio::Model::AirLoopHVACUnitarySystem.new(model)
3746
- unitary.setName("#{air_loop.name} unitary system")
3756
+ unitary.setName("#{air_loop.name} Unitary System")
3747
3757
  unitary.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3748
- unitary.setMaximumSupplyAirTemperature(OpenStudio.convert(120.0, 'F', 'C').get)
3758
+ unitary.setMaximumSupplyAirTemperature(dsgn_temps['zn_htg_dsgn_sup_air_temp_c'])
3749
3759
  unitary.setControllingZoneorThermostatLocation(zone)
3750
3760
  unitary.addToNode(air_loop.supplyInletNode)
3751
3761
 
@@ -3763,7 +3773,7 @@ class Standard
3763
3773
 
3764
3774
  # create a diffuser
3765
3775
  diffuser = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule)
3766
- diffuser.setName("#{zone.name} direct air")
3776
+ diffuser.setName("#{zone.name} Direct Air")
3767
3777
  air_loop.addBranchForZone(zone, diffuser)
3768
3778
 
3769
3779
  furnaces << air_loop
@@ -3804,6 +3814,20 @@ class Standard
3804
3814
  air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
3805
3815
  air_loop.setName("#{zone.name} Central Air Source HP")
3806
3816
 
3817
+ # default design temperatures across all air loops
3818
+ dsgn_temps = standard_design_sizing_temperatures
3819
+
3820
+ # adjusted temperatures for furnace_central_ac
3821
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_f'] = 122.0
3822
+ dsgn_temps['zn_htg_dsgn_sup_air_temp_c'] = OpenStudio.convert(dsgn_temps['zn_htg_dsgn_sup_air_temp_f'], 'F', 'C').get
3823
+ dsgn_temps['htg_dsgn_sup_air_temp_f'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_f']
3824
+ dsgn_temps['htg_dsgn_sup_air_temp_c'] = dsgn_temps['zn_htg_dsgn_sup_air_temp_c']
3825
+
3826
+ # default design settings used across all air loops
3827
+ sizing_system = adjust_sizing_system(air_loop, dsgn_temps, sizing_option: 'NonCoincident')
3828
+ sizing_system.setAllOutdoorAirinCooling(true)
3829
+ sizing_system.setAllOutdoorAirinHeating(true)
3830
+
3807
3831
  # create heating coil
3808
3832
  htg_coil = nil
3809
3833
  supplemental_htg_coil = nil
@@ -3824,14 +3848,15 @@ class Standard
3824
3848
  # Supplemental Heating Coil
3825
3849
 
3826
3850
  # create supplemental heating coil
3827
- supplemental_htg_coil = create_coil_heating_electric(model, name: "#{air_loop.name} Supplemental Htg Coil")
3851
+ supplemental_htg_coil = create_coil_heating_electric(model,
3852
+ name: "#{air_loop.name} Supplemental Htg Coil")
3828
3853
  end
3829
3854
 
3830
3855
  # create cooling coil
3831
3856
  clg_coil = nil
3832
3857
  if cooling
3833
3858
  clg_coil = create_coil_cooling_dx_single_speed(model,
3834
- name: "#{air_loop.name} cooling coil",
3859
+ name: "#{air_loop.name} Cooling Coil",
3835
3860
  type: 'Residential Central ASHP',
3836
3861
  cop: cop)
3837
3862
  clg_coil.setRatedSensibleHeatRatio(shr)
@@ -3848,7 +3873,7 @@ class Standard
3848
3873
  # create fan
3849
3874
  fan = create_fan_by_name(model,
3850
3875
  'Residential_HVAC_Fan',
3851
- fan_name: "#{air_loop.name} supply fan",
3876
+ fan_name: "#{air_loop.name} Supply Fan",
3852
3877
  end_use_subcategory: 'Residential HVAC Fans')
3853
3878
  fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3854
3879
 
@@ -3865,7 +3890,7 @@ class Standard
3865
3890
 
3866
3891
  # create unitary system (holds the coils and fan)
3867
3892
  unitary = OpenStudio::Model::AirLoopHVACUnitarySystem.new(model)
3868
- unitary.setName("#{air_loop.name} zone unitary system")
3893
+ unitary.setName("#{air_loop.name} Unitary System")
3869
3894
  unitary.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3870
3895
  unitary.setMaximumSupplyAirTemperature(OpenStudio.convert(170.0, 'F', 'C').get) # higher temp for supplemental heat as to not severely limit its use, resulting in unmet hours.
3871
3896
  unitary.setMaximumOutdoorDryBulbTemperatureforSupplementalHeaterOperation(OpenStudio.convert(40.0, 'F', 'C').get)
@@ -3885,7 +3910,7 @@ class Standard
3885
3910
 
3886
3911
  # create a diffuser
3887
3912
  diffuser = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule)
3888
- diffuser.setName(" #{zone.name} direct air")
3913
+ diffuser.setName(" #{zone.name} Direct Air")
3889
3914
  air_loop.addBranchForZone(zone, diffuser)
3890
3915
 
3891
3916
  hps << air_loop
@@ -3910,15 +3935,27 @@ class Standard
3910
3935
 
3911
3936
  water_to_air_hp_systems = []
3912
3937
  thermal_zones.each do |zone|
3913
- supplemental_htg_coil = create_coil_heating_electric(model, name: "#{zone.name} Supplemental Htg Coil")
3914
- htg_coil = create_coil_heating_water_to_air_heat_pump_equation_fit(model, condenser_loop, name: "#{zone.name} Water-to-Air HP Htg Coil")
3915
- clg_coil = create_coil_cooling_water_to_air_heat_pump_equation_fit(model, condenser_loop, name: "#{zone.name} Water-to-Air HP Clg Coil")
3938
+ supplemental_htg_coil = create_coil_heating_electric(model,
3939
+ name: "#{zone.name} Supplemental Htg Coil")
3940
+ htg_coil = create_coil_heating_water_to_air_heat_pump_equation_fit(model,
3941
+ condenser_loop,
3942
+ name: "#{zone.name} Water-to-Air HP Htg Coil")
3943
+ clg_coil = create_coil_cooling_water_to_air_heat_pump_equation_fit(model,
3944
+ condenser_loop,
3945
+ name: "#{zone.name} Water-to-Air HP Clg Coil")
3916
3946
 
3917
3947
  # add fan
3918
- fan = create_fan_by_name(model, 'WSHP_Fan', fan_name: "#{zone.name} WSHP Fan")
3948
+ fan = create_fan_by_name(model,
3949
+ 'WSHP_Fan',
3950
+ fan_name: "#{zone.name} WSHP Fan")
3919
3951
  fan.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
3920
3952
 
3921
- water_to_air_hp_system = OpenStudio::Model::ZoneHVACWaterToAirHeatPump.new(model, model.alwaysOnDiscreteSchedule, fan, htg_coil, clg_coil, supplemental_htg_coil)
3953
+ water_to_air_hp_system = OpenStudio::Model::ZoneHVACWaterToAirHeatPump.new(model,
3954
+ model.alwaysOnDiscreteSchedule,
3955
+ fan,
3956
+ htg_coil,
3957
+ clg_coil,
3958
+ supplemental_htg_coil)
3922
3959
  water_to_air_hp_system.setName("#{zone.name} WSHP")
3923
3960
  unless ventilation
3924
3961
  water_to_air_hp_system.setOutdoorAirFlowRateDuringHeatingOperation(OpenStudio::OptionalDouble.new(0.0))
@@ -3946,10 +3983,14 @@ class Standard
3946
3983
 
3947
3984
  # Determine the OA requirement for this zone
3948
3985
  min_oa_flow_m3_per_s_per_m2 = thermal_zone_outdoor_airflow_rate_per_area(zone)
3949
- supply_fan = create_fan_by_name(model, 'ERV_Supply_Fan', fan_name: "#{zone.name} ERV Supply Fan")
3986
+ supply_fan = create_fan_by_name(model,
3987
+ 'ERV_Supply_Fan',
3988
+ fan_name: "#{zone.name} ERV Supply Fan")
3950
3989
  impeller_eff = fan_baseline_impeller_efficiency(supply_fan)
3951
3990
  fan_change_impeller_efficiency(supply_fan, impeller_eff)
3952
- exhaust_fan = create_fan_by_name(model, 'ERV_Supply_Fan', fan_name: "#{zone.name} ERV Exhaust Fan")
3991
+ exhaust_fan = create_fan_by_name(model,
3992
+ 'ERV_Supply_Fan',
3993
+ fan_name: "#{zone.name} ERV Exhaust Fan")
3953
3994
  fan_change_impeller_efficiency(exhaust_fan, impeller_eff)
3954
3995
 
3955
3996
  erv_controller = OpenStudio::Model::ZoneHVACEnergyRecoveryVentilatorController.new(model)
@@ -4006,11 +4047,11 @@ class Standard
4006
4047
  hottest_erv_supply_c = OpenStudio.convert(hottest_erv_supply_f, 'F', 'C').get
4007
4048
 
4008
4049
  # Ensure that zone sizing accounts for OA from ERV
4009
- zone_sizing = zone.sizingZone
4010
- zone_sizing.setAccountforDedicatedOutdoorAirSystem(true)
4011
- zone_sizing.setDedicatedOutdoorAirSystemControlStrategy('NeutralSupplyAir')
4012
- zone_sizing.setDedicatedOutdoorAirLowSetpointTemperatureforDesign(coldest_erv_supply_c)
4013
- zone_sizing.setDedicatedOutdoorAirHighSetpointTemperatureforDesign(hottest_erv_supply_c)
4050
+ sizing_zone = zone.sizingZone
4051
+ sizing_zone.setAccountforDedicatedOutdoorAirSystem(true)
4052
+ sizing_zone.setDedicatedOutdoorAirSystemControlStrategy('NeutralSupplyAir')
4053
+ sizing_zone.setDedicatedOutdoorAirLowSetpointTemperatureforDesign(coldest_erv_supply_c)
4054
+ sizing_zone.setDedicatedOutdoorAirHighSetpointTemperatureforDesign(hottest_erv_supply_c)
4014
4055
 
4015
4056
  ervs << zone_hvac
4016
4057
  end
@@ -4020,19 +4061,158 @@ class Standard
4020
4061
 
4021
4062
  # Adds ideal air loads systems for each zone.
4022
4063
  #
4023
- # @param thermal_zones [Array<OpenStudio::Model::ThermalZone>] array of zones to add heat pumps to.
4064
+ # @param thermal_zones [Array<OpenStudio::Model::ThermalZone>] array of zones to enable ideal air loads
4065
+ # @param hvac_op_sch [String] name of the HVAC operation schedule, default is always on
4066
+ # @param heat_avail_sch [String] name of the heating availability schedule, default is always on
4067
+ # @param cool_avail_sch [String] name of the cooling availability schedule, default is always on
4068
+ # @param heat_limit_type [String] heating limit type
4069
+ # options are 'NoLimit', 'LimitFlowRate', 'LimitCapacity', and 'LimitFlowRateAndCapacity'
4070
+ # @param cool_limit_type [String] cooling limit type
4071
+ # options are 'NoLimit', 'LimitFlowRate', 'LimitCapacity', and 'LimitFlowRateAndCapacity'
4072
+ # @param dehumid_limit_type [String] dehumidification limit type
4073
+ # options are 'None', 'ConstantSensibleHeatRatio', 'Humidistat', 'ConstantSupplyHumidityRatio'
4074
+ # @param cool_sensible_heat_ratio [Double] cooling sensible heat ratio if dehumidification limit type is 'ConstantSensibleHeatRatio'
4075
+ # @param humid_ctrl_type [String] humidification control type
4076
+ # options are 'None', 'Humidistat', 'ConstantSupplyHumidityRatio'
4077
+ # @param include_outdoor_air [Boolean] include design specification outdoor air ventilation
4078
+ # @param enable_dcv [Boolean] include demand control ventilation, uses occupancy schedule if true
4079
+ # @param econo_ctrl_mthd [String] economizer control method (require a cool_limit_type and include_outdoor_air set to true)
4080
+ # options are 'NoEconomizer', 'DifferentialDryBulb', 'DifferentialEnthalpy'
4081
+ # @param heat_recovery_type [String] heat recovery type
4082
+ # options are 'None', 'Sensible', 'Enthalpy'
4083
+ # @param heat_recovery_sensible_eff [Double] heat recovery sensible effectivness if heat recovery specified
4084
+ # @param heat_recovery_latent_eff [Double] heat recovery latent effectivness if heat recovery specified
4085
+ # @param add_output_meters [Boolean] include and output custom meter objects to sum all ideal air loads values
4024
4086
  # @return [Array<OpenStudio::Model::ZoneHVACIdealLoadsAirSystem>] an array of ideal air loads systems
4025
- # TODO: enable default ventilation settings, see https://github.com/UnmetHours/openstudio-measures/tree/master/ideal_loads_options
4026
4087
  def model_add_ideal_air_loads(model,
4027
- thermal_zones)
4088
+ thermal_zones,
4089
+ hvac_op_sch: nil,
4090
+ heat_avail_sch: nil,
4091
+ cool_avail_sch: nil,
4092
+ heat_limit_type: 'NoLimit',
4093
+ cool_limit_type: 'NoLimit',
4094
+ dehumid_limit_type: 'ConstantSensibleHeatRatio',
4095
+ cool_sensible_heat_ratio: 0.7,
4096
+ humid_ctrl_type: 'None',
4097
+ include_outdoor_air: true,
4098
+ enable_dcv: false,
4099
+ econo_ctrl_mthd: 'NoEconomizer',
4100
+ heat_recovery_type: 'None',
4101
+ heat_recovery_sensible_eff: 0.7,
4102
+ heat_recovery_latent_eff: 0.65,
4103
+ add_output_meters: false)
4104
+
4105
+ # set availability schedules
4106
+ if hvac_op_sch.nil?
4107
+ hvac_op_sch = model.alwaysOnDiscreteSchedule
4108
+ else
4109
+ hvac_op_sch = model_add_schedule(model, hvac_op_sch)
4110
+ end
4111
+
4112
+ # set heating availability schedules
4113
+ if heat_avail_sch.nil?
4114
+ heat_avail_sch = model.alwaysOnDiscreteSchedule
4115
+ else
4116
+ heat_avail_sch = model_add_schedule(model, heat_avail_sch)
4117
+ end
4118
+
4119
+ # set cooling availability schedules
4120
+ if cool_avail_sch.nil?
4121
+ cool_avail_sch = model.alwaysOnDiscreteSchedule
4122
+ else
4123
+ cool_avail_sch = model_add_schedule(model, cool_avail_sch)
4124
+ end
4125
+
4028
4126
  ideal_systems = []
4029
4127
  thermal_zones.each do |zone|
4030
4128
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Adding ideal air loads for for #{zone.name}.")
4031
4129
  ideal_loads = OpenStudio::Model::ZoneHVACIdealLoadsAirSystem.new(model)
4130
+ ideal_loads.setName("#{zone.name} Ideal Loads Air System")
4131
+ ideal_loads.setAvailabilitySchedule(hvac_op_sch)
4132
+ ideal_loads.setHeatingAvailabilitySchedule(heat_avail_sch)
4133
+ ideal_loads.setCoolingAvailabilitySchedule(cool_avail_sch)
4134
+ ideal_loads.setHeatingLimit(heat_limit_type)
4135
+ ideal_loads.setCoolingLimit(cool_limit_type)
4136
+ ideal_loads.setDehumidificationControlType(dehumid_limit_type)
4137
+ ideal_loads.setCoolingSensibleHeatRatio(cool_sensible_heat_ratio)
4138
+ ideal_loads.setHumidificationControlType(humid_ctrl_type)
4139
+ if include_outdoor_air
4140
+ # get the design specification outdoor air of the largest space in the zone
4141
+ # TODO: create a new design specification outdoor air object that sums ventilation rates and schedules if multiple design specification outdoor air objects
4142
+ space_areas = zone.spaces.map { |s| s.floorArea }
4143
+ largest_space = zone.spaces.select { |s| s.floorArea == space_areas.max }
4144
+ largest_space = largest_space[0]
4145
+ design_spec_oa = largest_space.designSpecificationOutdoorAir
4146
+ if design_spec_oa.is_initialized
4147
+ design_spec_oa = design_spec_oa.get
4148
+ ideal_loads.setDesignSpecificationOutdoorAirObject(design_spec_oa)
4149
+ else
4150
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.Model.Model', "Outdoor air requested for ideal loads object, but space #{largest_space.name} in thermal zone #{zone.name} does not have a design specification outdoor air object.")
4151
+ end
4152
+ end
4153
+ if enable_dcv
4154
+ ideal_loads.setDemandControlledVentilationType('OccupancySchedule')
4155
+ else
4156
+ ideal_loads.setDemandControlledVentilationType('None')
4157
+ end
4158
+ ideal_loads.setOutdoorAirEconomizerType(econo_ctrl_mthd)
4159
+ ideal_loads.setHeatRecoveryType(heat_recovery_type)
4160
+ ideal_loads.setSensibleHeatRecoveryEffectiveness(heat_recovery_sensible_eff)
4161
+ ideal_loads.setLatentHeatRecoveryEffectiveness(heat_recovery_latent_eff)
4032
4162
  ideal_loads.addToThermalZone(zone)
4033
4163
  ideal_systems << ideal_loads
4034
4164
  end
4035
4165
 
4166
+ if add_output_meters
4167
+ # ideal air loads system variables to include
4168
+ ideal_air_loads_system_variables = [
4169
+ 'Zone Ideal Loads Supply Air Sensible Heating Energy',
4170
+ 'Zone Ideal Loads Supply Air Latent Heating Energy',
4171
+ 'Zone Ideal Loads Supply Air Total Heating Energy',
4172
+ 'Zone Ideal Loads Supply Air Sensible Cooling Energy',
4173
+ 'Zone Ideal Loads Supply Air Latent Cooling Energy',
4174
+ 'Zone Ideal Loads Supply Air Total Cooling Energy',
4175
+ 'Zone Ideal Loads Zone Sensible Heating Energy',
4176
+ 'Zone Ideal Loads Zone Latent Heating Energy',
4177
+ 'Zone Ideal Loads Zone Total Heating Energy',
4178
+ 'Zone Ideal Loads Zone Sensible Cooling Energy',
4179
+ 'Zone Ideal Loads Zone Latent Cooling Energy',
4180
+ 'Zone Ideal Loads Zone Total Cooling Energy',
4181
+ 'Zone Ideal Loads Outdoor Air Sensible Heating Energy',
4182
+ 'Zone Ideal Loads Outdoor Air Latent Heating Energy',
4183
+ 'Zone Ideal Loads Outdoor Air Total Heating Energy',
4184
+ 'Zone Ideal Loads Outdoor Air Sensible Cooling Energy',
4185
+ 'Zone Ideal Loads Outdoor Air Latent Cooling Energy',
4186
+ 'Zone Ideal Loads Outdoor Air Total Cooling Energy',
4187
+ 'Zone Ideal Loads Heat Recovery Sensible Heating Energy',
4188
+ 'Zone Ideal Loads Heat Recovery Latent Heating Energy',
4189
+ 'Zone Ideal Loads Heat Recovery Total Heating Energy',
4190
+ 'Zone Ideal Loads Heat Recovery Sensible Cooling Energy',
4191
+ 'Zone Ideal Loads Heat Recovery Latent Cooling Energy',
4192
+ 'Zone Ideal Loads Heat Recovery Total Cooling Energy'
4193
+ ]
4194
+
4195
+ meters_added = 0
4196
+ outputs_added = 0
4197
+ ideal_air_loads_system_variables.each do |variable|
4198
+ # create meter definition for variable
4199
+ meter_definition = OpenStudio::Model::MeterCustom.new(model)
4200
+ meter_definition.setName("Sum #{variable}")
4201
+ meter_definition.setFuelType('Generic')
4202
+ model.getZoneHVACIdealLoadsAirSystems.each { |sys| meter_definition.addKeyVarGroup(sys.name.to_s, variable) }
4203
+ meters_added += 1
4204
+
4205
+ # add output meter
4206
+ output_meter_definition = OpenStudio::Model::OutputMeter.new(model)
4207
+ output_meter_definition.setName("Sum #{variable}")
4208
+ output_meter_definition.setReportingFrequency('Hourly')
4209
+ output_meter_definition.setMeterFileOnly(true)
4210
+ output_meter_definition.setCumulative(false)
4211
+ outputs_added += 1
4212
+ end
4213
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.Model.Model', "Added #{meters_added} custom meter objects and #{outputs_added} meter outputs for ideal loads air systems.")
4214
+ end
4215
+
4036
4216
  return ideal_systems
4037
4217
  end
4038
4218
 
@@ -4044,6 +4224,7 @@ class Standard
4044
4224
  # @param flow_fraction_schedule_name [String] the name of the flow fraction schedule
4045
4225
  # @param balanced_exhaust_fraction_schedule_name [String] the name of the balanced exhaust fraction schedule
4046
4226
  # @return [Array<OpenStudio::Model::FanZoneExhaust>] an array of exhaust fans created
4227
+ # @todo: use the create_fan_zone_exhaust method, default to 1.25 inH2O pressure rise and fan efficiency of 0.6
4047
4228
  def model_add_exhaust_fan(model,
4048
4229
  thermal_zones,
4049
4230
  flow_rate: nil,
@@ -4935,172 +5116,4 @@ class Standard
4935
5116
  rename_air_loop_nodes(model)
4936
5117
  rename_plant_loop_nodes(model)
4937
5118
  end
4938
-
4939
- # Determine the typical system type given the inputs.
4940
- #
4941
- # @param area_type [String] Valid choices are residential and nonresidential
4942
- # @param delivery_type [String] Conditioning delivery type. Valid choices are air and hydronic
4943
- # @param heating_source [String] Valid choices are Electricity, NaturalGas, DistrictHeating, DistrictAmbient
4944
- # @param cooling_source [String] Valid choices are Electricity, DistrictCooling, DistrictAmbient
4945
- # @param area_m2 [Double] Area in m^2
4946
- # @param num_stories [Integer] Number of stories
4947
- # @return [String] The system type. Possibilities are
4948
- # PTHP, PTAC, PSZ_AC, PSZ_HP, PVAV_Reheat, PVAV_PFP_Boxes,
4949
- # VAV_Reheat, VAV_PFP_Boxes, Gas_Furnace, Electric_Furnace
4950
- def model_typical_hvac_system_type(model,
4951
- climate_zone,
4952
- area_type,
4953
- delivery_type,
4954
- heating_source,
4955
- cooling_source,
4956
- area_m2,
4957
- num_stories)
4958
-
4959
- # Convert area to ft^2
4960
- area_ft2 = OpenStudio.convert(area_m2, 'm^2', 'ft^2').get
4961
-
4962
- # categorize building by type & size
4963
- size_category = nil
4964
- case area_type
4965
- when 'residential'
4966
- # residential and less than 4 stories
4967
- size_category = if num_stories <= 3
4968
- 'res_small'
4969
- # residential and more than 4 stories
4970
- else
4971
- 'res_med'
4972
- end
4973
- when 'nonresidential', 'retail', 'publicassembly', 'heatedonly'
4974
- # nonresidential and 3 floors or less and < 75,000 ft2
4975
- if num_stories <= 3 && area_ft2 < 75_000
4976
- size_category = 'nonres_small'
4977
- # nonresidential and 4 or 5 floors OR 5 floors or less and 75,000 ft2 to 150,000 ft2
4978
- elsif ((num_stories == 4 || num_stories == 5) && area_ft2 < 75_000) || (num_stories <= 5 && (area_ft2 >= 75_000 && area_ft2 <= 150_000))
4979
- size_category = 'nonres_med'
4980
- # nonresidential and more than 5 floors or >150,000 ft2
4981
- elsif num_stories >= 5 || area_ft2 > 150_000
4982
- size_category = 'nonres_lg'
4983
- end
4984
- else
4985
- OpenStudio.logFree(OpenStudio::Error, 'openstudio.Model.Model', 'No area_type specified.')
4986
- end
4987
-
4988
- # Define the lookup by row and by fuel type
4989
- systems= Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
4990
- # [heating_source][cooling_source][delivery_type][size_category] = [type, central_heating_fuel, zone_heating_fuel, cooling_fuel]
4991
-
4992
- ## Forced Air ##
4993
-
4994
- # Gas, Electric, forced air
4995
- systems['NaturalGas']['Electricity']['air']['res_small'] = ['PTAC', 'NaturalGas', nil, 'Electricity']
4996
- systems['NaturalGas']['Electricity']['air']['res_med'] = ['PTAC', 'NaturalGas', nil, 'Electricity']
4997
- systems['NaturalGas']['Electricity']['air']['nonres_small'] = ['PSZ-AC', 'NaturalGas', nil, 'Electricity']
4998
- systems['NaturalGas']['Electricity']['air']['nonres_med'] = ['PVAV Reheat', 'NaturalGas', 'NaturalGas', 'Electricity']
4999
- systems['NaturalGas']['Electricity']['air']['nonres_lg'] = ['VAV Reheat', 'NaturalGas', 'NaturalGas', 'Electricity']
5000
-
5001
- # Electric, Electric, forced air
5002
- systems['Electricity']['Electricity']['air']['res_small'] = ['PTHP', 'Electricity', nil, 'Electricity']
5003
- systems['Electricity']['Electricity']['air']['res_med'] = ['PTHP', 'Electricity', nil, 'Electricity']
5004
- systems['Electricity']['Electricity']['air']['nonres_small'] = ['PSZ-HP', 'Electricity', nil, 'Electricity']
5005
- systems['Electricity']['Electricity']['air']['nonres_med'] = ['PVAV PFP Boxes', 'Electricity', 'Electricity', 'Electricity']
5006
- systems['Electricity']['Electricity']['air']['nonres_lg'] = ['VAV PFP Boxes', 'Electricity', 'Electricity', 'Electricity']
5007
-
5008
- # District Hot Water, Electric, forced air
5009
- systems['DistrictHeating']['Electricity']['air']['res_small'] = ['PTAC', 'DistrictHeating', nil, 'Electricity']
5010
- systems['DistrictHeating']['Electricity']['air']['res_med'] = ['PTAC', 'DistrictHeating', nil, 'Electricity']
5011
- systems['DistrictHeating']['Electricity']['air']['nonres_small'] = ['PVAV Reheat', 'DistrictHeating', 'DistrictHeating', 'Electricity']
5012
- systems['DistrictHeating']['Electricity']['air']['nonres_med'] = ['PVAV Reheat', 'DistrictHeating', 'DistrictHeating', 'Electricity']
5013
- systems['DistrictHeating']['Electricity']['air']['nonres_lg'] = ['VAV Reheat', 'DistrictHeating', 'DistrictHeating', 'Electricity']
5014
-
5015
- # Ambient Loop, Ambient Loop, forced air
5016
- systems['DistrictAmbient']['DistrictAmbient']['air']['res_small'] = ['Water Source Heat Pumps with ERVs', 'HeatPump', nil, 'HeatPump']
5017
- systems['DistrictAmbient']['DistrictAmbient']['air']['res_med'] = ['Water Source Heat Pumps with DOAS', 'HeatPump', nil, 'HeatPump']
5018
- systems['DistrictAmbient']['DistrictAmbient']['air']['nonres_small'] = ['PVAV Reheat', 'HeatPump', 'HeatPump', 'HeatPump']
5019
- systems['DistrictAmbient']['DistrictAmbient']['air']['nonres_med'] = ['PVAV Reheat', 'HeatPump', 'HeatPump', 'HeatPump']
5020
- systems['DistrictAmbient']['DistrictAmbient']['air']['nonres_lg'] = ['VAV Reheat', 'HeatPump', 'HeatPump', 'HeatPump']
5021
-
5022
- # Gas, District Chilled Water, forced air
5023
- systems['NaturalGas']['DistrictCooling']['air']['res_small'] = ['PSZ-AC', 'NaturalGas', nil, 'DistrictCooling']
5024
- systems['NaturalGas']['DistrictCooling']['air']['res_med'] = ['PSZ-AC', 'NaturalGas', nil, 'DistrictCooling']
5025
- systems['NaturalGas']['DistrictCooling']['air']['nonres_small'] = ['PSZ-AC', 'NaturalGas', nil, 'DistrictCooling']
5026
- systems['NaturalGas']['DistrictCooling']['air']['nonres_med'] = ['PVAV Reheat', 'NaturalGas', 'NaturalGas', 'DistrictCooling']
5027
- systems['NaturalGas']['DistrictCooling']['air']['nonres_lg'] = ['VAV Reheat', 'NaturalGas', 'NaturalGas', 'DistrictCooling']
5028
-
5029
- # Electric, District Chilled Water, forced air
5030
- systems['Electricity']['DistrictCooling']['air']['res_small'] = ['PSZ-AC', 'Electricity', nil, 'DistrictCooling']
5031
- systems['Electricity']['DistrictCooling']['air']['res_med'] = ['PSZ-AC', 'Electricity', nil, 'DistrictCooling']
5032
- systems['Electricity']['DistrictCooling']['air']['nonres_small'] = ['PSZ-AC', 'Electricity', nil, 'DistrictCooling']
5033
- systems['Electricity']['DistrictCooling']['air']['nonres_med'] = ['PVAV Reheat', 'Electricity', 'Electricity', 'DistrictCooling']
5034
- systems['Electricity']['DistrictCooling']['air']['nonres_lg'] = ['VAV Reheat', 'Electricity', 'Electricity', 'DistrictCooling']
5035
-
5036
- # District Hot Water, District Chilled Water, forced air
5037
- systems['DistrictHeating']['DistrictCooling']['air']['res_small'] = ['PSZ-AC', 'DistrictHeating', nil, 'DistrictCooling']
5038
- systems['DistrictHeating']['DistrictCooling']['air']['res_med'] = ['PSZ-AC', 'DistrictHeating', nil, 'DistrictCooling']
5039
- systems['DistrictHeating']['DistrictCooling']['air']['nonres_small'] = ['PVAV Reheat', 'DistrictHeating', 'DistrictHeating', 'DistrictCooling']
5040
- systems['DistrictHeating']['DistrictCooling']['air']['nonres_med'] = ['PVAV Reheat', 'DistrictHeating', 'DistrictHeating', 'DistrictCooling']
5041
- systems['DistrictHeating']['DistrictCooling']['air']['nonres_lg'] = ['VAV Reheat', 'DistrictHeating', 'DistrictHeating', 'DistrictCooling']
5042
-
5043
- ## Hydronic ##
5044
-
5045
- # Gas, Electric, hydronic
5046
- systems['NaturalGas']['Electricity']['hydronic']['res_med'] = ['Fan Coil with DOAS', 'NaturalGas', nil, 'Electricity']
5047
- systems['NaturalGas']['Electricity']['hydronic']['nonres_small'] = ['Water Source Heat Pumps with DOAS', 'NaturalGas', nil, 'Electricity']
5048
- systems['NaturalGas']['Electricity']['hydronic']['nonres_med'] = ['Fan Coil with DOAS', 'NaturalGas', 'NaturalGas', 'Electricity']
5049
- systems['NaturalGas']['Electricity']['hydronic']['nonres_lg'] = ['Fan Coil with DOAS', 'NaturalGas', 'NaturalGas', 'Electricity']
5050
-
5051
- # Electric, Electric, hydronic
5052
- systems['Electricity']['Electricity']['hydronic']['res_small'] = ['Ground Source Heat Pumps with ERVs', 'Electricity', nil, 'Electricity']
5053
- systems['Electricity']['Electricity']['hydronic']['res_med'] = ['Ground Source Heat Pumps with DOAS', 'Electricity', nil, 'Electricity']
5054
- systems['Electricity']['Electricity']['hydronic']['nonres_small'] = ['Ground Source Heat Pumps with DOAS', 'Electricity', nil, 'Electricity']
5055
- systems['Electricity']['Electricity']['hydronic']['nonres_med'] = ['Ground Source Heat Pumps with DOAS', 'Electricity', 'Electricity', 'Electricity']
5056
- systems['Electricity']['Electricity']['hydronic']['nonres_lg'] = ['Ground Source Heat Pumps with DOAS', 'Electricity', 'Electricity', 'Electricity']
5057
-
5058
- # District Hot Water, Electric, hydronic
5059
- systems['DistrictHeating']['Electricity']['hydronic']['res_small'] = [] # TODO decide if there is anything reasonable for this
5060
- systems['DistrictHeating']['Electricity']['hydronic']['res_med'] = ['Fan Coil with DOAS', 'DistrictHeating', nil, 'Electricity']
5061
- systems['DistrictHeating']['Electricity']['hydronic']['nonres_small'] = ['Water Source Heat Pumps with DOAS', 'DistrictHeating', 'DistrictHeating', 'Electricity']
5062
- systems['DistrictHeating']['Electricity']['hydronic']['nonres_med'] = ['Fan Coil with DOAS', 'DistrictHeating', 'DistrictHeating', 'Electricity']
5063
- systems['DistrictHeating']['Electricity']['hydronic']['nonres_lg'] = ['Fan Coil with DOAS', 'DistrictHeating', 'DistrictHeating', 'Electricity']
5064
-
5065
- # Ambient Loop, Ambient Loop, hydronic
5066
- systems['DistrictAmbient']['DistrictAmbient']['hydronic']['res_small'] = ['Water Source Heat Pumps with ERVs', 'HeatPump', nil, 'HeatPump']
5067
- systems['DistrictAmbient']['DistrictAmbient']['hydronic']['res_med'] = ['Water Source Heat Pumps with DOAS', 'HeatPump', nil, 'HeatPump']
5068
- systems['DistrictAmbient']['DistrictAmbient']['hydronic']['nonres_small'] = ['Water Source Heat Pumps with DOAS', 'HeatPump', 'HeatPump', 'HeatPump']
5069
- systems['DistrictAmbient']['DistrictAmbient']['hydronic']['nonres_med'] = ['Water Source Heat Pumps with DOAS', 'HeatPump', 'HeatPump', 'HeatPump']
5070
- systems['DistrictAmbient']['DistrictAmbient']['hydronic']['nonres_lg'] = ['Fan Coil with DOAS', 'DistrictHeating', nil, 'Electricity'] # TODO: is this reasonable?
5071
-
5072
- # Gas, District Chilled Water, hydronic
5073
- systems['NaturalGas']['DistrictCooling']['hydronic']['res_med'] = ['Fan Coil with DOAS', 'NaturalGas', nil, 'DistrictCooling']
5074
- systems['NaturalGas']['DistrictCooling']['hydronic']['nonres_small'] = ['Fan Coil with DOAS', 'NaturalGas', nil, 'DistrictCooling']
5075
- systems['NaturalGas']['DistrictCooling']['hydronic']['nonres_med'] = ['Fan Coil with DOAS', 'NaturalGas', 'NaturalGas', 'DistrictCooling']
5076
- systems['NaturalGas']['DistrictCooling']['hydronic']['nonres_lg'] = ['Fan Coil with DOAS', 'NaturalGas', 'NaturalGas', 'DistrictCooling']
5077
-
5078
- # Electric, District Chilled Water, hydronic
5079
- systems['Electricity']['DistrictCooling']['hydronic']['res_med'] = ['Fan Coil with ERVs', 'Electricity', nil, 'DistrictCooling']
5080
- systems['Electricity']['DistrictCooling']['hydronic']['nonres_small'] = ['Fan Coil with DOAS', 'Electricity', nil, 'DistrictCooling']
5081
- systems['Electricity']['DistrictCooling']['hydronic']['nonres_med'] = ['Fan Coil with DOAS', 'Electricity', 'Electricity', 'DistrictCooling']
5082
- systems['Electricity']['DistrictCooling']['hydronic']['nonres_lg'] = ['Fan Coil with DOAS', 'Electricity', 'Electricity', 'DistrictCooling']
5083
-
5084
- # District Hot Water, District Chilled Water, hydronic
5085
- systems['DistrictHeating']['DistrictCooling']['hydronic']['res_small'] = ['Fan Coil with ERVs', 'DistrictHeating', nil, 'DistrictCooling']
5086
- systems['DistrictHeating']['DistrictCooling']['hydronic']['res_med'] = ['Fan Coil with DOAS', 'DistrictHeating', nil, 'DistrictCooling']
5087
- systems['DistrictHeating']['DistrictCooling']['hydronic']['nonres_small'] = ['Fan Coil with DOAS', 'DistrictHeating', 'DistrictHeating', 'DistrictCooling']
5088
- systems['DistrictHeating']['DistrictCooling']['hydronic']['nonres_med'] = ['Fan Coil with DOAS', 'DistrictHeating', 'DistrictHeating', 'DistrictCooling']
5089
- systems['DistrictHeating']['DistrictCooling']['hydronic']['nonres_lg'] = ['Fan Coil with DOAS', 'DistrictHeating', 'DistrictHeating', 'DistrictCooling']
5090
-
5091
- # Get the system type
5092
- system_type = systems[heating_source][cooling_source][delivery_type][size_category]
5093
-
5094
- if system_type.nil? || system_type.empty?
5095
- system_type = [nil, nil, nil, nil]
5096
- OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Model', "Could not determine system type for #{template}, #{area_type}, #{heating_source} heating, #{cooling_source} cooling, #{delivery_type} delivery, #{area_ft2.round} ft^2, #{num_stories} stories.")
5097
- else
5098
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "System type is #{system_type[0]} for #{template}, #{area_type}, #{heating_source} heating, #{cooling_source} cooling, #{delivery_type} delivery, #{area_ft2.round} ft^2, #{num_stories} stories.")
5099
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "--- #{system_type[1]} for main heating") unless system_type[1].nil?
5100
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "--- #{system_type[2]} for zone heat/reheat") unless system_type[2].nil?
5101
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "--- #{system_type[3]} for cooling") unless system_type[3].nil?
5102
- end
5103
-
5104
- return system_type
5105
- end
5106
5119
  end