Adds tank overflow feature

This commit is contained in:
Lew Rossman
2019-06-17 09:16:04 -04:00
parent fe92a99554
commit 9669742ab3
7 changed files with 151 additions and 7 deletions

View File

@@ -61,7 +61,8 @@ typedef enum {
EN_MIXFRACTION = 22, //!< Tank mixing fraction
EN_TANK_KBULK = 23, //!< Tank bulk decay coefficient
EN_TANKVOLUME = 24, //!< Current computed tank volume (read only)
EN_MAXVOLUME = 25 //!< Tank maximum volume (read only)
EN_MAXVOLUME = 25, //!< Tank maximum volume (read only)
EN_CANOVERFLOW = 26 //!< Tank can overflow (= 1) or not (= 0)
} EN_NodeProperty;
/// Link properties

View File

@@ -1802,6 +1802,7 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType, int *index)
tank->Vcurve = 0;
tank->MixModel = 0;
tank->V1max = 10000;
tank->CanOverflow = FALSE;
}
net->Nnodes++;
p->parser.MaxNodes = net->Nnodes;
@@ -2197,6 +2198,11 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
v = tankvolume(p, index - nJuncs, NodeHead[index]) * Ucf[VOLUME];
break;
case EN_CANOVERFLOW:
if (Node[index].Type != TANK) return 0;
v = Tank[index - nJuncs].CanOverflow;
break;
default:
return 251;
}
@@ -2495,6 +2501,11 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
}
break;
case EN_CANOVERFLOW:
if (Node[index].Type != TANK) return 0;
Tank[index - nJuncs].CanOverflow = (value != 0.0);
break;
default:
return 251;
}

View File

@@ -441,7 +441,7 @@ void tankstatus(Project *pr, int k, int n1, int n2)
h = hyd->NodeHead[n1] - hyd->NodeHead[n2];
// If tank is full, then prevent flow into it
if (hyd->NodeHead[n1] >= tank->Hmax - hyd->Htol)
if (hyd->NodeHead[n1] >= tank->Hmax - hyd->Htol && !tank->CanOverflow)
{
// Case 1: Link is a pump discharging into tank
if (link->Type == PUMP)

View File

@@ -195,8 +195,10 @@ int saveinpfile(Project *pr, const char *fname)
sqrt(4.0 * tank->A / PI) * pr->Ucf[ELEV],
tank->Vmin * SQR(pr->Ucf[ELEV]) * pr->Ucf[ELEV]);
if ((j = tank->Vcurve) > 0) sprintf(s1, "%s", net->Curve[j].ID);
else if (tank->CanOverflow) strcpy(s1, "*");
else strcpy(s1, " ");
fprintf(f, "\n%s %-31s", s, s1);
if (tank->CanOverflow) fprintf(f, " YES ");
if (node->Comment) fprintf(f, " ;%s", node->Comment);
}
}

View File

@@ -138,7 +138,8 @@ int tankdata(Project *pr)
int i, // Node index
n, // # data items
pattern = 0, // Time pattern index
curve = 0; // Curve index
curve = 0, // Curve index
overflow = FALSE;// Overflow indicator
double el = 0.0, // Elevation
initlevel = 0.0, // Initial level
minlevel = 0.0, // Minimum level
@@ -185,12 +186,20 @@ int tankdata(Project *pr)
if (n >= 7 && !getfloat(parser->Tok[6], &minvol)) return setError(parser, 6, 202);
// If volume curve supplied check it exists
if (n == 8)
if (n >= 8)
{
if (strlen(parser->Tok[7]) > 0 && *(parser->Tok[7]) != '*')
{
curve = findcurve(net, parser->Tok[7]);
if (curve == 0) return setError(parser, 7, 206);
net->Curve[curve].Type = VOLUME_CURVE;
}
}
// Parse overflow indicator if present
if (n >= 9 && match(parser->Tok[8], w_YES))
overflow = TRUE;
if (initlevel < 0.0) return setError(parser, 2, 209);
if (minlevel < 0.0) return setError(parser, 3, 209);
if (maxlevel < 0.0) return setError(parser, 4, 209);
@@ -216,6 +225,7 @@ int tankdata(Project *pr)
tank->A = diam;
tank->Pat = pattern;
tank->Kb = MISSING;
tank->CanOverflow = overflow;
//*******************************************************************
// NOTE: The min, max, & initial volumes set here are based on a

View File

@@ -417,6 +417,7 @@ typedef struct // Tank Object
int Vcurve; // volume v. elev. curve index
MixType MixModel; // type of mixing model
double V1max; // mixing compartment size
int CanOverflow; // tank can overflow or not
} Stank;
typedef struct // Pump Object

119
tests/test_overflow.cpp Normal file
View File

@@ -0,0 +1,119 @@
/*
******************************************************************************
Project: OWA EPANET
Version: 2.2
Module: test_overflow.cpp
Description: Tests EPANET toolkit api functions
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 06/16/2019
******************************************************************************
*/
/*
Tests the EN_CANOVERFLOW option for Tank nodes
*/
#include <boost/test/unit_test.hpp>
#include "test_toolkit.hpp"
BOOST_AUTO_TEST_SUITE (test_overflow)
BOOST_AUTO_TEST_CASE(test_tank_overflow)
{
int error = 0;
int Nindex, Lindex;
double level, spillage, spillage2, inflow;
char testFile[] = "test_overflow.inp";
EN_Project ph = NULL;
error = EN_createproject(&ph);
error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, "");
// Get index of the tank and its inlet/outlet pipe
error = EN_getnodeindex(ph, (char *)"2", &Nindex);
BOOST_REQUIRE(error == 0);
error = EN_getlinkindex(ph, (char *)"110", &Lindex);
BOOST_REQUIRE(error == 0);
// Set initial & maximum level to 130
error = EN_setnodevalue(ph, Nindex, EN_TANKLEVEL, 130);
BOOST_REQUIRE(error == 0);
error = EN_setnodevalue(ph, Nindex, EN_MAXLEVEL, 130);
BOOST_REQUIRE(error == 0);
// Set duration to 1 hr
error = EN_settimeparam(ph, EN_DURATION, 3600);
BOOST_REQUIRE(error == 0);
// Solve hydraulics with default of no tank spillage allowed
error = EN_solveH(ph);
BOOST_REQUIRE(error == 0);
// Check that tank remains full
error = EN_getnodevalue(ph, Nindex, EN_TANKLEVEL, &level);
BOOST_REQUIRE(error == 0);
BOOST_REQUIRE(abs(level - 130.0) < 0.0001);
// Check that there is no spillage
error = EN_getnodevalue(ph, Nindex, EN_DEMAND, &spillage);
BOOST_REQUIRE(error == 0);
BOOST_REQUIRE(abs(spillage) < 0.0001);
// Check that inflow link is closed
error = EN_getlinkvalue(ph, Lindex, EN_FLOW, &inflow);
BOOST_REQUIRE(error == 0);
BOOST_REQUIRE(abs(inflow) < 0.0001);
// Turn tank overflow option on
error = EN_setnodevalue(ph, Nindex, EN_CANOVERFLOW, 1);
BOOST_REQUIRE(error == 0);
// Solve hydraulics again
error = EN_solveH(ph);
BOOST_REQUIRE(error == 0);
// Check that tank remains full
error = EN_getnodevalue(ph, Nindex, EN_TANKLEVEL, &level);
BOOST_REQUIRE(error == 0);
BOOST_REQUIRE(abs(level - 130.0) < 0.0001);
// Check that there is spillage equal to tank inflow
// (inflow has neg. sign since tank is start node of inflow pipe)
error = EN_getnodevalue(ph, Nindex, EN_DEMAND, &spillage);
BOOST_REQUIRE(error == 0);
BOOST_REQUIRE(spillage > 0.0001);
error = EN_getlinkvalue(ph, Lindex, EN_FLOW, &inflow);
BOOST_REQUIRE(error == 0);
BOOST_REQUIRE(abs(-inflow - spillage) < 0.0001);
// Save project to file and then close it
error = EN_saveinpfile(ph, testFile);
BOOST_REQUIRE(error == 0);
error = EN_close(ph);
BOOST_REQUIRE(error == 0);
// Re-open saved file & run it
error = EN_open(ph, testFile, DATA_PATH_RPT, "");
BOOST_REQUIRE(error == 0);
error = EN_solveH(ph);
BOOST_REQUIRE(error == 0);
// Check that tank spillage has same value as before
error = EN_getnodevalue(ph, Nindex, EN_DEMAND, &spillage2);
BOOST_REQUIRE(error == 0);
BOOST_REQUIRE(abs(spillage - spillage2) < 0.0001);
// Clean up
error = EN_close(ph);
BOOST_REQUIRE(error == 0);
error = EN_deleteproject(&ph);
BOOST_REQUIRE(error == 0);
}
BOOST_AUTO_TEST_SUITE_END()