-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ASHRAE 62.1 Simplified Procedure #1112
Conversation
…d Procedure MDP/system OA calculation for 90.1-2019.
# Apply multizone vav outdoor air method and | ||
# adjust multizone VAV damper positions | ||
# to achieve a system minimum ventilation effectiveness | ||
# of 0.6 per PNNL. Hard-size the resulting min OA | ||
# into the sizing:system object. | ||
# | ||
# return [Bool] returns true if successful, false if not | ||
# @todo move building-type-specific code to Prototype classes | ||
def air_loop_hvac_apply_multizone_vav_outdoor_air_sizing(air_loop_hvac) | ||
# First time adjustment: | ||
# Only applies to multi-zone vav systems | ||
# exclusion: for Outpatient: (1) both AHU1 and AHU2 in 'DOE Ref Pre-1980' and 'DOE Ref 1980-2004' | ||
# (2) AHU1 in 2004-2019 | ||
# TODO refactor: move building-type-specific code to Prototype classes | ||
if air_loop_hvac_multizone_vav_system?(air_loop_hvac) && !(air_loop_hvac.name.to_s.include? 'Outpatient F1') | ||
air_loop_hvac_adjust_minimum_vav_damper_positions(air_loop_hvac) | ||
end | ||
|
||
return true | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove redundant code.
# on a per zone basis, the zone primary airflow is | ||
# adjusted to removed the zone multiplier | ||
v_pz /= zone.multiplier.to_f | ||
|
||
# Set minimum damper position | ||
air_loop_hvac_set_minimum_damper_position(zone, [0.01, [1.5 * v_oz / v_pz, 1.0].min].max.round(3)) | ||
end | ||
|
||
# Occupant diversity (D): Ps / sum(Pz) | ||
# Current value is based on school prototypes | ||
# which are assumed to have the most diversity | ||
occ_diver_d = 0.66 | ||
|
||
# From ASHRAE Std 62.1-2019 Section 6.2.5.3 | ||
if occ_diver_d < 0.6 | ||
e_v = 0.88 * occ_diver_d + 0.22 | ||
else | ||
e_v = 0.75 | ||
end | ||
|
||
# Total system outdoor intake flow rate | ||
v_ot = v_ou / e_v | ||
v_ot_cfm = OpenStudio.convert(v_ot, 'm^3/s', 'cfm').get | ||
|
||
# Get maximum OA fraction schedule | ||
oa_ctrl = air_loop_hvac.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir | ||
max_oa_frac_sch = oa_ctrl.maximumFractionofOutdoorAirSchedule | ||
|
||
if !max_oa_frac_sch.is_initialized | ||
max_oa_frac_sch = OpenStudio::Model::ScheduleConstant.new(air_loop_hvac.model) | ||
max_oa_frac_sch.setName("#{air_loop_hvac.name}_MAX_OA_FRAC") | ||
max_oa_frac_sch.setValue(1.0) | ||
max_oa_frac_sch_type = 'Schedule:Constant' | ||
oa_ctrl.setMaximumFractionofOutdoorAirSchedule(max_oa_frac_sch) | ||
else | ||
if max_oa_frac_sch.to_ScheduleRuleset.is_initialized | ||
max_oa_frac_sch = max_oa_frac_sch.to_ScheduleRuleset.get | ||
max_oa_frac_sch_type = 'Schedule:Year' | ||
elsif max_oa_frac_sch.to_ScheduleConstant.is_initialized | ||
max_oa_frac_sch = max_oa_frac_sch.to_ScheduleConstant.get | ||
max_oa_frac_sch_type = 'Schedule:Constant' | ||
elsif max_oa_frac_sch.to_ScheduleCompact.is_initialized | ||
max_oa_frac_sch = max_oa_frac_sch.to_ScheduleCompact.get | ||
max_oa_frac_sch_type = 'Schedule:Compact' | ||
end | ||
end | ||
|
||
# Add EMS to "cap" the OA calculated by the | ||
# Controller:MechanicalVentilation object | ||
# to the design v_ot using the maximum OA | ||
# fraction schedule | ||
|
||
# Add EMS sensors | ||
# OA mass flow calculated by the Controller:MechanicalVentilation | ||
air_loop_hvac_name_ems = "EMS_#{air_loop_hvac.name.to_s.gsub(' ', '_')}" | ||
oa_vrp_mass_flow = OpenStudio::Model::EnergyManagementSystemSensor.new(air_loop_hvac.model, 'Air System Outdoor Air Mechanical Ventilation Requested Mass Flow Rate') | ||
oa_vrp_mass_flow.setKeyName(air_loop_hvac.name.to_s) | ||
oa_vrp_mass_flow.setName("#{air_loop_hvac_name_ems}_OA_VRP") | ||
# Actual sensed OA mass flow | ||
oa_mass_flow = OpenStudio::Model::EnergyManagementSystemSensor.new(air_loop_hvac.model, 'Air System Outdoor Air Mass Flow Rate') | ||
oa_mass_flow.setKeyName(air_loop_hvac.name.to_s) | ||
oa_mass_flow.setName("#{air_loop_hvac_name_ems}_OA") | ||
# Actual sensed volumetric OA flow | ||
oa_vol_flow = OpenStudio::Model::EnergyManagementSystemSensor.new(air_loop_hvac.model, 'System Node Standard Density Volume Flow Rate') | ||
oa_vol_flow.setKeyName("#{air_loop_hvac.name} Mixed Air Node") | ||
oa_vol_flow.setName("#{air_loop_hvac_name_ems}_SUPPLY_FLOW") | ||
|
||
# Add EMS actuator | ||
max_oa_fraction = OpenStudio::Model::EnergyManagementSystemActuator.new(max_oa_frac_sch, max_oa_frac_sch_type, 'Schedule Value') | ||
max_oa_fraction.setName("#{air_loop_hvac_name_ems}_MAX_OA_FRAC") | ||
|
||
# Add EMS program | ||
max_oa_ems_prog = OpenStudio::Model::EnergyManagementSystemProgram.new(air_loop_hvac.model) | ||
max_oa_ems_prog.setName("#{air_loop_hvac.name}_MAX_OA_FRAC") | ||
max_oa_ems_prog_body = <<-EMS | ||
IF #{air_loop_hvac_name_ems}_OA > #{air_loop_hvac_name_ems}_OA_VRP, | ||
SET #{air_loop_hvac_name_ems}_MAX_OA_FRAC = NULL, | ||
ELSE, | ||
IF #{air_loop_hvac_name_ems}_SUPPLY_FLOW > 0, | ||
SET #{air_loop_hvac_name_ems}_MAX_OA_FRAC = #{v_ot} / #{air_loop_hvac_name_ems}_SUPPLY_FLOW, | ||
ELSE, | ||
SET #{air_loop_hvac_name_ems}_MAX_OA_FRAC = NULL, | ||
ENDIF, | ||
ENDIF | ||
EMS | ||
max_oa_ems_prog.setBody(max_oa_ems_prog_body) | ||
|
||
max_oa_ems_prog_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(air_loop_hvac.model) | ||
max_oa_ems_prog_manager.setName("SET_#{air_loop_hvac.name.to_s.gsub(' ', '_')}_MAX_OA_FRAC") | ||
max_oa_ems_prog_manager.setCallingPoint('InsideHVACSystemIterationLoop') | ||
max_oa_ems_prog_manager.addProgram(max_oa_ems_prog) | ||
|
||
# Hard-size the sizing:system | ||
# object with the calculated min OA flow rate | ||
sizing_system = air_loop_hvac.sizingSystem | ||
sizing_system.setDesignOutdoorAirFlowRate(v_ot) | ||
sizing_system.setSystemOutdoorAirMethod('ZoneSum') | ||
|
||
return true | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New method that sets the MDP based on v_oz
and v_ot
based on a simplified e_v
calculation.
# @todo, update this section when OS allows to adjust minimum zone ventilation efficiency | ||
# In EnergyPlus this is done through the DesignSpecification:ZoneAirDistribution object | ||
# which is then assigned to a Sizing:Zone object | ||
sizing_zone.setDesignMinimumZoneVentilationEfficiency(0.6) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sets the minimum e_vz
which wasn't possible prior to OS 3.0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Add log/warning message for method that isn't supported for OS versions < 3.0 (add version check in code).
- check alignment between system outdoor air method in sizing system and controller mechanical ventilation
I added a warning for the unsupported method. As I expected, the fact that the controller mechanical ventilation is created by default and cannot be unassigned from the controller outdoor air (unless I'm mistaken) can potentially be an issue because if the OA flow rate specified at the sizing system level is lower than what is recalculated by the controller mechanical ventilation using the "zone sum" approach, the later is used during the simulation. Since this is can be an issue now, and will be if this PR is merged, I would be inclined to merge it as is, file an issue on the OpenStudio Github page, and reference this PR. What do you think? |
The proposed changes update the method to calculate the minimum damper position and system design outdoor air based on the ASHRAE 62.1 Simplified Procedure (as opposed to the method in Appendix A) as required by ASHRAE 90.1-2019. Additional information regarding the implementation are provided in Section B2.7 in the Energy Savings Analysis: ANSI/ASHRAE/IES Standard 90.1-2019 report.
The proposed changes also improve the existing method by letting EnergyPlus size the system outdoor air intake based on a minimum zone ventilation of 0.6 (not possible before OS 3.0, follow up on the issue identified in #776), and remove redundant code.
Note: It was noticed that the maximum air terminal air flow calculated from the sizing run could be different from the annual simulation run. The reason for that is that sizing runs are currently done without daylighting control, as they should, but autosizing calculation for the annual run are done with daylighting control because OS currently doesn't allow setting an availability schedule to daylighting control, see here.
Note 2: This PR is affected by NREL/OpenStudio#4436.