Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BoilerHotWater: new Off Cycle Parasitic Fuel Load field #4949

Merged
merged 17 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 13 additions & 6 deletions resources/model/OpenStudio.idd
Original file line number Diff line number Diff line change
Expand Up @@ -13633,7 +13633,7 @@ OS:Boiler:HotWater,
\memo curves are generated by fitting catalog data to polynomial equations.
\memo A constant efficiency boiler may be modeled by leaving the normalized
\memo boiler efficiency curve name input blank.
\min-fields 13
\min-fields 19
A1, \field Handle
\type handle
\required-field
Expand Down Expand Up @@ -13727,22 +13727,29 @@ OS:Boiler:HotWater,
\key LeavingSetpointModulated
\key NotModulated
\default NotModulated
N8, \field Parasitic Electric Load
N8, \field On Cycle Parasitic Electric Load
\type real
\units W
\ip-units W
\ip-units W
\minimum 0.0
\default 0.0
N9, \field Sizing Factor
N9, \field Off Cycle Parasitic Fuel Load
\type real
\units W
\ip-units W
\minimum 0.0
\note parasitic fuel load when the boiler is not operating (i.e., standing pilot)
\required-field
N10,\field Sizing Factor
\note Multiplies the autosized capacity and flow rates
\type real
\minimum> 0.0
\default 1.0
A9 ; \field End-Use Subcategory
A9; \field End-Use Subcategory
\note Any text may be used here to categorize the end-uses in the ABUPS End Uses by Subcategory table.
\type alpha
\retaincase
\default General
\required-field

OS:Boiler:Steam,
\memo This boiler model is an adaptation of the empirical model from the Building
Expand Down
1 change: 1 addition & 0 deletions src/energyplus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,7 @@ set(${target_name}_test_src
Test/AvailabilityManagerLowTemperatureTurnOff_GTest.cpp
Test/AvailabilityManagerNightCycle_GTest.cpp
Test/AvailabilityManagerHybridVentilation_GTest.cpp
Test/BoilerHotWater_GTest.cpp
Test/Building_GTest.cpp
Test/ChillerElectricASHRAE205_GTest.cpp
Test/CentralHeatPumpSystem_GTest.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ namespace energyplus {
idfObject.setString(Boiler_HotWaterFields::EndUseSubcategory, s.get());
}

// OffCycleParasiticFuelLoad

if ((value = modelObject.offCycleParasiticFuelLoad())) {
idfObject.setDouble(Boiler_HotWaterFields::OffCycleParasiticFuelLoad, value.get());
}

return boost::optional<IdfObject>(idfObject);
}

Expand Down
82 changes: 82 additions & 0 deletions src/energyplus/Test/BoilerHotWater_GTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/***********************************************************************************************************************
* OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
* See also https://openstudio.net/license
***********************************************************************************************************************/

#include <gtest/gtest.h>
#include "EnergyPlusFixture.hpp"

#include "../ForwardTranslator.hpp"

#include "../../model/Model.hpp"
#include "../../model/BoilerHotWater.hpp"
#include "../../model/Node.hpp"
#include "../../model/PlantLoop.hpp"
#include "../../model/CurveQuadratic.hpp"

#include <utilities/idd/Boiler_HotWater_FieldEnums.hxx>

#include <utilities/idd/IddEnums.hxx>
#include "../../utilities/idf/IdfObject.hpp"
#include "../../utilities/idf/IdfObject_Impl.hpp"

#include "../../utilities/idf/WorkspaceObject.hpp"
#include "../../utilities/idf/WorkspaceObject_Impl.hpp"

using namespace openstudio::energyplus;
using namespace openstudio::model;
using namespace openstudio;

TEST_F(EnergyPlusFixture, ForwardTranslator_BoilerHotWater) {
Model m;

PlantLoop plant_loop(m);

BoilerHotWater bhw(m);

EXPECT_TRUE(bhw.setFuelType("Propane"));
EXPECT_TRUE(bhw.setNominalCapacity(1.0));
EXPECT_TRUE(bhw.setNominalThermalEfficiency(0.9));
EXPECT_TRUE(bhw.setEfficiencyCurveTemperatureEvaluationVariable("EnteringBoiler"));
CurveQuadratic curve1(m);
EXPECT_TRUE(bhw.setNormalizedBoilerEfficiencyCurve(curve1));
EXPECT_TRUE(bhw.setDesignWaterFlowRate(3.0));
EXPECT_TRUE(bhw.setMinimumPartLoadRatio(4.0));
EXPECT_TRUE(bhw.setMaximumPartLoadRatio(5.0));
EXPECT_TRUE(bhw.setOptimumPartLoadRatio(6.0));
EXPECT_TRUE(bhw.setWaterOutletUpperTemperatureLimit(7.0));
EXPECT_TRUE(bhw.setBoilerFlowMode("LeavingSetpointModulated"));
EXPECT_TRUE(bhw.setParasiticElectricLoad(8.0));
EXPECT_TRUE(bhw.setSizingFactor(9.0));
EXPECT_TRUE(bhw.setEndUseSubcategory("Test"));
EXPECT_TRUE(bhw.setOffCycleParasiticFuelLoad(10.0));

EXPECT_TRUE(plant_loop.addSupplyBranchForComponent(bhw));

ForwardTranslator ft;
Workspace w = ft.translateModel(m);

EXPECT_EQ(1u, w.getObjectsByType(IddObjectType::Boiler_HotWater).size());
EXPECT_EQ(1u, w.getObjectsByType(IddObjectType::Curve_Quadratic).size());

IdfObject idf_bhw = w.getObjectsByType(IddObjectType::Boiler_HotWater)[0];

EXPECT_EQ(bhw.nameString(), idf_bhw.getString(Boiler_HotWaterFields::Name, false).get());
EXPECT_EQ("Propane", idf_bhw.getString(Boiler_HotWaterFields::FuelType, false).get());
EXPECT_EQ(1.0, idf_bhw.getDouble(Boiler_HotWaterFields::NominalCapacity, false).get());
EXPECT_EQ(0.9, idf_bhw.getDouble(Boiler_HotWaterFields::NominalThermalEfficiency, false).get());
EXPECT_EQ("EnteringBoiler", idf_bhw.getString(Boiler_HotWaterFields::EfficiencyCurveTemperatureEvaluationVariable, false).get());
EXPECT_EQ(curve1.nameString(), idf_bhw.getString(Boiler_HotWaterFields::NormalizedBoilerEfficiencyCurveName, false).get());
EXPECT_EQ(3.0, idf_bhw.getDouble(Boiler_HotWaterFields::DesignWaterFlowRate, false).get());
EXPECT_EQ(4.0, idf_bhw.getDouble(Boiler_HotWaterFields::MinimumPartLoadRatio, false).get());
EXPECT_EQ(5.0, idf_bhw.getDouble(Boiler_HotWaterFields::MaximumPartLoadRatio, false).get());
EXPECT_EQ(6.0, idf_bhw.getDouble(Boiler_HotWaterFields::OptimumPartLoadRatio, false).get());
EXPECT_EQ(bhw.inletModelObject().get().nameString(), idf_bhw.getString(Boiler_HotWaterFields::BoilerWaterInletNodeName, false).get());
EXPECT_EQ(bhw.outletModelObject().get().nameString(), idf_bhw.getString(Boiler_HotWaterFields::BoilerWaterOutletNodeName, false).get());
EXPECT_EQ(7.0, idf_bhw.getDouble(Boiler_HotWaterFields::WaterOutletUpperTemperatureLimit, false).get());
EXPECT_EQ("LeavingSetpointModulated", idf_bhw.getString(Boiler_HotWaterFields::BoilerFlowMode, false).get());
EXPECT_EQ(8.0, idf_bhw.getDouble(Boiler_HotWaterFields::OnCycleParasiticElectricLoad, false).get());
EXPECT_EQ(9.0, idf_bhw.getDouble(Boiler_HotWaterFields::SizingFactor, false).get());
EXPECT_EQ("Test", idf_bhw.getString(Boiler_HotWaterFields::EndUseSubcategory, false).get());
EXPECT_EQ(10.0, idf_bhw.getDouble(Boiler_HotWaterFields::OffCycleParasiticFuelLoad, false).get());
}
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,3 @@ TEST_F(EnergyPlusFixture, ForwardTranslator_CoilCoolingWaterToAirHeatPumpVariabl
->nameString());
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ TEST_F(EnergyPlusFixture, WindowPropertyFrameAndDivider) {
EXPECT_TRUE(subSurface2.setWindowPropertyFrameAndDivider(frameAndDivider));
ASSERT_TRUE(subSurface2.windowPropertyFrameAndDivider());


ForwardTranslator forwardTranslator;
auto workspace = forwardTranslator.translateModel(model);

Expand Down
29 changes: 25 additions & 4 deletions src/model/BoilerHotWater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ namespace model {
}

boost::optional<double> BoilerHotWater_Impl::parasiticElectricLoad() const {
return getDouble(OS_Boiler_HotWaterFields::ParasiticElectricLoad, true);
return getDouble(OS_Boiler_HotWaterFields::OnCycleParasiticElectricLoad, true);
}

double BoilerHotWater_Impl::sizingFactor() const {
Expand All @@ -203,6 +203,12 @@ namespace model {
return isEmpty(OS_Boiler_HotWaterFields::SizingFactor);
}

double BoilerHotWater_Impl::offCycleParasiticFuelLoad() const {
boost::optional<double> value = getDouble(OS_Boiler_HotWaterFields::OffCycleParasiticFuelLoad, true);
OS_ASSERT(value);
return value.get();
}

bool BoilerHotWater_Impl::setFuelType(const std::string& fuelType) {
bool result = setString(OS_Boiler_HotWaterFields::FuelType, fuelType);
return result;
Expand Down Expand Up @@ -344,15 +350,15 @@ namespace model {
bool BoilerHotWater_Impl::setParasiticElectricLoad(boost::optional<double> parasiticElectricLoad) {
bool result = false;
if (parasiticElectricLoad) {
result = setDouble(OS_Boiler_HotWaterFields::ParasiticElectricLoad, parasiticElectricLoad.get());
result = setDouble(OS_Boiler_HotWaterFields::OnCycleParasiticElectricLoad, parasiticElectricLoad.get());
} else {
result = setString(OS_Boiler_HotWaterFields::ParasiticElectricLoad, "");
result = setString(OS_Boiler_HotWaterFields::OnCycleParasiticElectricLoad, "");
}
return result;
}

void BoilerHotWater_Impl::resetParasiticElectricLoad() {
bool result = setString(OS_Boiler_HotWaterFields::ParasiticElectricLoad, "");
bool result = setString(OS_Boiler_HotWaterFields::OnCycleParasiticElectricLoad, "");
OS_ASSERT(result);
}

Expand All @@ -366,6 +372,11 @@ namespace model {
OS_ASSERT(result);
}

bool BoilerHotWater_Impl::setOffCycleParasiticFuelLoad(double offCycleParasiticFuelLoad) {
bool result = setDouble(OS_Boiler_HotWaterFields::OffCycleParasiticFuelLoad, offCycleParasiticFuelLoad);
return result;
}

bool BoilerHotWater_Impl::addToNode(Node& node) {
if (boost::optional<PlantLoop> plant = node.plantLoop()) {
if (plant->supplyComponent(node.handle())) {
Expand Down Expand Up @@ -472,6 +483,8 @@ namespace model {
setSizingFactor(1.0);

setEndUseSubcategory("General");

setOffCycleParasiticFuelLoad(0.0);
joseph-robertson marked this conversation as resolved.
Show resolved Hide resolved
}

IddObjectType BoilerHotWater::iddObjectType() {
Expand Down Expand Up @@ -576,6 +589,10 @@ namespace model {
return getImpl<detail::BoilerHotWater_Impl>()->isSizingFactorDefaulted();
}

double BoilerHotWater::offCycleParasiticFuelLoad() const {
return getImpl<detail::BoilerHotWater_Impl>()->offCycleParasiticFuelLoad();
}

bool BoilerHotWater::setFuelType(const std::string& fuelType) {
return getImpl<detail::BoilerHotWater_Impl>()->setFuelType(fuelType);
}
Expand Down Expand Up @@ -688,6 +705,10 @@ namespace model {
return getImpl<detail::BoilerHotWater_Impl>()->setEndUseSubcategory(endUseSubcategory);
}

bool BoilerHotWater::setOffCycleParasiticFuelLoad(double offCycleParasiticFuelLoad) {
return getImpl<detail::BoilerHotWater_Impl>()->setOffCycleParasiticFuelLoad(offCycleParasiticFuelLoad);
}

/// @cond
BoilerHotWater::BoilerHotWater(std::shared_ptr<detail::BoilerHotWater_Impl> impl) : StraightComponent(std::move(impl)) {}
/// @endcond
Expand Down
4 changes: 4 additions & 0 deletions src/model/BoilerHotWater.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ namespace model {

std::string endUseSubcategory() const;

double offCycleParasiticFuelLoad() const;

//@}
/** @name Setters */
//@{
Expand Down Expand Up @@ -157,6 +159,8 @@ namespace model {

bool setEndUseSubcategory(const std::string& endUseSubcategory);

bool setOffCycleParasiticFuelLoad(double offCycleParasiticFuelLoad);

//@}
protected:
/// @cond
Expand Down
4 changes: 4 additions & 0 deletions src/model/BoilerHotWater_Impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ namespace model {

std::string endUseSubcategory() const;

double offCycleParasiticFuelLoad() const;

//@}
/** @name Setters */
//@{
Expand Down Expand Up @@ -168,6 +170,8 @@ namespace model {

bool setEndUseSubcategory(const std::string& endUseSubcategory);

bool setOffCycleParasiticFuelLoad(double offCycleParasiticFuelLoad);

//@}
private:
REGISTER_LOGGER("openstudio.model.BoilerHotWater");
Expand Down
14 changes: 14 additions & 0 deletions src/model/test/BoilerHotWater_GTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ TEST_F(ModelFixture, BoilerHotWater_BoilerHotWater) {
exit(0);
},
::testing::ExitedWithCode(0), "");

Model m;
BoilerHotWater boiler(m);

ASSERT_TRUE(boiler.parasiticElectricLoad());
Copy link
Collaborator

Choose a reason for hiding this comment

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

(Side note but this should never have returned an optional)

EXPECT_EQ(0.0, boiler.parasiticElectricLoad().get());
EXPECT_EQ(0.0, boiler.offCycleParasiticFuelLoad());

EXPECT_TRUE(boiler.setParasiticElectricLoad(0.5));
ASSERT_TRUE(boiler.parasiticElectricLoad());
EXPECT_EQ(0.5, boiler.parasiticElectricLoad().get());

EXPECT_TRUE(boiler.setOffCycleParasiticFuelLoad(0.8));
EXPECT_EQ(0.8, boiler.offCycleParasiticFuelLoad());
}

TEST_F(ModelFixture, BoilerHotWater_connections) {
Expand Down
23 changes: 23 additions & 0 deletions src/osversion/VersionTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8287,6 +8287,29 @@ namespace osversion {
m_refactored.push_back(RefactoredObjectData(object, newObject));
ss << newObject;

} else if (iddname == "OS:Boiler:HotWater") {

// 1 Field has been added from 3.6.1 to 3.7.0:
// -------------------------------------------
// * Off Cycle Parasitic Fuel Load * 16
auto iddObject = idd_3_7_0.getObject(iddname);
IdfObject newObject(iddObject.get());

for (size_t i = 0; i < object.numFields(); ++i) {
if ((value = object.getString(i))) {
if (i < 16) {
newObject.setString(i, value.get());
} else {
newObject.setString(i + 1, value.get());
}
}
}

newObject.setDouble(16, 0.0);

m_refactored.push_back(RefactoredObjectData(object, newObject));
ss << newObject;

// No-op
} else {
ss << object;
Expand Down
34 changes: 34 additions & 0 deletions src/osversion/test/3_7_0/test_vt_BoilerHotWater.osm
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

OS:Version,
{da82353f-7f06-44d3-9003-9db5586aec1f}, !- Handle
3.6.1; !- Version Identifier

OS:Boiler:HotWater,
{4b65bc89-fbb7-423b-8b56-bfe9ec5ebd7f}, !- Handle
Boiler Hot Water 1, !- Name
Propane, !- Fuel Type
1, !- Nominal Capacity {W}
0.9, !- Nominal Thermal Efficiency
EnteringBoiler, !- Efficiency Curve Temperature Evaluation Variable
{9f578c74-3ee0-4edc-9521-b8ae5fb65fe7}, !- Normalized Boiler Efficiency Curve Name
3, !- Design Water Flow Rate {m3/s}
4, !- Minimum Part Load Ratio
5, !- Maximum Part Load Ratio
6, !- Optimum Part Load Ratio
, !- Boiler Water Inlet Node Name
, !- Boiler Water Outlet Node Name
7, !- Water Outlet Upper Temperature Limit {C}
LeavingSetpointModulated, !- Boiler Flow Mode
8, !- Parasitic Electric Load {W}
9, !- Sizing Factor
Test; !- End-Use Subcategory

OS:Curve:Quadratic,
{9f578c74-3ee0-4edc-9521-b8ae5fb65fe7}, !- Handle
Curve Quadratic 1, !- Name
0, !- Coefficient1 Constant
0, !- Coefficient2 x
1, !- Coefficient3 x**2
0, !- Minimum Value of x
1; !- Maximum Value of x

24 changes: 24 additions & 0 deletions src/osversion/test/3_7_0/test_vt_BoilerHotWater.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#require '/usr/local/openstudio-3.6.1/Ruby/openstudio'

include OpenStudio::Model

m = Model.new

boiler = BoilerHotWater.new(m)
boiler.setFuelType("Propane")
boiler.setNominalCapacity(1.0)
boiler.setNominalThermalEfficiency(0.9)
boiler.setEfficiencyCurveTemperatureEvaluationVariable("EnteringBoiler")
curve = CurveQuadratic.new(m)
boiler.setNormalizedBoilerEfficiencyCurve(curve)
boiler.setDesignWaterFlowRate(3.0)
boiler.setMinimumPartLoadRatio(4.0)
boiler.setMaximumPartLoadRatio(5.0)
boiler.setOptimumPartLoadRatio(6.0)
boiler.setWaterOutletUpperTemperatureLimit(7.0)
boiler.setBoilerFlowMode("LeavingSetpointModulated")
boiler.setParasiticElectricLoad(8.0)
boiler.setSizingFactor(9.0)
boiler.setEndUseSubcategory("Test")

m.save('test_vt_BoilerHotWater.osm', true)
Loading