diff --git a/coverage_model/parameter_functions.py b/coverage_model/parameter_functions.py index 09dedef..6461220 100644 --- a/coverage_model/parameter_functions.py +++ b/coverage_model/parameter_functions.py @@ -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) diff --git a/coverage_model/parameter_types.py b/coverage_model/parameter_types.py index efff221..cab37d0 100644 --- a/coverage_model/parameter_types.py +++ b/coverage_model/parameter_types.py @@ -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): @@ -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 diff --git a/coverage_model/parameter_values.py b/coverage_model/parameter_values.py index 38d4cab..93dbf62 100644 --- a/coverage_model/parameter_values.py +++ b/coverage_model/parameter_values.py @@ -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 diff --git a/coverage_model/storage/parameter_persisted_storage.py b/coverage_model/storage/parameter_persisted_storage.py index 57c4e77..cbedb86 100644 --- a/coverage_model/storage/parameter_persisted_storage.py +++ b/coverage_model/storage/parameter_persisted_storage.py @@ -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 diff --git a/coverage_model/test/test_complex_coverage.py b/coverage_model/test/test_complex_coverage.py index 637a550..2ba8abb 100644 --- a/coverage_model/test/test_complex_coverage.py +++ b/coverage_model/test/test_complex_coverage.py @@ -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='