Skip to content

Commit

Permalink
Merge pull request #3996 from NREL/3990_CoilCoolingDXMultiSpeed_stageAPI
Browse files Browse the repository at this point in the history
Fix #3990 -  Add an API to CoilCoolingDXMultiSpeed to add/remove stages
  • Loading branch information
kbenne authored Aug 10, 2020
2 parents d6fb42e + 59f759b commit 373a625
Show file tree
Hide file tree
Showing 12 changed files with 483 additions and 52 deletions.
7 changes: 7 additions & 0 deletions resources/model/OpenStudio.idd
Original file line number Diff line number Diff line change
Expand Up @@ -15918,6 +15918,13 @@ OS:CoilPerformance:DX:Cooling,

OS:Coil:Cooling:DX:MultiSpeed,
\extensible:1
\max-fields 22
\memo Direct expansion (DX) cooling coil and condensing unit (includes electric or
\memo engine-driven compressor and condenser fan), multi-speed (or variable-speed).
\memo Optional moisture evaporation from wet coil when compressor cycles off with continuous
\memo fan operation. Requires two to four sets of performance data and will interpolate
\memo between speeds. Modeled as a single coil (multi-speed compressor or multiple
\memo compressors with row split or intertwined coil).
A1, \field Handle
\type handle
\required-field
Expand Down
149 changes: 145 additions & 4 deletions src/model/CoilCoolingDXMultiSpeed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@ namespace detail {
return result;
}

unsigned CoilCoolingDXMultiSpeed_Impl::numberOfStages() const {
return numExtensibleGroups();
}

std::vector<CoilCoolingDXMultiSpeedStageData> CoilCoolingDXMultiSpeed_Impl::stages() const {
std::vector<CoilCoolingDXMultiSpeedStageData> result;
auto groups = extensibleGroups();
Expand All @@ -333,10 +337,115 @@ namespace detail {
return result;
}

void CoilCoolingDXMultiSpeed_Impl::addStage(CoilCoolingDXMultiSpeedStageData& stage) {
boost::optional<unsigned> CoilCoolingDXMultiSpeed_Impl::stageIndex(const CoilCoolingDXMultiSpeedStageData& stage) const {

boost::optional<unsigned> result;

auto egs = castVector<WorkspaceExtensibleGroup>(extensibleGroups());
auto h = openstudio::toString(stage.handle());
auto it = std::find_if(egs.begin(), egs.end(),
[&](const WorkspaceExtensibleGroup& eg) {
return (eg.getField(OS_Coil_Cooling_DX_MultiSpeedExtensibleFields::Stage).get() == h);
});

// If found, we compute the index by using std::distance between the start of vector and the iterator returned by std::find_if
if (it != egs.end()) {
result = std::distance(egs.begin(), it) + 1;
}

return result;
}

bool CoilCoolingDXMultiSpeed_Impl::addStage(const CoilCoolingDXMultiSpeedStageData& stage) {
if (auto _c = stage.parentCoil()) {
if (this->handle() == _c->handle()) {
return true; // already the case
} else {
LOG(Error, "For " << briefDescription() << " cannot add " << stage.briefDescription()
<< " since this Stage is already in use by another coil ('" << _c->nameString() << "').");
return false;
}
}
auto group = getObject<ModelObject>().pushExtensibleGroup().cast<WorkspaceExtensibleGroup>();
OS_ASSERT(! group.empty());
group.setPointer(OS_Coil_Cooling_DX_MultiSpeedExtensibleFields::Stage,stage.handle());
if (group.empty()) {
LOG(Error, "You have reached the maximum number of stages (=" << numberOfStages() << "), occurred for " << briefDescription() << ".");
return false;
}
bool result = group.setPointer(OS_Coil_Cooling_DX_MultiSpeedExtensibleFields::Stage, stage.handle());
if (!result) {
// Something went wrong, so erase the new extensible group
getObject<ModelObject>().eraseExtensibleGroup(group.groupIndex());
}
return result;
}

bool CoilCoolingDXMultiSpeed_Impl::setStageIndex(const CoilCoolingDXMultiSpeedStageData& stage, unsigned index)
{
boost::optional<unsigned> idx = stageIndex(stage);
if (!idx) {
LOG(Warn, "For " << briefDescription() << " cannot set the index of stage " << stage.briefDescription() << " since it is not part of it.");
return false;
}

// TODO: we could just set via string instead of doing a ton of typechecking below...

std::vector<CoilCoolingDXMultiSpeedStageData> stageVector = stages();

if (index > stageVector.size()) {
LOG(Warn, "Requested a stage index of " << index << " to be assigned to " << stage.briefDescription() << ", but "
<< briefDescription() << " only has " << stageVector.size() << " stages, resetting to that.");
index = stageVector.size();
} else if (index < 1) {
LOG(Warn, "Requested a stage index of " << index << " < 1 to be assigned to " << stage.briefDescription() << ", resetting to 1");
index = 1;
}

stageVector.erase(stageVector.begin() + idx.get() - 1); // stageIndex is 1-indexed, and vector is 0-indexed

stageVector.insert(stageVector.begin() + (index - 1), stage);

return setStages(stageVector);
}

bool CoilCoolingDXMultiSpeed_Impl::addStage(const CoilCoolingDXMultiSpeedStageData& stage, unsigned index) {
bool ok = addStage(stage);
if (!ok) {
return false;
}
ok = setStageIndex(stage, index);
return ok;
}
bool CoilCoolingDXMultiSpeed_Impl::setStages(const std::vector<CoilCoolingDXMultiSpeedStageData>& stages) {
// Clear the extensible groups, and redo them
bool ok = true;
clearExtensibleGroups();
for (const CoilCoolingDXMultiSpeedStageData& s : stages) {
ok &= addStage(s);
}
return ok;
}

void CoilCoolingDXMultiSpeed_Impl::removeAllStages() {
clearExtensibleGroups();
}

bool CoilCoolingDXMultiSpeed_Impl::removeStage(const CoilCoolingDXMultiSpeedStageData& stage) {
boost::optional<unsigned> idx = stageIndex(stage);
if (!idx) {
LOG(Warn, "For " << briefDescription() << " cannot remove stage " << stage.briefDescription() << " since it is not part of it.");
return false;
}

return removeStage(idx.get());
}

bool CoilCoolingDXMultiSpeed_Impl::removeStage(unsigned index) {
bool result = false;
if ((index > 0) && (index <= numberOfStages())) {
getObject<ModelObject>().eraseExtensibleGroup(index-1);
result = true;
}
return result;
}

boost::optional<HVACComponent> CoilCoolingDXMultiSpeed_Impl::containingHVACComponent() const
Expand Down Expand Up @@ -524,14 +633,46 @@ bool CoilCoolingDXMultiSpeed::setMinimumOutdoorDryBulbTemperatureforCompressorOp
return getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->setMinimumOutdoorDryBulbTemperatureforCompressorOperation(minimumOutdoorDryBulbTemperatureforCompressorOperation);
}

unsigned CoilCoolingDXMultiSpeed::numberOfStages() const {
return getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->numberOfStages();
}

boost::optional<unsigned> CoilCoolingDXMultiSpeed::stageIndex(const CoilCoolingDXMultiSpeedStageData& stage) const {
return getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->stageIndex(stage);
}

std::vector<CoilCoolingDXMultiSpeedStageData> CoilCoolingDXMultiSpeed::stages() const {
return getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->stages();
}

void CoilCoolingDXMultiSpeed::addStage(CoilCoolingDXMultiSpeedStageData& stage) {
bool CoilCoolingDXMultiSpeed::addStage(const CoilCoolingDXMultiSpeedStageData& stage) {
return getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->addStage(stage);
}

bool CoilCoolingDXMultiSpeed::addStage(const CoilCoolingDXMultiSpeedStageData& stage, unsigned index) {
return getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->addStage(stage, index);
}

bool CoilCoolingDXMultiSpeed::setStageIndex(const CoilCoolingDXMultiSpeedStageData& stage, unsigned index) {
return getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->setStageIndex(stage, index);
}

bool CoilCoolingDXMultiSpeed::setStages(const std::vector<CoilCoolingDXMultiSpeedStageData>& stages) {
return getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->setStages(stages);
}

void CoilCoolingDXMultiSpeed::removeAllStages() {
getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->removeAllStages();
}

bool CoilCoolingDXMultiSpeed::removeStage(const CoilCoolingDXMultiSpeedStageData& stage) {
return getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->removeStage(stage);
}

bool CoilCoolingDXMultiSpeed::removeStage(unsigned index) {
return getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->removeStage(index);
}

AirflowNetworkEquivalentDuct CoilCoolingDXMultiSpeed::getAirflowNetworkEquivalentDuct(double length, double diameter)
{
return getImpl<detail::CoilCoolingDXMultiSpeed_Impl>()->getAirflowNetworkEquivalentDuct(length, diameter);
Expand Down
50 changes: 48 additions & 2 deletions src/model/CoilCoolingDXMultiSpeed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,54 @@ class MODEL_API CoilCoolingDXMultiSpeed : public StraightComponent {
/** Return the performance data for each stage. **/
std::vector<CoilCoolingDXMultiSpeedStageData> stages() const;

/** Add a new stage after all of the existing stages **/
void addStage(CoilCoolingDXMultiSpeedStageData& stage);
unsigned numberOfStages() const;

/*
* Get the index of a given CoilCoolingDXMultiSpeedStageData (1-indexed)
*/
boost::optional<unsigned> stageIndex(const CoilCoolingDXMultiSpeedStageData& stage) const;

/*
* Add a new stage after all of the existing stages.
*/
bool addStage(const CoilCoolingDXMultiSpeedStageData& stage);

/*
* Add a new CoilCoolingDXMultiSpeedStageData to the list which a given index (1 to x).
* Internally calls addStage then setStageIndex, see remarks there
*/
bool addStage(const CoilCoolingDXMultiSpeedStageData& stage, unsigned index);

/*
* You can shuffle the priority of a given CoilCoolingDXMultiSpeedStageData after having added it
* If index is below 1, it's reset to 1.
* If index is greater than the number of stages, will reset to last
*/
bool setStageIndex(const CoilCoolingDXMultiSpeedStageData& stage, unsigned index);

/*
* Set all stages using a list of CoilCoolingDXMultiSpeedStageDatas
* Internally calls addStage, and will return the global status, but will continue trying if there are problems
* (eg: if you make a vector larger than the number of accepted stages, or a vector that has a stage from another model, the valid stages will be
* added indeed, but it'll eventually return false)
*/
bool setStages(const std::vector<CoilCoolingDXMultiSpeedStageData>& stages);

/*
* Removes all CoilCoolingDXMultiSpeedStageDatas in this object
*/
void removeAllStages();

/*
* Remove the given CoilCoolingDXMultiSpeedStageData from this object's stages
*/
bool removeStage(const CoilCoolingDXMultiSpeedStageData& stage);

/*
* Remove the CoilCoolingDXMultiSpeedStageData at the given index (1-indexed)
*/
bool removeStage(unsigned index);


/** Creates a new equivalent duct object if an object is not already attached. */
AirflowNetworkEquivalentDuct getAirflowNetworkEquivalentDuct(double length, double diameter);
Expand Down
53 changes: 29 additions & 24 deletions src/model/CoilCoolingDXMultiSpeedStageData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "../model/CurveBiquadratic_Impl.hpp"
#include "../model/CurveQuadratic.hpp"
#include "../model/CurveQuadratic_Impl.hpp"
#include "../model/CoilCoolingDXMultiSpeed.hpp"
#include "../model/CoilCoolingDXMultiSpeed_Impl.hpp"
#include <utilities/idd/OS_Coil_Cooling_DX_MultiSpeed_StageData_FieldEnums.hxx>
#include <utilities/idd/IddEnums.hxx>
Expand Down Expand Up @@ -416,39 +417,39 @@ namespace detail {
return t_clone;
}

boost::optional<std::tuple<int, CoilCoolingDXMultiSpeed>> CoilCoolingDXMultiSpeedStageData_Impl::stageIndexAndParentCoil() const {
std::vector<IdfObject> CoilCoolingDXMultiSpeedStageData_Impl::remove() {
if (auto _coil = parentCoil()) {
_coil->removeStage(getObject<CoilCoolingDXMultiSpeedStageData>());
}
return ParentObject_Impl::remove();
}

boost::optional<std::tuple<int, CoilCoolingDXMultiSpeed>> result;

// This coil performance object can only be found in a CoilCoolingDXMultiSpeed
// Check all CoilCoolingDXMultiSpeeds in the model, seeing if this is inside of one of them.
boost::optional<int> stageIndex;
boost::optional<CoilCoolingDXMultiSpeed> parentCoil;
auto coilCoolingDXMultiSpeeds = this->model().getConcreteModelObjects<CoilCoolingDXMultiSpeed>();
for (const auto & coilInModel : coilCoolingDXMultiSpeeds) {
// Check the coil performance objects in this coil to see if one of them is this object
std::vector<CoilCoolingDXMultiSpeedStageData> perfStages = coilInModel.stages();
int i = 1;
for (auto perfStage : perfStages) {
if (perfStage.handle() == this->handle()) {
stageIndex = i;
parentCoil = coilInModel;
break;
}
i++;
}
boost::optional<CoilCoolingDXMultiSpeed> CoilCoolingDXMultiSpeedStageData_Impl::parentCoil() const {
auto coils = getObject<ModelObject>().getModelObjectSources<CoilCoolingDXMultiSpeed>(CoilCoolingDXMultiSpeed::iddObjectType());
auto count = coils.size();
if (count == 1) {
return coils[0];
} else if (count > 1) {
LOG(Error, briefDescription() << " is referenced by more than one CoilCoolingDXMultiSpeed, returning the first");
return coils[0];
}
return boost::none;
}

boost::optional<std::tuple<int, CoilCoolingDXMultiSpeed>> CoilCoolingDXMultiSpeedStageData_Impl::stageIndexAndParentCoil() const {

// Warn if this coil performance object was not found inside a coil
if (!parentCoil) {
boost::optional<std::tuple<int, CoilCoolingDXMultiSpeed>> result;

if (auto _coil = parentCoil()) {
result = std::make_tuple(_coil->stageIndex(getObject<CoilCoolingDXMultiSpeedStageData>()).get(), _coil.get());
} else {
LOG(Warn, name().get() + " was not found inside a CoilCoolingDXMultiSpeed in the model, cannot retrieve the autosized value.");
return result;
}

return std::make_tuple(stageIndex.get(), parentCoil.get());
return result;
}


boost::optional<double> CoilCoolingDXMultiSpeedStageData_Impl::autosizedGrossRatedTotalCoolingCapacity() const {
auto indexAndNameOpt = stageIndexAndParentCoil();
boost::optional<double> result;
Expand Down Expand Up @@ -906,6 +907,10 @@ CoilCoolingDXMultiSpeedStageData::CoilCoolingDXMultiSpeedStageData(std::shared_p
return getImpl<detail::CoilCoolingDXMultiSpeedStageData_Impl>()->applySizingValues();
}

boost::optional<CoilCoolingDXMultiSpeed> CoilCoolingDXMultiSpeedStageData::parentCoil() const {
return getImpl<detail::CoilCoolingDXMultiSpeedStageData_Impl>()->parentCoil();
}

boost::optional<std::tuple<int, CoilCoolingDXMultiSpeed>> CoilCoolingDXMultiSpeedStageData::stageIndexAndParentCoil() const {
return getImpl<detail::CoilCoolingDXMultiSpeedStageData_Impl>()->stageIndexAndParentCoil();
}
Expand Down
3 changes: 3 additions & 0 deletions src/model/CoilCoolingDXMultiSpeedStageData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ class MODEL_API CoilCoolingDXMultiSpeedStageData : public ParentObject {
/** @name Other */
//@{

// Returns the CoilCoolingDXMultiSpeed that references it if any
boost::optional<CoilCoolingDXMultiSpeed> parentCoil() const;

boost::optional<double> autosizedGrossRatedTotalCoolingCapacity() const ;

boost::optional<double> autosizedGrossRatedSensibleHeatRatio() const ;
Expand Down
Loading

0 comments on commit 373a625

Please sign in to comment.