Class: OpenStudio::Model::WaterHeaterMixed

Inherits:
Object
  • Object
show all
Defined in:
lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb

Overview

Reopen the OpenStudio class to add methods to apply standards to this object

Instance Method Summary collapse

Instance Method Details

#setStandardEfficiency(template) ⇒ Bool

TODO:

break parasitic/skin losses into a separate method in Prototype.WaterHeaterMixed because not governed by standard?

Applies the standard efficiency ratings and typical losses and paraisitic loads to this object. Efficiency and skin loss coefficient (UA) Per PNNL www.energycodes.gov/sites/default/files/documents/PrototypeModelEnhancements_2014_0.pdf Appendix A: Service Water Heating

Parameters:

  • template (String)

    valid choices: ‘DOE Ref Pre-1980’, ‘DOE Ref 1980-2004’, ‘90.1-2004’, ‘90.1-2007’, ‘90.1-2010’, ‘90.1-2013’

  • standards (Hash)

    the OpenStudio_Standards spreadsheet in hash format

Returns:

  • (Bool)

    true if successful, false if not



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb', line 15

def setStandardEfficiency(template)

  # Get the capacity of the water heater
  # TODO add capability to pull autosized water heater capacity
  # if the Sizing:WaterHeater object is ever implemented in OpenStudio.
  capacity_w = self.heaterMaximumCapacity
  if capacity_w.empty?
    OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.WaterHeaterMixed", "For #{self.name}, cannot find capacity, standard will not be applied.")
    return false
  else
    capacity_w = capacity_w.get
  end
  capacity_btu_per_hr = OpenStudio.convert(capacity_w, "W", "Btu/hr").get
  capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, "W", "kBtu/hr").get
  
  # Get the volume of the water heater
  # TODO add capability to pull autosized water heater volume
  # if the Sizing:WaterHeater object is ever implemented in OpenStudio. 
  volume_m3 = self.tankVolume
  if volume_m3.empty?
    OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.WaterHeaterMixed", "For #{self.name}, cannot find volume, standard will not be applied.")
    return false
  else
    volume_m3 = volume_m3.get
  end
  volume_gal = OpenStudio.convert(volume_m3, "m^3", "gal").get

  # Get the heater fuel type
  fuel_type = self.heaterFuelType
  if !(fuel_type == 'NaturalGas' || fuel_type == 'Electricity')
    OpenStudio::logFree(OpenStudio::Warn, "openstudio.standards.WaterHeaterMixed", "For #{self.name}, fuel type of #{fuel_type} is not yet supported, standard will not be applied.")
  end
  
  # Calculate the water heater efficiency and
  # skin loss coefficient (UA)
  # Calculate the energy factor (EF)
  # From PNNL http://www.energycodes.gov/sites/default/files/documents/PrototypeModelEnhancements_2014_0.pdf
  # Appendix A: Service Water Heating
  water_heater_eff = nil
  ua_btu_per_hr_per_f = nil
  sl_btu_per_hr = nil
  case fuel_type
  when 'Electricity'
    if capacity_btu_per_hr <= 12000  
      # Fixed water heater efficiency per PNNL
      water_heater_eff = 1
      # Calculate the minimum Energy Factor (EF)
      ef = 0.97 - (0.00132 * volume_gal)
      # Calculate the skin loss coefficient (UA)
      ua_btu_per_hr_per_f = (41094*(1/ef - 1))/(24*67.5)
    else
      # Fixed water heater efficiency per PNNL
      water_heater_eff = 1
      # Calculate the max allowable standby loss (SL)
      sl_btu_per_hr = 20 + (35*Math.sqrt(volume_gal))
      # Calculate the skin loss coefficient (UA)
      ua_btu_per_hr_per_f = sl_btu_per_hr/70
    end
  when 'NaturalGas'
    case template # TODO inconsistency; ref buildings don't calculate water heater UA the same way
    when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
      water_heater_eff = 0.78
      ua_btu_per_hr_per_f = 11.37
    when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
      if capacity_btu_per_hr <= 75000  
        # Fixed water heater efficiency per PNNL
        water_heater_eff = 0.82
        # Calculate the minimum Energy Factor (EF)
        ef = 0.67 - (0.0019 * volume_gal)
        # Calculate the skin loss coefficient (UA)
        # TODO solve system of equations {u = (1/.95-1/r)/(67.5*(24/41094-1/(r*75000))), 0.82 = (u*67.5+75000*r)/75000}
        # Assume recovery efficieny = 0.81 based on regression of prototype models instead
        re = 0.81
        ua_btu_per_hr_per_f = (1/ef-1/re)/(67.5*(24/41094-1/(re*capacity_btu_per_hr)))
      else
        # Thermal efficiency requirement from 90.1
        et = 0.8
        # Calculate the max allowable standby loss (SL)
        sl_btu_per_hr = et*(capacity_btu_per_hr/800 + 110*Math.sqrt(volume_gal))
        # Calculate the skin loss coefficient (UA)
        ua_btu_per_hr_per_f = (sl_btu_per_hr*et)/70
        # Calculate water heater efficiency
        water_heater_eff = (ua_btu_per_hr_per_f*70 + capacity_btu_per_hr*et)/capacity_btu_per_hr
      end
    end
  end
  
  # Convert to SI
  ua_btu_per_hr_per_c = OpenStudio.convert(ua_btu_per_hr_per_f, "Btu/hr*R", "W/K").get

  # Set the water heater properties
  # Efficiency
  self.setHeaterThermalEfficiency(water_heater_eff)
  # Skin loss
  self.setOffCycleLossCoefficienttoAmbientTemperature(ua_btu_per_hr_per_c)
  self.setOnCycleLossCoefficienttoAmbientTemperature(ua_btu_per_hr_per_c)
  # TODO Parasitic loss (pilot light)
  # PNNL document says pilot lights were removed, but IDFs
  # still have the on/off cycle parasitic fuel consumptions filled in
  self.setOnCycleParasiticFuelType(fuel_type)
  #self.setOffCycleParasiticFuelConsumptionRate(??)
  self.setOnCycleParasiticHeatFractiontoTank(0)
  self.setOffCycleParasiticFuelType(fuel_type)
  #self.setOffCycleParasiticFuelConsumptionRate(??)
  self.setOffCycleParasiticHeatFractiontoTank(0.8)

  # Append the name with standards information
  self.setName("#{name} #{water_heater_eff.round(3)}Eff")
  OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.WaterHeaterMixed', "For #{template}: #{self.name}; efficiency = #{water_heater_eff.round(3)}, skin-loss UA = #{ua_btu_per_hr_per_f.round}Btu/hr AKA #{ua_btu_per_hr_per_c.round(1)}W/K")  

  return true

end