openstudio-standards 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/data/standards/OpenStudio_Standards.xlsx +0 -0
  3. data/data/standards/OpenStudio_Standards_boilers.json +62 -4
  4. data/data/standards/OpenStudio_Standards_chillers.json +778 -68
  5. data/data/standards/OpenStudio_Standards_construction_sets.json +52 -93
  6. data/data/standards/OpenStudio_Standards_curve_biquadratics.json +36 -36
  7. data/data/standards/OpenStudio_Standards_curve_quadratics.json +3 -3
  8. data/data/standards/OpenStudio_Standards_heat_pumps.json +840 -0
  9. data/data/standards/OpenStudio_Standards_heat_pumps_heating.json +352 -0
  10. data/data/standards/OpenStudio_Standards_heat_rejection.json +48 -0
  11. data/data/standards/OpenStudio_Standards_motors.json +270 -0
  12. data/data/standards/OpenStudio_Standards_space_types.json +10390 -2824
  13. data/data/standards/OpenStudio_Standards_unitary_acs.json +794 -18
  14. data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.ddy +538 -0
  15. data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.epw +8768 -0
  16. data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.stat +493 -0
  17. data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.ddy +536 -0
  18. data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.epw +8768 -0
  19. data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.stat +554 -0
  20. data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.ddy +536 -0
  21. data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.epw +8768 -0
  22. data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.stat +554 -0
  23. data/data/weather/envelope_info.csv +6 -0
  24. data/lib/openstudio-standards.rb +10 -11
  25. data/lib/openstudio-standards/btap/compliance.rb +251 -969
  26. data/lib/openstudio-standards/btap/envelope.rb +1 -1
  27. data/lib/openstudio-standards/btap/fileio.rb +37 -5
  28. data/lib/openstudio-standards/btap/geometry.rb +27 -17
  29. data/lib/openstudio-standards/btap/hvac.rb +80 -27
  30. data/lib/openstudio-standards/hvac_sizing/{HVACSizing.CoilHeatingDXMultiSpeed.rb → Siz.CoilHeatingDXMultiSpeed.rb} +0 -0
  31. data/lib/openstudio-standards/hvac_sizing/Siz.ControllerOutdoorAir.rb +30 -4
  32. data/lib/openstudio-standards/hvac_sizing/Siz.CoolingTowerTwoSpeed.rb +61 -5
  33. data/lib/openstudio-standards/hvac_sizing/Siz.CoolingTowerVariableSpeed.rb +37 -7
  34. data/lib/openstudio-standards/hvac_sizing/Siz.DistrictCooling.rb +27 -0
  35. data/lib/openstudio-standards/hvac_sizing/Siz.DistrictHeating.rb +27 -0
  36. data/lib/openstudio-standards/hvac_sizing/Siz.HeaderedPumpsConstantSpeed.rb +55 -0
  37. data/lib/openstudio-standards/hvac_sizing/Siz.HeaderedPumpsVariableSpeed.rb +55 -0
  38. data/lib/openstudio-standards/hvac_sizing/Siz.HeatingCoolingFuels.rb +51 -9
  39. data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +99 -17
  40. data/lib/openstudio-standards/hvac_sizing/Siz.PumpConstantSpeed.rb +1 -1
  41. data/lib/openstudio-standards/hvac_sizing/Siz.ThermalZone.rb +29 -6
  42. data/lib/openstudio-standards/hvac_sizing/Siz.WaterHeaterMixed.rb +16 -0
  43. data/lib/openstudio-standards/prototypes/Prototype.AirTerminalSingleDuctVAVReheat.rb +43 -48
  44. data/lib/openstudio-standards/prototypes/Prototype.ControllerWaterCoil.rb +5 -9
  45. data/lib/openstudio-standards/prototypes/Prototype.Fan.rb +68 -0
  46. data/lib/openstudio-standards/prototypes/Prototype.FanConstantVolume.rb +39 -43
  47. data/lib/openstudio-standards/prototypes/Prototype.FanOnOff.rb +49 -51
  48. data/lib/openstudio-standards/prototypes/Prototype.FanVariableVolume.rb +55 -61
  49. data/lib/openstudio-standards/prototypes/Prototype.FanZoneExhaust.rb +8 -10
  50. data/lib/openstudio-standards/prototypes/Prototype.HeatExchangerAirToAirSensibleAndLatent.rb +15 -20
  51. data/lib/openstudio-standards/prototypes/Prototype.Model.hvac.rb +330 -322
  52. data/lib/openstudio-standards/prototypes/Prototype.Model.rb +501 -446
  53. data/lib/openstudio-standards/prototypes/Prototype.Model.swh.rb +221 -230
  54. data/lib/openstudio-standards/prototypes/Prototype.add_objects.rb +0 -2
  55. data/lib/openstudio-standards/prototypes/Prototype.full_service_restaurant.rb +130 -137
  56. data/lib/openstudio-standards/prototypes/Prototype.high_rise_apartment.rb +374 -291
  57. data/lib/openstudio-standards/prototypes/Prototype.hospital.rb +146 -193
  58. data/lib/openstudio-standards/prototypes/Prototype.hvac_systems.rb +1315 -1113
  59. data/lib/openstudio-standards/prototypes/Prototype.large_hotel.rb +65 -88
  60. data/lib/openstudio-standards/prototypes/Prototype.large_office.rb +101 -156
  61. data/lib/openstudio-standards/prototypes/Prototype.medium_office.rb +46 -96
  62. data/lib/openstudio-standards/prototypes/Prototype.mid_rise_apartment.rb +113 -123
  63. data/lib/openstudio-standards/prototypes/Prototype.outpatient.rb +356 -345
  64. data/lib/openstudio-standards/prototypes/Prototype.primary_school.rb +48 -103
  65. data/lib/openstudio-standards/prototypes/Prototype.quick_service_restaurant.rb +115 -123
  66. data/lib/openstudio-standards/prototypes/Prototype.retail_standalone.rb +30 -39
  67. data/lib/openstudio-standards/prototypes/Prototype.retail_stripmall.rb +32 -45
  68. data/lib/openstudio-standards/prototypes/Prototype.secondary_school.rb +98 -258
  69. data/lib/openstudio-standards/prototypes/Prototype.small_hotel.rb +429 -474
  70. data/lib/openstudio-standards/prototypes/Prototype.small_office.rb +28 -36
  71. data/lib/openstudio-standards/prototypes/Prototype.strip_model.rb +7 -7
  72. data/lib/openstudio-standards/prototypes/Prototype.utilities.rb +172 -146
  73. data/lib/openstudio-standards/prototypes/Prototype.warehouse.rb +46 -53
  74. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +885 -707
  75. data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctParallelPIUReheat.rb +48 -57
  76. data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctVAVReheat.rb +24 -31
  77. data/lib/openstudio-standards/standards/Standards.BoilerHotWater.rb +80 -93
  78. data/lib/openstudio-standards/standards/Standards.BuildingStory.rb +69 -0
  79. data/lib/openstudio-standards/standards/Standards.ChillerElectricEIR.rb +60 -72
  80. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXMultiSpeed.rb +104 -108
  81. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +190 -198
  82. data/lib/openstudio-standards/standards/Standards.CoilCoolingDXTwoSpeed.rb +134 -146
  83. data/lib/openstudio-standards/standards/Standards.CoilHeatingDXMultiSpeed.rb +56 -60
  84. data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +151 -161
  85. data/lib/openstudio-standards/standards/Standards.CoilHeatingGasMultiStage.rb +30 -34
  86. data/lib/openstudio-standards/standards/Standards.Construction.rb +116 -132
  87. data/lib/openstudio-standards/standards/Standards.CoolingTower.rb +138 -0
  88. data/lib/openstudio-standards/standards/Standards.CoolingTowerSingleSpeed.rb +11 -0
  89. data/lib/openstudio-standards/standards/Standards.CoolingTowerTwoSpeed.rb +11 -0
  90. data/lib/openstudio-standards/standards/Standards.CoolingTowerVariableSpeed.rb +16 -0
  91. data/lib/openstudio-standards/standards/Standards.Fan.rb +190 -236
  92. data/lib/openstudio-standards/standards/Standards.FanConstantVolume.rb +0 -2
  93. data/lib/openstudio-standards/standards/Standards.FanOnOff.rb +0 -2
  94. data/lib/openstudio-standards/standards/Standards.FanVariableVolume.rb +168 -14
  95. data/lib/openstudio-standards/standards/Standards.FanZoneExhaust.rb +0 -2
  96. data/lib/openstudio-standards/standards/Standards.HeaderedPumpsConstantSpeed.rb +33 -0
  97. data/lib/openstudio-standards/standards/Standards.HeaderedPumpsVariableSpeed.rb +83 -0
  98. data/lib/openstudio-standards/standards/Standards.HeatExchangerSensLat.rb +22 -0
  99. data/lib/openstudio-standards/standards/Standards.Model.rb +2385 -1622
  100. data/lib/openstudio-standards/standards/Standards.PlanarSurface.rb +83 -35
  101. data/lib/openstudio-standards/standards/Standards.PlantLoop.rb +805 -395
  102. data/lib/openstudio-standards/standards/Standards.Pump.rb +139 -119
  103. data/lib/openstudio-standards/standards/Standards.PumpConstantSpeed.rb +0 -2
  104. data/lib/openstudio-standards/standards/Standards.PumpVariableSpeed.rb +16 -15
  105. data/lib/openstudio-standards/standards/Standards.ScheduleCompact.rb +35 -0
  106. data/lib/openstudio-standards/standards/Standards.ScheduleConstant.rb +7 -13
  107. data/lib/openstudio-standards/standards/Standards.ScheduleRuleset.rb +144 -59
  108. data/lib/openstudio-standards/standards/Standards.Space.rb +1509 -1326
  109. data/lib/openstudio-standards/standards/Standards.SpaceType.rb +254 -262
  110. data/lib/openstudio-standards/standards/Standards.SubSurface.rb +105 -105
  111. data/lib/openstudio-standards/standards/Standards.Surface.rb +27 -31
  112. data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +882 -157
  113. data/lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb +179 -69
  114. data/lib/openstudio-standards/standards/Standards.ZoneHVACComponent.rb +75 -0
  115. data/lib/openstudio-standards/utilities/logging.rb +31 -38
  116. data/lib/openstudio-standards/utilities/simulation.rb +118 -82
  117. data/lib/openstudio-standards/version.rb +1 -1
  118. data/lib/openstudio-standards/weather/Weather.Model.rb +382 -390
  119. data/lib/openstudio-standards/weather/Weather.stat_file.rb +159 -78
  120. metadata +59 -6
@@ -0,0 +1,138 @@
1
+
2
+ # A variety of cooling tower methods that are the same regardless of type.
3
+ # These methods are available to CoolingTowerSingleSpeed, CoolingTowerTwoSpeed, and CoolingTowerVariableSpeed
4
+ module CoolingTower
5
+ # Set the cooling tower fan power such that the tower
6
+ # hits the minimum performance (gpm/hp) specified by the standard.
7
+ # Note that in this case hp is motor nameplate hp, per 90.1.
8
+ # This method assumes that the fan brake horsepower is 90%
9
+ # of the motor nameplate hp.
10
+ # This method determines the minimum motor efficiency
11
+ # for the nameplate motor hp and sets the actual
12
+ # fan power by multiplying the brake horsepower
13
+ # by the efficiency. Thus the fan power used as
14
+ # an input to the simulation divided by the design flow
15
+ # rate will not (and should not)
16
+ # exactly equal the minimum tower performance.
17
+ #
18
+ # @param template [String] the template base requirements on
19
+ # @return [Bool] true if successful, false if not
20
+ def apply_minimum_power_per_flow(template)
21
+ # Get the design water flow rate
22
+ design_water_flow_m3_per_s = nil
23
+ if designWaterFlowRate.is_initialized
24
+ design_water_flow_m3_per_s = designWaterFlowRate.get
25
+ elsif autosizedDesignWaterFlowRate.is_initialized
26
+ design_water_flow_m3_per_s = autosizedDesignWaterFlowRate.get
27
+ else
28
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoolingTower', "For #{name} design water flow rate is not available, cannot apply efficiency standard.")
29
+ return false
30
+ end
31
+ design_water_flow_gpm = OpenStudio.convert(design_water_flow_m3_per_s, 'm^3/s', 'gal/min').get
32
+
33
+ # Get the table of cooling tower efficiencies
34
+ heat_rejection = $os_standards['heat_rejection']
35
+
36
+ # Define the criteria to find the cooling tower properties
37
+ # in the hvac standards data set.
38
+ search_criteria = {}
39
+ search_criteria['template'] = template
40
+
41
+ # By definition cooling towers in E+ are open.
42
+ # Closed cooling towers are the fluidcooler objects.
43
+ search_criteria['equipment_type'] = 'Open Cooling Tower'
44
+
45
+ # TODO: Standards replace this with a mechanism to store this
46
+ # data in the cooling tower object itself.
47
+ # For now, retrieve the fan type from the name
48
+ name = self.name.get
49
+ fan_type = nil
50
+ if name.include?('Centrifugal')
51
+ fan_type = 'Centrifugal'
52
+ elsif name.include?('Propeller or Axial')
53
+ fan_type = 'Propeller or Axial'
54
+ end
55
+ unless fan_type.nil?
56
+ search_criteria['fan_type'] = fan_type
57
+ end
58
+
59
+ # 90.1 6.5.5.3 Limit on Centrifugal Fan
60
+ # Open Circuit Cooling Towers.
61
+ case template
62
+ when '90.1-2010', '90.1-2013'
63
+ if fan_type == 'Centrifugal'
64
+ gpm_limit = 1100
65
+ if design_water_flow_gpm >= gpm_limit
66
+ fan_type = 'Propeller or Axial'
67
+ search_criteria['fan_type'] = fan_type
68
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoolingTower', "For #{self.name}, the design flow rate of #{design_water_flow_gpm.round} gpm is higher than the limit of #{gpm_limit.round} gpm for open centrifugal towers per 6.5.5.3. This tower must meet the minimum performance of #{fan_type} instead.")
69
+ end
70
+ end
71
+ end
72
+
73
+ # Get the cooling tower properties
74
+ ct_props = model.find_object(heat_rejection, search_criteria)
75
+ unless ct_props
76
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoolingTower', "For #{self.name}, cannot find heat rejection properties, cannot apply standard efficiencies or curves.")
77
+ return false
78
+ end
79
+
80
+ # Get cooling tower efficiency
81
+ min_gpm_per_hp = ct_props['minimum_performance']
82
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoolingTower', "For #{self.name}, design water flow = #{design_water_flow_gpm.round} gpm, minimum performance = #{min_gpm_per_hp} gpm/hp (nameplate).")
83
+
84
+ # Calculate the allowed fan brake horsepower
85
+ # per method used in PNNL prototype buildings.
86
+ # Assumes that the fan brake horsepower is 90%
87
+ # of the fan nameplate rated motor power.
88
+ fan_motor_nameplate_hp = design_water_flow_gpm / min_gpm_per_hp
89
+ fan_bhp = 0.9 * fan_motor_nameplate_hp
90
+
91
+ # Lookup the minimum motor efficiency
92
+ fan_motor_eff = 0.85
93
+ motors = $os_standards['motors']
94
+
95
+ # Assuming all fan motors are 4-pole Enclosed
96
+ search_criteria = {
97
+ 'template' => template,
98
+ 'number_of_poles' => 4.0,
99
+ 'type' => 'Enclosed'
100
+ }
101
+
102
+ motor_properties = model.find_object(motors, search_criteria, fan_motor_nameplate_hp)
103
+ if motor_properties.nil?
104
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.CoolingTower', "For #{self.name}, could not find motor properties using search criteria: #{search_criteria}, motor_hp = #{motor_hp} hp.")
105
+ return false
106
+ end
107
+
108
+ fan_motor_eff = motor_properties['nominal_full_load_efficiency']
109
+ nominal_hp = motor_properties['maximum_capacity'].to_f.round(1)
110
+ # Round to nearest whole HP for niceness
111
+ if nominal_hp >= 2
112
+ nominal_hp = nominal_hp.round
113
+ end
114
+
115
+ # Calculate the fan motor power
116
+ fan_motor_actual_power_hp = fan_bhp / fan_motor_eff
117
+ # Convert to W
118
+ fan_motor_actual_power_w = fan_motor_actual_power_hp * 745.7 # 745.7 W/HP
119
+
120
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoolingTower', "For #{self.name}, allowed fan motor nameplate hp = #{fan_motor_nameplate_hp.round(1)} hp, fan brake horsepower = #{fan_bhp.round(1)}, and fan motor actual power = #{fan_motor_actual_power_hp.round(1)} hp (#{fan_motor_actual_power_w.round} W) at #{fan_motor_eff} motor efficiency.")
121
+
122
+ # Append the efficiency to the name
123
+ setName("#{self.name} #{min_gpm_per_hp.round(1)} gpm/hp")
124
+
125
+ # Hard size the design fan power.
126
+ # Leave the water flow and air flow autosized.
127
+ if to_CoolingTowerSingleSpeed.is_initialized
128
+ setFanPoweratDesignAirFlowRate(fan_motor_actual_power_w)
129
+ elsif to_CoolingTowerTwoSpeed.is_initialized
130
+ setHighFanSpeedFanPower(fan_motor_actual_power_w)
131
+ setLowFanSpeedFanPower(0.3 * fan_motor_actual_power_w)
132
+ elsif to_CoolingTowerVariableSpeed.is_initialized
133
+ setDesignFanPower(fan_motor_actual_power_w)
134
+ end
135
+
136
+ return true
137
+ end
138
+ end
@@ -0,0 +1,11 @@
1
+
2
+ # Reopen the OpenStudio class to add methods to apply standards to this object
3
+ class OpenStudio::Model::CoolingTowerSingleSpeed
4
+ include CoolingTower
5
+
6
+ def apply_efficiency_and_curves(template)
7
+ apply_minimum_power_per_flow(template)
8
+
9
+ return true
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+
2
+ # Reopen the OpenStudio class to add methods to apply standards to this object
3
+ class OpenStudio::Model::CoolingTowerTwoSpeed
4
+ include CoolingTower
5
+
6
+ def apply_efficiency_and_curves(template)
7
+ apply_minimum_power_per_flow(template)
8
+
9
+ return true
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+
2
+ # Reopen the OpenStudio class to add methods to apply standards to this object
3
+ class OpenStudio::Model::CoolingTowerVariableSpeed
4
+ include CoolingTower
5
+
6
+ def apply_efficiency_and_curves(template)
7
+ apply_minimum_power_per_flow(template)
8
+
9
+ # 90.1-2013 6.5.2.2 Multicell heat rejection with VSD
10
+ if template == '90.1-2013'
11
+ setCellControl('MaximalCell')
12
+ end
13
+
14
+ return true
15
+ end
16
+ end
@@ -2,260 +2,185 @@
2
2
  # A variety of fan calculation methods that are the same regardless of fan type.
3
3
  # These methods are available to FanConstantVolume, FanOnOff, FanVariableVolume, and FanZoneExhaust
4
4
  module Fan
5
+ def apply_standard_minimum_motor_efficiency(template, allowed_bhp)
6
+ # Find the motor efficiency
7
+ motor_eff, nominal_hp = standard_minimum_motor_efficiency_and_size(template, allowed_bhp)
5
8
 
6
- # Sets the fan motor efficiency based on the standard.
7
- # Assumes 65% fan efficiency and 4-pole, enclosed motor.
8
- #
9
- # @return [Bool] true if successful, false if not
10
- def setStandardEfficiency(template)
11
-
12
- # Get the max flow rate from the fan.
13
- maximum_flow_rate_m3_per_s = nil
14
- if self.maximumFlowRate.is_initialized
15
- maximum_flow_rate_m3_per_s = self.maximumFlowRate.get
16
- elsif self.autosizedMaximumFlowRate.is_initialized
17
- maximum_flow_rate_m3_per_s = self.autosizedMaximumFlowRate.get
18
- else
19
- OpenStudio::logFree(OpenStudio::Warn, 'openstudio.standards.Fan', "For #{self.name} max flow rate is not hard sized, cannot apply efficiency standard.")
20
- return false
21
- end
9
+ # Change the motor efficiency
10
+ # but preserve the existing fan impeller
11
+ # efficiency.
12
+ change_motor_efficiency(motor_eff)
22
13
 
23
- # Convert max flow rate to cfm
24
- maximum_flow_rate_cfm = OpenStudio.convert(maximum_flow_rate_m3_per_s, 'm^3/s', 'cfm').get
25
-
26
- # Get the pressure rise from the fan
27
- pressure_rise_pa = self.pressureRise
28
- pressure_rise_in_h2o = OpenStudio.convert(pressure_rise_pa, 'Pa','inH_{2}O').get
29
-
30
- # Get the default impeller efficiency
31
- fan_impeller_eff = self.baselineImpellerEfficiency(template)
32
-
33
- # Calculate the Brake Horsepower
34
- brake_hp = (pressure_rise_in_h2o * maximum_flow_rate_cfm)/(fan_impeller_eff * 6356)
35
- allowed_hp = brake_hp * 1.1 # Per PNNL document #TODO add reference
36
- if allowed_hp > 0.1
37
- allowed_hp = allowed_hp.round(2)+0.0001
38
- elsif allowed_hp < 0.01
39
- allowed_hp = 0.01
40
- end
14
+ # Calculate the total motor HP
15
+ motor_hp = motor_horsepower
41
16
 
42
- # Minimum motor size for efficiency lookup
43
- # is 1 HP unless the motor serves an exhaust fan,
44
- # a powered VAV terminal, or a fan coil unit.
45
- unless self.is_small_fan
46
- if allowed_hp < 1.0
47
- allowed_hp = 1.01
48
- end
49
- end
50
-
51
- # Find the motor efficiency
52
- motor_eff, nominal_hp = standard_minimum_motor_efficiency_and_size(template, allowed_hp)
53
-
54
- # Calculate the total fan efficiency
55
- total_fan_eff = fan_impeller_eff * motor_eff
56
-
57
- # Set the total fan efficiency and the motor efficiency
58
- if self.to_FanZoneExhaust.is_initialized
59
- self.setFanEfficiency(total_fan_eff)
17
+ # Exception for small fans, including
18
+ # zone exhaust, fan coil, and fan powered terminals.
19
+ # In this case, 0.5 HP is used for the lookup.
20
+ if small_fan?
21
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Fan', "For #{name}: motor eff = #{(motor_eff * 100).round(2)}%; assumed to represent several < 1 HP motors.")
60
22
  else
61
- self.setFanEfficiency(total_fan_eff)
62
- self.setMotorEfficiency(motor_eff)
23
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Fan', "For #{name}: motor nameplate = #{nominal_hp}HP, motor eff = #{(motor_eff * 100).round(2)}%.")
63
24
  end
64
-
65
25
 
66
- if(template == 'NECB 2011')
67
- fan_power_kw = maximum_flow_rate_m3_per_s*pressure_rise_pa/(fan_impeller_eff*1000.0)
68
- end
69
-
70
- OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.Fan', "For #{self.name}: allowed_hp = #{allowed_hp.round(2)}HP; motor eff = #{(motor_eff*100).round(2)}%; total fan eff = #{(total_fan_eff*100).round}% based on #{maximum_flow_rate_cfm.round} cfm.")
71
-
72
26
  return true
73
-
74
27
  end
75
28
 
76
- def set_standard_minimum_motor_efficiency(template, allowed_bhp)
77
-
78
- # Find the motor efficiency
79
- motor_eff, nominal_hp = standard_minimum_motor_efficiency_and_size(template, allowed_bhp)
80
-
81
- # Change the motor efficiency
82
- # but preserve the existing fan impeller
83
- # efficiency.
84
- self.changeMotorEfficiency(motor_eff)
85
-
86
- # Calculate the total motor HP
87
- motor_hp = self.motorHorsepower
88
-
89
- OpenStudio::logFree(OpenStudio::Info, 'openstudio.standards.Fan', "For #{self.name}: motor nameplate = #{nominal_hp}HP, motor eff = #{(motor_eff*100).round(2)}%.")
90
-
91
- return true
92
-
93
- end
94
-
95
29
  # Adjust the fan pressure rise to hit the target fan power (W).
96
30
  # Keep the fan impeller and motor efficiencies static.
97
31
  #
98
32
  # @param target_fan_power [Double] the target fan power in W
99
33
  # @return [Bool] true if successful, false if not
100
34
  def adjust_pressure_rise_to_meet_fan_power(target_fan_power)
101
-
102
35
  # Get design supply air flow rate (whether autosized or hard-sized)
103
36
  dsn_air_flow_m3_per_s = 0
104
- if self.autosizedMaximumFlowRate.is_initialized
105
- dsn_air_flow_m3_per_s = self.autosizedMaximumFlowRate.get
106
- else
107
- dsn_air_flow_m3_per_s = self.maximumFlowRate.get
108
- end
109
-
37
+ dsn_air_flow_m3_per_s = if autosizedMaximumFlowRate.is_initialized
38
+ autosizedMaximumFlowRate.get
39
+ else
40
+ maximumFlowRate.get
41
+ end
42
+
110
43
  # Get the current fan power
111
- current_fan_power_w = self.fanPower
44
+ current_fan_power_w = fan_power
112
45
 
113
46
  # Get the current pressure rise (Pa)
114
- pressure_rise_pa = self.pressureRise
115
-
47
+ pressure_rise_pa = pressureRise
48
+
116
49
  # Get the total fan efficiency
117
- fan_total_eff = self.fanEfficiency
50
+ fan_total_eff = fanEfficiency
118
51
 
119
52
  # Calculate the new fan pressure rise (Pa)
120
53
  new_pressure_rise_pa = target_fan_power * fan_total_eff / dsn_air_flow_m3_per_s
121
- new_pressure_rise_in_h2o = OpenStudio.convert(new_pressure_rise_pa, 'Pa','inH_{2}O').get
122
-
54
+ new_pressure_rise_in_h2o = OpenStudio.convert(new_pressure_rise_pa, 'Pa', 'inH_{2}O').get
55
+
123
56
  # Set the new pressure rise
124
- self.setPressureRise(new_pressure_rise_pa)
125
-
57
+ setPressureRise(new_pressure_rise_pa)
58
+
126
59
  # Calculate the new power
127
- new_power_w = self.fanPower
128
-
129
- OpenStudio::logFree(OpenStudio::Info, "openstudio.standards.Fan", "For #{self.name}: pressure rise = #{new_pressure_rise_in_h2o.round(1)} in w.c., power = #{new_power_w.round} W // #{self.motorHorsepower.round(2)}HP.")
130
-
60
+ new_power_w = fan_power
61
+
62
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Fan', "For #{name}: pressure rise = #{new_pressure_rise_in_h2o.round(1)} in w.c., power = #{motor_horsepower.round(2)}HP.")
63
+
131
64
  return true
132
-
133
65
  end
134
-
135
- # Determines the fan power (W) based on
136
- # flow rate, pressure rise, and total fan efficiency(impeller eff * motor eff)
137
- #
66
+
67
+ # Determines the fan power (W) based on
68
+ # flow rate, pressure rise, and total fan efficiency(impeller eff * motor eff)
69
+ #
138
70
  # @return [Double] fan power
139
71
  # @units Watts (W)
140
- def fanPower()
141
-
72
+ def fan_power
142
73
  # Get design supply air flow rate (whether autosized or hard-sized)
143
74
  dsn_air_flow_m3_per_s = 0
144
- if self.autosizedMaximumFlowRate.is_initialized
145
- dsn_air_flow_m3_per_s = self.autosizedMaximumFlowRate.get
146
- else
147
- dsn_air_flow_m3_per_s = self.maximumFlowRate.get
148
- end
149
-
75
+ dsn_air_flow_m3_per_s = if to_FanZoneExhaust.empty?
76
+ if autosizedMaximumFlowRate.is_initialized
77
+ autosizedMaximumFlowRate.get
78
+ else
79
+ maximumFlowRate.get
80
+ end
81
+ else
82
+ maximumFlowRate.get
83
+ end
84
+
150
85
  # Get the total fan efficiency,
151
86
  # which in E+ includes both motor and
152
87
  # impeller efficiency.
153
- fan_total_eff = self.fanEfficiency
154
-
88
+ fan_total_eff = fanEfficiency
89
+
155
90
  # Get the pressure rise (Pa)
156
- pressure_rise_pa = self.pressureRise
157
-
91
+ pressure_rise_pa = pressureRise
92
+
158
93
  # Calculate the fan power (W)
159
94
  fan_power_w = pressure_rise_pa * dsn_air_flow_m3_per_s / fan_total_eff
160
-
95
+
161
96
  return fan_power_w
162
-
163
97
  end
164
98
 
165
99
  # Determines the brake horsepower of the fan
166
100
  # based on fan power and fan motor efficiency.
167
- #
101
+ #
168
102
  # @return [Double] brake horsepower
169
- # @units horsepower (hp)
170
- def brakeHorsepower()
171
-
103
+ # @units horsepower (hp)
104
+ def brake_horsepower
172
105
  # Get the fan motor efficiency
173
106
  existing_motor_eff = 0.7
174
- if self.to_FanZoneExhaust.empty?
175
- existing_motor_eff = self.motorEfficiency
107
+ if to_FanZoneExhaust.empty?
108
+ existing_motor_eff = motorEfficiency
176
109
  end
177
-
110
+
178
111
  # Get the fan power (W)
179
- fan_power_w = self.fanPower
180
-
112
+ fan_power_w = fan_power
113
+
181
114
  # Calculate the brake horsepower (bhp)
182
115
  fan_bhp = fan_power_w * existing_motor_eff / 746
183
-
184
- return fan_bhp
185
116
 
117
+ return fan_bhp
186
118
  end
187
119
 
188
120
  # Determines the horsepower of the fan
189
121
  # motor, including motor efficiency and
190
122
  # fan impeller efficiency.
191
- #
123
+ #
192
124
  # @return [Double] horsepower
193
- def motorHorsepower()
194
-
125
+ def motor_horsepower
195
126
  # Get the fan power
196
- fan_power_w = self.fanPower
197
-
127
+ fan_power_w = fan_power
128
+
198
129
  # Convert to HP
199
130
  fan_hp = fan_power_w / 745.7 # 745.7 W/HP
200
-
201
- return fan_hp
202
131
 
203
- end
132
+ return fan_hp
133
+ end
204
134
 
205
135
  # Changes the fan motor efficiency and also the fan total efficiency
206
136
  # at the same time, preserving the impeller efficiency.
207
137
  #
208
138
  # @param motor_eff [Double] motor efficiency (0.0 to 1.0)
209
- def changeMotorEfficiency(motor_eff)
210
-
139
+ def change_motor_efficiency(motor_eff)
211
140
  # Calculate the existing impeller efficiency
212
141
  existing_motor_eff = 0.7
213
- if self.to_FanZoneExhaust.empty?
214
- existing_motor_eff = self.motorEfficiency
142
+ if to_FanZoneExhaust.empty?
143
+ existing_motor_eff = motorEfficiency
215
144
  end
216
- existing_total_eff = self.fanEfficiency
145
+ existing_total_eff = fanEfficiency
217
146
  existing_impeller_eff = existing_total_eff / existing_motor_eff
218
-
147
+
219
148
  # Calculate the new total efficiency
220
149
  new_total_eff = motor_eff * existing_impeller_eff
221
-
150
+
222
151
  # Set the revised motor and total fan efficiencies
223
- if self.to_FanZoneExhaust.is_initialized
224
- self.setFanEfficiency(new_total_eff)
152
+ if to_FanZoneExhaust.is_initialized
153
+ setFanEfficiency(new_total_eff)
225
154
  else
226
- self.setFanEfficiency(new_total_eff)
227
- self.setMotorEfficiency(motor_eff)
155
+ setFanEfficiency(new_total_eff)
156
+ setMotorEfficiency(motor_eff)
228
157
  end
229
-
230
158
  end
231
159
 
232
160
  # Changes the fan impeller efficiency and also the fan total efficiency
233
161
  # at the same time, preserving the motor efficiency.
234
162
  #
235
- # @param impeller_eff [Double] impeller efficiency (0.0 to 1.0)
236
- def changeImpellerEfficiency(impeller_eff)
237
-
163
+ # @param impeller_eff [Double] impeller efficiency (0.0 to 1.0)
164
+ def change_impeller_efficiency(impeller_eff)
238
165
  # Get the existing motor efficiency
239
166
  existing_motor_eff = 0.7
240
- if self.to_FanZoneExhaust.empty?
241
- existing_motor_eff = self.motorEfficiency
167
+ if to_FanZoneExhaust.empty?
168
+ existing_motor_eff = motorEfficiency
242
169
  end
243
170
 
244
171
  # Calculate the new total efficiency
245
172
  new_total_eff = existing_motor_eff * impeller_eff
246
-
173
+
247
174
  # Set the revised motor and total fan efficiencies
248
- self.setFanEfficiency(new_total_eff)
249
-
175
+ setFanEfficiency(new_total_eff)
250
176
  end
251
-
177
+
252
178
  # Determines the baseline fan impeller efficiency
253
179
  # based on the specified fan type.
254
180
  #
255
181
  # @return [Double] impeller efficiency (0.0 to 1.0)
256
182
  # @todo Add fan type to data model and modify this method
257
- def baselineImpellerEfficiency(template)
258
-
183
+ def baseline_impeller_efficiency(template)
259
184
  # Assume that the fan efficiency is 65% for normal fans
260
185
  # and 55% for small fans (like exhaust fans).
261
186
  # TODO add fan type to fan data model
@@ -264,79 +189,108 @@ module Fan
264
189
  # fan impeller for the baseline system?
265
190
  # TODO check COMNET and T24 ACM and PNNL 90.1 doc
266
191
  fan_impeller_eff = 0.65
267
-
268
- if self.is_small_fan
192
+
193
+ if small_fan?
269
194
  fan_impeller_eff = 0.55
270
195
  end
271
196
 
272
197
  return fan_impeller_eff
273
-
274
198
  end
275
-
276
- # Determines the minimum fan motor efficiency
199
+
200
+ # Determines the minimum fan motor efficiency and nominal size
277
201
  # for a given motor bhp. This should be the total brake horsepower with
278
- # any desired safety factor already included. This method
202
+ # any desired safety factor already included. This method picks
203
+ # the next nominal motor catgory larger than the required brake
204
+ # horsepower, and the efficiency is based on that size. For example,
205
+ # if the bhp = 6.3, the nominal size will be 7.5HP and the efficiency
206
+ # for 90.1-2010 will be 91.7% from Table 10.8B. This method assumes
207
+ # 4-pole, 1800rpm totally-enclosed fan-cooled motors.
279
208
  #
280
209
  # @param motor_bhp [Double] motor brake horsepower (hp)
281
-
282
- # @return [Double] minimum motor efficiency (0.0 to 1.0), nominal HP
210
+ # @return [Array<Double>] minimum motor efficiency (0.0 to 1.0), nominal horsepower
283
211
  def standard_minimum_motor_efficiency_and_size(template, motor_bhp)
284
-
285
212
  fan_motor_eff = 0.85
286
213
  nominal_hp = motor_bhp
287
-
214
+
215
+ # Don't attempt to look up motor efficiency
216
+ # for zero-hp fans, which may occur when there is no
217
+ # airflow required for a particular system, typically
218
+ # heated-only spaces with high internal gains
219
+ # and no OA requirements such as elevator shafts.
220
+ return [fan_motor_eff, 0] if motor_bhp == 0.0
221
+
288
222
  # Lookup the minimum motor efficiency
289
- motors = $os_standards["motors"]
290
-
223
+ motors = $os_standards['motors']
224
+
291
225
  # Assuming all fan motors are 4-pole ODP
292
226
  template_mod = template.dup
293
- if(template == 'NECB 2011')
294
- if(self.class.name == 'OpenStudio::Model::FanConstantVolume')
295
- template_mod = template_mod+'-CONSTANT'
296
- elsif(self.class.name == 'OpenStudio::Model::FanVariableVolume')
297
- template_mod = template_mod+'-VARIABLE'
298
- fan_power_kw = 0.909*0.7457*motor_bhp
299
- if(fan_power_kw >= 25.0)
300
- power_vs_flow_curve_name = 'VarVolFan-FCInletVanes-NECB2011-FPLR'
301
- elsif(fan_power_kw >= 7.5 && fan_power_kw < 25)
302
- power_vs_flow_curve_name = 'VarVolFan-AFBIInletVanes-NECB2011-FPLR'
303
- else
304
- power_vs_flow_curve_name = 'VarVolFan-AFBIFanCurve-NECB2011-FPLR'
305
- end
306
- power_vs_flow_curve = self.model.add_curve(power_vs_flow_curve_name, standards)
307
- self.setFanPowerMinimumFlowRateInputMethod("Fraction")
308
- self.setFanPowerCoefficient5(0.0)
309
- self.setFanPowerMinimumFlowFraction(power_vs_flow_curve.minimumValueofx)
310
- self.setFanPowerCoefficient1(power_vs_flow_curve.coefficient1Constant)
311
- self.setFanPowerCoefficient2(power_vs_flow_curve.coefficient2x)
312
- self.setFanPowerCoefficient3(power_vs_flow_curve.coefficient3xPOW2)
313
- self.setFanPowerCoefficient4(power_vs_flow_curve.coefficient4xPOW3)
227
+ if template == 'NECB 2011'
228
+ if self.class.name == 'OpenStudio::Model::FanConstantVolume'
229
+ template_mod += '-CONSTANT'
230
+ elsif self.class.name == 'OpenStudio::Model::FanVariableVolume'
231
+ template_mod += '-VARIABLE'
232
+ # 0.909 corrects for 10% over sizing implemented upstream
233
+ # 0.7457 is to convert from bhp to kW
234
+ fan_power_kw = 0.909 * 0.7457 * motor_bhp
235
+ power_vs_flow_curve_name = if fan_power_kw >= 25.0
236
+ 'VarVolFan-FCInletVanes-NECB2011-FPLR'
237
+ elsif fan_power_kw >= 7.5 && fan_power_kw < 25
238
+ 'VarVolFan-AFBIInletVanes-NECB2011-FPLR'
239
+ else
240
+ 'VarVolFan-AFBIFanCurve-NECB2011-FPLR'
241
+ end
242
+ power_vs_flow_curve = model.add_curve(power_vs_flow_curve_name)
243
+ setFanPowerMinimumFlowRateInputMethod('Fraction')
244
+ setFanPowerCoefficient5(0.0)
245
+ setFanPowerMinimumFlowFraction(power_vs_flow_curve.minimumValueofx)
246
+ setFanPowerCoefficient1(power_vs_flow_curve.coefficient1Constant)
247
+ setFanPowerCoefficient2(power_vs_flow_curve.coefficient2x)
248
+ setFanPowerCoefficient3(power_vs_flow_curve.coefficient3xPOW2)
249
+ setFanPowerCoefficient4(power_vs_flow_curve.coefficient4xPOW3)
314
250
  end
315
251
  end
316
-
252
+
317
253
  search_criteria = {
318
- "template" => template_mod,
319
- "number_of_poles" => 4.0,
320
- "type" => "Enclosed",
254
+ 'template' => template_mod,
255
+ 'number_of_poles' => 4.0,
256
+ 'type' => 'Enclosed'
321
257
  }
322
-
323
- motor_properties = self.model.find_object(motors, search_criteria, motor_bhp)
258
+
259
+ # Exception for small fans, including
260
+ # zone exhaust, fan coil, and fan powered terminals.
261
+ # In this case, use the 0.5 HP for the lookup.
262
+ if small_fan?
263
+ nominal_hp = 0.5
264
+ else
265
+ motor_properties = model.find_object(motors, search_criteria, motor_bhp)
266
+ if motor_properties.nil?
267
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Fan', "For #{name}, could not find motor properties using search criteria: #{search_criteria}, motor_bhp = #{motor_bhp} hp.")
268
+ return [fan_motor_eff, nominal_hp]
269
+ end
270
+
271
+ nominal_hp = motor_properties['maximum_capacity'].to_f.round(1)
272
+ # If the biggest fan motor size is hit, use the highest category efficiency
273
+ if nominal_hp == 9999.0
274
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Fan', "For #{name}, there is no greater nominal HP. Use the efficiency of the largest motor category.")
275
+ nominal_hp = motor_bhp
276
+ end
277
+
278
+ # Round to nearest whole HP for niceness
279
+ if nominal_hp >= 2
280
+ nominal_hp = nominal_hp.round
281
+ end
282
+ end
283
+
284
+ # Get the efficiency based on the nominal horsepower
285
+ # Add 0.01 hp to avoid search errors.
286
+ motor_properties = model.find_object(motors, search_criteria, nominal_hp + 0.01)
324
287
  if motor_properties.nil?
325
- OpenStudio::logFree(OpenStudio::Error, "openstudio.standards.Fan", "For #{self.name}, could not find motor properties using search criteria: #{search_criteria}, motor_bhp = #{motor_bhp} hp.")
288
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Fan', "For #{name}, could not find nominal motor properties using search criteria: #{search_criteria}, motor_hp = #{nominal_hp} hp.")
326
289
  return [fan_motor_eff, nominal_hp]
327
290
  end
328
-
329
- fan_motor_eff = motor_properties["nominal_full_load_efficiency"]
330
- nominal_hp = motor_properties["maximum_capacity"].to_f.round(1)
331
- # Round to nearest whole HP for niceness
332
- if nominal_hp >= 2
333
- nominal_hp = nominal_hp.round
334
- end
335
-
336
- # TODO Add exception for small
291
+ fan_motor_eff = motor_properties['nominal_full_load_efficiency']
337
292
 
338
293
  return [fan_motor_eff, nominal_hp]
339
-
340
294
  end
341
295
 
342
296
  # Zone exhaust fans, fan coil unit fans,
@@ -344,29 +298,33 @@ module Fan
344
298
  # as small fans and get different impeller efficiencies
345
299
  # and motor efficiencies than other fans
346
300
  # @return [Bool] returns true if it is a small fan, false if not
347
- def is_small_fan()
348
-
301
+ def small_fan?
349
302
  is_small = false
350
303
 
351
304
  # Exhaust fan
352
- if self.to_FanZoneExhaust.is_initialized
305
+ if to_FanZoneExhaust.is_initialized
353
306
  is_small = true
354
- # Fan coil unit
355
- elsif self.containingZoneHVACComponent.is_initialized
356
- zone_hvac = self.containingZoneHVACComponent.get
307
+ # Fan coil unit, unit heater, PTAC, PTHP
308
+ elsif containingZoneHVACComponent.is_initialized
309
+ zone_hvac = containingZoneHVACComponent.get
357
310
  if zone_hvac.to_ZoneHVACFourPipeFanCoil.is_initialized
358
311
  is_small = true
312
+ elsif zone_hvac.to_ZoneHVACUnitHeater.is_initialized
313
+ is_small = true
314
+ elsif zone_hvac.to_ZoneHVACPackagedTerminalAirConditioner.is_initialized
315
+ is_small = true
316
+ elsif zone_hvac.to_ZoneHVACPackagedTerminalHeatPump.is_initialized
317
+ is_small = true
359
318
  end
360
319
  # Powered VAV terminal
361
- elsif self.containingHVACComponent.is_initialized
362
- zone_hvac = self.containingHVACComponent.get
320
+ elsif containingHVACComponent.is_initialized
321
+ zone_hvac = containingHVACComponent.get
363
322
  if zone_hvac.to_AirTerminalSingleDuctParallelPIUReheat.is_initialized || zone_hvac.to_AirTerminalSingleDuctSeriesPIUReheat.is_initialized
364
323
  is_small = true
365
324
  end
366
- end
367
-
325
+ end
326
+
368
327
  return is_small
369
-
370
328
  end
371
329
 
372
330
  # Find the actual rated fan power per flow (W/CFM)
@@ -374,33 +332,29 @@ module Fan
374
332
  #
375
333
  # @return [Double] rated power consumption per flow
376
334
  # @units Watts per CFM (W*min/ft^3)
377
- def rated_w_per_cfm()
378
-
335
+ def rated_w_per_cfm
379
336
  # Get design power (whether autosized or hard-sized)
380
- rated_power_w = self.model.getAutosizedValueFromEquipmentSummary(self, 'Fans', 'Rated Electric Power', 'W')
337
+ rated_power_w = model.getAutosizedValueFromEquipmentSummary(self, 'Fans', 'Rated Electric Power', 'W')
381
338
  if rated_power_w.is_initialized
382
339
  rated_power_w = rated_power_w.get
383
340
  else
384
- rated_power_w = self.fanPower
385
- OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.Pump", "For #{self.name}, could not find rated fan power from Equipment Summary. Will calculate it based on current pressure rise and total fan efficiency")
341
+ rated_power_w = fan_power
342
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Pump', "For #{name}, could not find rated fan power from Equipment Summary. Will calculate it based on current pressure rise and total fan efficiency")
386
343
  end
387
344
 
388
- if self.autosizedMaximumFlowRate.is_initialized
389
- max_m3_per_s = self.autosizedMaximumFlowRate.get
390
- elsif self.maximumFlowRate.is_initialized
391
- max_m3_per_s = self.ratedFlowRate.get
345
+ if autosizedMaximumFlowRate.is_initialized
346
+ max_m3_per_s = autosizedMaximumFlowRate.get
347
+ elsif maximumFlowRate.is_initialized
348
+ max_m3_per_s = ratedFlowRate.get
392
349
  else
393
- OpenStudio::logFree(OpenStudio::Error, "openstudio.standards.Pump", "For #{self.name}, could not find fan Maximum Flow Rate, cannot determine w per cfm correctly.")
350
+ OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Pump', "For #{name}, could not find fan Maximum Flow Rate, cannot determine w per cfm correctly.")
394
351
  return false
395
352
  end
396
353
 
397
354
  rated_w_per_m3s = rated_power_w / max_m3_per_s
398
355
 
399
- rated_w_per_gpm = OpenStudio::convert(rated_w_per_m3s, 'W*s/m^3', 'W*min/ft^3').get
356
+ rated_w_per_gpm = OpenStudio.convert(rated_w_per_m3s, 'W*s/m^3', 'W*min/ft^3').get
400
357
 
401
358
  return rated_w_per_gpm
402
-
403
-
404
359
  end
405
-
406
360
  end