def ue_trend(year_start, year_end, ndvi_1yr, climate_1yr, logger): # Convert the climate layer to meters (for precip) so that RUE layer can be # scaled correctly # TODO: Need to handle scaling for ET for WUE climate_1yr = climate_1yr.divide(1000) logger.debug("Entering ue_trend function.") def f_img_coll(ndvi_stack): img_coll = ee.List([]) for k in range(year_start, year_end + 1): ndvi_img = ndvi_stack.select('y{}'.format(k)).divide(climate_1yr.select('y{}'.format(k)))\ .addBands(ee.Image(k).float())\ .rename(['ue', 'year']).set({'year': k}) img_coll = img_coll.add(ndvi_img) return ee.ImageCollection(img_coll) ## Apply function to compute ue and store as a collection ue_1yr_coll = f_img_coll(ndvi_1yr) ## Compute linear trend function to predict ndvi based on year (ndvi trend) lf_trend = ue_1yr_coll.select(['year', 'ue']).reduce(ee.Reducer.linearFit()) ## Compute Kendall statistics mk_trend = stats.mann_kendall(ue_1yr_coll.select('ue')) return (lf_trend, mk_trend)
def ndvi_trend(year_start, year_end, ndvi_1yr, logger): """Calculate temporal NDVI analysis. Calculates the trend of temporal NDVI using NDVI data from the MODIS Collection 6 MOD13Q1 dataset. Areas where changes are not significant are masked out using a Mann-Kendall test. Args: year_start: The starting year (to define the period the trend is calculated over). year_end: The ending year (to define the period the trend is calculated over). Returns: Output of google earth engine task. """ logger.debug("Entering ndvi_trend function.") def f_img_coll(ndvi_stack): img_coll = ee.List([]) for k in range(year_start, year_end + 1): ndvi_img = ndvi_stack.select('y' + str(k)).addBands(ee.Image(k).float()).rename(['ndvi', 'year']) img_coll = img_coll.add(ndvi_img) return ee.ImageCollection(img_coll) ## Apply function to compute NDVI annual integrals from 15d observed NDVI data ndvi_1yr_coll = f_img_coll(ndvi_1yr) ## Compute linear trend function to predict ndvi based on year (ndvi trend) lf_trend = ndvi_1yr_coll.select(['year', 'ndvi']).reduce(ee.Reducer.linearFit()) ## Compute Kendall statistics mk_trend = stats.mann_kendall(ndvi_1yr_coll.select('ndvi')) return (lf_trend, mk_trend)
def restrend_pointwise(year_start, year_end, geojson, EXECUTION_ID, logger): """Calculate temporal NDVI analysis. Calculates the trend of temporal NDVI using NDVI data from the MODIS Collection 6 MOD13Q1 dataset. Areas where changes are not significant are masked out using a Mann-Kendall test. Args: year_start: The starting year (to define the period the trend is calculated over). year_end: The ending year (to define the period the trend is calculated over). geojson: A polygon defining the area of interest. Returns: Output of google earth engine task. """ # Function to integrate NDVI dataset from 15d to 1yr def int_15d_1yr_clim(img_stack): img_coll = ee.List([]) for k in range(1, 34): ndvi_lyr = img_stack.select( ee.List.sequence((k - 1) * 24, (k * 24) - 1)).reduce( ee.Reducer.mean()).rename(['ndvi']).set({'year': 1981 + k}) img_coll = img_coll.add(ndvi_lyr) return ee.ImageCollection(img_coll) # Function to compute differences between observed and predicted NDVI and comilation in an image collection def stack(year_start, year_end): img_coll = ee.List([]) for k in range(year_start, year_end): ndvi = ndvi_1yr_o.filter(ee.Filter.eq('year', k)).select('ndvi').median() clim = clim_1yr_o.filter(ee.Filter.eq('year', k)).select('ndvi').median() img = ndvi.addBands(clim.addBands(ee.Image(k).float())).rename( ['ndvi', 'clim', 'year']).set({'year': k}) img_coll = img_coll.add(img) return ee.ImageCollection(img_coll) # Function to predict NDVI from climate first = ee.List([]) def ndvi_clim_p(image, list): ndvi = lf_clim_ndvi.select('offset').add( (lf_clim_ndvi.select('scale').multiply(image))).set( {'year': image.get('year')}) return ee.List(list).add(ndvi) # Create image collection of residuals def ndvi_res(year_start, year_end): img_coll = ee.List([]) for k in range(year_start, year_end): ndvi_o = coll_1yr_o.filter(ee.Filter.eq( 'year', k)).select('ndvi').median() ndvi_p = ndvi_1yr_p.filter(ee.Filter.eq('year', k)).median() ndvi_r = ee.Image(k).float().addBands(ndvi_o.subtract(ndvi_p)) img_coll = img_coll.add(ndvi_r.rename(['year', 'ndvi_res'])) return ee.ImageCollection(img_coll) ndvi_1yr_o = preproc.modis_ndvi_annual_integral(year_start, year_end) # TODO: define clim_15d_o which is the merra-2 soil moisture data. For now, # forcing use of Senegal data for testing. clim_15d_o = ee.Image( 'users/geflanddegradation/soil/sen_soilm_merra2_15d_1982_2015') # Apply function to compute climate annual integrals from 15d observed data clim_1yr_o = int_15d_1yr_clim(clim_15d_o.divide(10000)) # Apply function to create image collection with stack of NDVI int, climate int and year coll_1yr_o = stack(year_start, year_end) # Reduce the collection with the linear fit reducer (independent var are followed by dependent var) lf_clim_ndvi = coll_1yr_o.select(['clim', 'ndvi']).reduce(ee.Reducer.linearFit()) # Apply function to predict NDVI based on climate ndvi_1yr_p = ee.ImageCollection( ee.List(coll_1yr_o.select('clim').iterate(ndvi_clim_p, first))) # Apply function to compute NDVI annual residuals ndvi_1yr_r = ndvi_res(year_start, year_end) # Fit a linear regression to the NDVI residuals lf_prest = ndvi_1yr_r.select(['year', 'ndvi_res']).reduce(ee.Reducer.linearFit()) # Compute Kendall statistics mk_prest = stats.mann_kendall(ndvi_1yr_r.select('ndvi_res')) # Define Kendall parameter values for a significance of 0.05 period = year_end - year_start + 1 coefficients = ee.Array([ 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 31, 33, 36, 40, 43, 47, 50, 54, 59, 63, 66, 70, 75, 79, 84, 88, 93, 97, 102, 106, 111, 115, 120, 126, 131, 137, 142 ]) kendall = coefficients.get([period - 4]) # Create export function export = { 'image': lf_prest.select('scale').where( mk_prest.abs().lte(kendall), -99999).where( lf_prest.select('scale').abs().lte(0.000001), -99999).unmask(-99999), 'description': EXECUTION_ID, 'fileNamePrefix': EXECUTION_ID, 'bucket': BUCKET, 'maxPixels': 10000000000, 'scale': 250, 'region': util.get_coords(geojson) } # Export final mosaic to assets task = ee.batch.Export.image.toCloudStorage(**export) task.start() task_state = task.status().get('state') while task_state == 'READY' or task_state == 'RUNNING': task_progress = task.status().get('progress', 0.0) # update GEF-EXECUTION progress logger.send_progress(task_progress) # update variable to check the condition task_state = task.status().get('state') sleep(5) return "https://{}.storage.googleapis.com/{}.tif".format( BUCKET, EXECUTION_ID)
def p_restrend(year_start, year_end, ndvi_1yr, climate_1yr, logger): logger.debug("Entering p_restrend function.") def f_img_coll(ndvi_stack): img_coll = ee.List([]) for k in range(year_start, year_end + 1): ndvi_img = ndvi_stack.select('y{}'.format(k))\ .addBands(climate_1yr.select('y{}'.format(k)))\ .rename(['ndvi', 'clim']).set({'year': k}) img_coll = img_coll.add(ndvi_img) return ee.ImageCollection(img_coll) ## Function to predict NDVI from climate first = ee.List([]) def f_ndvi_clim_p(image, list): ndvi = lf_clim_ndvi.select('offset').add((lf_clim_ndvi.select('scale').multiply(image))).set({'year': image.get('year')}) return ee.List(list).add(ndvi) ## Function to compute residuals (ndvi obs - ndvi pred) def f_ndvi_clim_r_img(year): ndvi_o = ndvi_1yr_coll.filter(ee.Filter.eq('year', year)).select('ndvi').median() ndvi_p = ndvi_1yr_p.filter(ee.Filter.eq('year', year)).median() ndvi_r = ee.Image(year).float().addBands(ndvi_o.subtract(ndvi_p)) return ndvi_r.rename(['year', 'ndvi_res']) # Function to compute differences between observed and predicted NDVI and compilation in an image collection def stack(year_start, year_end): img_coll = ee.List([]) for k in range(year_start, year_end + 1): ndvi = ndvi_1yr_o.filter(ee.Filter.eq('year', k)).select('ndvi').median() clim = clim_1yr_o.filter(ee.Filter.eq('year', k)).select('ndvi').median() img = ndvi.addBands(clim.addBands(ee.Image(k).float())).rename(['ndvi', 'clim', 'year']).set({'year': k}) img_coll = img_coll.add(img) return ee.ImageCollection(img_coll) ## Function create image collection of residuals def f_ndvi_clim_r_coll(year_start, year_end): res_list = ee.List([]) #for(i = year_start i <= year_end i += 1): for i in range(year_start, year_end + 1): res_image = f_ndvi_clim_r_img(i) res_list = res_list.add(res_image) return ee.ImageCollection(res_list) ## Apply function to create image collection of ndvi and climate ndvi_1yr_coll = f_img_coll(ndvi_1yr) ## Compute linear trend function to predict ndvi based on climate (independent are followed by dependent var lf_clim_ndvi = ndvi_1yr_coll.select(['clim', 'ndvi']).reduce(ee.Reducer.linearFit()) ## Apply function to predict NDVI based on climate ndvi_1yr_p = ee.ImageCollection(ee.List(ndvi_1yr_coll.select('clim').iterate(f_ndvi_clim_p, first))) ## Apply function to compute NDVI annual residuals ndvi_1yr_r = f_ndvi_clim_r_coll(year_start, year_end) ## Fit a linear regression to the NDVI residuals lf_trend = ndvi_1yr_r.select(['year', 'ndvi_res']).reduce(ee.Reducer.linearFit()) ## Compute Kendall statistics mk_trend = stats.mann_kendall(ndvi_1yr_r.select('ndvi_res')) return (lf_trend, mk_trend)
def restrend_system(year_start, year_end, geojson, EXECUTION_ID, logger): """Calculate temporal NDVI analysis. Calculates the trend of temporal NDVI using NDVI data from the MODIS Collection 6 MOD13Q1 dataset. Areas where changes are not significant are masked out using a Mann-Kendall test. Args: year_start: The starting year (to define the period the trend is calculated over). year_end: The ending year (to define the period the trend is calculated over). geojson: A polygon defining the area of interest. Returns: Output of google earth engine task. """ # Function to integrate NDVI dataset from 15d to 1yr def int_15d_1yr_p(img_stack): img_coll = ee.List([]) for k in range(1, 34): ndvi_lyr = img_stack.select( ee.List.sequence((k - 1) * 24, (k * 24) - 1)).reduce( ee.Reducer.mean()).rename(['ndvi']).set({'year': 1981 + k}) img_coll = img_coll.add(ndvi_lyr) return ee.ImageCollection(img_coll) # Create image collection of residuals def ndvi_res(year_start, year_end): img_coll = ee.List([]) for k in range(year_start, year_end): ndvi_o = coll_1yr_o.filter(ee.Filter.eq( 'year', k)).select('ndvi').median() ndvi_p = ndvi_1yr_p.filter(ee.Filter.eq('year', k)).median() ndvi_r = ee.Image(k).float().addBands(ndvi_o.subtract(ndvi_p)) img_coll = img_coll.add(ndvi_r.rename(['year', 'ndvi_res'])) return ee.ImageCollection(img_coll) # Conversion of soil moisture to NDVI using equations developed by NASA presented in the report 1 # TODO: define clim_15d_o which is the merra-2 soil moisture data. For now, # forcing use of Senegal data for testing. clim_15d_o = ee.Image( 'users/geflanddegradation/soil/sen_soilm_merra2_15d_1982_2015') ndvi_p1 = clim_15d_o.divide(10000).multiply(0.11).add(0.19) ndvi_p2 = clim_15d_o.divide(10000).multiply(6.63).add(-2.22) ndvi_p3 = clim_15d_o.divide(10000).pow(3).multiply(1.38).add( clim_15d_o.divide(10000).pow(2).multiply(-3.83)).add( clim_15d_o.divide(10000).multiply(3.83)).add(-0.63) # Conditional statement to combine the 3 NDVI estimates into one image ndvi_15d_p = ndvi_p2.where(clim_15d_o.lte(0.37 * 10000), ndvi_p1).where(clim_15d_o.gte(0.39 * 10000), ndvi_p3) # Apply function to compute predicted NDVI annual integrals from 15d predicted NDVI data ndvi_1yr_p = int_15d_1yr_p(ndvi_15d_p) coll_1yr_o = preproc.modis_ndvi_annual_integral(year_start, year_end) # Compute differences between observed and predicted NDVI annual integrals ndvi_1yr_r = ndvi_res(year_start, year_end) # Fit a linear regression to the NDVI differences lf_srest = ndvi_1yr_r.select(['year', 'ndvi_res']).reduce(ee.Reducer.linearFit()) # Compute Kendall statistics mk_srest = stats.mann_kendall(ndvi_1yr_r.select('ndvi_res')) # Define Kendall parameter values for a significance of 0.05 period = year_end - year_start + 1 coefficients = ee.Array([ 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 31, 33, 36, 40, 43, 47, 50, 54, 59, 63, 66, 70, 75, 79, 84, 88, 93, 97, 102, 106, 111, 115, 120, 126, 131, 137, 142 ]) kendall = coefficients.get([period - 4]) # Create export function export = { 'image': lf_srest.select('scale').where( mk_srest.abs().lte(kendall), -99999).where( lf_srest.select('scale').abs().lte(0.000001), -99999).unmask(-99999), 'description': EXECUTION_ID, 'fileNamePrefix': EXECUTION_ID, 'bucket': BUCKET, 'maxPixels': 10000000000, 'scale': 250, 'region': util.get_coords(geojson) } # Export final mosaic to assets task = ee.batch.Export.image.toCloudStorage(**export) task.start() task_state = task.status().get('state') while task_state == 'READY' or task_state == 'RUNNING': task_progress = task.status().get('progress', 0.0) # update GEF-EXECUTION progress logger.send_progress(task_progress) # update variable to check the condition task_state = task.status().get('state') sleep(5) return "https://{}.storage.googleapis.com/{}.tif".format( BUCKET, EXECUTION_ID)
def integral_trend(year_start, year_end, geojson, EXECUTION_ID, logger): """Calculate annual trend of integrated NDVI. Calculates the trend of annual integrated NDVI using NDVI data from the MODIS Collection 6 MOD13Q1 dataset. Areas where changes are not significant are masked out using a Mann-Kendall test. Args: year_start: The starting year (to define the period the trend is calculated over). year_end: The ending year (to define the period the trend is calculated over). geojson: A polygon defining the area of interest. EXECUTION_ID: String identifying this process, used in naming the results. Returns: Location of output on google cloud storage. """ # Compute NDVI annual integrals from 15d observed NDVI data ndvi_1yr_o = preproc.modis_ndvi_annual_integral(year_start, year_end) # Compute linear trend function to predict ndvi based on year (ndvi trend) lf_trend = ndvi_1yr_o.select(['year', 'ndvi']).reduce(ee.Reducer.linearFit()) # Define Kendall parameter values for a significance of 0.05 period = year_end - year_start + 1 coefficients = ee.Array([ 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 31, 33, 36, 40, 43, 47, 50, 54, 59, 63, 66, 70, 75, 79, 84, 88, 93, 97, 102, 106, 111, 115, 120, 126, 131, 137, 142 ]) kendall = coefficients.get([period - 4]) # Compute Kendall statistics mk_trend = stats.mann_kendall(ndvi_1yr_o.select('ndvi')) export = { 'image': lf_trend.select('scale').where( mk_trend.abs().lte(kendall), -99999).where( lf_trend.select('scale').abs().lte(0.000001), -99999).unmask(-99999), 'description': EXECUTION_ID, 'fileNamePrefix': EXECUTION_ID, 'bucket': BUCKET, 'maxPixels': 10000000000, 'scale': 250, 'region': util.get_coords(geojson) } # Export final mosaic to assets task = ee.batch.Export.image.toCloudStorage(**export) # Task -> READY task.start() task_state = task.status().get('state') while task_state == 'READY' or task_state == 'RUNNING': task_progress = task.status().get('progress', 0.0) # update GEF-EXECUTION progress logger.send_progress(task_progress) # update variable to check the condition task_state = task.status().get('state') sleep(5) return "https://{}.storage.googleapis.com/{}.tif".format( BUCKET, EXECUTION_ID)