From b21c5d50332dd3b0e8f15c6c896f8b76a30ab680 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 26 Mar 2025 12:31:49 -0700 Subject: [PATCH 1/9] Add new coilsystem_cooling_water.rb test file. --- .../coilsystem_cooling_water.rb | 143 ++++++++++++++++++ model_tests.rb | 13 ++ 2 files changed, 156 insertions(+) create mode 100644 model/simulationtests/coilsystem_cooling_water.rb diff --git a/model/simulationtests/coilsystem_cooling_water.rb b/model/simulationtests/coilsystem_cooling_water.rb new file mode 100644 index 00000000..9837e415 --- /dev/null +++ b/model/simulationtests/coilsystem_cooling_water.rb @@ -0,0 +1,143 @@ +# frozen_string_literal: true + +require 'openstudio' +require_relative 'lib/baseline_model' + +m = BaselineModel.new + +# make a 1 story, 100m X 50m, 2 zone core/perimeter building +m.add_geometry({ 'length' => 100, + 'width' => 50, + 'num_floors' => 2, + 'floor_to_floor_height' => 4, + 'plenum_height' => 1, + 'perimeter_zone_depth' => 0 }) + +# add windows at a 40% window-to-wall ratio +m.add_windows({ 'wwr' => 0.4, + 'offset' => 1, + 'application_type' => 'Above Floor' }) + +# add thermostats +m.add_thermostats({ 'heating_setpoint' => 24, + 'cooling_setpoint' => 28 }) + +# assign constructions from a local library to the walls/windows/etc. in the model +m.set_constructions + +# set whole building space type; simplified 90.1-2004 Large Office Whole Building +m.set_space_type + +# add design days to the model (Chicago) +m.add_design_days + +# add ASHRAE System type 07, VAV w/ Reheat +m.add_hvac({ 'ashrae_sys_num' => '07' }) + +# In order to produce more consistent results between different runs, +# we sort the zones by names (only one here anyways...) +zones = m.getThermalZones.sort_by { |z| z.name.to_s } + +### Water Size Economizer Model ### + +# CoilSystemCoolingWater +zone = zones[0] +airloop = zone.airLoopHVAC.get +airloop.setName('AirLoopHVAC CoilSystemCoolingWater') + +# create a CoilSystem object +coil_system = OpenStudio::Model::CoilSystemCoolingWater.new(m) +coil_system.setName('CoilSystemCoolingWater WaterSize') + +# Replace the default CoilCoolingWater with CoilSystem, then remove the default one +# Note: it's probably going to end up badly controlled when you place the +# CoilSystem directly on the AirLoopHVAC path and not inside another component +# (such as UnitarySys, cf: https://github.com/NREL/EnergyPlus/issues/7222) +water_coil = coil_system.coolingCoil.to_CoilCoolingWater.get +water_coil.setName('CoilSystemCoolingWater WaterSize CoolingCoil') + +coil = airloop.supplyComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).first.to_CoilCoolingWater.get +# Note that we connect the CoilSystem, NOT the underlying CoilCoolingWater +coil_system.addToNode(coil.airOutletModelObject.get.to_Node.get) +plant = coil.plantLoop.get +# But we have to connect the water_coil itself... +plant.addDemandBranchForComponent(water_coil) +# coil.remove # not yet + +# Rename some nodes and such, for ease of debugging +airloop.supplyInletNode.setName("#{airloop.name} Supply Inlet Node") +airloop.supplyOutletNode.setName("#{airloop.name} Supply Outlet Node") +airloop.mixedAirNode.get.setName("#{airloop.name} Mixed Air Node") +coil_system.outletModelObject.get.to_Node.get.setName("#{airloop.name} Outlet to Heating Coil Inlet Node") + +water_coil.waterInletModelObject.get.setName("#{water_coil.name} Water Inlet Node") +water_coil.waterOutletModelObject.get.setName("#{water_coil.name} Water Outlet Node") +# water_coil.controllerWaterCoil.get.setName("#{water_coil.name} Controller") + +heating_coil = airloop.supplyComponents(OpenStudio::Model::CoilHeatingWater.iddObjectType).first.to_CoilHeatingWater.get +heating_coil.waterInletModelObject.get.setName("#{airloop.name} Heating Coil Water Inlet Node") +heating_coil.waterOutletModelObject.get.setName("#{airloop.name} Heating Coil Water Outlet Node") +heating_coil.controllerWaterCoil.get.setName("#{airloop.name} Heating Coil Controller") +heating_coil.airOutletModelObject.get.setName("#{airloop.name} Heating Coil Air Outlet to Fan Inlet Node") + +###### + +### Wrap Around Water Coil Heat Recovery Mode ### + +# CoilSystemCoolingWater +zone = zones[1] +airloop = zone.airLoopHVAC.get +airloop.setName('AirLoopHVAC CoilSystemCoolingWater') + +# create a CoilSystem object +coil_system = OpenStudio::Model::CoilSystemCoolingWater.new(m) +coil_system.setName('CoilSystemCoolingWater WrapAround') + +# Replace the default CoilCoolingWater with CoilSystem, then remove the default one +# Note: it's probably going to end up badly controlled when you place the +# CoilSystem directly on the AirLoopHVAC path and not inside another component +# (such as UnitarySys, cf: https://github.com/NREL/EnergyPlus/issues/7222) +water_coil = coil_system.coolingCoil.to_CoilCoolingWater.get +water_coil.setName('CoilSystemCoolingWater WrapAround CoolingCoil') + +outdoorAirSystem = airloop.airLoopHVACOutdoorAirSystem.get + +coil = airloop.supplyComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).first.to_CoilCoolingWater.get +# Note that we connect the CoilSystem, NOT the underlying CoilCoolingWater +outdoorAirSystem.addToNode(coil.airOutletModelObject.get.to_Node.get) +coil_system.addToNode(outdoorAirSystem.outboardOANode.get) +plant = coil.plantLoop.get +# But we have to connect the water_coil itself... +plant.addDemandBranchForComponent(water_coil) +coil.remove + +companion_coil = OpenStudio::Model::CoilCoolingWater.new(m) +companion_coil.setName('CoilSystemCoolingWater WrapAround CompanionCoil') +coil_system.setCompanionCoilUsedForHeatRecovery(companion_coil) +companion_coil.addToNode(outdoorAirSystem.reliefAirModelObject.get.to_Node.get) + +pipe = OpenStudio::Model::PipeAdiabatic.new(m) +pipe.addToNode(coil_system.coolingCoil.waterOutletModelObject.get.to_Node.get) +companion_coil.addToNode(pipe.outletModelObject.get.to_Node.get) + +# Rename some nodes and such, for ease of debugging +airloop.supplyInletNode.setName("#{airloop.name} Supply Inlet Node") +airloop.supplyOutletNode.setName("#{airloop.name} Supply Outlet Node") +airloop.mixedAirNode.get.setName("#{airloop.name} Mixed Air Node") +coil_system.outletModelObject.get.to_Node.get.setName("#{airloop.name} Outlet to Heating Coil Inlet Node") + +water_coil.waterInletModelObject.get.setName("#{water_coil.name} Water Inlet Node") +water_coil.waterOutletModelObject.get.setName("#{water_coil.name} Water Outlet Node") +# water_coil.controllerWaterCoil.get.setName("#{water_coil.name} Controller") + +heating_coil = airloop.supplyComponents(OpenStudio::Model::CoilHeatingWater.iddObjectType).first.to_CoilHeatingWater.get +heating_coil.waterInletModelObject.get.setName("#{airloop.name} Heating Coil Water Inlet Node") +heating_coil.waterOutletModelObject.get.setName("#{airloop.name} Heating Coil Water Outlet Node") +heating_coil.controllerWaterCoil.get.setName("#{airloop.name} Heating Coil Controller") +heating_coil.airOutletModelObject.get.setName("#{airloop.name} Heating Coil Air Outlet to Fan Inlet Node") + +###### + +# save the OpenStudio model (.osm) +m.save_openstudio_osm({ 'osm_save_directory' => Dir.pwd, + 'osm_name' => 'in.osm' }) diff --git a/model_tests.rb b/model_tests.rb index 7bedb445..11f47981 100644 --- a/model_tests.rb +++ b/model_tests.rb @@ -425,6 +425,19 @@ def test_coilsystem_integrated_heatpump_osm result = sim_test('coilsystem_integrated_heatpump.osm') end + def test_coilsystem_cooling_water_rb + result = sim_test('coilsystem_cooling_water.rb') + end + + def test_coilsystem_cooling_water_py + result = sim_test('coilsystem_cooling_water.py') + end + + # TODO: To be added in the next official release after: 3.9.0 + # def test_coilsystem_cooling_water_osm + # result = sim_test('coilsystem_cooling_water.osm') + # end + def test_coolingtowers_osm result = sim_test('coolingtowers.osm') end From fba5b25e3b0cc1084f390fb83bf555c0e02ae396 Mon Sep 17 00:00:00 2001 From: "github-rubocop-actions[bot]" Date: Wed, 26 Mar 2025 19:35:29 +0000 Subject: [PATCH 2/9] Commit rubocop --auto-correct (Ruby ruby 2.7.8p225 (2023-03-30 revision 1f4d455848) [x86_64-linux], Rubocop 0.81.0) --- model/simulationtests/coilsystem_cooling_water.rb | 2 +- model_tests.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/model/simulationtests/coilsystem_cooling_water.rb b/model/simulationtests/coilsystem_cooling_water.rb index 9837e415..74a4bb59 100644 --- a/model/simulationtests/coilsystem_cooling_water.rb +++ b/model/simulationtests/coilsystem_cooling_water.rb @@ -140,4 +140,4 @@ # save the OpenStudio model (.osm) m.save_openstudio_osm({ 'osm_save_directory' => Dir.pwd, - 'osm_name' => 'in.osm' }) + 'osm_name' => 'in.osm' }) diff --git a/model_tests.rb b/model_tests.rb index 11f47981..7e320bc4 100644 --- a/model_tests.rb +++ b/model_tests.rb @@ -435,7 +435,7 @@ def test_coilsystem_cooling_water_py # TODO: To be added in the next official release after: 3.9.0 # def test_coilsystem_cooling_water_osm - # result = sim_test('coilsystem_cooling_water.osm') + # result = sim_test('coilsystem_cooling_water.osm') # end def test_coolingtowers_osm From f78d0edb1961207c547fc85fd118e666168e47b8 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 27 Mar 2025 16:29:42 -0700 Subject: [PATCH 3/9] Update wrap around recovery example. --- .../coilsystem_cooling_water.rb | 85 ++++++++++++------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/model/simulationtests/coilsystem_cooling_water.rb b/model/simulationtests/coilsystem_cooling_water.rb index 74a4bb59..307062ba 100644 --- a/model/simulationtests/coilsystem_cooling_water.rb +++ b/model/simulationtests/coilsystem_cooling_water.rb @@ -40,12 +40,11 @@ ### Water Size Economizer Model ### -# CoilSystemCoolingWater zone = zones[0] airloop = zone.airLoopHVAC.get airloop.setName('AirLoopHVAC CoilSystemCoolingWater') -# create a CoilSystem object +# create a CoilSystemCoolingWater object coil_system = OpenStudio::Model::CoilSystemCoolingWater.new(m) coil_system.setName('CoilSystemCoolingWater WaterSize') @@ -84,51 +83,79 @@ ### Wrap Around Water Coil Heat Recovery Mode ### -# CoilSystemCoolingWater +# create heat recovery plant loop +hr_loop = OpenStudio::Model::PlantLoop.new(m) +hr_loop.setName('Run Around Coil HR Loop') + +plant_siz = hr_loop.sizingPlant +plant_siz.setLoopType('cooling') +plant_siz.setDesignLoopExitTemperature(7) +plant_siz.setLoopDesignTemperatureDifference(4) + +# create supply side pump +pump = OpenStudio::Model::PumpVariableSpeed.new(m) +pump.setName('HR Circ Pump') +pump.setCoefficient1ofthePartLoadPerformanceCurve(0) +pump.setCoefficient2ofthePartLoadPerformanceCurve(1) +pump.setCoefficient3ofthePartLoadPerformanceCurve(0) +pump.setCoefficient4ofthePartLoadPerformanceCurve(0) + +hr_loop.addSupplyBranchForComponent(pump) + zone = zones[1] airloop = zone.airLoopHVAC.get airloop.setName('AirLoopHVAC CoilSystemCoolingWater') -# create a CoilSystem object -coil_system = OpenStudio::Model::CoilSystemCoolingWater.new(m) -coil_system.setName('CoilSystemCoolingWater WrapAround') +oa_sys = airloop.airLoopHVACOutdoorAirSystem.get -# Replace the default CoilCoolingWater with CoilSystem, then remove the default one -# Note: it's probably going to end up badly controlled when you place the -# CoilSystem directly on the AirLoopHVAC path and not inside another component -# (such as UnitarySys, cf: https://github.com/NREL/EnergyPlus/issues/7222) -water_coil = coil_system.coolingCoil.to_CoilCoolingWater.get -water_coil.setName('CoilSystemCoolingWater WrapAround CoolingCoil') +primary_coil = OpenStudio::Model::CoilCoolingWater.new(m, m.alwaysOnDiscreteSchedule) +primary_coil.setName("#{airloop.name.get} Primary HR Coil") +# primary_coil.setDesignWaterTemperatureDifference(4) -outdoorAirSystem = airloop.airLoopHVACOutdoorAirSystem.get +companion_coil = OpenStudio::Model::CoilCoolingWater.new(m, m.alwaysOnDiscreteSchedule) +companion_coil.setName("#{airloop.name.get} Companion HR Coil") +# companion_coil.setDesignWaterTemperatureDifference(4) -coil = airloop.supplyComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).first.to_CoilCoolingWater.get -# Note that we connect the CoilSystem, NOT the underlying CoilCoolingWater -outdoorAirSystem.addToNode(coil.airOutletModelObject.get.to_Node.get) -coil_system.addToNode(outdoorAirSystem.outboardOANode.get) -plant = coil.plantLoop.get -# But we have to connect the water_coil itself... -plant.addDemandBranchForComponent(water_coil) -coil.remove +coil_sys = OpenStudio::Model::CoilSystemCoolingWater.new(m, primary_coil) +coil_sys.setName('CoilSystemCoolingWater WrapAround') +coil_sys.setCompanionCoilUsedForHeatRecovery(companion_coil) +coil_sys.setMinimumWaterLoopTemperatureForHeatRecovery(3) -companion_coil = OpenStudio::Model::CoilCoolingWater.new(m) -companion_coil.setName('CoilSystemCoolingWater WrapAround CompanionCoil') -coil_system.setCompanionCoilUsedForHeatRecovery(companion_coil) -companion_coil.addToNode(outdoorAirSystem.reliefAirModelObject.get.to_Node.get) +coil_sys.addToNode(oa_sys.outboardOANode.get) +companion_coil.addToNode(oa_sys.reliefAirModelObject.get.to_Node.get) +# connect to plant loop +hr_loop.addDemandBranchForComponent(primary_coil) pipe = OpenStudio::Model::PipeAdiabatic.new(m) -pipe.addToNode(coil_system.coolingCoil.waterOutletModelObject.get.to_Node.get) +pipe.addToNode(primary_coil.waterOutletModelObject.get.to_Node.get) companion_coil.addToNode(pipe.outletModelObject.get.to_Node.get) +coil_spm_sch = OpenStudio::Model::ScheduleConstant.new(m) +coil_spm_sch.setName('OA HR Supply Air Temp Sch') +coil_spm_sch.setValue(4.5) + +primary_coil_spm = OpenStudio::Model::SetpointManagerScheduled.new(m, coil_spm_sch) +primary_coil_spm.setName('OA Air Temp Manager HR1') +# primary_coil_spm.addToNode(coil_sys.airOutletModelObject.get.to_Node.get) +# primary_coil_spm.addToNode(coil_sys.outletModelObject.get.to_Node.get) + +companion_coil_spm = OpenStudio::Model::SetpointManagerScheduled.new(m, coil_spm_sch) +companion_coil_spm.setName('OA Air Temp Manager HR2') +# companion_coil_spm.addToNode(companion_coil.airOutletModelObject.get.to_Node.get) + +hr_loop_spm = OpenStudio::Model::SetpointManagerScheduled.new(m, coil_spm_sch) +hr_loop_spm.setName('OA Air Temp Manager HR3') +hr_loop_spm.addToNode(hr_loop.loopTemperatureSetpointNode) + # Rename some nodes and such, for ease of debugging airloop.supplyInletNode.setName("#{airloop.name} Supply Inlet Node") airloop.supplyOutletNode.setName("#{airloop.name} Supply Outlet Node") airloop.mixedAirNode.get.setName("#{airloop.name} Mixed Air Node") coil_system.outletModelObject.get.to_Node.get.setName("#{airloop.name} Outlet to Heating Coil Inlet Node") -water_coil.waterInletModelObject.get.setName("#{water_coil.name} Water Inlet Node") -water_coil.waterOutletModelObject.get.setName("#{water_coil.name} Water Outlet Node") -# water_coil.controllerWaterCoil.get.setName("#{water_coil.name} Controller") +primary_coil.waterInletModelObject.get.setName("#{primary_coil.name} Water Inlet Node") +primary_coil.waterOutletModelObject.get.setName("#{primary_coil.name} Water Outlet Node") +# primary_coil.controllerWaterCoil.get.setName("#{primary_coil.name} Controller") heating_coil = airloop.supplyComponents(OpenStudio::Model::CoilHeatingWater.iddObjectType).first.to_CoilHeatingWater.get heating_coil.waterInletModelObject.get.setName("#{airloop.name} Heating Coil Water Inlet Node") From 4c3850efac02f9b597f559e11fd132bb992124f9 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Fri, 28 Mar 2025 09:38:38 -0700 Subject: [PATCH 4/9] Remove the default coil. --- model/simulationtests/coilsystem_cooling_water.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/simulationtests/coilsystem_cooling_water.rb b/model/simulationtests/coilsystem_cooling_water.rb index 307062ba..203aeb7c 100644 --- a/model/simulationtests/coilsystem_cooling_water.rb +++ b/model/simulationtests/coilsystem_cooling_water.rb @@ -61,7 +61,7 @@ plant = coil.plantLoop.get # But we have to connect the water_coil itself... plant.addDemandBranchForComponent(water_coil) -# coil.remove # not yet +coil.remove # Rename some nodes and such, for ease of debugging airloop.supplyInletNode.setName("#{airloop.name} Supply Inlet Node") From dae4472b649a19bd5ab1ff7f6681bcd62ed18930 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 31 Mar 2025 09:40:09 -0700 Subject: [PATCH 5/9] Minor updates. --- model/simulationtests/coilsystem_cooling_water.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/model/simulationtests/coilsystem_cooling_water.rb b/model/simulationtests/coilsystem_cooling_water.rb index 203aeb7c..f052e645 100644 --- a/model/simulationtests/coilsystem_cooling_water.rb +++ b/model/simulationtests/coilsystem_cooling_water.rb @@ -5,10 +5,10 @@ m = BaselineModel.new -# make a 1 story, 100m X 50m, 2 zone core/perimeter building +# make a 1 story, 100m X 50m, 1 zone core/perimeter building m.add_geometry({ 'length' => 100, 'width' => 50, - 'num_floors' => 2, + 'num_floors' => 1, 'floor_to_floor_height' => 4, 'plenum_height' => 1, 'perimeter_zone_depth' => 0 }) @@ -88,7 +88,7 @@ hr_loop.setName('Run Around Coil HR Loop') plant_siz = hr_loop.sizingPlant -plant_siz.setLoopType('cooling') +plant_siz.setLoopType('Cooling') plant_siz.setDesignLoopExitTemperature(7) plant_siz.setLoopDesignTemperatureDifference(4) @@ -102,9 +102,9 @@ hr_loop.addSupplyBranchForComponent(pump) -zone = zones[1] -airloop = zone.airLoopHVAC.get -airloop.setName('AirLoopHVAC CoilSystemCoolingWater') +# zone = zones[1] +# airloop = zone.airLoopHVAC.get +# airloop.setName('AirLoopHVAC CoilSystemCoolingWater WrapAround') oa_sys = airloop.airLoopHVACOutdoorAirSystem.get From 4fd77695ce79d885743b2a9be7caebb39abd1343 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 5 May 2025 19:03:40 +0200 Subject: [PATCH 6/9] Adjust Water Side test: add the CoilSystemCoolingWater upstream of the Central CHW Coil, and connect it to the Condenser Loop --- .../coilsystem_cooling_water.rb | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/model/simulationtests/coilsystem_cooling_water.rb b/model/simulationtests/coilsystem_cooling_water.rb index f052e645..9ba64c61 100644 --- a/model/simulationtests/coilsystem_cooling_water.rb +++ b/model/simulationtests/coilsystem_cooling_water.rb @@ -38,7 +38,7 @@ # we sort the zones by names (only one here anyways...) zones = m.getThermalZones.sort_by { |z| z.name.to_s } -### Water Size Economizer Model ### +### Water Side Economizer Model ### zone = zones[0] airloop = zone.airLoopHVAC.get @@ -46,38 +46,39 @@ # create a CoilSystemCoolingWater object coil_system = OpenStudio::Model::CoilSystemCoolingWater.new(m) -coil_system.setName('CoilSystemCoolingWater WaterSize') +coil_system.setName('CoilSystemCoolingWater WaterSide') -# Replace the default CoilCoolingWater with CoilSystem, then remove the default one -# Note: it's probably going to end up badly controlled when you place the -# CoilSystem directly on the AirLoopHVAC path and not inside another component -# (such as UnitarySys, cf: https://github.com/NREL/EnergyPlus/issues/7222) water_coil = coil_system.coolingCoil.to_CoilCoolingWater.get -water_coil.setName('CoilSystemCoolingWater WaterSize CoolingCoil') +water_coil.setName('CoilSystemCoolingWater WaterSide CoolingCoil') +# As a water-side economizer the CoilSystem:Cooling:Water object is placed upstream of packaged DX systems or chilled water main cooling coil +# We have a Chilled water coil already, so let's keep it coil = airloop.supplyComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).first.to_CoilCoolingWater.get +coil.setName('Central ChW Coil') + # Note that we connect the CoilSystem, NOT the underlying CoilCoolingWater -coil_system.addToNode(coil.airOutletModelObject.get.to_Node.get) +coil_system.addToNode(coil.airInletModelObject.get.to_Node.get) plant = coil.plantLoop.get -# But we have to connect the water_coil itself... -plant.addDemandBranchForComponent(water_coil) -coil.remove +# But we have to connect the water_coil itself. Ideally this would be on a Condenser Loop, so let's get it +cts = m.getCoolingTowerSingleSpeeds.sort_by { |c| c.name.to_s } +condenser_loop = cts.first.plantLoop.get +condenser_loop.addDemandBranchForComponent(water_coil) # Rename some nodes and such, for ease of debugging -airloop.supplyInletNode.setName("#{airloop.name} Supply Inlet Node") -airloop.supplyOutletNode.setName("#{airloop.name} Supply Outlet Node") -airloop.mixedAirNode.get.setName("#{airloop.name} Mixed Air Node") -coil_system.outletModelObject.get.to_Node.get.setName("#{airloop.name} Outlet to Heating Coil Inlet Node") +airloop.supplyInletNode.setName("#{airloop.nameString} Supply Inlet Node") +airloop.supplyOutletNode.setName("#{airloop.nameString} Supply Outlet Node") +airloop.mixedAirNode.get.setName("#{airloop.nameString} Mixed Air Node") +coil_system.outletModelObject.get.to_Node.get.setName("#{coil_system.nameString} Outlet to #{coil.nameString} Inlet Node") -water_coil.waterInletModelObject.get.setName("#{water_coil.name} Water Inlet Node") -water_coil.waterOutletModelObject.get.setName("#{water_coil.name} Water Outlet Node") +water_coil.waterInletModelObject.get.setName("#{water_coil.nameString} Water Inlet Node") +water_coil.waterOutletModelObject.get.setName("#{water_coil.nameString} Water Outlet Node") # water_coil.controllerWaterCoil.get.setName("#{water_coil.name} Controller") heating_coil = airloop.supplyComponents(OpenStudio::Model::CoilHeatingWater.iddObjectType).first.to_CoilHeatingWater.get -heating_coil.waterInletModelObject.get.setName("#{airloop.name} Heating Coil Water Inlet Node") -heating_coil.waterOutletModelObject.get.setName("#{airloop.name} Heating Coil Water Outlet Node") -heating_coil.controllerWaterCoil.get.setName("#{airloop.name} Heating Coil Controller") -heating_coil.airOutletModelObject.get.setName("#{airloop.name} Heating Coil Air Outlet to Fan Inlet Node") +heating_coil.waterInletModelObject.get.setName("#{airloop.nameString} Heating Coil Water Inlet Node") +heating_coil.waterOutletModelObject.get.setName("#{airloop.nameString} Heating Coil Water Outlet Node") +heating_coil.controllerWaterCoil.get.setName("#{airloop.nameString} Heating Coil Controller") +heating_coil.airOutletModelObject.get.setName("#{airloop.nameString} Heating Coil Air Outlet to Fan Inlet Node") ###### @@ -108,6 +109,7 @@ oa_sys = airloop.airLoopHVACOutdoorAirSystem.get +# TODO: use a CoilSystemCoolingWaterHeatExchangerAssisted primary_coil = OpenStudio::Model::CoilCoolingWater.new(m, m.alwaysOnDiscreteSchedule) primary_coil.setName("#{airloop.name.get} Primary HR Coil") # primary_coil.setDesignWaterTemperatureDifference(4) From 6755f511932aae3eed92e63ee157d1a6f469329b Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 5 May 2025 22:40:14 +0200 Subject: [PATCH 7/9] Adjusts coil system cooling water test Refactors node naming for clarity and consistency in the coil system cooling water test. --- .../coilsystem_cooling_water.rb | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/model/simulationtests/coilsystem_cooling_water.rb b/model/simulationtests/coilsystem_cooling_water.rb index 9ba64c61..ab491a32 100644 --- a/model/simulationtests/coilsystem_cooling_water.rb +++ b/model/simulationtests/coilsystem_cooling_water.rb @@ -53,12 +53,11 @@ # As a water-side economizer the CoilSystem:Cooling:Water object is placed upstream of packaged DX systems or chilled water main cooling coil # We have a Chilled water coil already, so let's keep it -coil = airloop.supplyComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).first.to_CoilCoolingWater.get -coil.setName('Central ChW Coil') +central_cooling_coil = airloop.supplyComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).first.to_CoilCoolingWater.get +central_cooling_coil.setName('Central ChW Coil') # Note that we connect the CoilSystem, NOT the underlying CoilCoolingWater -coil_system.addToNode(coil.airInletModelObject.get.to_Node.get) -plant = coil.plantLoop.get +coil_system.addToNode(central_cooling_coil.airInletModelObject.get.to_Node.get) # But we have to connect the water_coil itself. Ideally this would be on a Condenser Loop, so let's get it cts = m.getCoolingTowerSingleSpeeds.sort_by { |c| c.name.to_s } condenser_loop = cts.first.plantLoop.get @@ -68,17 +67,22 @@ airloop.supplyInletNode.setName("#{airloop.nameString} Supply Inlet Node") airloop.supplyOutletNode.setName("#{airloop.nameString} Supply Outlet Node") airloop.mixedAirNode.get.setName("#{airloop.nameString} Mixed Air Node") -coil_system.outletModelObject.get.to_Node.get.setName("#{coil_system.nameString} Outlet to #{coil.nameString} Inlet Node") + +central_heating_coil = airloop.supplyComponents(OpenStudio::Model::CoilHeatingWater.iddObjectType).first.to_CoilHeatingWater.get +central_heating_coil.setName('Central HW Coil') +coil_system.outletModelObject.get.to_Node.get.setName("#{coil_system.nameString} Air Outlet to #{central_cooling_coil.nameString} Inlet Node") +central_cooling_coil.airOutletModelObject.get.to_Node.get.setName("#{central_cooling_coil.nameString} Air Outlet to #{central_heating_coil.nameString} Inlet Node") water_coil.waterInletModelObject.get.setName("#{water_coil.nameString} Water Inlet Node") water_coil.waterOutletModelObject.get.setName("#{water_coil.nameString} Water Outlet Node") # water_coil.controllerWaterCoil.get.setName("#{water_coil.name} Controller") -heating_coil = airloop.supplyComponents(OpenStudio::Model::CoilHeatingWater.iddObjectType).first.to_CoilHeatingWater.get -heating_coil.waterInletModelObject.get.setName("#{airloop.nameString} Heating Coil Water Inlet Node") -heating_coil.waterOutletModelObject.get.setName("#{airloop.nameString} Heating Coil Water Outlet Node") -heating_coil.controllerWaterCoil.get.setName("#{airloop.nameString} Heating Coil Controller") -heating_coil.airOutletModelObject.get.setName("#{airloop.nameString} Heating Coil Air Outlet to Fan Inlet Node") +fan = airloop.supplyFan.get +fan.setName("Supply Fan") + +central_heating_coil.waterOutletModelObject.get.setName("#{airloop.nameString} Heating Coil Water Outlet Node") +central_heating_coil.controllerWaterCoil.get.setName("#{airloop.nameString} Heating Coil Controller") +central_heating_coil.airOutletModelObject.get.setName("#{central_heating_coil.nameString} Air Outlet to #{fan.nameString} Inlet Node") ###### @@ -124,7 +128,7 @@ coil_sys.setMinimumWaterLoopTemperatureForHeatRecovery(3) coil_sys.addToNode(oa_sys.outboardOANode.get) -companion_coil.addToNode(oa_sys.reliefAirModelObject.get.to_Node.get) +companion_coil.addToNode(oa_sys.outboardReliefNode.get) # connect to plant loop hr_loop.addDemandBranchForComponent(primary_coil) @@ -150,20 +154,15 @@ hr_loop_spm.addToNode(hr_loop.loopTemperatureSetpointNode) # Rename some nodes and such, for ease of debugging -airloop.supplyInletNode.setName("#{airloop.name} Supply Inlet Node") -airloop.supplyOutletNode.setName("#{airloop.name} Supply Outlet Node") -airloop.mixedAirNode.get.setName("#{airloop.name} Mixed Air Node") -coil_system.outletModelObject.get.to_Node.get.setName("#{airloop.name} Outlet to Heating Coil Inlet Node") +oa_sys.outboardOANode.get.setName("OA Inlet Node"); +oa_sys.outboardReliefNode.get.setName("OA Relief Node"); +oa_sys.reliefAirModelObject.get.setName("Return to OA System Node"); +oa_sys.outdoorAirModelObject.get.setName("OA System Outlet to Mixed Node"); primary_coil.waterInletModelObject.get.setName("#{primary_coil.name} Water Inlet Node") primary_coil.waterOutletModelObject.get.setName("#{primary_coil.name} Water Outlet Node") # primary_coil.controllerWaterCoil.get.setName("#{primary_coil.name} Controller") -heating_coil = airloop.supplyComponents(OpenStudio::Model::CoilHeatingWater.iddObjectType).first.to_CoilHeatingWater.get -heating_coil.waterInletModelObject.get.setName("#{airloop.name} Heating Coil Water Inlet Node") -heating_coil.waterOutletModelObject.get.setName("#{airloop.name} Heating Coil Water Outlet Node") -heating_coil.controllerWaterCoil.get.setName("#{airloop.name} Heating Coil Controller") -heating_coil.airOutletModelObject.get.setName("#{airloop.name} Heating Coil Air Outlet to Fan Inlet Node") ###### From e2570b43b7a73c67bc9d472bc60f720a04d3ef62 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 5 May 2025 23:06:21 +0200 Subject: [PATCH 8/9] Eliminate warnings by setting some design conditions like the E+ example files --- .../coilsystem_cooling_water.rb | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/model/simulationtests/coilsystem_cooling_water.rb b/model/simulationtests/coilsystem_cooling_water.rb index ab491a32..b1b5ba13 100644 --- a/model/simulationtests/coilsystem_cooling_water.rb +++ b/model/simulationtests/coilsystem_cooling_water.rb @@ -51,6 +51,13 @@ water_coil = coil_system.coolingCoil.to_CoilCoolingWater.get water_coil.setName('CoilSystemCoolingWater WaterSide CoolingCoil') +# Set coil conditions to mimic "Free Cooling Coil" from WaterSideEconomizer_PreCoolCoil.idf +water_coil.setDesignInletWaterTemperature(11.0) +water_coil.setDesignInletAirTemperature 34.0 +water_coil.setDesignOutletAirTemperature(16.0) +water_coil.setDesignInletAirHumidityRatio(0.009) +water_coil.setDesignOutletAirHumidityRatio(0.009) + # As a water-side economizer the CoilSystem:Cooling:Water object is placed upstream of packaged DX systems or chilled water main cooling coil # We have a Chilled water coil already, so let's keep it central_cooling_coil = airloop.supplyComponents(OpenStudio::Model::CoilCoolingWater.iddObjectType).first.to_CoilCoolingWater.get @@ -78,7 +85,7 @@ # water_coil.controllerWaterCoil.get.setName("#{water_coil.name} Controller") fan = airloop.supplyFan.get -fan.setName("Supply Fan") +fan.setName('Supply Fan') central_heating_coil.waterOutletModelObject.get.setName("#{airloop.nameString} Heating Coil Water Outlet Node") central_heating_coil.controllerWaterCoil.get.setName("#{airloop.nameString} Heating Coil Controller") @@ -88,6 +95,8 @@ ### Wrap Around Water Coil Heat Recovery Mode ### +# 5ZoneAirCooled_RunaroundHeatRecovery.idf +# # create heat recovery plant loop hr_loop = OpenStudio::Model::PlantLoop.new(m) hr_loop.setName('Run Around Coil HR Loop') @@ -125,7 +134,8 @@ coil_sys = OpenStudio::Model::CoilSystemCoolingWater.new(m, primary_coil) coil_sys.setName('CoilSystemCoolingWater WrapAround') coil_sys.setCompanionCoilUsedForHeatRecovery(companion_coil) -coil_sys.setMinimumWaterLoopTemperatureForHeatRecovery(3) +coil_sys.setMinimumAirToWaterTemperatureOffset(3.0) +coil_sys.setMinimumWaterLoopTemperatureForHeatRecovery(5.0) coil_sys.addToNode(oa_sys.outboardOANode.get) companion_coil.addToNode(oa_sys.outboardReliefNode.get) @@ -153,17 +163,26 @@ hr_loop_spm.setName('OA Air Temp Manager HR3') hr_loop_spm.addToNode(hr_loop.loopTemperatureSetpointNode) +sz = airloop.sizingSystem +sz.setPreheatDesignTemperature(4.5) +sz.setPrecoolDesignTemperature(11.0) +sz.setCentralCoolingDesignSupplyAirTemperature(12.8) +sz.setCentralHeatingDesignSupplyAirTemperature(16.7) +sz.setAllOutdoorAirinCooling(false) +sz.setAllOutdoorAirinHeating(false) +sz.setCentralCoolingDesignSupplyAirHumidityRatio(0.008) +sz.setCentralCoolingCapacityControlMethod('VAV') + # Rename some nodes and such, for ease of debugging -oa_sys.outboardOANode.get.setName("OA Inlet Node"); -oa_sys.outboardReliefNode.get.setName("OA Relief Node"); -oa_sys.reliefAirModelObject.get.setName("Return to OA System Node"); -oa_sys.outdoorAirModelObject.get.setName("OA System Outlet to Mixed Node"); +oa_sys.outboardOANode.get.setName('OA Inlet Node') +oa_sys.outboardReliefNode.get.setName('OA Relief Node') +oa_sys.reliefAirModelObject.get.setName('Return to OA System Node') +oa_sys.outdoorAirModelObject.get.setName('OA System Outlet to Mixed Node') primary_coil.waterInletModelObject.get.setName("#{primary_coil.name} Water Inlet Node") primary_coil.waterOutletModelObject.get.setName("#{primary_coil.name} Water Outlet Node") # primary_coil.controllerWaterCoil.get.setName("#{primary_coil.name} Controller") - ###### # save the OpenStudio model (.osm) From aceb27377d25238373835163a3fe248604c815ff Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 5 May 2025 23:13:02 +0200 Subject: [PATCH 9/9] Add a python version of the ruby test --- .../coilsystem_cooling_water.py | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 model/simulationtests/coilsystem_cooling_water.py diff --git a/model/simulationtests/coilsystem_cooling_water.py b/model/simulationtests/coilsystem_cooling_water.py new file mode 100644 index 00000000..baf6cda5 --- /dev/null +++ b/model/simulationtests/coilsystem_cooling_water.py @@ -0,0 +1,190 @@ +import openstudio +from lib.baseline_model import BaselineModel + +m = BaselineModel() + +# make a 1 story, 100m X 50m, 1 zone core/perimeter building +m.add_geometry(length=100, width=50, num_floors=1, floor_to_floor_height=4, plenum_height=1, perimeter_zone_depth=0) + +# add windows at a 40% window-to-wall ratio +m.add_windows(wwr=0.4, offset=1, application_type="Above Floor") + +# add thermostats +m.add_thermostats(heating_setpoint=24, cooling_setpoint=28) + +# assign constructions from a local library to the walls/windows/etc. in the model +m.set_constructions() + +# set whole building space type; simplified 90.1-2004 Large Office Whole Building +m.set_space_type() + +# add design days to the model (Chicago) +m.add_design_days() + +# add ASHRAE System type 07, VAV w/ Reheat +m.add_hvac(ashrae_sys_num="07") + +# In order to produce more consistent results between different runs, +# we sort the zones by names (only one here anyways...) +zones = sorted(m.getThermalZones(), key=lambda z: z.nameString()) + +### Water Side Economizer Model ### + +zone = zones[0] +airloop = zone.airLoopHVAC().get() +airloop.setName("AirLoopHVAC CoilSystemCoolingWater") + +# create a CoilSystemCoolingWater object +coil_system = openstudio.model.CoilSystemCoolingWater(m) +coil_system.setName("CoilSystemCoolingWater WaterSide") + +water_coil = coil_system.coolingCoil().to_CoilCoolingWater().get() +water_coil.setName("CoilSystemCoolingWater WaterSide CoolingCoil") + +# Set coil conditions to mimic "Free Cooling Coil" from WaterSideEconomizer_PreCoolCoil.idf +water_coil.setDesignInletWaterTemperature(11.0) +water_coil.setDesignInletAirTemperature(34.0) +water_coil.setDesignOutletAirTemperature(16.0) +water_coil.setDesignInletAirHumidityRatio(0.009) +water_coil.setDesignOutletAirHumidityRatio(0.009) + +# As a water-side economizer the CoilSystem:Cooling:Water object is placed upstream of packaged DX systems or chilled water main cooling coil +# We have a Chilled water coil already, so let's keep it +central_cooling_coil = ( + airloop.supplyComponents(openstudio.model.CoilCoolingWater.iddObjectType())[0].to_CoilCoolingWater().get() +) +central_cooling_coil.setName("Central ChW Coil") + +# Note that we connect the CoilSystem, NOT the underlying CoilCoolingWater +coil_system.addToNode(central_cooling_coil.airInletModelObject().get().to_Node().get()) +# But we have to connect the water_coil itself. Ideally this would be on a Condenser Loop, so let's get it +cts = sorted(m.getCoolingTowerSingleSpeeds(), key=lambda c: c.nameString()) +condenser_loop = cts[0].plantLoop().get() +condenser_loop.addDemandBranchForComponent(water_coil) + +# Rename some nodes and such, for ease of debugging +airloop.supplyInletNode().setName("#{airloop.nameString()} Supply Inlet Node") +airloop.supplyOutletNode().setName("#{airloop.nameString()} Supply Outlet Node") +airloop.mixedAirNode().get().setName("#{airloop.nameString()} Mixed Air Node") + +central_heating_coil = ( + airloop.supplyComponents(openstudio.model.CoilHeatingWater.iddObjectType())[0].to_CoilHeatingWater().get() +) +central_heating_coil.setName("Central HW Coil") +coil_system.outletModelObject().get().to_Node().get().setName( + "#{coil_system.nameString()} Air Outlet to #{central_cooling_coil.nameString()} Inlet Node" +) +central_cooling_coil.airOutletModelObject().get().to_Node().get().setName( + "#{central_cooling_coil.nameString()} Air Outlet to #{central_heating_coil.nameString()} Inlet Node" +) + +water_coil.waterInletModelObject().get().setName("#{water_coil.nameString()} Water Inlet Node") +water_coil.waterOutletModelObject().get().setName("#{water_coil.nameString()} Water Outlet Node") +# water_coil.controllerWaterCoil.get.setName("#{water_coil.name} Controller") + +fan = airloop.supplyFan().get() +fan.setName("Supply Fan") + +central_heating_coil.waterOutletModelObject().get().setName("#{airloop.nameString()} Heating Coil Water Outlet Node") +central_heating_coil.controllerWaterCoil().get().setName("#{airloop.nameString()} Heating Coil Controller") +central_heating_coil.airOutletModelObject().get().setName( + "#{central_heating_coil.nameString()} Air Outlet to #{fan.nameString()} Inlet Node" +) + +###### + +### Wrap Around Water Coil Heat Recovery Mode ### + +# 5ZoneAirCooled_RunaroundHeatRecovery.idf +# +# create heat recovery plant loop +hr_loop = openstudio.model.PlantLoop(m) +hr_loop.setName("Run Around Coil HR Loop") + +plant_siz = hr_loop.sizingPlant() +plant_siz.setLoopType("Cooling") +plant_siz.setDesignLoopExitTemperature(7) +plant_siz.setLoopDesignTemperatureDifference(4) + +# create supply side pump +pump = openstudio.model.PumpVariableSpeed(m) +pump.setName("HR Circ Pump") +pump.setCoefficient1ofthePartLoadPerformanceCurve(0) +pump.setCoefficient2ofthePartLoadPerformanceCurve(1) +pump.setCoefficient3ofthePartLoadPerformanceCurve(0) +pump.setCoefficient4ofthePartLoadPerformanceCurve(0) + +hr_loop.addSupplyBranchForComponent(pump) + +# zone = zones[1] +# airloop = zone.airLoopHVAC.get +# airloop.setName('AirLoopHVAC CoilSystemCoolingWater WrapAround') + +oa_sys = airloop.airLoopHVACOutdoorAirSystem().get() + +# TODO: use a CoilSystemCoolingWaterHeatExchangerAssisted +primary_coil = openstudio.model.CoilCoolingWater(m, m.alwaysOnDiscreteSchedule()) +primary_coil.setName("#{airloop.nameString()} Primary HR Coil") +# primary_coil.setDesignWaterTemperatureDifference(4) + +companion_coil = openstudio.model.CoilCoolingWater(m, m.alwaysOnDiscreteSchedule()) +companion_coil.setName("#{airloop.nameString()} Companion HR Coil") +# companion_coil.setDesignWaterTemperatureDifference(4) + +coil_sys = openstudio.model.CoilSystemCoolingWater(m, primary_coil) +coil_sys.setName("CoilSystemCoolingWater WrapAround") +coil_sys.setCompanionCoilUsedForHeatRecovery(companion_coil) +coil_sys.setMinimumAirToWaterTemperatureOffset(3.0) +coil_sys.setMinimumWaterLoopTemperatureForHeatRecovery(5.0) + +coil_sys.addToNode(oa_sys.outboardOANode().get()) +companion_coil.addToNode(oa_sys.outboardReliefNode().get()) + +# connect to plant loop +hr_loop.addDemandBranchForComponent(primary_coil) +pipe = openstudio.model.PipeAdiabatic(m) +pipe.addToNode(primary_coil.waterOutletModelObject().get().to_Node().get()) +companion_coil.addToNode(pipe.outletModelObject().get().to_Node().get()) + +coil_spm_sch = openstudio.model.ScheduleConstant(m) +coil_spm_sch.setName("OA HR Supply Air Temp Sch") +coil_spm_sch.setValue(4.5) + +primary_coil_spm = openstudio.model.SetpointManagerScheduled(m, coil_spm_sch) +primary_coil_spm.setName("OA Air Temp Manager HR1") +# primary_coil_spm.addToNode(coil_sys.airOutletModelObject.get.to_Node.get) +# primary_coil_spm.addToNode(coil_sys.outletModelObject.get.to_Node.get) + +companion_coil_spm = openstudio.model.SetpointManagerScheduled(m, coil_spm_sch) +companion_coil_spm.setName("OA Air Temp Manager HR2") +# companion_coil_spm.addToNode(companion_coil.airOutletModelObject.get.to_Node.get) + +hr_loop_spm = openstudio.model.SetpointManagerScheduled(m, coil_spm_sch) +hr_loop_spm.setName("OA Air Temp Manager HR3") +hr_loop_spm.addToNode(hr_loop.loopTemperatureSetpointNode()) + +sz = airloop.sizingSystem() +sz.setPreheatDesignTemperature(4.5) +sz.setPrecoolDesignTemperature(11.0) +sz.setCentralCoolingDesignSupplyAirTemperature(12.8) +sz.setCentralHeatingDesignSupplyAirTemperature(16.7) +sz.setAllOutdoorAirinCooling(False) +sz.setAllOutdoorAirinHeating(False) +sz.setCentralCoolingDesignSupplyAirHumidityRatio(0.008) +sz.setCentralCoolingCapacityControlMethod("VAV") + +# Rename some nodes and such, for ease of debugging +oa_sys.outboardOANode().get().setName("OA Inlet Node") +oa_sys.outboardReliefNode().get().setName("OA Relief Node") +oa_sys.reliefAirModelObject().get().setName("Return to OA System Node") +oa_sys.outdoorAirModelObject().get().setName("OA System Outlet to Mixed Node") + +primary_coil.waterInletModelObject().get().setName("#{primary_coil.name()} Water Inlet Node") +primary_coil.waterOutletModelObject().get().setName("#{primary_coil.name()} Water Outlet Node") +# primary_coil.controllerWaterCoil.get.setName("#{primary_coil.name} Controller") + + +###### + +# save the OpenStudio model (.osm) +m.save_openstudio_osm(osm_save_directory=None, osm_name="in.osm")