example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/airflow.rb in urbanopt-cli-0.7.1 vs example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/airflow.rb in urbanopt-cli-0.8.0
- old
+ new
@@ -9,18 +9,20 @@
@runner = runner
@spaces = spaces
@year = hpxml.header.sim_calendar_year
@infil_volume = hpxml.air_infiltration_measurements.select { |i| !i.infiltration_volume.nil? }[0].infiltration_volume
- @infil_height = hpxml.inferred_infiltration_height(@infil_volume)
+ @infil_height = hpxml.air_infiltration_measurements.select { |i| !i.infiltration_height.nil? }[0].infiltration_height
@living_space = spaces[HPXML::LocationLivingSpace]
@living_zone = @living_space.thermalZone.get
@nbeds = nbeds
@ncfl_ag = ncfl_ag
@eri_version = eri_version
@apply_ashrae140_assumptions = apply_ashrae140_assumptions
@cfa = cfa
+ @cooking_range_in_cond_space = hpxml.cooking_ranges.empty? ? true : HPXML::conditioned_locations_this_unit.include?(hpxml.cooking_ranges[0].location)
+ @clothes_dryer_in_cond_space = hpxml.clothes_dryers.empty? ? true : HPXML::conditioned_locations_this_unit.include?(hpxml.clothes_dryers[0].location)
# Global sensors
@pbar_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Site Outdoor Air Barometric Pressure')
@pbar_sensor.setName('out pb s')
@@ -56,21 +58,21 @@
if vent_fan.used_for_whole_building_ventilation
vent_fans_mech << vent_fan
elsif vent_fan.used_for_seasonal_cooling_load_reduction
vent_fans_whf << vent_fan
- elsif vent_fan.used_for_local_ventilation && vent_fan.fan_location == HPXML::LocationKitchen
- vent_fans_kitchen << vent_fan
- elsif vent_fan.used_for_local_ventilation && vent_fan.fan_location == HPXML::LocationBath
- vent_fans_bath << vent_fan
- else
- @runner.registerWarning("Unexpected ventilation fan '#{vent_fan.id}'. The fan will not be modeled.")
+ elsif vent_fan.used_for_local_ventilation
+ if vent_fan.fan_location == HPXML::LocationKitchen
+ vent_fans_kitchen << vent_fan
+ elsif vent_fan.fan_location == HPXML::LocationBath
+ vent_fans_bath << vent_fan
+ end
end
end
- # Vented clothes dryers in conditioned space
- vented_dryers = hpxml.clothes_dryers.select { |cd| cd.is_vented && cd.vented_flow_rate.to_f > 0 && HPXML::conditioned_locations_this_unit.include?(cd.location) }
+ # Vented clothes dryers
+ vented_dryers = hpxml.clothes_dryers.select { |cd| cd.is_vented && cd.vented_flow_rate.to_f > 0 }
# Initialization
initialize_cfis(model, vent_fans_mech, airloop_map)
model.getAirLoopHVACs.each do |air_loop|
initialize_fan_objects(model, air_loop)
@@ -80,11 +82,11 @@
end
# Apply ducts
duct_systems.each do |ducts, object|
- apply_ducts(model, ducts, object)
+ apply_ducts(model, ducts, object, vent_fans_mech)
end
# Apply infiltration/ventilation
set_wind_speed_correction(model, hpxml.site)
@@ -94,20 +96,22 @@
vented_attic = nil
hpxml.attics.each do |attic|
next unless attic.attic_type == HPXML::AtticTypeVented
vented_attic = attic
+ break
end
vented_crawl = nil
hpxml.foundations.each do |foundation|
next unless foundation.foundation_type == HPXML::FoundationTypeCrawlspaceVented
vented_crawl = foundation
+ break
end
apply_natural_ventilation_and_whole_house_fan(model, weather, hpxml.site, vent_fans_whf, open_window_area, clg_ssn_sensor)
- apply_infiltration_and_ventilation_fans(model, weather, hpxml.site, vent_fans_mech, vent_fans_kitchen, vent_fans_bath, vented_dryers,
+ apply_infiltration_and_ventilation_fans(model, @runner, weather, hpxml.site, vent_fans_mech, vent_fans_kitchen, vent_fans_bath, vented_dryers,
hpxml.building_construction.has_flue_or_chimney, hpxml.air_infiltration_measurements,
vented_attic, vented_crawl, clg_ssn_sensor, schedules_file)
end
def self.get_default_fraction_of_windows_operable()
@@ -149,11 +153,11 @@
end
def self.get_default_mech_vent_flow_rate(hpxml, vent_fan, infil_measurements, weather, infil_a_ext, cfa, nbeds)
# Calculates Qfan cfm requirement per ASHRAE 62.2-2019
infil_volume = infil_measurements[0].infiltration_volume
- infil_height = hpxml.inferred_infiltration_height(infil_volume)
+ infil_height = infil_measurements[0].infiltration_height
infil_a_ext = 1.0
if [HPXML::ResidentialTypeSFA, HPXML::ResidentialTypeApartment].include? hpxml.building_construction.residential_facility_type
tot_cb_area, ext_cb_area = hpxml.compartmentalization_boundary_areas()
infil_a_ext = ext_cb_area / tot_cb_area
@@ -416,11 +420,11 @@
vent_program.addLine(" Set #{whf_elec_actuator.name} = 0")
vent_program.addLine('EndIf')
manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
manager.setName("#{vent_program.name} calling manager")
- manager.setCallingPoint('BeginTimestepBeforePredictor')
+ manager.setCallingPoint('BeginZoneTimestepAfterInitHeatBalance')
manager.addProgram(vent_program)
end
def self.create_nv_and_whf_avail_sch(model, obj_name, num_days_per_week)
avail_sch = OpenStudio::Model::ScheduleRuleset.new(model)
@@ -593,11 +597,11 @@
else
fail "Unexpected fan: #{supply_fan.name}"
end
end
- def self.apply_ducts(model, ducts, object)
+ def self.apply_ducts(model, ducts, object, vent_fans_mech)
ducts.each do |duct|
duct.rvalue = get_duct_insulation_rvalue(duct.rvalue, duct.side) # Convert from nominal to actual R-value
if not duct.loc_schedule.nil?
# Pass MF space temperature schedule name
duct.location = duct.loc_schedule.name.to_s
@@ -1058,14 +1062,15 @@
duct_program.addLine("Set #{duct_actuators['liv_to_dz_flow_rate'].name} = #{duct_vars['liv_to_dz_flow_rate'].name}")
end
if @cfis_airloop.values.include? object
- # Calculate CFIS duct losses
+ # Calculate additional CFIS duct losses during fan-only mode
cfis_id = @cfis_airloop.key(object)
+ vent_mech = vent_fans_mech.select { |vfm| vfm.id == cfis_id }[0]
duct_program.addLine("If #{@cfis_f_damper_extra_open_var[cfis_id].name} > 0")
- duct_program.addLine(" Set cfis_m3s = (#{@fan_mfr_max_var[object].name} / 1.16097654)") # Density of 1.16097654 was back calculated using E+ results
+ duct_program.addLine(" Set cfis_m3s = (#{@fan_mfr_max_var[object].name} * #{vent_mech.cfis_vent_mode_airflow_fraction} / 1.16097654)") # Density of 1.16097654 was back calculated using E+ results
duct_program.addLine(" Set #{@fan_rtf_var[object].name} = #{@cfis_f_damper_extra_open_var[cfis_id].name}") # Need to use global vars to sync duct_program and infiltration program of different calling points
duct_program.addLine(" Set #{ah_vfr_var.name} = #{@fan_rtf_var[object].name}*cfis_m3s")
duct_program.addLine(" Set rho_in = (@RhoAirFnPbTdbW #{@pbar_sensor.name} #{@tin_sensor.name} #{@win_sensor.name})")
duct_program.addLine(" Set #{ah_mfr_var.name} = #{ah_vfr_var.name} * rho_in")
duct_program.addLine(" Set #{ah_tout_var.name} = #{ra_t_sensor.name}")
@@ -1209,75 +1214,69 @@
ach = get_default_unvented_space_ach()
cfm = ach / UnitConversions.convert(1.0, 'hr', 'min') * volume
apply_infiltration_to_unconditioned_space(model, space, ach, nil, nil, nil)
end
- def self.apply_local_ventilation(model, vent_object_array, obj_type_name)
- obj_sch_sensors = {}
- vent_object_array.each_with_index do |vent_object, index|
- daily_sch = [0.0] * 24
- obj_name = "#{obj_type_name} #{index}"
- remaining_hrs = vent_object.hours_in_operation
- for hr in 1..(vent_object.hours_in_operation.ceil)
- if remaining_hrs >= 1
- daily_sch[(vent_object.start_hour + hr - 1) % 24] = 1.0
- else
- daily_sch[(vent_object.start_hour + hr - 1) % 24] = remaining_hrs
- end
- remaining_hrs -= 1
+ def self.apply_local_ventilation(model, vent_object, obj_type_name, index)
+ daily_sch = [0.0] * 24
+ obj_name = "#{obj_type_name} #{index}"
+ remaining_hrs = vent_object.hours_in_operation
+ for hr in 1..(vent_object.hours_in_operation.ceil)
+ if remaining_hrs >= 1
+ daily_sch[(vent_object.start_hour + hr - 1) % 24] = 1.0
+ else
+ daily_sch[(vent_object.start_hour + hr - 1) % 24] = remaining_hrs
end
- obj_sch = HourlyByMonthSchedule.new(model, "#{obj_name} schedule", [daily_sch] * 12, [daily_sch] * 12, Constants.ScheduleTypeLimitsFraction, false)
- obj_sch_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
- obj_sch_sensor.setName("#{obj_name} sch s")
- obj_sch_sensor.setKeyName(obj_sch.schedule.name.to_s)
- obj_sch_sensors[vent_object.id] = obj_sch_sensor
-
- equip_def = OpenStudio::Model::ElectricEquipmentDefinition.new(model)
- equip_def.setName(obj_name)
- equip = OpenStudio::Model::ElectricEquipment.new(equip_def)
- equip.setName(obj_name)
- equip.setSpace(@living_space)
- equip_def.setDesignLevel(vent_object.fan_power * vent_object.quantity)
- equip_def.setFractionRadiant(0)
- equip_def.setFractionLatent(0)
- equip_def.setFractionLost(1)
- equip.setSchedule(obj_sch.schedule)
- equip.setEndUseSubcategory(Constants.ObjectNameMechanicalVentilation)
+ remaining_hrs -= 1
end
+ obj_sch = HourlyByMonthSchedule.new(model, "#{obj_name} schedule", [daily_sch] * 12, [daily_sch] * 12, Constants.ScheduleTypeLimitsFraction, false)
+ obj_sch_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
+ obj_sch_sensor.setName("#{obj_name} sch s")
+ obj_sch_sensor.setKeyName(obj_sch.schedule.name.to_s)
- return obj_sch_sensors
+ equip_def = OpenStudio::Model::ElectricEquipmentDefinition.new(model)
+ equip_def.setName(obj_name)
+ equip = OpenStudio::Model::ElectricEquipment.new(equip_def)
+ equip.setName(obj_name)
+ equip.setSpace(@living_space)
+ equip_def.setDesignLevel(vent_object.fan_power * vent_object.quantity)
+ equip_def.setFractionRadiant(0)
+ equip_def.setFractionLatent(0)
+ equip_def.setFractionLost(1)
+ equip.setSchedule(obj_sch.schedule)
+ equip.setEndUseSubcategory(Constants.ObjectNameMechanicalVentilation)
+
+ return obj_sch_sensor
end
- def self.apply_dryer_exhaust(model, vented_dryers, schedules_file)
- obj_sch_sensors = {}
- obj_type_name = Constants.ObjectNameClothesDryerExhaust
- vented_dryers.each_with_index do |vented_dryer, index|
- obj_name = "#{obj_type_name} #{index}"
+ def self.apply_dryer_exhaust(model, runner, vented_dryer, schedules_file, index)
+ obj_name = "#{Constants.ObjectNameClothesDryerExhaust} #{index}"
- if not schedules_file.nil?
- obj_sch = schedules_file.create_schedule_file(col_name: 'clothes_dryer')
- obj_sch_name = 'clothes_dryer'
- full_load_hrs = schedules_file.annual_equivalent_full_load_hrs(col_name: 'clothes_dryer')
- else
- cd_weekday_sch = vented_dryer.weekday_fractions
- cd_weekend_sch = vented_dryer.weekend_fractions
- cd_monthly_sch = vented_dryer.monthly_multipliers
- obj_sch = MonthWeekdayWeekendSchedule.new(model, Constants.ObjectNameClothesDryer, cd_weekday_sch, cd_weekend_sch, cd_monthly_sch, Constants.ScheduleTypeLimitsFraction)
- obj_sch = obj_sch.schedule
- obj_sch_name = obj_sch.name.to_s
- full_load_hrs = Schedule.annual_equivalent_full_load_hrs(@year, obj_sch)
- end
- # Assume standard dryer exhaust runs 1 hr/day per BA HSP
- cfm_mult = Constants.NumDaysInYear(@year) * vented_dryer.usage_multiplier / full_load_hrs
-
- obj_sch_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
- obj_sch_sensor.setName("#{obj_name} sch s")
- obj_sch_sensor.setKeyName(obj_sch_name)
- obj_sch_sensors[vented_dryer.id] = [obj_sch_sensor, cfm_mult]
+ # Create schedule
+ obj_sch = nil
+ if not schedules_file.nil?
+ obj_sch_name = SchedulesFile::ColumnClothesDryer
+ obj_sch = schedules_file.create_schedule_file(col_name: obj_sch_name)
+ full_load_hrs = schedules_file.annual_equivalent_full_load_hrs(col_name: obj_sch_name)
end
+ if obj_sch.nil?
+ cd_weekday_sch = vented_dryer.weekday_fractions
+ cd_weekend_sch = vented_dryer.weekend_fractions
+ cd_monthly_sch = vented_dryer.monthly_multipliers
+ obj_sch = MonthWeekdayWeekendSchedule.new(model, Constants.ObjectNameClothesDryer, cd_weekday_sch, cd_weekend_sch, cd_monthly_sch, Constants.ScheduleTypeLimitsFraction)
+ obj_sch = obj_sch.schedule
+ obj_sch_name = obj_sch.name.to_s
+ full_load_hrs = Schedule.annual_equivalent_full_load_hrs(@year, obj_sch)
+ end
+ # Assume standard dryer exhaust runs 1 hr/day per BA HSP
+ cfm_mult = Constants.NumDaysInYear(@year) * vented_dryer.usage_multiplier / full_load_hrs
- return obj_sch_sensors
+ obj_sch_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value')
+ obj_sch_sensor.setName("#{obj_name} sch s")
+ obj_sch_sensor.setKeyName(obj_sch_name)
+
+ return obj_sch_sensor, cfm_mult
end
def self.calc_hrv_erv_effectiveness(vent_mech_fans)
# Create the mapping between mech vent instance and the effectiveness results
hrv_erv_effectiveness_map = {}
@@ -1468,30 +1467,42 @@
program.addLine('Set ZoneAirEnth = (@HFnTdbW ZoneTemp ZoneW)')
return fan_sens_load_actuator, fan_lat_load_actuator
end
- def self.apply_infiltration_adjustment(infil_program, vent_fans_kitchen, vent_fans_bath, vented_dryers, sup_cfm_tot, exh_cfm_tot, bal_cfm_tot, erv_hrv_cfm_tot,
- infil_flow_actuator, range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map)
+ def self.apply_infiltration_adjustment_to_conditioned(model, runner, infil_program, vent_fans_kitchen, vent_fans_bath, vented_dryers,
+ sup_cfm_tot, exh_cfm_tot, bal_cfm_tot, erv_hrv_cfm_tot, infil_flow_actuator, schedules_file)
infil_program.addLine('Set Qrange = 0')
- vent_fans_kitchen.each do |vent_kitchen|
- infil_program.addLine("Set Qrange = Qrange + #{UnitConversions.convert(vent_kitchen.flow_rate * vent_kitchen.quantity, 'cfm', 'm^3/s').round(4)} * #{range_sch_sensors_map[vent_kitchen.id].name}")
+ vent_fans_kitchen.each_with_index do |vent_kitchen, index|
+ # Electricity impact
+ obj_sch_sensor = apply_local_ventilation(model, vent_kitchen, Constants.ObjectNameMechanicalVentilationRangeFan, index)
+ next unless @cooking_range_in_cond_space
+
+ # Infiltration impact
+ infil_program.addLine("Set Qrange = Qrange + #{UnitConversions.convert(vent_kitchen.flow_rate * vent_kitchen.quantity, 'cfm', 'm^3/s').round(5)} * #{obj_sch_sensor.name}")
end
infil_program.addLine('Set Qbath = 0')
- vent_fans_bath.each do |vent_bath|
- infil_program.addLine("Set Qbath = Qbath + #{UnitConversions.convert(vent_bath.flow_rate * vent_bath.quantity, 'cfm', 'm^3/s').round(4)} * #{bath_sch_sensors_map[vent_bath.id].name}")
+ vent_fans_bath.each_with_index do |vent_bath, index|
+ # Electricity impact
+ obj_sch_sensor = apply_local_ventilation(model, vent_bath, Constants.ObjectNameMechanicalVentilationBathFan, index)
+ # Infiltration impact
+ infil_program.addLine("Set Qbath = Qbath + #{UnitConversions.convert(vent_bath.flow_rate * vent_bath.quantity, 'cfm', 'm^3/s').round(5)} * #{obj_sch_sensor.name}")
end
infil_program.addLine('Set Qdryer = 0')
- vented_dryers.each do |vented_dryer|
- infil_program.addLine("Set Qdryer = Qdryer + #{UnitConversions.convert(vented_dryer.vented_flow_rate * dryer_exhaust_sch_sensors_map[vented_dryer.id][1], 'cfm', 'm^3/s').round(5)} * #{dryer_exhaust_sch_sensors_map[vented_dryer.id][0].name}")
+ vented_dryers.each_with_index do |vented_dryer, index|
+ next unless @clothes_dryer_in_cond_space
+
+ # Infiltration impact
+ obj_sch_sensor, cfm_mult = apply_dryer_exhaust(model, runner, vented_dryer, schedules_file, index)
+ infil_program.addLine("Set Qdryer = Qdryer + #{UnitConversions.convert(vented_dryer.vented_flow_rate * cfm_mult, 'cfm', 'm^3/s').round(5)} * #{obj_sch_sensor.name}")
end
- infil_program.addLine("Set QWHV_sup = #{UnitConversions.convert(sup_cfm_tot, 'cfm', 'm^3/s').round(4)}")
- infil_program.addLine("Set QWHV_exh = #{UnitConversions.convert(exh_cfm_tot, 'cfm', 'm^3/s').round(4)}")
- infil_program.addLine("Set QWHV_bal_erv_hrv = #{UnitConversions.convert(bal_cfm_tot + erv_hrv_cfm_tot, 'cfm', 'm^3/s').round(4)}")
+ infil_program.addLine("Set QWHV_sup = #{UnitConversions.convert(sup_cfm_tot, 'cfm', 'm^3/s').round(5)}")
+ infil_program.addLine("Set QWHV_exh = #{UnitConversions.convert(exh_cfm_tot, 'cfm', 'm^3/s').round(5)}")
+ infil_program.addLine("Set QWHV_bal_erv_hrv = #{UnitConversions.convert(bal_cfm_tot + erv_hrv_cfm_tot, 'cfm', 'm^3/s').round(5)}")
infil_program.addLine('Set Qexhaust = Qrange + Qbath + Qdryer + QWHV_exh + QWHV_bal_erv_hrv')
infil_program.addLine('Set Qsupply = QWHV_sup + QWHV_bal_erv_hrv + QWHV_cfis_oa')
infil_program.addLine('Set Qfan = (@Max Qexhaust Qsupply)')
if Constants.ERIVersions.index(@eri_version) >= Constants.ERIVersions.index('2019')
@@ -1529,14 +1540,16 @@
infil_program.addLine('Set ZoneInTemp = OASupInTemp')
if not vent_mech_erv_hrv_tot.empty?
# ERV/HRV EMS load model
# E+ ERV model is using standard density for MFR calculation, caused discrepancy with other system types.
# Therefore ERV is modeled within EMS infiltration program
+ infil_program.addLine("If #{q_var} > 0")
vent_mech_erv_hrv_tot.each do |vent_fan|
- infil_program.addLine("Set Effectiveness_Sens = Effectiveness_Sens + #{UnitConversions.convert(vent_fan.average_oa_unit_flow_rate, 'cfm', 'm^3/s').round(4)} / #{q_var} * #{hrv_erv_effectiveness_map[vent_fan][:vent_mech_sens_eff]}")
- infil_program.addLine("Set Effectiveness_Lat = Effectiveness_Lat + #{UnitConversions.convert(vent_fan.average_oa_unit_flow_rate, 'cfm', 'm^3/s').round(4)} / #{q_var} * #{hrv_erv_effectiveness_map[vent_fan][:vent_mech_lat_eff]}")
+ infil_program.addLine(" Set Effectiveness_Sens = Effectiveness_Sens + #{UnitConversions.convert(vent_fan.average_oa_unit_flow_rate, 'cfm', 'm^3/s').round(4)} / #{q_var} * #{hrv_erv_effectiveness_map[vent_fan][:vent_mech_sens_eff]}")
+ infil_program.addLine(" Set Effectiveness_Lat = Effectiveness_Lat + #{UnitConversions.convert(vent_fan.average_oa_unit_flow_rate, 'cfm', 'm^3/s').round(4)} / #{q_var} * #{hrv_erv_effectiveness_map[vent_fan][:vent_mech_lat_eff]}")
end
+ infil_program.addLine('EndIf')
infil_program.addLine('Set ERVCpMin = (@Min OASupCp ZoneCp)')
infil_program.addLine('Set ERVSupOutTemp = OASupInTemp + ERVCpMin/OASupCp * Effectiveness_Sens * (ZoneTemp - OASupInTemp)')
infil_program.addLine('Set ERVSupOutW = OASupInW + ERVCpMin/OASupCp * Effectiveness_Lat * (ZoneW - OASupInW)')
infil_program.addLine('Set ERVSupOutEnth = (@HFnTdbW ERVSupOutTemp ERVSupOutW)')
infil_program.addLine('Set ERVSensHeatTrans = Fan_MFR * OASupCp * (ERVSupOutTemp - OASupInTemp)')
@@ -1587,11 +1600,11 @@
infil_program.addLine(' If ZoneInTemp < HtgStp')
infil_program.addLine(' Set FanSensToSpt = Fan_MFR * ZoneCp * (ZoneInTemp - HtgStp)')
infil_program.addLine(" Set PreHeatingWatt = (-FanSensToSpt) * #{f_preheat.preheating_fraction_load_served}")
infil_program.addLine(" Set #{fan_sens_load_actuator.name} = #{fan_sens_load_actuator.name} + PreHeatingWatt")
- infil_program.addLine(" Set #{fan_lat_load_actuator.name} = #{fan_lat_load_actuator.name} - FanLatToLv") # Fixme:Does this assumption still apply?
+ infil_program.addLine(" Set #{fan_lat_load_actuator.name} = #{fan_lat_load_actuator.name} - FanLatToLv")
infil_program.addLine(' Else')
infil_program.addLine(' Set PreHeatingWatt = 0.0')
infil_program.addLine(' EndIf')
infil_program.addLine('Else')
infil_program.addLine(' Set PreHeatingWatt = 0.0')
@@ -1623,12 +1636,12 @@
infil_program.addLine('EndIf')
infil_program.addLine("Set #{clg_energy_actuator.name} = PreCoolingWatt / #{f_precool.precooling_efficiency_cop}")
end
end
- def self.apply_infiltration_and_mechanical_ventilation(model, site, vent_fans_mech, living_ach50, living_const_ach, weather, vent_fans_kitchen, vent_fans_bath, vented_dryers,
- range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map, has_flue_chimney, clg_ssn_sensor)
+ def self.apply_infiltration_ventilation_to_conditioned(model, runner, site, vent_fans_mech, living_ach50, living_const_ach, weather, vent_fans_kitchen, vent_fans_bath, vented_dryers,
+ has_flue_chimney, clg_ssn_sensor, schedules_file)
# Categorize fans into different types
vent_mech_preheat = vent_fans_mech.select { |vent_mech| (not vent_mech.preheating_efficiency_cop.nil?) }
vent_mech_precool = vent_fans_mech.select { |vent_mech| (not vent_mech.precooling_efficiency_cop.nil?) }
vent_mech_shared = vent_fans_mech.select { |vent_mech| vent_mech.is_shared_system }
@@ -1675,23 +1688,23 @@
# Living Space Infiltration Calculation/Program
infil_program = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
infil_program.setName(Constants.ObjectNameInfiltration + ' program')
# Calculate infiltration without adjustment by ventilation
- apply_infiltration_to_living(site, living_ach50, living_const_ach, infil_program, weather, has_flue_chimney)
+ apply_infiltration_to_conditioned(site, living_ach50, living_const_ach, infil_program, weather, has_flue_chimney)
# Common variable and load actuators across multiple mech vent calculations, create only once
fan_sens_load_actuator, fan_lat_load_actuator = setup_mech_vent_vars_actuators(model: model, program: infil_program)
# Apply CFIS
infil_program.addLine("Set #{cfis_fan_actuator.name} = 0.0")
apply_cfis(infil_program, vent_mech_cfis_tot, cfis_fan_actuator)
# Calculate Qfan, Qinf_adj
# Calculate adjusted infiltration based on mechanical ventilation system
- apply_infiltration_adjustment(infil_program, vent_fans_kitchen, vent_fans_bath, vented_dryers, sup_cfm_tot, exh_cfm_tot, bal_cfm_tot, erv_hrv_cfm_tot,
- infil_flow_actuator, range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map)
+ apply_infiltration_adjustment_to_conditioned(model, runner, infil_program, vent_fans_kitchen, vent_fans_bath, vented_dryers,
+ sup_cfm_tot, exh_cfm_tot, bal_cfm_tot, erv_hrv_cfm_tot, infil_flow_actuator, schedules_file)
# Address load of Qfan (Qload)
# Qload as variable for tracking outdoor air flow rate, excluding recirculation
infil_program.addLine('Set Qload = Qfan')
vent_fans_mech.each do |f|
@@ -1703,15 +1716,15 @@
# Address preconditioning
calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_mech_precool, hrv_erv_effectiveness_map, fan_sens_load_actuator, fan_lat_load_actuator, clg_ssn_sensor)
program_calling_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
program_calling_manager.setName("#{infil_program.name} calling manager")
- program_calling_manager.setCallingPoint('BeginTimestepBeforePredictor')
+ program_calling_manager.setCallingPoint('BeginZoneTimestepAfterInitHeatBalance')
program_calling_manager.addProgram(infil_program)
end
- def self.apply_infiltration_and_ventilation_fans(model, weather, site, vent_fans_mech, vent_fans_kitchen, vent_fans_bath, vented_dryers,
+ def self.apply_infiltration_and_ventilation_fans(model, runner, weather, site, vent_fans_mech, vent_fans_kitchen, vent_fans_bath, vented_dryers,
has_flue_chimney, air_infils, vented_attic, vented_crawl, clg_ssn_sensor, schedules_file)
# Get living space infiltration
living_ach50 = nil
living_const_ach = nil
air_infils.each do |air_infil|
@@ -1737,22 +1750,15 @@
apply_infiltration_to_vented_crawlspace(model, weather, vented_crawl)
apply_infiltration_to_unvented_crawlspace(model, weather)
apply_infiltration_to_vented_attic(model, weather, site, vented_attic)
apply_infiltration_to_unvented_attic(model, weather, site)
- # Local ventilation
- range_sch_sensors_map = apply_local_ventilation(model, vent_fans_kitchen, Constants.ObjectNameMechanicalVentilationRangeFan)
- bath_sch_sensors_map = apply_local_ventilation(model, vent_fans_bath, Constants.ObjectNameMechanicalVentilationBathFan)
-
- # Clothes dryer exhaust
- dryer_exhaust_sch_sensors_map = apply_dryer_exhaust(model, vented_dryers, schedules_file)
-
- # Get mechanical ventilation
- apply_infiltration_and_mechanical_ventilation(model, site, vent_fans_mech, living_ach50, living_const_ach, weather, vent_fans_kitchen, vent_fans_bath, vented_dryers,
- range_sch_sensors_map, bath_sch_sensors_map, dryer_exhaust_sch_sensors_map, has_flue_chimney, clg_ssn_sensor)
+ # Infiltration/ventilation for conditioned space
+ apply_infiltration_ventilation_to_conditioned(model, runner, site, vent_fans_mech, living_ach50, living_const_ach, weather, vent_fans_kitchen, vent_fans_bath, vented_dryers,
+ has_flue_chimney, clg_ssn_sensor, schedules_file)
end
- def self.apply_infiltration_to_living(site, living_ach50, living_const_ach, infil_program, weather, has_flue_chimney)
+ def self.apply_infiltration_to_conditioned(site, living_ach50, living_const_ach, infil_program, weather, has_flue_chimney)
site_ap = site.additional_properties
if living_ach50.to_f > 0
# Based on "Field Validation of Algebraic Equations for Stack and
# Wind Driven Air Infiltration Calculations" by Walker and Wilson (1998)