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.
- checksums.yaml +4 -4
- data/data/standards/OpenStudio_Standards.xlsx +0 -0
- data/data/standards/OpenStudio_Standards_boilers.json +62 -4
- data/data/standards/OpenStudio_Standards_chillers.json +778 -68
- data/data/standards/OpenStudio_Standards_construction_sets.json +52 -93
- data/data/standards/OpenStudio_Standards_curve_biquadratics.json +36 -36
- data/data/standards/OpenStudio_Standards_curve_quadratics.json +3 -3
- data/data/standards/OpenStudio_Standards_heat_pumps.json +840 -0
- data/data/standards/OpenStudio_Standards_heat_pumps_heating.json +352 -0
- data/data/standards/OpenStudio_Standards_heat_rejection.json +48 -0
- data/data/standards/OpenStudio_Standards_motors.json +270 -0
- data/data/standards/OpenStudio_Standards_space_types.json +10390 -2824
- data/data/standards/OpenStudio_Standards_unitary_acs.json +794 -18
- data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.ddy +538 -0
- data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.epw +8768 -0
- data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.stat +493 -0
- data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.ddy +536 -0
- data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.epw +8768 -0
- data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.stat +554 -0
- data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.ddy +536 -0
- data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.epw +8768 -0
- data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.stat +554 -0
- data/data/weather/envelope_info.csv +6 -0
- data/lib/openstudio-standards.rb +10 -11
- data/lib/openstudio-standards/btap/compliance.rb +251 -969
- data/lib/openstudio-standards/btap/envelope.rb +1 -1
- data/lib/openstudio-standards/btap/fileio.rb +37 -5
- data/lib/openstudio-standards/btap/geometry.rb +27 -17
- data/lib/openstudio-standards/btap/hvac.rb +80 -27
- data/lib/openstudio-standards/hvac_sizing/{HVACSizing.CoilHeatingDXMultiSpeed.rb → Siz.CoilHeatingDXMultiSpeed.rb} +0 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.ControllerOutdoorAir.rb +30 -4
- data/lib/openstudio-standards/hvac_sizing/Siz.CoolingTowerTwoSpeed.rb +61 -5
- data/lib/openstudio-standards/hvac_sizing/Siz.CoolingTowerVariableSpeed.rb +37 -7
- data/lib/openstudio-standards/hvac_sizing/Siz.DistrictCooling.rb +27 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.DistrictHeating.rb +27 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.HeaderedPumpsConstantSpeed.rb +55 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.HeaderedPumpsVariableSpeed.rb +55 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.HeatingCoolingFuels.rb +51 -9
- data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +99 -17
- data/lib/openstudio-standards/hvac_sizing/Siz.PumpConstantSpeed.rb +1 -1
- data/lib/openstudio-standards/hvac_sizing/Siz.ThermalZone.rb +29 -6
- data/lib/openstudio-standards/hvac_sizing/Siz.WaterHeaterMixed.rb +16 -0
- data/lib/openstudio-standards/prototypes/Prototype.AirTerminalSingleDuctVAVReheat.rb +43 -48
- data/lib/openstudio-standards/prototypes/Prototype.ControllerWaterCoil.rb +5 -9
- data/lib/openstudio-standards/prototypes/Prototype.Fan.rb +68 -0
- data/lib/openstudio-standards/prototypes/Prototype.FanConstantVolume.rb +39 -43
- data/lib/openstudio-standards/prototypes/Prototype.FanOnOff.rb +49 -51
- data/lib/openstudio-standards/prototypes/Prototype.FanVariableVolume.rb +55 -61
- data/lib/openstudio-standards/prototypes/Prototype.FanZoneExhaust.rb +8 -10
- data/lib/openstudio-standards/prototypes/Prototype.HeatExchangerAirToAirSensibleAndLatent.rb +15 -20
- data/lib/openstudio-standards/prototypes/Prototype.Model.hvac.rb +330 -322
- data/lib/openstudio-standards/prototypes/Prototype.Model.rb +501 -446
- data/lib/openstudio-standards/prototypes/Prototype.Model.swh.rb +221 -230
- data/lib/openstudio-standards/prototypes/Prototype.add_objects.rb +0 -2
- data/lib/openstudio-standards/prototypes/Prototype.full_service_restaurant.rb +130 -137
- data/lib/openstudio-standards/prototypes/Prototype.high_rise_apartment.rb +374 -291
- data/lib/openstudio-standards/prototypes/Prototype.hospital.rb +146 -193
- data/lib/openstudio-standards/prototypes/Prototype.hvac_systems.rb +1315 -1113
- data/lib/openstudio-standards/prototypes/Prototype.large_hotel.rb +65 -88
- data/lib/openstudio-standards/prototypes/Prototype.large_office.rb +101 -156
- data/lib/openstudio-standards/prototypes/Prototype.medium_office.rb +46 -96
- data/lib/openstudio-standards/prototypes/Prototype.mid_rise_apartment.rb +113 -123
- data/lib/openstudio-standards/prototypes/Prototype.outpatient.rb +356 -345
- data/lib/openstudio-standards/prototypes/Prototype.primary_school.rb +48 -103
- data/lib/openstudio-standards/prototypes/Prototype.quick_service_restaurant.rb +115 -123
- data/lib/openstudio-standards/prototypes/Prototype.retail_standalone.rb +30 -39
- data/lib/openstudio-standards/prototypes/Prototype.retail_stripmall.rb +32 -45
- data/lib/openstudio-standards/prototypes/Prototype.secondary_school.rb +98 -258
- data/lib/openstudio-standards/prototypes/Prototype.small_hotel.rb +429 -474
- data/lib/openstudio-standards/prototypes/Prototype.small_office.rb +28 -36
- data/lib/openstudio-standards/prototypes/Prototype.strip_model.rb +7 -7
- data/lib/openstudio-standards/prototypes/Prototype.utilities.rb +172 -146
- data/lib/openstudio-standards/prototypes/Prototype.warehouse.rb +46 -53
- data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +885 -707
- data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctParallelPIUReheat.rb +48 -57
- data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctVAVReheat.rb +24 -31
- data/lib/openstudio-standards/standards/Standards.BoilerHotWater.rb +80 -93
- data/lib/openstudio-standards/standards/Standards.BuildingStory.rb +69 -0
- data/lib/openstudio-standards/standards/Standards.ChillerElectricEIR.rb +60 -72
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXMultiSpeed.rb +104 -108
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +190 -198
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXTwoSpeed.rb +134 -146
- data/lib/openstudio-standards/standards/Standards.CoilHeatingDXMultiSpeed.rb +56 -60
- data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +151 -161
- data/lib/openstudio-standards/standards/Standards.CoilHeatingGasMultiStage.rb +30 -34
- data/lib/openstudio-standards/standards/Standards.Construction.rb +116 -132
- data/lib/openstudio-standards/standards/Standards.CoolingTower.rb +138 -0
- data/lib/openstudio-standards/standards/Standards.CoolingTowerSingleSpeed.rb +11 -0
- data/lib/openstudio-standards/standards/Standards.CoolingTowerTwoSpeed.rb +11 -0
- data/lib/openstudio-standards/standards/Standards.CoolingTowerVariableSpeed.rb +16 -0
- data/lib/openstudio-standards/standards/Standards.Fan.rb +190 -236
- data/lib/openstudio-standards/standards/Standards.FanConstantVolume.rb +0 -2
- data/lib/openstudio-standards/standards/Standards.FanOnOff.rb +0 -2
- data/lib/openstudio-standards/standards/Standards.FanVariableVolume.rb +168 -14
- data/lib/openstudio-standards/standards/Standards.FanZoneExhaust.rb +0 -2
- data/lib/openstudio-standards/standards/Standards.HeaderedPumpsConstantSpeed.rb +33 -0
- data/lib/openstudio-standards/standards/Standards.HeaderedPumpsVariableSpeed.rb +83 -0
- data/lib/openstudio-standards/standards/Standards.HeatExchangerSensLat.rb +22 -0
- data/lib/openstudio-standards/standards/Standards.Model.rb +2385 -1622
- data/lib/openstudio-standards/standards/Standards.PlanarSurface.rb +83 -35
- data/lib/openstudio-standards/standards/Standards.PlantLoop.rb +805 -395
- data/lib/openstudio-standards/standards/Standards.Pump.rb +139 -119
- data/lib/openstudio-standards/standards/Standards.PumpConstantSpeed.rb +0 -2
- data/lib/openstudio-standards/standards/Standards.PumpVariableSpeed.rb +16 -15
- data/lib/openstudio-standards/standards/Standards.ScheduleCompact.rb +35 -0
- data/lib/openstudio-standards/standards/Standards.ScheduleConstant.rb +7 -13
- data/lib/openstudio-standards/standards/Standards.ScheduleRuleset.rb +144 -59
- data/lib/openstudio-standards/standards/Standards.Space.rb +1509 -1326
- data/lib/openstudio-standards/standards/Standards.SpaceType.rb +254 -262
- data/lib/openstudio-standards/standards/Standards.SubSurface.rb +105 -105
- data/lib/openstudio-standards/standards/Standards.Surface.rb +27 -31
- data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +882 -157
- data/lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb +179 -69
- data/lib/openstudio-standards/standards/Standards.ZoneHVACComponent.rb +75 -0
- data/lib/openstudio-standards/utilities/logging.rb +31 -38
- data/lib/openstudio-standards/utilities/simulation.rb +118 -82
- data/lib/openstudio-standards/version.rb +1 -1
- data/lib/openstudio-standards/weather/Weather.Model.rb +382 -390
- data/lib/openstudio-standards/weather/Weather.stat_file.rb +159 -78
- metadata +59 -6
@@ -1,7 +1,6 @@
|
|
1
1
|
|
2
2
|
# Reopen the OpenStudio class to add methods to apply standards to this object
|
3
3
|
class OpenStudio::Model::WaterHeaterMixed
|
4
|
-
|
5
4
|
# Applies the standard efficiency ratings and typical losses and paraisitic loads to this object.
|
6
5
|
# Efficiency and skin loss coefficient (UA)
|
7
6
|
# Per PNNL http://www.energycodes.gov/sites/default/files/documents/PrototypeModelEnhancements_2014_0.pdf
|
@@ -10,41 +9,38 @@ class OpenStudio::Model::WaterHeaterMixed
|
|
10
9
|
# @param template [String] valid choices: 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
|
11
10
|
# @param standards [Hash] the OpenStudio_Standards spreadsheet in hash format
|
12
11
|
# @return [Bool] true if successful, false if not
|
13
|
-
|
14
|
-
# Prototype.WaterHeaterMixed because not governed by standard?
|
15
|
-
def setStandardEfficiency(template)
|
16
|
-
|
12
|
+
def apply_efficiency(template)
|
17
13
|
# Get the capacity of the water heater
|
18
14
|
# TODO add capability to pull autosized water heater capacity
|
19
15
|
# if the Sizing:WaterHeater object is ever implemented in OpenStudio.
|
20
|
-
capacity_w =
|
16
|
+
capacity_w = heaterMaximumCapacity
|
21
17
|
if capacity_w.empty?
|
22
|
-
OpenStudio
|
18
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.WaterHeaterMixed', "For #{name}, cannot find capacity, standard will not be applied.")
|
23
19
|
return false
|
24
20
|
else
|
25
21
|
capacity_w = capacity_w.get
|
26
22
|
end
|
27
|
-
capacity_btu_per_hr = OpenStudio.convert(capacity_w,
|
28
|
-
capacity_kbtu_per_hr = OpenStudio.convert(capacity_w,
|
29
|
-
|
23
|
+
capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
|
24
|
+
capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
|
25
|
+
|
30
26
|
# Get the volume of the water heater
|
31
27
|
# TODO add capability to pull autosized water heater volume
|
32
|
-
# if the Sizing:WaterHeater object is ever implemented in OpenStudio.
|
33
|
-
volume_m3 =
|
28
|
+
# if the Sizing:WaterHeater object is ever implemented in OpenStudio.
|
29
|
+
volume_m3 = tankVolume
|
34
30
|
if volume_m3.empty?
|
35
|
-
OpenStudio
|
31
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.WaterHeaterMixed', "For #{name}, cannot find volume, standard will not be applied.")
|
36
32
|
return false
|
37
33
|
else
|
38
34
|
volume_m3 = volume_m3.get
|
39
35
|
end
|
40
|
-
volume_gal = OpenStudio.convert(volume_m3,
|
41
|
-
|
36
|
+
volume_gal = OpenStudio.convert(volume_m3, 'm^3', 'gal').get
|
37
|
+
|
42
38
|
# Get the heater fuel type
|
43
|
-
fuel_type =
|
44
|
-
|
45
|
-
OpenStudio
|
39
|
+
fuel_type = heaterFuelType
|
40
|
+
unless fuel_type == 'NaturalGas' || fuel_type == 'Electricity'
|
41
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.WaterHeaterMixed', "For #{name}, fuel type of #{fuel_type} is not yet supported, standard will not be applied.")
|
46
42
|
end
|
47
|
-
|
43
|
+
|
48
44
|
# Calculate the water heater efficiency and
|
49
45
|
# skin loss coefficient (UA)
|
50
46
|
# Calculate the energy factor (EF)
|
@@ -54,102 +50,216 @@ class OpenStudio::Model::WaterHeaterMixed
|
|
54
50
|
ua_btu_per_hr_per_f = nil
|
55
51
|
sl_btu_per_hr = nil
|
56
52
|
case fuel_type
|
57
|
-
when 'Electricity'
|
53
|
+
when 'Electricity'
|
58
54
|
case template
|
59
|
-
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004','90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
|
60
|
-
|
61
|
-
if capacity_w <=
|
55
|
+
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
|
56
|
+
|
57
|
+
if capacity_w <= 12_000 # I think this should be 12000W, use variable capacity_w instead of capacity_btu_per_hr (as per PNNL doc)
|
62
58
|
# Fixed water heater efficiency per PNNL
|
63
59
|
water_heater_eff = 1
|
64
60
|
# Calculate the minimum Energy Factor (EF)
|
65
|
-
|
61
|
+
base_ef, vol_drt = case template
|
62
|
+
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007'
|
63
|
+
[0.93, 0.00132]
|
64
|
+
when '90.1-2010'
|
65
|
+
[0.97, 0.00132]
|
66
|
+
when '90.1-2013'
|
67
|
+
[0.97, 0.00035]
|
68
|
+
end
|
69
|
+
|
70
|
+
ef = base_ef - (vol_drt * volume_gal)
|
66
71
|
# Calculate the skin loss coefficient (UA)
|
67
|
-
ua_btu_per_hr_per_f = (
|
72
|
+
ua_btu_per_hr_per_f = (41_094 * (1 / ef - 1)) / (24 * 67.5)
|
68
73
|
else
|
69
74
|
# Fixed water heater efficiency per PNNL
|
70
75
|
water_heater_eff = 1
|
71
|
-
# Calculate the max allowable standby loss (SL)
|
72
|
-
sl_btu_per_hr = 20 + (35*Math.sqrt(volume_gal))
|
73
76
|
# Calculate the skin loss coefficient (UA)
|
74
|
-
|
77
|
+
case template
|
78
|
+
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007', '90.1-2010'
|
79
|
+
# Calculate the max allowable standby loss (SL)
|
80
|
+
sl_btu_per_hr = 20 + (35 * Math.sqrt(volume_gal))
|
81
|
+
# Calculate the skin loss coefficient (UA)
|
82
|
+
ua_btu_per_hr_per_f = sl_btu_per_hr / 70
|
83
|
+
when '90.1-2013'
|
84
|
+
# Calculate the percent loss per hr
|
85
|
+
hrly_loss_pct = (0.3 + 27 / volume_gal) / 100
|
86
|
+
# Convert to Btu/hr, assuming:
|
87
|
+
# Water at 120F, density = 8.25 lb/gal
|
88
|
+
# 1 Btu to raise 1 lb of water 1 F
|
89
|
+
# Therefore 8.25 Btu / gal of water * deg F
|
90
|
+
# 70F delta-T between water and zone
|
91
|
+
hrly_loss_btu_per_hr = hrly_loss_pct * volume_gal * 8.25 * 70
|
92
|
+
# Calculate the skin loss coefficient (UA)
|
93
|
+
ua_btu_per_hr_per_f = hrly_loss_btu_per_hr / 70
|
94
|
+
end
|
75
95
|
end
|
76
96
|
|
77
97
|
when 'NECB 2011'
|
78
98
|
volume_l_per_s = volume_m3 * 1000
|
79
|
-
if
|
99
|
+
if capacity_btu_per_hr <= OpenStudio.convert(12, 'kW', 'Btu/hr')
|
80
100
|
# Fixed water heater efficiency per PNNL
|
81
101
|
water_heater_eff = 1
|
82
|
-
# Calculate the max allowable standby loss (SL)
|
83
|
-
if volume_l_per_s < 270
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
sl_btu_per_hr = OpenStudio.convert(sl_w,
|
102
|
+
# Calculate the max allowable standby loss (SL)
|
103
|
+
sl_w = if volume_l_per_s < 270
|
104
|
+
40 + 0.2 * volume_l_per_s # assume bottom inlet
|
105
|
+
else
|
106
|
+
0.472 * volume_l_per_s - 33.5
|
107
|
+
end # assume bottom inlet
|
108
|
+
sl_btu_per_hr = OpenStudio.convert(sl_w, 'W', 'Btu/hr').get
|
89
109
|
else
|
90
110
|
# Fixed water heater efficiency per PNNL
|
91
111
|
water_heater_eff = 1
|
92
112
|
# Calculate the max allowable standby loss (SL) # use this - NECB does not give SL calculation for cap > 12 kW
|
93
|
-
sl_btu_per_hr = 20 + (35*Math.sqrt(volume_gal))
|
113
|
+
sl_btu_per_hr = 20 + (35 * Math.sqrt(volume_gal))
|
94
114
|
end
|
95
115
|
# Calculate the skin loss coefficient (UA)
|
96
|
-
ua_btu_per_hr_per_f = sl_btu_per_hr/70
|
116
|
+
ua_btu_per_hr_per_f = sl_btu_per_hr / 70
|
97
117
|
end
|
98
|
-
|
118
|
+
|
99
119
|
when 'NaturalGas'
|
100
|
-
case template # TODO inconsistency; ref buildings don't calculate water heater UA the same way
|
120
|
+
case template # TODO: inconsistency; ref buildings don't calculate water heater UA the same way
|
101
121
|
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
|
102
122
|
water_heater_eff = 0.78
|
103
123
|
ua_btu_per_hr_per_f = 11.37
|
104
124
|
when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013', 'NECB 2011'
|
105
|
-
if capacity_btu_per_hr <=
|
106
|
-
# Fixed water heater efficiency per PNNL
|
125
|
+
if capacity_btu_per_hr <= 75_000
|
126
|
+
# Fixed water heater thermal efficiency per PNNL
|
107
127
|
water_heater_eff = 0.82
|
108
128
|
# Calculate the minimum Energy Factor (EF)
|
109
|
-
|
129
|
+
base_ef, vol_drt = case template
|
130
|
+
when '90.1-2004', '90.1-2007'
|
131
|
+
[0.62, 0.0019]
|
132
|
+
when '90.1-2010'
|
133
|
+
[0.67, 0.0019]
|
134
|
+
when '90.1-2013'
|
135
|
+
[0.67, 0.0005]
|
136
|
+
end
|
137
|
+
|
138
|
+
ef = base_ef - (vol_drt * volume_gal)
|
139
|
+
# Calculate the Recovery Efficiency (RE)
|
140
|
+
# based on a fixed capacity of 75,000 Btu/hr
|
141
|
+
# and a fixed volume of 40 gallons by solving
|
142
|
+
# this system of equations:
|
143
|
+
# ua = (1/.95-1/re)/(67.5*(24/41094-1/(re*cap)))
|
144
|
+
# 0.82 = (ua*67.5+cap*re)/cap
|
145
|
+
cap = 75_000.0
|
146
|
+
re = (Math.sqrt(6724 * ef**2 * cap**2 + 40_409_100 * ef**2 * cap - 28_080_900 * ef * cap + 29_318_000_625 * ef**2 - 58_636_001_250 * ef + 29_318_000_625) + 82 * ef * cap + 171_225 * ef - 171_225) / (200 * ef * cap)
|
110
147
|
# Calculate the skin loss coefficient (UA)
|
111
|
-
#
|
112
|
-
|
113
|
-
re = 0.81
|
114
|
-
ua_btu_per_hr_per_f = (1/ef-1/re)/(67.5*(24/41094-1/(re*capacity_btu_per_hr)))
|
148
|
+
# based on the actual capacity.
|
149
|
+
ua_btu_per_hr_per_f = (water_heater_eff - re) * capacity_btu_per_hr / 67.5
|
115
150
|
else
|
116
151
|
# Thermal efficiency requirement from 90.1
|
117
152
|
et = 0.8
|
118
153
|
# Calculate the max allowable standby loss (SL)
|
119
|
-
|
154
|
+
cap_adj, vol_drt = case template
|
155
|
+
when '90.1-2004', '90.1-2007', '90.1-2010'
|
156
|
+
[800, 110]
|
157
|
+
when '90.1-2013'
|
158
|
+
[799, 16.6]
|
159
|
+
end
|
160
|
+
|
161
|
+
sl_btu_per_hr = (capacity_btu_per_hr / cap_adj + vol_drt * Math.sqrt(volume_gal))
|
120
162
|
# Calculate the skin loss coefficient (UA)
|
121
|
-
ua_btu_per_hr_per_f = (sl_btu_per_hr*et)/70
|
163
|
+
ua_btu_per_hr_per_f = (sl_btu_per_hr * et) / 70
|
122
164
|
# Calculate water heater efficiency
|
123
|
-
water_heater_eff = (ua_btu_per_hr_per_f*70 + capacity_btu_per_hr*et)/capacity_btu_per_hr
|
165
|
+
water_heater_eff = (ua_btu_per_hr_per_f * 70 + capacity_btu_per_hr * et) / capacity_btu_per_hr
|
124
166
|
end
|
125
167
|
end
|
126
168
|
end
|
127
|
-
|
169
|
+
|
128
170
|
# Convert to SI
|
129
|
-
ua_btu_per_hr_per_c = OpenStudio.convert(ua_btu_per_hr_per_f,
|
130
|
-
|
171
|
+
ua_btu_per_hr_per_c = OpenStudio.convert(ua_btu_per_hr_per_f, 'Btu/hr*R', 'W/K').get
|
172
|
+
|
131
173
|
# Set the water heater properties
|
132
174
|
# Efficiency
|
133
|
-
|
175
|
+
setHeaterThermalEfficiency(water_heater_eff)
|
134
176
|
# Skin loss
|
135
|
-
|
136
|
-
|
137
|
-
# TODO Parasitic loss (pilot light)
|
177
|
+
setOffCycleLossCoefficienttoAmbientTemperature(ua_btu_per_hr_per_c)
|
178
|
+
setOnCycleLossCoefficienttoAmbientTemperature(ua_btu_per_hr_per_c)
|
179
|
+
# TODO: Parasitic loss (pilot light)
|
138
180
|
# PNNL document says pilot lights were removed, but IDFs
|
139
181
|
# still have the on/off cycle parasitic fuel consumptions filled in
|
140
|
-
|
141
|
-
#self.setOffCycleParasiticFuelConsumptionRate(??)
|
142
|
-
|
143
|
-
|
144
|
-
#self.setOffCycleParasiticFuelConsumptionRate(??)
|
145
|
-
|
146
|
-
|
182
|
+
setOnCycleParasiticFuelType(fuel_type)
|
183
|
+
# self.setOffCycleParasiticFuelConsumptionRate(??)
|
184
|
+
setOnCycleParasiticHeatFractiontoTank(0)
|
185
|
+
setOffCycleParasiticFuelType(fuel_type)
|
186
|
+
# self.setOffCycleParasiticFuelConsumptionRate(??)
|
187
|
+
setOffCycleParasiticHeatFractiontoTank(0.8)
|
188
|
+
|
147
189
|
# Append the name with standards information
|
148
|
-
|
149
|
-
OpenStudio
|
150
|
-
|
190
|
+
setName("#{name} #{water_heater_eff.round(3)} Therm Eff")
|
191
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.WaterHeaterMixed', "For #{template}: #{name}; thermal efficiency = #{water_heater_eff.round(3)}, skin-loss UA = #{ua_btu_per_hr_per_f.round}Btu/hr")
|
192
|
+
|
193
|
+
return true
|
194
|
+
end
|
195
|
+
|
196
|
+
# Applies the correct fuel type for the water heaters
|
197
|
+
# in the baseline model. For most standards and for most building
|
198
|
+
# types, the baseline uses the same fuel type as the proposed.
|
199
|
+
# However, certain standards like 90.1-2013 require a change
|
200
|
+
# in some scenarios.
|
201
|
+
#
|
202
|
+
# @param building_type [String] the building type
|
203
|
+
# @return [Bool] returns true if successful, false if not.
|
204
|
+
def apply_prm_baseline_fuel_type(template, building_type)
|
205
|
+
# For all standards except 90.1-2013
|
206
|
+
# baseline is same as proposed per
|
207
|
+
# Table G3.1 item 11.b
|
208
|
+
unless template == '90.1-2013'
|
209
|
+
return true
|
210
|
+
end
|
211
|
+
|
212
|
+
# Determine the building-type specific
|
213
|
+
# fuel requirements from Table G3.1.1-2
|
214
|
+
new_fuel = nil
|
215
|
+
case building_type
|
216
|
+
when 'SecondarySchool', 'PrimarySchool', # School/university
|
217
|
+
'SmallHotel', # Motel
|
218
|
+
'LargeHotel', # Hotel
|
219
|
+
'QuickServiceRestaurant', # Dining: Cafeteria/fast food
|
220
|
+
'FullServiceRestaurant', # Dining: Family
|
221
|
+
'MidriseApartment', 'HighriseApartment', # Multifamily
|
222
|
+
'Hospital', # Hospital
|
223
|
+
'Outpatient' # Health-care clinic
|
224
|
+
new_fuel = 'NaturalGas'
|
225
|
+
when 'SmallOffice', 'MediumOffice', 'LargeOffice', # Office
|
226
|
+
'RetailStandalone', 'RetailStripmall', # Retail
|
227
|
+
'Warehouse' # Warehouse
|
228
|
+
new_fuel = 'Electricity'
|
229
|
+
else
|
230
|
+
new_fuel = 'NaturalGas'
|
231
|
+
end
|
232
|
+
|
233
|
+
# Change the fuel type if necessary
|
234
|
+
old_fuel = heaterFuelType
|
235
|
+
unless new_fuel == old_fuel
|
236
|
+
setHeaterFuelType(new_fuel)
|
237
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.WaterHeaterMixed', "For #{name}, changed baseline water heater fuel from #{old_fuel} to #{new_fuel}.")
|
238
|
+
end
|
239
|
+
|
151
240
|
return true
|
152
|
-
|
153
241
|
end
|
154
|
-
|
242
|
+
|
243
|
+
# Finds capacity in Btu/hr
|
244
|
+
#
|
245
|
+
# @return [Double] capacity in Btu/hr to be used for find object
|
246
|
+
def find_capacity()
|
247
|
+
|
248
|
+
# Get the coil capacity
|
249
|
+
capacity_w = nil
|
250
|
+
if self.heaterMaximumCapacity.is_initialized
|
251
|
+
capacity_w = self.heaterMaximumCapacity.get
|
252
|
+
elsif self.autosizedHeaterMaximumCapacity.is_initialized
|
253
|
+
capacity_w = self.autosizedHeaterMaximumCapacity.get
|
254
|
+
else
|
255
|
+
OpenStudio::logFree(OpenStudio::Warn, 'openstudio.standards.WaterHeaterMixed', "For #{self.name} capacity is not available.")
|
256
|
+
return false
|
257
|
+
end
|
258
|
+
|
259
|
+
# Convert capacity to Btu/hr
|
260
|
+
capacity_btu_per_hr = OpenStudio.convert(capacity_w, "W", "Btu/hr").get
|
261
|
+
|
262
|
+
return capacity_btu_per_hr
|
263
|
+
|
264
|
+
end
|
155
265
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# open the class to add methods to apply HVAC efficiency standards
|
2
|
+
class OpenStudio::Model::ZoneHVACComponent
|
3
|
+
# Sets the fan power of zone level HVAC equipment
|
4
|
+
# (PTACs, PTHPs, Fan Coils, and Unit Heaters)
|
5
|
+
# based on the W/cfm specified in the standard.
|
6
|
+
#
|
7
|
+
# @param template [String] the template base requirements on
|
8
|
+
# @return [Bool] returns true if successful, false if not
|
9
|
+
def apply_prm_baseline_fan_power(template)
|
10
|
+
OpenStudio.logFree(OpenStudio::Debug, 'openstudio.model.ZoneHVACComponent', "Setting fan power for #{name}.")
|
11
|
+
|
12
|
+
# Convert this to the actual class type
|
13
|
+
zone_hvac = if to_ZoneHVACFourPipeFanCoil.is_initialized
|
14
|
+
to_ZoneHVACFourPipeFanCoil.get
|
15
|
+
elsif to_ZoneHVACUnitHeater.is_initialized
|
16
|
+
to_ZoneHVACUnitHeater.get
|
17
|
+
elsif to_ZoneHVACPackagedTerminalAirConditioner.is_initialized
|
18
|
+
to_ZoneHVACPackagedTerminalAirConditioner.get
|
19
|
+
elsif to_ZoneHVACPackagedTerminalHeatPump.is_initialized
|
20
|
+
to_ZoneHVACPackagedTerminalHeatPump.get
|
21
|
+
else
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# Do nothing for other types of zone HVAC equipment
|
26
|
+
if zone_hvac.nil?
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
|
30
|
+
# Determine the W/cfm
|
31
|
+
fan_efficacy_w_per_cfm = 0.3
|
32
|
+
|
33
|
+
# Convert efficacy to metric
|
34
|
+
# 1 cfm = 0.0004719 m^3/s
|
35
|
+
fan_efficacy_w_per_m3_per_s = fan_efficacy_w_per_cfm / 0.0004719
|
36
|
+
|
37
|
+
# Get the fan
|
38
|
+
fan = if zone_hvac.supplyAirFan.to_FanConstantVolume.is_initialized
|
39
|
+
zone_hvac.supplyAirFan.to_FanConstantVolume.get
|
40
|
+
elsif zone_hvac.supplyAirFan.to_FanVariableVolume.is_initialized
|
41
|
+
zone_hvac.supplyAirFan.to_FanVariableVolume.get
|
42
|
+
elsif zone_hvac.supplyAirFan.to_FanOnOff.is_initialized
|
43
|
+
zone_hvac.supplyAirFan.to_FanOnOff.get
|
44
|
+
end
|
45
|
+
|
46
|
+
# Get the maximum flow rate through the fan
|
47
|
+
max_air_flow_rate = nil
|
48
|
+
if fan.autosizedMaximumFlowRate.is_initialized
|
49
|
+
max_air_flow_rate = fan.autosizedMaximumFlowRate.get
|
50
|
+
elsif fan.maximumFlowRate.is_initialized
|
51
|
+
max_air_flow_rate = fan.maximumFlowRate.get
|
52
|
+
end
|
53
|
+
max_air_flow_rate_cfm = OpenStudio.convert(max_air_flow_rate, 'm^3/s', 'ft^3/min').get
|
54
|
+
|
55
|
+
# Set the impeller efficiency
|
56
|
+
fan.change_impeller_efficiency(fan.baseline_impeller_efficiency(template))
|
57
|
+
|
58
|
+
# Set the motor efficiency, preserving the impeller efficency.
|
59
|
+
# For zone HVAC fans, a bhp lookup of 0.5bhp is always used because
|
60
|
+
# they are assumed to represent a series of small fans in reality.
|
61
|
+
fan.apply_standard_minimum_motor_efficiency(template, fan.brake_horsepower)
|
62
|
+
|
63
|
+
# Calculate a new pressure rise to hit the target W/cfm
|
64
|
+
fan_tot_eff = fan.fanEfficiency
|
65
|
+
fan_rise_new_pa = fan_efficacy_w_per_m3_per_s * fan_tot_eff
|
66
|
+
fan.setPressureRise(fan_rise_new_pa)
|
67
|
+
|
68
|
+
# Calculate the newly set efficacy
|
69
|
+
fan_power_new_w = fan_rise_new_pa * max_air_flow_rate / fan_tot_eff
|
70
|
+
fan_efficacy_new_w_per_cfm = fan_power_new_w / max_air_flow_rate_cfm
|
71
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.ZoneHVACComponent', "For #{name}: fan efficacy set to #{fan_efficacy_new_w_per_cfm.round(2)} W/cfm.")
|
72
|
+
|
73
|
+
return true
|
74
|
+
end
|
75
|
+
end
|
@@ -8,18 +8,18 @@ $OPENSTUDIO_LOG.setLogLevel(OpenStudio::Debug)
|
|
8
8
|
# debug @param [Boolean] If true, include the debug messages in the log
|
9
9
|
# @return [Runner] The same Measure runner, with messages from the openstudio-standards library added
|
10
10
|
def log_messages_to_runner(runner, debug = false)
|
11
|
-
|
12
11
|
$OPENSTUDIO_LOG.logMessages.each do |msg|
|
13
12
|
# DLM: you can filter on log channel here for now
|
14
|
-
if /openstudio
|
13
|
+
if /openstudio.*/ =~ msg.logChannel # /openstudio\.model\..*/
|
15
14
|
# Skip certain messages that are irrelevant/misleading
|
16
|
-
next if msg.logMessage.include?(
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
next if msg.logMessage.include?('Skipping layer') || # Annoying/bogus "Skipping layer" warnings
|
16
|
+
msg.logChannel.include?('runmanager') || # RunManager messages
|
17
|
+
msg.logChannel.include?('setFileExtension') || # .ddy extension unexpected
|
18
|
+
msg.logChannel.include?('Translator') || # Forward translator and geometry translator
|
19
|
+
msg.logMessage.include?('UseWeatherFile') || # 'UseWeatherFile' is not yet a supported option for YearDescription
|
20
|
+
msg.logMessage.include?('Successive data points') || # Successive data points (2004-Jan-31 to 2001-Feb-01, ending on line 753) are greater than 1 day apart in EPW file
|
21
|
+
msg.logMessage.include?('has multiple parents') # Bogus errors about curves having multiple parents
|
22
|
+
|
23
23
|
# Report the message in the correct way
|
24
24
|
if msg.logLevel == OpenStudio::Info
|
25
25
|
runner.registerInfo(msg.logMessage)
|
@@ -32,7 +32,6 @@ def log_messages_to_runner(runner, debug = false)
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
36
35
|
end
|
37
36
|
|
38
37
|
# Log the info, warning, and error messages to a file.
|
@@ -40,33 +39,32 @@ end
|
|
40
39
|
# debug @param [Boolean] If true, include the debug messages in the log
|
41
40
|
# @return [Array<String>] The array of messages, which can be used elsewhere.
|
42
41
|
def log_messages_to_file(file_path, debug = false)
|
43
|
-
|
44
42
|
messages = []
|
45
43
|
|
46
|
-
File.open(file_path, 'w') do |file|
|
47
|
-
|
44
|
+
File.open(file_path, 'w') do |file|
|
48
45
|
$OPENSTUDIO_LOG.logMessages.each do |msg|
|
49
46
|
# DLM: you can filter on log channel here for now
|
50
|
-
if /openstudio
|
47
|
+
if /openstudio.*/ =~ msg.logChannel # /openstudio\.model\..*/
|
51
48
|
# Skip certain messages that are irrelevant/misleading
|
52
|
-
next if msg.logMessage.include?(
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
49
|
+
next if msg.logMessage.include?('Skipping layer') || # Annoying/bogus "Skipping layer" warnings
|
50
|
+
msg.logChannel.include?('runmanager') || # RunManager messages
|
51
|
+
msg.logChannel.include?('setFileExtension') || # .ddy extension unexpected
|
52
|
+
msg.logChannel.include?('Translator') || # Forward translator and geometry translator
|
53
|
+
msg.logMessage.include?('UseWeatherFile') || # 'UseWeatherFile' is not yet a supported option for YearDescription
|
54
|
+
msg.logMessage.include?('Successive data points') || # Successive data points (2004-Jan-31 to 2001-Feb-01, ending on line 753) are greater than 1 day apart in EPW file
|
55
|
+
msg.logMessage.include?('has multiple parents') # Bogus errors about curves having multiple parents
|
56
|
+
|
59
57
|
# Report the message in the correct way
|
60
58
|
if msg.logLevel == OpenStudio::Info
|
61
59
|
s = "INFO #{msg.logMessage}"
|
62
60
|
file.puts(s)
|
63
61
|
messages << s
|
64
62
|
elsif msg.logLevel == OpenStudio::Warn
|
65
|
-
s = "WARN
|
63
|
+
s = "WARN #{msg.logMessage}"
|
66
64
|
file.puts(s)
|
67
65
|
messages << s
|
68
66
|
elsif msg.logLevel == OpenStudio::Error
|
69
|
-
s = "ERROR
|
67
|
+
s = "ERROR #{msg.logMessage}"
|
70
68
|
file.puts(s)
|
71
69
|
messages << s
|
72
70
|
elsif msg.logLevel == OpenStudio::Debug && debug
|
@@ -76,40 +74,35 @@ def log_messages_to_file(file_path, debug = false)
|
|
76
74
|
end
|
77
75
|
end
|
78
76
|
end
|
79
|
-
|
80
77
|
end
|
81
|
-
|
78
|
+
|
82
79
|
return messages
|
83
|
-
|
84
80
|
end
|
85
81
|
|
86
82
|
# Get an array of all messages of a given type in the log
|
87
83
|
def get_logs(log_type = OpenStudio::Error)
|
88
|
-
|
89
84
|
errors = []
|
90
85
|
|
91
86
|
$OPENSTUDIO_LOG.logMessages.each do |msg|
|
92
|
-
if /openstudio
|
87
|
+
if /openstudio.*/ =~ msg.logChannel
|
93
88
|
# Skip certain messages that are irrelevant/misleading
|
94
|
-
next if msg.logMessage.include?(
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
89
|
+
next if msg.logMessage.include?('Skipping layer') || # Annoying/bogus "Skipping layer" warnings
|
90
|
+
msg.logChannel.include?('runmanager') || # RunManager messages
|
91
|
+
msg.logChannel.include?('setFileExtension') || # .ddy extension unexpected
|
92
|
+
msg.logChannel.include?('Translator') || # Forward translator and geometry translator
|
93
|
+
msg.logMessage.include?('UseWeatherFile') || # 'UseWeatherFile' is not yet a supported option for YearDescription
|
94
|
+
msg.logMessage.include?('Successive data points') || # Successive data points (2004-Jan-31 to 2001-Feb-01, ending on line 753) are greater than 1 day apart in EPW file
|
95
|
+
msg.logMessage.include?('has multiple parents') # Bogus errors about curves having multiple parents
|
100
96
|
# Only fail on the errors
|
101
97
|
if msg.logLevel == log_type
|
102
98
|
errors << "[#{msg.logChannel}] #{msg.logMessage}"
|
103
99
|
end
|
104
100
|
end
|
105
|
-
end
|
101
|
+
end
|
106
102
|
|
107
103
|
return errors
|
108
|
-
|
109
104
|
end
|
110
105
|
|
111
106
|
def reset_log
|
112
|
-
|
113
107
|
$OPENSTUDIO_LOG.resetStringStream
|
114
|
-
|
115
108
|
end
|