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)

References#

Exercises#