206 lines
8.1 KiB
Python
206 lines
8.1 KiB
Python
#!/usr/bin/env python
|
|
|
|
##\file
|
|
# This file defined the base Function class.
|
|
# This class is used to provide a piece-wise
|
|
# linear function for use in the model. The
|
|
# primary use of this these classes is presenting
|
|
# the information from the species establishment
|
|
# and senescenes tables.
|
|
#
|
|
|
|
# Standard Python Modules
|
|
import exceptions
|
|
import numpy
|
|
import random
|
|
import scipy
|
|
import scipy.interpolate as interp
|
|
import xlrd
|
|
|
|
# Third Party Modules
|
|
import matplotlib as mpl
|
|
import matplotlib.pylab as plt
|
|
import mpl_toolkits.mplot3d.axes3d as Axes3D
|
|
import pandas
|
|
|
|
class Function(object):
|
|
xValue = list()
|
|
yValue = list()
|
|
|
|
def __init__(self, xValue, yValue):
|
|
if len(xValue) != len(yValue):
|
|
msg = 'Function: Error: Number of elements in xValue an yValue must match'
|
|
msg += ' len(xValue) = ' + str(len(xValue)) + ' len(yValue) = ' + str(len(yValue))
|
|
raise exceptions.RuntimeError(msg)
|
|
|
|
self.xValue = xValue
|
|
self.yValue = yValue
|
|
|
|
def toIndex(self, x, vec):
|
|
if ( x < vec[0] or vec[-1] < x ):
|
|
msg = 'Function: Error: x out of range\n'
|
|
msg += 'x = ' + str(x) + '\n'
|
|
msg += 'vec[0] = ' + str(vec[0]) + '\n'
|
|
msg += 'vec[-1] = ' + str(vec[-1]) + '\n'
|
|
raise exceptions.RuntimeError(msg)
|
|
|
|
b = 0 # b = the "bottom" index
|
|
t = len(vec)-1 # t = the "top" index
|
|
m = int(scipy.ceil((b+t)/2.0)) # m = the middle index
|
|
|
|
if ( x == vec[t] ):
|
|
b = t-1
|
|
scale = 1.0
|
|
return b,scale
|
|
|
|
while ( vec[b+1] <= x ):
|
|
if ( vec[b] <= x and x < vec[m] ):
|
|
t = m
|
|
else:
|
|
b = m
|
|
m = int(scipy.ceil((b+t)/2.0))
|
|
|
|
scale = (x - vec[b])/(vec[b+1] - vec[b])
|
|
|
|
return b,scale
|
|
|
|
def __getitem__(self, x):
|
|
b,scale = self.toIndex(x, self.xValue)
|
|
return self.yValue[b]*(1.0 - scale) + self.yValue[b+1]*scale
|
|
|
|
|
|
class ReadVegTable1D(object):
|
|
def __init__(self):
|
|
pass
|
|
|
|
def read(self, filename, modelType, species):
|
|
try:
|
|
data = pandas.read_excel(filename, modelType, index_col=None )
|
|
xValue = list( data.ix[:,0] )
|
|
yValue = list( data[species] )
|
|
return {'elvValue':xValue, 'rate':yValue}
|
|
except exceptions.IOError as error:
|
|
errorMessage = 'ReadVegTable1D: Error: Could not open file for reading : ' + filename + '\n'
|
|
errorMessage += 'ReadVegTable1D: Error: Addition error info : ' + str(error) + '\n'
|
|
raise exceptions.RuntimeError(errorMessage)
|
|
except xlrd.biffh.XLRDError as error:
|
|
errorMessage = 'ReadVegTable1D: Error: Could not find sheet named ' + modelType + ' in file ' + filename + '\n'
|
|
errorMessage += 'ReadVegTable1D: Error: Additional error info : ' + str(error) + '\n'
|
|
raise exceptions.RuntimeError(errorMessage)
|
|
except exceptions.KeyError as error:
|
|
errorMessage = 'ReadVegTable1D: Error: Could not find species named ' + species + ' in sheet ' + modelType + ' in file ' + filename +'\n'
|
|
errorMessage += 'ReadVegTable1D: Error: Additional error info : ' + str(error) + '\n'
|
|
raise exceptions.RuntimeError(errorMessage)
|
|
|
|
class Function2DFast(object):
|
|
|
|
def __init__(self, xValue, yValue, data):
|
|
# xValue = wave amplitudes
|
|
# yValue = mean salinity
|
|
# data = senescence and growth rates
|
|
if ( len(yValue) != numpy.size(data, 0) ):
|
|
msg = 'Function2DFast: Error: number of elements in yValue must match number of rows in data'
|
|
msg += ' len(yValue) = ' + str(len(yValue)) + ' data.shape = ' + str(data.shape)
|
|
raise exceptions.RuntimeError(msg)
|
|
|
|
if ( len(xValue) != numpy.size(data, 1) ):
|
|
msg = 'Function2DFast: Error: number of elements in xValue must match number of columns in data'
|
|
msg += ' len(xValue) = ' + str(len(Value)) + ' size(data) = ' + str(data.shape)
|
|
raise exceptions.RuntimeError(msg)
|
|
|
|
self.xValue = xValue
|
|
self.yValue = yValue
|
|
self.data = data
|
|
|
|
def toIndex(self, x, vec):
|
|
if ( x < vec[0] or vec[-1] < x ):
|
|
msg = 'Function2DFast: Error: x out of range\n'
|
|
msg += 'x = ' + str(x) + '\n'
|
|
msg += 'vec[0] = ' + str(vec[0]) + '\n'
|
|
msg += 'vec[-1] = ' + str(vec[-1]) + '\n'
|
|
raise exceptions.RuntimeError(msg)
|
|
|
|
b = 0 # b = the "bottom" index
|
|
t = len(vec)-1 # t = the "top" index
|
|
m = int(scipy.ceil((b+t)/2.0)) # m = the middle index
|
|
|
|
if ( x == vec[t] ):
|
|
b = t-1
|
|
scale = 1.0
|
|
return b,scale
|
|
|
|
while ( vec[b+1] <= x ):
|
|
if ( vec[b] <= x and x < vec[m] ):
|
|
t = m
|
|
else:
|
|
b = m
|
|
m = int(scipy.ceil((b+t)/2.0))
|
|
|
|
scale = (x - vec[b])/(vec[b+1] - vec[b])
|
|
|
|
return b,scale
|
|
|
|
def __getitem__(self, item):
|
|
i, i_scale = self.toIndex(item[0], self.xValue)
|
|
j, j_scale = self.toIndex(item[1], self.yValue)
|
|
|
|
x0 = self.data[j ,i] * (1.0 - i_scale) + self.data[j ,i+1]*i_scale
|
|
x1 = self.data[j+1,i] * (1.0 - i_scale) + self.data[j+1,i+1]*i_scale
|
|
|
|
return x0*(1.0 - j_scale) + x1*j_scale
|
|
|
|
class Function2D(object):
|
|
|
|
def __init__(self, xValue, yValue, data = 0):
|
|
# xValue = wave amplitudes
|
|
# yValue = mean salinity
|
|
# data = senescence and growth rates
|
|
if len(yValue) != numpy.size(data, 0):
|
|
msg = 'Function2D: Error: number of elements in yValue must match number of rows in data'
|
|
msg += ' len(yValue) = ' + str(len(yValue)) + ' data.shape = ' + str(data.shape)
|
|
raise exceptions.RuntimeError(msg)
|
|
|
|
if len(xValue) != numpy.size(data, 1):
|
|
msg = 'Function2D: Error: number of elements in xValue must match number of columns in data'
|
|
msg += ' len(xValue) = ' + str(len(Value)) + ' size(data) = ' + str(data.shape)
|
|
raise exceptions.RuntimeError(msg)
|
|
|
|
self.point = numpy.array( [ [x,y] for y in yValue for x in xValue ] )
|
|
self.value = numpy.array( [elt for row in data for elt in row] )
|
|
self.minX = min( xValue )
|
|
self.maxX = max( xValue )
|
|
self.minY = min( yValue )
|
|
self.maxY = max( yValue )
|
|
|
|
def __getitem__(self, item):
|
|
if ( item[0] < self.minX or self.maxX < item[0] ):
|
|
raise exceptions.RuntimeError('Function2D: Error: x coordinate out of range. ' + str(item[0]) + ' not in ' + '[ ' + str(self.minX) + ', ' + str(self.maxX) + ' ]' )
|
|
|
|
if ( item[1] < self.minY or self.maxY < item[1] ):
|
|
raise exceptions.RuntimeError('Function2D: Error: y coordinate out of range. ' + str(item[1]) + ' not in ' + '[ ' + str(self.minY) + ', ' + str(self.maxY) + ' ]' )
|
|
|
|
return interp.griddata(self.point, self.value, ([item[0]],[item[1]] ), method='linear')[0]
|
|
|
|
class ReadVegTable2D(object):
|
|
def __init__(self):
|
|
pass
|
|
|
|
def read(self, filename, species):
|
|
try:
|
|
data = pandas.read_excel(filename, species, index_col=None, parse_cols=range(1,23), skiprows=1)
|
|
waValue = data.columns.values.tolist()[1:len(data.columns)]
|
|
spcode = data.columns.values.tolist()[0]
|
|
salValue = data[spcode].tolist()
|
|
rate = numpy.asarray(data)[:,1:22]
|
|
return {'spcode':spcode, 'waValue':waValue, 'salValue':salValue, 'rate':rate }
|
|
except exceptions.IOError as error:
|
|
errorMessage = 'ReadVegTable2D: Error: Could not open file for reading : ' + filename + '\n'
|
|
errorMessage += 'ReadVegTable2D: Error: Addition error info : ' + str(error) + '\n'
|
|
raise exceptions.RuntimeError(errorMessage)
|
|
except xlrd.biffh.XLRDError as error:
|
|
errorMessage = 'ReadVegTable2D: Error: Could not find sheet named ' + species + ' in file : ' + filename + '\n'
|
|
errorMessage += 'ReadVegTable2D: Error: Addition error info : ' + str(error) + '\n'
|
|
raise exceptions.RuntimeError(errorMessage)
|
|
|
|
|