New positional control valve added
This commit is contained in:
@@ -24,6 +24,7 @@ This document describes the changes and updates that have been made in version 2
|
|||||||
- dropping the check for identical status report content since it prevents accepting code changes that produce more accurate solutions in fewer iterations.
|
- dropping the check for identical status report content since it prevents accepting code changes that produce more accurate solutions in fewer iterations.
|
||||||
- A possible loss of network connectivity when evaluating a Pressure Sustaining Valve was prevented.
|
- A possible loss of network connectivity when evaluating a Pressure Sustaining Valve was prevented.
|
||||||
- Having the implied loss coefficient for an active Flow Control Valve be less than its fully opened value was prevented.
|
- Having the implied loss coefficient for an active Flow Control Valve be less than its fully opened value was prevented.
|
||||||
|
- A new type of valve, a Positional Control Valve (PCV), was added that uses a valve characteristic curve to relate its loss coefficient to its fraction open setting.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -92,9 +92,10 @@ __Remarks:__
|
|||||||
- Head v. Flow for pumps
|
- Head v. Flow for pumps
|
||||||
- Efficiency v. Flow for pumps
|
- Efficiency v. Flow for pumps
|
||||||
- Volume v. Depth for tanks
|
- Volume v. Depth for tanks
|
||||||
|
- Fraction of fully open flow v. fraction open for Positional Control Valves
|
||||||
- Head Loss v. Flow for General Purpose Valves
|
- Head Loss v. Flow for General Purpose Valves
|
||||||
2. The points of a curve must be entered in order of increasing X-values (lower to higher).
|
2. The points of a curve must be entered in order of increasing X-values (lower to higher).
|
||||||
3. If the input file will be used with the Windows version of EPANET, then adding a comment which contains the curve type and description, separated by a colon, directly above the first entry for a curve will ensure that these items appear correctly in EPANET's Curve Editor. Curve types include <B>PUMP, EFFICIENCY, VOLUME</B>, and <B>HEADLOSS</B>. See the examples below.
|
3. If the input file will be used with the Windows version of EPANET, then adding a comment which contains the curve type and description, separated by a colon, directly above the first entry for a curve will ensure that these items appear correctly in EPANET's Curve Editor. Curve types include <B>PUMP, EFFICIENCY, VOLUME, VALVE</B>, and <B>HEADLOSS</B>. See the examples below.
|
||||||
|
|
||||||
__Example:__
|
__Example:__
|
||||||
```
|
```
|
||||||
@@ -1028,7 +1029,8 @@ One line for each valve containing:
|
|||||||
- Diameter, inches (mm)
|
- Diameter, inches (mm)
|
||||||
- Valve type
|
- Valve type
|
||||||
- Valve setting
|
- Valve setting
|
||||||
- Minor loss coefficient
|
- Minor loss coefficient when fully open
|
||||||
|
- ID of valve characteristic curve (PCVs only)
|
||||||
|
|
||||||
__Remarks:__
|
__Remarks:__
|
||||||
1. Valve types and settings include:
|
1. Valve types and settings include:
|
||||||
@@ -1038,9 +1040,13 @@ __Remarks:__
|
|||||||
|<B>PSV</B> (pressure sustaining valve) | Pressure, psi (m) |
|
|<B>PSV</B> (pressure sustaining valve) | Pressure, psi (m) |
|
||||||
|<B>PBV</B> (pressure breaker valve) | Pressure, psi (m) |
|
|<B>PBV</B> (pressure breaker valve) | Pressure, psi (m) |
|
||||||
|<B>FCV</B> (flow control valve) | Flow (flow units) |
|
|<B>FCV</B> (flow control valve) | Flow (flow units) |
|
||||||
|<B>TCV</B> (throttle control valve) | Loss Coefficient |
|
|<B>TCV</B> (throttle control valve) | Partially open loss coefficient |
|
||||||
|
|<B>PCV</B> (positional control valve) | Fraction open |
|
||||||
|<B>GPV</B> (general purpose valve) | ID of head loss curve |
|
|<B>GPV</B> (general purpose valve) | ID of head loss curve |
|
||||||
2. Shutoff valves and check valves are considered to be part of a pipe, not a separate control valve component (see @ref PipesPage).
|
2. Shutoff valves and check valves are considered to be part of a pipe, not a separate control valve component (see @ref PipesPage).
|
||||||
|
3. The loss coefficient setting for a TCV should not be less than its fully open loss coefficient.
|
||||||
|
4. The characteristic curve for a PCV relates the valve's fraction of fully open flow to the fraction open.
|
||||||
|
5. The head loss curve for a GPV relates head loss across the valve to the flow rate through it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 02/01/2020
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -97,7 +97,8 @@ typedef enum {
|
|||||||
EN_PUMP_ECOST = 21, //!< Pump average energy price
|
EN_PUMP_ECOST = 21, //!< Pump average energy price
|
||||||
EN_PUMP_EPAT = 22, //!< Pump energy price time pattern index
|
EN_PUMP_EPAT = 22, //!< Pump energy price time pattern index
|
||||||
EN_LINK_INCONTROL = 23, //!< Is present in any simple or rule-based control (= 1) or not (= 0)
|
EN_LINK_INCONTROL = 23, //!< Is present in any simple or rule-based control (= 1) or not (= 0)
|
||||||
EN_GPV_CURVE = 24 //!< GPV head loss v. flow curve index
|
EN_GPV_CURVE = 24, //!< GPV head loss v. flow curve index
|
||||||
|
EN_PCV_CURVE = 25 //!< PCV loss coeff. curve index
|
||||||
} EN_LinkProperty;
|
} EN_LinkProperty;
|
||||||
|
|
||||||
/// Time parameters
|
/// Time parameters
|
||||||
@@ -191,7 +192,8 @@ typedef enum {
|
|||||||
EN_PBV = 5, //!< Pressure breaker valve
|
EN_PBV = 5, //!< Pressure breaker valve
|
||||||
EN_FCV = 6, //!< Flow control valve
|
EN_FCV = 6, //!< Flow control valve
|
||||||
EN_TCV = 7, //!< Throttle control valve
|
EN_TCV = 7, //!< Throttle control valve
|
||||||
EN_GPV = 8 //!< General purpose valve
|
EN_GPV = 8, //!< General purpose valve
|
||||||
|
EN_PCV = 9 //!< Positional control valve
|
||||||
} EN_LinkType;
|
} EN_LinkType;
|
||||||
|
|
||||||
/// Link status
|
/// Link status
|
||||||
@@ -397,7 +399,8 @@ typedef enum {
|
|||||||
EN_PUMP_CURVE = 1, //!< Pump head v. flow curve
|
EN_PUMP_CURVE = 1, //!< Pump head v. flow curve
|
||||||
EN_EFFIC_CURVE = 2, //!< Pump efficiency v. flow curve
|
EN_EFFIC_CURVE = 2, //!< Pump efficiency v. flow curve
|
||||||
EN_HLOSS_CURVE = 3, //!< Valve head loss v. flow curve
|
EN_HLOSS_CURVE = 3, //!< Valve head loss v. flow curve
|
||||||
EN_GENERIC_CURVE = 4 //!< Generic curve
|
EN_GENERIC_CURVE = 4, //!< Generic curve
|
||||||
|
EN_VALVE_CURVE = 5 //!< Valve loss coeff. v. frac. open
|
||||||
} EN_CurveType;
|
} EN_CurveType;
|
||||||
|
|
||||||
/// Deletion action codes
|
/// Deletion action codes
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 06/20/2019
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -27,7 +27,8 @@ char *LinkTxt[] = {w_CV,
|
|||||||
w_PBV,
|
w_PBV,
|
||||||
w_FCV,
|
w_FCV,
|
||||||
w_TCV,
|
w_TCV,
|
||||||
w_GPV};
|
w_GPV,
|
||||||
|
w_PCV};
|
||||||
|
|
||||||
char *StatTxt[] = {t_XHEAD,
|
char *StatTxt[] = {t_XHEAD,
|
||||||
t_TEMPCLOSED,
|
t_TEMPCLOSED,
|
||||||
|
|||||||
24
src/epanet.c
24
src/epanet.c
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 11/08/2020
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -3149,7 +3149,7 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, int linkType,
|
|||||||
if (EN_getlinkindex(p, id, &i) == 0) return 215;
|
if (EN_getlinkindex(p, id, &i) == 0) return 215;
|
||||||
|
|
||||||
// Check for valid link type
|
// Check for valid link type
|
||||||
if (linkType < CVPIPE || linkType > GPV) return 251;
|
if (linkType < CVPIPE || linkType > PCV) return 251;
|
||||||
|
|
||||||
// Lookup the link's from and to nodes
|
// Lookup the link's from and to nodes
|
||||||
n1 = hashtable_find(net->NodeHashTable, fromNode);
|
n1 = hashtable_find(net->NodeHashTable, fromNode);
|
||||||
@@ -3209,6 +3209,7 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, int linkType,
|
|||||||
size = (net->Nvalves + 1) * sizeof(Svalve);
|
size = (net->Nvalves + 1) * sizeof(Svalve);
|
||||||
net->Valve = (Svalve *)realloc(net->Valve, size);
|
net->Valve = (Svalve *)realloc(net->Valve, size);
|
||||||
net->Valve[net->Nvalves].Link = n;
|
net->Valve[net->Nvalves].Link = n;
|
||||||
|
net->Valve[net->Nvalves].Curve = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
link->Type = linkType;
|
link->Type = linkType;
|
||||||
@@ -3468,7 +3469,7 @@ int DLLEXPORT EN_setlinktype(EN_Project p, int *index, int linkType, int actionC
|
|||||||
if (p->hydraul.OpenHflag || p->quality.OpenQflag) return 262;
|
if (p->hydraul.OpenHflag || p->quality.OpenQflag) return 262;
|
||||||
|
|
||||||
// Check for valid input parameters
|
// Check for valid input parameters
|
||||||
if (linkType < 0 || linkType > GPV || actionCode < EN_UNCONDITIONAL ||
|
if (linkType < 0 || linkType > PCV || actionCode < EN_UNCONDITIONAL ||
|
||||||
actionCode > EN_CONDITIONAL)
|
actionCode > EN_CONDITIONAL)
|
||||||
{
|
{
|
||||||
return 251;
|
return 251;
|
||||||
@@ -3794,6 +3795,13 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EN_PCV_CURVE:
|
||||||
|
if (Link[index].Type == PCV)
|
||||||
|
{
|
||||||
|
v = net->Valve[findvalve(&p->network, index)].Curve;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case EN_GPV_CURVE:
|
case EN_GPV_CURVE:
|
||||||
if (Link[index].Type == GPV)
|
if (Link[index].Type == GPV)
|
||||||
{
|
{
|
||||||
@@ -3916,6 +3924,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
|
|||||||
value /= Ucf[FLOW];
|
value /= Ucf[FLOW];
|
||||||
break;
|
break;
|
||||||
case TCV:
|
case TCV:
|
||||||
|
case PCV:
|
||||||
break;
|
break;
|
||||||
case GPV:
|
case GPV:
|
||||||
return 207; // Cannot modify setting for GPV
|
return 207; // Cannot modify setting for GPV
|
||||||
@@ -4012,6 +4021,15 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EN_PCV_CURVE:
|
||||||
|
if (Link[index].Type == PCV)
|
||||||
|
{
|
||||||
|
curveIndex = ROUND(value);
|
||||||
|
if (curveIndex < 0 || curveIndex > net->Ncurves) return 206;
|
||||||
|
net->Valve[findvalve(&p->network, index)].Curve = curveIndex;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case EN_GPV_CURVE:
|
case EN_GPV_CURVE:
|
||||||
if (Link[index].Type == GPV)
|
if (Link[index].Type == GPV)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 02/03/2020
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
#ifndef FUNCS_H
|
#ifndef FUNCS_H
|
||||||
@@ -166,6 +166,7 @@ void headlosscoeffs(Project *);
|
|||||||
void matrixcoeffs(Project *);
|
void matrixcoeffs(Project *);
|
||||||
void emitterheadloss(Project *, int, double *, double *);
|
void emitterheadloss(Project *, int, double *, double *);
|
||||||
void demandheadloss(Project *, int, double, double, double *, double *);
|
void demandheadloss(Project *, int, double, double, double *, double *);
|
||||||
|
double pcvlosscoeff(Project *, int, double);
|
||||||
|
|
||||||
// ------- QUALITY.C --------------------
|
// ------- QUALITY.C --------------------
|
||||||
|
|
||||||
|
|||||||
121
src/hydcoeffs.c
121
src/hydcoeffs.c
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 03/30/2022
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -36,6 +36,7 @@ const double CBIG = 1.e8;
|
|||||||
|
|
||||||
// Exported functions
|
// Exported functions
|
||||||
//void resistcoeff(Project *, int );
|
//void resistcoeff(Project *, int );
|
||||||
|
//double pcvlosscoeff(Project *, int, double);
|
||||||
//void headlosscoeffs(Project *);
|
//void headlosscoeffs(Project *);
|
||||||
//void matrixcoeffs(Project *);
|
//void matrixcoeffs(Project *);
|
||||||
//void emitterheadloss(Project *, int, double *, double *);
|
//void emitterheadloss(Project *, int, double *, double *);
|
||||||
@@ -59,6 +60,7 @@ static void valvecoeff(Project *pr, int k);
|
|||||||
static void gpvcoeff(Project *pr, int k);
|
static void gpvcoeff(Project *pr, int k);
|
||||||
static void pbvcoeff(Project *pr, int k);
|
static void pbvcoeff(Project *pr, int k);
|
||||||
static void tcvcoeff(Project *pr, int k);
|
static void tcvcoeff(Project *pr, int k);
|
||||||
|
static void pcvcoeff(Project *pr, int k);
|
||||||
static void prvcoeff(Project *pr, int k, int n1, int n2);
|
static void prvcoeff(Project *pr, int k, int n1, int n2);
|
||||||
static void psvcoeff(Project *pr, int k, int n1, int n2);
|
static void psvcoeff(Project *pr, int k, int n1, int n2);
|
||||||
static void fcvcoeff(Project *pr, int k, int n1, int n2);
|
static void fcvcoeff(Project *pr, int k, int n1, int n2);
|
||||||
@@ -107,6 +109,10 @@ void resistcoeff(Project *pr, int k)
|
|||||||
case PUMP:
|
case PUMP:
|
||||||
link->R = CBIG;
|
link->R = CBIG;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PCV:
|
||||||
|
link->R = pcvlosscoeff(pr, k, link->Kc);
|
||||||
|
break;
|
||||||
|
|
||||||
// ... For all other links (e.g. valves) use a small resistance
|
// ... For all other links (e.g. valves) use a small resistance
|
||||||
default:
|
default:
|
||||||
@@ -116,6 +122,86 @@ void resistcoeff(Project *pr, int k)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double pcvlosscoeff(Project* pr, int k, double s)
|
||||||
|
/*
|
||||||
|
**--------------------------------------------------------------
|
||||||
|
** Input: k = link index
|
||||||
|
** s = valve fraction open setting
|
||||||
|
** Output: returns a valve loss coefficient
|
||||||
|
** Purpose: finds a Positional Control Valve's loss
|
||||||
|
** coefficient from its fraction open setting.
|
||||||
|
**--------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Network* net = &pr->network;
|
||||||
|
|
||||||
|
int v = findvalve(net, k); // valve index
|
||||||
|
int c = net->Valve[v].Curve; // Kv curve index
|
||||||
|
double d; // valve diameter
|
||||||
|
double kmo; // fully open loss coeff.
|
||||||
|
double km; // partly open loss coeff.
|
||||||
|
double kvr; // Kv / Kvo (Kvo = Kv at fully open)
|
||||||
|
double *x, *y; // points on kvr v. frac. open curve
|
||||||
|
int k1, k2, npts;
|
||||||
|
Scurve *curve;
|
||||||
|
|
||||||
|
// Valve has no setting so return 0
|
||||||
|
if (s == MISSING) return 0.0;
|
||||||
|
|
||||||
|
// Valve is completely open so return its Km value
|
||||||
|
d = net->Link[k].Diam;
|
||||||
|
kmo = net->Link[k].Km;
|
||||||
|
if (s >= 1.0) return kmo;
|
||||||
|
|
||||||
|
// Valve is completely closed so return a large coeff.
|
||||||
|
if (s <= 0.0) return CBIG;
|
||||||
|
|
||||||
|
// Valve has no assigned curve so assume a linear one
|
||||||
|
if (c == 0) kvr = s;
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Valve curve data
|
||||||
|
curve = &net->Curve[c];
|
||||||
|
npts = curve->Npts;
|
||||||
|
x = curve->X; // x = frac. open
|
||||||
|
y = curve->Y; // y = Kv / Kvo
|
||||||
|
|
||||||
|
// s lies below first point of curve
|
||||||
|
if (s < x[0])
|
||||||
|
kvr = s / x[0] * y[0];
|
||||||
|
|
||||||
|
// s lies above last point of curve
|
||||||
|
else if (s > x[npts-1])
|
||||||
|
{
|
||||||
|
k2 = npts - 1;
|
||||||
|
kvr = (s - x[k2]) / (1. - x[k2]) * (1. - y[k2]) + y[k2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise interpolate over curve segment that brackets s
|
||||||
|
else
|
||||||
|
{
|
||||||
|
k2 = 0;
|
||||||
|
while (k2 < npts && x[k2] < s) k2++;
|
||||||
|
if (k2 == 0) k2++;
|
||||||
|
else if (k2 == npts) k2--;
|
||||||
|
k1 = k2 - 1;
|
||||||
|
kvr = (y[k2] - y[k1]) / (x[k2] - x[k1]);
|
||||||
|
kvr = y[k1] + kvr * (s - x[k1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// kvr can't be > 1 or <= 0
|
||||||
|
kvr = MIN(kvr, 1.0);
|
||||||
|
kvr = MAX(kvr, CSMALL);
|
||||||
|
|
||||||
|
// Convert from Kv ratio to minor loss coeff.
|
||||||
|
km = kmo / (kvr * kvr);
|
||||||
|
km = MIN(km, CBIG);
|
||||||
|
return km;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void headlosscoeffs(Project *pr)
|
void headlosscoeffs(Project *pr)
|
||||||
/*
|
/*
|
||||||
**--------------------------------------------------------------
|
**--------------------------------------------------------------
|
||||||
@@ -148,6 +234,9 @@ void headlosscoeffs(Project *pr)
|
|||||||
case TCV:
|
case TCV:
|
||||||
tcvcoeff(pr, k);
|
tcvcoeff(pr, k);
|
||||||
break;
|
break;
|
||||||
|
case PCV:
|
||||||
|
pcvcoeff(pr, k);
|
||||||
|
break;
|
||||||
case GPV:
|
case GPV:
|
||||||
gpvcoeff(pr, k);
|
gpvcoeff(pr, k);
|
||||||
break;
|
break;
|
||||||
@@ -945,6 +1034,36 @@ void tcvcoeff(Project *pr, int k)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void pcvcoeff(Project *pr, int k)
|
||||||
|
/*
|
||||||
|
**--------------------------------------------------------------
|
||||||
|
** Input: k = link index
|
||||||
|
** Output: none
|
||||||
|
** Purpose: computes P & Y coeffs. for positional control valve
|
||||||
|
**--------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
double km;
|
||||||
|
Hydraul *hyd = &pr->hydraul;
|
||||||
|
Slink *link = &pr->network.Link[k];
|
||||||
|
|
||||||
|
// Save original loss coeff. for open valve
|
||||||
|
km = link->Km;
|
||||||
|
|
||||||
|
// If valve not fixed OPEN or CLOSED, compute its loss coeff.
|
||||||
|
if (hyd->LinkSetting[k] != MISSING)
|
||||||
|
{
|
||||||
|
link->Km = link->R;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then apply usual valve formula
|
||||||
|
valvecoeff(pr, k);
|
||||||
|
|
||||||
|
// Restore original loss coeff.
|
||||||
|
link->Km = km;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void prvcoeff(Project *pr, int k, int n1, int n2)
|
void prvcoeff(Project *pr, int k, int n1, int n2)
|
||||||
/*
|
/*
|
||||||
**--------------------------------------------------------------
|
**--------------------------------------------------------------
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 03/19/2022
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -450,6 +450,7 @@ void setlinksetting(Project *pr, int index, double value, StatusType *s,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (*k == MISSING && *s <= CLOSED) *s = OPEN;
|
if (*k == MISSING && *s <= CLOSED) *s = OPEN;
|
||||||
|
if (t == PCV) link->R = pcvlosscoeff(pr, index, link->Kc);
|
||||||
*k = value;
|
*k = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -605,6 +606,7 @@ int controls(Project *pr)
|
|||||||
{
|
{
|
||||||
hyd->LinkStatus[k] = s2;
|
hyd->LinkStatus[k] = s2;
|
||||||
hyd->LinkSetting[k] = k2;
|
hyd->LinkSetting[k] = k2;
|
||||||
|
if (link->Type == PCV) link->R = pcvlosscoeff(pr, k, k2);
|
||||||
if (pr->report.Statflag) writecontrolaction(pr,k,i);
|
if (pr->report.Statflag) writecontrolaction(pr,k,i);
|
||||||
setsum++;
|
setsum++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Description: saves network data to an EPANET formatted text file
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 10/29/2019
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -312,6 +312,11 @@ int saveinpfile(Project *pr, const char *fname)
|
|||||||
{
|
{
|
||||||
sprintf(s1, "%-31s %12.4f", net->Curve[j].ID, km);
|
sprintf(s1, "%-31s %12.4f", net->Curve[j].ID, km);
|
||||||
}
|
}
|
||||||
|
// For PCV add loss curve if present
|
||||||
|
else if (link->Type == PCV && (j = net->Valve[i].Curve) > 0)
|
||||||
|
{
|
||||||
|
sprintf(s1, "%12.4f %12.4f %-31s", kc, km, net->Curve[j].ID);
|
||||||
|
}
|
||||||
else sprintf(s1, "%12.4f %12.4f", kc, km);
|
else sprintf(s1, "%12.4f %12.4f", kc, km);
|
||||||
fprintf(f, "\n%s %s", s, s1);
|
fprintf(f, "\n%s %s", s, s1);
|
||||||
if (link->Comment) fprintf(f, " ;%s", link->Comment);
|
if (link->Comment) fprintf(f, " ;%s", link->Comment);
|
||||||
|
|||||||
20
src/input3.c
20
src/input3.c
@@ -7,7 +7,7 @@ Description: parses network data from a line of an EPANET input file
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 03/20/2022
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -471,7 +471,7 @@ int valvedata(Project *pr)
|
|||||||
** Purpose: processes valve data
|
** Purpose: processes valve data
|
||||||
** Format:
|
** Format:
|
||||||
** [VALVE]
|
** [VALVE]
|
||||||
** id node1 node2 diam type setting (lcoeff)
|
** id node1 node2 diam type setting (lcoeff lcurve)
|
||||||
**--------------------------------------------------------------
|
**--------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
@@ -488,7 +488,8 @@ int valvedata(Project *pr)
|
|||||||
setting, // Valve setting
|
setting, // Valve setting
|
||||||
lcoeff = 0.0; // Minor loss coeff.
|
lcoeff = 0.0; // Minor loss coeff.
|
||||||
Slink *link;
|
Slink *link;
|
||||||
int err = 0;
|
int err = 0,
|
||||||
|
losscurve = 0; // Loss coeff. curve
|
||||||
|
|
||||||
// Add new valve to data base
|
// Add new valve to data base
|
||||||
n = parser->Ntokens;
|
n = parser->Ntokens;
|
||||||
@@ -521,6 +522,8 @@ int valvedata(Project *pr)
|
|||||||
type = TCV;
|
type = TCV;
|
||||||
else if (match(parser->Tok[4], w_GPV))
|
else if (match(parser->Tok[4], w_GPV))
|
||||||
type = GPV;
|
type = GPV;
|
||||||
|
else if (match(parser->Tok[4], w_PCV))
|
||||||
|
type = PCV;
|
||||||
else
|
else
|
||||||
return setError(parser, 4, 213);
|
return setError(parser, 4, 213);
|
||||||
|
|
||||||
@@ -538,6 +541,16 @@ int valvedata(Project *pr)
|
|||||||
}
|
}
|
||||||
else if (!getfloat(parser->Tok[5], &setting)) return setError(parser, 5, 202);
|
else if (!getfloat(parser->Tok[5], &setting)) return setError(parser, 5, 202);
|
||||||
if (n >= 7 && !getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202);
|
if (n >= 7 && !getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202);
|
||||||
|
|
||||||
|
// Find loss coeff. curve for PCV
|
||||||
|
if (type == PCV && n >= 8)
|
||||||
|
{
|
||||||
|
c = findcurve(net, parser->Tok[7]);
|
||||||
|
if (c == 0) return setError(parser, 7, 206);
|
||||||
|
losscurve = c;
|
||||||
|
net->Curve[c].Type = VALVE_CURVE;
|
||||||
|
if (setting > 1.0) setting = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for illegal connections
|
// Check for illegal connections
|
||||||
if (valvecheck(pr, net->Nlinks, type, j1, j2))
|
if (valvecheck(pr, net->Nlinks, type, j1, j2))
|
||||||
@@ -563,6 +576,7 @@ int valvedata(Project *pr)
|
|||||||
link->ResultIndex = 0;
|
link->ResultIndex = 0;
|
||||||
link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
|
link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
|
||||||
net->Valve[net->Nvalves].Link = net->Nlinks;
|
net->Valve[net->Nvalves].Link = net->Nlinks;
|
||||||
|
net->Valve[net->Nvalves].Curve = losscurve;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Description: binary file read/write routines
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 05/13/2019
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -567,6 +567,7 @@ int linkoutput(Project *pr, int j, REAL4 *x, double ucf)
|
|||||||
case FCV:
|
case FCV:
|
||||||
x[i] = (REAL4)(setting * pr->Ucf[FLOW]); break;
|
x[i] = (REAL4)(setting * pr->Ucf[FLOW]); break;
|
||||||
case TCV:
|
case TCV:
|
||||||
|
case PCV:
|
||||||
x[i] = (REAL4)setting; break;
|
x[i] = (REAL4)setting; break;
|
||||||
default: x[i] = 0.0f;
|
default: x[i] = 0.0f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 02/03/2020
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -860,7 +860,7 @@ int findtank(Network *network, int index)
|
|||||||
/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
||||||
** Input: index = node index
|
** Input: index = node index
|
||||||
** Output: none
|
** Output: none
|
||||||
** Returns: index of tank with given node id, or NOTFOUND if tank not found
|
** Returns: index of tank with given node index, or NOTFOUND if tank not found
|
||||||
** Purpose: for use in the deletenode function
|
** Purpose: for use in the deletenode function
|
||||||
**----------------------------------------------------------------
|
**----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -877,7 +877,7 @@ int findpump(Network *network, int index)
|
|||||||
/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
||||||
** Input: index = link ID
|
** Input: index = link ID
|
||||||
** Output: none
|
** Output: none
|
||||||
** Returns: index of pump with given link id, or NOTFOUND if pump not found
|
** Returns: index of pump with given link index, or NOTFOUND if pump not found
|
||||||
** Purpose: for use in the deletelink function
|
** Purpose: for use in the deletelink function
|
||||||
**----------------------------------------------------------------
|
**----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -894,7 +894,7 @@ int findvalve(Network *network, int index)
|
|||||||
/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
||||||
** Input: index = link ID
|
** Input: index = link ID
|
||||||
** Output: none
|
** Output: none
|
||||||
** Returns: index of valve with given link id, or NOTFOUND if valve not found
|
** Returns: index of valve with given link index, or NOTFOUND if valve not found
|
||||||
** Purpose: for use in the deletelink function
|
** Purpose: for use in the deletelink function
|
||||||
**----------------------------------------------------------------
|
**----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -1010,7 +1010,7 @@ void adjustcurves(Network *network, int index)
|
|||||||
**----------------------------------------------------------------
|
**----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int j, k, setting;
|
int j, k, curve;
|
||||||
|
|
||||||
// Adjust tank volume curves
|
// Adjust tank volume curves
|
||||||
for (j = 1; j <= network->Ntanks; j++)
|
for (j = 1; j <= network->Ntanks; j++)
|
||||||
@@ -1025,15 +1025,25 @@ void adjustcurves(Network *network, int index)
|
|||||||
adjustcurve(&network->Pump[j].Ecurve, index);
|
adjustcurve(&network->Pump[j].Ecurve, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust GPV curves
|
// Adjust PCV & GPV curves
|
||||||
for (j = 1; j <= network->Nvalves; j++)
|
for (j = 1; j <= network->Nvalves; j++)
|
||||||
{
|
{
|
||||||
k = network->Valve[j].Link;
|
k = network->Valve[j].Link;
|
||||||
|
if (network->Link[k].Type == PCV)
|
||||||
|
{
|
||||||
|
if ((curve = network->Valve[j].Curve) > 0)
|
||||||
|
{
|
||||||
|
adjustcurve(&curve, index);
|
||||||
|
network->Valve[j].Curve = curve;
|
||||||
|
if (curve == 0)
|
||||||
|
network->Link[k].Kc = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (network->Link[k].Type == GPV)
|
if (network->Link[k].Type == GPV)
|
||||||
{
|
{
|
||||||
setting = INT(network->Link[k].Kc);
|
curve = INT(network->Link[k].Kc);
|
||||||
adjustcurve(&setting, index);
|
adjustcurve(&curve, index);
|
||||||
network->Link[k].Kc = setting;
|
network->Link[k].Kc = curve;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 07/15/2019
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
#define w_FCV "FCV"
|
#define w_FCV "FCV"
|
||||||
#define w_TCV "TCV"
|
#define w_TCV "TCV"
|
||||||
#define w_GPV "GPV"
|
#define w_GPV "GPV"
|
||||||
|
#define w_PCV "PCV"
|
||||||
|
|
||||||
#define w_OPEN "OPEN"
|
#define w_OPEN "OPEN"
|
||||||
#define w_CLOSED "CLOSED"
|
#define w_CLOSED "CLOSED"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 07/11/2020
|
Last Updated: 08/13/2022
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -145,7 +145,8 @@ typedef enum {
|
|||||||
PBV, // pressure breaker valve
|
PBV, // pressure breaker valve
|
||||||
FCV, // flow control valve
|
FCV, // flow control valve
|
||||||
TCV, // throttle control valve
|
TCV, // throttle control valve
|
||||||
GPV // general purpose valve
|
GPV, // general purpose valve
|
||||||
|
PCV // positional control valve
|
||||||
} LinkType;
|
} LinkType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -166,7 +167,8 @@ typedef enum {
|
|||||||
PUMP_CURVE, // pump curve
|
PUMP_CURVE, // pump curve
|
||||||
EFFIC_CURVE, // efficiency curve
|
EFFIC_CURVE, // efficiency curve
|
||||||
HLOSS_CURVE, // head loss curve
|
HLOSS_CURVE, // head loss curve
|
||||||
GENERIC_CURVE // generic curve
|
GENERIC_CURVE, // generic curve
|
||||||
|
VALVE_CURVE // positional valve loss curve
|
||||||
} CurveType;
|
} CurveType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -455,6 +457,7 @@ typedef struct // Pump Object
|
|||||||
typedef struct // Valve Object
|
typedef struct // Valve Object
|
||||||
{
|
{
|
||||||
int Link; // link index of valve
|
int Link; // link index of valve
|
||||||
|
int Curve; // positional loss coeff. curve
|
||||||
} Svalve;
|
} Svalve;
|
||||||
|
|
||||||
typedef struct // Control Statement
|
typedef struct // Control Statement
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ set(toolkit_test_srcs
|
|||||||
test_control.cpp
|
test_control.cpp
|
||||||
test_overflow.cpp
|
test_overflow.cpp
|
||||||
test_pda.cpp
|
test_pda.cpp
|
||||||
|
test_valve.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(test_toolkit ${toolkit_test_srcs})
|
add_executable(test_toolkit ${toolkit_test_srcs})
|
||||||
|
|||||||
73
tests/test_valve.cpp
Normal file
73
tests/test_valve.cpp
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
******************************************************************************
|
||||||
|
Project: OWA EPANET
|
||||||
|
Version: 2.2
|
||||||
|
Module: test_valve.cpp
|
||||||
|
Description: Tests EPANET toolkit api functions
|
||||||
|
Authors: see AUTHORS
|
||||||
|
Copyright: see AUTHORS
|
||||||
|
License: see LICENSE
|
||||||
|
Last Updated: 07/28/2022
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Tests PCV valve with position curve
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include "test_toolkit.hpp"
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE (test_valve)
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(test_PCV_valve, FixtureOpenClose)
|
||||||
|
|
||||||
|
{
|
||||||
|
int npts = 5;
|
||||||
|
double x[] = { 0.0, 0.25, 0.5, 0.75, 1. };
|
||||||
|
double y[] = {0.0, 0.089, 0.184, 0.406, 1.0};
|
||||||
|
double v;
|
||||||
|
int linkIndex, curveIndex;
|
||||||
|
|
||||||
|
// Make steady state run
|
||||||
|
error = EN_settimeparam(ph, EN_DURATION, 0);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
// Convert pipe 22 to a PCV
|
||||||
|
error = EN_getlinkindex(ph, (char*)"22", &linkIndex);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_setlinktype(ph, &linkIndex, EN_PCV, EN_UNCONDITIONAL);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_setlinkvalue(ph, linkIndex, EN_DIAMETER, 12);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_setlinkvalue(ph, linkIndex, EN_MINORLOSS, 0.19);
|
||||||
|
|
||||||
|
// Create the PCV's position-loss curve
|
||||||
|
error = EN_addcurve(ph, (char*)"ValveCurve");
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getcurveindex(ph, (char*)"ValveCurve", &curveIndex);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_setcurve(ph, curveIndex, x, y, npts);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
// Assign curve & initial setting to PCV
|
||||||
|
error = EN_setlinkvalue(ph, linkIndex, EN_PCV_CURVE, curveIndex);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_setlinkvalue(ph, linkIndex, EN_INITSETTING, 0.35);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
// Solve for hydraulics
|
||||||
|
error = EN_solveH(ph);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
// The PCV interpolated relative flow coeff. at 0.35 open is 0.127.
|
||||||
|
// This translates to a minor loss coeff. of 0.19 / 0.127^2 = 11.78.
|
||||||
|
// If the PCV were replaced with a TCV at that setting the resulting
|
||||||
|
// head loss would be 0.0255 ft which should equal the PCV result.
|
||||||
|
error = EN_getlinkvalue(ph, linkIndex, EN_HEADLOSS, &v);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_REQUIRE(abs(v - 0.0255) < 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
Reference in New Issue
Block a user