Path: blob/main/latex-templates/templates/hydrology/rainfall_runoff.tex
51 views
unlisted
% Rainfall-Runoff Modeling Template1% Topics: Unit hydrograph theory, SCS Curve Number method, Nash cascade, watershed response2% Style: Engineering hydrology report with computational modeling34\documentclass[a4paper, 11pt]{article}5\usepackage[utf8]{inputenc}6\usepackage[T1]{fontenc}7\usepackage{amsmath, amssymb}8\usepackage{graphicx}9\usepackage{siunitx}10\usepackage{booktabs}11\usepackage{subcaption}12\usepackage[makestderr]{pythontex}13\usepackage{geometry}14\geometry{margin=1in}1516% Theorem environments17\newtheorem{definition}{Definition}[section]18\newtheorem{theorem}{Theorem}[section]19\newtheorem{example}{Example}[section]20\newtheorem{remark}{Remark}[section]2122\title{Rainfall-Runoff Modeling: Unit Hydrograph Theory and SCS Curve Number Method}23\author{Hydrology Research Group}24\date{\today}2526\begin{document}27\maketitle2829\begin{abstract}30This engineering report presents a comprehensive analysis of rainfall-runoff transformation31using the unit hydrograph approach and the Soil Conservation Service (SCS) Curve Number method.32We develop synthetic unit hydrographs using the Nash cascade model, compute excess rainfall33from design storms using the SCS-CN method, and apply discrete convolution to generate direct34runoff hydrographs. The analysis demonstrates watershed response characteristics including35time of concentration, peak discharge estimation, and the effects of antecedent moisture36conditions and land use on runoff generation.37\end{abstract}3839\section{Introduction}4041Rainfall-runoff modeling is fundamental to hydrologic engineering, providing the basis42for flood forecasting, drainage design, and water resources planning. The transformation43of precipitation into streamflow involves complex processes including interception,44infiltration, surface detention, and channel routing. The unit hydrograph approach,45introduced by Sherman (1932), provides an elegant framework for this transformation46by treating the watershed as a linear time-invariant system.4748\begin{definition}[Unit Hydrograph]49A unit hydrograph (UH) is the direct runoff hydrograph resulting from 1 unit (typically501 inch or 1 cm) of excess rainfall generated uniformly over the drainage area at a constant51rate for an effective duration $D$. The direct runoff excludes baseflow and represents52only the surface and rapid subsurface response.53\end{definition}5455The SCS Curve Number method, developed by the USDA Natural Resources Conservation Service,56provides a practical approach to estimating rainfall excess from total precipitation based57on watershed characteristics including soil type, land use, and antecedent moisture conditions.5859\section{Theoretical Framework}6061\subsection{Unit Hydrograph Theory}6263The unit hydrograph method relies on three fundamental principles:6465\begin{enumerate}66\item \textbf{Time invariance}: The UH for a given watershed is time-invariant67\item \textbf{Proportionality}: Direct runoff ordinates are proportional to excess rainfall depth68\item \textbf{Superposition}: Runoff hydrographs from successive storms can be superposed69\end{enumerate}7071\begin{theorem}[Convolution Equation]72For a watershed with unit hydrograph $u(t)$ and excess rainfall intensity $i_e(t)$,73the direct runoff $Q(t)$ is given by the convolution integral:74\begin{equation}75Q(t) = \int_0^t i_e(\tau) \cdot u(t - \tau) \, d\tau76\end{equation}77In discrete form with time intervals $\Delta t$:78\begin{equation}79Q_n = \sum_{m=1}^{n} P_m \cdot U_{n-m+1}80\end{equation}81where $P_m$ is excess rainfall in period $m$ and $U_n$ is the unit hydrograph ordinate.82\end{theorem}8384\subsection{SCS Curve Number Method}8586The SCS-CN method estimates direct runoff depth from rainfall depth based on the curve number $CN$,87which ranges from 0 (no runoff potential) to 100 (complete runoff).8889\begin{definition}[SCS Runoff Equation]90The direct runoff depth $Q$ (inches) from rainfall depth $P$ (inches) is:91\begin{equation}92Q = \frac{(P - I_a)^2}{P - I_a + S}93\end{equation}94where $I_a$ is initial abstraction (interception + infiltration before runoff begins)95and $S$ is potential maximum retention after runoff begins. The relationships are:96\begin{equation}97S = \frac{1000}{CN} - 10 \quad \text{(inches)}98\end{equation}99\begin{equation}100I_a = 0.2S \quad \text{(standard assumption)}101\end{equation}102\end{definition}103104\begin{remark}[Curve Number Selection]105Curve numbers depend on:106\begin{itemize}107\item \textbf{Hydrologic Soil Group}: A (low runoff), B, C, D (high runoff)108\item \textbf{Land Use/Cover}: Urban areas have higher CN than forests109\item \textbf{Antecedent Moisture Condition}: AMC I (dry), II (normal), III (wet)110\end{itemize}111\end{remark}112113\subsection{Nash Cascade Model}114115The Nash cascade represents the watershed as a series of $N$ identical linear reservoirs,116each with storage coefficient $K$.117118\begin{theorem}[Nash Instantaneous Unit Hydrograph]119The instantaneous unit hydrograph (IUH) for a Nash cascade is:120\begin{equation}121u(t) = \frac{1}{K \Gamma(N)} \left(\frac{t}{K}\right)^{N-1} e^{-t/K}122\end{equation}123where $\Gamma(N)$ is the gamma function. The parameters relate to watershed properties:124\begin{equation}125K = \frac{t_p}{N} \quad \text{and} \quad N = \left(\frac{t_p}{\sigma}\right)^2126\end{equation}127where $t_p$ is time to peak and $\sigma$ is standard deviation of the IUH.128\end{theorem}129130\section{Computational Analysis}131132\subsection{Watershed Characteristics and Design Storm}133134We analyze a small urban watershed to demonstrate rainfall-runoff transformation.135The watershed has mixed land use with moderate infiltration characteristics, typical136of suburban development with 40\% impervious cover. We apply a 6-hour design storm137with total precipitation depth of 4.5 inches, distributed using the SCS Type II138temporal distribution commonly used in the eastern United States.139140\begin{pycode}141import numpy as np142import matplotlib.pyplot as plt143from scipy.special import gamma144from scipy.interpolate import interp1d145146np.random.seed(42)147148# Watershed characteristics149drainage_area = 2.5 # square miles150time_of_concentration = 1.2 # hours151CN = 75 # Curve number for suburban residential (1/4 acre lots, 38% impervious)152153# Calculate storage parameters154S_inches = 1000/CN - 10 # Maximum retention (inches)155Ia_inches = 0.2 * S_inches # Initial abstraction (inches)156157# Design storm parameters158total_rainfall = 4.5 # inches159storm_duration = 6.0 # hours160dt = 0.25 # time step (hours)161162# SCS Type II storm distribution (cumulative fractions)163# Time fractions of storm duration164time_fractions = np.array([0, 0.1, 0.2, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6,1650.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0])166# Cumulative rainfall fractions (Type II distribution)167cum_rainfall_fractions = np.array([0, 0.035, 0.076, 0.125, 0.156, 0.194, 0.219,1680.663, 0.735, 0.772, 0.799, 0.820, 0.844,1690.871, 0.898, 0.926, 0.963, 1.0])170171# Create time series172time_storm = time_fractions * storm_duration173cum_rainfall = cum_rainfall_fractions * total_rainfall174175# Interpolate to finer time step176time_series = np.arange(0, storm_duration + dt, dt)177interp_func = interp1d(time_storm, cum_rainfall, kind='linear', fill_value='extrapolate')178cum_rainfall_series = interp_func(time_series)179cum_rainfall_series = np.maximum(cum_rainfall_series, 0)180cum_rainfall_series = np.minimum(cum_rainfall_series, total_rainfall)181182# Incremental rainfall depth183rainfall_incremental = np.diff(cum_rainfall_series, prepend=0)184185# Calculate excess rainfall using SCS-CN method186excess_rainfall = np.zeros_like(cum_rainfall_series)187for i in range(len(cum_rainfall_series)):188P = cum_rainfall_series[i]189if P > Ia_inches:190Q = ((P - Ia_inches)**2) / (P - Ia_inches + S_inches)191excess_rainfall[i] = Q192193# Incremental excess rainfall194excess_incremental = np.diff(excess_rainfall, prepend=0)195196# Calculate runoff coefficient197total_excess = excess_rainfall[-1]198runoff_coefficient = total_excess / total_rainfall if total_rainfall > 0 else 0199200# Plot rainfall and excess rainfall201fig1, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))202203# Rainfall hyetograph204ax1.bar(time_series, rainfall_incremental / dt, width=dt*0.9,205color='steelblue', edgecolor='black', alpha=0.7, label='Total rainfall')206ax1.bar(time_series, excess_incremental / dt, width=dt*0.9,207color='darkred', edgecolor='black', alpha=0.7, label='Excess rainfall')208ax1.set_xlabel('Time (hours)', fontsize=11)209ax1.set_ylabel('Rainfall intensity (in/hr)', fontsize=11)210ax1.set_title(f'SCS Type II Design Storm (Total P = {total_rainfall} in, CN = {CN})', fontsize=12)211ax1.legend(fontsize=10, loc='upper left')212ax1.grid(True, alpha=0.3)213ax1.set_xlim(0, storm_duration)214215# Cumulative rainfall and runoff216ax2.plot(time_series, cum_rainfall_series, 'b-', linewidth=2.5, label='Cumulative rainfall')217ax2.plot(time_series, excess_rainfall, 'r-', linewidth=2.5, label='Cumulative excess rainfall')218ax2.axhline(y=Ia_inches, color='gray', linestyle='--', linewidth=1.5,219label=f'Initial abstraction = {Ia_inches:.2f} in')220ax2.fill_between(time_series, 0, excess_rainfall, color='darkred', alpha=0.2)221ax2.set_xlabel('Time (hours)', fontsize=11)222ax2.set_ylabel('Cumulative depth (inches)', fontsize=11)223ax2.set_title(f'Cumulative Rainfall and Runoff (Runoff coefficient = {runoff_coefficient:.3f})', fontsize=12)224ax2.legend(fontsize=10, loc='upper left')225ax2.grid(True, alpha=0.3)226ax2.set_xlim(0, storm_duration)227ax2.set_ylim(0, total_rainfall * 1.1)228229plt.tight_layout()230plt.savefig('rainfall_runoff_scs_cn.pdf', dpi=150, bbox_inches='tight')231plt.close()232\end{pycode}233234\begin{figure}[htbp]235\centering236\includegraphics[width=0.95\textwidth]{rainfall_runoff_scs_cn.pdf}237\caption{SCS Curve Number method applied to Type II design storm showing (top) rainfall238hyetograph with incremental rainfall intensity and excess rainfall intensity, and (bottom)239cumulative rainfall and runoff depths. The curve number CN = \py{CN} represents suburban240residential land use with moderate runoff potential. Initial abstraction $I_a$ = \py{f"{Ia_inches:.2f}"}241inches must be satisfied before runoff begins, resulting in a runoff coefficient of242\py{f"{runoff_coefficient:.3f}"}, indicating that \py{f"{runoff_coefficient*100:.1f}"}\%243of total precipitation becomes direct runoff. The nonlinear relationship between rainfall244and runoff is evident in the cumulative plot, with runoff generation accelerating once245initial abstraction is exceeded.}246\label{fig:scs_cn}247\end{figure}248249\subsection{Synthetic Unit Hydrograph Development}250251Using the time of concentration and drainage area, we develop a synthetic unit hydrograph252based on the Nash cascade model. The Nash model parameters are calibrated to match typical253watershed response characteristics for small urban basins. We use $N = 3$ reservoirs to254represent the storage-routing behavior of the watershed, which provides a realistic shape255with moderate skewness. The storage coefficient $K$ is derived from the time of concentration256using empirical relationships for urban watersheds.257258\begin{pycode}259# Nash cascade parameters260N_reservoirs = 3 # Number of linear reservoirs261lag_time = 0.6 * time_of_concentration # Lag time approximation262263# Storage coefficient K from time to peak relationship264# For Nash model: tp ≈ K(N-1) for N > 1265K_hours = lag_time / (N_reservoirs - 1) if N_reservoirs > 1 else lag_time266267# Time array for unit hydrograph (extended beyond storm)268time_uh = np.arange(0, 12, dt)269270# Nash IUH function271def nash_iuh(t, K, N):272"""Nash instantaneous unit hydrograph"""273if t <= 0:274return 0275return (1 / (K * gamma(N))) * ((t / K)**(N - 1)) * np.exp(-t / K)276277# Generate instantaneous unit hydrograph278iuh = np.array([nash_iuh(t, K_hours, N_reservoirs) for t in time_uh])279280# Convert IUH to unit hydrograph for duration D = dt281# UH(t) ≈ IUH(t) * dt for small dt282unit_hydrograph = iuh * dt283284# Normalize to ensure sum equals 1 inch over drainage area285uh_sum = np.sum(unit_hydrograph)286if uh_sum > 0:287unit_hydrograph = unit_hydrograph / uh_sum288289# Convert to flow units (cfs per inch of excess rainfall)290# Q (cfs) = Depth (in) * Area (sq mi) * 640 acres/sq mi * 43560 sq ft/acre / (duration * 3600 s/hr)291conversion_factor = drainage_area * 640 * 43560 / (dt * 3600)292unit_hydrograph_cfs = unit_hydrograph * conversion_factor293294# Calculate unit hydrograph properties295peak_uh = np.max(unit_hydrograph_cfs)296time_to_peak_uh = time_uh[np.argmax(unit_hydrograph_cfs)]297base_time_idx = np.where(unit_hydrograph_cfs > 0.01 * peak_uh)[0]298base_time_uh = time_uh[base_time_idx[-1]] if len(base_time_idx) > 0 else time_uh[-1]299300# Plot unit hydrograph301fig2, ax = plt.subplots(figsize=(12, 7))302ax.fill_between(time_uh, 0, unit_hydrograph_cfs, color='steelblue', alpha=0.3, label='UH area')303ax.plot(time_uh, unit_hydrograph_cfs, 'b-', linewidth=2.5, label=f'Unit hydrograph (D = {dt} hr)')304ax.axvline(x=time_to_peak_uh, color='red', linestyle='--', linewidth=1.5,305label=f'Time to peak = {time_to_peak_uh:.2f} hr')306ax.axhline(y=peak_uh, color='red', linestyle=':', linewidth=1.5, alpha=0.7)307ax.scatter([time_to_peak_uh], [peak_uh], s=100, c='red', zorder=5, edgecolor='black')308309# Add annotations310ax.annotate(f'Peak = {peak_uh:.0f} cfs',311xy=(time_to_peak_uh, peak_uh), xytext=(time_to_peak_uh + 1.5, peak_uh + 50),312arrowprops=dict(arrowstyle='->', color='red', lw=1.5),313fontsize=11, color='red', weight='bold')314315ax.set_xlabel('Time (hours)', fontsize=12)316ax.set_ylabel('Discharge (cfs per inch of excess rainfall)', fontsize=12)317ax.set_title(f'Synthetic Unit Hydrograph - Nash Cascade Model (N = {N_reservoirs}, K = {K_hours:.2f} hr)',318fontsize=13)319ax.legend(fontsize=11, loc='upper right')320ax.grid(True, alpha=0.3)321ax.set_xlim(0, 10)322ax.set_ylim(0, peak_uh * 1.2)323324plt.tight_layout()325plt.savefig('rainfall_runoff_unit_hydrograph.pdf', dpi=150, bbox_inches='tight')326plt.close()327\end{pycode}328329\begin{figure}[htbp]330\centering331\includegraphics[width=0.95\textwidth]{rainfall_runoff_unit_hydrograph.pdf}332\caption{Synthetic unit hydrograph derived from Nash cascade model with N = \py{N_reservoirs}333linear reservoirs and storage coefficient K = \py{f"{K_hours:.2f}"} hours. The unit hydrograph334represents the direct runoff response to 1 inch of excess rainfall uniformly distributed over335the \py{f"{drainage_area:.1f}"} square mile watershed during a \py{dt}-hour duration. Peak336discharge occurs at \py{f"{time_to_peak_uh:.2f}"} hours with magnitude \py{f"{peak_uh:.0f}"}337cfs per inch of excess rainfall. The base time is approximately \py{f"{base_time_uh:.1f}"}338hours, indicating the duration of direct runoff. The shape exhibits characteristic rising limb,339sharp peak, and gradual recession typical of small urban watersheds with rapid concentration340and moderate storage effects.}341\label{fig:unit_hydrograph}342\end{figure}343344\subsection{Direct Runoff Hydrograph by Convolution}345346We now apply discrete convolution of the excess rainfall hyetograph with the unit hydrograph347to generate the complete direct runoff hydrograph. This demonstrates the superposition principle,348where each increment of excess rainfall generates its own hydrograph following the unit hydrograph349shape, and all individual responses are summed to produce the total watershed response. The350convolution process accounts for the temporal distribution of rainfall intensity and the storage-351routing characteristics of the watershed.352353\begin{pycode}354# Extend time series to accommodate full hydrograph355time_total = np.arange(0, storm_duration + base_time_uh + dt, dt)356357# Extend excess rainfall array with zeros358excess_extended = np.zeros(len(time_total))359excess_extended[:len(excess_incremental)] = excess_incremental360361# Extend unit hydrograph to match length362uh_extended = np.zeros(len(time_total))363uh_length = min(len(unit_hydrograph_cfs), len(uh_extended))364uh_extended[:uh_length] = unit_hydrograph_cfs[:uh_length]365366# Perform discrete convolution367# Q(n) = sum(P(m) * U(n-m+1)) for m = 1 to n368direct_runoff = np.zeros(len(time_total))369for n in range(len(time_total)):370for m in range(n + 1):371if m < len(excess_extended) and (n - m) < len(uh_extended):372direct_runoff[n] += excess_extended[m] * uh_extended[n - m]373374# Calculate peak discharge and time to peak375peak_discharge = np.max(direct_runoff)376time_to_peak = time_total[np.argmax(direct_runoff)]377378# Calculate runoff volume379runoff_volume_cf = np.sum(direct_runoff) * dt * 3600 # cubic feet380runoff_volume_inches = runoff_volume_cf / (drainage_area * 640 * 43560)381382# Add baseflow (simplified constant baseflow)383baseflow = 15.0 # cfs384total_streamflow = direct_runoff + baseflow385386# Calculate centroid of excess rainfall and runoff387excess_centroid = np.sum(time_series[:len(excess_incremental)] * excess_incremental) / np.sum(excess_incremental) if np.sum(excess_incremental) > 0 else 0388runoff_centroid = np.sum(time_total * direct_runoff * dt) / np.sum(direct_runoff * dt) if np.sum(direct_runoff * dt) > 0 else 0389lag_time_computed = runoff_centroid - excess_centroid390391# Plot direct runoff hydrograph392fig3, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))393394# Rainfall and runoff395ax1_twin = ax1.twinx()396ax1_twin.bar(time_series, rainfall_incremental / dt, width=dt*0.9,397color='steelblue', alpha=0.4, edgecolor='black', linewidth=0.5)398ax1_twin.bar(time_series, excess_incremental / dt, width=dt*0.9,399color='darkred', alpha=0.5, edgecolor='black', linewidth=0.7)400ax1_twin.set_ylabel('Rainfall intensity (in/hr)', fontsize=11, color='steelblue')401ax1_twin.tick_params(axis='y', labelcolor='steelblue')402ax1_twin.set_ylim(0, np.max(rainfall_incremental / dt) * 2.5)403ax1_twin.invert_yaxis()404405ax1.fill_between(time_total, 0, direct_runoff, color='navy', alpha=0.3, label='Direct runoff')406ax1.plot(time_total, direct_runoff, 'b-', linewidth=2.5, label='Direct runoff hydrograph')407ax1.axvline(x=time_to_peak, color='red', linestyle='--', linewidth=1.5,408label=f'Time to peak = {time_to_peak:.2f} hr')409ax1.axhline(y=peak_discharge, color='red', linestyle=':', linewidth=1.5, alpha=0.7)410ax1.scatter([time_to_peak], [peak_discharge], s=120, c='red', zorder=5,411edgecolor='black', linewidth=1.5)412ax1.annotate(f'$Q_p$ = {peak_discharge:.0f} cfs',413xy=(time_to_peak, peak_discharge), xytext=(time_to_peak + 1.5, peak_discharge * 0.85),414arrowprops=dict(arrowstyle='->', color='red', lw=1.5),415fontsize=12, color='red', weight='bold')416417ax1.set_xlabel('Time (hours)', fontsize=11)418ax1.set_ylabel('Discharge (cfs)', fontsize=11)419ax1.set_title('Direct Runoff Hydrograph from Convolution of Excess Rainfall with Unit Hydrograph',420fontsize=13)421ax1.legend(fontsize=10, loc='upper right')422ax1.grid(True, alpha=0.3)423ax1.set_xlim(0, storm_duration + base_time_uh)424ax1.set_ylim(0, peak_discharge * 1.3)425426# Total streamflow with baseflow427ax2.fill_between(time_total, baseflow, total_streamflow, color='navy', alpha=0.3, label='Direct runoff')428ax2.fill_between(time_total, 0, baseflow, color='lightblue', alpha=0.5, label='Baseflow')429ax2.plot(time_total, total_streamflow, 'b-', linewidth=2.5, label='Total streamflow')430ax2.plot(time_total, np.ones_like(time_total) * baseflow, 'c--', linewidth=1.5, label=f'Baseflow = {baseflow} cfs')431ax2.axvline(x=time_to_peak, color='red', linestyle='--', linewidth=1.5, alpha=0.7)432ax2.scatter([time_to_peak], [peak_discharge + baseflow], s=120, c='red', zorder=5,433edgecolor='black', linewidth=1.5)434435ax2.set_xlabel('Time (hours)', fontsize=11)436ax2.set_ylabel('Discharge (cfs)', fontsize=11)437ax2.set_title(f'Total Streamflow Hydrograph (Direct Runoff + Baseflow)', fontsize=13)438ax2.legend(fontsize=10, loc='upper right')439ax2.grid(True, alpha=0.3)440ax2.set_xlim(0, storm_duration + base_time_uh)441ax2.set_ylim(0, (peak_discharge + baseflow) * 1.2)442443plt.tight_layout()444plt.savefig('rainfall_runoff_hydrograph.pdf', dpi=150, bbox_inches='tight')445plt.close()446\end{pycode}447448\begin{figure}[htbp]449\centering450\includegraphics[width=0.95\textwidth]{rainfall_runoff_hydrograph.pdf}451\caption{Direct runoff hydrograph generated by discrete convolution of excess rainfall452with the unit hydrograph (top panel) and complete streamflow hydrograph including baseflow453(bottom panel). The peak discharge $Q_p$ = \py{f"{peak_discharge:.0f}"} cfs occurs at454$t_p$ = \py{f"{time_to_peak:.2f}"} hours, demonstrating the lag between peak rainfall455intensity and peak watershed response. The computed lag time is \py{f"{lag_time_computed:.2f}"}456hours, measured between the centroids of excess rainfall and direct runoff. Total runoff457volume is \py{f"{runoff_volume_inches:.2f}"} inches, which matches the excess rainfall458calculated by the SCS-CN method, validating the convolution procedure. The hydrograph shape459exhibits rapid rise following intense rainfall, sustained peak during the main storm period,460and exponential recession characteristic of the Nash cascade routing. Baseflow contribution461of \py{baseflow} cfs represents the pre-storm groundwater contribution to streamflow.}462\label{fig:runoff_hydrograph}463\end{figure}464465\section{Sensitivity Analysis}466467\subsection{Effect of Curve Number on Runoff}468469The curve number exerts strong control on runoff generation, with small changes in CN470producing significant changes in total runoff volume and peak discharge. We analyze471watershed response across a range of curve numbers representing different land use472conditions, from forested areas (low CN) to highly urbanized basins (high CN). This473sensitivity is particularly important for assessing the hydrologic impacts of land474development and urban sprawl.475476\begin{pycode}477# Analyze sensitivity to curve number478CN_values = [60, 65, 70, 75, 80, 85, 90] # Range from forest to urban479colors_cn = plt.cm.viridis(np.linspace(0.1, 0.9, len(CN_values)))480481fig4, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(14, 10))482483# Store results for each CN484peak_discharges_cn = []485runoff_coeffs = []486times_to_peak_cn = []487488for i, CN_test in enumerate(CN_values):489# Calculate excess rainfall for this CN490S_test = 1000/CN_test - 10491Ia_test = 0.2 * S_test492493excess_test = np.zeros_like(cum_rainfall_series)494for j in range(len(cum_rainfall_series)):495P = cum_rainfall_series[j]496if P > Ia_test:497Q = ((P - Ia_test)**2) / (P - Ia_test + S_test)498excess_test[j] = Q499500excess_incr_test = np.diff(excess_test, prepend=0)501502# Convolution503excess_ext_test = np.zeros(len(time_total))504excess_ext_test[:len(excess_incr_test)] = excess_incr_test505506runoff_test = np.zeros(len(time_total))507for n in range(len(time_total)):508for m in range(n + 1):509if m < len(excess_ext_test) and (n - m) < len(uh_extended):510runoff_test[n] += excess_ext_test[m] * uh_extended[n - m]511512peak_q = np.max(runoff_test)513peak_discharges_cn.append(peak_q)514runoff_coeffs.append(excess_test[-1] / total_rainfall if total_rainfall > 0 else 0)515times_to_peak_cn.append(time_total[np.argmax(runoff_test)])516517# Plot hydrograph518ax1.plot(time_total, runoff_test, color=colors_cn[i], linewidth=2,519label=f'CN = {CN_test}', alpha=0.8)520521# Plot cumulative runoff522ax2.plot(time_total, np.cumsum(runoff_test) * dt * 3600 / (drainage_area * 640 * 43560),523color=colors_cn[i], linewidth=2, label=f'CN = {CN_test}', alpha=0.8)524525# Peak discharge vs CN526ax3.plot(CN_values, peak_discharges_cn, 'o-', color='darkblue', linewidth=2.5,527markersize=8, markerfacecolor='steelblue', markeredgecolor='black', markeredgewidth=1.5)528ax3.set_xlabel('Curve Number (CN)', fontsize=11)529ax3.set_ylabel('Peak discharge (cfs)', fontsize=11)530ax3.set_title('Peak Discharge vs. Curve Number', fontsize=12)531ax3.grid(True, alpha=0.3)532533# Runoff coefficient vs CN534ax4.plot(CN_values, runoff_coeffs, 's-', color='darkred', linewidth=2.5,535markersize=8, markerfacecolor='coral', markeredgecolor='black', markeredgewidth=1.5)536ax4.set_xlabel('Curve Number (CN)', fontsize=11)537ax4.set_ylabel('Runoff coefficient', fontsize=11)538ax4.set_title('Runoff Coefficient vs. Curve Number', fontsize=12)539ax4.grid(True, alpha=0.3)540ax4.set_ylim(0, 1)541542ax1.set_xlabel('Time (hours)', fontsize=11)543ax1.set_ylabel('Discharge (cfs)', fontsize=11)544ax1.set_title('Effect of Curve Number on Hydrograph Shape', fontsize=12)545ax1.legend(fontsize=9, loc='upper right')546ax1.grid(True, alpha=0.3)547ax1.set_xlim(0, 15)548549ax2.set_xlabel('Time (hours)', fontsize=11)550ax2.set_ylabel('Cumulative runoff depth (inches)', fontsize=11)551ax2.set_title('Cumulative Direct Runoff Depth', fontsize=12)552ax2.legend(fontsize=9, loc='lower right')553ax2.grid(True, alpha=0.3)554ax2.set_xlim(0, 15)555556plt.tight_layout()557plt.savefig('rainfall_runoff_cn_sensitivity.pdf', dpi=150, bbox_inches='tight')558plt.close()559560# Calculate CN sensitivity metrics561CN_mid_idx = len(CN_values) // 2562dQ_dCN = (peak_discharges_cn[-1] - peak_discharges_cn[0]) / (CN_values[-1] - CN_values[0])563relative_change = (peak_discharges_cn[-1] - peak_discharges_cn[0]) / peak_discharges_cn[0] * 100564\end{pycode}565566\begin{figure}[htbp]567\centering568\includegraphics[width=0.98\textwidth]{rainfall_runoff_cn_sensitivity.pdf}569\caption{Sensitivity of watershed response to curve number variation from CN = 60 (forested,570permeable soils) to CN = 90 (heavily urbanized, impervious surfaces). Top left panel shows571direct runoff hydrographs demonstrating dramatic increases in peak discharge and runoff volume572with increasing CN. Top right panel displays cumulative runoff depth, illustrating how573urbanization increases total runoff. Bottom panels quantify peak discharge sensitivity574(slope = \py{f"{dQ_dCN:.1f}"} cfs per CN unit) and runoff coefficient progression from575\py{f"{runoff_coeffs[0]:.2f}"} to \py{f"{runoff_coeffs[-1]:.2f}"}. The \py{f"{relative_change:.0f}"}\%576increase in peak discharge from CN = 60 to CN = 90 demonstrates the profound hydrologic impact577of urbanization, with corresponding increases in flood risk and reduced groundwater recharge.}578\label{fig:cn_sensitivity}579\end{figure}580581\subsection{Effect of Time of Concentration}582583Time of concentration affects both the unit hydrograph shape and watershed response timing.584Shorter times of concentration, typical of urbanized or steep watersheds, produce higher,585sharper peaks with reduced lag time. Longer times of concentration, characteristic of flat586rural watersheds with longer flow paths, produce attenuated hydrographs with delayed peaks.587We examine this sensitivity by varying the Nash model storage coefficient while maintaining588constant excess rainfall.589590\begin{pycode}591# Analyze sensitivity to time of concentration592tc_values = [0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8] # hours593colors_tc = plt.cm.plasma(np.linspace(0.1, 0.9, len(tc_values)))594595fig5, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(14, 10))596597peak_discharges_tc = []598times_to_peak_tc = []599600for i, tc_test in enumerate(tc_values):601# Recalculate unit hydrograph with new tc602lag_test = 0.6 * tc_test603K_test = lag_test / (N_reservoirs - 1) if N_reservoirs > 1 else lag_test604605iuh_test = np.array([nash_iuh(t, K_test, N_reservoirs) for t in time_uh])606uh_test = iuh_test * dt607uh_sum_test = np.sum(uh_test)608if uh_sum_test > 0:609uh_test = uh_test / uh_sum_test610uh_test_cfs = uh_test * conversion_factor611612# Extend for convolution613uh_ext_test = np.zeros(len(time_total))614uh_length_test = min(len(uh_test_cfs), len(uh_ext_test))615uh_ext_test[:uh_length_test] = uh_test_cfs[:uh_length_test]616617# Convolution with original excess rainfall618runoff_tc_test = np.zeros(len(time_total))619for n in range(len(time_total)):620for m in range(n + 1):621if m < len(excess_extended) and (n - m) < len(uh_ext_test):622runoff_tc_test[n] += excess_extended[m] * uh_ext_test[n - m]623624peak_q_tc = np.max(runoff_tc_test)625peak_discharges_tc.append(peak_q_tc)626times_to_peak_tc.append(time_total[np.argmax(runoff_tc_test)])627628# Plot unit hydrograph629ax1.plot(time_uh, uh_test_cfs, color=colors_tc[i], linewidth=2,630label=f'$t_c$ = {tc_test} hr', alpha=0.8)631632# Plot runoff hydrograph633ax2.plot(time_total, runoff_tc_test, color=colors_tc[i], linewidth=2,634label=f'$t_c$ = {tc_test} hr', alpha=0.8)635636# Peak discharge vs tc637ax3.plot(tc_values, peak_discharges_tc, 'o-', color='darkblue', linewidth=2.5,638markersize=8, markerfacecolor='steelblue', markeredgecolor='black', markeredgewidth=1.5)639ax3.set_xlabel('Time of concentration (hours)', fontsize=11)640ax3.set_ylabel('Peak discharge (cfs)', fontsize=11)641ax3.set_title('Peak Discharge vs. Time of Concentration', fontsize=12)642ax3.grid(True, alpha=0.3)643644# Time to peak vs tc645ax4.plot(tc_values, times_to_peak_tc, 's-', color='darkred', linewidth=2.5,646markersize=8, markerfacecolor='coral', markeredgecolor='black', markeredgewidth=1.5)647ax4.plot(tc_values, tc_values, 'k--', linewidth=1.5, alpha=0.5, label='1:1 line')648ax4.set_xlabel('Time of concentration (hours)', fontsize=11)649ax4.set_ylabel('Time to peak discharge (hours)', fontsize=11)650ax4.set_title('Time to Peak vs. Time of Concentration', fontsize=12)651ax4.legend(fontsize=10)652ax4.grid(True, alpha=0.3)653654ax1.set_xlabel('Time (hours)', fontsize=11)655ax1.set_ylabel('Discharge (cfs per inch)', fontsize=11)656ax1.set_title('Unit Hydrographs for Different $t_c$', fontsize=12)657ax1.legend(fontsize=9, loc='upper right')658ax1.grid(True, alpha=0.3)659ax1.set_xlim(0, 8)660661ax2.set_xlabel('Time (hours)', fontsize=11)662ax2.set_ylabel('Discharge (cfs)', fontsize=11)663ax2.set_title('Runoff Hydrographs for Different $t_c$', fontsize=12)664ax2.legend(fontsize=9, loc='upper right')665ax2.grid(True, alpha=0.3)666ax2.set_xlim(0, 15)667668plt.tight_layout()669plt.savefig('rainfall_runoff_tc_sensitivity.pdf', dpi=150, bbox_inches='tight')670plt.close()671672# Calculate inverse relationship strength673from scipy.stats import linregress674slope_tc, intercept_tc, r_tc, p_tc, se_tc = linregress(tc_values, peak_discharges_tc)675\end{pycode}676677\begin{figure}[htbp]678\centering679\includegraphics[width=0.98\textwidth]{rainfall_runoff_tc_sensitivity.pdf}680\caption{Sensitivity of watershed response to time of concentration $t_c$ ranging from6810.6 hours (highly urbanized, steep watershed) to 1.8 hours (rural, mild slopes). Top left682shows unit hydrographs becoming more attenuated and delayed with increasing $t_c$. Top right683displays corresponding runoff hydrographs exhibiting the inverse relationship between $t_c$684and peak discharge. Bottom left quantifies this relationship with regression slope685\py{f"{slope_tc:.1f}"} cfs/hour (R² = \py{f"{r_tc**2:.3f}"}), demonstrating that shorter686concentration times produce \py{f"{abs(peak_discharges_tc[0] - peak_discharges_tc[-1]):.0f}"}687cfs higher peaks. Bottom right shows time to peak increases approximately linearly with $t_c$,688though storm timing also influences this relationship. These results have critical implications689for urban drainage design and flood mitigation.}690\label{fig:tc_sensitivity}691\end{figure}692693\section{Results Summary}694695\begin{pycode}696print(r"\begin{table}[htbp]")697print(r"\centering")698print(r"\caption{Summary of Rainfall-Runoff Analysis Results}")699print(r"\begin{tabular}{lcc}")700print(r"\toprule")701print(r"\textbf{Parameter} & \textbf{Value} & \textbf{Units} \\")702print(r"\midrule")703print(r"\multicolumn{3}{l}{\textit{Watershed Characteristics}} \\")704print(f"Drainage area & {drainage_area:.2f} & sq mi \\\\")705print(f"Time of concentration & {time_of_concentration:.2f} & hr \\\\")706print(f"Curve number (CN) & {CN} & --- \\\\")707print(f"Maximum retention (S) & {S_inches:.2f} & in \\\\")708print(f"Initial abstraction ($I_a$) & {Ia_inches:.2f} & in \\\\")709print(r"\midrule")710print(r"\multicolumn{3}{l}{\textit{Design Storm}} \\")711print(f"Total rainfall depth & {total_rainfall:.2f} & in \\\\")712print(f"Storm duration & {storm_duration:.1f} & hr \\\\")713print(f"Distribution type & SCS Type II & --- \\\\")714print(r"\midrule")715print(r"\multicolumn{3}{l}{\textit{Runoff Generation}} \\")716print(f"Total excess rainfall & {total_excess:.2f} & in \\\\")717print(f"Runoff coefficient & {runoff_coefficient:.3f} & --- \\\\")718print(f"Runoff volume & {runoff_volume_cf:.0f} & cu ft \\\\")719print(r"\midrule")720print(r"\multicolumn{3}{l}{\textit{Unit Hydrograph}} \\")721print(f"Nash N parameter & {N_reservoirs} & --- \\\\")722print(f"Storage coefficient (K) & {K_hours:.2f} & hr \\\\")723print(f"Peak UH discharge & {peak_uh:.0f} & cfs/in \\\\")724print(f"Time to peak (UH) & {time_to_peak_uh:.2f} & hr \\\\")725print(f"Base time & {base_time_uh:.1f} & hr \\\\")726print(r"\midrule")727print(r"\multicolumn{3}{l}{\textit{Direct Runoff Hydrograph}} \\")728print(f"Peak discharge & {peak_discharge:.0f} & cfs \\\\")729print(f"Time to peak & {time_to_peak:.2f} & hr \\\\")730print(f"Lag time & {lag_time_computed:.2f} & hr \\\\")731print(r"\bottomrule")732print(r"\end{tabular}")733print(r"\label{tab:results}")734print(r"\end{table}")735\end{pycode}736737\section{Discussion}738739\subsection{Hydrologic Insights}740741The analysis demonstrates several key principles of rainfall-runoff transformation:742743\begin{enumerate}744\item \textbf{Nonlinear losses}: The SCS-CN method captures the nonlinear relationship745between precipitation and runoff, with runoff coefficient increasing from near-zero for746small storms to asymptotically approaching $(1 - I_a/P)$ for large storms.747748\item \textbf{Watershed routing}: The Nash cascade model provides a parsimonious representation749of watershed storage and routing effects with physically meaningful parameters (N and K)750related to watershed geomorphology.751752\item \textbf{Peak attenuation}: The convolution process demonstrates how watershed storage753attenuates and delays the runoff response relative to rainfall input, with peak discharge754occurring \py{f"{lag_time_computed:.2f}"} hours after the rainfall centroid.755756\item \textbf{Land use sensitivity}: The CN sensitivity analysis quantifies the dramatic757impact of urbanization on flood potential, with peak discharge increasing by758\py{f"{relative_change:.0f}"}\% when CN increases from 60 to 90.759\end{enumerate}760761\subsection{Engineering Applications}762763These methods provide the foundation for:764765\begin{itemize}766\item \textbf{Flood frequency analysis}: Design hydrographs for culvert and bridge sizing767\item \textbf{Stormwater management}: Detention basin sizing and outlet design768\item \textbf{Urban drainage}: Storm sewer network design and analysis769\item \textbf{Regulatory compliance}: Post-development runoff not exceeding pre-development conditions770\item \textbf{Watershed planning}: Assessing hydrologic impacts of land use changes771\end{itemize}772773\subsection{Method Limitations}774775Important assumptions and limitations include:776777\begin{remark}[Model Assumptions]778\begin{itemize}779\item \textbf{Spatial uniformity}: Rainfall and watershed properties assumed spatially uniform780\item \textbf{Temporal invariance}: Unit hydrograph assumed constant for all storm events781\item \textbf{Linearity}: Superposition assumes linear watershed response782\item \textbf{Empiricism}: SCS-CN method is empirical, calibrated to agricultural watersheds783\item \textbf{Initial conditions}: Antecedent moisture significantly affects CN selection784\end{itemize}785\end{remark}786787For large or heterogeneous watersheds, distributed hydrologic models may be more appropriate.788789\section{Conclusions}790791This comprehensive analysis of rainfall-runoff transformation demonstrates the coupled792application of the SCS Curve Number method and unit hydrograph theory for watershed response793prediction. Key findings include:794795\begin{enumerate}796\item For the \py{f"{drainage_area:.1f}"} square mile urban watershed with CN = \py{CN},797the \py{total_rainfall}-inch design storm produces peak discharge $Q_p$ = \py{f"{peak_discharge:.0f}"}798cfs occurring at $t_p$ = \py{f"{time_to_peak:.2f}"} hours.799800\item The runoff coefficient of \py{f"{runoff_coefficient:.3f}"} indicates that801\py{f"{runoff_coefficient*100:.1f}"}\% of total precipitation becomes direct runoff, with802\py{f"{Ia_inches:.2f}"} inches lost to initial abstraction and \py{f"{S_inches:.2f}"}803inches to continuing infiltration and retention.804805\item The Nash cascade unit hydrograph with N = \py{N_reservoirs} reservoirs and K =806\py{f"{K_hours:.2f}"} hours accurately represents the storage-routing characteristics807of small urban watersheds, producing realistic hydrograph shape and timing.808809\item Sensitivity analysis reveals peak discharge varies from \py{f"{peak_discharges_cn[0]:.0f}"}810to \py{f"{peak_discharges_cn[-1]:.0f}"} cfs across the CN range 60-90, emphasizing the811critical importance of land use in flood generation and the need for effective stormwater812management in developing areas.813814\item Time of concentration exerts strong control on hydrograph attenuation, with the815inverse relationship between $t_c$ and peak discharge (slope = \py{f"{slope_tc:.1f}"}816cfs/hour) demonstrating why urbanization (which reduces $t_c$) amplifies flood peaks.817\end{enumerate}818819These methods provide essential tools for hydrologic engineering practice, enabling820quantitative assessment of watershed response to design storms for infrastructure planning,821flood mitigation, and environmental protection.822823\section*{References}824825\begin{enumerate}826\item Sherman, L.K. (1932). Streamflow from rainfall by the unit-graph method.827\textit{Engineering News-Record}, 108, 501-505.828829\item Soil Conservation Service (1985). \textit{National Engineering Handbook, Section 4: Hydrology}.830U.S. Department of Agriculture, Washington, D.C.831832\item Chow, V.T., Maidment, D.R., and Mays, L.W. (1988). \textit{Applied Hydrology}.833McGraw-Hill, New York.834835\item Nash, J.E. (1957). The form of the instantaneous unit hydrograph.836\textit{International Association of Scientific Hydrology, Publication}, 45(3), 114-121.837838\item Hawkins, R.H., Ward, T.J., Woodward, D.E., and Van Mullem, J.A. (2009).839\textit{Curve Number Hydrology: State of the Practice}. American Society of Civil Engineers.840841\item Natural Resources Conservation Service (2010). \textit{National Engineering Handbook,842Part 630: Hydrology}. U.S. Department of Agriculture.843844\item Dooge, J.C.I. (1973). Linear theory of hydrologic systems. \textit{Technical Bulletin845No. 1468}, Agricultural Research Service, U.S. Department of Agriculture.846847\item McCuen, R.H. (2016). \textit{Hydrologic Analysis and Design}, 4th ed. Pearson, Upper Saddle River, NJ.848849\item Singh, V.P. (1988). \textit{Hydrologic Systems: Rainfall-Runoff Modeling}, Volume I.850Prentice Hall, Englewood Cliffs, NJ.851852\item Viessman, W. and Lewis, G.L. (2003). \textit{Introduction to Hydrology}, 5th ed.853Pearson Education, Upper Saddle River, NJ.854855\item Ponce, V.M. (1989). \textit{Engineering Hydrology: Principles and Practices}.856Prentice Hall, Englewood Cliffs, NJ.857858\item USDA-NRCS (2004). Estimation of direct runoff from storm rainfall. In \textit{National859Engineering Handbook Part 630}, Chapter 10. U.S. Department of Agriculture.860861\item Mishra, S.K. and Singh, V.P. (2003). \textit{Soil Conservation Service Curve Number (SCS-CN)862Methodology}. Kluwer Academic Publishers, Dordrecht.863864\item Singh, V.P. (1992). \textit{Elementary Hydrology}. Prentice Hall, Englewood Cliffs, NJ.865866\item Hjelmfelt, A.T. (1991). Investigation of curve number procedure. \textit{Journal of867Hydraulic Engineering}, 117(6), 725-737.868869\item Mockus, V. (1949). Estimation of total (and peak rates of) surface runoff for individual870storms. \textit{Exhibit A of Appendix B, Interim Survey Report, Grand (Neosho) River Watershed},871U.S. Department of Agriculture.872873\item Snyder, F.F. (1938). Synthetic unit-graphs. \textit{Transactions of the American Geophysical874Union}, 19, 447-454.875876\item U.S. Army Corps of Engineers (2000). \textit{Hydrologic Modeling System HEC-HMS: Technical877Reference Manual}. Hydrologic Engineering Center, Davis, CA.878879\item Singh, V.P. and Frevert, D.K. (2006). \textit{Watershed Models}. CRC Press, Boca Raton, FL.880881\item Beven, K.J. (2012). \textit{Rainfall-Runoff Modelling: The Primer}, 2nd ed. Wiley-Blackwell,882Chichester, UK.883\end{enumerate}884885\end{document}886887888