diff --git a/src/energyplus/CMakeLists.txt b/src/energyplus/CMakeLists.txt index fd1d301ed6..48f956fd4c 100644 --- a/src/energyplus/CMakeLists.txt +++ b/src/energyplus/CMakeLists.txt @@ -706,6 +706,7 @@ set(${target_name}_test_src Test/CoilCoolingDXTwoSpeed_GTest.cpp Test/CoilCoolingDXTwoStageWithHumidityControlMode_GTest.cpp Test/CoilCoolingDXVariableSpeed_GTest.cpp + Test/CoilCoolingWater_GTest.cpp Test/CoilCoolingWaterToAirHeatPumpEquationFit_GTest.cpp Test/CoilCoolingWaterToAirHeatPumpVariableSpeedEquationFit_GTest.cpp Test/CoilHeatingDXMultiSpeed_GTest.cpp @@ -716,6 +717,7 @@ set(${target_name}_test_src Test/CoilHeatingGasMultiStage_GTest.cpp Test/CoilHeatingWaterToAirHeatPumpEquationFit_GTest.cpp Test/CoilHeatingWaterToAirHeatPumpVariableSpeedEquationFit_GTest.cpp + Test/CoilSystemCoolingWaterHeatExchangerAssisted_GTest.cpp Test/CoilSystemIntegratedHeatPumpAirSource_GTest.cpp Test/CoilUserDefined_GTest.cpp Test/CoilWaterHeatingAirToWaterHeatPump_GTest.cpp diff --git a/src/energyplus/ForwardTranslator.cpp b/src/energyplus/ForwardTranslator.cpp index 8eaef4ae05..a264233466 100644 --- a/src/energyplus/ForwardTranslator.cpp +++ b/src/energyplus/ForwardTranslator.cpp @@ -1072,7 +1072,11 @@ namespace energyplus { } case openstudio::IddObjectType::OS_Coil_Cooling_Water: { auto coil = modelObject.cast(); - retVal = translateCoilCoolingWater(coil); + if (isHVACComponentWithinUnitary(coil)) { + retVal = translateCoilCoolingWaterWithoutUnitary(coil); + } else { + retVal = translateCoilCoolingWater(coil); + } break; } case openstudio::IddObjectType::OS_Coil_Cooling_Water_Panel_Radiant: { @@ -1208,8 +1212,12 @@ namespace energyplus { break; } case openstudio::IddObjectType::OS_CoilSystem_Cooling_Water_HeatExchangerAssisted: { - auto mo = modelObject.cast(); - retVal = translateCoilSystemCoolingWaterHeatExchangerAssisted(mo); + auto coil = modelObject.cast(); + if (isHVACComponentWithinUnitary(coil)) { + retVal = translateCoilSystemCoolingWaterHeatExchangerAssistedWithoutUnitary(coil); + } else { + retVal = translateCoilSystemCoolingWaterHeatExchangerAssisted(coil); + } break; } case openstudio::IddObjectType::OS_CoilSystem_Cooling_DX_HeatExchangerAssisted: { diff --git a/src/energyplus/ForwardTranslator.hpp b/src/energyplus/ForwardTranslator.hpp index e2699e9f9a..c22eb2e5fa 100644 --- a/src/energyplus/ForwardTranslator.hpp +++ b/src/energyplus/ForwardTranslator.hpp @@ -801,6 +801,8 @@ namespace energyplus { boost::optional translateCoilCoolingWater(model::CoilCoolingWater& modelObject); + boost::optional translateCoilCoolingWaterWithoutUnitary(model::CoilCoolingWater& modelObject); + boost::optional translateCoilCoolingWaterToAirHeatPumpEquationFit(model::CoilCoolingWaterToAirHeatPumpEquationFit& modelObject); boost::optional @@ -844,6 +846,9 @@ namespace energyplus { boost::optional translateCoilSystemCoolingWaterHeatExchangerAssisted(model::CoilSystemCoolingWaterHeatExchangerAssisted& modelObject); + boost::optional + translateCoilSystemCoolingWaterHeatExchangerAssistedWithoutUnitary(model::CoilSystemCoolingWaterHeatExchangerAssisted& modelObject); + boost::optional translateCoilSystemIntegratedHeatPumpAirSource(model::CoilSystemIntegratedHeatPumpAirSource& modelObject); boost::optional translateCoilUserDefined(model::CoilUserDefined& modelObject); diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateCoilCoolingWater.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateCoilCoolingWater.cpp index 8968638ad8..744fd357b1 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslateCoilCoolingWater.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslateCoilCoolingWater.cpp @@ -13,6 +13,7 @@ #include "../../model/CoilCoolingWater_Impl.hpp" #include "../../utilities/core/Logger.hpp" #include "../../utilities/core/Assert.hpp" +#include #include #include "../../utilities/idd/IddEnums.hpp" #include @@ -26,7 +27,7 @@ namespace openstudio { namespace energyplus { - boost::optional ForwardTranslator::translateCoilCoolingWater(CoilCoolingWater& modelObject) { + boost::optional ForwardTranslator::translateCoilCoolingWaterWithoutUnitary(model::CoilCoolingWater& modelObject) { boost::optional s; boost::optional value; @@ -150,8 +151,55 @@ namespace energyplus { return boost::optional(idfObject); } - //((Name)(Name)) - //((AvailabilityScheduleName)(Availability Schedule Name)) + boost::optional ForwardTranslator::translateCoilCoolingWater(CoilCoolingWater& modelObject) { + IdfObject coilSystemCoolingWaterIdf(IddObjectType::CoilSystem_Cooling_Water); + + m_idfObjects.push_back(coilSystemCoolingWaterIdf); + + boost::optional oIdfObject = translateCoilCoolingWaterWithoutUnitary(modelObject); + + if (!oIdfObject) { + return boost::none; + } + + IdfObject idfObject = oIdfObject.get(); + + OptionalString s; + + s = modelObject.name(); + if (s) { + coilSystemCoolingWaterIdf.setString(CoilSystem_Cooling_WaterFields::CoolingCoilObjectType, idfObject.iddObject().name()); + + coilSystemCoolingWaterIdf.setString(CoilSystem_Cooling_WaterFields::CoolingCoilName, *s); + + coilSystemCoolingWaterIdf.setName(*s + " CoilSystem"); + } + + Schedule sched = modelObject.availabilitySchedule(); + translateAndMapModelObject(sched); + + coilSystemCoolingWaterIdf.setString(CoilSystem_Cooling_WaterFields::AvailabilityScheduleName, sched.name().get()); + + OptionalModelObject omo = modelObject.airInletModelObject(); + if (omo) { + translateAndMapModelObject(*omo); + s = omo->name(); + if (s) { + coilSystemCoolingWaterIdf.setString(CoilSystem_Cooling_WaterFields::AirInletNodeName, *s); + } + } + + omo = modelObject.airOutletModelObject(); + if (omo) { + translateAndMapModelObject(*omo); + s = omo->name(); + if (s) { + coilSystemCoolingWaterIdf.setString(CoilSystem_Cooling_WaterFields::AirOutletNodeName, *s); + } + } + + return coilSystemCoolingWaterIdf; + } } // namespace energyplus diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWaterHeatExchangerAssisted.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWaterHeatExchangerAssisted.cpp index 3cd67ee19a..0197e59eb1 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWaterHeatExchangerAssisted.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWaterHeatExchangerAssisted.cpp @@ -27,6 +27,7 @@ #include "../../model/Model.hpp" #include "../../utilities/core/Assert.hpp" +#include #include #include #include @@ -41,8 +42,8 @@ namespace openstudio { namespace energyplus { - boost::optional - ForwardTranslator::translateCoilSystemCoolingWaterHeatExchangerAssisted(CoilSystemCoolingWaterHeatExchangerAssisted& modelObject) { + boost::optional ForwardTranslator::translateCoilSystemCoolingWaterHeatExchangerAssistedWithoutUnitary( + model::CoilSystemCoolingWaterHeatExchangerAssisted& modelObject) { IdfObject idfObject = createRegisterAndNameIdfObject(openstudio::IddObjectType::CoilSystem_Cooling_Water_HeatExchangerAssisted, modelObject); @@ -157,5 +158,51 @@ namespace energyplus { return idfObject; } + boost::optional + ForwardTranslator::translateCoilSystemCoolingWaterHeatExchangerAssisted(CoilSystemCoolingWaterHeatExchangerAssisted& modelObject) { + IdfObject coilSystemCoolingWaterIdf(IddObjectType::CoilSystem_Cooling_Water); + + m_idfObjects.push_back(coilSystemCoolingWaterIdf); + + boost::optional oIdfObject = translateCoilSystemCoolingWaterHeatExchangerAssistedWithoutUnitary(modelObject); + + if (!oIdfObject) { + return boost::none; + } + + IdfObject idfObject = oIdfObject.get(); + + OptionalString s; + + s = modelObject.name(); + if (s) { + coilSystemCoolingWaterIdf.setString(CoilSystem_Cooling_WaterFields::CoolingCoilObjectType, idfObject.iddObject().name()); + + coilSystemCoolingWaterIdf.setString(CoilSystem_Cooling_WaterFields::CoolingCoilName, *s); + + coilSystemCoolingWaterIdf.setName(*s + " CoilSystem"); + } + + OptionalModelObject omo = modelObject.inletModelObject(); + if (omo) { + translateAndMapModelObject(*omo); + s = omo->name(); + if (s) { + coilSystemCoolingWaterIdf.setString(CoilSystem_Cooling_WaterFields::AirInletNodeName, *s); + } + } + + omo = modelObject.outletModelObject(); + if (omo) { + translateAndMapModelObject(*omo); + s = omo->name(); + if (s) { + coilSystemCoolingWaterIdf.setString(CoilSystem_Cooling_WaterFields::AirOutletNodeName, *s); + } + } + + return coilSystemCoolingWaterIdf; + } + } // namespace energyplus } // namespace openstudio diff --git a/src/energyplus/ForwardTranslator/ForwardTranslatePlantLoop.cpp b/src/energyplus/ForwardTranslator/ForwardTranslatePlantLoop.cpp index a3dc363a53..86be1a7531 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslatePlantLoop.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslatePlantLoop.cpp @@ -76,6 +76,8 @@ #include "../../model/CoilCoolingCooledBeam_Impl.hpp" #include "../../model/CoilCoolingFourPipeBeam.hpp" #include "../../model/CoilCoolingFourPipeBeam_Impl.hpp" +#include "../../model/CoilCoolingWater.hpp" +#include "../../model/CoilCoolingWater_Impl.hpp" #include "../../model/CoilHeatingFourPipeBeam.hpp" #include "../../model/CoilHeatingFourPipeBeam_Impl.hpp" #include "../../model/StraightComponent.hpp" @@ -116,6 +118,7 @@ #include #include #include +#include #include "../../utilities/core/Assert.hpp" using namespace openstudio::model; @@ -300,6 +303,17 @@ namespace energyplus { if (loop.optionalCast()) { inletNode = waterToAirComponent->waterInletModelObject()->optionalCast(); outletNode = waterToAirComponent->waterOutletModelObject()->optionalCast(); + // Special case for Coil:Cooling:Water. + if (boost::optional ccw = modelObject.optionalCast()) { + boost::optional idfCoil = this->translateAndMapModelObject(*ccw); + if (idfCoil) { + if (idfCoil->iddObject().type() == IddObjectType::CoilSystem_Cooling_Water) { + //Get the name and idd type of the coil cooling water inside the coil system + objectName = idfCoil->getString(CoilSystem_Cooling_WaterFields::CoolingCoilName).get(); + iddType = idfCoil->getString(CoilSystem_Cooling_WaterFields::CoolingCoilObjectType).get(); + } + } + } } else { inletNode = waterToAirComponent->airInletModelObject()->optionalCast(); outletNode = waterToAirComponent->airOutletModelObject()->optionalCast(); diff --git a/src/energyplus/Test/CoilCoolingWater_GTest.cpp b/src/energyplus/Test/CoilCoolingWater_GTest.cpp new file mode 100644 index 0000000000..52e440931b --- /dev/null +++ b/src/energyplus/Test/CoilCoolingWater_GTest.cpp @@ -0,0 +1,167 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC. +* See also https://openstudio.net/license +***********************************************************************************************************************/ + +#include +#include "EnergyPlusFixture.hpp" + +#include "../ForwardTranslator.hpp" + +#include "../../model/Model.hpp" +#include "../../model/CoilCoolingWater.hpp" +#include "../../model/CoilCoolingWater_Impl.hpp" + +#include "../../model/AirLoopHVAC.hpp" +#include "../../model/AirLoopHVACUnitarySystem.hpp" +#include "../../model/Node.hpp" + +#include "../../utilities/idf/IdfObject.hpp" +#include "../../utilities/idf/IdfObject_Impl.hpp" +#include "../../utilities/idf/WorkspaceObject.hpp" +#include "../../utilities/idf/WorkspaceObject_Impl.hpp" +#include "../../utilities/idf/IdfExtensibleGroup.hpp" +#include "../../utilities/idf/WorkspaceExtensibleGroup.hpp" + +#include +#include +#include +#include +#include +#include +#include + +using namespace openstudio::energyplus; +using namespace openstudio::model; +using namespace openstudio; + +TEST_F(EnergyPlusFixture, ForwardTranslator_CoilCoolingWater_Unitary) { + Model m; + CoilCoolingWater coil(m); + coil.setName("My CoilCoolingWater"); + + // put it inside a Unitary, and put Unitary on an AirLoopHVAC so it gets translated + AirLoopHVACUnitarySystem unitary(m); + unitary.setCoolingCoil(coil); + AirLoopHVAC airLoop(m); + Node supplyOutletNode = airLoop.supplyOutletNode(); + unitary.addToNode(supplyOutletNode); + ASSERT_TRUE(unitary.inletNode()); + EXPECT_TRUE(unitary.inletNode()->setName("Coil Air Inlet Node")); + ASSERT_TRUE(unitary.outletNode()); + EXPECT_TRUE(unitary.outletNode()->setName("Coil Air Outlet Node")); + + // They must be connected to a PlantLoop too + PlantLoop chw_p(m); + chw_p.addDemandBranchForComponent(coil); + coil.waterInletModelObject()->setName("Coil Water Inlet Node"); + coil.waterOutletModelObject()->setName("Coil Water Outlet Node"); + + ForwardTranslator ft; + Workspace w = ft.translateModel(m); + + WorkspaceObjectVector idfUnitarys(w.getObjectsByType(IddObjectType::AirLoopHVAC_UnitarySystem)); + ASSERT_EQ(1u, idfUnitarys.size()); + WorkspaceObject idfUnitary(idfUnitarys[0]); + + WorkspaceObjectVector idfCoils(w.getObjectsByType(IddObjectType::Coil_Cooling_Water)); + ASSERT_EQ(1u, idfCoils.size()); + WorkspaceObject idfCoil(idfCoils[0]); + + // No CoilSystem:Cooling:Water wrapper needed, it's inside a unitary + EXPECT_EQ(0, w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water).size()); + + // Check that the Unitary ends up with the CoilCoolingWater + EXPECT_EQ("Coil:Cooling:Water", idfUnitary.getString(AirLoopHVAC_UnitarySystemFields::CoolingCoilObjectType).get()); + EXPECT_EQ(idfCoil.nameString(), idfUnitary.getString(AirLoopHVAC_UnitarySystemFields::CoolingCoilName).get()); + + // Since the Unitary only has a Cooling Coil (no fan, not HC / Suppl HC), the nodes should match + EXPECT_EQ(idfUnitary.getString(AirLoopHVAC_UnitarySystemFields::AirInletNodeName).get(), + idfCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); + + EXPECT_EQ(idfUnitary.getString(AirLoopHVAC_UnitarySystemFields::AirOutletNodeName).get(), + idfCoil.getString(Coil_Cooling_WaterFields::AirOutletNodeName).get()); + + EXPECT_EQ("My CoilCoolingWater", idfCoil.getString(Coil_Cooling_WaterFields::Name).get()); + EXPECT_EQ("Always On Discrete", idfCoil.getString(Coil_Cooling_WaterFields::AvailabilityScheduleName).get()); + EXPECT_EQ("Autosize", idfCoil.getString(Coil_Cooling_WaterFields::DesignWaterFlowRate).get()); + EXPECT_EQ("Autosize", idfCoil.getString(Coil_Cooling_WaterFields::DesignAirFlowRate).get()); + EXPECT_EQ("Autosize", idfCoil.getString(Coil_Cooling_WaterFields::DesignInletWaterTemperature).get()); + EXPECT_EQ("Autosize", idfCoil.getString(Coil_Cooling_WaterFields::DesignInletAirTemperature).get()); + EXPECT_EQ("Autosize", idfCoil.getString(Coil_Cooling_WaterFields::DesignInletAirHumidityRatio).get()); + EXPECT_EQ("Autosize", idfCoil.getString(Coil_Cooling_WaterFields::DesignOutletAirHumidityRatio).get()); + EXPECT_EQ("Coil Water Inlet Node", idfCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); + EXPECT_EQ("Coil Water Outlet Node", idfCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); + EXPECT_EQ("Coil Air Inlet Node", idfCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ("Coil Air Outlet Node", idfCoil.getString(Coil_Cooling_WaterFields::AirOutletNodeName).get()); + EXPECT_EQ("SimpleAnalysis", idfCoil.getString(Coil_Cooling_WaterFields::TypeofAnalysis).get()); + EXPECT_EQ("CrossFlow", idfCoil.getString(Coil_Cooling_WaterFields::HeatExchangerConfiguration).get()); + EXPECT_TRUE(idfCoil.isEmpty(Coil_Cooling_WaterFields::CondensateCollectionWaterStorageTankName)); + EXPECT_TRUE(idfCoil.isEmpty(Coil_Cooling_WaterFields::DesignWaterTemperatureDifference)); +} + +TEST_F(EnergyPlusFixture, ForwardTranslator_CoilCoolingWater_AirLoopHVAC) { + Model m; + CoilCoolingWater coil(m); + + // put it on an AirLoopHVAC + AirLoopHVAC airLoop(m); + Node supplyOutletNode = airLoop.supplyOutletNode(); + EXPECT_TRUE(coil.addToNode(supplyOutletNode)); + + // They must be connected to a PlantLoop too + PlantLoop chw_p(m); + chw_p.addDemandBranchForComponent(coil); + + ForwardTranslator ft; + Workspace w = ft.translateModel(m); + + WorkspaceObjectVector idfCoils(w.getObjectsByType(IddObjectType::Coil_Cooling_Water)); + ASSERT_EQ(1u, idfCoils.size()); + WorkspaceObject idfCoil(idfCoils[0]); + + EXPECT_EQ(idfCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get(), coil.waterInletModelObject().get().nameString()); + EXPECT_EQ(idfCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get(), coil.waterOutletModelObject().get().nameString()); + EXPECT_EQ(idfCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get(), coil.airInletModelObject().get().nameString()); + EXPECT_EQ(idfCoil.getString(Coil_Cooling_WaterFields::AirOutletNodeName).get(), coil.airOutletModelObject().get().nameString()); + + EXPECT_EQ(1, w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water).size()); + + // Go from AirLoopHVAC to BranchList to Branch + WorkspaceObjectVector idf_airloops = w.getObjectsByType(IddObjectType::AirLoopHVAC); + ASSERT_EQ(1u, idf_airloops.size()); + + WorkspaceObject& idf_airLoopHVAC = idf_airloops.front(); + WorkspaceObject idf_brlist = idf_airLoopHVAC.getTarget(AirLoopHVACFields::BranchListName).get(); + + // Should have one branch only + ASSERT_EQ(1u, idf_brlist.extensibleGroups().size()); + auto w_eg = idf_brlist.extensibleGroups()[0].cast(); + WorkspaceObject idf_branch = w_eg.getTarget(BranchListExtensibleFields::BranchName).get(); + + // There should be only one equipment on the branch + ASSERT_EQ(1u, idf_branch.extensibleGroups().size()); + auto w_eg2 = idf_branch.extensibleGroups()[0].cast(); + + EXPECT_EQ(w_eg2.getString(BranchExtensibleFields::ComponentInletNodeName).get(), coil.airInletModelObject().get().nameString()); + EXPECT_EQ(w_eg2.getString(BranchExtensibleFields::ComponentOutletNodeName).get(), coil.airOutletModelObject().get().nameString()); + + EXPECT_EQ("CoilSystem:Cooling:Water", w_eg2.getString(BranchExtensibleFields::ComponentObjectType).get()); + auto idf_coilSystem = w_eg2.getTarget(BranchExtensibleFields::ComponentName).get(); + // CoilSystem:Cooling:Water wrapper needed, it's not inside a unitary + EXPECT_EQ(1, w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water).size()); + + EXPECT_EQ(coil.airInletModelObject().get().nameString(), idf_coilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ(coil.airOutletModelObject().get().nameString(), idf_coilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get()); + EXPECT_EQ("Always On Discrete", idf_coilSystem.getString(CoilSystem_Cooling_WaterFields::AvailabilityScheduleName).get()); + EXPECT_EQ("Coil:Cooling:Water", idf_coilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilObjectType).get()); + EXPECT_EQ(coil.nameString(), idf_coilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilName).get()); + EXPECT_EQ(idfCoil, idf_coilSystem.getTarget(CoilSystem_Cooling_WaterFields::CoolingCoilName).get()); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::DehumidificationControlType)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::RunonSensibleLoad)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::RunonLatentLoad)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::MinimumAirToWaterTemperatureOffset)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::EconomizerLockout)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::MinimumWaterLoopTemperatureForHeatRecovery)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery)); +} diff --git a/src/energyplus/Test/CoilSystemCoolingWaterHeatExchangerAssisted_GTest.cpp b/src/energyplus/Test/CoilSystemCoolingWaterHeatExchangerAssisted_GTest.cpp new file mode 100644 index 0000000000..7b43b17c56 --- /dev/null +++ b/src/energyplus/Test/CoilSystemCoolingWaterHeatExchangerAssisted_GTest.cpp @@ -0,0 +1,159 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC. +* See also https://openstudio.net/license +***********************************************************************************************************************/ + +#include +#include "EnergyPlusFixture.hpp" + +#include "../ForwardTranslator.hpp" + +#include "../../model/Model.hpp" +#include "../../model/CoilSystemCoolingWaterHeatExchangerAssisted.hpp" +#include "../../model/CoilSystemCoolingWaterHeatExchangerAssisted_Impl.hpp" +#include "../../model/CoilCoolingWater.hpp" +#include "../../model/CoilCoolingWater_Impl.hpp" +#include "../../model/HeatExchangerAirToAirSensibleAndLatent.hpp" +#include "../../model/HeatExchangerAirToAirSensibleAndLatent_Impl.hpp" + +#include "../../model/AirLoopHVAC.hpp" +#include "../../model/AirLoopHVACUnitarySystem.hpp" +#include "../../model/Node.hpp" + +#include "../../utilities/idf/IdfObject.hpp" +#include "../../utilities/idf/IdfObject_Impl.hpp" +#include "../../utilities/idf/WorkspaceObject.hpp" +#include "../../utilities/idf/WorkspaceObject_Impl.hpp" +#include "../../utilities/idf/IdfExtensibleGroup.hpp" +#include "../../utilities/idf/WorkspaceExtensibleGroup.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace openstudio::energyplus; +using namespace openstudio::model; +using namespace openstudio; + +TEST_F(EnergyPlusFixture, ForwardTranslator_CoilSystemCoolingWaterHeatExchangerAssisted_Unitary) { + Model m; + CoilSystemCoolingWaterHeatExchangerAssisted coil(m); + coil.setName("My CoilSystemCoolingWaterHeatExchangerAssisted"); + + // put it inside a Unitary, and put Unitary on an AirLoopHVAC so it gets translated + AirLoopHVACUnitarySystem unitary(m); + unitary.setCoolingCoil(coil); + AirLoopHVAC airLoop(m); + Node supplyOutletNode = airLoop.supplyOutletNode(); + unitary.addToNode(supplyOutletNode); + ASSERT_TRUE(unitary.inletNode()); + EXPECT_TRUE(unitary.inletNode()->setName("Coil Air Inlet Node")); + ASSERT_TRUE(unitary.outletNode()); + EXPECT_TRUE(unitary.outletNode()->setName("Coil Air Outlet Node")); + + // They must be connected to a PlantLoop too + PlantLoop chw_p(m); + chw_p.addDemandBranchForComponent(coil.coolingCoil()); + + ForwardTranslator ft; + Workspace w = ft.translateModel(m); + + WorkspaceObjectVector idfUnitarys(w.getObjectsByType(IddObjectType::AirLoopHVAC_UnitarySystem)); + ASSERT_EQ(1u, idfUnitarys.size()); + WorkspaceObject idfUnitary(idfUnitarys[0]); + + WorkspaceObjectVector idfCoils(w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water_HeatExchangerAssisted)); + ASSERT_EQ(1u, idfCoils.size()); + WorkspaceObject idfCoil(idfCoils[0]); + + WorkspaceObjectVector idfHXs(w.getObjectsByType(IddObjectType::HeatExchanger_AirToAir_SensibleAndLatent)); + ASSERT_EQ(1u, idfHXs.size()); + WorkspaceObject idfHX(idfHXs[0]); + + // No CoilSystem:Cooling:Water wrapper needed, it's inside a unitary + EXPECT_EQ(0, w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water).size()); + + // Check that the Unitary ends up with the CoilSystemCoolingWaterHeatExchangerAssisted + EXPECT_EQ("CoilSystem:Cooling:Water:HeatExchangerAssisted", idfUnitary.getString(AirLoopHVAC_UnitarySystemFields::CoolingCoilObjectType).get()); + EXPECT_EQ(idfCoil.nameString(), idfUnitary.getString(AirLoopHVAC_UnitarySystemFields::CoolingCoilName).get()); + + // Since the Unitary only has a Cooling Coil (no fan, not HC / Suppl HC), the nodes should match + EXPECT_EQ(idfUnitary.getString(AirLoopHVAC_UnitarySystemFields::AirInletNodeName).get(), + idfHX.getString(HeatExchanger_AirToAir_SensibleAndLatentFields::SupplyAirInletNodeName).get()); + + EXPECT_EQ(idfUnitary.getString(AirLoopHVAC_UnitarySystemFields::AirOutletNodeName).get(), + idfHX.getString(HeatExchanger_AirToAir_SensibleAndLatentFields::ExhaustAirOutletNodeName).get()); + + EXPECT_EQ("My CoilSystemCoolingWaterHeatExchangerAssisted", idfCoil.getString(CoilSystem_Cooling_Water_HeatExchangerAssistedFields::Name).get()); + EXPECT_EQ("HeatExchanger:AirToAir:SensibleAndLatent", + idfCoil.getString(CoilSystem_Cooling_Water_HeatExchangerAssistedFields::HeatExchangerObjectType).get()); + EXPECT_EQ(coil.heatExchanger().nameString(), idfCoil.getString(CoilSystem_Cooling_Water_HeatExchangerAssistedFields::HeatExchangerName).get()); + EXPECT_EQ("Coil:Cooling:Water", idfCoil.getString(CoilSystem_Cooling_Water_HeatExchangerAssistedFields::CoolingCoilObjectType).get()); + EXPECT_EQ(coil.coolingCoil().nameString(), idfCoil.getString(CoilSystem_Cooling_Water_HeatExchangerAssistedFields::CoolingCoilName).get()); +} + +TEST_F(EnergyPlusFixture, ForwardTranslator_CoilSystemCoolingWaterHeatExchangerAssisted_AirLoopHVAC) { + Model m; + CoilSystemCoolingWaterHeatExchangerAssisted coil(m); + + // put it on an AirLoopHVAC + AirLoopHVAC airLoop(m); + Node supplyOutletNode = airLoop.supplyOutletNode(); + EXPECT_TRUE(coil.addToNode(supplyOutletNode)); + + // They must be connected to a PlantLoop too + PlantLoop chw_p(m); + chw_p.addDemandBranchForComponent(coil.coolingCoil()); + + ForwardTranslator ft; + Workspace w = ft.translateModel(m); + + WorkspaceObjectVector idfCoils(w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water_HeatExchangerAssisted)); + ASSERT_EQ(1u, idfCoils.size()); + WorkspaceObject idfCoil(idfCoils[0]); + + EXPECT_EQ(1, w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water).size()); + + // Go from AirLoopHVAC to BranchList to Branch + WorkspaceObjectVector idf_airloops = w.getObjectsByType(IddObjectType::AirLoopHVAC); + ASSERT_EQ(1u, idf_airloops.size()); + + WorkspaceObject& idf_airLoopHVAC = idf_airloops.front(); + WorkspaceObject idf_brlist = idf_airLoopHVAC.getTarget(AirLoopHVACFields::BranchListName).get(); + + // Should have one branch only + ASSERT_EQ(1u, idf_brlist.extensibleGroups().size()); + auto w_eg = idf_brlist.extensibleGroups()[0].cast(); + WorkspaceObject idf_branch = w_eg.getTarget(BranchListExtensibleFields::BranchName).get(); + + // There should be only one equipment on the branch + ASSERT_EQ(1u, idf_branch.extensibleGroups().size()); + auto w_eg2 = idf_branch.extensibleGroups()[0].cast(); + + EXPECT_EQ(w_eg2.getString(BranchExtensibleFields::ComponentInletNodeName).get(), coil.inletModelObject().get().nameString()); + EXPECT_EQ(w_eg2.getString(BranchExtensibleFields::ComponentOutletNodeName).get(), coil.outletModelObject().get().nameString()); + + EXPECT_EQ("CoilSystem:Cooling:Water", w_eg2.getString(BranchExtensibleFields::ComponentObjectType).get()); + auto idf_coilSystem = w_eg2.getTarget(BranchExtensibleFields::ComponentName).get(); + // CoilSystem:Cooling:Water wrapper needed, it's not inside a unitary + EXPECT_EQ(1, w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water).size()); + + EXPECT_EQ(coil.inletModelObject().get().nameString(), idf_coilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ(coil.outletModelObject().get().nameString(), idf_coilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get()); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::AvailabilityScheduleName)); + EXPECT_EQ("CoilSystem:Cooling:Water:HeatExchangerAssisted", idf_coilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilObjectType).get()); + EXPECT_EQ(coil.nameString(), idf_coilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilName).get()); + EXPECT_EQ(idfCoil, idf_coilSystem.getTarget(CoilSystem_Cooling_WaterFields::CoolingCoilName).get()); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::DehumidificationControlType)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::RunonSensibleLoad)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::RunonLatentLoad)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::MinimumAirToWaterTemperatureOffset)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::EconomizerLockout)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::MinimumWaterLoopTemperatureForHeatRecovery)); + EXPECT_TRUE(idf_coilSystem.isEmpty(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery)); +}