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