# Reopen the OpenStudio class to add methods to apply standards to this object
class OpenStudio::Model::WaterHeaterMixed

  # Applies the standard efficiency ratings and typical losses and paraisitic loads to this object.
  # Efficiency and skin loss coefficient (UA)
  # Per PNNL http://www.energycodes.gov/sites/default/files/documents/PrototypeModelEnhancements_2014_0.pdf
  # Appendix A: Service Water Heating
  #
  # @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'
  # @param standards [Hash] the OpenStudio_Standards spreadsheet in hash format
  # @return [Bool] true if successful, false if not
  # @todo break parasitic/skin losses into a separate method in
  #   Prototype.WaterHeaterMixed because not governed by standard?
  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'  
      case template
      when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004','90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
      
        if capacity_w <= 12000     # I think this should be 12000W, use variable capacity_w instead of capacity_btu_per_hr (as per PNNL doc)
          # 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 'NECB 2011'
        volume_l_per_s = volume_m3 * 1000
        if capacity_w <= 12000     
          # Fixed water heater efficiency per PNNL
          water_heater_eff = 1
          # Calculate the max allowable standby loss (SL)         
          if volume_l_per_s < 270
            sl_w = 40 + 0.2 * volume_l_per_s          # assume bottom inlet
          else
            sl_w = 0.472 * volume_l_per_s - 33.5   
          end                                         # assume bottom inlet
          sl_btu_per_hr = OpenStudio.convert(sl_w, "W", "Btu/hr").get  
        else
          # Fixed water heater efficiency per PNNL
          water_heater_eff = 1
          # Calculate the max allowable standby loss (SL)   # use this - NECB does not give SL calculation for cap > 12 kW
          sl_btu_per_hr = 20 + (35*Math.sqrt(volume_gal))          
        end
        # 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', 'NECB 2011'
        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
  
end