From a9bcf9bead05c24fd9316fcca54759122f0e08d9 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 15 May 2020 15:26:26 +0200 Subject: [PATCH 1/4] Add test for #3984 --- src/energyplus/CMakeLists.txt | 1 + .../Test/ControllerOutdoorAir_GTest.cpp | 96 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 src/energyplus/Test/ControllerOutdoorAir_GTest.cpp diff --git a/src/energyplus/CMakeLists.txt b/src/energyplus/CMakeLists.txt index 78632d86d62..cc5dcd81ef4 100644 --- a/src/energyplus/CMakeLists.txt +++ b/src/energyplus/CMakeLists.txt @@ -583,6 +583,7 @@ set(${target_name}_test_src Test/CoilHeatingGas_GTest.cpp Test/CoilCoolingDXMultiSpeed_GTest.cpp Test/Construction_GTest.cpp + Test/ControllerOutdoorAir_GTest.cpp Test/DaylightingControl_GTest.cpp Test/DaylightingDeviceShelf_GTest.cpp Test/DesignSpecificationOutdoorAir_GTest.cpp diff --git a/src/energyplus/Test/ControllerOutdoorAir_GTest.cpp b/src/energyplus/Test/ControllerOutdoorAir_GTest.cpp new file mode 100644 index 00000000000..f868c7b3570 --- /dev/null +++ b/src/energyplus/Test/ControllerOutdoorAir_GTest.cpp @@ -0,0 +1,96 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +* following conditions are met: +* +* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following +* disclaimer. +* +* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the distribution. +* +* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products +* derived from this software without specific prior written permission from the respective party. +* +* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works +* may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior +* written permission from Alliance for Sustainable Energy, LLC. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED +* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +#include +#include "EnergyPlusFixture.hpp" + +#include "../ForwardTranslator.hpp" + +#include "../../model/ControllerOutdoorAir.hpp" + +#include "../../model/Model.hpp" +#include "../../model/AirLoopHVAC.hpp" +#include "../../model/AirLoopHVACOutdoorAirSystem.hpp" +#include "../../model/Node.hpp" +#include "../../model/ControllerMechanicalVentilation.hpp" + +#include +#include +#include "../../utilities/idf/IdfExtensibleGroup.hpp" + +#include "../../utilities/core/Logger.hpp" + +using namespace openstudio::energyplus; +using namespace openstudio::model; +using namespace openstudio; + + +TEST_F(EnergyPlusFixture, ForwardTranslator_ControllerOutdoorAir) { + // Test for #3984 + Model m; + ForwardTranslator ft; + + ControllerOutdoorAir controller_oa(m); + + // Not used: not translated + { + ASSERT_NO_THROW(ft.translateModel(m)); + Workspace w = ft.translateModel(m); + + WorkspaceObjectVector idf_controller_oas(w.getObjectsByType(IddObjectType::Controller_OutdoorAir)); + EXPECT_EQ(0u, idf_controller_oas.size()); + EXPECT_EQ(0u, w.getObjectsByType(IddObjectType::AirLoopHVAC).size()); + EXPECT_EQ(0u, w.getObjectsByType(IddObjectType::AirLoopHVAC_OutdoorAirSystem).size()); + } + + AirLoopHVAC a(m); + AirLoopHVACOutdoorAirSystem oa_sys(m, controller_oa); + + // Not used since the OutdoorAirSystem isn't used itself: not translated + { + Workspace w = ft.translateModel(m); + + WorkspaceObjectVector idf_controller_oas(w.getObjectsByType(IddObjectType::Controller_OutdoorAir)); + EXPECT_EQ(0u, idf_controller_oas.size()); + EXPECT_EQ(1u, w.getObjectsByType(IddObjectType::AirLoopHVAC).size()); + EXPECT_EQ(0u, w.getObjectsByType(IddObjectType::AirLoopHVAC_OutdoorAirSystem).size()); + } + + Node supplyOutlet = a.supplyOutletNode(); + EXPECT_TRUE(oa_sys.addToNode(supplyOutlet)); + // Not used: should be translated + { + Workspace w = ft.translateModel(m); + + WorkspaceObjectVector idf_controller_oas(w.getObjectsByType(IddObjectType::Controller_OutdoorAir)); + EXPECT_EQ(1u, idf_controller_oas.size()); + EXPECT_EQ(1u, w.getObjectsByType(IddObjectType::AirLoopHVAC).size()); + EXPECT_EQ(1u, w.getObjectsByType(IddObjectType::AirLoopHVAC_OutdoorAirSystem).size()); + } +} From b23d66d1bbc63cf258834ad9a890fa1c24ad99b8 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 15 May 2020 15:15:44 +0200 Subject: [PATCH 2/4] Fix #3984 - AirLoopHVAC translates the AirLoopHVACOutdoorAirSystem, which in turns translates the ControllerOutdoorAir. --- src/energyplus/ForwardTranslator.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/energyplus/ForwardTranslator.cpp b/src/energyplus/ForwardTranslator.cpp index 04c1ff1d225..0a460eb4aad 100644 --- a/src/energyplus/ForwardTranslator.cpp +++ b/src/energyplus/ForwardTranslator.cpp @@ -3570,7 +3570,10 @@ std::vector ForwardTranslator::iddObjectsToTranslateInitializer() result.push_back(IddObjectType::OS_AirLoopHVAC); result.push_back(IddObjectType::OS_AirLoopHVAC_ControllerList); - result.push_back(IddObjectType::OS_AirLoopHVAC_OutdoorAirSystem); + + // Translated by AirLoopHVAC (and AirLoopHVAC:DedicatedOutdoorAirSystem but not wrapped) + // result.push_back(IddObjectType::OS_AirLoopHVAC_OutdoorAirSystem) + result.push_back(IddObjectType::OS_AirLoopHVAC_UnitaryHeatCool_VAVChangeoverBypass); result.push_back(IddObjectType::OS_AirLoopHVAC_UnitaryCoolOnly); result.push_back(IddObjectType::OS_AirLoopHVAC_ZoneMixer); @@ -3594,7 +3597,7 @@ std::vector ForwardTranslator::iddObjectsToTranslateInitializer() result.push_back(IddObjectType::OS_Connection); result.push_back(IddObjectType::OS_Connector_Mixer); result.push_back(IddObjectType::OS_Connector_Splitter); - result.push_back(IddObjectType::OS_Controller_OutdoorAir); + // result.push_back(IddObjectType::OS_Controller_OutdoorAir); // Will be translated by the AirLoopHVACOutdoorAirSystem result.push_back(IddObjectType::OS_CoolingTower_SingleSpeed); result.push_back(IddObjectType::OS_Curve_Bicubic); result.push_back(IddObjectType::OS_Curve_Biquadratic); From d7bbe288bcbd22642e4c5f643ecbcc3895d0a5c3 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 15 May 2020 15:30:26 +0200 Subject: [PATCH 3/4] Add test for #3926 --- src/energyplus/Test/AirLoopHVAC_GTest.cpp | 70 +++++++++++++++++++++-- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/src/energyplus/Test/AirLoopHVAC_GTest.cpp b/src/energyplus/Test/AirLoopHVAC_GTest.cpp index 27af30d6d9a..a6946b656fe 100644 --- a/src/energyplus/Test/AirLoopHVAC_GTest.cpp +++ b/src/energyplus/Test/AirLoopHVAC_GTest.cpp @@ -33,30 +33,36 @@ #include "../ForwardTranslator.hpp" #include "../../model/AirLoopHVAC.hpp" +#include "../../model/AirLoopHVAC_Impl.hpp" #include "../../model/Model.hpp" #include "../../model/AvailabilityManagerAssignmentList.hpp" #include "../../model/AvailabilityManagerAssignmentList_Impl.hpp" #include "../../model/AvailabilityManagerScheduledOn.hpp" #include "../../model/Node.hpp" +#include "../../model/Schedule.hpp" #include "../../model/ScheduleCompact.hpp" #include "../../model/FanVariableVolume.hpp" #include "../../model/FanConstantVolume.hpp" #include "../../model/AirTerminalSingleDuctSeriesPIUReheat.hpp" +#include "../../model/AirTerminalSingleDuctConstantVolumeNoReheat.hpp" #include "../../model/CoilHeatingElectric.hpp" - +#include "../../model/DesignSpecificationOutdoorAir.hpp" #include "../../model/Space.hpp" #include "../../model/ThermalZone.hpp" -#include "../../utilities/geometry/Point3d.hpp" - -#include "../../model/AirLoopHVAC_Impl.hpp" #include "../../model/ThermalZone_Impl.hpp" +#include "../../model/AirLoopHVACOutdoorAirSystem.hpp" +#include "../../model/ControllerOutdoorAir.hpp" +#include "../../model/ControllerMechanicalVentilation.hpp" +#include "../../model/DesignDay.hpp" +#include "../../utilities/geometry/Point3d.hpp" #include #include #include #include #include +#include #include #include "../../utilities/idf/IdfExtensibleGroup.hpp" @@ -290,4 +296,60 @@ TEST_F(EnergyPlusFixture, ForwardTranslator_AirLoopHVAC_AvailabilityManagers_Nig } +TEST_F(EnergyPlusFixture, ForwardTranslator_AirLoopHVAC_MultiLoop_ControllerMV) { + // Test for #3926 + + Model m; + + ThermalZone z(m); + Space s(m); + DesignSpecificationOutdoorAir dsoa(m); + EXPECT_TRUE(dsoa.setOutdoorAirMethod("Sum")); + EXPECT_TRUE(dsoa.setOutdoorAirFlowAirChangesperHour(0.5)); + EXPECT_TRUE(s.setThermalZone(z)); + EXPECT_TRUE(s.setDesignSpecificationOutdoorAir(dsoa)); + + // Absolutely need a sizing period for the Sizing:Zone to be translated + DesignDay d(m); + + Schedule alwaysOn = m.alwaysOnDiscreteSchedule(); + + AirLoopHVAC a1(m); + ControllerOutdoorAir controller_oa1(m); + AirLoopHVACOutdoorAirSystem oa_sys1(m, controller_oa1); + Node supplyInletNode1 = a1.supplyInletNode(); + EXPECT_TRUE(oa_sys1.addToNode(supplyInletNode1)); + AirTerminalSingleDuctConstantVolumeNoReheat atu1(m, alwaysOn); + EXPECT_TRUE(a1.multiAddBranchForZone(z, atu1)); + + AirLoopHVAC a2(m); + ControllerOutdoorAir controller_oa2(m); + AirLoopHVACOutdoorAirSystem oa_sys2(m, controller_oa2); + Node supplyInletNode2 = a2.supplyInletNode(); + EXPECT_TRUE(oa_sys2.addToNode(supplyInletNode2)); + AirTerminalSingleDuctConstantVolumeNoReheat atu2(m, alwaysOn); + EXPECT_TRUE(a2.multiAddBranchForZone(z, atu2)); + + EXPECT_EQ(2u, z.airLoopHVACs().size()); + + ForwardTranslator ft; + Workspace w = ft.translateModel(m); + + WorkspaceObjectVector idf_controller_mvs(w.getObjectsByType(IddObjectType::Controller_MechanicalVentilation)); + ASSERT_EQ(2u, idf_controller_mvs.size()); + + int i = 1; + for (const auto& idf_controller_mv: idf_controller_mvs) { + // This construct is weird but I want to showcase that it works fine for the first ControllerMV but not the second one + // so I don't want to use ASSERT_EQ + if (idf_controller_mv.numExtensibleGroups() == 1u) { + IdfExtensibleGroup w_eg = idf_controller_mv.extensibleGroups()[0]; + EXPECT_EQ(z.nameString(), w_eg.getString(Controller_MechanicalVentilationExtensibleFields::ZoneorZoneListName).get()); + EXPECT_EQ(dsoa.nameString(), w_eg.getString(Controller_MechanicalVentilationExtensibleFields::DesignSpecificationOutdoorAirObjectName).get()); + } else { + EXPECT_EQ(1u, idf_controller_mv.numExtensibleGroups()) << "Failed for " << idf_controller_mv.nameString() << "(i = " << i << ")"; + } + ++i; + } +} From d8c85eaf168e067bfb49ab13c0f2dfb5c0080f9f Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 15 May 2020 15:49:17 +0200 Subject: [PATCH 4/4] Fix #3926 - handle multiple AirLoopHVACs and assign the DSOA to all ControllerMechanicalVentilation objects --- .../ForwardTranslateSizingZone.cpp | 91 +++++++------------ 1 file changed, 33 insertions(+), 58 deletions(-) diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateSizingZone.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateSizingZone.cpp index ecda47d9c1a..74a9b595e07 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslateSizingZone.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslateSizingZone.cpp @@ -64,26 +64,20 @@ boost::optional ForwardTranslator::translateSizingZone( SizingZone & boost::optional s; boost::optional value; - IdfObject idfObject(IddObjectType::Sizing_Zone); - - m_idfObjects.push_back(idfObject); - // ZoneorZoneListName - model::ThermalZone thermalZone = modelObject.thermalZone(); - boost::optional _thermalZone = translateAndMapModelObject(thermalZone); - - boost::optional name; - - if( _thermalZone ) - { - name = _thermalZone->name(); + if (!_thermalZone) { + // This shouldn't even happen, but in any case, there's no point translating a Sizing:Zone for no Zone... + return boost::none; } - if( name ) + IdfObject idfObject(IddObjectType::Sizing_Zone); + m_idfObjects.push_back(idfObject); + + std::string name = _thermalZone->nameString(); { - idfObject.setString(Sizing_ZoneFields::ZoneorZoneListName,name.get()); + idfObject.setString(Sizing_ZoneFields::ZoneorZoneListName, name); } // ZoneCoolingDesignSupplyAirTemperatureInputMethod @@ -261,11 +255,8 @@ boost::optional ForwardTranslator::translateSizingZone( SizingZone & { IdfObject dSZAD(IddObjectType::DesignSpecification_ZoneAirDistribution); - if( name ) - { - dSZADName = name.get() + " Design Spec Zone Air Dist"; - dSZAD.setName(dSZADName); - } + dSZADName = name + " Design Spec Zone Air Dist"; + dSZAD.setName(dSZADName); // register the DSZAD m_idfObjects.push_back(dSZAD); @@ -298,50 +289,34 @@ boost::optional ForwardTranslator::translateSizingZone( SizingZone & // Add ThermalZone and associated design objects to ControllerMechanicalVentilation. // This would be done in forwardTranslateControllerMechanicalVentilation except doing it here maintains proper order of the idf file. - boost::optional controllerMechanicalVentilation; - boost::optional _controllerMechanicalVentilation; - - if( boost::optional airLoopHVAC = thermalZone.airLoopHVAC() ) - { - if( boost::optional oaSystem = airLoopHVAC->airLoopHVACOutdoorAirSystem() ) - { + // Now that Multiple AirLoopHVACs serving the same zone are possible, need to loop on all + for (const auto& airLoopHVAC : thermalZone.airLoopHVACs()) { + if (boost::optional oaSystem = airLoopHVAC.airLoopHVACOutdoorAirSystem()) { model::ControllerOutdoorAir controllerOutdoorAir = oaSystem->getControllerOutdoorAir(); + model::ControllerMechanicalVentilation controllerMechanicalVentilation = controllerOutdoorAir.controllerMechanicalVentilation(); + if (boost::optional _controllerMechanicalVentilation = translateAndMapModelObject(controllerMechanicalVentilation)) { + IdfExtensibleGroup eg = _controllerMechanicalVentilation->pushExtensibleGroup(); + + // Thermal Zone Name + eg.setString(Controller_MechanicalVentilationExtensibleFields::ZoneorZoneListName, name); + + // DesignSpecificationOutdoorAir + std::vector spaces = thermalZone.spaces(); + + if (spaces.size() > 0) { + if (boost::optional designOASpec = spaces.front().designSpecificationOutdoorAir()) { + if (boost::optional _designOASpec = translateAndMapModelObject(designOASpec.get()) ) { + eg.setString(Controller_MechanicalVentilationExtensibleFields::DesignSpecificationOutdoorAirObjectName,_designOASpec->name().get()); + } + } + } - controllerMechanicalVentilation = controllerOutdoorAir.controllerMechanicalVentilation(); - } - } - - if( controllerMechanicalVentilation ) - { - _controllerMechanicalVentilation = translateAndMapModelObject(controllerMechanicalVentilation.get()); - } - - if( _controllerMechanicalVentilation && _thermalZone ) - { - IdfExtensibleGroup eg = _controllerMechanicalVentilation->pushExtensibleGroup(); - - // Thermal Zone Name - eg.setString(Controller_MechanicalVentilationExtensibleFields::ZoneorZoneListName,_thermalZone->name().get()); - - // DesignSpecificationOutdoorAir - std::vector spaces = thermalZone.spaces(); - - if( spaces.size() > 0 ) - { - if( boost::optional designOASpec = spaces.front().designSpecificationOutdoorAir() ) - { - if( boost::optional _designOASpec = translateAndMapModelObject(designOASpec.get()) ) - { - eg.setString(Controller_MechanicalVentilationExtensibleFields::DesignSpecificationOutdoorAirObjectName,_designOASpec->name().get()); + // DesignSpecificationZoneAirDistributionObjectName + if (isDSZADTranslated) { + eg.setString(Controller_MechanicalVentilationExtensibleFields::DesignSpecificationZoneAirDistributionObjectName, dSZADName); } } } - - // DesignSpecificationZoneAirDistributionObjectName - if( _thermalZone && isDSZADTranslated ) - { - eg.setString(Controller_MechanicalVentilationExtensibleFields::DesignSpecificationZoneAirDistributionObjectName, dSZADName); - } } if( modelObject.accountforDedicatedOutdoorAirSystem() ) {