Skip to contents

This function uses the Hardy-Cross method to iteratively solve the equations for conservation of mass and energy in a water pipe network. The input consists of a data frame with the pipe characteristics and lists of the pipes in each loop (listed in a clockwise direction) and the initial guesses of flows in each pipe (positive flows are in a clockwise direction).


  dfpipes = dfpipes,
  loops = loops,
  Qs = Qs,
  n_iter = 1,
  units = c("SI", "Eng"),
  ret_units = FALSE



data frame with the pipe data. Format is described above, but must contain a column named _ID_.


integer list defining pipes in each loop of the network.


numeric list of initial flows for each pipe in each loop [\(m^3 s^{-1}\) or \(ft^3 s^{-1}\)]


integer identifying the number of iterations to perform.


character vector that contains the system of units [options are SI for International System of Units and Eng for English (US customary) units.


If set to TRUE the value(s) returned for pipe flows are of class units with units attached to the value. [Default is FALSE]


Returns a list of two data frames:

  • dfloops - the final flow magnitude and direction (clockwise positive) for each loop and pipe

  • dfpipes - the input pipe data frame, with additional columns including final Q


The input data frame with the pipe data must contain a pipe ID column with the pipe numbers used in the loops input list. There are three options for input column of the pipe roughness data frame:

Column NameApproach for Determining K
ksf calculated using Colebrook equation, K using Darcy-Weisbach
ff treated as fixed, K calculated using Darcy-Weisbach
KK treated as fixed

In the case where absolute pipe roughness, \(ks\) (in m or ft), is input, the input pipe data frame must also include columns for the length, \(L\) and diameter, \(D\), (both in m or ft) so \(K\) can be calculated. In this case, a new \(f\) and \(K\) are calculated at each iteration, the final values of which are included in the output. If input \(K\) or \(f\) columns are provided, values for \(ks\) are ignored. If an input \(K\) column is provided, \(ks\) and \(f\) are ignored. If the Colebrook equation is used to determine \(f\), a water temperature of \(20^{o}C\) or \(68^{o}F\) is used.

The number of iterations to perform may be specified with the n_iter input value, but execution stops if the average flow adjustment becomes smaller than 1 percent of the average flow in all pipes.

The Darcy-Weisbach equation is used to estimate the head loss in each pipe segment, expressed in a condensed form as \(h_f = KQ^{2}\) where: $$K = \frac{8fL}{\pi^{2}gD^{5}}$$ If needed, the friction factor \(f\) is calculated using the Colebrook equation. The flow adjustment in each loop is calculated at each iteration as: $$\Delta{Q_i} = -\frac{\sum_{j=1}^{p_i} K_{ij}Q_j|Q_j|}{\sum_{j=1}^{p_i} 2K_{ij}Q_j^2}$$ where \(i\) is the loop number, \(j\) is the pipe number, \(p_i\) is the number of pipes in loop \(i\) and \(\Delta{Q_i}\) is the flow adjustment to be applied to each pipe in loop \(i\) for the next iteration.


#              A----------B --> 0.5m^3/s
#              |\   (4)   |
#              | \        |
#              |  \       |
#              |   \(2)   |
#              |    \     |(5)
#              |(1)  \    |
#              |      \   |
#              |       \  |
#              |        \ |
#              |   (3)   \|
# 0.5m^3/s --> C----------D

#Input pipe characteristics data frame. With K given other columns not needed
dfpipes <- data.frame(
ID = c(1,2,3,4,5),                     #pipe ID
K = c(200,2500,500,800,300)            #resistance used in hf=KQ^2
loops <- list(c(1,2,3),c(2,4,5))
Qs <- list(c(0.3,0.1,-0.2),c(-0.1,0.2,-0.3))
hardycross(dfpipes = dfpipes, loops = loops, Qs = Qs, n_iter = 1, units = "SI")
#> Using fixed K values
#> Iteration: 1, Loop: 1, dQ: -0.02805
#> Iteration: 1, Loop: 2, dQ: 0.02000
#> $dfloops
#>   loop pipe        flow
#> 1    1    1  0.27195122
#> 2    1    2  0.05195122
#> 3    1    3 -0.22804878
#> 4    2    2 -0.05195122
#> 5    2    4  0.22000000
#> 6    2    5 -0.28000000
#> $dfpipes
#>   ID    K           Q
#> 1  1  200  0.27195122
#> 2  2 2500  0.05195122
#> 3  3  500 -0.22804878
#> 4  4  800  0.22000000
#> 5  5  300 -0.28000000