# Display graphics inline with the notebook
%matplotlib inline
# Standard Python modules
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.dates as mdates
import pandas as pd
import os
import datetime
# Modules to display images and data tables
from IPython.display import Image
from IPython.core.display import display
# set graphics context
sns.set_context('talk')
# directories
dir = '../data/'
img = '../images/'
# plot rule curve with a specified color
def plotRC(RC,color,alpha=0.5):
plt.plot(RC.index,RC['EHW'],color=color,alpha=alpha)
plt.plot(RC.index,RC['ELW'],color=color,alpha=alpha)
plt.plot(RC.index,RC['AGO'],color+'--',alpha=alpha)
RC['LRC'].plot(color=color,lw=3,alpha=alpha)
RC['URC'].plot(color=color,lw=3,alpha=alpha)
if 'EDL' in RC.columns:
RC['EDL'].plot(color=color,lw=3,alpha=alpha)
plt.fill_between(RC.index,
RC['LRC'].tolist(),
RC['URC'].tolist(),
color=color, alpha=alpha)
plt.ylabel('meters')
plt.ylim(336,341.5)
plt.gca().xaxis.set_major_locator(mdates.MonthLocator())
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b'))
# add right hand y-axis scaled in feet
def twiny():
ax1 = plt.gca()
locs = ax1.get_yticks()
y1,y2 = ax1.get_ylim()
ax2 = plt.twinx()
ax2.set_ylim(y1,y2)
lbls = ['{0:.2f}'.format(y*3.2808) for y in locs]
ax2.set_yticklabels(lbls)
plt.grid(None)
ax2.set_ylabel('feet')
def saveRC(fname):
fname = img + fname
plt.savefig(fname)
!convert $fname -trim $fname
# Generic Year to represent data
yr = 2014
# Rainy Lake
RL1949 = {
datetime.datetime(yr, 1, 1): [1104.61, 1107.11, 1107.11, 1108.11, 1108.61],
datetime.datetime(yr, 2, 1): [1104.61, 1106.61, 1106.61, 1108.11, 1108.61],
datetime.datetime(yr, 3, 1): [1104.61, 1105.61, 1105.61, 1108.11, 1108.61],
datetime.datetime(yr, 4, 1): [1104.61, 1104.61, 1104.61, 1108.11, 1108.61],
datetime.datetime(yr, 5, 1): [1104.61, 1106.61, 1106.61, 1108.11, 1108.61],
datetime.datetime(yr, 6, 1): [1104.61, 1107.61, 1107.61, 1108.11, 1108.61],
datetime.datetime(yr, 7, 1): [1104.61, 1108.11, 1108.11, 1108.11, 1108.61],
datetime.datetime(yr, 8, 1): [1104.61, 1108.11, 1108.11, 1108.11, 1108.61],
datetime.datetime(yr, 9, 1): [1104.61, 1108.11, 1108.11, 1108.11, 1108.61],
datetime.datetime(yr,10, 1): [1104.61, 1108.11, 1108.11, 1108.11, 1108.61],
datetime.datetime(yr,11, 1): [1104.61, 1108.11, 1108.11, 1108.11, 1108.61],
datetime.datetime(yr,12, 1): [1104.61, 1107.61, 1107.61, 1108.11, 1108.61],
datetime.datetime(yr,12,31): [1104.61, 1107.11, 1107.11, 1108.11, 1108.61]
}
RL1949 = pd.DataFrame.from_dict(RL1949).transpose()/3.2808
RL1949.columns = ['ELW','LRC','URC','EHW','AGO']
RL1949 = RL1949.resample(rule='1D').interpolate()
# Namakan Lake
NL1949 = {
datetime.datetime(yr, 1, 1): [1108.61, 1113.61, 1113.61, 1118.61, 1119.1],
datetime.datetime(yr, 2, 1): [1108.61, 1111.91, 1111.91, 1118.61, 1119.1],
datetime.datetime(yr, 3, 1): [1108.61, 1110.31, 1110.31, 1118.61, 1119.1],
datetime.datetime(yr, 4, 1): [1108.61, 1108.61, 1108.61, 1118.61, 1119.1],
datetime.datetime(yr, 5, 1): [1108.61, 1111.91, 1111.91, 1118.61, 1119.1],
datetime.datetime(yr, 6, 1): [1108.61, 1115.31, 1115.31, 1118.61, 1119.1],
datetime.datetime(yr, 7, 1): [1108.61, 1118.61, 1118.61, 1118.61, 1119.1],
datetime.datetime(yr, 8, 1): [1108.61, 1118.61, 1118.61, 1118.61, 1119.1],
datetime.datetime(yr, 9, 1): [1108.61, 1118.61, 1118.61, 1118.61, 1119.1],
datetime.datetime(yr,10, 1): [1108.61, 1118.61, 1118.61, 1118.61, 1119.1],
datetime.datetime(yr,11, 1): [1108.61, 1116.91, 1116.91, 1118.61, 1119.1],
datetime.datetime(yr,12, 1): [1108.61, 1115.31, 1115.31, 1118.61, 1119.1],
datetime.datetime(yr,12,31): [1108.61, 1113.61, 1113.61, 1118.61, 1119.1]
}
NL1949 = pd.DataFrame.from_dict(NL1949).transpose()/3.2808
NL1949.columns = ['ELW','LRC','URC','EHW','AGO']
NL1949 = NL1949.resample(rule='1D').interpolate()
plt.figure(figsize=(10,6))
plotRC(NL1949,'b')
plotRC(RL1949,'r')
twiny()
plt.title('Rule Curves for Namakan and Rainy Lakes: 1949-1957')
saveRC('RuleCurve1949.png')
The adjustments that created the 1957 rule curve orders were based on the following conclusions:
# Generic Year to represent data
yr = 2014
# Rainy Lake
RL1957 = RL1949.copy()
# Namakan Lake
NL1957 = {
datetime.datetime(yr, 1, 1): [1108.61, 1113.61, 1115.27, 1118.61, 1119.1],
datetime.datetime(yr, 2, 1): [1108.61, 1111.91, 1114.14, 1118.61, 1119.1],
datetime.datetime(yr, 3, 1): [1108.61, 1110.31, 1113.13, 1118.61, 1119.1],
datetime.datetime(yr, 4, 1): [1108.61, 1108.61, 1112.00, 1118.61, 1119.1],
datetime.datetime(yr, 4,21): [1108.61, 1110.91, 1112.00, 1118.61, 1119.1],
datetime.datetime(yr, 5, 1): [1108.61, 1111.91, 1113.61, 1118.61, 1119.1],
datetime.datetime(yr, 6, 1): [1108.61, 1115.31, 1118.61, 1118.61, 1119.1],
datetime.datetime(yr, 7, 1): [1108.61, 1118.61, 1118.61, 1118.61, 1119.1],
datetime.datetime(yr, 8, 1): [1108.61, 1118.61, 1118.61, 1118.61, 1119.1],
datetime.datetime(yr, 9, 1): [1108.61, 1118.61, 1118.61, 1118.61, 1119.1],
datetime.datetime(yr,10, 1): [1108.61, 1118.61, 1118.61, 1118.61, 1119.1],
datetime.datetime(yr,11, 1): [1108.61, 1116.91, 1117.48, 1118.61, 1119.1],
datetime.datetime(yr,12, 1): [1108.61, 1115.31, 1116.39, 1118.61, 1119.1],
datetime.datetime(yr,12,31): [1108.61, 1113.61, 1116.39, 1118.61, 1119.1]
}
NL1957 = pd.DataFrame.from_dict(NL1957).transpose()/3.2808
NL1957.columns = ['ELW','LRC','URC','EHW','AGO']
NL1957 = NL1957.resample(rule='1D').interpolate()
plt.figure(figsize=(10,6))
plotRC(NL1957,'b')
plotRC(RL1957,'r')
twiny()
plt.title('Rule Curves for Namakan and Rainy Lakes: 1957-1970')
saveRC('RuleCurve1957.png')
Text of the 1970 Rule Curve rule curve order
# Generic Year to represent data
yr = 2014
# Rainy Lake
RL1970 = {
datetime.datetime(yr, 1, 1): [1104.6, 1106.6, 1107.1, 1108.1, 1108.6],
datetime.datetime(yr, 2, 1): [1104.6, 1105.8, 1106.6, 1108.1, 1108.6],
datetime.datetime(yr, 3, 1): [1104.6, 1105.2, 1106.2, 1108.1, 1108.6],
datetime.datetime(yr, 4, 1): [1104.6, 1104.6, 1105.6, 1108.1, 1108.6],
datetime.datetime(yr, 4,21): [1104.6, 1104.6, 1106.2, 1108.1, 1108.6],
datetime.datetime(yr, 5, 1): [1104.6, 1105.1, 1106.6, 1108.1, 1108.6],
datetime.datetime(yr, 6, 1): [1104.6, 1106.6, 1107.6, 1108.1, 1108.6],
datetime.datetime(yr, 7, 1): [1104.6, 1107.4, 1108.1, 1108.1, 1108.6],
datetime.datetime(yr, 8, 1): [1104.6, 1107.4, 1108.1, 1108.1, 1108.6],
datetime.datetime(yr, 9, 1): [1104.6, 1107.4, 1108.1, 1108.1, 1108.6],
datetime.datetime(yr,10, 1): [1104.6, 1107.4, 1108.1, 1108.1, 1108.6],
datetime.datetime(yr,10,11): [1104.6, 1107.4, 1108.1, 1108.1, 1108.6],
datetime.datetime(yr,11, 1): [1104.6, 1107.2, 1108.1, 1108.1, 1108.6],
datetime.datetime(yr,12, 1): [1104.6, 1106.8, 1107.6, 1108.1, 1108.6],
datetime.datetime(yr,12,31): [1104.6, 1106.4, 1107.1, 1108.1, 1108.6]
}
RL1970 = pd.DataFrame.from_dict(RL1970).transpose()/3.2808
RL1970.columns = ['ELW','LRC','URC','EHW','AGO']
# print rule curve in format portable to Simulink 1D Table Lookup
# print("Breakpoints: ", RL1970.index.dayofyear, "\n")
# print("LRC: [" + ", ".join(["{0:.2f}".format(d) for d in RL1970['LRC']]) + "]\n")
# print("URC: [" + ", ".join(["{0:.2f}".format(d) for d in RL1970['URC']]) + "]\n")
RL1970 = RL1970.resample(rule='1D').interpolate()
# Namakan Lake
NL1970 = {
datetime.datetime(yr, 1, 1): [1108.6, 1113.6, 1115.3, 1118.6, 1119.1],
datetime.datetime(yr, 2, 1): [1108.6, 1111.9, 1114.1, 1118.6, 1119.1],
datetime.datetime(yr, 3, 1): [1108.6, 1110.3, 1113.1, 1118.6, 1119.1],
datetime.datetime(yr, 4, 1): [1108.6, 1108.6, 1112.0, 1118.6, 1119.1],
datetime.datetime(yr, 4,21): [1108.6, 1108.6, 1113.1, 1118.6, 1119.1],
datetime.datetime(yr, 5, 1): [1108.6, 1110.2, 1113.6, 1118.6, 1119.1],
datetime.datetime(yr, 6, 1): [1108.6, 1115.3, 1116.6, 1118.6, 1119.1],
datetime.datetime(yr, 6,21): [1108.6, 1117.5, 1118.6, 1118.6, 1119.1],
datetime.datetime(yr, 7, 1): [1108.6, 1117.6, 1118.6, 1118.6, 1119.1],
datetime.datetime(yr, 7,21): [1108.6, 1118.0, 1118.6, 1118.6, 1119.1],
datetime.datetime(yr, 8, 1): [1108.6, 1118.0, 1118.6, 1118.6, 1119.1],
datetime.datetime(yr, 9, 1): [1108.6, 1118.0, 1118.6, 1118.6, 1119.1],
datetime.datetime(yr, 9,11): [1108.6, 1118.0, 1118.6, 1118.6, 1119.1],
datetime.datetime(yr,10, 1): [1108.6, 1117.6, 1118.6, 1118.6, 1119.1],
datetime.datetime(yr,11, 1): [1108.6, 1116.3, 1117.5, 1118.6, 1119.1],
datetime.datetime(yr,12, 1): [1108.6, 1115.0, 1116.5, 1118.6, 1119.1],
datetime.datetime(yr,12,31): [1108.6, 1113.6, 1115.3, 1118.6, 1119.1]
}
NL1970 = pd.DataFrame.from_dict(NL1970).transpose()/3.2808
NL1970.columns = ['ELW','LRC','URC','EHW','AGO']
NL1970 = NL1970.resample(rule='1D').interpolate()
plt.figure(figsize=(10,6))
plotRC(NL1970,'b')
plotRC(RL1970,'r')
twiny()
plt.title('Rule Curves for Namakan and Rainy Lakes: 1970-2000')
saveRC('RuleCurve1970.png')
The 2001 Consolidated Order of the International Joint Commission establishes the rule curves for Namakan and Rainy Lakes, and operating constraints for the dams at Kettle Falls and International Falls. The consolidated order incorporates relevant language from the original Order of 1949 and Supplemental Orders of 1957, 1970, and 2000, into a single document describing current regulations on the management of levels for Rainy Lake and the Namakan chain of lakes.
# Namakan Lake
ELW = {
datetime.datetime(yr, 1, 1): 337.90,
datetime.datetime(yr,12,31): 337.90
}
EDL = {
datetime.datetime(yr, 1, 1): 338.95,
datetime.datetime(yr, 6,30): 338.95,
datetime.datetime(yr, 7, 1): 340.15,
datetime.datetime(yr, 9,30): 340.15,
datetime.datetime(yr,12,31): 338.95
}
LRC = {
datetime.datetime(yr, 1, 1): 339.70,
datetime.datetime(yr, 4, 1): 338.95,
datetime.datetime(yr, 4,15): 338.95,
datetime.datetime(yr, 6, 7): 340.70,
datetime.datetime(yr, 9, 1): 340.45,
datetime.datetime(yr,10, 1): 340.45,
datetime.datetime(yr,12,31): 339.70
}
URC = {
datetime.datetime(yr, 1, 1): 340.00,
datetime.datetime(yr, 4, 1): 339.70,
datetime.datetime(yr, 6, 1): 340.95,
datetime.datetime(yr, 9, 1): 340.65,
datetime.datetime(yr,10, 1): 340.65,
datetime.datetime(yr,12,31): 340.00
}
EHW = {
datetime.datetime(yr, 1, 1): 340.95,
datetime.datetime(yr,12,31): 340.95
}
AGO = {
datetime.datetime(yr, 1, 1): 341.10,
datetime.datetime(yr,12,31): 341.10
}
NL2000 = pd.concat([pd.Series(ELW),pd.Series(EDL),pd.Series(LRC),
pd.Series(URC),pd.Series(EHW),pd.Series(AGO)], axis=1)
NL2000.columns = ['ELW','EDL','LRC','URC','EHW','AGO']
NL2000 = NL2000.resample(rule='1D').interpolate()
# Rainy Lake
ELW = {
datetime.datetime(yr, 1, 1): 336.68,
datetime.datetime(yr,12,31): 336.68
}
LRC = {
datetime.datetime(yr, 1, 1): 337.20,
datetime.datetime(yr, 4, 1): 336.70,
datetime.datetime(yr, 5, 1): 336.80,
datetime.datetime(yr, 6, 1): 337.30,
datetime.datetime(yr, 7, 1): 337.50,
datetime.datetime(yr, 8,15): 337.50,
datetime.datetime(yr,12, 1): 337.30,
datetime.datetime(yr,12,31): 337.20
}
URC = {
datetime.datetime(yr, 1, 1): 337.45,
datetime.datetime(yr, 4, 1): 337.00,
datetime.datetime(yr, 5, 1): 337.40,
datetime.datetime(yr, 6, 1): 337.60,
datetime.datetime(yr, 7, 1): 337.75,
datetime.datetime(yr, 8,15): 337.75,
datetime.datetime(yr,12, 1): 337.60,
datetime.datetime(yr,12,31): 337.45
}
EDL = {
datetime.datetime(yr, 1, 1): 336.90,
datetime.datetime(yr, 4, 1): 336.70,
datetime.datetime(yr, 6,30): 336.70,
datetime.datetime(yr, 7, 1): 337.20,
datetime.datetime(yr,10,24): 337.20,
datetime.datetime(yr,12,31): 336.90
}
EHW = {
datetime.datetime(yr, 1, 1): 337.75,
datetime.datetime(yr,12,31): 337.75
}
AGO = {
datetime.datetime(yr, 1, 1): 337.90,
datetime.datetime(yr,12,31): 337.90
}
RL2000 = pd.concat([pd.Series(ELW),pd.Series(LRC),pd.Series(URC),
pd.Series(EDL),pd.Series(EHW),pd.Series(AGO)], axis=1)
RL2000.columns = ['ELW','LRC','URC','EDL','EHW','AGO']
RL2000 = RL2000.resample(rule='1D').interpolate()
plt.figure(figsize=(10,6))
plotRC(RL2000,'r')
plotRC(NL2000,'b')
twiny()
plt.title('Rule Curves for Namakan and Rainy Lakes: 2000 - present')
saveRC('RuleCurve2000.png')
plt.figure(figsize=(10,6))
plotRC(NL1970,'y')
plotRC(RL1970,'g')
plotRC(NL2000,'b')
plotRC(RL2000,'r')
plt.title('Comparison of 1970 and 2000 Rule Curves')
import matplotlib.patches as mpatches
gold_patch = mpatches.Patch(color='y', alpha = 0.5, label='Namakan 1970')
blue_patch = mpatches.Patch(color='b', alpha = 0.5, label='Namakan 2000')
green_patch = mpatches.Patch(color='g', alpha = 0.5, label='Rainy 1970')
red_patch = mpatches.Patch(color='r', alpha = 0.5, label='Rainy 2000')
nlegend = plt.legend(handles=[gold_patch,blue_patch],bbox_to_anchor=[1.0,0.55])
plt.gca().add_artist(nlegend)
plt.legend(handles=[green_patch,red_patch],loc=4)
twiny()
saveRC('RuleCurveComparison.png')
NL1970.to_pickle(dir+'NL1970.pkl')
RL1970.to_pickle(dir+'RL1970.pkl')
NL2000.to_pickle(dir+'NL2000.pkl')
RL2000.to_pickle(dir+'RL2000.pkl')
RL2000.head()
ELW | LRC | URC | EDL | EHW | AGO | |
---|---|---|---|---|---|---|
2014-01-01 | 336.68 | 337.200000 | 337.450 | 336.900000 | 337.75 | 337.9 |
2014-01-02 | 336.68 | 337.194444 | 337.445 | 336.897778 | 337.75 | 337.9 |
2014-01-03 | 336.68 | 337.188889 | 337.440 | 336.895556 | 337.75 | 337.9 |
2014-01-04 | 336.68 | 337.183333 | 337.435 | 336.893333 | 337.75 | 337.9 |
2014-01-05 | 336.68 | 337.177778 | 337.430 | 336.891111 | 337.75 | 337.9 |