Skip to content

Commit

Permalink
Merge pull request #8399 from NREL/6435_WaterStorage_Fill_Valve
Browse files Browse the repository at this point in the history
Fix #6435 - WaterUse:Storage Design Inflow Rate not respected
  • Loading branch information
mitchute authored Dec 11, 2020
2 parents de57172 + 17b1d5a commit edb5081
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 3 deletions.
7 changes: 5 additions & 2 deletions src/EnergyPlus/DataWater.hh
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ namespace DataWater {
int OverflowTankSupplyARRID;
Real64 ValveOnCapacity; // tank capacity at lower control range [m3]
Real64 ValveOffCapacity; // tank capacity at upper control range [m3]
bool LastTimeStepFilling; // Indicates that tank was filling up at last timestep, to determine whether to continue until ValveOffCapacity
ControlSupplyType ControlSupply; // mode for tank controlled resupply
int GroundWellID; // index "pointer" to well if present
std::string SupplyTankName;
Expand Down Expand Up @@ -172,8 +173,10 @@ namespace DataWater {

// Default Constructor
StorageTankDataStruct()
: MaxCapacity(0.0), OverflowMode(Overflow::Unassigned), OverflowTankID(0), OverflowTankSupplyARRID(0), ValveOnCapacity(0.0), ValveOffCapacity(0.0), ControlSupply(ControlSupplyType::Unassigned), GroundWellID(0), SupplyTankID(0), SupplyTankDemandARRID(0), BackupMainsCapacity(0.0), InitialVolume(0.0),
MaxInFlowRate(0.0), MaxOutFlowRate(0.0), ThermalMode(TankThermalMode::Unassigned), InitialTankTemp(20.0), TempSchedID(0), AmbientTempIndicator(AmbientTempType::Unassigned),
: MaxCapacity(0.0), OverflowMode(Overflow::Unassigned), OverflowTankID(0), OverflowTankSupplyARRID(0), ValveOnCapacity(0.0),
ValveOffCapacity(0.0), LastTimeStepFilling(false), ControlSupply(ControlSupplyType::Unassigned), GroundWellID(0), SupplyTankID(0),
SupplyTankDemandARRID(0), BackupMainsCapacity(0.0), InitialVolume(0.0), MaxInFlowRate(0.0), MaxOutFlowRate(0.0),
ThermalMode(TankThermalMode::Unassigned), InitialTankTemp(20.0), TempSchedID(0), AmbientTempIndicator(AmbientTempType::Unassigned),
AmbientTempSchedule(0), ZoneID(0), UValue(0.0), SurfArea(0.0), InternalMassID(0), ThisTimeStepVolume(0.0), LastTimeStepVolume(0.0),
LastTimeStepTemp(0.0), NumWaterSupplies(0), NumWaterDemands(0), VdotFromTank(0.0), VdotToTank(0.0), VdotOverflow(0.0), VolOverflow(0.0),
NetVdot(0.0), Twater(0.0), TouterSkin(0.0), TwaterOverflow(0.0), MainsDrawVdot(0.0), MainsDrawVol(0.0), SkinLossPower(0.0),
Expand Down
12 changes: 11 additions & 1 deletion src/EnergyPlus/WaterManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1049,9 +1049,14 @@ namespace WaterManager {

// is tank lower than float valve on capacity and requesting fill from controlled supplier?
FillVolRequest = 0.0;
if ((VolumePredict) < state.dataWaterData->WaterStorage(TankNum).ValveOnCapacity) { // turn on supply to fill tank

if ( ((VolumePredict) < state.dataWaterData->WaterStorage(TankNum).ValveOnCapacity) ||
state.dataWaterData->WaterStorage(TankNum).LastTimeStepFilling )
{ // turn on supply to fill tank
FillVolRequest = state.dataWaterData->WaterStorage(TankNum).ValveOffCapacity - VolumePredict;

state.dataWaterData->WaterStorage(TankNum).LastTimeStepFilling = true;

// set mains draws for float on (all the way to Float off)
if (state.dataWaterData->WaterStorage(TankNum).ControlSupply == DataWater::ControlSupplyType::MainsFloatValve) {

Expand Down Expand Up @@ -1080,6 +1085,11 @@ namespace WaterManager {
}

state.dataWaterData->WaterStorage(TankNum).ThisTimeStepVolume = state.dataWaterData->WaterStorage(TankNum).LastTimeStepVolume + NetVolAdd;
if (state.dataWaterData->WaterStorage(TankNum).ThisTimeStepVolume >= state.dataWaterData->WaterStorage(TankNum).ValveOffCapacity) {
state.dataWaterData->WaterStorage(TankNum).LastTimeStepFilling = false;
}


state.dataWaterData->WaterStorage(TankNum).VdotOverflow = overflowVol / (TimeStepSys * DataGlobalConstants::SecInHour());
state.dataWaterData->WaterStorage(TankNum).VolOverflow = overflowVol;
state.dataWaterData->WaterStorage(TankNum).TwaterOverflow = overflowTwater;
Expand Down
138 changes: 138 additions & 0 deletions tst/EnergyPlus/unit/WaterManager.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include <EnergyPlus/Data/EnergyPlusData.hh>
#include <EnergyPlus/WaterManager.hh>
#include <EnergyPlus/DataWater.hh>
#include <EnergyPlus/DataHVACGlobals.hh>
#include <EnergyPlus/ScheduleManager.hh>

#include "Fixtures/EnergyPlusFixture.hh"
Expand Down Expand Up @@ -122,3 +123,140 @@ TEST_F(EnergyPlusFixture, WaterManager_ZeroAnnualPrecipitation)
Real64 CurrentRate = state->dataWaterData->RainFall.CurrentRate;
EXPECT_NEAR(CurrentRate, 0.0, 0.000001);
}

TEST_F(EnergyPlusFixture, WaterManager_Fill)
{
// Test for #6435 : When using a Valve from a well, it should keep on filling until it hits the ValveOffCapacity instead of stopping after
// the first timestep as soon as it's over ValveOnCapacity
std::string const idf_objects = delimited_string({

"WaterUse:Storage,",
" Cooling Tower Water Storage Tank, !- Name",
" Mains, !- Water Quality Subcategory",
" 3, !- Maximum Capacity {m3}",
" 0.25, !- Initial Volume {m3}",
" 0.003, !- Design In Flow Rate {m3/s}",
" , !- Design Out Flow Rate {m3/s}",
" , !- Overflow Destination",
" GroundwaterWell, !- Type of Supply Controlled by Float Valve",
" 0.20, !- Float Valve On Capacity {m3}",
" 3, !- Float Valve Off Capacity {m3}",
" 0.10, !- Backup Mains Capacity {m3}",
" , !- Other Tank Name",
" ScheduledTemperature, !- Water Thermal Mode",
" Always 18, !- Water Temperature Schedule Name",
" , !- Ambient Temperature Indicator",
" , !- Ambient Temperature Schedule Name",
" , !- Zone Name",
" , !- Tank Surface Area {m2}",
" , !- Tank U Value {W/m2-K}",
" ; !- Tank Outside Surface Material Name",

"WaterUse:Well,",
" Cooling Tower Transfer Pumps, !- Name",
" Cooling Tower Water Storage Tank, !- Storage Tank Name",
" , !- Pump Depth {m}",
" 0.003, !- Pump Rated Flow Rate {m3/s}",
" , !- Pump Rated Head {Pa}",
" 1500, !- Pump Rated Power Consumption {W}",
" , !- Pump Efficiency",
" , !- Well Recovery Rate {m3/s}",
" , !- Nominal Well Storage Volume {m3}",
" , !- Water Table Depth Mode",
" , !- Water Table Depth {m}",
" ; !- Water Table Depth Schedule Name",

"Schedule:Constant,",
" Always 18, !- Name",
" , !- Schedule Type Limits Name",
" 18.0; !- Hourly Value",
});

ASSERT_TRUE(process_idf(idf_objects));

WaterManager::GetWaterManagerInput(*state);
state->dataWaterManager->GetInputFlag = false;

EXPECT_EQ(1u, state->dataWaterData->WaterStorage.size());
int TankNum = 1;
EXPECT_EQ(DataWater::ControlSupplyType::WellFloatMainsBackup, state->dataWaterData->WaterStorage(TankNum).ControlSupply);
EXPECT_EQ(0u, state->dataWaterData->WaterStorage(TankNum).NumWaterDemands);
EXPECT_EQ(0.003, state->dataWaterData->WaterStorage(TankNum).MaxInFlowRate);
EXPECT_EQ(0.20, state->dataWaterData->WaterStorage(TankNum).ValveOnCapacity);
EXPECT_EQ(3.0, state->dataWaterData->WaterStorage(TankNum).ValveOffCapacity);
EXPECT_EQ(3.0, state->dataWaterData->WaterStorage(TankNum).MaxCapacity);

// Initialize the tank at 0.29 m3
Real64 calcVolume = 0.26;
state->dataWaterData->WaterStorage(TankNum).LastTimeStepVolume = calcVolume;
state->dataWaterData->WaterStorage(TankNum).ThisTimeStepVolume = calcVolume;

// Simulate a call for tank water that would produce 0.025m3 of draw in one timestep
DataHVACGlobals::TimeStepSys = 10.0 / 60.0;
state->dataWaterData->WaterStorage(TankNum).NumWaterDemands = 1;
state->dataWaterData->WaterStorage(TankNum).VdotRequestDemand.allocate(1);
Real64 draw = 0.025;
state->dataWaterData->WaterStorage(TankNum).VdotRequestDemand(1) = draw / (DataHVACGlobals::TimeStepSys * DataGlobalConstants::SecInHour());


// First call, should bring predicted volume above the ValveOnCapacity
WaterManager::ManageWater(*state);
calcVolume -= draw;
EXPECT_DOUBLE_EQ(calcVolume, state->dataWaterData->WaterStorage(TankNum).ThisTimeStepVolume);
EXPECT_DOUBLE_EQ(0.235, calcVolume);
EXPECT_FALSE(state->dataWaterData->WaterStorage(TankNum).LastTimeStepFilling);

WaterManager::UpdateWaterManager(*state);

// Second call, still above the ValveOnCapacity
WaterManager::ManageWater(*state);
calcVolume -= draw;
EXPECT_DOUBLE_EQ(calcVolume, state->dataWaterData->WaterStorage(TankNum).ThisTimeStepVolume);
EXPECT_DOUBLE_EQ(0.21, calcVolume);
EXPECT_FALSE(state->dataWaterData->WaterStorage(TankNum).LastTimeStepFilling);

WaterManager::UpdateWaterManager(*state);

// Third call: Predicted volume is below ValveOnCapacity, it kicks on
WaterManager::ManageWater(*state);
calcVolume -= draw;
calcVolume += state->dataWaterData->WaterStorage(TankNum).MaxInFlowRate * (DataHVACGlobals::TimeStepSys * DataGlobalConstants::SecInHour());
EXPECT_DOUBLE_EQ(calcVolume, state->dataWaterData->WaterStorage(TankNum).ThisTimeStepVolume);
EXPECT_DOUBLE_EQ(1.985, calcVolume);
EXPECT_TRUE(state->dataWaterData->WaterStorage(TankNum).LastTimeStepFilling);


WaterManager::UpdateWaterManager(*state);

// Fourth call: it should keep on filling, until it hits ValveOffCapacity
WaterManager::ManageWater(*state);
calcVolume -= draw;
calcVolume += state->dataWaterData->WaterStorage(TankNum).MaxInFlowRate * (DataHVACGlobals::TimeStepSys * DataGlobalConstants::SecInHour());
EXPECT_DOUBLE_EQ(3.76, calcVolume);
calcVolume = min(calcVolume, state->dataWaterData->WaterStorage(TankNum).MaxCapacity);
EXPECT_DOUBLE_EQ(calcVolume, state->dataWaterData->WaterStorage(TankNum).ThisTimeStepVolume);
EXPECT_DOUBLE_EQ(3.0, calcVolume);
EXPECT_FALSE(state->dataWaterData->WaterStorage(TankNum).LastTimeStepFilling);

WaterManager::UpdateWaterManager(*state);

// Fifth Call: now it starts drawing only
WaterManager::ManageWater(*state);
calcVolume -= draw;
EXPECT_DOUBLE_EQ(calcVolume, state->dataWaterData->WaterStorage(TankNum).ThisTimeStepVolume);
EXPECT_DOUBLE_EQ(2.975, calcVolume);
EXPECT_FALSE(state->dataWaterData->WaterStorage(TankNum).LastTimeStepFilling);

WaterManager::UpdateWaterManager(*state);

// Sixth call: same.
WaterManager::ManageWater(*state);
calcVolume -= draw;
EXPECT_DOUBLE_EQ(calcVolume, state->dataWaterData->WaterStorage(TankNum).ThisTimeStepVolume);
EXPECT_DOUBLE_EQ(2.95, calcVolume);
EXPECT_FALSE(state->dataWaterData->WaterStorage(TankNum).LastTimeStepFilling);

WaterManager::UpdateWaterManager(*state);


}

5 comments on commit edb5081

@nrel-bot-3
Copy link

Choose a reason for hiding this comment

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

develop (mitchute) - x86_64-MacOS-10.15-clang-11.0.0: OK (2279 of 2279 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot-2c
Copy link

Choose a reason for hiding this comment

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

develop (mitchute) - x86_64-Linux-Ubuntu-18.04-gcc-7.5: OK (2299 of 2299 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot-2b
Copy link

Choose a reason for hiding this comment

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

develop (mitchute) - x86_64-Linux-Ubuntu-18.04-gcc-7.5-UnitTestsCoverage-Debug: OK (1561 of 1561 tests passed, 0 test warnings)

Build Badge Test Badge Coverage Badge

@nrel-bot
Copy link

Choose a reason for hiding this comment

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

develop (mitchute) - Win64-Windows-10-VisualStudio-16: OK (2252 of 2252 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot-2c
Copy link

Choose a reason for hiding this comment

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

develop (mitchute) - x86_64-Linux-Ubuntu-18.04-gcc-7.5-IntegrationCoverage-Debug: Coverage Too Low

Build Badge Test Badge Coverage Badge

Please sign in to comment.