Skip to content

Commit 9b90723

Browse files
committed
Merge branch 'dev'
2 parents fea7d04 + 44428f5 commit 9b90723

File tree

8 files changed

+81
-34
lines changed

8 files changed

+81
-34
lines changed

ReleaseNotes2_3.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,14 @@ This document describes the changes and updates that have been made in version 2
137137
- A failure to close a temporary hydraulics file between successive simulations of an opened project was fixed.
138138

139139
- Corrupting the index of a water quality Trace Node when adding or deleting a node was fixed.
140+
141+
### Patch Releases
142+
#### 2.3.1:
143+
- Restores the ability to assign an initial status of fully open to a valve and corrects how the setting of a Positional Control Valve is changed using the API or with a control.
144+
#### 2.3.2:
145+
- Fixes how `EN_setpipedata` assigns a minor loss coefficient to a pipe.
146+
#### 2.3.3:
147+
- Corrects how `EN_setlinkvalue` assigns OPEN/CLOSED status to a link.
148+
#### 2.3.4:
149+
- Fixes errors converting the units of the Leak Area and Leak Area Expansion parameters used in the FAVAD pipe leakage model.
150+
- To avoid reporting that full tanks are overflowing when they see negligible net inflows or outflows, those flows are now ignored when updating the tank's volume and head.

src/epanet.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Authors: see AUTHORS
88
Copyright: see AUTHORS
99
License: see LICENSE
10-
Last Updated: 09/03/2025
10+
Last Updated: 01/28/2026
1111
******************************************************************************
1212
*/
1313

@@ -4020,11 +4020,11 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
40204020
break;
40214021

40224022
case EN_LEAK_AREA:
4023-
v = Link[index].LeakArea * Ucf[LENGTH];
4023+
v = Link[index].LeakArea / Ucf[LENGTH];
40244024
break;
40254025

40264026
case EN_LEAK_EXPAN:
4027-
v = Link[index].LeakExpan * Ucf[LENGTH];
4027+
v = Link[index].LeakExpan / Ucf[LENGTH];
40284028
break;
40294029

40304030
case EN_LINK_LEAKAGE:
@@ -4287,14 +4287,14 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
42874287
}
42884288
break;
42894289

4290-
case EN_LEAK_AREA: // leak area in sq mm per 100 pipe length units
4290+
case EN_LEAK_AREA: // leak area per 100 pipe lengths units
42914291
if (value < 0.0) return 211;
4292-
Link[index].LeakArea = value / Ucf[LENGTH];
4292+
Link[index].LeakArea = value * Ucf[LENGTH];
42934293
break;
42944294

4295-
case EN_LEAK_EXPAN: // leak area expansion slope (sq mm per unit of head)
4295+
case EN_LEAK_EXPAN: // leak area expansion slope per 100 pipe length units
42964296
if (value < 0.0) return 211;
4297-
Link[index].LeakExpan = value / Ucf[LENGTH];
4297+
Link[index].LeakExpan = value * Ucf[LENGTH];
42984298
break;
42994299

43004300
case EN_VALVE_TYPE:

src/hydraul.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Authors: see AUTHORS
88
Copyright: see AUTHORS
99
License: see LICENSE
10-
Last Updated: 04/19/2025
10+
Last Updated: 01/28/2026
1111
******************************************************************************
1212
*/
1313

@@ -1066,6 +1066,7 @@ void tanklevels(Project *pr, long tstep)
10661066

10671067
// Update the tank's volume & water elevation
10681068
n = tank->Node;
1069+
if (ABS(hyd->NodeDemand[n]) <= QZERO) continue;
10691070
dv = hyd->NodeDemand[n] * tstep;
10701071
tank->V += dv;
10711072

src/inpfile.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,8 @@ int saveinpfile(Project *pr, const char *fname)
370370
link = &net->Link[i];
371371
if (link->LeakArea == 0.0 && link->LeakExpan == 0.0) continue;
372372
fprintf(f, "\n %-31s %14.6f %14.6f", link->ID,
373-
link->LeakArea * pr->Ucf[LENGTH], link->LeakExpan * pr->Ucf[LENGTH]);
373+
link->LeakArea / pr->Ucf[LENGTH],
374+
link->LeakExpan / pr->Ucf[LENGTH]);
374375
}
375376

376377
// Write [STATUS] section

src/input1.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Description: retrieves network data from an EPANET input file
77
Authors: see AUTHORS
88
Copyright: see AUTHORS
99
License: see LICENSE
10-
Last Updated: 04/19/2025
10+
Last Updated: 01/28/2026
1111
******************************************************************************
1212
*/
1313

@@ -602,8 +602,8 @@ void convertunits(Project *pr)
602602
link->Kw /= SECperDAY;
603603

604604
// Convert leakage parameters
605-
link->LeakArea /= pr->Ucf[LENGTH];
606-
link->LeakExpan /= pr->Ucf[LENGTH];
605+
link->LeakArea *= pr->Ucf[LENGTH];
606+
link->LeakExpan *= pr->Ucf[LENGTH];
607607
}
608608

609609
else if (link->Type == PUMP)

src/leakage.c

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@
77
Authors: see AUTHORS
88
Copyright: see AUTHORS
99
License: see LICENSE
10-
Last Updated: 09/10/2025
10+
Last Updated: 01/28/2026
1111
******************************************************************************
1212
*/
1313
/*
1414
This module uses the FAVAD (Fixed and Variable Discharge) equation to model
1515
leaky pipes:
1616
17-
Q = Co * L * (Ao + m * H) * sqrt(H)
17+
Q = Co * (Ao + m * H) * sqrt(H)
1818
19-
where Q = pipe leak flow rate, Co = an orifice coefficient (= 0.6*sqrt(2g)),
20-
L = pipe length, Ao = initial area of leak per unit of pipe length,
21-
m = change in leak area per unit of pressure head, and H = pressure head.
19+
where Q = pipe leak flow rate, Co = an orifice coefficient = 0.6*sqrt(2g),
20+
Ao = initial area of leak, m = change in leak area per unit of pressure
21+
head, and H = pressure head.
2222
2323
The inverted form of this equation is used to model the leakage demand from
2424
a pipe's end node using a pair of equivalent emitters as follows:
@@ -27,13 +27,8 @@ a pipe's end node using a pair of equivalent emitters as follows:
2727
H = Cva * Qva^(2/3)
2828
2929
where Qfa = fixed area node leakage rate, Qva = variable area node leakage rate,
30-
Cfa = 1 / SUM(Co*(L/2)*Ao)^2, Cva = 1 / SUM(Co*(L/2)*m)^2/3, and
30+
Cfa = 1 / SUM(Co/2*Ao)^2, Cva = 1 / SUM(Co/2*m)^2/3, and
3131
SUM(x) is the summation of x over all pipes connected to the node.
32-
33-
In implementing this model, the pipe property "LeakArea" represents Ao in
34-
sq. mm per 100 units of pipe length and "LeakExpan" represents m in sq. mm
35-
per unit of pressure head.
36-
3732
*/
3833
#include <stdlib.h>
3934
#include <math.h>
@@ -154,8 +149,8 @@ void convert_pipe_to_node_leakage(Project *pr)
154149
Snode *node1;
155150
Snode *node2;
156151

157-
// Orifice coeff. with conversion from sq. mm to sq. m
158-
c_orif = 4.8149866 * 1.e-6;
152+
// Orifice coeff. = 0.6 * sqrt(2 * g) * (sq m per sq mm)
153+
c_orif = 4.8149766 * 1.e-6;
159154

160155
// Examine each link
161156
for (i = 1; i <= net->Nlinks; i++)
@@ -173,10 +168,10 @@ void convert_pipe_to_node_leakage(Project *pr)
173168
// Get pipe's fixed and variable area leak coeffs.
174169
if (link->LeakArea == 0.0 && link->LeakExpan == 0.0) continue;
175170
c_area = c_orif * link->LeakArea / SQR(MperFT);
176-
c_expan = c_orif * link->LeakExpan;
171+
c_expan = c_orif * link->LeakExpan / MperFT;
177172

178173
// Adjust for number of 100-ft pipe sections
179-
len = link->Len * pr->Ucf[LENGTH] / 100.;
174+
len = link->Len / 100.;
180175
if (node1->Type == JUNCTION && node2->Type == JUNCTION)
181176
{
182177
len *= 0.5;
@@ -286,11 +281,11 @@ double findlinkleakage(Project *pr, int i)
286281
h2 = hyd->NodeHead[n2] - net->Node[n2].El;
287282
h2 = MAX(h2, 0.0);
288283

289-
// Pipe leak parameters converted to feet
284+
// Pipe leak parameters
290285
a = link->LeakArea / SQR(MperFT);
291-
m = link->LeakExpan;
292-
len = link->Len * pr->Ucf[LENGTH] / 100.; // # 100 ft pipe lengths
293-
c = 4.8149866 * len / 2.0 * 1.e-6;
286+
m = link->LeakExpan / MperFT;
287+
len = link->Len / 100.; // # 100 ft pipe lengths
288+
c = 4.8149766 * (len / 2.0) * 1.0e-6;
294289

295290
// Leakage from 1st half of pipe connected to node n1
296291
q1 = 0.0;

src/types.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Authors: see AUTHORS
88
Copyright: see AUTHORS
99
License: see LICENSE
10-
Last Updated: 09/03/2025
10+
Last Updated: 02/03/2026
1111
******************************************************************************
1212
*/
1313

@@ -31,7 +31,7 @@ typedef int INT4;
3131
Various constants
3232
----------------------------------------------
3333
*/
34-
#define CODEVERSION 20303
34+
#define CODEVERSION 20304
3535
#define MAGICNUMBER 516114521
3636
#define ENGINE_VERSION 201 // Used for binary hydraulics file
3737
#define EOFMARK 0x1A // Use 0x04 for UNIX systems

tests/test_leakage.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Authors: see AUTHORS
88
Copyright: see AUTHORS
99
License: see LICENSE
10-
Last Updated: 06/26/2024
10+
Last Updated: 02/02/2026
1111
******************************************************************************
1212
*/
1313

@@ -33,6 +33,9 @@ BOOST_AUTO_TEST_CASE(test_leakage_model)
3333
int Pipe21, Junc21, Junc22;
3434
double pipe21Leak, junc21Leak, junc22Leak;
3535
EN_Project ph = NULL;
36+
double A, C, M, L, E1, E2, H1, H2, Q1, Q2, Q;
37+
const double GPMperCFS = 448.831;
38+
const double MperFT = 0.3048;
3639

3740
error = EN_createproject(&ph);
3841
BOOST_REQUIRE(error == 0);
@@ -82,6 +85,42 @@ BOOST_AUTO_TEST_CASE(test_leakage_model)
8285
//printf("\n Node leakage flow: %.4f\n", junc21Leak + junc22Leak);
8386
BOOST_REQUIRE(abs(pipe21Leak - (junc21Leak+junc22Leak)) < 0.01);
8487

88+
// Independently verify pipe leakage flow
89+
90+
// Retrieve leak parameters (in mm units)
91+
EN_getlinkvalue(ph, Pipe21, EN_LEAK_AREA, &A);
92+
EN_getlinkvalue(ph, Pipe21, EN_LEAK_EXPAN, &M);
93+
94+
// Convert leak parameters to feet units
95+
A = A / MperFT / MperFT / 1.e6;
96+
M = M / MperFT / 1.e6;
97+
98+
// Find number of 100-ft pipe lengths
99+
EN_getlinkvalue(ph, Pipe21, EN_LENGTH, &L);
100+
L = L / 100.;
101+
102+
// Compute orifice coefficient
103+
C = 0.6 * sqrt(2. * 32.2);
104+
105+
// Find pressure heads at up and down stream nodes
106+
EN_getnodevalue(ph, Junc21, EN_ELEVATION, &E1);
107+
EN_getnodevalue(ph, Junc22, EN_ELEVATION, &E2);
108+
EN_getnodevalue(ph, Junc21, EN_HEAD, &H1);
109+
EN_getnodevalue(ph, Junc22, EN_HEAD, &H2);
110+
H1 = H1 - E1;
111+
H2 = H2 - E2;
112+
113+
// Compute leakage flow over each half of pipe (in cfs)
114+
Q1 = C * (L/2.) * (A + M * H1) * sqrt(H1);
115+
Q2 = C * (L/2.) * (A + M * H2) * sqrt(H2);
116+
117+
// Find total pipe leakage in gpm
118+
Q = (Q1 + Q2) * GPMperCFS;
119+
// printf(" Calculated leakage: %.4f\n", Q);
120+
121+
// Compare pipe leakage with EPANET's value
122+
BOOST_REQUIRE(abs(pipe21Leak - Q) < 0.01);
123+
85124
// Clean up
86125
error = EN_close(ph);
87126
BOOST_REQUIRE(error == 0);

0 commit comments

Comments
 (0)