Skip to content

Commit

Permalink
Initial support for etr_resample parameter
Browse files Browse the repository at this point in the history
I added support for the parameter but it doesn't seem to be working in the collection class yet.
  • Loading branch information
cgmorton committed Sep 1, 2019
1 parent 0bcfec9 commit 27e3a44
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 41 deletions.
2 changes: 1 addition & 1 deletion openet/sims/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .image import Image
from .collection import Collection

__version__ = "0.0.11"
__version__ = "0.0.12"

MODEL_NAME = 'SIMS'
64 changes: 49 additions & 15 deletions openet/sims/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,14 @@ def __init__(
cloud_cover_max=70,
etr_source=None,
etr_band=None,
etr_factor=1.0,
etr_factor=None,
etr_resample=None,
filter_args=None,
model_args=None,
# model_args={'etr_source': 'IDAHO_EPSCOR/GRIDMET',
# 'etr_band': 'etr',
# 'etr_factor': 0.85},
# 'etr_factor': 0.85,
# 'etr_resample': 'bilinear},
# **kwargs
):
"""Earth Engine based SIMS ETcb Image Collection object
Expand Down Expand Up @@ -89,8 +91,12 @@ def __init__(
etr_band : str, optional
Reference ET band name (the default is None). ETr Parameters must
be be set here or in model args to interpolate ET, ETf, or ETr.
etr_factor : float, optional
Reference ET scaling factor (the default is 1.0).
etr_factor : float, None, optional
Reference ET scaling factor. The default is None which is
equivalent to 1.0 (or no scaling).
etr_resample : {'nearest', 'bilinear', 'bicubic'}, None, optional
Reference ET resampling. The default is None which is equivalent
to nearest neighbor resampling.
filter_args : dict
Image collection filter keyword arguments (the default is None).
Organize filter arguments as a nested dictionary with the primary
Expand Down Expand Up @@ -121,14 +127,26 @@ def __init__(
self.etr_source = etr_source
self.etr_band = etr_band
self.etr_factor = etr_factor
self.etr_resample = etr_resample

# Check reference ET parameters
if etr_factor and not utils.is_number(etr_factor):
raise ValueError('etr_factor must be a number')
if etr_factor and self.etr_factor < 0:
raise ValueError('etr_factor must be greater than zero')
etr_resample_methods = ['nearest', 'bilinear', 'bicubic']
if etr_resample and etr_resample.lower() not in etr_resample_methods:
raise ValueError('unsupported etr_resample method')

# Set/update the ETr parameters in model_args if they were set in init()
if etr_source:
self.model_args['etr_source'] = etr_source
if etr_band:
self.model_args['etr_band'] = etr_band
if etr_factor != 1 and etr_factor:
self.model_args['etr_factor'] = etr_factor
if self.etr_source:
self.model_args['etr_source'] = self.etr_source
if self.etr_band:
self.model_args['etr_band'] = self.etr_band
if self.etr_factor:
self.model_args['etr_factor'] = self.etr_factor
if self.etr_resample:
self.model_args['etr_resample'] = self.etr_resample

# Model specific variables that can be interpolated to a daily timestep
# CGM - Should this be specified in the interpolation method instead?
Expand Down Expand Up @@ -397,9 +415,11 @@ def interpolate(self, variables=None, t_interval='custom',
self.model_args['etr_band'] = kwargs['etr_band']
if 'etr_factor' in kwargs.keys() and kwargs['etr_factor'] is not None:
self.model_args['etr_factor'] = kwargs['etr_factor']
if 'etr_resample' in kwargs.keys() and kwargs['etr_resample'] is not None:
self.model_args['etr_resample'] = kwargs['etr_resample']

# Check that all etr parameters were set
for etr_param in ['etr_source', 'etr_band', 'etr_factor']:
for etr_param in ['etr_source', 'etr_band', 'etr_factor', 'etr_resample']:
if etr_param not in self.model_args.keys():
raise ValueError('{} was not set'.format(etr_param))
elif not self.model_args[etr_param]:
Expand All @@ -408,8 +428,8 @@ def interpolate(self, variables=None, t_interval='custom',
if type(self.model_args['etr_source']) is str:
# Assume a string source is an single image collection ID
# not an list of collection IDs or ee.ImageCollection
daily_etr_coll = ee.ImageCollection(self.model_args['etr_source'])\
.filterDate(start_date, end_date)\
daily_etr_coll = ee.ImageCollection(self.model_args['etr_source']) \
.filterDate(start_date, end_date) \
.select([self.model_args['etr_band']], ['etr'])
# elif isinstance(self.model_args['etr_source'], computedobject.ComputedObject):
# # Interpret computed objects as image collections
Expand Down Expand Up @@ -471,6 +491,9 @@ def interpolate(self, variables=None, t_interval='custom',
# if 'et' in variables or 'etf' in variables:
def compute_et(img):
"""This function assumes ETr and ETf are present"""

# TODO: Should ETr be mapped to the etf band here?

et_img = img.select(['etf']).multiply(img.select(['etr']))
return img.addBands(et_img.rename('et'))
daily_coll = daily_coll.map(compute_et)
Expand Down Expand Up @@ -509,10 +532,21 @@ def aggregate_image(agg_start_date, agg_end_date, date_format):
"""
# if 'et' in variables or 'etf' in variables:
et_img = daily_coll.filterDate(agg_start_date, agg_end_date)\
.select(['et']).sum().multiply(self.model_args['etr_factor'])
.select(['et']).sum()
# if 'etr' in variables or 'etf' in variables:
etr_img = daily_coll.filterDate(agg_start_date, agg_end_date)\
.select(['etr']).sum().multiply(self.model_args['etr_factor'])
.select(['etr']).sum()

if self.model_args['etr_factor']:
et_img = et_img.multiply(self.model_args['etr_factor'])
etr_img = etr_img.multiply(self.model_args['etr_factor'])

# DEADBEEF - This doesn't seem to be doing anything
if self.etr_resample in ['bilinear', 'bicubic']:
print('collection interpolate aggregate bilinear')
etr_img = etr_img.resample(self.model_args['etr_resample'])
# Will mapping ETr to the ET band trigger the resample?
# etr_img = et_img.multiply(0).add(etr_img)

# Round and save ET and ETr as integer values to save space
# Ensure that ETr > 0 after rounding to avoid divide by zero
Expand Down
36 changes: 27 additions & 9 deletions openet/sims/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ def __init__(
crop_type_kc_flag=False, # CGM - Not sure what to call this parameter yet
etr_source=None,
etr_band=None,
etr_factor=1.0,
etr_factor=None,
etr_resample=None,
mask_non_ag_flag=False,
water_kc_flag=True,
):
Expand All @@ -72,8 +73,12 @@ def __init__(
etr_band : str, optional
Reference ET band name (the default is None).
Parameter is required if computing 'et' or 'etr'.
etr_factor : float, optional
Reference ET scaling factor (the default is 1.0).
etr_factor : float, None, optional
Reference ET scaling factor. The default is None which is
equivalent to 1.0 (or no scaling).
etr_resample : {'nearest', 'bilinear', 'bicubic', None}, optional
Reference ET resampling. The default is None which is equivalent
to nearest neighbor resampling.
mask_non_ag_flag : bool, optional
If True, mask all pixels that don't map to a crop_class.
The default is False.
Expand Down Expand Up @@ -116,6 +121,16 @@ def __init__(
self.etr_source = etr_source
self.etr_band = etr_band
self.etr_factor = etr_factor
self.etr_resample = etr_resample

# Check reference ET parameters
if etr_factor and not utils.is_number(etr_factor):
raise ValueError('etr_factor must be a number')
if etr_factor and self.etr_factor < 0:
raise ValueError('etr_factor must be greater than zero')
etr_resample_methods = ['nearest', 'bilinear', 'bicubic']
if etr_resample and etr_resample.lower() not in etr_resample_methods:
raise ValueError('unsupported etr_resample method')

# CGM - Model class could inherit these from Image instead of passing them
# Could pass time_start instead of separate year and doy
Expand Down Expand Up @@ -201,17 +216,20 @@ def etr(self):
etr_img = ee.Image.constant(self.etr_source)
elif type(self.etr_source) is str:
# Assume a string source is an image collection ID (not an image ID)
etr_img = ee.Image(
ee.ImageCollection(self.etr_source)\
.filterDate(self._start_date, self._end_date)\
.select([self.etr_band])\
.first())
etr_coll = ee.ImageCollection(self.etr_source)\
.filterDate(self._start_date, self._end_date)\
.select([self.etr_band])
etr_img = ee.Image(etr_coll.first())
if self.etr_resample in ['bilinear', 'bicubic']:
etr_img = etr_img.resample(self.etr_resample)
else:
raise ValueError('unsupported etr_source: {}'.format(
self.etr_source))

if self.etr_factor:
etr_img = etr_img.multiply(self.etr_factor)

return self.ndvi.multiply(0).add(etr_img)\
.multiply(self.etr_factor)\
.rename(['etr']).set(self._properties)

@lazy_property
Expand Down
18 changes: 9 additions & 9 deletions openet/sims/tests/test_c_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,15 @@ def default_image(ndvi=0.8):
# Setting etr_source and etr_band on the default image to simplify testing
# but these do not have defaults in the Image class init
def default_image_args(ndvi=0.8, etr_source='IDAHO_EPSCOR/GRIDMET',
etr_band='etr', etr_factor=0.85,
etr_band='etr', etr_factor=0.85, etr_resample='nearest',
crop_type_source='USDA/NASS/CDL', crop_type_remap='CDL',
crop_type_kc_flag=False, mask_non_ag_flag=False):
return {
'image': default_image(ndvi=ndvi),
'etr_source': etr_source,
'etr_band': etr_band,
'etr_factor': etr_factor,
'etr_resample': etr_resample,
'crop_type_source': crop_type_source,
'crop_type_remap': crop_type_remap,
'crop_type_kc_flag': crop_type_kc_flag,
Expand All @@ -56,24 +57,23 @@ def default_image_args(ndvi=0.8, etr_source='IDAHO_EPSCOR/GRIDMET',


def default_image_obj(ndvi=0.8, etr_source='IDAHO_EPSCOR/GRIDMET',
etr_band='etr', etr_factor=0.85,
etr_band='etr', etr_factor=0.85, etr_resample='nearest',
crop_type_source='USDA/NASS/CDL', crop_type_remap='CDL',
crop_type_kc_flag=False, mask_non_ag_flag=False):
return sims.Image(**default_image_args(
ndvi=ndvi,
etr_source=etr_source, etr_band=etr_band, etr_factor=etr_factor,
crop_type_source=crop_type_source,
crop_type_remap=crop_type_remap,
crop_type_kc_flag=crop_type_kc_flag,
mask_non_ag_flag=mask_non_ag_flag,
ndvi=ndvi, etr_source=etr_source, etr_band=etr_band,
etr_factor=etr_factor, etr_resample=etr_resample,
crop_type_source=crop_type_source, crop_type_remap=crop_type_remap,
crop_type_kc_flag=crop_type_kc_flag, mask_non_ag_flag=mask_non_ag_flag,
))


def test_Image_init_default_parameters():
m = sims.Image(image=default_image())
assert m.etr_source == None
assert m.etr_band == None
assert m.etr_factor == 1.0
assert m.etr_factor == None
assert m.etr_resample == None
# assert m.crop_type_source == 'USDA/NASS/CDL'
# assert m.crop_type_remap == 'CDL'
# assert m.crop_type_kc_flag == False
Expand Down
43 changes: 36 additions & 7 deletions openet/sims/tests/test_d_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
'start_date': START_DATE, 'end_date': END_DATE,
'variables': list(VARIABLES), 'cloud_cover_max': 70,
'etr_source': 'IDAHO_EPSCOR/GRIDMET', 'etr_band': 'etr',
'etr_factor': 0.85, 'model_args': {}, 'filter_args': {},
'etr_factor': 0.85, 'etr_resample': 'nearest',
'model_args': {}, 'filter_args': {},
}

def default_coll_obj(**kwargs):
Expand All @@ -46,13 +47,15 @@ def test_Collection_init_default_parameters():
del args['etr_source']
del args['etr_band']
del args['etr_factor']
del args['etr_resample']
del args['variables']

m = sims.Collection(**args)
assert m.variables == None
assert m.etr_source == None
assert m.etr_band == None
assert m.etr_factor == 1.0
assert m.etr_factor == None
assert m.etr_resample == None
assert m.cloud_cover_max == 70
assert m.model_args == {}
assert m.filter_args == {}
Expand Down Expand Up @@ -328,34 +331,60 @@ def test_Collection_interpolate_etr_factor_not_set():
etr_factor=None, model_args={}).interpolate())


def test_Collection_interpolate_etr_factor_exception():
"""Test if Exception is raised if etr_factor is not a number or negative"""
with pytest.raises(ValueError):
utils.getinfo(default_coll_obj(
etr_factor=-1, model_args={}).interpolate())


def test_Collection_interpolate_etr_resample_not_set():
"""Test if Exception is raised if etr_resample is not set"""
with pytest.raises(ValueError):
utils.getinfo(default_coll_obj(
etr_resample=None, model_args={}).interpolate())


def test_Collection_interpolate_etr_resample_exception():
"""Test if Exception is raised if etr_resample is not set"""
with pytest.raises(ValueError):
utils.getinfo(default_coll_obj(
etr_resample='deadbeef', model_args={}).interpolate())


def test_Collection_interpolate_etr_params_kwargs():
"""Test setting etr parameters in the Collection init args"""
output = utils.getinfo(default_coll_obj(
etr_source='IDAHO_EPSCOR/GRIDMET', etr_band='etr',
etr_factor=0.5, model_args={}).interpolate())
etr_factor=0.5, etr_resample='bilinear', model_args={}).interpolate())
assert {y['id'] for x in output['features'] for y in x['bands']} == VARIABLES
assert output['features'][0]['properties']['etr_factor'] == 0.5
assert output['features'][0]['properties']['etr_resample'] == 'bilinear'


def test_Collection_interpolate_etr_params_model_args():
"""Test setting etr parameters in the model_args"""
output = utils.getinfo(default_coll_obj(
etr_source=None, etr_band=None, etr_factor=None,
etr_source=None, etr_band=None, etr_factor=None, etr_resample=None,
model_args={'etr_source': 'IDAHO_EPSCOR/GRIDMET',
'etr_band': 'etr', 'etr_factor': 0.5}).interpolate())
'etr_band': 'etr', 'etr_factor': 0.5,
'etr_resample': 'bilinear'}).interpolate())
assert {y['id'] for x in output['features'] for y in x['bands']} == VARIABLES
assert output['features'][0]['properties']['etr_factor'] == 0.5
assert output['features'][0]['properties']['etr_resample'] == 'bilinear'


def test_Collection_interpolate_etr_params_interpolate_args():
"""Test setting etr parameters in the interpolate call"""
etr_args = {'etr_source': 'IDAHO_EPSCOR/GRIDMET',
'etr_band': 'etr', 'etr_factor': 0.5}
'etr_band': 'etr', 'etr_factor': 0.5,
'etr_resample': 'bilinear'}
output = utils.getinfo(default_coll_obj(
etr_source=None, etr_band=None, etr_factor=None,
etr_source=None, etr_band=None, etr_factor=None, etr_resample=None,
model_args={}).interpolate(**etr_args))
assert {y['id'] for x in output['features'] for y in x['bands']} == VARIABLES
assert output['features'][0]['properties']['etr_factor'] == 0.5
assert output['features'][0]['properties']['etr_resample'] == 'bilinear'


def test_Collection_interpolate_t_interval_exception():
Expand Down

0 comments on commit 27e3a44

Please sign in to comment.