diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateAirLoopHVAC.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateAirLoopHVAC.cpp index f43861de00..e40d2ebf48 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslateAirLoopHVAC.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslateAirLoopHVAC.cpp @@ -277,13 +277,6 @@ namespace energyplus { controller = supplyComponent.cast().controllerWaterCoil(); break; } - case openstudio::IddObjectType::OS_CoilSystem_Cooling_Water: { - auto coolingCoil = supplyComponent.cast().coolingCoil(); - if (auto coilCoolingWater = coolingCoil.optionalCast()) { - controller = coilCoolingWater->controllerWaterCoil(); - } - break; - } case openstudio::IddObjectType::OS_CoilSystem_Cooling_Water_HeatExchangerAssisted: { auto coolingCoil = supplyComponent.cast().coolingCoil(); if (auto coilCoolingWater = coolingCoil.optionalCast()) { @@ -291,6 +284,10 @@ namespace energyplus { } break; } + // case openstudio::IddObjectType::OS_CoilSystem_Cooling_Water: { + // // No-op: this has its own controller + // break; + // } default: { break; } diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWater.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWater.cpp index b2ec41fadf..f167f8bc18 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWater.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWater.cpp @@ -74,36 +74,32 @@ namespace energyplus { idf->setString(Coil_Cooling_WaterFields::AirInletNodeName, airInletNodeName); idf->setString(Coil_Cooling_WaterFields::AirOutletNodeName, airOutletNodeName); // Add IddObjectType::Coil_Cooling_Water_DetailedGeometry if implemented + } else if (idf->iddObject().type() == IddObjectType::CoilSystem_Cooling_Water_HeatExchangerAssisted) { + // The logic is built in the translateCoilSystemCoolingWaterHeatExchangerAssisted method + // Essentially it's the same as getting the HX (CoilSystem_Cooling_Water_HeatExchangerAssistedFields::HeatExchangerName) + // and setting HeatExchanger_AirToAir_SensibleAndLatentFields::SupplyAirInletNodeName & ExhaustAirOutletNodeName } else { - // Shouldn't happen, accepts only Coil:Cooling:Water or Coil:Cooling:Water:DetailedGeometry - // Shouldn't happen, accepts only Coil:Cooling:DX:SingleSpeed or Coil:Cooling:DX:VariableSpeed - LOG(Fatal, modelObject.briefDescription() - << " appears to have a cooling coil that shouldn't have been accepted: " << coolingCoil.briefDescription()); - OS_ASSERT(false); - } - } - if (auto coilCoolingWater = coolingCoil.optionalCast()) { - if (auto controller = coilCoolingWater->controllerWaterCoil()) { - if (auto idf = translateAndMapModelObject(controller.get())) { - idf->setString(Controller_WaterCoilFields::SensorNodeName, airOutletNodeName); - } + // Shouldn't happen, accepts only Coil:Cooling:Water CoilSystem:Cooling:Water:HeatExchangerAssisted (or Coil:Cooling:Water:DetailedGeometry, not wrapped) + LOG_AND_THROW(modelObject.briefDescription() + << " appears to have a cooling coil that shouldn't have been accepted: " << coolingCoil.briefDescription()); } } - // Need a SPM:MixedAir on the Coil:Cooling:Water outlet node (that we **created** just above in IDF directly, so it won't get picked up by the + // TODO: is that true?! + // Need a SPM:MixedAir on the outlet node (that we **created** just above in IDF directly, so it won't get picked up by the // ForwardTranslateAirLoopHVAC method) if (boost::optional airLoop_ = modelObject.airLoopHVAC()) { std::vector fans; std::vector supplyComponents = airLoop_->supplyComponents(); - for (auto it = supplyComponents.begin(); it != supplyComponents.end(); ++it) { - if (auto fan_ = it->optionalCast()) { + for (auto& supplyComponent : supplyComponents) { + if (auto fan_ = supplyComponent.optionalCast()) { fans.insert(fans.begin(), std::move(*fan_)); - } else if (auto fan_ = it->optionalCast()) { + } else if (auto fan_ = supplyComponent.optionalCast()) { fans.insert(fans.begin(), std::move(*fan_)); - } else if (auto fan_ = it->optionalCast()) { + } else if (auto fan_ = supplyComponent.optionalCast()) { fans.insert(fans.begin(), std::move(*fan_)); - } else if (auto fan_ = it->optionalCast()) { + } else if (auto fan_ = supplyComponent.optionalCast()) { fans.insert(fans.begin(), std::move(*fan_)); } } @@ -177,20 +173,21 @@ namespace energyplus { idfObject.setDouble(CoilSystem_Cooling_WaterFields::MinimumWaterLoopTemperatureForHeatRecovery, minimumWaterLoopTemperatureForHeatRecovery); // Companion Coil Used For Heat Recovery: Optional Object - if (boost::optional companionCoilUsedForHeatRecovery_ = modelObject.companionCoilUsedForHeatRecovery()) { - if (boost::optional wo_ = translateAndMapModelObject(companionCoilUsedForHeatRecovery_.get())) { - idfObject.setString(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery, wo_->nameString()); - if (wo_->iddObject().type() == IddObjectType::Coil_Cooling_Water) { - wo_->setString(Coil_Cooling_WaterFields::AirInletNodeName, modelObject.airLoopHVACOutdoorAirSystem()->reliefAirModelObject()->nameString()); - wo_->setString(Coil_Cooling_WaterFields::AirOutletNodeName, wo_->nameString() + " Exhaust Outlet Node"); // FIXME - // Add IddObjectType::Coil_Cooling_Water_DetailedGeometry if implemented + if (boost::optional companionCoilUsedForHeatRecovery_ = modelObject.companionCoilUsedForHeatRecovery()) { + if (auto comp_ = companionCoilUsedForHeatRecovery_->optionalCast()) { + if (comp_->airInletModelObject()) { + if (boost::optional idf_ = translateAndMapModelObject(companionCoilUsedForHeatRecovery_.get())) { + idfObject.setString(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery, idf_->nameString()); + } } else { - // Shouldn't happen, accepts only Coil:Cooling:Water or Coil:Cooling:Water:DetailedGeometry - // Shouldn't happen, accepts only Coil:Cooling:DX:SingleSpeed or Coil:Cooling:DX:VariableSpeed - LOG(Fatal, modelObject.briefDescription() << " appears to have a companion coil used for heat recovery that shouldn't have been accepted: " - << companionCoilUsedForHeatRecovery_.get().briefDescription()); - OS_ASSERT(false); + LOG(Warn, modelObject.briefDescription() + << " has a companion coil used for heat recovery that is not connected to an AirLoopHVAC / AirLoopHVACOutdoorAirSystem" + << " and will not be translated:" << comp_->briefDescription()); } + } else { + // Shouldn't happen, accepts only Coil:Cooling:Water + LOG_AND_THROW(modelObject.briefDescription() << " appears to have a companion coil used for heat recovery that shouldn't have been accepted: " + << companionCoilUsedForHeatRecovery_.get().briefDescription()); } } diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWaterHeatExchangerAssisted.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWaterHeatExchangerAssisted.cpp index 3cd67ee19a..e54247683b 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWaterHeatExchangerAssisted.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslateCoilSystemCoolingWaterHeatExchangerAssisted.cpp @@ -14,6 +14,8 @@ #include "../../model/CoilCoolingWater_Impl.hpp" #include "../../model/ControllerWaterCoil.hpp" #include "../../model/ControllerWaterCoil_Impl.hpp" +#include "../../model/CoilSystemCoolingWater.hpp" +#include "../../model/CoilSystemCoolingWater_Impl.hpp" #include "../../model/AirLoopHVAC.hpp" #include "../../model/FanVariableVolume.hpp" @@ -47,18 +49,30 @@ namespace energyplus { IdfObject idfObject = createRegisterAndNameIdfObject(openstudio::IddObjectType::CoilSystem_Cooling_Water_HeatExchangerAssisted, modelObject); std::string hxSupplyAirInletNodeName; + std::string hxExhaustAirOutletNodeName; // InletNodeName if (auto mo = modelObject.inletModelObject()) { if (auto node = mo->optionalCast()) { hxSupplyAirInletNodeName = node->nameString(); } - } - - std::string hxExhaustAirOutletNodeName; - // OutletNodeName - if (auto mo = modelObject.outletModelObject()) { - if (auto node = mo->optionalCast()) { - hxExhaustAirOutletNodeName = node->nameString(); + // OutletNodeName + if (auto mo = modelObject.outletModelObject()) { + if (auto node = mo->optionalCast()) { + hxExhaustAirOutletNodeName = node->nameString(); + } + } + } else if (auto comp_ = modelObject.containingHVACComponent()) { + if (auto coilSystem_ = comp_->optionalCast()) { + if (auto mo = coilSystem_->inletModelObject()) { + if (auto node = mo->optionalCast()) { + hxSupplyAirInletNodeName = node->nameString(); + } + } + if (auto mo = coilSystem_->outletModelObject()) { + if (auto node = mo->optionalCast()) { + hxExhaustAirOutletNodeName = node->nameString(); + } + } } } diff --git a/src/energyplus/Test/CoilSystemCoolingWater_GTest.cpp b/src/energyplus/Test/CoilSystemCoolingWater_GTest.cpp index 85b1838cb4..3746e2f41f 100644 --- a/src/energyplus/Test/CoilSystemCoolingWater_GTest.cpp +++ b/src/energyplus/Test/CoilSystemCoolingWater_GTest.cpp @@ -12,9 +12,13 @@ #include "../../model/CoilSystemCoolingWater_Impl.hpp" #include "../../model/Schedule.hpp" #include "../../model/Schedule_Impl.hpp" +#include "../../model/ScheduleConstant.hpp" #include "../../model/CoilCoolingWater.hpp" #include "../../model/CoilCoolingWater_Impl.hpp" - +#include "../../model/CoilSystemCoolingWaterHeatExchangerAssisted.hpp" +#include "../../model/CoilSystemCoolingWaterHeatExchangerAssisted_Impl.hpp" +#include "../../model/HeatExchangerAirToAirSensibleAndLatent.hpp" +#include "../../model/HeatExchangerAirToAirSensibleAndLatent_Impl.hpp" #include "../../model/AirLoopHVAC.hpp" #include "../../model/AirLoopHVACUnitarySystem.hpp" #include "../../model/Node.hpp" @@ -37,6 +41,8 @@ #include #include #include +#include +#include #include #include #include @@ -48,13 +54,106 @@ using namespace openstudio::energyplus; using namespace openstudio::model; using namespace openstudio; -TEST_F(EnergyPlusFixture, ForwardTranslator_CoilSystemCoolingWater_Unitary) { +TEST_F(EnergyPlusFixture, ForwardTranslator_CoilSystemCoolingWater_WithoutCompanion) { + ForwardTranslator ft; + + Model m; + + CoilSystemCoolingWater coilSystemCoolingWater(m); + auto cc = coilSystemCoolingWater.coolingCoil().cast(); + + coilSystemCoolingWater.setName("My CoilSystemCoolingWater"); + Schedule availabilitySchedule = m.alwaysOnDiscreteSchedule(); + EXPECT_TRUE(coilSystemCoolingWater.setAvailabilitySchedule(availabilitySchedule)); + EXPECT_TRUE(coilSystemCoolingWater.setDehumidificationControlType("CoolReheat")); + EXPECT_TRUE(coilSystemCoolingWater.setRunonSensibleLoad(false)); // Opposite from IDD default + EXPECT_TRUE(coilSystemCoolingWater.setRunonLatentLoad(true)); // Opposite from IDD default + EXPECT_TRUE(coilSystemCoolingWater.setMinimumAirToWaterTemperatureOffset(1.0)); + EXPECT_TRUE(coilSystemCoolingWater.setEconomizerLockout(false)); // Opposite from IDD default + EXPECT_TRUE(coilSystemCoolingWater.setMinimumWaterLoopTemperatureForHeatRecovery(1.2)); + + AirLoopHVAC airLoop(m); + Node supplyOutletNode = airLoop.supplyOutletNode(); + EXPECT_TRUE(coilSystemCoolingWater.addToNode(supplyOutletNode)); + + // They must be connected to a PlantLoop too + PlantLoop chw_p(m); + chw_p.addDemandBranchForComponent(cc); + const Workspace w = ft.translateModel(m); + + const auto idfCoilSystems = w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water); + ASSERT_EQ(1u, idfCoilSystems.size()); + const auto& idfCoilSystem = idfCoilSystems.front(); + + WorkspaceObjectVector idfCoils(w.getObjectsByType(IddObjectType::Coil_Cooling_Water)); + ASSERT_EQ(1u, idfCoils.size()); + WorkspaceObject idfCoil(idfCoils[0]); + + // 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(), coilSystemCoolingWater.inletModelObject().get().nameString()); + EXPECT_EQ(w_eg2.getString(BranchExtensibleFields::ComponentOutletNodeName).get(), coilSystemCoolingWater.outletModelObject().get().nameString()); + EXPECT_EQ("CoilSystem:Cooling:Water", w_eg2.getString(BranchExtensibleFields::ComponentObjectType).get()); + + EXPECT_EQ(coilSystemCoolingWater.inletModelObject().get().nameString(), + idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ(coilSystemCoolingWater.outletModelObject().get().nameString(), + idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get()); + EXPECT_EQ(availabilitySchedule.nameString(), idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AvailabilityScheduleName).get()); + EXPECT_EQ("Coil:Cooling:Water", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilObjectType).get()); + EXPECT_EQ(coilSystemCoolingWater.coolingCoil().nameString(), idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilName).get()); + EXPECT_EQ("CoolReheat", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::DehumidificationControlType).get()); + EXPECT_EQ("No", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::RunonSensibleLoad).get()); + EXPECT_EQ("Yes", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::RunonLatentLoad).get()); + EXPECT_EQ(1.0, idfCoilSystem.getDouble(CoilSystem_Cooling_WaterFields::MinimumAirToWaterTemperatureOffset).get()); + EXPECT_EQ("No", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::EconomizerLockout).get()); + EXPECT_EQ(1.2, idfCoilSystem.getDouble(CoilSystem_Cooling_WaterFields::MinimumWaterLoopTemperatureForHeatRecovery).get()); + EXPECT_TRUE(idfCoilSystem.isEmpty(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery)); + + EXPECT_EQ(coilSystemCoolingWater.coolingCoil().nameString(), 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(cc.waterInletModelObject().get().nameString(), idfCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); + EXPECT_EQ(cc.waterOutletModelObject().get().nameString(), idfCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); + EXPECT_EQ(idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get(), + idfCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ(idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get(), + 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)); + + EXPECT_EQ(0, w.getObjectsByType(IddObjectType::Controller_WaterCoil).size()); +} + +TEST_F(EnergyPlusFixture, ForwardTranslator_CoilSystemCoolingWater_WithCompanion) { ForwardTranslator ft; Model m; CoilSystemCoolingWater coilSystemCoolingWater(m); + auto cc = coilSystemCoolingWater.coolingCoil().cast(); coilSystemCoolingWater.setName("My CoilSystemCoolingWater"); Schedule availabilitySchedule = m.alwaysOnDiscreteSchedule(); @@ -66,262 +165,338 @@ TEST_F(EnergyPlusFixture, ForwardTranslator_CoilSystemCoolingWater_Unitary) { EXPECT_TRUE(coilSystemCoolingWater.setEconomizerLockout(false)); // Opposite from IDD default EXPECT_TRUE(coilSystemCoolingWater.setMinimumWaterLoopTemperatureForHeatRecovery(1.2)); CoilCoolingWater companionCoilUsedForHeatRecovery(m); + companionCoilUsedForHeatRecovery.setName("CompanionCoilUsedForHeatRecovery"); EXPECT_TRUE(coilSystemCoolingWater.setCompanionCoilUsedForHeatRecovery(companionCoilUsedForHeatRecovery)); - // put it inside a Unitary, and put Unitary on an AirLoopHVAC - AirLoopHVACUnitarySystem unitary(m); - EXPECT_FALSE(unitary.setCoolingCoil(coilSystemCoolingWater)); 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")); + ControllerOutdoorAir controller1(m); + AirLoopHVACOutdoorAirSystem oaSystem(m, controller1); + EXPECT_TRUE(oaSystem.addToNode(supplyOutletNode)); + Node oaNode = oaSystem.outboardOANode().get(); + EXPECT_TRUE(coilSystemCoolingWater.addToNode(oaNode)); + Node reliefNode = oaSystem.outboardReliefNode().get(); + EXPECT_TRUE(companionCoilUsedForHeatRecovery.addToNode(reliefNode)); + + oaNode.setName("Outdoor Air Inlet Node"); + reliefNode.setName("Relief Node"); + oaSystem.reliefAirModelObject()->setName("Return to OA System Node"); + oaSystem.outdoorAirModelObject()->setName("OA System Outlet to Mixed Node"); + airLoop.mixedAirNode()->setName("Mixed Air Node"); + airLoop.supplyInletNode().setName("Supply Inlet Node"); + airLoop.supplyOutletNode().setName("Supply Outlet Node"); // They must be connected to a PlantLoop too PlantLoop chw_p(m); - chw_p.addDemandBranchForComponent(coilSystemCoolingWater.coolingCoil()); + chw_p.addDemandBranchForComponent(cc); + PipeAdiabatic pipe(m); + Node coolingOutlet = cc.waterOutletModelObject()->cast(); + EXPECT_TRUE(pipe.addToNode(coolingOutlet)); + Node pipeOutlet = pipe.outletModelObject()->cast(); + EXPECT_TRUE(companionCoilUsedForHeatRecovery.addToNode(pipeOutlet)); + + cc.waterInletModelObject()->setName("Cooling Coil Water Inlet Node"); + cc.waterOutletModelObject()->setName("Cooling Coil Water Outlet to Pipe Inlet Node"); + pipe.outletModelObject()->setName("Pipe Outlet to Companion Coil Water Inlet Node"); + companionCoilUsedForHeatRecovery.waterOutletModelObject()->setName("Companion Coil Water Outlet Node"); const Workspace w = ft.translateModel(m); - const auto idfUnitarys = w.getObjectsByType(IddObjectType::AirLoopHVAC_UnitarySystem); - ASSERT_EQ(1u, idfUnitarys.size()); - const auto idfCoilSystems = w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water); - ASSERT_EQ(0u, idfCoilSystems.size()); + ASSERT_EQ(1u, idfCoilSystems.size()); + const auto& idfCoilSystem = idfCoilSystems.front(); + + WorkspaceObjectVector idfCoils(w.getObjectsByType(IddObjectType::Coil_Cooling_Water)); + ASSERT_EQ(2u, idfCoils.size()); + + WorkspaceObjectVector idfControllers(w.getObjectsByType(IddObjectType::Controller_OutdoorAir)); + ASSERT_EQ(1u, idfControllers.size()); + const auto& idfController = idfControllers.front(); + + // 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(), coilSystemCoolingWater.inletModelObject().get().nameString()); + EXPECT_EQ(w_eg2.getString(BranchExtensibleFields::ComponentOutletNodeName).get(), coilSystemCoolingWater.outletModelObject().get().nameString()); */ + EXPECT_EQ("AirLoopHVAC:OutdoorAirSystem", w_eg2.getString(BranchExtensibleFields::ComponentObjectType).get()); + + EXPECT_EQ(coilSystemCoolingWater.inletModelObject().get().nameString(), + idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ(coilSystemCoolingWater.outletModelObject().get().nameString(), + idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get()); + EXPECT_EQ(availabilitySchedule.nameString(), idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AvailabilityScheduleName).get()); + EXPECT_EQ("Coil:Cooling:Water", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilObjectType).get()); + EXPECT_EQ(coilSystemCoolingWater.coolingCoil().nameString(), idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilName).get()); + EXPECT_EQ("CoolReheat", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::DehumidificationControlType).get()); + EXPECT_EQ("No", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::RunonSensibleLoad).get()); + EXPECT_EQ("Yes", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::RunonLatentLoad).get()); + EXPECT_EQ(1.0, idfCoilSystem.getDouble(CoilSystem_Cooling_WaterFields::MinimumAirToWaterTemperatureOffset).get()); + EXPECT_EQ("No", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::EconomizerLockout).get()); + EXPECT_EQ(1.2, idfCoilSystem.getDouble(CoilSystem_Cooling_WaterFields::MinimumWaterLoopTemperatureForHeatRecovery).get()); + EXPECT_EQ(companionCoilUsedForHeatRecovery.nameString(), + idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery).get()); + + WorkspaceObject idf_coolingCoil = idfCoilSystem.getTarget(CoilSystem_Cooling_WaterFields::CoolingCoilName).get(); + WorkspaceObject idf_companionCoil = idfCoilSystem.getTarget(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery).get(); + + EXPECT_EQ(coilSystemCoolingWater.coolingCoil().nameString(), idf_coolingCoil.getString(Coil_Cooling_WaterFields::Name).get()); + EXPECT_EQ("Always On Discrete", idf_coolingCoil.getString(Coil_Cooling_WaterFields::AvailabilityScheduleName).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignWaterFlowRate).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignAirFlowRate).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignInletWaterTemperature).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignInletAirTemperature).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignInletAirHumidityRatio).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignOutletAirHumidityRatio).get()); + + EXPECT_EQ(cc.waterInletModelObject().get().nameString(), idf_coolingCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); + EXPECT_EQ("Cooling Coil Water Inlet Node", idf_coolingCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); + EXPECT_EQ(cc.waterOutletModelObject().get().nameString(), idf_coolingCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); + EXPECT_EQ("Cooling Coil Water Outlet to Pipe Inlet Node", idf_coolingCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); + EXPECT_EQ(idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get(), + idf_coolingCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); + + EXPECT_EQ("Outdoor Air Inlet Node", idf_coolingCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ(idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get(), + idf_coolingCoil.getString(Coil_Cooling_WaterFields::AirOutletNodeName).get()); + EXPECT_EQ("OA System Outlet to Mixed Node", idf_coolingCoil.getString(Coil_Cooling_WaterFields::AirOutletNodeName).get()); + + EXPECT_EQ("SimpleAnalysis", idf_coolingCoil.getString(Coil_Cooling_WaterFields::TypeofAnalysis).get()); + EXPECT_EQ("CrossFlow", idf_coolingCoil.getString(Coil_Cooling_WaterFields::HeatExchangerConfiguration).get()); + EXPECT_TRUE(idf_coolingCoil.isEmpty(Coil_Cooling_WaterFields::CondensateCollectionWaterStorageTankName)); + EXPECT_TRUE(idf_coolingCoil.isEmpty(Coil_Cooling_WaterFields::DesignWaterTemperatureDifference)); + + EXPECT_EQ(coilSystemCoolingWater.companionCoilUsedForHeatRecovery().get().nameString(), + idf_companionCoil.getString(Coil_Cooling_WaterFields::Name).get()); + EXPECT_EQ("Always On Discrete", idf_companionCoil.getString(Coil_Cooling_WaterFields::AvailabilityScheduleName).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignWaterFlowRate).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignAirFlowRate).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignInletWaterTemperature).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignInletAirTemperature).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignInletAirHumidityRatio).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignOutletAirHumidityRatio).get()); + + EXPECT_EQ(companionCoilUsedForHeatRecovery.waterInletModelObject().get().nameString(), + idf_companionCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); + EXPECT_EQ("Companion Coil Water Outlet Node", idf_companionCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); + EXPECT_EQ(companionCoilUsedForHeatRecovery.waterOutletModelObject().get().nameString(), + idf_companionCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); + EXPECT_EQ("Pipe Outlet to Companion Coil Water Inlet Node", idf_companionCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); + + EXPECT_EQ(idfController.getString(Controller_OutdoorAirFields::ReliefAirOutletNodeName).get(), + idf_companionCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ("Return to OA System Node", idf_companionCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ("Relief Node", idf_companionCoil.getString(Coil_Cooling_WaterFields::AirOutletNodeName).get()); + + EXPECT_EQ("SimpleAnalysis", idf_companionCoil.getString(Coil_Cooling_WaterFields::TypeofAnalysis).get()); + EXPECT_EQ("CrossFlow", idf_companionCoil.getString(Coil_Cooling_WaterFields::HeatExchangerConfiguration).get()); + EXPECT_TRUE(idf_companionCoil.isEmpty(Coil_Cooling_WaterFields::CondensateCollectionWaterStorageTankName)); + EXPECT_TRUE(idf_companionCoil.isEmpty(Coil_Cooling_WaterFields::DesignWaterTemperatureDifference)); + + EXPECT_EQ(0, w.getObjectsByType(IddObjectType::Controller_WaterCoil).size()); } -TEST_F(EnergyPlusFixture, ForwardTranslator_CoilSystemCoolingWater_AirLoopHVAC) { - // without companion - { - ForwardTranslator ft; - - Model m; - - CoilSystemCoolingWater coilSystemCoolingWater(m); - - coilSystemCoolingWater.setName("My CoilSystemCoolingWater"); - Schedule availabilitySchedule = m.alwaysOnDiscreteSchedule(); - EXPECT_TRUE(coilSystemCoolingWater.setAvailabilitySchedule(availabilitySchedule)); - EXPECT_TRUE(coilSystemCoolingWater.setDehumidificationControlType("CoolReheat")); - EXPECT_TRUE(coilSystemCoolingWater.setRunonSensibleLoad(false)); // Opposite from IDD default - EXPECT_TRUE(coilSystemCoolingWater.setRunonLatentLoad(true)); // Opposite from IDD default - EXPECT_TRUE(coilSystemCoolingWater.setMinimumAirToWaterTemperatureOffset(1.0)); - EXPECT_TRUE(coilSystemCoolingWater.setEconomizerLockout(false)); // Opposite from IDD default - EXPECT_TRUE(coilSystemCoolingWater.setMinimumWaterLoopTemperatureForHeatRecovery(1.2)); - - AirLoopHVAC airLoop(m); - Node supplyOutletNode = airLoop.supplyOutletNode(); - EXPECT_TRUE(coilSystemCoolingWater.addToNode(supplyOutletNode)); - - // They must be connected to a PlantLoop too - PlantLoop chw_p(m); - chw_p.addDemandBranchForComponent(coilSystemCoolingWater.coolingCoil()); - - const Workspace w = ft.translateModel(m); - - const auto idfCoilSystems = w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water); - ASSERT_EQ(1u, idfCoilSystems.size()); - const auto& idfCoilSystem = idfCoilSystems.front(); - - WorkspaceObjectVector idfCoils(w.getObjectsByType(IddObjectType::Coil_Cooling_Water)); - ASSERT_EQ(1u, idfCoils.size()); - WorkspaceObject idfCoil(idfCoils[0]); - - // 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(), coilSystemCoolingWater.inletModelObject().get().nameString()); - EXPECT_EQ(w_eg2.getString(BranchExtensibleFields::ComponentOutletNodeName).get(), coilSystemCoolingWater.outletModelObject().get().nameString()); - EXPECT_EQ("CoilSystem:Cooling:Water", w_eg2.getString(BranchExtensibleFields::ComponentObjectType).get()); - - EXPECT_EQ(coilSystemCoolingWater.inletModelObject().get().nameString(), - idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get()); - EXPECT_EQ(coilSystemCoolingWater.outletModelObject().get().nameString(), - idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get()); - EXPECT_EQ(availabilitySchedule.nameString(), idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AvailabilityScheduleName).get()); - EXPECT_EQ("Coil:Cooling:Water", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilObjectType).get()); - EXPECT_EQ(coilSystemCoolingWater.coolingCoil().nameString(), idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilName).get()); - EXPECT_EQ("CoolReheat", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::DehumidificationControlType).get()); - EXPECT_EQ("No", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::RunonSensibleLoad).get()); - EXPECT_EQ("Yes", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::RunonLatentLoad).get()); - EXPECT_EQ(1.0, idfCoilSystem.getDouble(CoilSystem_Cooling_WaterFields::MinimumAirToWaterTemperatureOffset).get()); - EXPECT_EQ("No", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::EconomizerLockout).get()); - EXPECT_EQ(1.2, idfCoilSystem.getDouble(CoilSystem_Cooling_WaterFields::MinimumWaterLoopTemperatureForHeatRecovery).get()); - EXPECT_TRUE(idfCoilSystem.isEmpty(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery)); - - EXPECT_EQ(coilSystemCoolingWater.coolingCoil().nameString(), 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(coilSystemCoolingWater.coolingCoil().waterInletModelObject().get().nameString(), - idfCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); - EXPECT_EQ(coilSystemCoolingWater.coolingCoil().waterOutletModelObject().get().nameString(), - idfCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); - EXPECT_EQ(idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get(), - idfCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); - EXPECT_EQ(idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get(), - 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)); - - EXPECT_EQ(0, w.getObjectsByType(IddObjectType::Controller_WaterCoil).size()); - } - - // with companion - { - ForwardTranslator ft; - - Model m; - - CoilSystemCoolingWater coilSystemCoolingWater(m); - - coilSystemCoolingWater.setName("My CoilSystemCoolingWater"); - Schedule availabilitySchedule = m.alwaysOnDiscreteSchedule(); - EXPECT_TRUE(coilSystemCoolingWater.setAvailabilitySchedule(availabilitySchedule)); - EXPECT_TRUE(coilSystemCoolingWater.setDehumidificationControlType("CoolReheat")); - EXPECT_TRUE(coilSystemCoolingWater.setRunonSensibleLoad(false)); // Opposite from IDD default - EXPECT_TRUE(coilSystemCoolingWater.setRunonLatentLoad(true)); // Opposite from IDD default - EXPECT_TRUE(coilSystemCoolingWater.setMinimumAirToWaterTemperatureOffset(1.0)); - EXPECT_TRUE(coilSystemCoolingWater.setEconomizerLockout(false)); // Opposite from IDD default - EXPECT_TRUE(coilSystemCoolingWater.setMinimumWaterLoopTemperatureForHeatRecovery(1.2)); - CoilCoolingWater companionCoilUsedForHeatRecovery(m); - EXPECT_TRUE(coilSystemCoolingWater.setCompanionCoilUsedForHeatRecovery(companionCoilUsedForHeatRecovery)); - - AirLoopHVAC airLoop(m); - Node supplyOutletNode = airLoop.supplyOutletNode(); - ControllerOutdoorAir controller1(m); - AirLoopHVACOutdoorAirSystem oaSystem(m, controller1); - EXPECT_TRUE(oaSystem.addToNode(supplyOutletNode)); - Node oaNode = oaSystem.outboardOANode().get(); - EXPECT_TRUE(coilSystemCoolingWater.addToNode(oaNode)); - Node reliefNode = oaSystem.reliefAirModelObject()->cast(); - EXPECT_TRUE(companionCoilUsedForHeatRecovery.addToNode(reliefNode)); - - // They must be connected to a PlantLoop too - PlantLoop chw_p(m); - chw_p.addDemandBranchForComponent(coilSystemCoolingWater.coolingCoil()); - PipeAdiabatic pipe(m); - Node coolingOutlet = coilSystemCoolingWater.coolingCoil().waterOutletModelObject()->cast(); - EXPECT_TRUE(pipe.addToNode(coolingOutlet)); - Node pipeOutlet = pipe.outletModelObject()->cast(); - EXPECT_TRUE(companionCoilUsedForHeatRecovery.addToNode(pipeOutlet)); - - const Workspace w = ft.translateModel(m); - - const auto idfCoilSystems = w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water); - ASSERT_EQ(1u, idfCoilSystems.size()); - const auto& idfCoilSystem = idfCoilSystems.front(); - - WorkspaceObjectVector idfCoils(w.getObjectsByType(IddObjectType::Coil_Cooling_Water)); - ASSERT_EQ(2u, idfCoils.size()); - - WorkspaceObjectVector idfControllers(w.getObjectsByType(IddObjectType::Controller_OutdoorAir)); - ASSERT_EQ(1u, idfControllers.size()); - const auto& idfController = idfControllers.front(); - - // 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(), coilSystemCoolingWater.inletModelObject().get().nameString()); +TEST_F(EnergyPlusFixture, ForwardTranslator_CoilSystemCoolingWater_HXAssisted) { + ForwardTranslator ft; + + Model m; + + CoilSystemCoolingWaterHeatExchangerAssisted coilSystemHXAssisted(m); + coilSystemHXAssisted.setName("HX Assisted"); + auto cc = coilSystemHXAssisted.coolingCoil().cast(); + auto hx = coilSystemHXAssisted.heatExchanger().cast(); + cc.setName("Primary Cooling Coil inside HXAssisted"); + hx.setName("HX AirToAir"); + CoilSystemCoolingWater coilSystemCoolingWater(m, coilSystemHXAssisted); + coilSystemCoolingWater.setName("My CoilSystemCoolingWater"); + + ScheduleConstant availabilitySchedule(m); + availabilitySchedule.setName("availabilitySchedule"); + EXPECT_TRUE(coilSystemCoolingWater.setAvailabilitySchedule(availabilitySchedule)); + EXPECT_TRUE(coilSystemCoolingWater.setDehumidificationControlType("CoolReheat")); + EXPECT_TRUE(coilSystemCoolingWater.setRunonSensibleLoad(false)); // Opposite from IDD default + EXPECT_TRUE(coilSystemCoolingWater.setRunonLatentLoad(true)); // Opposite from IDD default + EXPECT_TRUE(coilSystemCoolingWater.setMinimumAirToWaterTemperatureOffset(1.0)); + EXPECT_TRUE(coilSystemCoolingWater.setEconomizerLockout(false)); // Opposite from IDD default + EXPECT_TRUE(coilSystemCoolingWater.setMinimumWaterLoopTemperatureForHeatRecovery(1.2)); + CoilCoolingWater companionCoilUsedForHeatRecovery(m); + companionCoilUsedForHeatRecovery.setName("CompanionCoilUsedForHeatRecovery"); + EXPECT_TRUE(coilSystemCoolingWater.setCompanionCoilUsedForHeatRecovery(companionCoilUsedForHeatRecovery)); + + AirLoopHVAC airLoop(m); + Node supplyOutletNode = airLoop.supplyOutletNode(); + ControllerOutdoorAir controller1(m); + AirLoopHVACOutdoorAirSystem oaSystem(m, controller1); + EXPECT_TRUE(oaSystem.addToNode(supplyOutletNode)); + Node oaNode = oaSystem.outboardOANode().get(); + EXPECT_TRUE(coilSystemCoolingWater.addToNode(oaNode)); + Node reliefNode = oaSystem.outboardReliefNode().get(); + EXPECT_TRUE(companionCoilUsedForHeatRecovery.addToNode(reliefNode)); + + oaNode.setName("Outdoor Air Inlet Node"); + reliefNode.setName("Relief Node"); + oaSystem.reliefAirModelObject()->setName("Return to OA System Node"); + oaSystem.outdoorAirModelObject()->setName("OA System Outlet to Mixed Node"); + airLoop.mixedAirNode()->setName("Mixed Air Node"); + airLoop.supplyInletNode().setName("Supply Inlet Node"); + airLoop.supplyOutletNode().setName("Supply Outlet Node"); + + // They must be connected to a PlantLoop too + PlantLoop chw_p(m); + chw_p.addDemandBranchForComponent(cc); + PipeAdiabatic pipe(m); + Node coolingOutlet = cc.waterOutletModelObject()->cast(); + EXPECT_TRUE(pipe.addToNode(coolingOutlet)); + Node pipeOutlet = pipe.outletModelObject()->cast(); + EXPECT_TRUE(companionCoilUsedForHeatRecovery.addToNode(pipeOutlet)); + + cc.waterInletModelObject()->setName("Cooling Coil Water Inlet Node"); + cc.waterOutletModelObject()->setName("Cooling Coil Water Outlet to Pipe Inlet Node"); + pipe.outletModelObject()->setName("Pipe Outlet to Companion Coil Water Inlet Node"); + companionCoilUsedForHeatRecovery.waterOutletModelObject()->setName("Companion Coil Water Outlet Node"); + + const Workspace w = ft.translateModel(m); + + const auto idfCoilSystems = w.getObjectsByType(IddObjectType::CoilSystem_Cooling_Water); + ASSERT_EQ(1u, idfCoilSystems.size()); + const auto& idfCoilSystem = idfCoilSystems.front(); + + WorkspaceObjectVector idfCoils(w.getObjectsByType(IddObjectType::Coil_Cooling_Water)); + ASSERT_EQ(2u, idfCoils.size()); + + WorkspaceObjectVector idfControllers(w.getObjectsByType(IddObjectType::Controller_OutdoorAir)); + ASSERT_EQ(1u, idfControllers.size()); + const auto& idfController = idfControllers.front(); + + // 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(), coilSystemCoolingWater.inletModelObject().get().nameString()); EXPECT_EQ(w_eg2.getString(BranchExtensibleFields::ComponentOutletNodeName).get(), coilSystemCoolingWater.outletModelObject().get().nameString()); */ - EXPECT_EQ("AirLoopHVAC:OutdoorAirSystem", w_eg2.getString(BranchExtensibleFields::ComponentObjectType).get()); - - EXPECT_EQ(coilSystemCoolingWater.inletModelObject().get().nameString(), - idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get()); - EXPECT_EQ(coilSystemCoolingWater.outletModelObject().get().nameString(), - idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get()); - EXPECT_EQ(availabilitySchedule.nameString(), idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AvailabilityScheduleName).get()); - EXPECT_EQ("Coil:Cooling:Water", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilObjectType).get()); - EXPECT_EQ(coilSystemCoolingWater.coolingCoil().nameString(), idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilName).get()); - EXPECT_EQ("CoolReheat", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::DehumidificationControlType).get()); - EXPECT_EQ("No", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::RunonSensibleLoad).get()); - EXPECT_EQ("Yes", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::RunonLatentLoad).get()); - EXPECT_EQ(1.0, idfCoilSystem.getDouble(CoilSystem_Cooling_WaterFields::MinimumAirToWaterTemperatureOffset).get()); - EXPECT_EQ("No", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::EconomizerLockout).get()); - EXPECT_EQ(1.2, idfCoilSystem.getDouble(CoilSystem_Cooling_WaterFields::MinimumWaterLoopTemperatureForHeatRecovery).get()); - EXPECT_EQ(companionCoilUsedForHeatRecovery.nameString(), - idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery).get()); - - WorkspaceObject idf_coolingCoil = idfCoilSystem.getTarget(CoilSystem_Cooling_WaterFields::CoolingCoilName).get(); - WorkspaceObject idf_companionCoil = idfCoilSystem.getTarget(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery).get(); - - EXPECT_EQ(coilSystemCoolingWater.coolingCoil().nameString(), idf_coolingCoil.getString(Coil_Cooling_WaterFields::Name).get()); - EXPECT_EQ("Always On Discrete", idf_coolingCoil.getString(Coil_Cooling_WaterFields::AvailabilityScheduleName).get()); - EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignWaterFlowRate).get()); - EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignAirFlowRate).get()); - EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignInletWaterTemperature).get()); - EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignInletAirTemperature).get()); - EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignInletAirHumidityRatio).get()); - EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignOutletAirHumidityRatio).get()); - EXPECT_EQ(coilSystemCoolingWater.coolingCoil().waterInletModelObject().get().nameString(), - idf_coolingCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); - EXPECT_EQ(coilSystemCoolingWater.coolingCoil().waterOutletModelObject().get().nameString(), - idf_coolingCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); - EXPECT_EQ(idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get(), - idf_coolingCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); - EXPECT_EQ(idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get(), - idf_coolingCoil.getString(Coil_Cooling_WaterFields::AirOutletNodeName).get()); - EXPECT_EQ("SimpleAnalysis", idf_coolingCoil.getString(Coil_Cooling_WaterFields::TypeofAnalysis).get()); - EXPECT_EQ("CrossFlow", idf_coolingCoil.getString(Coil_Cooling_WaterFields::HeatExchangerConfiguration).get()); - EXPECT_TRUE(idf_coolingCoil.isEmpty(Coil_Cooling_WaterFields::CondensateCollectionWaterStorageTankName)); - EXPECT_TRUE(idf_coolingCoil.isEmpty(Coil_Cooling_WaterFields::DesignWaterTemperatureDifference)); - - EXPECT_EQ(coilSystemCoolingWater.companionCoilUsedForHeatRecovery().get().nameString(), - idf_companionCoil.getString(Coil_Cooling_WaterFields::Name).get()); - EXPECT_EQ("Always On Discrete", idf_companionCoil.getString(Coil_Cooling_WaterFields::AvailabilityScheduleName).get()); - EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignWaterFlowRate).get()); - EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignAirFlowRate).get()); - EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignInletWaterTemperature).get()); - EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignInletAirTemperature).get()); - EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignInletAirHumidityRatio).get()); - EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignOutletAirHumidityRatio).get()); - EXPECT_EQ(coilSystemCoolingWater.companionCoilUsedForHeatRecovery().get().waterInletModelObject().get().nameString(), - idf_companionCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); - EXPECT_EQ(coilSystemCoolingWater.companionCoilUsedForHeatRecovery().get().waterOutletModelObject().get().nameString(), - idf_companionCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); - EXPECT_EQ(idfController.getString(Controller_OutdoorAirFields::ReliefAirOutletNodeName).get(), - idf_companionCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); - EXPECT_EQ(coilSystemCoolingWater.companionCoilUsedForHeatRecovery().get().nameString() + " Exhaust Outlet Node", - idf_companionCoil.getString(Coil_Cooling_WaterFields::AirOutletNodeName).get()); // FIXME - EXPECT_EQ("SimpleAnalysis", idf_companionCoil.getString(Coil_Cooling_WaterFields::TypeofAnalysis).get()); - EXPECT_EQ("CrossFlow", idf_companionCoil.getString(Coil_Cooling_WaterFields::HeatExchangerConfiguration).get()); - EXPECT_TRUE(idf_companionCoil.isEmpty(Coil_Cooling_WaterFields::CondensateCollectionWaterStorageTankName)); - EXPECT_TRUE(idf_companionCoil.isEmpty(Coil_Cooling_WaterFields::DesignWaterTemperatureDifference)); - - EXPECT_EQ(0, w.getObjectsByType(IddObjectType::Controller_WaterCoil).size()); - } + EXPECT_EQ("AirLoopHVAC:OutdoorAirSystem", w_eg2.getString(BranchExtensibleFields::ComponentObjectType).get()); + + EXPECT_EQ(coilSystemCoolingWater.inletModelObject().get().nameString(), + idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ(coilSystemCoolingWater.outletModelObject().get().nameString(), + idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get()); + EXPECT_EQ(availabilitySchedule.nameString(), idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AvailabilityScheduleName).get()); + EXPECT_EQ("CoilSystem:Cooling:Water:HeatExchangerAssisted", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilObjectType).get()); + EXPECT_EQ(coilSystemCoolingWater.coolingCoil().nameString(), idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CoolingCoilName).get()); + EXPECT_EQ("CoolReheat", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::DehumidificationControlType).get()); + EXPECT_EQ("No", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::RunonSensibleLoad).get()); + EXPECT_EQ("Yes", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::RunonLatentLoad).get()); + EXPECT_EQ(1.0, idfCoilSystem.getDouble(CoilSystem_Cooling_WaterFields::MinimumAirToWaterTemperatureOffset).get()); + EXPECT_EQ("No", idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::EconomizerLockout).get()); + EXPECT_EQ(1.2, idfCoilSystem.getDouble(CoilSystem_Cooling_WaterFields::MinimumWaterLoopTemperatureForHeatRecovery).get()); + EXPECT_EQ(companionCoilUsedForHeatRecovery.nameString(), + idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery).get()); + + WorkspaceObject idf_hxAssisted = idfCoilSystem.getTarget(CoilSystem_Cooling_WaterFields::CoolingCoilName).get(); + EXPECT_EQ("HeatExchanger:AirToAir:SensibleAndLatent", + idf_hxAssisted.getString(CoilSystem_Cooling_Water_HeatExchangerAssistedFields::HeatExchangerObjectType).get()); + EXPECT_EQ("HX AirToAir", idf_hxAssisted.getString(CoilSystem_Cooling_Water_HeatExchangerAssistedFields::HeatExchangerName).get()); + EXPECT_EQ("Coil:Cooling:Water", idf_hxAssisted.getString(CoilSystem_Cooling_Water_HeatExchangerAssistedFields::CoolingCoilObjectType).get()); + EXPECT_EQ("Primary Cooling Coil inside HXAssisted", + idf_hxAssisted.getString(CoilSystem_Cooling_Water_HeatExchangerAssistedFields::CoolingCoilName).get()); + + // This fails for some reason? + // auto idf_hx = idf_hxAssisted.getTarget(CoilSystem_Cooling_Water_HeatExchangerAssistedFields::HeatExchangerName).get(); + ASSERT_EQ(1, w.getObjectsByType(IddObjectType::HeatExchanger_AirToAir_SensibleAndLatent).size()); + auto idf_hx = w.getObjectsByType(IddObjectType::HeatExchanger_AirToAir_SensibleAndLatent).front(); + + EXPECT_EQ(hx.nameString(), idf_hx.getString(HeatExchanger_AirToAir_SensibleAndLatentFields::Name).get()); + EXPECT_EQ(idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirInletNodeName).get(), + idf_hx.getString(HeatExchanger_AirToAir_SensibleAndLatentFields::SupplyAirInletNodeName).get()); + EXPECT_EQ("Outdoor Air Inlet Node", idf_hx.getString(HeatExchanger_AirToAir_SensibleAndLatentFields::SupplyAirInletNodeName).get()); + + EXPECT_EQ(idfCoilSystem.getString(CoilSystem_Cooling_WaterFields::AirOutletNodeName).get(), + idf_hx.getString(HeatExchanger_AirToAir_SensibleAndLatentFields::ExhaustAirOutletNodeName).get()); + EXPECT_EQ("OA System Outlet to Mixed Node", idf_hx.getString(HeatExchanger_AirToAir_SensibleAndLatentFields::ExhaustAirOutletNodeName).get()); + + EXPECT_EQ("HX Assisted HX Supply Air Outlet - Cooling Inlet Node", + idf_hx.getString(HeatExchanger_AirToAir_SensibleAndLatentFields::SupplyAirOutletNodeName).get()); + EXPECT_EQ("HX Assisted HX Exhaust Air Inlet - Cooling Outlet Node", + idf_hx.getString(HeatExchanger_AirToAir_SensibleAndLatentFields::ExhaustAirInletNodeName).get()); + + WorkspaceObject idf_coolingCoil = idf_hxAssisted.getTarget(CoilSystem_Cooling_Water_HeatExchangerAssistedFields::CoolingCoilName).get(); + WorkspaceObject idf_companionCoil = idfCoilSystem.getTarget(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery).get(); + + EXPECT_EQ("Primary Cooling Coil inside HXAssisted", idf_coolingCoil.getString(Coil_Cooling_WaterFields::Name).get()); + EXPECT_EQ("Always On Discrete", idf_coolingCoil.getString(Coil_Cooling_WaterFields::AvailabilityScheduleName).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignWaterFlowRate).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignAirFlowRate).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignInletWaterTemperature).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignInletAirTemperature).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignInletAirHumidityRatio).get()); + EXPECT_EQ("Autosize", idf_coolingCoil.getString(Coil_Cooling_WaterFields::DesignOutletAirHumidityRatio).get()); + + EXPECT_EQ(cc.waterInletModelObject().get().nameString(), idf_coolingCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); + EXPECT_EQ("Cooling Coil Water Inlet Node", idf_coolingCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); + EXPECT_EQ(cc.waterOutletModelObject().get().nameString(), idf_coolingCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); + EXPECT_EQ("Cooling Coil Water Outlet to Pipe Inlet Node", idf_coolingCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); + EXPECT_EQ(idf_hx.getString(HeatExchanger_AirToAir_SensibleAndLatentFields::SupplyAirOutletNodeName).get(), + idf_coolingCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ("HX Assisted HX Supply Air Outlet - Cooling Inlet Node", idf_coolingCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ(idf_hx.getString(HeatExchanger_AirToAir_SensibleAndLatentFields::ExhaustAirInletNodeName).get(), + idf_coolingCoil.getString(Coil_Cooling_WaterFields::AirOutletNodeName).get()); + EXPECT_EQ("HX Assisted HX Exhaust Air Inlet - Cooling Outlet Node", idf_coolingCoil.getString(Coil_Cooling_WaterFields::AirOutletNodeName).get()); + + EXPECT_EQ("SimpleAnalysis", idf_coolingCoil.getString(Coil_Cooling_WaterFields::TypeofAnalysis).get()); + EXPECT_EQ("CrossFlow", idf_coolingCoil.getString(Coil_Cooling_WaterFields::HeatExchangerConfiguration).get()); + EXPECT_TRUE(idf_coolingCoil.isEmpty(Coil_Cooling_WaterFields::CondensateCollectionWaterStorageTankName)); + EXPECT_TRUE(idf_coolingCoil.isEmpty(Coil_Cooling_WaterFields::DesignWaterTemperatureDifference)); + + EXPECT_EQ(coilSystemCoolingWater.companionCoilUsedForHeatRecovery().get().nameString(), + idf_companionCoil.getString(Coil_Cooling_WaterFields::Name).get()); + EXPECT_EQ("Always On Discrete", idf_companionCoil.getString(Coil_Cooling_WaterFields::AvailabilityScheduleName).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignWaterFlowRate).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignAirFlowRate).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignInletWaterTemperature).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignInletAirTemperature).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignInletAirHumidityRatio).get()); + EXPECT_EQ("Autosize", idf_companionCoil.getString(Coil_Cooling_WaterFields::DesignOutletAirHumidityRatio).get()); + + EXPECT_EQ(companionCoilUsedForHeatRecovery.waterInletModelObject().get().nameString(), + idf_companionCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); + EXPECT_EQ("Companion Coil Water Outlet Node", idf_companionCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); + EXPECT_EQ(companionCoilUsedForHeatRecovery.waterOutletModelObject().get().nameString(), + idf_companionCoil.getString(Coil_Cooling_WaterFields::WaterOutletNodeName).get()); + EXPECT_EQ("Pipe Outlet to Companion Coil Water Inlet Node", idf_companionCoil.getString(Coil_Cooling_WaterFields::WaterInletNodeName).get()); + + EXPECT_EQ(idfController.getString(Controller_OutdoorAirFields::ReliefAirOutletNodeName).get(), + idf_companionCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ("Return to OA System Node", idf_companionCoil.getString(Coil_Cooling_WaterFields::AirInletNodeName).get()); + EXPECT_EQ("Relief Node", idf_companionCoil.getString(Coil_Cooling_WaterFields::AirOutletNodeName).get()); + + EXPECT_EQ("SimpleAnalysis", idf_companionCoil.getString(Coil_Cooling_WaterFields::TypeofAnalysis).get()); + EXPECT_EQ("CrossFlow", idf_companionCoil.getString(Coil_Cooling_WaterFields::HeatExchangerConfiguration).get()); + EXPECT_TRUE(idf_companionCoil.isEmpty(Coil_Cooling_WaterFields::CondensateCollectionWaterStorageTankName)); + EXPECT_TRUE(idf_companionCoil.isEmpty(Coil_Cooling_WaterFields::DesignWaterTemperatureDifference)); + + EXPECT_EQ(0, w.getObjectsByType(IddObjectType::Controller_WaterCoil).size()); } diff --git a/src/model/CoilCoolingWater.cpp b/src/model/CoilCoolingWater.cpp index afe42feb17..4be5cc9b66 100644 --- a/src/model/CoilCoolingWater.cpp +++ b/src/model/CoilCoolingWater.cpp @@ -273,48 +273,68 @@ namespace model { } bool CoilCoolingWater_Impl::addToNode(Node& node) { - bool success(false); + bool success = false; auto t_containingHVACComponent = containingHVACComponent(); auto t_airLoop = node.airLoopHVAC(); - if (t_airLoop && t_containingHVACComponent && t_containingHVACComponent->optionalCast()) { - LOG(Warn, this->briefDescription() - << " cannot be connected directly to an AirLoopHVAC when it's part of a parent CoilSystemCoolingWaterHeatExchangerAssisted. " - "Please call CoilSystemCoolingWaterHeatExchangerAssisted::addToNode instead"); - - /* } else if (t_airLoop && t_containingHVACComponent && t_containingHVACComponent->optionalCast()) { - LOG(Warn, this->briefDescription() - << " cannot be connected directly to an AirLoopHVAC when it's part of a parent CoilSystemCoolingWater. " - "Please call CoilSystemCoolingWater::addToNode instead"); */ + // Reject adding coils parent of a Parent System + if (t_airLoop && t_containingHVACComponent) { + if (t_containingHVACComponent->optionalCast()) { + LOG(Warn, this->briefDescription() + << " cannot be connected directly to an AirLoopHVAC when it's part of a parent CoilSystemCoolingWaterHeatExchangerAssisted. " + "Please call CoilSystemCoolingWaterHeatExchangerAssisted::addToNode instead"); + return false; + } - } else { + if (t_containingHVACComponent->optionalCast() + && t_containingHVACComponent->cast().coolingCoil().handle() == this->handle()) { + LOG(Warn, this->briefDescription() + << " cannot be connected directly to an AirLoopHVAC when it's the primary cooling coil of a parent CoilSystemCoolingWater. " + "Please call CoilSystemCoolingWater::addToNode instead"); + return false; + } + } - success = WaterToAirComponent_Impl::addToNode(node); - auto t_containingZoneHVACComponent = containingZoneHVACComponent(); + success = WaterToAirComponent_Impl::addToNode(node); + if (!success) { + return false; + } + // We only add the controller if we are not part of a containing ZoneHVACComponent, and we have a PlantLoop assigned + if (containingZoneHVACComponent() || !waterInletModelObject()) { + // We're done + return true; + } - if (success && (!t_containingZoneHVACComponent)) { - if (auto t_waterInletModelObject = waterInletModelObject()) { - if (auto oldController = controllerWaterCoil()) { - if (!openstudio::istringEqual(oldController->action().get(), "Reverse")) { - LOG(Warn, - briefDescription() - << " has an existing ControllerWaterCoil with action set to something else than 'Reverse'. Make sure this is what you want"); - } - } else { - if (t_containingHVACComponent && t_containingHVACComponent->optionalCast()) { - // no-op - } else { - Model t_model = model(); - ControllerWaterCoil controller(t_model); - controller.getImpl()->setWaterCoil(getObject()); - controller.setAction("Reverse"); - } + // We don't need a controller if we are part of a CoilSystemCoolingWater (directly, or indirectly via a + // CoilSystemCoolingWaterHeatExchangerAssisted) + bool needAController = true; + if (t_containingHVACComponent) { + if (t_containingHVACComponent->optionalCast()) { + needAController = false; + } else if (auto hxAssisted_ = t_containingHVACComponent->optionalCast()) { + if (auto parent_ = hxAssisted_->containingHVACComponent()) { + if (parent_->optionalCast()) { + needAController = false; } } } } + if (auto oldController_ = controllerWaterCoil()) { + if (!needAController) { + oldController_->remove(); + } else if (!openstudio::istringEqual(oldController_->action().get(), "Reverse")) { + LOG(Warn, briefDescription() + << " has an existing ControllerWaterCoil with action set to something else than 'Reverse'. Make sure this is what you want"); + } + } else if (needAController) { + Model t_model = model(); + ControllerWaterCoil controller(t_model); + controller.getImpl()->setWaterCoil(getObject()); + controller.setAction("Reverse"); + } + return success; } @@ -389,7 +409,7 @@ namespace model { if (coilSystem.coolingCoil().handle() == handle()) { return coilSystem; } - if (boost::optional companionCoilUsedForHeatRecovery = coilSystem.companionCoilUsedForHeatRecovery()) { + if (boost::optional companionCoilUsedForHeatRecovery = coilSystem.companionCoilUsedForHeatRecovery()) { if (companionCoilUsedForHeatRecovery->handle() == this->handle()) { return coilSystem; } diff --git a/src/model/CoilSystemCoolingWater.cpp b/src/model/CoilSystemCoolingWater.cpp index 2b200413ff..6b85a453e6 100644 --- a/src/model/CoilSystemCoolingWater.cpp +++ b/src/model/CoilSystemCoolingWater.cpp @@ -8,10 +8,12 @@ #include "Schedule.hpp" #include "Schedule_Impl.hpp" -#include "WaterToAirComponent.hpp" -#include "WaterToAirComponent_Impl.hpp" +#include "HVACComponent.hpp" +#include "HVACComponent_Impl.hpp" #include "CoilCoolingWater.hpp" #include "CoilCoolingWater_Impl.hpp" +#include "CoilSystemCoolingWaterHeatExchangerAssisted.hpp" +#include "CoilSystemCoolingWaterHeatExchangerAssisted_Impl.hpp" #include "Model.hpp" #include "Model_Impl.hpp" #include "Node.hpp" @@ -87,24 +89,47 @@ namespace model { std::vector CoilSystemCoolingWater_Impl::children() const { std::vector result; - if (OptionalWaterToAirComponent intermediate = optionalCoolingCoil()) { + if (OptionalHVACComponent intermediate = optionalCoolingCoil()) { result.push_back(*intermediate); } - if (OptionalWaterToAirComponent intermediate = optionalCompanionCoilUsedForHeatRecovery()) { + if (OptionalHVACComponent intermediate = companionCoilUsedForHeatRecovery()) { result.push_back(*intermediate); } return result; } + std::vector CoilSystemCoolingWater_Impl::remove() { + std::vector result; + + if (auto c_ = optionalCoolingCoil()) { // This is false when the explicit ctor throws + if (boost::optional cc_ = c_->optionalCast()) { + cc_->removeFromPlantLoop(); + } else if (auto cc_ = c_->optionalCast()) { + cc_->coolingCoil().removeFromPlantLoop(); + } else { + OS_ASSERT(false); + } + } + if (auto companionCoil_ = companionCoilUsedForHeatRecovery()) { + if (auto cc_ = companionCoil_->optionalCast()) { + cc_->removeFromPlantLoop(); + } else { + OS_ASSERT(false); + } + } + + return StraightComponent_Impl::remove(); + } + ModelObject CoilSystemCoolingWater_Impl::clone(Model model) const { auto coilSystemClone = StraightComponent_Impl::clone(model).cast(); - if (OptionalWaterToAirComponent intermediate = optionalCoolingCoil()) { - coilSystemClone.setCoolingCoil(intermediate->clone(model).cast()); + if (OptionalHVACComponent intermediate = optionalCoolingCoil()) { + coilSystemClone.setCoolingCoil(intermediate->clone(model).cast()); } - if (OptionalWaterToAirComponent intermediate = optionalCompanionCoilUsedForHeatRecovery()) { - coilSystemClone.setCompanionCoilUsedForHeatRecovery(intermediate->clone(model).cast()); + if (OptionalHVACComponent intermediate = companionCoilUsedForHeatRecovery()) { + coilSystemClone.setCompanionCoilUsedForHeatRecovery(intermediate->clone(model).cast()); } return std::move(coilSystemClone); @@ -127,50 +152,10 @@ namespace model { } boost::optional CoilSystemCoolingWater_Impl::containingHVACComponent() const { - // AirLoopHVACUnitarySystem - std::vector airLoopHVACUnitarySystems = this->model().getConcreteModelObjects(); - - for (const auto& airLoopHVACUnitarySystem : airLoopHVACUnitarySystems) { - if (boost::optional coolingCoil = airLoopHVACUnitarySystem.coolingCoil()) { - if (coolingCoil->handle() == this->handle()) { - return airLoopHVACUnitarySystem; - } - } - } - return boost::none; } boost::optional CoilSystemCoolingWater_Impl::containingZoneHVACComponent() const { - - // ZoneHVACFourPipeFanCoil - std::vector zoneHVACFourPipeFanCoils; - - zoneHVACFourPipeFanCoils = this->model().getConcreteModelObjects(); - - for (const auto& zoneHVACFourPipeFanCoil : zoneHVACFourPipeFanCoils) { - if (boost::optional coil = zoneHVACFourPipeFanCoil.coolingCoil()) { - if (coil->handle() == this->handle()) { - return zoneHVACFourPipeFanCoil; - } - } - } - - // ZoneHVACUnitVentilator - std::vector zoneHVACUnitVentilators; - - zoneHVACUnitVentilators = this->model().getConcreteModelObjects(); - - for (const auto& zoneHVACUnitVentilator : zoneHVACUnitVentilators) { - if (boost::optional coil = zoneHVACUnitVentilator.coolingCoil()) { - if (coil->handle() == this->handle()) { - return zoneHVACUnitVentilator; - } - } - } - - // ZoneHVAC:WindowAirConditioner not wrapped - return boost::none; } @@ -198,8 +183,8 @@ namespace model { return value.get(); } - WaterToAirComponent CoilSystemCoolingWater_Impl::coolingCoil() const { - boost::optional value = optionalCoolingCoil(); + HVACComponent CoilSystemCoolingWater_Impl::coolingCoil() const { + boost::optional value = optionalCoolingCoil(); if (!value) { LOG_AND_THROW(briefDescription() << " does not have an Cooling Coil attached."); } @@ -236,8 +221,8 @@ namespace model { return value.get(); } - boost::optional CoilSystemCoolingWater_Impl::companionCoilUsedForHeatRecovery() const { - return optionalCompanionCoilUsedForHeatRecovery(); + boost::optional CoilSystemCoolingWater_Impl::companionCoilUsedForHeatRecovery() const { + return getObject().getModelObjectTarget(OS_CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery); } bool CoilSystemCoolingWater_Impl::setAvailabilitySchedule(Schedule& schedule) { @@ -246,7 +231,7 @@ namespace model { return result; } - bool CoilSystemCoolingWater_Impl::setCoolingCoil(const WaterToAirComponent& coolingCoil) { + bool CoilSystemCoolingWater_Impl::setCoolingCoil(const HVACComponent& coolingCoil) { const bool result = setPointer(OS_CoilSystem_Cooling_WaterFields::CoolingCoil, coolingCoil.handle()); return result; } @@ -286,9 +271,16 @@ namespace model { return result; } - bool CoilSystemCoolingWater_Impl::setCompanionCoilUsedForHeatRecovery(const WaterToAirComponent& companionCoilUsedForHeatRecovery) { - const bool result = setPointer(OS_CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery, companionCoilUsedForHeatRecovery.handle()); - return result; + bool CoilSystemCoolingWater_Impl::setCompanionCoilUsedForHeatRecovery(const HVACComponent& companionCoilUsedForHeatRecovery) { + if (companionCoilUsedForHeatRecovery.iddObjectType() == IddObjectType::OS_Coil_Cooling_Water) { + const bool result = + setPointer(OS_CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery, companionCoilUsedForHeatRecovery.handle()); + return result; + } else { + LOG(Warn, "Invalid Companion Coil Used For Heat Recovery Type (expected CoilCoolingWater, not '" + << companionCoilUsedForHeatRecovery.iddObjectType().valueName() << "') for " << briefDescription()); + return false; + } } void CoilSystemCoolingWater_Impl::resetCompanionCoilUsedForHeatRecovery() { @@ -300,27 +292,18 @@ namespace model { return getObject().getModelObjectTarget(OS_CoilSystem_Cooling_WaterFields::AvailabilityScheduleName); } - boost::optional CoilSystemCoolingWater_Impl::optionalCoolingCoil() const { - return getObject().getModelObjectTarget(OS_CoilSystem_Cooling_WaterFields::CoolingCoil); - } - - boost::optional CoilSystemCoolingWater_Impl::optionalCompanionCoilUsedForHeatRecovery() const { - return getObject().getModelObjectTarget(OS_CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery); + boost::optional CoilSystemCoolingWater_Impl::optionalCoolingCoil() const { + return getObject().getModelObjectTarget(OS_CoilSystem_Cooling_WaterFields::CoolingCoil); } } // namespace detail - CoilSystemCoolingWater::CoilSystemCoolingWater(const Model& model) : StraightComponent(CoilSystemCoolingWater::iddObjectType(), model) { - OS_ASSERT(getImpl()); - + void CoilSystemCoolingWater::assignEnergyPlusIDDDefaults() { bool ok = true; - auto alwaysOn = model.alwaysOnDiscreteSchedule(); + auto alwaysOn = model().alwaysOnDiscreteSchedule(); ok = setAvailabilitySchedule(alwaysOn); OS_ASSERT(ok); - CoilCoolingWater coolingCoil(model); - ok = setCoolingCoil(coolingCoil); - OS_ASSERT(ok); ok = setDehumidificationControlType("None"); OS_ASSERT(ok); ok = setRunonSensibleLoad(true); @@ -335,29 +318,29 @@ namespace model { OS_ASSERT(ok); } - CoilSystemCoolingWater::CoilSystemCoolingWater(const Model& model, const WaterToAirComponent& coolingCoil) - : StraightComponent(CoilSystemCoolingWater::iddObjectType(), model) { + CoilSystemCoolingWater::CoilSystemCoolingWater(const Model& model) : StraightComponent(CoilSystemCoolingWater::iddObjectType(), model) { OS_ASSERT(getImpl()); - bool ok = true; - auto alwaysOn = model.alwaysOnDiscreteSchedule(); - ok = setAvailabilitySchedule(alwaysOn); + CoilCoolingWater coolingCoil(model); + coolingCoil.setName(name().get() + " Cooling Coil"); + bool ok = setCoolingCoil(coolingCoil); OS_ASSERT(ok); + assignEnergyPlusIDDDefaults(); + } + + CoilSystemCoolingWater::CoilSystemCoolingWater(const Model& model, const HVACComponent& coolingCoil) + : StraightComponent(CoilSystemCoolingWater::iddObjectType(), model) { + OS_ASSERT(getImpl()); + + bool ok = true; ok = setCoolingCoil(coolingCoil); - OS_ASSERT(ok); - ok = setDehumidificationControlType("None"); - OS_ASSERT(ok); - ok = setRunonSensibleLoad(true); - OS_ASSERT(ok); - ok = setRunonLatentLoad(false); - OS_ASSERT(ok); - ok = setMinimumAirToWaterTemperatureOffset(0.0); - OS_ASSERT(ok); - ok = setEconomizerLockout(true); - OS_ASSERT(ok); - ok = setMinimumWaterLoopTemperatureForHeatRecovery(0.0); - OS_ASSERT(ok); + if (!ok) { + remove(); + LOG_AND_THROW("Unable to set " << briefDescription() << "'s Cooling Coil " << coolingCoil.briefDescription() << "."); + } + + assignEnergyPlusIDDDefaults(); } IddObjectType CoilSystemCoolingWater::iddObjectType() { @@ -372,7 +355,7 @@ namespace model { return getImpl()->availabilitySchedule(); } - WaterToAirComponent CoilSystemCoolingWater::coolingCoil() const { + HVACComponent CoilSystemCoolingWater::coolingCoil() const { return getImpl()->coolingCoil(); } @@ -400,7 +383,7 @@ namespace model { return getImpl()->minimumWaterLoopTemperatureForHeatRecovery(); } - boost::optional CoilSystemCoolingWater::companionCoilUsedForHeatRecovery() const { + boost::optional CoilSystemCoolingWater::companionCoilUsedForHeatRecovery() const { return getImpl()->companionCoilUsedForHeatRecovery(); } @@ -408,7 +391,7 @@ namespace model { return getImpl()->setAvailabilitySchedule(schedule); } - bool CoilSystemCoolingWater::setCoolingCoil(const WaterToAirComponent& coolingCoil) { + bool CoilSystemCoolingWater::setCoolingCoil(const HVACComponent& coolingCoil) { return getImpl()->setCoolingCoil(coolingCoil); } @@ -436,7 +419,7 @@ namespace model { return getImpl()->setMinimumWaterLoopTemperatureForHeatRecovery(minimumWaterLoopTemperatureForHeatRecovery); } - bool CoilSystemCoolingWater::setCompanionCoilUsedForHeatRecovery(const WaterToAirComponent& companionCoilUsedForHeatRecovery) { + bool CoilSystemCoolingWater::setCompanionCoilUsedForHeatRecovery(const HVACComponent& companionCoilUsedForHeatRecovery) { return getImpl()->setCompanionCoilUsedForHeatRecovery(companionCoilUsedForHeatRecovery); } diff --git a/src/model/CoilSystemCoolingWater.hpp b/src/model/CoilSystemCoolingWater.hpp index e22211ecbd..dcc2cebd74 100644 --- a/src/model/CoilSystemCoolingWater.hpp +++ b/src/model/CoilSystemCoolingWater.hpp @@ -14,7 +14,7 @@ namespace openstudio { namespace model { class Schedule; - class WaterToAirComponent; + class HVACComponent; namespace detail { @@ -31,7 +31,7 @@ namespace model { explicit CoilSystemCoolingWater(const Model& model); - explicit CoilSystemCoolingWater(const Model& model, const WaterToAirComponent& coolingCoil); + explicit CoilSystemCoolingWater(const Model& model, const HVACComponent& coolingCoil); virtual ~CoilSystemCoolingWater() = default; // Default the copy and move operators because the virtual dtor is explicit @@ -51,7 +51,7 @@ namespace model { Schedule availabilitySchedule() const; - WaterToAirComponent coolingCoil() const; + HVACComponent coolingCoil() const; std::string dehumidificationControlType() const; @@ -65,7 +65,7 @@ namespace model { double minimumWaterLoopTemperatureForHeatRecovery() const; - boost::optional companionCoilUsedForHeatRecovery() const; + boost::optional companionCoilUsedForHeatRecovery() const; //@} /** @name Setters */ @@ -73,7 +73,8 @@ namespace model { bool setAvailabilitySchedule(Schedule& schedule); - bool setCoolingCoil(const WaterToAirComponent& coolingCoil); + // CoilCoolingWater or CoilSystemCoolingWaterHeatExchangerAssisted + bool setCoolingCoil(const HVACComponent& coolingCoil); bool setDehumidificationControlType(const std::string& dehumidificationControlType); @@ -87,7 +88,8 @@ namespace model { bool setMinimumWaterLoopTemperatureForHeatRecovery(double minimumWaterLoopTemperatureForHeatRecovery); - bool setCompanionCoilUsedForHeatRecovery(const WaterToAirComponent& companionCoilUsedForHeatRecovery); + // Only CoilCoolingWater is supported by E+ as a companion coil right now + bool setCompanionCoilUsedForHeatRecovery(const HVACComponent& companionCoilUsedForHeatRecovery); void resetCompanionCoilUsedForHeatRecovery(); @@ -109,6 +111,8 @@ namespace model { /// @endcond private: REGISTER_LOGGER("openstudio.model.CoilSystemCoolingWater"); + + void assignEnergyPlusIDDDefaults(); }; /** \relates CoilSystemCoolingWater*/ diff --git a/src/model/CoilSystemCoolingWaterHeatExchangerAssisted.cpp b/src/model/CoilSystemCoolingWaterHeatExchangerAssisted.cpp index ddfcb53090..4c47c420be 100644 --- a/src/model/CoilSystemCoolingWaterHeatExchangerAssisted.cpp +++ b/src/model/CoilSystemCoolingWaterHeatExchangerAssisted.cpp @@ -11,6 +11,8 @@ #include "WaterToAirComponent_Impl.hpp" #include "CoilCoolingWater.hpp" #include "CoilCoolingWater_Impl.hpp" +#include "CoilSystemCoolingWater.hpp" +#include "CoilSystemCoolingWater_Impl.hpp" #include "Model.hpp" #include "Model_Impl.hpp" #include "Node.hpp" @@ -71,8 +73,12 @@ namespace model { std::vector CoilSystemCoolingWaterHeatExchangerAssisted_Impl::children() const { std::vector result; - result.push_back(coolingCoil()); - result.push_back(heatExchanger()); + if (auto intermediate = optionalCoolingCoil()) { + result.push_back(*intermediate); + } + if (auto intermediate = optionalHeatExchanger()) { + result.push_back(*intermediate); + } return result; } @@ -93,6 +99,14 @@ namespace model { return std::move(newCoilSystem); } + std::vector CoilSystemCoolingWaterHeatExchangerAssisted_Impl::remove() { + if (auto cc_ = optionalCoolingCoil()) { + cc_->removeFromPlantLoop(); + } + + return StraightComponent_Impl::remove(); + } + boost::optional CoilSystemCoolingWaterHeatExchangerAssisted_Impl::containingHVACComponent() const { // AirLoopHVACUnitarySystem std::vector airLoopHVACUnitarySystems = this->model().getConcreteModelObjects(); @@ -105,6 +119,17 @@ namespace model { } } + // CoilSystemCoolingWater + for (const auto& coilSystem : this->model().getConcreteModelObjects()) { + if (coilSystem.coolingCoil().handle() == this->handle()) { + return coilSystem; + } else if (boost::optional companionCoil_ = coilSystem.companionCoilUsedForHeatRecovery()) { + if (companionCoil_->handle() == this->handle()) { + return coilSystem; + } + } + } + return boost::none; } @@ -235,13 +260,12 @@ namespace model { bool ok = setHeatExchanger(heatExchanger); if (!ok) { + remove(); LOG_AND_THROW("Unable to set " << briefDescription() << "'s Heat Exchanger " << heatExchanger.briefDescription() << "."); } CoilCoolingWater coolingCoil(model); setCoolingCoil(coolingCoil); - - setHeatExchanger(heatExchanger); } IddObjectType CoilSystemCoolingWaterHeatExchangerAssisted::iddObjectType() { diff --git a/src/model/CoilSystemCoolingWaterHeatExchangerAssisted_Impl.hpp b/src/model/CoilSystemCoolingWaterHeatExchangerAssisted_Impl.hpp index 85bb4ef471..375e842e9e 100644 --- a/src/model/CoilSystemCoolingWaterHeatExchangerAssisted_Impl.hpp +++ b/src/model/CoilSystemCoolingWaterHeatExchangerAssisted_Impl.hpp @@ -51,9 +51,12 @@ namespace model { // Will also clone the coolingCoil and heatExchanger virtual ModelObject clone(Model model) const override; - // This function will connect the underlying Coil:Cooling:Water object + // This function will connect the air side only, for water side, use the coils directly virtual bool addToNode(Node& node) override; + // Need to disconnect the Water side of the coil(s) before removing + virtual std::vector remove() override; + virtual boost::optional containingHVACComponent() const override; virtual boost::optional containingZoneHVACComponent() const override; diff --git a/src/model/CoilSystemCoolingWater_Impl.hpp b/src/model/CoilSystemCoolingWater_Impl.hpp index 860dd9dc5f..8793eba87e 100644 --- a/src/model/CoilSystemCoolingWater_Impl.hpp +++ b/src/model/CoilSystemCoolingWater_Impl.hpp @@ -13,7 +13,7 @@ namespace openstudio { namespace model { class Schedule; - class WaterToAirComponent; + class HVACComponent; namespace detail { @@ -52,9 +52,12 @@ namespace model { // Will also clone the coolingCoil and companionCoilUsedForHeatRecovery virtual ModelObject clone(Model model) const override; - // This function will connect the underlying Coil:Cooling:Water object + // This function will connect the air side only, for water side, use the coils directly virtual bool addToNode(Node& node) override; + // Need to disconnect the Water side of the coil(s) before removing + virtual std::vector remove() override; + virtual boost::optional containingHVACComponent() const override; virtual boost::optional containingZoneHVACComponent() const override; @@ -70,7 +73,7 @@ namespace model { Schedule availabilitySchedule() const; - WaterToAirComponent coolingCoil() const; + HVACComponent coolingCoil() const; std::string dehumidificationControlType() const; @@ -84,7 +87,7 @@ namespace model { double minimumWaterLoopTemperatureForHeatRecovery() const; - boost::optional companionCoilUsedForHeatRecovery() const; + boost::optional companionCoilUsedForHeatRecovery() const; //@} /** @name Setters */ @@ -92,7 +95,7 @@ namespace model { bool setAvailabilitySchedule(Schedule& schedule); - bool setCoolingCoil(const WaterToAirComponent& coolingCoil); + bool setCoolingCoil(const HVACComponent& coolingCoil); bool setDehumidificationControlType(const std::string& dehumidificationControlType); @@ -106,7 +109,7 @@ namespace model { bool setMinimumWaterLoopTemperatureForHeatRecovery(double minimumWaterLoopTemperatureForHeatRecovery); - bool setCompanionCoilUsedForHeatRecovery(const WaterToAirComponent& companionCoilUsedForHeatRecovery); + bool setCompanionCoilUsedForHeatRecovery(const HVACComponent& companionCoilUsedForHeatRecovery); void resetCompanionCoilUsedForHeatRecovery(); @@ -120,8 +123,7 @@ namespace model { REGISTER_LOGGER("openstudio.model.CoilSystemCoolingWater"); boost::optional optionalAvailabilitySchedule() const; - boost::optional optionalCoolingCoil() const; - boost::optional optionalCompanionCoilUsedForHeatRecovery() const; + boost::optional optionalCoolingCoil() const; }; } // namespace detail diff --git a/src/model/test/CoilSystemCoolingWaterHeatExchangerAssisted_GTest.cpp b/src/model/test/CoilSystemCoolingWaterHeatExchangerAssisted_GTest.cpp index 914fe9cfa3..78bf7460a0 100644 --- a/src/model/test/CoilSystemCoolingWaterHeatExchangerAssisted_GTest.cpp +++ b/src/model/test/CoilSystemCoolingWaterHeatExchangerAssisted_GTest.cpp @@ -98,11 +98,16 @@ TEST_F(ModelFixture, CoilSystemCoolingWaterHeatExchangerAssisted_clone) { auto hx = coilSystem.heatExchanger().cast(); AirLoopHVAC a(m); + EXPECT_EQ(2, a.supplyComponents().size()); // o --- o Node n = a.supplyOutletNode(); EXPECT_TRUE(coilSystem.addToNode(n)); + EXPECT_EQ(3, a.supplyComponents().size()); // o --- oa_sys --- o PlantLoop p(m); + EXPECT_EQ(5, p.demandComponents().size()); // o --- Splitter --- o --- Mixer --- o + EXPECT_TRUE(p.addDemandBranchForComponent(cc)); + EXPECT_EQ(7, p.demandComponents().size()); // o --- Splitter --- o --- coolingCoil --- Mixer --- o EXPECT_EQ(1u, m.getConcreteModelObjects().size()); EXPECT_EQ(1u, m.getConcreteModelObjects().size()); @@ -118,7 +123,7 @@ TEST_F(ModelFixture, CoilSystemCoolingWaterHeatExchangerAssisted_clone) { //EXPECT_EQ(coilSystem.plantLoop()->handle(), p.handle()); //EXPECT_TRUE(hx.airLoopHVAC()); - auto coilSystem2 = coilSystem.clone(m).cast(); + auto coilSystemClone = coilSystem.clone(m).cast(); EXPECT_EQ(2u, m.getConcreteModelObjects().size()); EXPECT_EQ(2u, m.getConcreteModelObjects().size()); @@ -128,12 +133,23 @@ TEST_F(ModelFixture, CoilSystemCoolingWaterHeatExchangerAssisted_clone) { EXPECT_TRUE(coilSystem.inletModelObject()); EXPECT_TRUE(coilSystem.outletModelObject()); - EXPECT_FALSE(coilSystem2.airLoopHVAC()); - EXPECT_FALSE(coilSystem2.inletModelObject()); - EXPECT_FALSE(coilSystem2.outletModelObject()); + EXPECT_FALSE(coilSystemClone.airLoopHVAC()); + EXPECT_FALSE(coilSystemClone.inletModelObject()); + EXPECT_FALSE(coilSystemClone.outletModelObject()); + + EXPECT_NE(coilSystemClone.coolingCoil().handle(), cc.handle()); + EXPECT_NE(coilSystemClone.heatExchanger().handle(), hx.handle()); + + coilSystemClone.remove(); + EXPECT_EQ(1, m.getConcreteModelObjects().size()); + EXPECT_EQ(1, m.getConcreteModelObjects().size()); + + coilSystem.remove(); + EXPECT_EQ(0, m.getConcreteModelObjects().size()); + EXPECT_EQ(0, m.getConcreteModelObjects().size()); - EXPECT_NE(coilSystem2.coolingCoil().handle(), cc.handle()); - EXPECT_NE(coilSystem2.heatExchanger().handle(), hx.handle()); + EXPECT_EQ(2, a.supplyComponents().size()); // o --- o + EXPECT_EQ(5, p.demandComponents().size()); // o --- Splitter --- o --- Mixer --- o } TEST_F(ModelFixture, CoilSystemCoolingWaterHeatExchangerAssisted_containingComponent) { diff --git a/src/model/test/CoilSystemCoolingWater_GTest.cpp b/src/model/test/CoilSystemCoolingWater_GTest.cpp index 7c1aa4b661..964dfa57a8 100644 --- a/src/model/test/CoilSystemCoolingWater_GTest.cpp +++ b/src/model/test/CoilSystemCoolingWater_GTest.cpp @@ -7,13 +7,25 @@ #include "../CoilSystemCoolingWater.hpp" #include "../CoilSystemCoolingWater_Impl.hpp" -#include "../Schedule.hpp" -#include "../Schedule_Impl.hpp" + #include "../CoilCoolingWater.hpp" #include "../CoilCoolingWater_Impl.hpp" +#include "../CoilSystemCoolingWaterHeatExchangerAssisted.hpp" +#include "../CoilSystemCoolingWaterHeatExchangerAssisted_Impl.hpp" + #include "../AirLoopHVAC.hpp" -#include "../PlantLoop.hpp" +#include "../AirLoopHVACOutdoorAirSystem.hpp" +#include "../ChillerElectricEIR.hpp" +#include "../CoilCoolingDXSingleSpeed.hpp" +#include "../CoilCoolingDXSingleSpeed_Impl.hpp" +#include "../ControllerWaterCoil.hpp" +#include "../ControllerWaterCoil_Impl.hpp" #include "../Node.hpp" +#include "../Node_Impl.hpp" +#include "../PlantLoop.hpp" +#include "../Schedule.hpp" +#include "../ScheduleConstant.hpp" +#include "../ScheduleTypeLimits.hpp" using namespace openstudio; using namespace openstudio::model; @@ -26,35 +38,70 @@ TEST_F(ModelFixture, CoilSystemCoolingWater_GettersSetters) { coilSystemCoolingWater.setName("My CoilSystemCoolingWater"); // Availability Schedule Name: Required Object + // Ctor default Schedule availabilitySchedule = m.alwaysOnDiscreteSchedule(); - EXPECT_TRUE(coilSystemCoolingWater.setAvailabilitySchedule(availabilitySchedule)); EXPECT_EQ(availabilitySchedule, coilSystemCoolingWater.availabilitySchedule()); + // set + ScheduleConstant availSch(m); + EXPECT_TRUE(coilSystemCoolingWater.setAvailabilitySchedule(availSch)); + EXPECT_EQ(availSch, coilSystemCoolingWater.availabilitySchedule()); + // The Schedule Type Registry should have done it's thing and assigned a scheduleTypeLimits + ASSERT_TRUE(availSch.scheduleTypeLimits()); + { + auto sch_type_lim = availSch.scheduleTypeLimits().get(); + EXPECT_EQ("OnOff", sch_type_lim.nameString()); + ASSERT_TRUE(sch_type_lim.lowerLimitValue()); + EXPECT_EQ(0.0, sch_type_lim.lowerLimitValue().get()); + ASSERT_TRUE(sch_type_lim.upperLimitValue()); + EXPECT_EQ(1.0, sch_type_lim.upperLimitValue().get()); + ASSERT_TRUE(sch_type_lim.numericType()); + EXPECT_EQ("Discrete", sch_type_lim.numericType().get()); + EXPECT_EQ("Availability", sch_type_lim.unitType()); + } // Cooling Coil: Required Object + // Ctor instantiates a CoilCoolingWater + EXPECT_TRUE(coilSystemCoolingWater.coolingCoil().optionalCast()); CoilCoolingWater coolingCoil(m); EXPECT_TRUE(coilSystemCoolingWater.setCoolingCoil(coolingCoil)); EXPECT_EQ(coolingCoil, coilSystemCoolingWater.coolingCoil()); + CoilSystemCoolingWaterHeatExchangerAssisted coilSystemCoolingWaterHeatExchangerAssisted(m); + EXPECT_TRUE(coilSystemCoolingWater.setCoolingCoil(coilSystemCoolingWaterHeatExchangerAssisted)); + EXPECT_EQ(coilSystemCoolingWaterHeatExchangerAssisted, coilSystemCoolingWater.coolingCoil()); + // Dehumidification Control Type: Required String - EXPECT_TRUE(coilSystemCoolingWater.setDehumidificationControlType("None")); + // Ctor default EXPECT_EQ("None", coilSystemCoolingWater.dehumidificationControlType()); + // set + EXPECT_TRUE(coilSystemCoolingWater.setDehumidificationControlType("CoolReheat")); + EXPECT_EQ("CoolReheat", coilSystemCoolingWater.dehumidificationControlType()); // Bad Value EXPECT_FALSE(coilSystemCoolingWater.setDehumidificationControlType("BADENUM")); - EXPECT_EQ("None", coilSystemCoolingWater.dehumidificationControlType()); + EXPECT_EQ("CoolReheat", coilSystemCoolingWater.dehumidificationControlType()); // Run on Sensible Load: Required Boolean - EXPECT_TRUE(coilSystemCoolingWater.setRunonSensibleLoad(true)); + // Ctor default EXPECT_TRUE(coilSystemCoolingWater.runonSensibleLoad()); + // set EXPECT_TRUE(coilSystemCoolingWater.setRunonSensibleLoad(false)); EXPECT_FALSE(coilSystemCoolingWater.runonSensibleLoad()); + EXPECT_TRUE(coilSystemCoolingWater.setRunonSensibleLoad(true)); + EXPECT_TRUE(coilSystemCoolingWater.runonSensibleLoad()); // Run on Latent Load: Required Boolean + // Ctor default + EXPECT_FALSE(coilSystemCoolingWater.runonLatentLoad()); + // set EXPECT_TRUE(coilSystemCoolingWater.setRunonLatentLoad(true)); EXPECT_TRUE(coilSystemCoolingWater.runonLatentLoad()); EXPECT_TRUE(coilSystemCoolingWater.setRunonLatentLoad(false)); EXPECT_FALSE(coilSystemCoolingWater.runonLatentLoad()); // Minimum Air To Water Temperature Offset: Required Double + // Ctor default + EXPECT_EQ(0.0, coilSystemCoolingWater.minimumAirToWaterTemperatureOffset()); + // set EXPECT_TRUE(coilSystemCoolingWater.setMinimumAirToWaterTemperatureOffset(1.0)); EXPECT_EQ(1.0, coilSystemCoolingWater.minimumAirToWaterTemperatureOffset()); // Bad Value @@ -62,36 +109,228 @@ TEST_F(ModelFixture, CoilSystemCoolingWater_GettersSetters) { EXPECT_EQ(1.0, coilSystemCoolingWater.minimumAirToWaterTemperatureOffset()); // Economizer Lockout: Required Boolean - EXPECT_TRUE(coilSystemCoolingWater.setEconomizerLockout(true)); + // Ctor default EXPECT_TRUE(coilSystemCoolingWater.economizerLockout()); + // set EXPECT_TRUE(coilSystemCoolingWater.setEconomizerLockout(false)); EXPECT_FALSE(coilSystemCoolingWater.economizerLockout()); + EXPECT_TRUE(coilSystemCoolingWater.setEconomizerLockout(true)); + EXPECT_TRUE(coilSystemCoolingWater.economizerLockout()); // Minimum Water Loop Temperature For Heat Recovery: Required Double + // Ctor default + EXPECT_EQ(0.0, coilSystemCoolingWater.minimumWaterLoopTemperatureForHeatRecovery()); + // set EXPECT_TRUE(coilSystemCoolingWater.setMinimumWaterLoopTemperatureForHeatRecovery(1.2)); EXPECT_EQ(1.2, coilSystemCoolingWater.minimumWaterLoopTemperatureForHeatRecovery()); // Companion Coil Used For Heat Recovery: Optional Object + // The only type allowed is CoilCoolingWater CoilCoolingWater companionCoilUsedForHeatRecovery(m); EXPECT_TRUE(coilSystemCoolingWater.setCompanionCoilUsedForHeatRecovery(companionCoilUsedForHeatRecovery)); ASSERT_TRUE(coilSystemCoolingWater.companionCoilUsedForHeatRecovery()); EXPECT_EQ(companionCoilUsedForHeatRecovery, coilSystemCoolingWater.companionCoilUsedForHeatRecovery().get()); + + CoilSystemCoolingWaterHeatExchangerAssisted wrongCompanionCoil(m); + EXPECT_FALSE(coilSystemCoolingWater.setCompanionCoilUsedForHeatRecovery(wrongCompanionCoil)); + ASSERT_TRUE(coilSystemCoolingWater.companionCoilUsedForHeatRecovery()); + EXPECT_EQ(companionCoilUsedForHeatRecovery, coilSystemCoolingWater.companionCoilUsedForHeatRecovery().get()); +} + +TEST_F(ModelFixture, CoilSystemCoolingWater_ExplicitCtor) { + { + Model m; + CoilCoolingWater coolingCoil(m); + CoilSystemCoolingWater coilSystem(m, coolingCoil); + EXPECT_EQ(coolingCoil, coilSystem.coolingCoil()); + EXPECT_EQ(1, m.getConcreteModelObjects().size()); + EXPECT_EQ(1, m.getConcreteModelObjects().size()); + } + + { + Model m; + CoilSystemCoolingWaterHeatExchangerAssisted coolingCoil(m); + CoilSystemCoolingWater coilSystem(m, coolingCoil); + EXPECT_EQ(coolingCoil, coilSystem.coolingCoil()); + EXPECT_EQ(1, m.getConcreteModelObjects().size()); + EXPECT_EQ(1, m.getConcreteModelObjects().size()); + } + + { + Model m; + CoilCoolingDXSingleSpeed coolingCoil(m); + EXPECT_ANY_THROW(CoilSystemCoolingWater coilSystem(m, coolingCoil)); + EXPECT_EQ(0, m.getConcreteModelObjects().size()); + EXPECT_EQ(1, m.getConcreteModelObjects().size()); + } } TEST_F(ModelFixture, CoilSystemCoolingWater_HeatCoolFuelTypes) { Model m; - CoilSystemCoolingWater coilSystemCoolingWater(m); - - EXPECT_EQ(ComponentType(ComponentType::Cooling), coilSystemCoolingWater.componentType()); - testFuelTypeEquality({}, coilSystemCoolingWater.coolingFuelTypes()); - testFuelTypeEquality({}, coilSystemCoolingWater.heatingFuelTypes()); - testAppGFuelTypeEquality({}, coilSystemCoolingWater.appGHeatingFuelTypes()); + CoilSystemCoolingWater coilSystem(m); + auto cc = coilSystem.coolingCoil().cast(); + + EXPECT_EQ(ComponentType(ComponentType::Cooling), coilSystem.componentType()); + testFuelTypeEquality({}, coilSystem.coolingFuelTypes()); + testFuelTypeEquality({}, coilSystem.heatingFuelTypes()); + testAppGFuelTypeEquality({}, coilSystem.appGHeatingFuelTypes()); + + PlantLoop p(m); + ChillerElectricEIR ch(m); + EXPECT_TRUE(p.addSupplyBranchForComponent(ch)); + EXPECT_TRUE(p.addDemandBranchForComponent(cc)); + EXPECT_EQ(ComponentType(ComponentType::Cooling), coilSystem.componentType()); + testFuelTypeEquality({FuelType::Electricity}, coilSystem.coolingFuelTypes()); + testFuelTypeEquality({}, coilSystem.heatingFuelTypes()); + testAppGFuelTypeEquality({}, coilSystem.appGHeatingFuelTypes()); } -TEST_F(ModelFixture, CoilSystemCoolingWater_clone) {} +TEST_F(ModelFixture, CoilSystemCoolingWater_clone_remove) { -TEST_F(ModelFixture, CoilSystemCoolingWater_remove) {} + Model m; + + // Wrap Around Water Coil Heat Recovery Mode + // CoilSystem has: + // - Primary Cooling Coil: a CoilSystemCoolingWaterHeatExchangerAssisted + // - This HXAssisted has a CoilCoolingWater as its coolingCoil + // - Companion Coil: a CoilCoolingWater + // + // CoilSystem is connected to an AirLoopHVACOutdoorAirSystem on the OA Intake + // Companion Coil is connected to OA Relief + // Both coils are connected to a PlantLoop in series on the demand side + + CoilSystemCoolingWaterHeatExchangerAssisted coilSystemHXAssisted(m); + auto coolingCoil = coilSystemHXAssisted.coolingCoil().cast(); + coolingCoil.setName("Primary Cooling Coil inside HXAssisted"); + CoilSystemCoolingWater coilSystem(m, coilSystemHXAssisted); + + CoilCoolingWater companionCoil(m); + companionCoil.setName("Companion Coil"); + EXPECT_TRUE(coilSystem.setCompanionCoilUsedForHeatRecovery(companionCoil)); + + // Air side connections + AirLoopHVAC a(m); + AirLoopHVACOutdoorAirSystem oa_sys(m); + EXPECT_EQ(2, a.supplyComponents().size()); // o --- o + EXPECT_EQ(1, oa_sys.oaComponents().size()); // o + EXPECT_EQ(1, oa_sys.reliefComponents().size()); // o + { + Node n = a.supplyOutletNode(); + EXPECT_TRUE(oa_sys.addToNode(n)); + } + EXPECT_EQ(3, a.supplyComponents().size()); // o --- oa_sys --- o + EXPECT_EQ(1, oa_sys.oaComponents().size()); // o + EXPECT_EQ(1, oa_sys.reliefComponents().size()); // o + { + Node n = oa_sys.outboardOANode().get(); + EXPECT_TRUE(coilSystem.addToNode(n)); + } + EXPECT_EQ(3, a.supplyComponents().size()); // o --- oa_sys --- o + EXPECT_EQ(3, oa_sys.oaComponents().size()); // o --- coilSystem --- o + EXPECT_EQ(1, oa_sys.reliefComponents().size()); // o + { + Node n = oa_sys.outboardReliefNode().get(); + EXPECT_TRUE(companionCoil.addToNode(n)); + } + EXPECT_EQ(3, a.supplyComponents().size()); // o --- oa_sys --- o + EXPECT_EQ(3, oa_sys.oaComponents().size()); // o --- coilSystem --- o + EXPECT_EQ(3, oa_sys.reliefComponents().size()); // o --- companionCoil --- o + + // Plant Side connections: in series + PlantLoop p(m); + EXPECT_EQ(5, p.demandComponents().size()); // o --- Splitter --- o --- Mixer --- o + + EXPECT_TRUE(p.addDemandBranchForComponent(coolingCoil)); + EXPECT_EQ(7, p.demandComponents().size()); // o --- Splitter --- o --- coolingCoil --- Mixer --- o + + { + Node n = coolingCoil.waterOutletModelObject()->cast(); + EXPECT_TRUE(companionCoil.addToNode(n)); + } + EXPECT_EQ(9, p.demandComponents().size()); // o --- Splitter --- o --- coolingCoil --- o --- HR Coil --- o --- Mixer --- o + + EXPECT_EQ(1, m.getConcreteModelObjects().size()); + EXPECT_EQ(1, m.getConcreteModelObjects().size()); + EXPECT_EQ(2, m.getConcreteModelObjects().size()); + + ASSERT_TRUE(coilSystem.airLoopHVAC()); + EXPECT_EQ(coilSystem.airLoopHVAC()->handle(), a.handle()); + + EXPECT_TRUE(coolingCoil.plantLoop()); + EXPECT_TRUE(companionCoil.plantLoop()); + + EXPECT_FALSE(coolingCoil.controllerWaterCoil()); + EXPECT_FALSE(companionCoil.controllerWaterCoil()); + EXPECT_EQ(0, m.getConcreteModelObjects().size()); + + auto coilSystemClone = coilSystem.clone(m).cast(); + + EXPECT_EQ(2, m.getConcreteModelObjects().size()); + EXPECT_EQ(2, m.getConcreteModelObjects().size()); + EXPECT_EQ(4, m.getConcreteModelObjects().size()); + EXPECT_EQ(0, m.getConcreteModelObjects().size()); + + EXPECT_TRUE(coilSystem.airLoopHVAC()); + EXPECT_TRUE(coilSystem.inletModelObject()); + EXPECT_TRUE(coilSystem.outletModelObject()); + + EXPECT_FALSE(coilSystemClone.airLoopHVAC()); + EXPECT_FALSE(coilSystemClone.inletModelObject()); + EXPECT_FALSE(coilSystemClone.outletModelObject()); + + EXPECT_TRUE(coilSystemClone.coolingCoil().optionalCast()); + EXPECT_NE(coilSystemHXAssisted.handle(), coilSystemClone.coolingCoil().handle()); + + ASSERT_TRUE(coilSystemClone.companionCoilUsedForHeatRecovery()); + EXPECT_TRUE(coilSystemClone.companionCoilUsedForHeatRecovery()->optionalCast()); + EXPECT_NE(companionCoil.handle(), coilSystemClone.companionCoilUsedForHeatRecovery()->handle()); + + // Clone into another Model + { + Model m2; + auto coilSystemClone = coilSystem.clone(m2).cast(); + + EXPECT_EQ(1, m2.getConcreteModelObjects().size()); + EXPECT_EQ(1, m2.getConcreteModelObjects().size()); + EXPECT_EQ(2, m2.getConcreteModelObjects().size()); + EXPECT_EQ(0, m2.getConcreteModelObjects().size()); + + EXPECT_FALSE(coilSystemClone.airLoopHVAC()); + EXPECT_FALSE(coilSystemClone.inletModelObject()); + EXPECT_FALSE(coilSystemClone.outletModelObject()); + + EXPECT_TRUE(coilSystemClone.coolingCoil().optionalCast()); + EXPECT_NE(coilSystemHXAssisted.handle(), coilSystemClone.coolingCoil().handle()); + + ASSERT_TRUE(coilSystemClone.companionCoilUsedForHeatRecovery()); + EXPECT_TRUE(coilSystemClone.companionCoilUsedForHeatRecovery()->optionalCast()); + EXPECT_NE(companionCoil.handle(), coilSystemClone.companionCoilUsedForHeatRecovery()->handle()); + + // Remove + coilSystemClone.remove(); + EXPECT_EQ(0, m2.getConcreteModelObjects().size()); + EXPECT_EQ(0, m2.getConcreteModelObjects().size()); + EXPECT_EQ(0, m2.getConcreteModelObjects().size()); + } + + coilSystemClone.remove(); + EXPECT_EQ(1, m.getConcreteModelObjects().size()); + EXPECT_EQ(1, m.getConcreteModelObjects().size()); + EXPECT_EQ(2, m.getConcreteModelObjects().size()); + EXPECT_EQ(0, m.getConcreteModelObjects().size()); + + coilSystem.remove(); + EXPECT_EQ(0, m.getConcreteModelObjects().size()); + EXPECT_EQ(0, m.getConcreteModelObjects().size()); + EXPECT_EQ(0, m.getConcreteModelObjects().size()); + EXPECT_EQ(0, m.getConcreteModelObjects().size()); + + EXPECT_EQ(3, a.supplyComponents().size()); // o --- oa_sys --- o + EXPECT_EQ(1, oa_sys.oaComponents().size()); // o + EXPECT_EQ(1, oa_sys.reliefComponents().size()); // o + EXPECT_EQ(5, p.demandComponents().size()); // o --- Splitter --- o --- Mixer --- o +} TEST_F(ModelFixture, CoilSystemCoolingWater_addToNode) { // Water Size Economizer Model @@ -106,11 +345,11 @@ TEST_F(ModelFixture, CoilSystemCoolingWater_addToNode) { EXPECT_EQ(2u, a.supplyComponents().size()); - EXPECT_TRUE(cc.addToNode(n)); - EXPECT_EQ(3u, a.supplyComponents().size()); + EXPECT_FALSE(cc.addToNode(n)); + EXPECT_EQ(2u, a.supplyComponents().size()); EXPECT_TRUE(coilSystem.addToNode(n)); - EXPECT_EQ(5u, a.supplyComponents().size()); + EXPECT_EQ(3u, a.supplyComponents().size()); { auto containingHVACComponent = cc.containingHVACComponent(); @@ -138,14 +377,14 @@ TEST_F(ModelFixture, CoilSystemCoolingWater_addToNode) { EXPECT_EQ(2u, a.supplyComponents().size()); - EXPECT_TRUE(cc.addToNode(n)); - EXPECT_EQ(3u, a.supplyComponents().size()); + EXPECT_FALSE(cc.addToNode(n)); + EXPECT_EQ(2, a.supplyComponents().size()); EXPECT_TRUE(hr.addToNode(n)); - EXPECT_EQ(5u, a.supplyComponents().size()); + EXPECT_EQ(3, a.supplyComponents().size()); EXPECT_TRUE(coilSystem.addToNode(n)); - EXPECT_EQ(7u, a.supplyComponents().size()); + EXPECT_EQ(5, a.supplyComponents().size()); { auto containingHVACComponent = cc.containingHVACComponent();