3.2 EPANET (Examples 1 and 2) using the Toolkit
Contents
3.2 EPANET (Examples 1 and 2) using the Toolkit#
Purpose#
This section demonstrates the various previous examples using the Toolkit to run the example and make changes to inputs and rerun the examples. The main concept is that the Toolkit allows manipulation of models independent of a GUI which when combined with either Toolkit supplied control rules, or external “control” lets one model and interpret (assuming IF-THEN interpretation is amenable) many changes automatically.
Installation Notes#
The examples herein are on the developmental computer (a Raspberry Pi). The scripts should work fine on another computer with the toolkit installed (Windows probably takes a bit more fussing to get the Linux subsystem to call to the Toolkit).
Example 1 - Head Loss in a Pipeline#
A simple model to consider is a single pipe connecting two reservoirs.
A problem statement might be something like:
A 5-foot diameter, enamel coated, steel pipe carries 60oF water at a dis- charge of 295 cubic-feet per second (cfs). Using the Moody chart, estimate the head loss in a 10,000 foot length of this pipe.
Note
This example is verbatim from the previous sections, here the examples are presented using the Toolkit interface. The ASCII (.net) input file is taken from the previous section. Then manipulated in the example - it is the essence of the Toolkit. Many of the steps below, are repetitive so I don’t forget the steps myself. As one gets familiar with the process, I would suspect it becomes second nature.
Path to the library#
Either copy the library into the working directory which on the development machine is ects-epanet/ects-epanet-notes/lessons/lesson03/ex1-tk
or adapt the path to the already installed working directory, in this example we will take the second approach. Here is the directory listing before running the example .
Note
The file removal step is to delete any existing output files. Its not necessary except to ensure this notebook builds in a fashion that tells the manipulation story well.
!rm -rf ./ex1-tk/*.rpt
!ls -la ./ex1-tk
total 16
drwxrwxr-x 3 sensei sensei 4096 Nov 28 06:40 .
drwxrwxr-x 10 sensei sensei 4096 Aug 4 05:38 ..
drwxrwxr-x 2 sensei sensei 4096 Jul 28 14:27 .ipynb_checkpoints
-rw-rw-r-- 1 sensei sensei 2911 Jul 28 14:27 EX1tk.inp
And a look at the contents of the input file
! cat ./ex1-tk/EX1tk.inp
[TITLE]
[JUNCTIONS]
;ID Elev Demand Pattern
2 0 295 ;
[RESERVOIRS]
;ID Head Pattern
R1 100 ;
[TANKS]
;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve
[PIPES]
;ID Node1 Node2 Length Diameter Roughness MinorLoss Status
frenchy R1 2 10000 60 0.15 0.15 Open ;
[PUMPS]
;ID Node1 Node2 Parameters
[VALVES]
;ID Node1 Node2 Diameter Type Setting MinorLoss
[TAGS]
[DEMANDS]
;Junction Demand Pattern Category
[STATUS]
;ID Status/Setting
[PATTERNS]
;ID Multipliers
[CURVES]
;ID X-Value Y-Value
[CONTROLS]
[RULES]
[ENERGY]
Global Efficiency 75
Global Price 0
Demand Charge 0
[EMITTERS]
;Junction Coefficient
[QUALITY]
;Node InitQual
[SOURCES]
;Node Type Quality Pattern
[REACTIONS]
;Type Pipe/Tank Coefficient
[REACTIONS]
Order Bulk 1
Order Tank 1
Order Wall 1
Global Bulk 0
Global Wall 0
Limiting Potential 0
Roughness Correlation 0
[MIXING]
;Tank Model
[TIMES]
Duration 0
Hydraulic Timestep 1:00
Quality Timestep 0:05
Pattern Timestep 1:00
Pattern Start 0:00
Report Timestep 1:00
Report Start 0:00
Start ClockTime 12 am
Statistic None
[REPORT]
Status No
Summary Yes
Nodes ALL
Links ALL
Page 0
[OPTIONS]
Units CFS
Headloss D-W
Specific Gravity 1
Viscosity 1
Trials 40
Accuracy 0.001
CHECKFREQ 2
MAXCHECK 10
DAMPLIMIT 0
Unbalanced Continue 10
Pattern 1
Demand Multiplier 1.0
Emitter Exponent 0.5
Quality None mg/L
Diffusivity 1
Tolerance 0.01
[COORDINATES]
;Node X-Coord Y-Coord
2 4509.15 8053.24
R1 -2945.09 8119.80
[VERTICES]
;Link X-Coord Y-Coord
[LABELS]
;X-Coord Y-Coord Label & Anchor Node
[BACKDROP]
DIMENSIONS 0.00 0.00 10000.00 10000.00
UNITS None
FILE
OFFSET 0.00 0.00
[END]
The library epamodule.py
and the shared object library (similar to a DLL) are already installed at ects-epanet/ects-epanet-notes/lessons/lesson03
which houses the examples. Next we build and run the necessary script(s)
import epamodule as em # import the package
---------------------------------------------------------------------------
OSError Traceback (most recent call last)
/tmp/ipykernel_219804/1326067120.py in <module>
----> 1 import epamodule as em # import the package
~/ects-epanet/ects-epanet-notes/lessons/lesson03/epamodule.py in <module>
10 _plat= platform.system()
11 if _plat=='Linux':
---> 12 _lib = ctypes.CDLL("./libepanet2.so") # For My Raspberry Pi
13 ## _lib = ctypes.CDLL("./en2tools.so.1.5.0")
14 ## _lib = ctypes.CDLL("./epanet2toolkit.so")
/usr/lib/python3.8/ctypes/__init__.py in __init__(self, name, mode, handle, use_errno, use_last_error, winmode)
371
372 if handle is None:
--> 373 self._handle = _dlopen(self._name, mode)
374 else:
375 self._handle = handle
OSError: ./libepanet2.so: cannot open shared object file: No such file or directory
#em.ENepanet("./ex1-tk/EX1tk.inp", "./ex1-tk/EX1tk.rpt") # runs a complete simulation. input file must exist and have contents.
#Open the EPANET toolkit & hydraulics solver
em.ENopen("./ex1-tk/EX1tk.inp", "./ex1-tk/EX1tk.rpt")
em.ENopenH()
em.ENsolveH()
em.ENsaveH() # need to save to a binary file before write
em.ENcloseH()
em.ENopenQ()
em.ENsolveQ()
em.ENreport() # now write report
# Close hydraulics solver & toolkit */
em.ENclose()
Now can look at simulation results
! cat ./ex1-tk/EX1tk.rpt
Page 1 Fri Jul 28 18:52:56 2023
******************************************************************
* E P A N E T *
* Hydraulic and Water Quality *
* Analysis for Pipe Networks *
* Version 2.2 *
******************************************************************
Input Data File ................... ./ex1-tk/EX1tk.inp
Number of Junctions................ 1
Number of Reservoirs............... 1
Number of Tanks ................... 0
Number of Pipes ................... 1
Number of Pumps ................... 0
Number of Valves .................. 0
Headloss Formula .................. Darcy-Weisbach
Nodal Demand Model ................ DDA
Hydraulic Timestep ................ 1.00 hrs
Hydraulic Accuracy ................ 0.001000
Status Check Frequency ............ 2
Maximum Trials Checked ............ 10
Damping Limit Threshold ........... 0.000000
Maximum Trials .................... 40
Quality Analysis .................. None
Specific Gravity .................. 1.00
Relative Kinematic Viscosity ...... 1.00
Relative Chemical Diffusivity ..... 1.00
Demand Multiplier ................. 1.00
Total Duration .................... 0.00 hrs
Reporting Criteria:
All Nodes
All Links
Analysis begun Fri Jul 28 18:52:56 2023
Node Results:
----------------------------------------------
Demand Head Pressure
Node cfs ft psi
----------------------------------------------
2 295.00 26.93 11.67
R1 -295.00 100.00 0.00 Reservoir
Link Results:
----------------------------------------------
Flow Velocity Headloss
Link cfs fps /1000ft
----------------------------------------------
frenchy 295.00 15.02 7.31
Analysis ended Fri Jul 28 18:52:56 2023
Now to manipulate the model, we will make the link half as long.
Note
The python module seems a little different from C
and R
scripting examples and uses numeric codes in place of the string codes in the online examples of the Toolkit. Maybe its an IQ test; but here are the codes for links:
EN_DIAMETER = 0 # /* Link parameters */
EN_LENGTH = 1
EN_ROUGHNESS = 2
EN_MINORLOSS = 3
EN_INITSTATUS = 4
EN_INITSETTING = 5
EN_KBULK = 6
EN_KWALL = 7
EN_FLOW = 8
EN_VELOCITY = 9
EN_HEADLOSS = 10
EN_STATUS = 11
EN_SETTING = 12
EN_ENERGY = 13
import epamodule as em # import the package
#Open the EPANET toolkit & hydraulics solver
em.ENopen("./ex1-tk/EX1tk.inp", "./ex1-tk/EX1-1tk.rpt")
em.ENopenH()
linkname = em.ENgetlinkid(1) # get the name of the link - numbering starts at 1, linkname is a byte literal
decoded_linkname = linkname.decode('utf-8')
print("linkname is :" + decoded_linkname)
# now lets get the length of the link
parmcode=1 # this is the code for length - a table exists in the epamodule.py file
linklong = em.ENgetlinkvalue(1,parmcode)
print("link length is: " + str(linklong) + ' feet')
print("lets decrease the length and re-run the model")
linklong = 0.5*linklong
print("link length is: " + str(linklong) + ' feet')
em.ENsetlinkvalue(1, parmcode, linklong)
print("verify the reset")
newlinklong = em.ENgetlinkvalue(1,parmcode)
print("new link length is: " + str(newlinklong) + ' feet')
em.ENsolveH()
em.ENsaveH() # need to save to a binary file before write
em.ENcloseH()
em.ENopenQ()
em.ENsolveQ()
em.ENreport() # now write report
# Close hydraulics solver & toolkit */
em.ENclose()
linkname is :frenchy
link length is: 10000.0 feet
lets decrease the length and re-run the model
link length is: 5000.0 feet
verify the reset
new link length is: 5000.0 feet
Now look at the output and observe the changes - in this instance the pressure head is larger at the node than in the longer pipe case; an anticipated result.
! cat ./ex1-tk/EX1-1tk.rpt
Page 1 Fri Jul 28 18:52:57 2023
******************************************************************
* E P A N E T *
* Hydraulic and Water Quality *
* Analysis for Pipe Networks *
* Version 2.2 *
******************************************************************
Input Data File ................... ./ex1-tk/EX1tk.inp
Number of Junctions................ 1
Number of Reservoirs............... 1
Number of Tanks ................... 0
Number of Pipes ................... 1
Number of Pumps ................... 0
Number of Valves .................. 0
Headloss Formula .................. Darcy-Weisbach
Nodal Demand Model ................ DDA
Hydraulic Timestep ................ 1.00 hrs
Hydraulic Accuracy ................ 0.001000
Status Check Frequency ............ 2
Maximum Trials Checked ............ 10
Damping Limit Threshold ........... 0.000000
Maximum Trials .................... 40
Quality Analysis .................. None
Specific Gravity .................. 1.00
Relative Kinematic Viscosity ...... 1.00
Relative Chemical Diffusivity ..... 1.00
Demand Multiplier ................. 1.00
Total Duration .................... 0.00 hrs
Reporting Criteria:
All Nodes
All Links
Analysis begun Fri Jul 28 18:52:57 2023
Node Results:
----------------------------------------------
Demand Head Pressure
Node cfs ft psi
----------------------------------------------
2 295.00 63.20 27.38
R1 -295.00 100.00 0.00 Reservoir
Link Results:
----------------------------------------------
Flow Velocity Headloss
Link cfs fps /1000ft
----------------------------------------------
frenchy 295.00 15.02 7.36
Analysis ended Fri Jul 28 18:52:57 2023
That concludes this simple (not intrinsicly usefull just yet) example. Lets continue with another one from our GUI cases.
Example 2 Flow Rate in a Pipeline#
This example represents the situation where the total head is known at two points on a pipeline, and one wishes to determine the flow rate (or specify a flow rate and solve for a pipe diameter). Like the prior example it is contrived, but follows the same general modeling process.
As in the prior example, we will use EPANET to solve a problem we have already solved by hand.
The problem statement is:
Using the Moody chart, and the energy equation, estimate the diameter of a cast-iron pipe needed to carry 60oF water at a discharge of 10 cubic- feet per second (cfs) between two reservoirs 2 miles apart. The elevation difference between the water surfaces in the two reservoirs is 20 feet. A sketch of the situation is
As in the prior example, we will start with the ASCII input file and manipulate the model with the Toolkit. The default input file will produce very little output other than to acknowledge the simulation ran to completion. So we will manipulate the output instructions. First we start with the input file, in this case it is named EX2-JB-Copy1.inp
! cat ./ex2-tk/EX2-JB-Copy1.inp
[TITLE]
[JUNCTIONS]
;ID Elev Demand Pattern
2 70 295 ;
[RESERVOIRS]
;ID Head Pattern
1 100 ;
3 80 ;
[TANKS]
;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve Overflow
[PIPES]
;ID Node1 Node2 Length Diameter Roughness MinorLoss Status
1 1 2 10560 22.47 0.85 0 Open ;
2 2 3 10 120 0.05 0 Open ;
[PUMPS]
;ID Node1 Node2 Parameters
[VALVES]
;ID Node1 Node2 Diameter Type Setting MinorLoss
[TAGS]
[DEMANDS]
;Junction Demand Pattern Category
[STATUS]
;ID Status/Setting
[PATTERNS]
;ID Multipliers
[CURVES]
;ID X-Value Y-Value
[CONTROLS]
[RULES]
[ENERGY]
Global Efficiency 75
Global Price 0
Demand Charge 0
[EMITTERS]
;Junction Coefficient
[QUALITY]
;Node InitQual
[SOURCES]
;Node Type Quality Pattern
[REACTIONS]
;Type Pipe/Tank Coefficient
[REACTIONS]
Order Bulk 1
Order Tank 1
Order Wall 1
Global Bulk 0
Global Wall 0
Limiting Potential 0
Roughness Correlation 0
[MIXING]
;Tank Model
[TIMES]
Duration 0
Hydraulic Timestep 1:00
Quality Timestep 0:05
Pattern Timestep 1:00
Pattern Start 0:00
Report Timestep 1:00
Report Start 0:00
Start ClockTime 12 am
Statistic None
[REPORT]
Status No
Summary No
Page 0
[OPTIONS]
Units CFS
Headloss D-W
Specific Gravity 1
Viscosity 1
Trials 40
Accuracy 0.001
CHECKFREQ 2
MAXCHECK 10
DAMPLIMIT 0
Unbalanced Continue 10
Pattern 1
Demand Multiplier 1.0
Emitter Exponent 0.5
Quality None mg/L
Diffusivity 1
Tolerance 0.01
[COORDINATES]
;Node X-Coord Y-Coord
2 8015.152 6606.061
1 1075.758 8818.182
3 9045.455 6606.061
[VERTICES]
;Link X-Coord Y-Coord
[LABELS]
;X-Coord Y-Coord Label & Anchor Node
-1045.455 9969.697 "Reservoir Node"
6924.242 5787.879 "Inlet Node"
[BACKDROP]
DIMENSIONS 0.000 0.000 10000.000 10000.000
UNITS None
FILE C:\users\antares\Desktop\EPANET-Files\EX2\EX2.bmp
OFFSET 0.00 0.00
[END]
Now lets examine the section regarding the report.
[REPORT]
Status No
Summary No
Page 0
This pretty much says report nothing - we can see the impact by running the model and examining the output report.
import epamodule as em # import the package
#Open the EPANET toolkit & hydraulics solver
em.ENopen("./ex2-tk/EX2-JB-Copy1.inp", "./ex2-tk/EX2-JB-Copy1.rpt")
em.ENopenH()
em.ENsolveH()
em.ENsaveH() # need to save to a binary file before write
em.ENcloseH()
em.ENopenQ()
em.ENsolveQ()
em.ENreport() # now write report
# Close hydraulics solver & toolkit */
em.ENclose()
Examine the output file
! cat ./ex2-tk/EX2-JB-Copy1.rpt
Page 1 Sat Jul 29 06:10:03 2023
******************************************************************
* E P A N E T *
* Hydraulic and Water Quality *
* Analysis for Pipe Networks *
* Version 2.2 *
******************************************************************
Analysis begun Sat Jul 29 06:10:03 2023
Analysis ended Sat Jul 29 06:10:03 2023
Observe not much of a report. Lets use the toolkit to enhance the report output.
import epamodule as em # import the package
#Open the EPANET toolkit & hydraulics solver
em.ENopen("./ex2-tk/EX2-JB-Copy1.inp", "./ex2-tk/EX2-JB-Copy1.rpt")
# build report command strings Keyword Action see user manual
command0 = "Status Yes"
command1 = "Summary Yes"
command2 = "Nodes ALL"
command3 = "Links ALL"
em.ENsetstatusreport(2) # full status report
em.ENsetreport(command0)
em.ENsetreport(command1)
em.ENsetreport(command2)
em.ENsetreport(command3)
em.ENsaveinpfile("./ex2-tk/EX2-tkmodify.inp") #write to a new file
em.ENclose()
# now run from the new file
em.ENopen("./ex2-tk/EX2-tkmodify.inp", "./ex2-tk/EX2-tkmodify.rpt")
em.ENopenH()
em.ENsolveH()
em.ENsaveH() # need to save to a binary file before write
em.ENcloseH()
em.ENopenQ()
em.ENsolveQ()
em.ENreport() # now write report
# Close hydraulics solver & toolkit */
em.ENclose()
# The old file
! cat ./ex2-tk/EX2-JB-Copy1.rpt
Page 1 Sat Jul 29 06:31:19 2023
******************************************************************
* E P A N E T *
* Hydraulic and Water Quality *
* Analysis for Pipe Networks *
* Version 2.2 *
******************************************************************
Analysis begun Sat Jul 29 06:31:19 2023
Analysis ended Sat Jul 29 06:31:19 2023
# The new file
! cat ./ex2-tk/EX2-tkmodify.rpt
Page 1 Sat Jul 29 06:31:19 2023
******************************************************************
* E P A N E T *
* Hydraulic and Water Quality *
* Analysis for Pipe Networks *
* Version 2.2 *
******************************************************************
Input Data File ................... ./ex2-tk/EX2-tkmodify.inp
Number of Junctions................ 1
Number of Reservoirs............... 2
Number of Tanks ................... 0
Number of Pipes ................... 2
Number of Pumps ................... 0
Number of Valves .................. 0
Headloss Formula .................. Darcy-Weisbach
Nodal Demand Model ................ DDA
Hydraulic Timestep ................ 1.00 hrs
Hydraulic Accuracy ................ 0.001000
Status Check Frequency ............ 2
Maximum Trials Checked ............ 10
Damping Limit Threshold ........... 0.000000
Maximum Trials .................... 40
Quality Analysis .................. None
Specific Gravity .................. 1.00
Relative Kinematic Viscosity ...... 1.00
Relative Chemical Diffusivity ..... 1.00
Demand Multiplier ................. 1.00
Total Duration .................... 0.00 hrs
Reporting Criteria:
All Nodes
All Links
Analysis begun Sat Jul 29 06:31:19 2023
Hydraulic Status:
-----------------------------------------------------------------------
0:00:00: Balanced after 5 trials
0:00:00: Reservoir 1 is emptying
0:00:00: Reservoir 3 is emptying
Node Results:
----------------------------------------------
Demand Head Pressure
Node cfs ft psi
----------------------------------------------
2 295.00 80.00 4.33
1 -10.01 100.00 0.00 Reservoir
3 -284.99 80.00 0.00 Reservoir
Link Results:
----------------------------------------------
Flow Velocity Headloss
Link cfs fps /1000ft
----------------------------------------------
1 10.01 3.63 1.89
2 -284.99 3.63 0.20
Analysis ended Sat Jul 29 06:31:19 2023
So we have the ability to modify important parts of input files to meet our needs. We could have also overwritten to the original file and juct run everything in a single pass, but for clarity we have kept the files separate. Naturally, we are now responsible for our own “graphics” if thats of interest (later on we can try to adapt EPyT scripts)