Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ namespace energyplus {
idfObject.setDouble(CoilSystem_Cooling_WaterFields::MinimumWaterLoopTemperatureForHeatRecovery, minimumWaterLoopTemperatureForHeatRecovery);

// Companion Coil Used For Heat Recovery: Optional Object
if (boost::optional<WaterToAirComponent> companionCoilUsedForHeatRecovery_ = modelObject.companionCoilUsedForHeatRecovery()) {
if (boost::optional<HVACComponent> companionCoilUsedForHeatRecovery_ = modelObject.companionCoilUsedForHeatRecovery()) {
if (boost::optional<IdfObject> wo_ = translateAndMapModelObject(companionCoilUsedForHeatRecovery_.get())) {
idfObject.setString(CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery, wo_->nameString());
if (wo_->iddObject().type() == IddObjectType::Coil_Cooling_Water) {
Expand Down
444 changes: 198 additions & 246 deletions src/energyplus/Test/CoilSystemCoolingWater_GTest.cpp

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I improved the testing for the cases you wrote, and I added a new one for CoilSystem_Cooling_Water_HeatExchangerAssisted

Large diffs are not rendered by default.

82 changes: 51 additions & 31 deletions src/model/CoilCoolingWater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CoilSystemCoolingWaterHeatExchangerAssisted>()) {
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<CoilSystemCoolingWater>()) {
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<CoilSystemCoolingWaterHeatExchangerAssisted>()) {
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<CoilSystemCoolingWater>()
&& t_containingHVACComponent->cast<CoilSystemCoolingWater>().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;
}
}
Comment on lines +281 to +297

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The primary cooling coil of the CoilSystemCoolingWater shouldn't be connected directly to an AirLoopHVAC, at least that's my interpretation of the E+ testfiles.


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;
}
Comment on lines +299 to +307

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exit early when we definitely don't need a controller water coil


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<CoilSystemCoolingWater>()) {
// no-op
} else {
Model t_model = model();
ControllerWaterCoil controller(t_model);
controller.getImpl<ControllerWaterCoil_Impl>()->setWaterCoil(getObject<HVACComponent>());
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<CoilSystemCoolingWater>()) {
needAController = false;
} else if (auto hxAssisted_ = t_containingHVACComponent->optionalCast<CoilSystemCoolingWaterHeatExchangerAssisted>()) {
if (auto parent_ = hxAssisted_->containingHVACComponent()) {
if (parent_->optionalCast<CoilSystemCoolingWater>()) {
needAController = false;
Comment on lines +309 to +318

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a ControllerWaterCoil except if we're directly or indirectly (via a CoilSystemCoolingWaterHeatExchangerAssisted) part of a CoilSystemCoolingWater.

}
}
}
}

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<ControllerWaterCoil_Impl>()->setWaterCoil(getObject<HVACComponent>());
controller.setAction("Reverse");
}
Comment on lines +324 to +336

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we need a controller:

  • If there is one, we kept it, but warn if not reverse
  • If there isn't one: we create it

If we don't need a controller, just remove any existing one


return success;
}

Expand Down Expand Up @@ -389,7 +409,7 @@ namespace model {
if (coilSystem.coolingCoil().handle() == handle()) {
return coilSystem;
}
if (boost::optional<WaterToAirComponent> companionCoilUsedForHeatRecovery = coilSystem.companionCoilUsedForHeatRecovery()) {
if (boost::optional<HVACComponent> companionCoilUsedForHeatRecovery = coilSystem.companionCoilUsedForHeatRecovery()) {
if (companionCoilUsedForHeatRecovery->handle() == this->handle()) {
return coilSystem;
}
Expand Down
129 changes: 60 additions & 69 deletions src/model/CoilSystemCoolingWater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -87,24 +89,47 @@ namespace model {

std::vector<ModelObject> CoilSystemCoolingWater_Impl::children() const {
std::vector<ModelObject> 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<IdfObject> CoilSystemCoolingWater_Impl::remove() {
std::vector<IdfObject> result;

if (auto c_ = optionalCoolingCoil()) { // This is false when the explicit ctor throws
if (boost::optional<WaterToAirComponent> cc_ = c_->optionalCast<WaterToAirComponent>()) {
cc_->removeFromPlantLoop();
} else if (auto cc_ = c_->optionalCast<CoilSystemCoolingWaterHeatExchangerAssisted>()) {
cc_->coolingCoil().removeFromPlantLoop();
} else {
OS_ASSERT(false);
}
}
if (auto companionCoil_ = companionCoilUsedForHeatRecovery()) {
if (auto cc_ = companionCoil_->optionalCast<WaterToAirComponent>()) {
cc_->removeFromPlantLoop();
} else {
OS_ASSERT(false);
}
}

return StraightComponent_Impl::remove();
}

ModelObject CoilSystemCoolingWater_Impl::clone(Model model) const {
auto coilSystemClone = StraightComponent_Impl::clone(model).cast<CoilSystemCoolingWater>();

if (OptionalWaterToAirComponent intermediate = optionalCoolingCoil()) {
coilSystemClone.setCoolingCoil(intermediate->clone(model).cast<WaterToAirComponent>());
if (OptionalHVACComponent intermediate = optionalCoolingCoil()) {
coilSystemClone.setCoolingCoil(intermediate->clone(model).cast<HVACComponent>());
}
if (OptionalWaterToAirComponent intermediate = optionalCompanionCoilUsedForHeatRecovery()) {
coilSystemClone.setCompanionCoilUsedForHeatRecovery(intermediate->clone(model).cast<WaterToAirComponent>());
if (OptionalHVACComponent intermediate = companionCoilUsedForHeatRecovery()) {
coilSystemClone.setCompanionCoilUsedForHeatRecovery(intermediate->clone(model).cast<HVACComponent>());
}

return std::move(coilSystemClone);
Expand All @@ -127,50 +152,10 @@ namespace model {
}

boost::optional<HVACComponent> CoilSystemCoolingWater_Impl::containingHVACComponent() const {
// AirLoopHVACUnitarySystem
std::vector<AirLoopHVACUnitarySystem> airLoopHVACUnitarySystems = this->model().getConcreteModelObjects<AirLoopHVACUnitarySystem>();

for (const auto& airLoopHVACUnitarySystem : airLoopHVACUnitarySystems) {
if (boost::optional<HVACComponent> coolingCoil = airLoopHVACUnitarySystem.coolingCoil()) {
if (coolingCoil->handle() == this->handle()) {
return airLoopHVACUnitarySystem;
}
}
}
Comment on lines 154 to -139

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CANNOT be part of a containing HVACComponent AFAIK


return boost::none;
}

boost::optional<ZoneHVACComponent> CoilSystemCoolingWater_Impl::containingZoneHVACComponent() const {

// ZoneHVACFourPipeFanCoil
std::vector<ZoneHVACFourPipeFanCoil> zoneHVACFourPipeFanCoils;

zoneHVACFourPipeFanCoils = this->model().getConcreteModelObjects<ZoneHVACFourPipeFanCoil>();
Comment on lines 158 to -149

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CANNOT be part of a containing ZoneHVACComponent AFAIK

This is from the E+ IDD, there are ZERO possible references.


for (const auto& zoneHVACFourPipeFanCoil : zoneHVACFourPipeFanCoils) {
if (boost::optional<HVACComponent> coil = zoneHVACFourPipeFanCoil.coolingCoil()) {
if (coil->handle() == this->handle()) {
return zoneHVACFourPipeFanCoil;
}
}
}

// ZoneHVACUnitVentilator
std::vector<ZoneHVACUnitVentilator> zoneHVACUnitVentilators;

zoneHVACUnitVentilators = this->model().getConcreteModelObjects<ZoneHVACUnitVentilator>();

for (const auto& zoneHVACUnitVentilator : zoneHVACUnitVentilators) {
if (boost::optional<HVACComponent> coil = zoneHVACUnitVentilator.coolingCoil()) {
if (coil->handle() == this->handle()) {
return zoneHVACUnitVentilator;
}
}
}

// ZoneHVAC:WindowAirConditioner not wrapped

return boost::none;
}

Expand Down Expand Up @@ -198,8 +183,8 @@ namespace model {
return value.get();
}

WaterToAirComponent CoilSystemCoolingWater_Impl::coolingCoil() const {
boost::optional<WaterToAirComponent> value = optionalCoolingCoil();
HVACComponent CoilSystemCoolingWater_Impl::coolingCoil() const {
boost::optional<HVACComponent> value = optionalCoolingCoil();
if (!value) {
LOG_AND_THROW(briefDescription() << " does not have an Cooling Coil attached.");
}
Expand Down Expand Up @@ -236,8 +221,8 @@ namespace model {
return value.get();
}

boost::optional<WaterToAirComponent> CoilSystemCoolingWater_Impl::companionCoilUsedForHeatRecovery() const {
return optionalCompanionCoilUsedForHeatRecovery();
boost::optional<HVACComponent> CoilSystemCoolingWater_Impl::companionCoilUsedForHeatRecovery() const {
return getObject<ModelObject>().getModelObjectTarget<HVACComponent>(OS_CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery);
}

bool CoilSystemCoolingWater_Impl::setAvailabilitySchedule(Schedule& schedule) {
Expand All @@ -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;
}
Expand Down Expand Up @@ -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() {
Expand All @@ -300,12 +292,8 @@ namespace model {
return getObject<ModelObject>().getModelObjectTarget<Schedule>(OS_CoilSystem_Cooling_WaterFields::AvailabilityScheduleName);
}

boost::optional<WaterToAirComponent> CoilSystemCoolingWater_Impl::optionalCoolingCoil() const {
return getObject<ModelObject>().getModelObjectTarget<WaterToAirComponent>(OS_CoilSystem_Cooling_WaterFields::CoolingCoil);
}

boost::optional<WaterToAirComponent> CoilSystemCoolingWater_Impl::optionalCompanionCoilUsedForHeatRecovery() const {
return getObject<ModelObject>().getModelObjectTarget<WaterToAirComponent>(OS_CoilSystem_Cooling_WaterFields::CompanionCoilUsedForHeatRecovery);
boost::optional<HVACComponent> CoilSystemCoolingWater_Impl::optionalCoolingCoil() const {
return getObject<ModelObject>().getModelObjectTarget<HVACComponent>(OS_CoilSystem_Cooling_WaterFields::CoolingCoil);
}

} // namespace detail
Expand Down Expand Up @@ -335,17 +323,20 @@ namespace model {
OS_ASSERT(ok);
}

CoilSystemCoolingWater::CoilSystemCoolingWater(const Model& model, const WaterToAirComponent& coolingCoil)
CoilSystemCoolingWater::CoilSystemCoolingWater(const Model& model, const HVACComponent& coolingCoil)
: StraightComponent(CoilSystemCoolingWater::iddObjectType(), model) {
OS_ASSERT(getImpl<detail::CoilSystemCoolingWater_Impl>());

bool ok = true;
ok = setCoolingCoil(coolingCoil);
if (!ok) {
remove();
LOG_AND_THROW("Unable to set " << briefDescription() << "'s Cooling Coil " << coolingCoil.briefDescription() << ".");
}
Comment on lines 342 to +341

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how you handle the explicit ctor being passed the wrong object, which can definitely happen.

auto alwaysOn = model.alwaysOnDiscreteSchedule();
ok = setAvailabilitySchedule(alwaysOn);
OS_ASSERT(ok);

ok = setCoolingCoil(coolingCoil);
OS_ASSERT(ok);
ok = setDehumidificationControlType("None");
OS_ASSERT(ok);
ok = setRunonSensibleLoad(true);
Expand All @@ -372,7 +363,7 @@ namespace model {
return getImpl<detail::CoilSystemCoolingWater_Impl>()->availabilitySchedule();
}

WaterToAirComponent CoilSystemCoolingWater::coolingCoil() const {
HVACComponent CoilSystemCoolingWater::coolingCoil() const {
return getImpl<detail::CoilSystemCoolingWater_Impl>()->coolingCoil();
}

Expand Down Expand Up @@ -400,15 +391,15 @@ namespace model {
return getImpl<detail::CoilSystemCoolingWater_Impl>()->minimumWaterLoopTemperatureForHeatRecovery();
}

boost::optional<WaterToAirComponent> CoilSystemCoolingWater::companionCoilUsedForHeatRecovery() const {
boost::optional<HVACComponent> CoilSystemCoolingWater::companionCoilUsedForHeatRecovery() const {
return getImpl<detail::CoilSystemCoolingWater_Impl>()->companionCoilUsedForHeatRecovery();
}

bool CoilSystemCoolingWater::setAvailabilitySchedule(Schedule& schedule) {
return getImpl<detail::CoilSystemCoolingWater_Impl>()->setAvailabilitySchedule(schedule);
}

bool CoilSystemCoolingWater::setCoolingCoil(const WaterToAirComponent& coolingCoil) {
bool CoilSystemCoolingWater::setCoolingCoil(const HVACComponent& coolingCoil) {
return getImpl<detail::CoilSystemCoolingWater_Impl>()->setCoolingCoil(coolingCoil);
}

Expand Down Expand Up @@ -436,7 +427,7 @@ namespace model {
return getImpl<detail::CoilSystemCoolingWater_Impl>()->setMinimumWaterLoopTemperatureForHeatRecovery(minimumWaterLoopTemperatureForHeatRecovery);
}

bool CoilSystemCoolingWater::setCompanionCoilUsedForHeatRecovery(const WaterToAirComponent& companionCoilUsedForHeatRecovery) {
bool CoilSystemCoolingWater::setCompanionCoilUsedForHeatRecovery(const HVACComponent& companionCoilUsedForHeatRecovery) {
return getImpl<detail::CoilSystemCoolingWater_Impl>()->setCompanionCoilUsedForHeatRecovery(companionCoilUsedForHeatRecovery);
}

Expand Down
Loading