diff --git a/ReleaseNotes2_3.md b/ReleaseNotes2_3.md index 7042988..5a3b2d3 100644 --- a/ReleaseNotes2_3.md +++ b/ReleaseNotes2_3.md @@ -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. - 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. + - 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. diff --git a/doc/input-file.dox b/doc/input-file.dox index 8bbe5c1..f4d36ce 100644 --- a/doc/input-file.dox +++ b/doc/input-file.dox @@ -92,9 +92,10 @@ __Remarks:__ - Head v. Flow for pumps - Efficiency v. Flow for pumps - 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 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 PUMP, EFFICIENCY, VOLUME, and HEADLOSS. 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 PUMP, EFFICIENCY, VOLUME, VALVE, and HEADLOSS. See the examples below. __Example:__ ``` @@ -1028,7 +1029,8 @@ One line for each valve containing: - Diameter, inches (mm) - Valve type - Valve setting -- Minor loss coefficient +- Minor loss coefficient when fully open +- ID of valve characteristic curve (PCVs only) __Remarks:__ 1. Valve types and settings include: @@ -1038,9 +1040,14 @@ __Remarks:__ |PSV (pressure sustaining valve) | Pressure, psi (m) | |PBV (pressure breaker valve) | Pressure, psi (m) | |FCV (flow control valve) | Flow (flow units) | -|TCV (throttle control valve) | Loss Coefficient | +|TCV (throttle control valve) | Partially open loss coefficient | +|PCV (positional control valve) | Fraction open | |GPV (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). +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. If not supplied then a linear curve is assumed. +5. The partially opened loss coefficient for a PCV is the inverse of the squared value from its characteristic curve times the fully open loss coefficient. +6. The head loss curve for a GPV relates head loss across the valve to the flow rate through it. */ /** diff --git a/include/epanet.cs b/include/epanet.cs index 2cec376..68489e6 100644 --- a/include/epanet.cs +++ b/include/epanet.cs @@ -73,6 +73,9 @@ namespace EpanetCSharpLibrary public const int EN_PUMP_ECURVE = 20; public const int EN_PUMP_ECOST = 21; public const int EN_PUMP_EPAT = 22; + public const int EN_LINK_INCONTROL = 23; + public const int EN_GPV_CURVE = 24; + public const int EN_PCV_CURVE = 25; public const int EN_DURATION = 0; //Time parameters public const int EN_HYDSTEP = 1; @@ -126,6 +129,7 @@ namespace EpanetCSharpLibrary public const int EN_FCV = 6; public const int EN_TCV = 7; public const int EN_GPV = 8; + public const int EN_PCV = 9; public const int EN_NONE = 0; //Quality analysis types public const int EN_CHEM = 1; @@ -209,6 +213,7 @@ namespace EpanetCSharpLibrary public const int EN_EFFIC_CURVE = 2; //Efficiency curve public const int EN_HLOSS_CURVE = 3; //Head loss curve public const int EN_GENERIC_CURVE = 4; //Generic curve + public const int EN_VALVE_CURVE = 5; //Valve position curve public const int EN_UNCONDITIONAL = 0; //Unconditional object deletion public const int EN_CONDITIONAL = 1; //Conditional object deletion diff --git a/include/epanet2.bas b/include/epanet2.bas index c38003e..bc2ce1e 100644 --- a/include/epanet2.bas +++ b/include/epanet2.bas @@ -5,7 +5,7 @@ Attribute VB_Name = "Module1" 'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT '(EPANET2.DLL) -'Last updated on 02/01/2020 +'Last updated on 07/28/2022 ' These are codes used by the DLL functions Public Const EN_ELEVATION = 0 ' Node parameters @@ -63,6 +63,7 @@ Public Const EN_PUMP_ECOST = 21 Public Const EN_PUMP_EPAT = 22 Public Const EN_LINK_INCONTROL = 23 Public Const EN_GPV_CURVE = 24 +Public Const EN_PCV_CURVE= 25 Public Const EN_DURATION = 0 ' Time parameters Public Const EN_HYDSTEP = 1 @@ -117,6 +118,7 @@ Public Const EN_PBV = 5 Public Const EN_FCV = 6 Public Const EN_TCV = 7 Public Const EN_GPV = 8 +Public Const EN_PCV = 9 Public Const EN_CLOSED = 0 ' Link status types Public Const EN_OPEN = 1 @@ -209,6 +211,7 @@ Public Const EN_PUMP_CURVE = 1 ' Pump curve Public Const EN_EFFIC_CURVE = 2 ' Efficiency curve Public Const EN_HLOSS_CURVE = 3 ' Head loss curve Public Const EN_GENERIC_CURVE = 4 ' Generic curve +Public Const EN_VALVE_CURVE = 5 ' Valve position curve Public Const EN_UNCONDITIONAL = 0 ' Unconditional object deletion Public Const EN_CONDITIONAL = 1 ' Conditional object deletion diff --git a/include/epanet2.pas b/include/epanet2.pas index cbba41e..fba8147 100644 --- a/include/epanet2.pas +++ b/include/epanet2.pas @@ -3,7 +3,7 @@ unit epanet2; { Declarations of imported procedures from the EPANET PROGRAMMERs TOOLKIT } { (EPANET2.DLL) } -{Last updated on 02/01/2020} +{Last updated on 07/28/2022} interface @@ -69,6 +69,7 @@ const EN_PUMP_EPAT = 22; EN_LINK_INCONTROL = 23; EN_GPV_CURVE = 24; + EN_PCV_CURVE = 25; EN_DURATION = 0; { Time parameters } EN_HYDSTEP = 1; @@ -123,6 +124,7 @@ const EN_FCV = 6; EN_TCV = 7; EN_GPV = 8; + EN_PCV = 9; EN_CLOSED = 0; { Link status types } EN_OPEN = 1; @@ -214,7 +216,8 @@ const EN_PUMP_CURVE = 1; EN_EFFIC_CURVE = 2; EN_HLOSS_CURVE = 3; - EN_GENERIC_CURVE = 4; + EN_GENERIC_CURVE = 4; + EN_VALVE_CURVE = 5; EN_UNCONDITIONAL = 0; { Deletion action codes } EN_CONDITIONAL = 1; diff --git a/include/epanet2.vb b/include/epanet2.vb index bbd365e..7c283f0 100644 --- a/include/epanet2.vb +++ b/include/epanet2.vb @@ -4,7 +4,7 @@ 'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT '(EPANET2.DLL) for use with VB.Net. -'Last updated on 02/01/2020 +'Last updated on 07/28/2022 Imports System.Runtime.InteropServices Imports System.Text @@ -67,6 +67,7 @@ Public Const EN_PUMP_ECOST = 21 Public Const EN_PUMP_EPAT = 22 Public Const EN_LINK_INCONTROL = 23 Public Const EN_GPV_CURVE = 24 +Public Const EN_PCV_CURVE = 25 Public Const EN_DURATION = 0 ' Time parameters Public Const EN_HYDSTEP = 1 @@ -120,6 +121,7 @@ Public Const EN_PBV = 5 Public Const EN_FCV = 6 Public Const EN_TCV = 7 Public Const EN_GPV = 8 +Public Const EN_PCV = 9 Public Const EN_NONE = 0 ' Quality analysis types Public Const EN_CHEM = 1 @@ -203,6 +205,7 @@ Public Const EN_PUMP_CURVE = 1 ' Pump curve Public Const EN_EFFIC_CURVE = 2 ' Efficiency curve Public Const EN_HLOSS_CURVE = 3 ' Head loss curve Public Const EN_GENERIC_CURVE = 4 ' Generic curve +Public Const EN_VALVE_CURVE = 5 ' Valve position curve Public Const EN_UNCONDITIONAL = 0 ' Unconditional object deletion Public Const EN_CONDITIONAL = 1 ' Conditional object deletion diff --git a/include/epanet2_enums.h b/include/epanet2_enums.h index a000b0c..b3347bc 100644 --- a/include/epanet2_enums.h +++ b/include/epanet2_enums.h @@ -9,7 +9,7 @@ Authors: see AUTHORS Copyright: see AUTHORS 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_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_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; /// Time parameters @@ -191,7 +192,8 @@ typedef enum { EN_PBV = 5, //!< Pressure breaker valve EN_FCV = 6, //!< Flow 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; /// Link status @@ -397,7 +399,8 @@ typedef enum { EN_PUMP_CURVE = 1, //!< Pump head v. flow curve EN_EFFIC_CURVE = 2, //!< Pump efficiency 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; /// Deletion action codes diff --git a/src/enumstxt.h b/src/enumstxt.h index fdb9311..ccc12e8 100755 --- a/src/enumstxt.h +++ b/src/enumstxt.h @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 06/20/2019 + Last Updated: 08/13/2022 ****************************************************************************** */ @@ -27,7 +27,8 @@ char *LinkTxt[] = {w_CV, w_PBV, w_FCV, w_TCV, - w_GPV}; + w_GPV, + w_PCV}; char *StatTxt[] = {t_XHEAD, t_TEMPCLOSED, diff --git a/src/epanet.c b/src/epanet.c index 9a3c194..1635b36 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS 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; // 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 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); net->Valve = (Svalve *)realloc(net->Valve, size); net->Valve[net->Nvalves].Link = n; + net->Valve[net->Nvalves].Curve = 0; } 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; // Check for valid input parameters - if (linkType < 0 || linkType > GPV || actionCode < EN_UNCONDITIONAL || + if (linkType < 0 || linkType > PCV || actionCode < EN_UNCONDITIONAL || actionCode > EN_CONDITIONAL) { return 251; @@ -3794,6 +3795,13 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val } break; + case EN_PCV_CURVE: + if (Link[index].Type == PCV) + { + v = net->Valve[findvalve(&p->network, index)].Curve; + } + break; + case EN_GPV_CURVE: 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]; break; case TCV: + case PCV: break; case 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; + 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: if (Link[index].Type == GPV) { diff --git a/src/funcs.h b/src/funcs.h index 366e5c7..f3e5ea4 100755 --- a/src/funcs.h +++ b/src/funcs.h @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 02/03/2020 + Last Updated: 08/13/2022 ****************************************************************************** */ #ifndef FUNCS_H @@ -166,6 +166,7 @@ void headlosscoeffs(Project *); void matrixcoeffs(Project *); void emitterheadloss(Project *, int, double *, double *); void demandheadloss(Project *, int, double, double, double *, double *); +double pcvlosscoeff(Project *, int, double); // ------- QUALITY.C -------------------- diff --git a/src/hydcoeffs.c b/src/hydcoeffs.c index 83b2dc3..b45f032 100644 --- a/src/hydcoeffs.c +++ b/src/hydcoeffs.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 03/30/2022 + Last Updated: 08/13/2022 ****************************************************************************** */ @@ -36,6 +36,7 @@ const double CBIG = 1.e8; // Exported functions //void resistcoeff(Project *, int ); +//double pcvlosscoeff(Project *, int, double); //void headlosscoeffs(Project *); //void matrixcoeffs(Project *); //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 pbvcoeff(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 psvcoeff(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: link->R = CBIG; break; + + case PCV: + link->R = pcvlosscoeff(pr, k, link->Kc); + break; // ... For all other links (e.g. valves) use a small resistance 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) /* **-------------------------------------------------------------- @@ -148,6 +234,9 @@ void headlosscoeffs(Project *pr) case TCV: tcvcoeff(pr, k); break; + case PCV: + pcvcoeff(pr, k); + break; case GPV: gpvcoeff(pr, k); 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) /* **-------------------------------------------------------------- diff --git a/src/hydraul.c b/src/hydraul.c index 36cd67b..fe9999a 100755 --- a/src/hydraul.c +++ b/src/hydraul.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS 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 { if (*k == MISSING && *s <= CLOSED) *s = OPEN; + if (t == PCV) link->R = pcvlosscoeff(pr, index, link->Kc); *k = value; } } @@ -605,6 +606,7 @@ int controls(Project *pr) { hyd->LinkStatus[k] = s2; hyd->LinkSetting[k] = k2; + if (link->Type == PCV) link->R = pcvlosscoeff(pr, k, k2); if (pr->report.Statflag) writecontrolaction(pr,k,i); setsum++; } diff --git a/src/inpfile.c b/src/inpfile.c index bc5d4e6..c1fcc48 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -7,7 +7,7 @@ Description: saves network data to an EPANET formatted text file Authors: see AUTHORS Copyright: see AUTHORS 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); } + // 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); fprintf(f, "\n%s %s", s, s1); if (link->Comment) fprintf(f, " ;%s", link->Comment); diff --git a/src/input3.c b/src/input3.c index c32eaf7..9534b35 100644 --- a/src/input3.c +++ b/src/input3.c @@ -7,7 +7,7 @@ Description: parses network data from a line of an EPANET input file Authors: see AUTHORS Copyright: see AUTHORS 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 ** Format: ** [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 lcoeff = 0.0; // Minor loss coeff. Slink *link; - int err = 0; + int err = 0, + losscurve = 0; // Loss coeff. curve // Add new valve to data base n = parser->Ntokens; @@ -521,6 +522,8 @@ int valvedata(Project *pr) type = TCV; else if (match(parser->Tok[4], w_GPV)) type = GPV; + else if (match(parser->Tok[4], w_PCV)) + type = PCV; else 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); 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 if (valvecheck(pr, net->Nlinks, type, j1, j2)) @@ -563,6 +576,7 @@ int valvedata(Project *pr) link->ResultIndex = 0; link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG); net->Valve[net->Nvalves].Link = net->Nlinks; + net->Valve[net->Nvalves].Curve = losscurve; return 0; } diff --git a/src/output.c b/src/output.c index 1e9a6ab..51685e2 100644 --- a/src/output.c +++ b/src/output.c @@ -7,7 +7,7 @@ Description: binary file read/write routines Authors: see AUTHORS Copyright: see AUTHORS 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: x[i] = (REAL4)(setting * pr->Ucf[FLOW]); break; case TCV: + case PCV: x[i] = (REAL4)setting; break; default: x[i] = 0.0f; } diff --git a/src/project.c b/src/project.c index b470ec3..4b8a971 100644 --- a/src/project.c +++ b/src/project.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS 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 ** 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 **---------------------------------------------------------------- */ @@ -877,7 +877,7 @@ int findpump(Network *network, int index) /*---------------------------------------------------------------- ** Input: index = link ID ** 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 **---------------------------------------------------------------- */ @@ -894,7 +894,7 @@ int findvalve(Network *network, int index) /*---------------------------------------------------------------- ** Input: index = link ID ** 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 **---------------------------------------------------------------- */ @@ -1010,7 +1010,7 @@ void adjustcurves(Network *network, int index) **---------------------------------------------------------------- */ { - int j, k, setting; + int j, k, curve; // Adjust tank volume curves for (j = 1; j <= network->Ntanks; j++) @@ -1025,15 +1025,25 @@ void adjustcurves(Network *network, int index) adjustcurve(&network->Pump[j].Ecurve, index); } - // Adjust GPV curves + // Adjust PCV & GPV curves for (j = 1; j <= network->Nvalves; j++) { 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) { - setting = INT(network->Link[k].Kc); - adjustcurve(&setting, index); - network->Link[k].Kc = setting; + curve = INT(network->Link[k].Kc); + adjustcurve(&curve, index); + network->Link[k].Kc = curve; } } } diff --git a/src/text.h b/src/text.h index a4ac84b..72fef68 100755 --- a/src/text.h +++ b/src/text.h @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 07/15/2019 + Last Updated: 08/13/2022 ****************************************************************************** */ @@ -40,6 +40,7 @@ #define w_FCV "FCV" #define w_TCV "TCV" #define w_GPV "GPV" +#define w_PCV "PCV" #define w_OPEN "OPEN" #define w_CLOSED "CLOSED" diff --git a/src/types.h b/src/types.h index b0e91b5..281e012 100755 --- a/src/types.h +++ b/src/types.h @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 07/11/2020 + Last Updated: 08/13/2022 ****************************************************************************** */ @@ -145,7 +145,8 @@ typedef enum { PBV, // pressure breaker valve FCV, // flow control valve TCV, // throttle control valve - GPV // general purpose valve + GPV, // general purpose valve + PCV // positional control valve } LinkType; typedef enum { @@ -166,7 +167,8 @@ typedef enum { PUMP_CURVE, // pump curve EFFIC_CURVE, // efficiency curve HLOSS_CURVE, // head loss curve - GENERIC_CURVE // generic curve + GENERIC_CURVE, // generic curve + VALVE_CURVE // positional valve loss curve } CurveType; typedef enum { @@ -455,6 +457,7 @@ typedef struct // Pump Object typedef struct // Valve Object { int Link; // link index of valve + int Curve; // positional loss coeff. curve } Svalve; typedef struct // Control Statement diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 995d01f..946e9f6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -39,6 +39,7 @@ set(toolkit_test_srcs test_control.cpp test_overflow.cpp test_pda.cpp + test_valve.cpp ) add_executable(test_toolkit ${toolkit_test_srcs}) diff --git a/tests/test_valve.cpp b/tests/test_valve.cpp new file mode 100644 index 0000000..a4c3c89 --- /dev/null +++ b/tests/test_valve.cpp @@ -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 + +#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()