Stage-Volume relationships expresses the relationship between lake surface elevation and the amount of water stored in the lake. For most flow and rule curve calculations, the most important feature of the stage-volume relationship is the change in lake volume associated with a change in lake volume.
This notebook displays stage-volume relationship data for Rainy Lake and Namakan Reservoir obtained from
Thompson, A.F. (2013). Rainy and Namakan Hydrologic Response Model Documentation. Prepared for the Evaluation of the International Joint Commission 2000 Order for Rainy and Namakan Lakes and Rainy River.
The data is fitted to a polynomial function to create a dictionary of interpolation functions
volume[key]()
and differentiated to create a dictionary of area functions
area[key]()
These are pickled and stored in the data directory in files of the same name.
Initilization of the graphics system and computational modules used in this IPython notebook.
# Display graphics inline with the notebook
%matplotlib inline
# Standard Python modules
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import os
import datetime
import seaborn as sns
sns.set_context('talk')
# Modules to display images and data tables
from IPython.display import Image
from IPython.core.display import display
# Data directory
dir = '../data/'
img = '../images/'
The following data is extracted from Tables 1 and 2 of the Thompson report. Evidently these data were extracted from a 1932 stage/volume curve derived from earlier hydrographic measurements of the lakes.
The data is stored here in a dictionary constructed as key, dataframe pairs. (this is the old data. We want to add a new data set, then compare new versus old estimates of area as function of lake level.).
data = {}
data['Rainy Lake'] = pd.DataFrame(
[[335.0, 112.67],
[336.0, 798.00],
[336.5, 1176.42],
[337.0, 1577.25],
[337.5, 2002.06],
[338.0, 2450.57],
[339.0, 3416.85],
[340.0, 4458.97]],
columns = ['stage','volume'])
data['Namakan Reservoir'] = pd.DataFrame(
[[337.0, 65.33],
[338.0, 259.95],
[338.5, 364.20],
[339.0, 475.58],
[339.5, 592.46],
[340.0, 712.28],
[340.5, 836.56],
[341.0, 966.17],
[341.5, 1099.79],
[342.0, 1239.68],
[343.0, 1540.75]],
columns = ['stage','volume'])
Everything from this point on should be automatic and require no editing.
import matplotlib.cm as cm
colors = dict(zip(data.keys(),cm.rainbow(np.linspace(0, 1, len(data)))))
plt.figure(figsize=(10,6))
axes = plt.subplot()
for key in data.keys():
data[key].plot(
x = 'stage',
y = 'volume',
kind='scatter',
color = colors[key],
s=50, marker='d',
ax = axes)
plt.xlabel('Stage [m]')
plt.ylabel('Volume [million m^3]')
plt.title('Stage-Volume Relationship - Thompson')
plt.legend(data.keys(),loc='upper left')
plt.xlim([334,344])
plt.ylim([0,5000]);
data['Rainy Lake - Morin'] = pd.DataFrame(
[[335.5, 7194.67197, 719.271],
[336.0, 7570.67329, 770.153],
[336.5, 7957.68641, 794.916],
[337.0, 8358.73022, 833.198],
[337.5, 8779.56914, 919.860],
[338.0, 9244.10878, 966.400],
[338.6, 9826.74905, 1011.093],
[339.3, 10533.87720, 1048.357]],
columns = ['stage','volume', 'area'])
dV = 7570.67329 - 798.0
data['Rainy Lake - Morin']['volume'] += -dV
data['Namakan Reservoir - Morin'] = pd.DataFrame(
[[337.0, 65.33],
[338.0, 259.95],
[338.5, 364.20],
[339.0, 475.58],
[339.5, 592.46],
[340.0, 712.28],
[340.5, 836.56],
[341.0, 966.17],
[341.5, 1099.79],
[342.0, 1239.68],
[343.0, 1540.75]],
columns = ['stage','volume'])
import matplotlib.cm as cm
colors = dict(zip(data.keys(),cm.rainbow(np.linspace(0, 1, len(data)))))
plt.figure(figsize=(10,6))
axes = plt.subplot()
for key in data.keys():
data[key].plot(
x = 'stage',
y = 'volume',
kind='scatter',
color = colors[key],
s=50, marker='d',
ax = axes)
plt.xlabel('Stage [m]')
plt.ylabel('Volume [million m^3]')
plt.title('Stage-Volume Relationship - Thompson')
plt.legend(data.keys(),loc='upper left')
plt.xlim([334,344])
#plt.ylim([0,5000]);
(334, 344)
Numpy provides functions to fit data to a polynomial of arbitrary degree, and to create a 1d interpolation based on the result.
volume = {}
for key in data.keys():
volume[key] = np.poly1d(np.polyfit(data[key]['stage'],data[key]['volume'],2))
print("\n",key,"\n",volume[key])
Rainy Lake 2 45.37 x - 2.975e+04 x + 4.876e+06 Namakan Reservoir 2 10.14 x - 6653 x + 1.09e+06 Rainy Lake - Morin 2 45.84 x - 3.006e+04 x + 4.924e+06 Namakan Reservoir - Morin 2 10.14 x - 6653 x + 1.09e+06
plt.figure(figsize=(10,6))
axes = plt.subplot()
for key in data.keys():
data[key].plot(
x = 'stage',
y = 'volume',
kind='scatter',
color = colors[key],
s=50, marker='d',
ax = axes)
h = np.linspace(data[key]['stage'].min(),data[key]['stage'].max())
plt.plot(h,volume[key](h),color=colors[key])
plt.xlabel('Stage [m]')
plt.ylabel('Volume [million m^3]')
plt.title('Stage-Volume Relationship')
plt.legend(data.keys(),loc='upper left')
plt.xlim([334,344])
plt.ylim([0,5000]);
plt.savefig('../images/Stage-Volume.png')
The stage-area relationship expresses the dependence of lake area on lake elevation.
area = {}
for key in data.keys():
area[key] = volume[key].deriv()
print("\n",key,"\n",area[key])
Rainy Lake 90.73 x - 2.975e+04 Namakan Reservoir 20.29 x - 6653 Rainy Lake - Morin 91.68 x - 3.006e+04 Namakan Reservoir - Morin 20.29 x - 6653
plt.figure(figsize=(10,6))
axes = plt.subplot()
for key in data.keys():
h = np.linspace(data[key]['stage'].min(),data[key]['stage'].max())
plt.plot(h,area[key](h),color=colors[key])
plt.xlabel('Stage [m]')
plt.ylabel('Area [km^2]')
plt.title('Stage-Area Relationship')
plt.legend(data.keys(),loc='upper left')
plt.xlim([334,344])
(334, 344)
import pickle
with open(dir + 'area.pkl', 'wb') as handle:
pickle.dump(area, handle)
with open(dir + 'area.pkl', 'rb') as handle:
area = pickle.load(handle)
Under the emergency high water level for Rainy Lake under the 2000 Rule Curve is 337.5 meters.
file = open(dir + 'area.pkl', 'rb')
area = pickle.load(file)
file.close()
display(area)
h_ehw = 337.90
a_ehw = area['Rainy Lake'](h_ehw)
h_nl = 340.95
a_nl = area['Namakan Reservoir'](h_nl)
print(a_nl)
print('Area of area at Emergency High Water =', a_ehw, 'km^2')
{'Namakan Reservoir': poly1d([ 20.28853147, -6652.59327511]), 'Namakan Reservoir - Morin': poly1d([ 20.28853147, -6652.59327511]), 'Rainy Lake': poly1d([ 90.73298003, -29751.96877493]), 'Rainy Lake - Morin': poly1d([ 91.68112663, -30055.98839021])}
264.781529137 Area of area at Emergency High Water = 906.705177419 km^2
file = open(dir + 'volume.pkl', 'rb')
volume = pickle.load(file)
file.close()
display(volume)
h_ehw = 337.75
h_ago = 337.90
v_ehw = volume['Rainy Lake'](h_ehw)
v_ago = volume['Rainy Lake'](h_ago)
print('Volume of Rainy lake between EHW and EGO =', v_ago-v_ehw, 'million m^3')
--------------------------------------------------------------------------- UnicodeDecodeError Traceback (most recent call last) <ipython-input-13-dedc70ca5d32> in <module>() 1 file = open(dir + 'volume.pkl', 'rb') ----> 2 volume = pickle.load(file) 3 file.close() 4 5 display(volume) UnicodeDecodeError: 'ascii' codec can't decode byte 0xe9 in position 4: ordinal not in range(128)
Assuming a net outflow of 1000 cubic meters/sec,
dv = (v_ago - v_ehw)*1.0e6
dt = dv/1000.0/86400.0
print('Time to empty =', dt, 'days')
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-13-9b4b85169584> in <module>() ----> 1 dv = (v_ago - v_ehw)*1.0e6 2 dt = dv/1000.0/86400.0 3 4 print('Time to empty =', dt, 'days') NameError: name 'v_ago' is not defined
lrc = 336.80
urc = 337.75
a = 100*(area['Rainy Lake'](urc) - area['Rainy Lake'](lrc))/area['Rainy Lake'](lrc)
print("Area of Rainy lake increases by {:4.3f}% between low and high water of the 2000 rule curve order.".format(a))
Area of Rainy lake increases by 10.682% between low and high water of the 2000 rule curve order.
lrc = 336.80
urc = 338.745
a = 100*(area['Rainy Lake'](urc) - area['Rainy Lake'](lrc))/area['Rainy Lake'](lrc)
print("Area of Rainy lake increases by {:4.3f}% between low and high water of the 2000 rule curve order.".format(a))
Area of Rainy lake increases by 21.871% between low and high water of the 2000 rule curve order.