Skip to content

Commit

Permalink
Support passing et_reference parameters in interp_args to from_scene_…
Browse files Browse the repository at this point in the history
…et_actual() calls

Bumping version number.

Also started adding interpolate_prep code into from_scene_et_actual() and from_scene_et_fraction() functions.  Everything is commented out for now, but it will likely be enabled in v0.5.0.
  • Loading branch information
cgmorton committed May 17, 2024
1 parent e204a57 commit 3a867a9
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 74 deletions.
205 changes: 169 additions & 36 deletions openet/core/interpolate.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ def from_scene_et_fraction(
# Supporting reading the parameters from both the interp_args and model_args dictionaries
# Check interp_args then model_args, and eventually drop support for reading from model_args
# Assume that if source and band are present, factor and resample should also be read
if 'et_reference_source' in interp_args.keys() and 'et_reference_band' in interp_args.keys():
if ('et_reference_source' in interp_args.keys()) and ('et_reference_band' in interp_args.keys()):
et_reference_source = interp_args['et_reference_source']
et_reference_band = interp_args['et_reference_band']
if not et_reference_source or not et_reference_band:
Expand All @@ -508,14 +508,14 @@ def from_scene_et_fraction(
if not et_reference_resample:
et_reference_resample = 'nearest'
logging.debug('et_reference_resample was not set, default to nearest')
elif et_reference_resample not in ['nearest', 'bilinear', 'bicubic']:
elif et_reference_resample not in RESAMPLE_METHODS:
raise ValueError(f'unsupported et_reference_resample method: '
f'{et_reference_resample}')
else:
et_reference_resample = 'nearest'
logging.debug('et_reference_resample was not set, default to nearest')

elif 'et_reference_source' in model_args.keys() and 'et_reference_band' in model_args.keys():
elif ('et_reference_source' in model_args.keys()) and ('et_reference_band' in model_args.keys()):
et_reference_source = model_args['et_reference_source']
et_reference_band = model_args['et_reference_band']
if not et_reference_source or not et_reference_band:
Expand All @@ -532,7 +532,7 @@ def from_scene_et_fraction(
if not et_reference_resample:
et_reference_resample = 'nearest'
logging.debug('et_reference_resample was not set, default to nearest')
elif et_reference_resample not in ['nearest', 'bilinear', 'bicubic']:
elif et_reference_resample not in RESAMPLE_METHODS:
raise ValueError(f'unsupported et_reference_resample method: '
f'{et_reference_resample}')
else:
Expand Down Expand Up @@ -584,15 +584,59 @@ def et_reference_adjust(input_img):
if ('et_reference' in variables) and ('et_fraction' not in interp_vars):
interp_vars.append('et_fraction')

# The time band is always needed for interpolation
# The time band is needed for interpolation
# (until interpolate_prep below is added)
interp_vars.append('time')

# TODO: Look into implementing et_fraction clamping here
# (similar to et_actual below)

# Filter scene collection to the interpolation range
# This probably isn't needed since scene_coll was built to this range
scene_coll = scene_coll.filterDate(interp_start_date, interp_end_date)
# ############
# def interpolate_prep(img):
# """Prep WRS2 scene images for interpolation
#
# "Unscale" the images using the "scale_factor" property and convert to double.
# Add a mask and time band to each image in the scene_coll since
# interpolator is assuming time and mask bands exist.
# The interpolation could be modified to get the mask from the
# time band instead of setting it here.
# The time image must be the 0 UTC time
#
# """
# mask_img = (
# img.select(['et_fraction']).multiply(0).add(1).updateMask(1).uint8()
# .rename('mask')
# )
# time_img = (
# img.select(['et_fraction']).double().multiply(0)
# .add(utils.date_0utc(ee.Date(img.get('system:time_start'))).millis())
# .rename('time')
# )
#
# # Set the default scale factor to 1 if the image does not have the property
# scale_factor = (
# ee.Dictionary({'scale_factor': img.get('scale_factor')})
# .combine({'scale_factor': 1.0}, overwrite=False)
# )
#
# return (
# img.select(interp_vars)
# .double().multiply(ee.Number(scale_factor.get('scale_factor')))
# .addBands([mask_img, time_img])
# .set({
# 'system:time_start': ee.Number(img.get('system:time_start')),
# 'image_id': ee.String(img.get('system:index')),
# })
# )
#
# # Filter scene collection to the interpolation range
# # This probably isn't needed since scene_coll was built to this range
# # Then add the time and mask bands needed for interpolation
# scene_coll = ee.ImageCollection(
# scene_coll.filterDate(interp_start_date, interp_end_date)
# .map(interpolate_prep)
# )
# ############

# For count, compute the composite/mosaic image for the mask band only
if 'count' in variables:
Expand All @@ -612,6 +656,14 @@ def et_reference_adjust(input_img):
.set({'system:time_start': ee.Date(start_date).millis()})
)

# import pprint
# print('Prep Collection')
# pprint.pprint(scene_coll.select(['et_fraction']).getInfo())
# pprint.pprint(scene_coll.select(['ndvi']).getInfo())
# pprint.pprint(scene_coll.select(['time']).getInfo())
# pprint.pprint(scene_coll.select(['mask']).getInfo())
# print('DEADBEEF 3')

# Interpolate to a daily time step
daily_coll = daily(
target_coll=daily_et_ref_coll,
Expand Down Expand Up @@ -692,9 +744,7 @@ def aggregate_image(agg_start_date, agg_end_date, date_format):
image_list.append(et_reference_img.float())
if 'et_fraction' in variables:
# Compute average et fraction over the aggregation period
image_list.append(
et_img.divide(et_reference_img).rename(['et_fraction']).float()
)
image_list.append(et_img.divide(et_reference_img).rename(['et_fraction']).float())
if 'ndvi' in variables:
# Compute average NDVI over the aggregation period
ndvi_img = (
Expand Down Expand Up @@ -924,36 +974,78 @@ def from_scene_et_actual(
raise ValueError(f'unsupported interp_resample: {interp_resample}')

# Get reference ET collection
if 'et_reference' in variables or 'et_fraction' in variables:
if 'et_reference_source' not in model_args.keys():
raise ValueError('et_reference_source was not set')
if ('et_reference' in variables) or ('et_fraction' in variables):

# Supporting reading the parameters from both the interp_args and model_args dictionaries
# Check interp_args then model_args, and eventually drop support for reading from model_args
# Assume that if source and band are present, factor and resample should also be read
if (('et_reference_source' in interp_args.keys()) and
('et_reference_band' in interp_args.keys())):
et_reference_source = interp_args['et_reference_source']
et_reference_band = interp_args['et_reference_band']

if 'et_reference_factor' in interp_args.keys():
et_reference_factor = interp_args['et_reference_factor']
else:
et_reference_factor = 1.0
logging.debug('et_reference_factor was not set, default to 1.0')

if 'et_reference_resample' in interp_args.keys():
et_reference_resample = interp_args['et_reference_resample'].lower()
if not et_reference_resample:
et_reference_resample = 'nearest'
logging.debug('et_reference_resample was not set, default to nearest')
elif et_reference_resample not in RESAMPLE_METHODS:
raise ValueError(f'unsupported et_reference_resample method: '
f'{et_reference_resample}')
else:
et_reference_resample = 'nearest'
logging.debug('et_reference_resample was not set, default to nearest')

if 'et_reference_band' not in model_args.keys():
raise ValueError('et_reference_band was not set')
if et_reference_resample and (et_reference_resample not in RESAMPLE_METHODS):
raise ValueError(f'unsupported et_reference_resample: {et_reference_resample}')

# TODO: Check if model_args can be modified instead of making new variables
if 'et_reference_factor' in model_args.keys():
et_reference_factor = model_args['et_reference_factor']
else:
et_reference_factor = 1.0
logging.debug('et_reference_factor was not set, default to 1.0')
elif (('et_reference_source' in model_args.keys()) and
('et_reference_band' in model_args.keys())):
et_reference_source = model_args['et_reference_source']
et_reference_band = model_args['et_reference_band']

if 'et_reference_resample' in model_args.keys():
et_reference_resample = model_args['et_reference_resample'].lower()
else:
et_reference_resample = 'nearest'
logging.debug('et_reference_resample was not set, default to nearest')
if 'et_reference_factor' in model_args.keys():
et_reference_factor = model_args['et_reference_factor']
else:
et_reference_factor = 1.0
logging.debug('et_reference_factor was not set, default to 1.0')

if 'et_reference_resample' in model_args.keys():
et_reference_resample = model_args['et_reference_resample'].lower()
if not et_reference_resample:
et_reference_resample = 'nearest'
logging.debug('et_reference_resample was not set, default to nearest')
elif et_reference_resample not in RESAMPLE_METHODS:
raise ValueError(f'unsupported et_reference_resample method: '
f'{et_reference_resample}')
else:
et_reference_resample = 'nearest'
logging.debug('et_reference_resample was not set, default to nearest')

if et_reference_resample and (et_reference_resample not in RESAMPLE_METHODS):
raise ValueError(f'unsupported et_reference_resample: {et_reference_resample}')
if et_reference_resample and (et_reference_resample not in RESAMPLE_METHODS):
raise ValueError(f'unsupported et_reference_resample: {et_reference_resample}')

# Assume a string source is a single image collection ID
# not a list of collection IDs or ee.ImageCollection
daily_et_ref_coll = (
ee.ImageCollection(model_args['et_reference_source'])
.filterDate(start_date, end_date)
.select([model_args['et_reference_band']], ['et_reference'])
)
else:
raise ValueError('et_reference_source or et_reference_band were not set')

if type(et_reference_source) is str:
# Assume a string source is a single image collection ID
# not a list of collection IDs or ee.ImageCollection
daily_et_ref_coll = (
ee.ImageCollection(et_reference_source)
.filterDate(start_date, end_date)
.select([et_reference_band], ['et_reference'])
)
# elif isinstance(et_reference_source, computedobject.ComputedObject):
# # Interpret computed objects as image collections
else:
raise ValueError(f'unsupported et_reference_source: {et_reference_source}')

# Scale reference ET images (if necessary)
if et_reference_factor and (et_reference_factor != 1):
Expand All @@ -975,6 +1067,47 @@ def et_reference_adjust(input_img):
.select([interp_args['interp_band']])
)

# ############
# def interpolate_prep(img):
# """Prep WRS2 scene images for interpolation
#
# "Unscale" the images using the "scale_factor" property and convert to double.
# Add a mask and time band to each image in the scene_coll since
# interpolator is assuming time and mask bands exist.
# The interpolation could be modified to get the mask from the
# time band instead of setting it here.
# The time image must be the 0 UTC time
#
# """
# mask_img = (
# img.select(['et']).multiply(0).add(1).updateMask(1).uint8()
# .rename('mask')
# )
# time_img = (
# img.select(['et']).double().multiply(0)
# .add(utils.date_0utc(ee.Date(img.get('system:time_start'))).millis())
# .rename('time')
# )
#
# # Set the default scale factor to 1 if the image does not have the property
# scale_factor = (
# ee.Dictionary({'scale_factor': img.get('scale_factor')})
# .combine({'scale_factor': 1.0}, overwrite=False)
# )
#
# return (
# img.select(['et'])
# .double().multiply(ee.Number(scale_factor.get('scale_factor')))
# .addBands([mask_img, time_img])
# .set({
# 'system:time_start': ee.Number(img.get('system:time_start')),
# 'system:index': ee.String(img.get('system:index')),
# })
# )
#
# scene_coll = scene_coll.map(interpolate_prep)
# ###########

# For count, compute the composite/mosaic image for the mask band only
if 'count' in variables:
aggregate_coll = aggregate_to_daily(
Expand Down
Loading

0 comments on commit 3a867a9

Please sign in to comment.