From 742bbb9e8ddbedde1cda41849f1a1bc5fb87c4a5 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 19 Aug 2024 10:39:32 -0700 Subject: [PATCH 1/4] New test file for ControllerOutdoorAir setters. --- .../simulationtests/controller_outdoorair.rb | 106 ++++++++++++++++++ model_tests.rb | 9 ++ 2 files changed, 115 insertions(+) create mode 100644 model/simulationtests/controller_outdoorair.rb diff --git a/model/simulationtests/controller_outdoorair.rb b/model/simulationtests/controller_outdoorair.rb new file mode 100644 index 00000000..41e35ebd --- /dev/null +++ b/model/simulationtests/controller_outdoorair.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +require 'openstudio' +require_relative 'lib/baseline_model' + +model = BaselineModel.new + +# make a 1 story, 100m X 50m, 1 zone core/perimeter building +model.add_geometry({ 'length' => 100, + 'width' => 50, + 'num_floors' => 1, + 'floor_to_floor_height' => 3, + 'plenum_height' => 1, + 'perimeter_zone_depth' => 0 }) + +# add windows at a 40% window-to-wall ratio +model.add_windows({ 'wwr' => 0.4, + 'offset' => 1, + 'application_type' => 'Above Floor' }) + +# Make a Dual Duct AirLoopHVAC +air_loop = OpenStudio::Model::AirLoopHVAC.new(model, true) + +fan = OpenStudio::Model::FanVariableVolume.new(model) +fan.addToNode(air_loop.supplyInletNode) + +oa_controller = OpenStudio::Model::ControllerOutdoorAir.new(model) +oa_controller.setEconomizerControlType("ElectronicEnthalpy") +enthalpy_limit_curve = OpenStudio::Model::CurveCubic.new(model) +enthalpy_limit_curve.setName("ElectronicEnthalpyCurveA") +enthalpy_limit_curve.setCoefficient1Constant(0.01342704) +enthalpy_limit_curve.setCoefficient2x(-0.00047892) +enthalpy_limit_curve.setCoefficient3xPOW2(0.000053352) +enthalpy_limit_curve.setCoefficient4xPOW3(-0.0000018103) +enthalpy_limit_curve.setMinimumValueofx(16.6) +enthalpy_limit_curve.setMaximumValueofx(29.13) +# oa_controller.setElectronicEnthalpyLimitCurve(enthalpy_limit_curve) +min_outdoorair_sch = OpenStudio::Model::ScheduleRuleset.new(model) +min_outdoorair_sch.setName("OAFractionSched") +min_outdoorair_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 7, 0, 0), 0.05) +min_outdoorair_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 18, 0, 0), 1.0) +min_outdoorair_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0.05) +oa_controller.setMinimumOutdoorAirSchedule(min_outdoorair_sch) +economizer_control_sch = OpenStudio::Model::ScheduleRuleset.new(model) +economizer_control_sch.setName("TimeOfDayEconomizerSch") +economizer_control_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 7, 0, 0), 0.0) +economizer_control_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 7, 30, 0), 1.0) +economizer_control_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0.0) +oa_controller.setTimeofDayEconomizerControlSchedule(economizer_control_sch) + +# Add a humidistat at 50% RH to the zone +dehumidify_sch = OpenStudio::Model::ScheduleConstant.new(model) +dehumidify_sch.setValue(50) +humidistat = OpenStudio::Model::ZoneControlHumidistat.new(model) +humidistat.setHumidifyingRelativeHumiditySetpointSchedule(dehumidify_sch) + +oa_system = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, oa_controller) +oa_system.addToNode(air_loop.supplyInletNode) + +# After the splitter, we will now have two supply outlet nodes +supply_outlet_nodes = air_loop.supplyOutletNodes + +heating_coil = OpenStudio::Model::CoilHeatingGas.new(model) +heating_coil.addToNode(supply_outlet_nodes[0]) + +heating_sch = OpenStudio::Model::ScheduleRuleset.new(model) +heating_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 45.0) +heating_spm = OpenStudio::Model::SetpointManagerScheduled.new(model, heating_sch) +heating_spm.addToNode(supply_outlet_nodes[0]) + +cooling_coil = OpenStudio::Model::CoilCoolingDXTwoSpeed.new(model) +cooling_coil.addToNode(supply_outlet_nodes[1]) + +cooling_sch = OpenStudio::Model::ScheduleRuleset.new(model) +cooling_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 12.8) +cooling_spm = OpenStudio::Model::SetpointManagerScheduled.new(model, cooling_sch) +cooling_spm.addToNode(supply_outlet_nodes[1]) + +# In order to produce more consistent results between different runs, +# we sort the zones by names (doesn't matter here, just in case) +zones = model.getThermalZones.sort_by { |z| z.name.to_s } +zones.each do |zone| + terminal = OpenStudio::Model::AirTerminalDualDuctVAV.new(model) + air_loop.addBranchForZone(zone, terminal) +end + +zone = zones[0] +zone.setZoneControlHumidistat(humidistat) +# oa_controller.setHumidistatControlZone(zone) + +# add thermostats +model.add_thermostats({ 'heating_setpoint' => 24, + 'cooling_setpoint' => 28 }) + +# assign constructions from a local library to the walls/windows/etc. in the model +model.set_constructions + +# set whole building space type; simplified 90.1-2004 Large Office Whole Building +model.set_space_type + +# add design days to the model (Chicago) +model.add_design_days + +# save the OpenStudio model (.osm) +model.save_openstudio_osm({ 'osm_save_directory' => Dir.pwd, + 'osm_name' => 'in.osm' }) diff --git a/model_tests.rb b/model_tests.rb index 309db1c2..3f2d74ff 100644 --- a/model_tests.rb +++ b/model_tests.rb @@ -426,6 +426,15 @@ def test_coilsystem_integrated_heatpump_osm result = sim_test('coilsystem_integrated_heatpump.osm') end + # TODO: To be added in the next official release after: 3.8.0 + # def test_controller_outdoorair_osm + # result = sim_test('controller_outdoorair.osm') + # end + + def test_controller_outdoorair_rb + result = sim_test('controller_outdoorair.rb') + end + def test_coolingtowers_osm result = sim_test('coolingtowers.osm') end From 6f1c4f5a1094af19769bbf4a68c8495bc8680ecc Mon Sep 17 00:00:00 2001 From: "github-rubocop-actions[bot]" Date: Mon, 19 Aug 2024 17:43:13 +0000 Subject: [PATCH 2/4] Commit rubocop --auto-correct (Ruby ruby 2.7.8p225 (2023-03-30 revision 1f4d455848) [x86_64-linux], Rubocop 0.81.0) --- model/simulationtests/controller_outdoorair.rb | 8 ++++---- model_tests.rb | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/model/simulationtests/controller_outdoorair.rb b/model/simulationtests/controller_outdoorair.rb index 41e35ebd..be4b0602 100644 --- a/model/simulationtests/controller_outdoorair.rb +++ b/model/simulationtests/controller_outdoorair.rb @@ -25,9 +25,9 @@ fan.addToNode(air_loop.supplyInletNode) oa_controller = OpenStudio::Model::ControllerOutdoorAir.new(model) -oa_controller.setEconomizerControlType("ElectronicEnthalpy") +oa_controller.setEconomizerControlType('ElectronicEnthalpy') enthalpy_limit_curve = OpenStudio::Model::CurveCubic.new(model) -enthalpy_limit_curve.setName("ElectronicEnthalpyCurveA") +enthalpy_limit_curve.setName('ElectronicEnthalpyCurveA') enthalpy_limit_curve.setCoefficient1Constant(0.01342704) enthalpy_limit_curve.setCoefficient2x(-0.00047892) enthalpy_limit_curve.setCoefficient3xPOW2(0.000053352) @@ -36,13 +36,13 @@ enthalpy_limit_curve.setMaximumValueofx(29.13) # oa_controller.setElectronicEnthalpyLimitCurve(enthalpy_limit_curve) min_outdoorair_sch = OpenStudio::Model::ScheduleRuleset.new(model) -min_outdoorair_sch.setName("OAFractionSched") +min_outdoorair_sch.setName('OAFractionSched') min_outdoorair_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 7, 0, 0), 0.05) min_outdoorair_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 18, 0, 0), 1.0) min_outdoorair_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0.05) oa_controller.setMinimumOutdoorAirSchedule(min_outdoorair_sch) economizer_control_sch = OpenStudio::Model::ScheduleRuleset.new(model) -economizer_control_sch.setName("TimeOfDayEconomizerSch") +economizer_control_sch.setName('TimeOfDayEconomizerSch') economizer_control_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 7, 0, 0), 0.0) economizer_control_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 7, 30, 0), 1.0) economizer_control_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0.0) diff --git a/model_tests.rb b/model_tests.rb index 3f2d74ff..41949455 100644 --- a/model_tests.rb +++ b/model_tests.rb @@ -428,13 +428,13 @@ def test_coilsystem_integrated_heatpump_osm # TODO: To be added in the next official release after: 3.8.0 # def test_controller_outdoorair_osm - # result = sim_test('controller_outdoorair.osm') + # result = sim_test('controller_outdoorair.osm') # end def test_controller_outdoorair_rb result = sim_test('controller_outdoorair.rb') - end - + end + def test_coolingtowers_osm result = sim_test('coolingtowers.osm') end From 78aaf65ecc6911592cef86f88d754debb746fcaa Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 10 Oct 2024 09:12:40 -0700 Subject: [PATCH 3/4] Try testing the new setters. --- .../simulationtests/controller_outdoorair.rb | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/model/simulationtests/controller_outdoorair.rb b/model/simulationtests/controller_outdoorair.rb index be4b0602..b748df0c 100644 --- a/model/simulationtests/controller_outdoorair.rb +++ b/model/simulationtests/controller_outdoorair.rb @@ -24,8 +24,8 @@ fan = OpenStudio::Model::FanVariableVolume.new(model) fan.addToNode(air_loop.supplyInletNode) -oa_controller = OpenStudio::Model::ControllerOutdoorAir.new(model) -oa_controller.setEconomizerControlType('ElectronicEnthalpy') +# Similar to FurnaceWithDXSystemRHcontrol.idf + enthalpy_limit_curve = OpenStudio::Model::CurveCubic.new(model) enthalpy_limit_curve.setName('ElectronicEnthalpyCurveA') enthalpy_limit_curve.setCoefficient1Constant(0.01342704) @@ -34,19 +34,38 @@ enthalpy_limit_curve.setCoefficient4xPOW3(-0.0000018103) enthalpy_limit_curve.setMinimumValueofx(16.6) enthalpy_limit_curve.setMaximumValueofx(29.13) -# oa_controller.setElectronicEnthalpyLimitCurve(enthalpy_limit_curve) + min_outdoorair_sch = OpenStudio::Model::ScheduleRuleset.new(model) min_outdoorair_sch.setName('OAFractionSched') min_outdoorair_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 7, 0, 0), 0.05) min_outdoorair_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 18, 0, 0), 1.0) min_outdoorair_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0.05) -oa_controller.setMinimumOutdoorAirSchedule(min_outdoorair_sch) + economizer_control_sch = OpenStudio::Model::ScheduleRuleset.new(model) economizer_control_sch.setName('TimeOfDayEconomizerSch') economizer_control_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 7, 0, 0), 0.0) economizer_control_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 7, 30, 0), 1.0) economizer_control_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0.0) + +oa_controller = OpenStudio::Model::ControllerOutdoorAir.new(model) +oa_controller.setMinimumOutdoorAirFlowRate(0.25) +oa_controller.setMaximumOutdoorAirFlowRate(1.6) +oa_controller.setEconomizerControlType('ElectronicEnthalpy') +oa_controller.setEconomizerControlActionType('ModulateFlow') +oa_controller.setEconomizerMaximumLimitDryBulbTemperature(23.0) +# oa_controller.setEconomizerMaximumLimitEnthalpy() +oa_controller.setEconomizerMaximumLimitDewpointTemperature(13.5) +oa_controller.setElectronicEnthalpyLimitCurve(enthalpy_limit_curve) +oa_controller.setEconomizerMinimumLimitDryBulbTemperature(14.0) +oa_controller.setLockoutType('NoLockout') +oa_controller.setMinimumLimitType('FixedMinimum') +oa_controller.setMinimumOutdoorAirSchedule(min_outdoorair_sch) +# oa_controller.setMinimumFractionofOutdoorAirSchedule() +# oa_controller.setMaximumFractionofOutdoorAirSchedule() +# oa_controller.setControllerMechanicalVentilation() oa_controller.setTimeofDayEconomizerControlSchedule(economizer_control_sch) +oa_controller.setHighHumidityOutdoorAirFlowRatio(0.9) +oa_controller.setControlHighIndoorHumidityBasedOnOutdoorHumidityRatio(true) # Add a humidistat at 50% RH to the zone dehumidify_sch = OpenStudio::Model::ScheduleConstant.new(model) @@ -86,7 +105,7 @@ zone = zones[0] zone.setZoneControlHumidistat(humidistat) -# oa_controller.setHumidistatControlZone(zone) +oa_controller.setHumidistatControlZone(zone) # add thermostats model.add_thermostats({ 'heating_setpoint' => 24, From 435ae627ec2aae5411b438468ec69891d992f7cc Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 10 Oct 2024 09:28:47 -0700 Subject: [PATCH 4/4] Point to develop build. --- model/simulationtests/controller_outdoorair.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/model/simulationtests/controller_outdoorair.rb b/model/simulationtests/controller_outdoorair.rb index b748df0c..fc24ca3d 100644 --- a/model/simulationtests/controller_outdoorair.rb +++ b/model/simulationtests/controller_outdoorair.rb @@ -101,11 +101,10 @@ zones.each do |zone| terminal = OpenStudio::Model::AirTerminalDualDuctVAV.new(model) air_loop.addBranchForZone(zone, terminal) -end -zone = zones[0] -zone.setZoneControlHumidistat(humidistat) -oa_controller.setHumidistatControlZone(zone) + zone.setZoneControlHumidistat(humidistat) + oa_controller.setHumidistatControlZone(zone) +end # add thermostats model.add_thermostats({ 'heating_setpoint' => 24,