Skip to content

Commit

Permalink
M117 / Issue ooici#155 - Reworked interface for external parameter re…
Browse files Browse the repository at this point in the history
…ferences.
  • Loading branch information
caseybryant committed Jul 7, 2014
1 parent c8296ba commit 6cf4181
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 40 deletions.
41 changes: 11 additions & 30 deletions coverage_model/parameter_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,38 +280,19 @@ def __eq__(self, other):
return ret


class ExternalFunction(AbstractFunction):
def __init__(self, name, external_guid, external_name):
class ExternalFunction(PythonFunction):
def __init__(self, name, external_guid, external_name, owner=None, func_name=None, arg_list=[], kwarg_map=None, param_map={}, egg_uri='', remove_fills=True):
self.external_name = external_name
param_map = {external_name : external_guid}
AbstractFunction.__init__(self, name, [], param_map)
if func_name is None and owner is None:
owner = 'coverage_model.util.external_parameter_methods'
func_name = 'linear_map'
param_map[external_name] = external_guid
super(ExternalFunction, self).__init__(name, owner, func_name, arg_list=arg_list, kwarg_map=kwarg_map, egg_uri=egg_uri, param_map=param_map, remove_fills=remove_fills)

def load_coverage(self, pdir):
def evaluate(self, pval_callback, time_segment, fill_value=-9999, stride_length=None):
self._import_func()
from coverage_model.coverage import AbstractCoverage
external_guid = self.param_map[self.external_name]
cov = AbstractCoverage.resurrect(external_guid, mode='r')
return cov

def evaluate(self, pval_callback, pdir, time_segment, fill_value=-9999):
return self.linear_map(pval_callback, pdir, time_segment)

def linear_map(self, pval_callback, pdir, time_segment):
cov = self.load_coverage(pdir)
# TODO: Might not want to hard-code time
x = pval_callback('time', time_segment).get_data()['time']
x_i = cov.get_parameter_values('time', time_segment=time_segment).get_data()['time']
y_i = cov.get_parameter_values(self.external_name, time_segment=time_segment).get_data()[self.external_name]


# Where in x_i does x fit in?
upper = np.searchsorted(x_i, x)
# Clip values not in [1, N-1]
upper = upper.clip(1, len(x_i)-1).astype(int)
lower = upper - 1

# Linear interpolation
w = (x - x_i[lower]) / (x_i[upper] - x_i[lower])
y = y_i[lower] * (1-w) + y_i[upper] * w
return y
cov = AbstractCoverage.resurrect(self.param_map[self.external_name], mode='r')
return self._callable(pval_callback, cov, self.external_name, time_segment)


3 changes: 1 addition & 2 deletions coverage_model/parameter_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ def get_function_map(self, parent_arg_name=None):

def _todict(self, exclude=None):
# Must exclude _cov_range_value from persistence
return super(ParameterFunctionType, self)._todict(exclude=['_pdir', '_pval_callback', '_pctxt_callback', '_fmap', '_iparams', '_dparams', '_callback'])
return super(ParameterFunctionType, self)._todict(exclude=['_pval_callback', '_pctxt_callback', '_fmap', '_iparams', '_dparams', '_callback'])

@property
def callback(self):
Expand All @@ -660,7 +660,6 @@ def _fromdict(cls, cmdict, arg_masks=None):
ret = super(ParameterFunctionType, cls)._fromdict(cmdict, arg_masks=arg_masks)
# Add the _pval_callback attribute, initialized to None
ret._pval_callback = None
ret._pdir = None
ret.callback = None
return ret

Expand Down
5 changes: 1 addition & 4 deletions coverage_model/parameter_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,7 @@ def __getitem__(self, time_segment=None, stride_length=None):
# slice_ = utils.fix_slice(slice_, self.shape)

try:
if isinstance(self.parameter_type.function, ExternalFunction):
r = self.content.evaluate(self._pval_callback, self._pdir, time_segment, self.parameter_type.fill_value)
else:
r = self.content.evaluate(self._pval_callback, time_segment, self.parameter_type.fill_value)
r = self.content.evaluate(self._pval_callback, time_segment, self.parameter_type.fill_value)
ve = self.parameter_type.value_encoding
if hasattr(self.parameter_type, 'inner_encoding'):
ve = self.parameter_type.inner_encoding
Expand Down
5 changes: 1 addition & 4 deletions coverage_model/storage/parameter_persisted_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,7 @@ def _append_parameter_fuction_data(self, params, param_dict, fill_dict, time_seg
if param in self.master_manager.parameter_metadata:
param_type = self.master_manager.parameter_metadata[param].parameter_context.param_type
if isinstance(param_type, ParameterFunctionType):
if isinstance(param_type.function, ExternalFunction):
data = param_type.function.evaluate(param_type.callback, self.master_manager.root_dir, time_segment, time)
else:
data = param_type.function.evaluate(param_type.callback, time_segment, time)
data = param_type.function.evaluate(param_type.callback, time_segment, time)
param_dict[param] = data
return param_dict, fill_dict

Expand Down
17 changes: 17 additions & 0 deletions coverage_model/test/test_complex_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,12 @@ def test_external_refs(self):
cova_pth = _make_cov(self.working_dir, ['value_set', ctx], data_dict={'time':np.arange(0,10,0.7), 'value_set':np.arange(20,30, 0.7)})
cova = SimplexCoverage.load(cova_pth, mode='r')

with self.assertRaises(AttributeError): # method doesn't exist
pfunc = ExternalFunction('example', cova.persistence_guid, 'value_set', 'coverage_model.parameter_functions', 'linear_map', [])
ctx = ParameterContext('example', param_type=ParameterFunctionType(pfunc, value_encoding='<f4'))
covb_pth = _make_cov(self.working_dir, [ctx], data_dict={'time':np.arange(0.5, 10.5, 1)})
cov = SimplexCoverage.load(covb_pth, mode='r')
data = cov.get_parameter_values().get_data()

# Create another coverage that references the above
pfunc = ExternalFunction('example', cova.persistence_guid, 'value_set')
Expand All @@ -1090,6 +1096,17 @@ def test_external_refs(self):
np.testing.assert_allclose(data['example'], np.arange(20.5, 30.5, 1))
np.testing.assert_array_equal(data['time'], np.arange(0.5, 10.5, 1))

cov.close()

pfunc_explicit = ExternalFunction('example', cova.persistence_guid, 'value_set', 'coverage_model.util.external_parameter_methods', 'linear_map', [])
ctx_explicit = ParameterContext('example', param_type=ParameterFunctionType(pfunc_explicit, value_encoding='<f4'))
covc_pth = _make_cov(self.working_dir, [ctx_explicit], data_dict={'time':np.arange(0.5, 10.5, 1)})
covc = SimplexCoverage.load(covc_pth, mode='r')
# Assert that the values are correctly interpolated
data = covc.get_parameter_values().get_data()
np.testing.assert_allclose(data['example'], np.arange(20.5, 30.5, 1))
np.testing.assert_array_equal(data['time'], np.arange(0.5, 10.5, 1))


def create_all_params():
'''
Expand Down
22 changes: 22 additions & 0 deletions coverage_model/util/external_parameter_methods.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
__author__ = 'casey'

import numpy as np


def linear_map(pval_callback, cov, external_param_name, time_segment):
# TODO: Might not want to hard-code time
x = pval_callback('time', time_segment).get_data()['time']
x_i = cov.get_parameter_values('time', time_segment=time_segment).get_data()['time']
y_i = cov.get_parameter_values(external_param_name, time_segment=time_segment).get_data()[external_param_name]


# Where in x_i does x fit in?
upper = np.searchsorted(x_i, x)
# Clip values not in [1, N-1]
upper = upper.clip(1, len(x_i)-1).astype(int)
lower = upper - 1

# Linear interpolation
w = (x - x_i[lower]) / (x_i[upper] - x_i[lower])
y = y_i[lower] * (1-w) + y_i[upper] * w
return y

0 comments on commit 6cf4181

Please sign in to comment.