openstudio-standards 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
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