lib/openstudio-standards/weather/Weather.Model.rb in openstudio-standards-0.2.14 vs lib/openstudio-standards/weather/Weather.Model.rb in openstudio-standards-0.2.15.pre.rc1

- old
+ new

@@ -1,10 +1,14 @@ class Standard # Helper method to set the weather file, import the design days, set # water mains temperature, and set ground temperature. # Based on ChangeBuildingLocation measure by Nicholas Long + # A method to return an array of .epw files names mapped to each climate zone + # + # @param epw_file [String] optional epw_file name for NECB methods + # @return [Hash] a hash of ashrae climate zone weather file pairs def model_get_climate_zone_weather_file_map(epw_file = '') # Define the weather file for each climate zone climate_zone_weather_file_map = { 'ASHRAE 169-2006-0A' => 'VNM_SVN_Ho.Chi.Minh-Tan.Son.Nhat.Intl.AP.489000_TMYx.epw', 'ASHRAE 169-2006-0B' => 'ARE_DU_Dubai.Intl.AP.411940_TMYx.epw', @@ -75,11 +79,17 @@ 'CEC T24-CEC16' => 'BLUE-CANYON_725845_CZ2010.epw' } return climate_zone_weather_file_map end - def model_add_design_days_and_weather_file(model, climate_zone, epw_file) + # Adds the design days and weather file for the specified climate zone + # + # @param model [OpenStudio::Model::Model] OpenStudio model object + # @param climate_zone [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A' + # @param epw_file [String] the name of the epw file; if blank will default to epw file for the ASHRAE climate zone + # @return [Bool] returns true if successful, false if not + def model_add_design_days_and_weather_file(model, climate_zone, epw_file = '') success = true require_relative 'Weather.stat_file' # Remove any existing Design Day objects that are in the file model.getDesignDays.each(&:remove) @@ -181,10 +191,19 @@ end return success end + # Adds ground temperatures to the model based on a building type and climate zone lookup + # It will first attempt to find ground temperatures from the .stat file associated with the epw + # Otherwise, it will use values from the prototypes per a given template, building type, and climate zone + # If neither are available, it will default to a set of typical ground temperatures + # + # @param model [OpenStudio::Model::Model] OpenStudio model object + # @param [String] openstudio-standards building type + # @param [String] ASHRAE climate zone, e.g. 'ASHRAE 169-2013-4A' + # @return [Bool] returns true if successful, false if not def model_add_ground_temperatures(model, building_type, climate_zone) # Define the weather file for each climate zone climate_zone_weather_file_map = model_get_climate_zone_weather_file_map # Get the weather file name from the hash @@ -268,30 +287,31 @@ ground_temp.setNovemberGroundTemperature(19.802) ground_temp.setDecemberGroundTemperature(19.633) end end - # Gets the maximum OA dry bulb temperatures - # for all WinterDesignDays in the model. + # Returns the winter design outdoor air dry bulb temperatures in the model # - # @return [Array<Double>] an array of OA temperatures in C - def heating_design_outdoor_temperatures + # @param model [OpenStudio::Model::Model] OpenStudio model object + # @return [Array<Double>] an array of outdoor design dry bulb temperatures in degrees Celsius + def model_get_heating_design_outdoor_temperatures(model) heating_design_outdoor_temps = [] - getDesignDays.each do |dd| + model.getDesignDays.each do |dd| next unless dd.dayType == 'WinterDesignDay' heating_design_outdoor_temps << dd.maximumDryBulbTemperature end return heating_design_outdoor_temps end # This function gets the average ground temperature averages, under the assumption that ground temperature - # lags 3 months behind the ambient dry bulb temperature. (e.g. April's ground temperature equal January's - # average dry bulb temperature) + # lags 3 months behind the ambient dry bulb temperature. + # (e.g. April's ground temperature equal January's average dry bulb temperature) + # # @param stat_file_path [String] path to STAT file - # @return [Array] a length 12 array of monthly ground temperatures, one for each month + # @return [Array<Double>] a length 12 array of monthly ground temperatures, one for each month def model_get_monthly_ground_temps_from_stat_file(stat_file_path) if File.exist? stat_file_path stat_file = EnergyPlus::StatFile.new(stat_file_path) monthly_dry_bulb = stat_file.monthly_dry_bulb[0..11] ground_temperatures = monthly_dry_bulb.rotate(-3) @@ -474,10 +494,16 @@ SNOW_DEPTH = 30 DAYS_SINCE_LAST_SNOWFALL = 31 # not used ALBEDO = 32 # not used LIQUID_PRECIPITATION_DEPTH = 33 LIQUID_PRECIPITATION_QUANTITY = 34 + CALCULATED_SATURATION_PRESSURE_OF_WATER_VAPOR = 100 # pws + CALCULATED_PARTIAL_PRESSURE_OF_WATER_VAPOR = 101 # pw + CALCULATED_TOTAL_MIXTURE_PRESSURE = 102 # p + CALCULATED_HUMIDITY_RATIO = 103 # w + CALCULATED_HUMIDITY_RATIO_AVG_DAILY = 104 # w averaged daily + CALCULATED_HUMIDITY_RATIO_AVG_DAILY_DIFF_BASE = 105 # difference of w_averaged_daily from base if w_averaged_daily > base # This method initializes and returns self. # @author phylroy.lopez@nrcan.gc.ca # @param weather_file [String] # @return [String] self @@ -802,8 +828,182 @@ end # copies original file FileUtils.cp(@ddy_filepath, "#{File.dirname(filename)}/#{File.basename(filename, '.epw')}.ddy") FileUtils.cp(@stat_filepath, "#{File.dirname(filename)}/#{File.basename(filename, '.epw')}.stat") end + + # This method calculates annual global horizontal irradiance (GHI) + # @author sara.gilani@canada.ca + # This value has been used as 'Irradiance, Global, Annual' (IGA) (kWh/m2.yr) for PHIUS performance targets calculation. + def get_annual_ghi + sum_hourly_ghi = 0.0 + scan if @filearray.nil? + @filearray.each do |line| + unless line.first =~ /\D(.*)/ + ghi_hourly = line[GLOBAL_HORIZONTAL_RADIATION].to_f + sum_hourly_ghi += ghi_hourly + end + end + annual_ghi_kwh_per_m_sq = sum_hourly_ghi / 1000.0 + return annual_ghi_kwh_per_m_sq + end + + # This method calculates global horizontal irradiance on heating design day + # @author sara.gilani@canada.ca + # This value has been used as 'Irradiance, Global, at the heating design condition' (IGHL) for PHIUS performance targets calculation. + def get_ghi_on_heating_design_day + heating_design_day_number, cooling_design_day_number = get_heating_design_day_number + coldest_month = @heating_design_info[0].to_f + sum_hourly_ghi_on_heating_design_day = 0.0 + number_of_hours_with_sunshine = 0.0 + scan if @filearray.nil? + @filearray.each do |line| + unless line.first =~ /\D(.*)/ + if line[MONTH].to_f == coldest_month && line[DAY].to_f == heating_design_day_number.to_f && line[GLOBAL_HORIZONTAL_RADIATION].to_f > 0.0 + sum_hourly_ghi_on_heating_design_day += line[GLOBAL_HORIZONTAL_RADIATION].to_f + number_of_hours_with_sunshine += 1.0 + end + end + end + ghi_on_heating_design_day_w_per_m_sq = sum_hourly_ghi_on_heating_design_day / number_of_hours_with_sunshine + return ghi_on_heating_design_day_w_per_m_sq + end + + # This method calculates global horizontal irradiance on cooling design day + # @author sara.gilani@canada.ca + # This value has been used as 'Irradiance, Global, at the cooling design condition' (IGHL) for PHIUS performance targets calculation. + def get_ghi_on_cooling_design_day + heating_design_day_number, cooling_design_day_number = get_heating_design_day_number + hottest_month = @cooling_design_info[0].to_f + sum_hourly_ghi_on_cooling_design_day = 0.0 + number_of_hours_with_sunshine = 0.0 + scan if @filearray.nil? + @filearray.each do |line| + unless line.first =~ /\D(.*)/ + if line[MONTH].to_f == hottest_month && line[DAY].to_f == cooling_design_day_number.to_f && line[GLOBAL_HORIZONTAL_RADIATION].to_f > 0.0 + sum_hourly_ghi_on_cooling_design_day += line[GLOBAL_HORIZONTAL_RADIATION].to_f + number_of_hours_with_sunshine += 1.0 + end + end + end + ghi_on_cooling_design_day_w_per_m_sq = sum_hourly_ghi_on_cooling_design_day / number_of_hours_with_sunshine + return ghi_on_cooling_design_day_w_per_m_sq + end + + # This method finds which day of the coldest/hottest month is the heating/cooling design day + # @author sara.gilani@canada.ca + def get_heating_design_day_number + heating_design_day_number = nil + cooling_design_day_number = nil + # which day of the coldest month is the heating design day + @ddy_file.getObjectsByType('OS:SizingPeriod:DesignDay'.to_IddObjectType).each do |d| + if d.name.to_s.include?('Htg 99.6% Condns DB') + idf_object = d.idfObject + idf_object.dataFields.each do |data_field| + design_day_field = idf_object.fieldComment(data_field, true) + if design_day_field.to_s.include?('Day of Month') + heating_design_day_number = idf_object.getString(data_field) + heating_design_day_number = heating_design_day_number.to_s + # puts "heating_design_day_number is #{heating_design_day_number}" + end + end + end + + # which day of the hottest month is the cooling design day + if d.name.to_s.include?('Clg .4% Condns DB=>MWB') + idf_object = d.idfObject + idf_object.dataFields.each do |data_field| + design_day_field = idf_object.fieldComment(data_field, true) + if design_day_field.to_s.include?('Day of Month') + cooling_design_day_number = idf_object.getString(data_field) + cooling_design_day_number = cooling_design_day_number.to_s + # puts "cooling_design_day_number is #{cooling_design_day_number}" + end + end + end + end + return heating_design_day_number, cooling_design_day_number + end #def get_heating_design_day_number + + # This method calculates dehumidification degree days (DDD) + # @author sara.gilani@canada.ca + # Reference: ASHRAE Handbook - Fundamentals > CHAPTER 1. PSYCHROMETRICS + def calculate_humidity_ratio + # coefficients for the calculation of pws (Reference: ASHRAE Handbook - Fundamentals > CHAPTER 1. PSYCHROMETRICS) + c1 = -5.6745359E+03 + c2 = 6.3925247E+00 + c3 = -9.6778430E-03 + c4 = 6.2215701E-07 + c5 = 2.0747825E-09 + c6 = -9.4840240E-13 + c7 = 4.1635019E+00 + c8 = -5.8002206E+03 + c9 = 1.3914993E+00 + c10 = -4.8640239E-02 + c11 = 4.1764768E-05 + c12 = -1.4452093E-08 + c13 = 6.5459673E+00 + sum_w = 0.0 + w_base = 0.010 # Note: this is base for the calculation of 'dehumidification degree days' (REF: Wright, L. (2019). Setting the Heating/Cooling Performance Criteria for the PHIUS 2018 Passive Building Standard. In ASHRAE Topical Conference Proceedings, pp. 399-409) + ddd = 0.0 # dehimudifation degree-days + convert_c_to_k = 273.15 # convert degree C to kelvins (k) + + scan if @filearray.nil? + @filearray.each do |line| + unless line.first =~ /\D(.*)/ + # Note: the below Step 1, 2, 3, and 4 are the steps for the calculation of humidity ratio as per ASHRAE Handbook - Fundamentals > CHAPTER 1. PSYCHROMETRICS + # Step 1: calculate pws (SATURATION_PRESSURE_OF_WATER_VAPOR), [Pascal] + if line[DRY_BULB_TEMPERATURE].to_f <= 0.0 + line[CALCULATED_SATURATION_PRESSURE_OF_WATER_VAPOR] = c1 / (line[DRY_BULB_TEMPERATURE].to_f + convert_c_to_k) + + c2 + + c3 * (line[DRY_BULB_TEMPERATURE].to_f + convert_c_to_k) + + c4 * (line[DRY_BULB_TEMPERATURE].to_f + convert_c_to_k)**2 + + c5 * (line[DRY_BULB_TEMPERATURE].to_f + convert_c_to_k)**3 + + c6 * (line[DRY_BULB_TEMPERATURE].to_f + convert_c_to_k)**4 + + c7 * Math.log((line[DRY_BULB_TEMPERATURE].to_f + convert_c_to_k), Math.exp(1)) # 2.718281828459 + line[CALCULATED_SATURATION_PRESSURE_OF_WATER_VAPOR] = (Math.exp(1))**(line[CALCULATED_SATURATION_PRESSURE_OF_WATER_VAPOR].to_f) + else # if line[DRY_BULB_TEMPERATURE].to_f > 0.0 + line[CALCULATED_SATURATION_PRESSURE_OF_WATER_VAPOR] = c8 / (line[DRY_BULB_TEMPERATURE].to_f + convert_c_to_k) + + c9 + + c10 * (line[DRY_BULB_TEMPERATURE].to_f + convert_c_to_k) + + c11 * (line[DRY_BULB_TEMPERATURE].to_f + convert_c_to_k)**2 + + c12 * (line[DRY_BULB_TEMPERATURE].to_f + convert_c_to_k)**3 + + c13 * Math.log((line[DRY_BULB_TEMPERATURE].to_f + convert_c_to_k), Math.exp(1)) + line[CALCULATED_SATURATION_PRESSURE_OF_WATER_VAPOR] = (Math.exp(1))**(line[CALCULATED_SATURATION_PRESSURE_OF_WATER_VAPOR].to_f) + end + + # Step 2: calculate pw (PARTIAL_PRESSURE_OF_WATER_VAPOR), [Pascal] + # Relative Humidity (RH) = 100 * pw / pws + line[CALCULATED_PARTIAL_PRESSURE_OF_WATER_VAPOR] = line[CALCULATED_SATURATION_PRESSURE_OF_WATER_VAPOR].to_f * line[RELATIVE_HUMIDITY].to_f / 100.0 + + # Step 3: calculate p (TOTAL_MIXTURE_PRESSURE), [Pascal] + line[CALCULATED_TOTAL_MIXTURE_PRESSURE] = line[CALCULATED_PARTIAL_PRESSURE_OF_WATER_VAPOR].to_f + line[ATMOSPHERIC_STATION_PRESSURE].to_f + + # Step 4: calculate w (HUMIDITY_RATIO) + line[CALCULATED_HUMIDITY_RATIO] = 0.621945 * line[CALCULATED_PARTIAL_PRESSURE_OF_WATER_VAPOR].to_f / (line[CALCULATED_TOTAL_MIXTURE_PRESSURE].to_f - line[CALCULATED_PARTIAL_PRESSURE_OF_WATER_VAPOR].to_f) + + #----------------------------------------------------------------------------------------------------------- + # calculate daily average of w AND its difference from base + if line[HOUR].to_f < 24.0 + sum_w += line[CALCULATED_HUMIDITY_RATIO].to_f + line[CALCULATED_HUMIDITY_RATIO_AVG_DAILY] = 0.0 + elsif line[HOUR].to_f == 24.0 + line[CALCULATED_HUMIDITY_RATIO_AVG_DAILY] = (sum_w + line[CALCULATED_HUMIDITY_RATIO].to_f) / 24.0 + if line[CALCULATED_HUMIDITY_RATIO_AVG_DAILY].to_f > w_base + line[CALCULATED_HUMIDITY_RATIO_AVG_DAILY_DIFF_BASE] = line[CALCULATED_HUMIDITY_RATIO_AVG_DAILY].to_f - w_base + else + line[CALCULATED_HUMIDITY_RATIO_AVG_DAILY_DIFF_BASE] = 0.0 + end + sum_w = 0.0 + end + + ddd += line[CALCULATED_HUMIDITY_RATIO_AVG_DAILY_DIFF_BASE].to_f + + end # unless line.first =~ /\D(.*)/ + end # @filearray.each do |line| + # puts @filearray + return ddd + end # def calculate_humidity_ratio + end # Environment end end