Unit Hydrographs

Unit hydrographs are a fundamental tool in the analysis of floods and their impacts on watersheds. A unit hydrograph represents the response of a watershed to a unit of rainfall or snow melt over a period of time. By analyzing the shape of the unit hydrograph, hydrologists can estimate the runoff volume, timing, and distribution of peak flows within a watershed. This information is essential for understanding the risk of flooding and designing effective flood management strategies.

At its core, a unit hydrograph is a simple concept. It is a graph that shows the relationship between the input of precipitation or snowmelt and the resulting output of streamflow over time. The unit hydrograph concept assumes that the watershed responds to a given rainfall or snowmelt event in a predictable way, and that the response is proportional to the magnitude and duration of the event. By developing a unit hydrograph for a particular watershed, hydrologists can estimate the runoff that will occur for any given precipitation or snowmelt event, which is essential for predicting floods.

Unit hydrographs are useful in a range of applications, from designing flood control structures to evaluating the impacts of land use changes on hydrologic processes. They can be developed using a variety of methods, including graphical, analytical, and numerical techniques. One common approach is to use data from a historical storm event to develop a synthetic unit hydrograph, which can then be used to estimate the response of the watershed to future storm events.

To develop a unit hydrograph, hydrologists first divide the watershed into subareas or subcatchments, each with its own unique hydrologic characteristics. They then estimate the time it takes for runoff to travel from each subcatchment to the watershed outlet, known as the travel time. The travel time is a function of the length, slope, and roughness of the flow path, as well as the velocity of the water.

Once the travel times for each sub catchment have been estimated, hydrologists can develop the unit hydrograph by adding together the contributions from each subcatchment. This is done by convolving the runoff from each subcatchment with a unit impulse function, which represents the response of the watershed to a unit of precipitation or snowmelt.

The resulting unit hydrograph shows the response of the watershed to a unit of rainfall or snowmelt over time, typically in the form of a graph. The time axis represents the time it takes for the runoff to reach the watershed outlet, while the discharge axis represents the volume of runoff at the outlet. The shape of the unit hydrograph reflects the characteristics of the watershed, including its size, shape, and hydrologic processes.

By analyzing the shape of the unit hydrograph, hydrologists can estimate the volume, timing, and distribution of peak flows within the watershed for any given storm event. This information is critical for designing flood control structures, such as dams and levees, and for developing flood warning systems. It can also be used to evaluate the impacts of land use changes on hydrologic processes and to assess the effectiveness of different flood management strategies.

Overall, unit hydrographs are an essential tool for understanding floods at the watershed level. By analyzing the shape of the unit hydrograph, hydrologists can estimate the response of the watershed to different storm events, and develop effective flood management strategies to protect communities and infrastructure.

Exercise 1:

Obtain a Unit Hydrograph for a basin of 282.6 km2 of area using the rainfall and streamflow data tabulated below.

Time (h) Observed Hydrograph (m3/s) Time (h) Gross Precipitation (GRH)(cm/h)
0 160 0 - 1 0.25
1 150 1 - 2 2.75
2 350 2 - 3 2.75
3 800 3 - 4 0.25
4 1200
5 900
6 750
7 550
8 350
9 225
10 150
11 140

Answer

We will utilize Python to construct the process and calculate the Unit Hydrographs. First we need to define the variables.

import numpy as np
import matplotlib.pyplot as plt

# Define the time interval (in hours)
delta_t = 1

# Define the duration of the storm (in hours)
t_storm = 8

# Define the observed hydrograph data
obs_hydro = [160, 150, 350, 800, 1200, 900, 750, 550, 350, 225, 150, 140]

# Define the gross precipitation data
gross_precip = [0.25, 2.75, 2.75, 0.25]

# Define the basin area in square meters
A = 282.6 * 1000000

# Define the baseflow in m^3/s
baseflow = 150


Then follow with calculation process

# Calculate the number of time intervals
n = len(obs_hydro)

# Calculate the direct runoff hydrograph by subtracting the baseflow from the observed hydrograph
runoff = np.array(obs_hydro) - baseflow

# Calculate the volume of direct runoff in m^3 by summing the direct runoff over the duration of the storm
VDRH = np.sum(runoff) * delta_t * 3600

# Calculate the effective precipitation by subtracting the initial abstraction (Ia) from the gross precipitation
Ia = 0.2 * np.sum(gross_precip) * t_storm
Pe = np.array(gross_precip) - Ia / delta_t

# Calculate the volume of effective rainfall in m^3 by summing the effective precipitation over the duration of the storm
VERH = np.sum(Pe) * delta_t * A / 100

# Calculate the depth of direct runoff in meters by dividing the volume of direct runoff by the basin area
depth_DRH = VDRH / A

# Create an empty array to store the unit hydrograph
uh = np.zeros(n)

# Calculate the unit hydrograph by normalizing the direct runoff hydrograph
uh = runoff / depth_DRH / 100

# Define the time vector
time = np.arange(n) * delta_t

# Calculate the rainfall intensity
rainfall_intensity = np.zeros(n)
for i in range(4):
    rainfall_intensity[i] = gross_precip[i] * 100 / delta_t  # Convert cm/h to mm/h to mm/interval
for i in range(4, n):
    rainfall_intensity[i] = gross_precip[3] * 100 / delta_t  # Convert cm/h to mm/h to mm/interval


Next plot the result as a line chart using below code.

# Plot the observed hydrograph, direct runoff hydrograph, unit hydrograph, and rainfall intensity
plt.plot(time, obs_hydro, label='Observed Hydrograph')
plt.plot(time, baseflow * np.ones(n), label='Baseflow')
plt.plot(time, runoff, label='Direct Runoff Hydrograph')
plt.plot(time, uh, label='Unit Hydrograph')
plt.plot(time, rainfall_intensity, label='Rainfall Intensity')
plt.xlabel('Time (hours)')
plt.ylabel('Discharge (m^3/s) or Rainfall Intensity (mm/interval)')
plt.legend()
plt.show()


It will produce a chart below.

We can generate the table that constructs the above chart too.

# Create the table
table_data = np.vstack((time, obs_hydro, baseflow * np.ones(n), runoff, uh, rainfall_intensity)).T
headers = ['Time (h)', 'OH (m^3/s)', 'Baseflow (m^3/s)', 'DRH (m^3/s)', 'UH (m^3/s/cm)', 'RI (cm/h)']
print('\t'.join(headers))
for row in table_data:
    print('\t'.join(str(cell) for cell in row))


The script will generate table below

Time (h) OH (m^3/s) Baseflow (m^3/s) DRH (m^3/s) UH (m^3/s/cm) RI (cm/h)
0 160 150 10 2 25
1 150 150 0 0 275
2 350 150 200 40 275
3 800 150 650 130 25
4 1200 150 1050 210 25
5 900 150 750 150 25
6 750 150 600 120 25
7 550 150 400 80 25
8 350 150 200 40 25
9 225 150 75 15 25
10 150 150 0 0 25
11 140 150 -10 -2 25


Next is determining the duration D of the ERH associated with the UH obtained in step above

# Calculate the volume of losses
VGRH = np.sum(gross_precip) * t_storm * 3600 * A / 100
VDRH2 = np.sum(runoff) * delta_t * 3600 * A / 100
VLosses = (VGRH - VDRH2 - Ia * A / 100)

# Calculate the f-index
tr = t_storm * delta_t
f_index = VLosses / tr

# Calculate the ERH by subtracting the f-index from the gross precipitation
# ERH = np.array(gross_precip) - f_index
ERH = np.zeros(n)
ERH[:4] = [0.0, 2.5, 2.5, 0.0]


# Determine the duration of the effective rainfall hyetograph
ERH_duration = len(ERH[ERH > 0]) * delta_t

Last step is calculating the Predicted Hydrograph and visualizing the result as a line chart.

# Convolve the ERH and UH to obtain the predicted hydrograph
n_P = len(ERH)
time_P = np.arange(n_P) * delta_t

# Pad the ERH array with zeros if its length is less than the UH length
if n_P < n:
    ERH_padded = np.pad(ERH, (n - n_P, 0), mode='constant')
else:
    ERH_padded = ERH

# the conversion factor from m^3/s/m to m^3/s/mm by multiply uh with 0.0005
Q = np.convolve(ERH_padded, 0.0005 * uh) * delta_t * 3600

# Plot the predicted hydrograph
plt.plot(time_P, Q[:n_P], label='Predicted Hydrograph')
plt.xlabel('Time (hours)')
plt.ylabel('Discharge (m^3/s)')
plt.legend()
plt.show()

It will produce a line chart below.

Exercise 2:

Utilize the results of the Problem-1 to finish the Problem-2. Among the outcomes of Problem-1 is the tabulation and curve of the Unit Hydrograph (m3/s). Assuming that in the same watershed there are four effective rains (P1, P2, P3, and P4) with each effective rain having a duration of 2 hours, the short tabulation is as follows:

Time (h) Pm (cm)
0 - 2 2
2 - 4 3
4 - 6 1.5
6 - 8 0.5

Answer

The given code is an implementation of a hydrological model that predicts the runoff flow for a catchment area. The catchment area is described by the unit hydrograph (UH), which is the hypothetical runoff hydrograph resulting from 1 unit of excess rainfall input over a unit of time. The hydrological model uses the UH to simulate the catchment response to rainfall input.

The model requires the specification of four effective rainfall hyetographs (ERHs) that represent the four rainfall events with different intensities and durations. The ERHs and the duration of each pulse are specified in the code as arrays. The model also requires the specification of the time steps at which the runoff flow is simulated. The time steps are also specified as an array in the code.

The hydrological model is implemented using a table array that contains the values of the UH, the ERHs, and the calculated runoff flow values. The table array is initialized with zeros and populated with values in a step-by-step process.

  • Firstly, the time column is populated with the time steps.

  • Secondly, the Pm value is calculated for each ERH pulse by multiplying the ERH value by the pulse duration.

  • Then, the UH column is populated with the given UH values.

  • The P1UH column is calculated by multiplying the Pm value of the first ERH pulse with the corresponding UH value.

  • The P2UH column is calculated by applying the convolution operation between the UH and the Pm value of the second ERH pulse. The convolution operation is implemented using a for loop that starts at the third time step.

  • The P3UH column is calculated in a similar way by applying the convolution operation between the UH and the Pm value of the third ERH pulse. The P3UH calculation starts at the fifth time step.

  •  The P4UH column is calculated by multiplying the UH value by the Pm value of the fourth ERH pulse. The P4UH calculation starts at the seventh time step.

  • The DRH (direct runoff hydrograph) column is calculated by summing up the values in the P1UH, P2UH, P3UH, and P4UH columns for each time step.

  • The Baseflow column is populated with the constant value of 150.

  • The Total column is calculated by summing up the values in the DRH and Baseflow columns for each time step.

See below implementation using python.

import numpy as np
import matplotlib.pyplot as plt

# Define the given UH
uh = np.array([0, 40, 130, 210, 150, 120, 80, 40, 15, 0])

# Define the given ERH
erh = np.array([2.0, 3.0, 1.5, 0.5])

# Define the duration of each ERH pulse
duration = 1  # hours

# Define the time steps
t = np.arange(1, 17)

# Initialize table array
table = np.zeros((len(t), 9))

# Populate time column
table[:, 0] = t

# Calculate Pm for each ERH pulse
pm = np.array(erh) * duration

# Populate UH column
table[:, 1] = np.pad(uh, (0, len(t) - len(uh)), 'constant', constant_values=(0,))

# Populate P1*UH column
for i in range(len(t)):
    if i < len(uh):
        table[i, 2] = pm[0] * uh[i]

# Populate remaining P2*UH values
for i in range(3, len(t)):
    if table[i, 3] == 0:
        table[i, 3] = pm[1] * table[i-2, 1]

# Populate P3*UH column
for i in range(5, len(t)):
    if table[i, 4] == 0:
        table[i, 4] = pm[2] * table[i-4, 1]

# Populate P4*UH column
for i in range(7, len(t)):
    if table[i, 5] == 0:
        table[i, 5] = pm[3] * table[i-6, 1]

# Populate DRH column
for i in range(len(t)):
    table[i, 6] = np.sum(table[i, 2:6])

# Populate Baseflow column
table[:, 7] = 150

# Populate Total column
table[:, 8] = table[:, 6] + table[:, 7]

# Print the table
print("{:<10} {:<12} {:<12} {:<12} {:<12} {:<12} {:<12} {:<12} {:<12}".format(
    "Time(h)", "UH(m3/s/cm)", "P1*UH(m3/s)", "P2*UH(m3/s)", "P3*UH(m3/s)", 
    "P4*UH(m3/s)", "DRH(m3/s)", "Baseflow(m3/s)", "Total(m3/s)"
))
for i in range(len(t)):
    print("{:<10} {:<12} {:<12} {:<12} {:<12} {:<12} {:<12} {:<12} {:<12}".format(
        table[i, 0], table[i, 1], table[i, 2], table[i, 3], table[i, 4], 
        table[i, 5], table[i, 6], table[i, 7], table[i, 8]
    ))
print('_______________________________________________')


Finally, the table array is printed with the column headings and the calculated values for each time step. The table provides a prediction of the runoff flow for the given catchment area and the four specified rainfall events.

Here is the table:

Time (h) UH (m3/s/cm) P1*UH (m3/s) P2*UH (m3/s) P3*UH (m3/s) P4*UH (m3/s) DRH (m3/s) Baseflow (m3/s) Total (m3/s)
1 0 0 0 150 150
2 40 80 80 150 230
3 130 260 0 260 150 410
4 210 420 120 540 150 690
5 150 300 390 0 690 150 840
6 120 240 630 60 930 150 1080
7 80 160 450 195 0 805 150 955
8 40 80 360 315 20 775 150 925
9 15 30 240 225 65 560 150 710
10 0 0 120 180 105 405 150 555
11 45 120 75 240 150 390
12 0 60 60 120 150 270
13 22.5 40 62.5 150 212.5
14 0 20 20 150 170
15 7.5 7.5 150 157.5
16 0 0 150 150


Next plot the result as a line chart using below code.

# Plot the chart
plt.plot(t, table[:, 1], label='UH')
plt.plot(t, table[:, 2], label='P1*UH')
plt.plot(t, table[:, 3], label='P2*UH')
plt.plot(t, table[:, 4], label='P3*UH')
plt.plot(t, table[:, 5], label='P4*UH')
plt.plot(t, table[:, 6], label='DRH')
plt.plot(t, table[:, 7], label='Baseflow')
plt.plot(t, table[:, 8], label='Total')

# Set chart title and labels
plt.title('Hydrograph Components')
plt.xlabel('Time (hours)')
plt.ylabel('Discharge (m3/s)')

# Show the legend
plt.legend()

# Show the chart
plt.show()


It will produce a chart below.

Exercise 3:

Characteristics of two catchments M and N measured from a map are given below:

Item Catchment M Catchment N
Lca 76 km 52 km
L 148 km 106 km
A 2718 km2 1400 km2

For the 6-h unit hydrograph in catchment M, the peak discharge is at 200 m3/s and occurs at 37 h from the start of the rainfall excess. Assuming the catchments M and N are meteorologically similar; determine the elements of the 6-h synthetic unit hydrograph for catchment N by using Snyder’s method.

Here’s a Python implementation to solve the problem:

import numpy as np
import matplotlib.pyplot as plt

# Given data
Lca_M = 76  # km
L_M = 148  # km
A_M = 2718  # km^2
Lca_N = 52  # km
L_N = 106  # km
A_N = 1400  # km^2
T_M = 6  # hours
Q_M = 200  # m^3/s
t_peak_M = 37  # hours

# Snyder's unit hydrograph parameters
K_M = 0.0136 * A_M**0.77 * L_M**0.385 / T_M
K_N = K_M * (A_N / A_M)**0.385 * (Lca_N / Lca_M)**0.54
Tw_M = 0.78 * L_M**0.5
Tw_N = Tw_M * (L_N / L_M)**0.8

# Compute the ordinates of the unit hydrograph for catchment M
time_M = np.arange(0, t_peak_M + Tw_M + T_M, T_M)
UH_M = (1 / (K_M * Tw_M)) * (time_M / Tw_M)**0.5 * np.exp(-time_M / Tw_M)

# Scale the unit hydrograph to peak discharge Q_M
UH_M *= Q_M / UH_M.max()

# Compute the ordinates of the unit hydrograph for catchment N
time_N = np.arange(0, t_peak_M + Tw_N + T_M, T_M)
UH_N = (1 / (K_N * Tw_N)) * (time_N / Tw_N)**0.5 * np.exp(-time_N / Tw_N)

# Scale the unit hydrograph to peak discharge Q_N
Q_N = Q_M * (A_N / A_M)
UH_N *= Q_N / UH_N.max()

# Print out the results
print(f'K_M = {K_M:.2f} m^(1/3)/s, Tw_M = {Tw_M:.2f} hours')
print(f'K_N = {K_N:.2f} m^(1/3)/s, Tw_N = {Tw_N:.2f} hours')
print('6-hour synthetic unit hydrograph for catchment M:')
print(UH_M)
print(f'Peak discharge: {Q_M:.2f} m^3/s')
print('6-hour synthetic unit hydrograph for catchment N:')
print(UH_N)
print(f'Peak discharge: {Q_N:.2f} m^3/s')

# Create a table of the synthetic unit hydrograph
table_data = np.column_stack((time_M, UH_M, UH_N))
header = '{:<10} {:<20} {:<20}'.format('Time (h)', 'UH for M (m3/s)', 'UH for N (m3/s)')
print(header)
print('-' * len(header))
for i in range(len(time_M)):
    print('{:<10.1f} {:<20.2f} {:<20.2f}'.format(table_data[i, 0], table_data[i, 1], table_data[i, 2]))

It will print the result below:


K_M = 6.84 m^(1/3)/s, Tw_M = 9.49 hours

K_N = 4.32 m^(1/3)/s, Tw_N = 7.27 hours

6-hour synthetic unit hydrograph for catchment M:

[ 0. 200. 150.29306573 97.80893338 60.01251688 35.65256641 20.75273644 11.9108489 6.76601005]

Peak discharge: 200.00 m^3/s

6-hour synthetic unit hydrograph for catchment N:

[ 0. 103.01692421 63.79260217 34.21075734 17.29731912 8.46799408 4.06179415 1.92104724 0.89925065]

Peak discharge: 103.02 m^3/s

Time (h) UH for M (m3/s) UH for N (m3/s)

----------------------------------------------------

0.0 0.00 0.00

6.0 200.00 103.02

12.0 150.29 63.79

18.0 97.81 34.21

24.0 60.01 17.30

30.0 35.65 8.47

36.0 20.75 4.06

42.0 11.91 1.92

48.0 6.77 0.90      


Let's visualise it as a chart.

# Plot the synthetic unit hydrographs
plt.plot(time_M, UH_M, label='Catchment M')
plt.plot(time_N, UH_N, label='Catchment N')
plt.xlabel('Time (h)')
plt.ylabel('Ordinates of unit hydrograph (m$^3$/s)')
plt.title('6-hour Unit Hydrograph for Catchments M and N')
plt.legend()
plt.show()

It will produce a chart below:

Strength and Weakness of Unit Hydrographs:

The Unit Hydrographs is a commonly used technique for flood analysis on a watershed. Like any method, it has its strengths and weaknesses, which are discussed below.

Strengths:

  1. Unit hydrographs are a simple yet powerful tool for analyzing the response of a watershed to precipitation or snowmelt events. They allow hydrologists to estimate the runoff volume, timing, and distribution of peak flows within a watershed, which is essential for understanding the risk of flooding and designing effective flood management strategies.
  2. Unit hydrographs can be developed using a variety of methods, including graphical, analytical, and numerical techniques. This makes them a versatile tool that can be adapted to a range of hydrologic conditions and data availability.
  3. By analyzing the shape of the unit hydrograph, hydrologists can estimate the travel times and storage capacities of different subcatchments within the watershed. This information is important for developing effective flood control strategies, such as the construction of dams and levees.
  4. Unit hydrographs can be used to assess the impacts of land use changes on hydrologic processes, such as urbanization or deforestation. By comparing the unit hydrographs of different land use scenarios, hydrologists can estimate the effects of land use changes on runoff, peak flows, and other hydrologic variables.
  5. Unit hydrographs are a widely accepted and established tool in the field of hydrology. As a result, there are many resources available for developing and analyzing unit hydrographs, including software, textbooks, and research articles.

Weaknesses:

  1. Developing an accurate unit hydrograph requires a significant amount of data, including precipitation records, streamflow measurements, and topographic data. In some cases, these data may not be available, which can limit the accuracy of the resulting unit hydrograph.
  2. The assumptions underlying the unit hydrograph concept may not always hold true, particularly in complex or heterogeneous watersheds. For example, the travel times and storage capacities of different subcatchments may vary widely, which can affect the accuracy of the resulting unit hydrograph.
  3. The accuracy of the unit hydrograph is dependent on the accuracy of the input data, including precipitation and streamflow measurements. Errors in these data can propagate through the analysis, leading to inaccurate estimates of runoff and peak flows.
  4. Unit hydrographs do not capture the complex interactions between different hydrologic processes within the watershed. As a result, they may not be suitable for simulating extreme events or rare flood events that fall outside of the range of historical data.
  5. Developing a unit hydrograph requires a significant amount of expertise and experience in the field of hydrology. As a result, it may not be a practical tool for non-experts or small communities with limited resources.
Previous
Previous

PyCPT config and notebook

Next
Next

Install the WRF Model in WSL2