def clip_project_raster_func(input_raster, resampling_type, input_osr, input_cs, input_extent, ouput_osr, output_cs, output_extent): """Clip and then project an input raster""" # Read array from input raster using input extent input_array = drigo.raster_to_array(input_raster, 1, input_extent, return_nodata=False) # Project and clip array to block output_array = drigo.project_array(input_array, resampling_type, input_osr, input_cs, input_extent, ouput_osr, output_cs, output_extent) return output_array
def metric_weather_func(output_raster, input_ws, input_re, prev_dt, next_dt, resample_method=gdal.GRA_NearestNeighbour, rounding_flag=False): """Interpolate/project/clip METRIC hourly rasters""" logging.debug(' Output: {}'.format(output_raster)) if os.path.isfile(output_raster): if overwrite_flag: logging.debug(' Overwriting output') dripy.remove_file(output_raster) else: logging.debug(' Skipping, file already exists ' + 'and overwrite is False') return False prev_ws = os.path.join(input_ws, str(prev_dt.year)) next_ws = os.path.join(input_ws, str(next_dt.year)) # Technically previous and next could come from different days # or even years, although this won't happen in the U.S. try: prev_path = [ os.path.join(prev_ws, input_name) for input_name in os.listdir(prev_ws) for input_match in [input_re.match(input_name)] if (input_match and (prev_dt.strftime('%Y%m%d') == input_match.group('YYYYMMDD')))][0] logging.debug(' Input prev: {}'.format(prev_path)) except IndexError: logging.error(' No previous hourly file') logging.error(' {}'.format(prev_dt)) return False try: next_path = [ os.path.join(next_ws, input_name) for input_name in os.listdir(next_ws) for input_match in [input_re.match(input_name)] if (input_match and (next_dt.strftime('%Y%m%d') == input_match.group('YYYYMMDD')))][0] logging.debug(' Input next: {}'.format(next_path)) except IndexError: logging.error(' No next hourly file') logging.error(' {}'.format(next_dt)) return False # Band numbers are 1's based prev_band = int(prev_dt.strftime('%H')) + 1 next_band = int(next_dt.strftime('%H')) + 1 logging.debug(' Input prev band: {}'.format(prev_band)) logging.debug(' Input next band: {}'.format(next_band)) # Read arrays prev_array = drigo.raster_to_array( prev_path, band=prev_band, mask_extent=common_gcs_extent, return_nodata=False) next_array = drigo.raster_to_array( next_path, band=next_band, mask_extent=common_gcs_extent, return_nodata=False) if not np.any(prev_array) or not np.any(next_array): logging.warning('\nWARNING: Input NLDAS array is all nodata\n') return None output_array = hourly_interpolate_func( prev_array, next_array, prev_dt, next_dt, image.acq_datetime) output_array = drigo.project_array( output_array, resample_method, input_osr, input_cs, common_gcs_extent, common_osr, env.cellsize, common_extent, output_nodata=None) # Apply common area mask output_array[~common_array] = np.nan # Reduce the file size by rounding to the nearest n digits if rounding_flag: output_array = np.around(output_array, rounding_digits) # Force output to 32-bit float drigo.array_to_raster( output_array.astype(np.float32), output_raster, output_geo=common_geo, output_proj=common_proj, stats_flag=stats_flag) del output_array return True
def main(image_ws, ini_path, bs=2048, stats_flag=False, overwrite_flag=False): """Prep a Landsat scene for METRIC Parameters ---------- image_ws : str Landsat scene folder that will be prepped. ini_path : str File path of the input parameters file. bs : int, optional Processing block size (the default is 2048). stats_flag : bool, optional If True, compute raster statistics (the default is True). overwrite_flag : bool, optional If True, overwrite existing files (the default is False). Returns ------- True is successful """ # Open config file config = dripy.open_ini(ini_path) # Get input parameters logging.debug(' Reading Input File') calc_refl_toa_flag = dripy.read_param( 'calc_refl_toa_flag', True, config, 'INPUTS') calc_refl_toa_qa_flag = dripy.read_param( 'calc_refl_toa_qa_flag', True, config, 'INPUTS') # calc_refl_sur_ledaps_flag = dripy.read_param( # 'calc_refl_sur_ledaps_flag', False, config, 'INPUTS') # calc_refl_sur_qa_flag = dripy.read_param( # 'calc_refl_sur_qa_flag', False, config, 'INPUTS') calc_ts_bt_flag = dripy.read_param( 'calc_ts_bt_flag', True, config, 'INPUTS') # Use QA band to set common area # Fmask cloud, shadow, & snow pixels will be removed from common area calc_fmask_common_flag = dripy.read_param( 'calc_fmask_common_flag', True, config, 'INPUTS') fmask_smooth_flag = dripy.read_param( 'fmask_smooth_flag', False, config, 'INPUTS') fmask_buffer_flag = dripy.read_param( 'fmask_buffer_flag', False, config, 'INPUTS') fmask_erode_flag = dripy.read_param( 'fmask_erode_flag', False, config, 'INPUTS') if fmask_smooth_flag: fmask_smooth_cells = int(dripy.read_param( 'fmask_smooth_cells', 1, config, 'INPUTS')) if fmask_smooth_cells == 0 and fmask_smooth_flag: fmask_smooth_flag = False if fmask_erode_flag: fmask_erode_cells = int(dripy.read_param( 'fmask_erode_cells', 1, config, 'INPUTS')) if fmask_erode_cells == 0 and fmask_erode_flag: fmask_erode_flag = False if fmask_buffer_flag: fmask_buffer_cells = int(dripy.read_param( 'fmask_buffer_cells', 1, config, 'INPUTS')) if fmask_buffer_cells == 0 and fmask_buffer_flag: fmask_buffer_flag = False # Remove edge (fringe) cells edge_smooth_flag = dripy.read_param( 'edge_smooth_flag', True, config, 'INPUTS') # Include hand made cloud masks cloud_mask_flag = dripy.read_param( 'cloud_mask_flag', False, config, 'INPUTS') cloud_mask_ws = "" if cloud_mask_flag: cloud_mask_ws = config.get('INPUTS', 'cloud_mask_ws') # Extract separate Fmask rasters calc_fmask_flag = dripy.read_param( 'calc_fmask_flag', True, config, 'INPUTS') calc_fmask_cloud_flag = dripy.read_param( 'calc_fmask_cloud_flag', True, config, 'INPUTS') calc_fmask_snow_flag = dripy.read_param( 'calc_fmask_snow_flag', True, config, 'INPUTS') calc_fmask_water_flag = dripy.read_param( 'calc_fmask_water_flag', True, config, 'INPUTS') # Keep Landsat DN, LEDAPS, and Fmask rasters keep_dn_flag = dripy.read_param( 'keep_dn_flag', True, config, 'INPUTS') # keep_sr_flag = dripy.read_param( # 'keep_sr_flag', True, config, 'INPUTS') # For this to work I would need to pass in the metric input file # calc_elev_flag = dripy.read_param( # 'calc_elev_flag', False, config, 'INPUTS') # calc_landuse_flag = dripy.read_param( # 'calc_landuse_flag', False, config, 'INPUTS') # calc_acca_cloud_flag = dripy.read_param( # 'calc_acca_cloud_flag', True, config, 'INPUTS') # calc_acca_snow_flag = dripy.read_param( # 'calc_acca_snow_flag', True, config, 'INPUTS') # calc_ledaps_dem_land_flag = dripy.read_param( # 'calc_ledaps_dem_land_flag', False, config, 'INPUTS') # calc_ledaps_veg_flag = dripy.read_param( # 'calc_ledaps_veg_flag', False, config, 'INPUTS') # calc_ledaps_snow_flag = dripy.read_param( # 'calc_ledaps_snow_flag', False, config, 'INPUTS') # calc_ledaps_land_flag = dripy.read_param( # 'calc_ledaps_land_flag', False, config, 'INPUTS') # calc_ledaps_cloud_flag = dripy.read_param( # 'calc_ledaps_cloud_flag', False, config, 'INPUTS') # Interpolate/clip/project hourly rasters for each Landsat scene # calc_metric_flag = dripy.read_param( # 'calc_metric_flag', False, config, 'INPUTS') calc_metric_ea_flag = dripy.read_param( 'calc_metric_ea_flag', False, config, 'INPUTS') calc_metric_wind_flag = dripy.read_param( 'calc_metric_wind_flag', False, config, 'INPUTS') calc_metric_etr_flag = dripy.read_param( 'calc_metric_etr_flag', False, config, 'INPUTS') calc_metric_tair_flag = dripy.read_param( 'calc_metric_tair_flag', False, config, 'INPUTS') # Interpolate/clip/project AWC and daily ETr/PPT rasters # to compute SWB Ke for each Landsat scene calc_swb_ke_flag = dripy.read_param( 'calc_swb_ke_flag', False, config, 'INPUTS') if cloud_mask_flag: spinup_days = dripy.read_param( 'swb_spinup_days', 30, config, 'INPUTS') min_spinup_days = dripy.read_param( 'swb_min_spinup_days', 5, config, 'INPUTS') # Round ea raster to N digits to save space rounding_digits = dripy.read_param( 'rounding_digits', 3, config, 'INPUTS') env = drigo.env image = et_image.Image(image_ws, env) np.seterr(invalid='ignore', divide='ignore') gdal.UseExceptions() # Input file paths dn_image_dict = et_common.landsat_band_image_dict( image.orig_data_ws, image.image_name_re) # # Open METRIC config file # if config_file: # logging.info( # log_f.format('METRIC INI File:', os.path.basename(config_file))) # config = configparser.ConfigParser() # try: # config.read(config_file) # except: # logging.error('\nERROR: Config file could not be read, ' + # 'is not an input file, or does not exist\n' + # 'ERROR: config_file = {}\n').format(config_file) # sys.exit() # # Overwrite # overwrite_flag = dripy.read_param('overwrite_flag', True, config) # # # Elevation and landuse parameters/flags from METRIC input file # calc_elev_flag = dripy.read_param('save_dem_raster_flag', True, config) # calc_landuse_flag = dripy.read_param( # 'save_landuse_raster_flag', True, config) # if calc_elev_flag: # elev_pr_path = config.get('INPUTS','dem_raster') # if calc_landuse_flag: # landuse_pr_path = config.get('INPUTS', 'landuse_raster') # else: # overwrite_flag = False # calc_elev_flag = False # calc_landuse_flag = False # # Elev raster must exist # if calc_elev_flag and not os.path.isfile(elev_pr_path): # logging.error('\nERROR: Elevation raster {} does not exist\n'.format( # elev_pr_path)) # return False # Landuse raster must exist # if calc_landuse_flag and not os.path.isfile(landuse_pr_path): # logging.error('\nERROR: Landuse raster {} does not exist\n'.format( # landuse_pr_path)) # return False # Removing ancillary files before checking for inputs if os.path.isdir(os.path.join(image.orig_data_ws, 'gap_mask')): shutil.rmtree(os.path.join(image.orig_data_ws, 'gap_mask')) for item in os.listdir(image.orig_data_ws): if (image.type == 'Landsat7' and (item.endswith('_B8.TIF') or item.endswith('_B6_VCID_2.TIF'))): os.remove(os.path.join(image.orig_data_ws, item)) elif (image.type == 'Landsat8' and (item.endswith('_B1.TIF') or item.endswith('_B8.TIF') or item.endswith('_B9.TIF') or item.endswith('_B11.TIF'))): os.remove(os.path.join(image.orig_data_ws, item)) elif (item.endswith('_VER.jpg') or item.endswith('_VER.txt') or item.endswith('_GCP.txt') or item == 'README.GTF'): os.remove(os.path.join(image.orig_data_ws, item)) # Check correction level (image must be L1T to process) if image.correction != 'L1TP': logging.debug(' Image is not L1TP corrected, skipping') return False # calc_fmask_common_flag = False # calc_refl_toa_flag = False # calc_ts_bt_flag = False # calc_metric_ea_flag = False # calc_metric_wind_flag = False # calc_metric_etr_flag = False # overwrite_flag = False # QA band must exist if calc_fmask_common_flag and image.qa_band not in dn_image_dict.keys(): logging.warning( '\nQA band does not exist but calc_fmask_common_flag=True' '\n Setting calc_fmask_common_flag=False\n {}'.format( image.qa_band)) calc_fmask_common_flag = False if cloud_mask_flag and not os.path.isdir(cloud_mask_ws): logging.warning( '\ncloud_mask_ws is not a directory but cloud_mask_flag=True.' '\n Setting cloud_mask_flag=False\n {}'.format(cloud_mask_ws)) cloud_mask_flag = False # Check for Landsat TOA images if (calc_refl_toa_flag and (set(list(image.band_toa_dict.keys()) + [image.thermal_band, image.qa_band]) != set(dn_image_dict.keys()))): logging.warning( '\nMissing Landsat images but calc_refl_toa_flag=True' '\n Setting calc_refl_toa_flag=False') calc_refl_toa_flag = False # Check for Landsat brightness temperature image if calc_ts_bt_flag and image.thermal_band not in dn_image_dict.keys(): logging.warning( '\nThermal band image does not exist but calc_ts_bt_flag=True' '\n Setting calc_ts_bt_flag=False') calc_ts_bt_flag = False # DEADBEEF - Should the function return False if Ts doesn't exist? # return False # Check for METRIC hourly/daily input folders if calc_metric_ea_flag: metric_ea_input_ws = config.get('INPUTS', 'metric_ea_input_folder') if not os.path.isdir(metric_ea_input_ws): logging.warning( '\nHourly Ea folder does not exist but calc_metric_ea_flag=True' '\n Setting calc_metric_ea_flag=False\n {}'.format( metric_ea_input_ws)) calc_metric_ea_flag = False if calc_metric_wind_flag: metric_wind_input_ws = config.get('INPUTS', 'metric_wind_input_folder') if not os.path.isdir(metric_wind_input_ws): logging.warning( '\nHourly wind folder does not exist but calc_metric_wind_flag=True' '\n Setting calc_metric_wind_flag=False\n {}'.format( metric_wind_input_ws)) calc_metric_wind_flag = False if calc_metric_etr_flag: metric_etr_input_ws = config.get('INPUTS', 'metric_etr_input_folder') if not os.path.isdir(metric_etr_input_ws): logging.warning( '\nHourly ETr folder does not exist but calc_metric_etr_flag=True' '\n Setting calc_metric_etr_flag=False\n {}'.format( metric_etr_input_ws)) calc_metric_etr_flag = False if calc_metric_tair_flag: metric_tair_input_ws = config.get('INPUTS', 'metric_tair_input_folder') if not os.path.isdir(metric_tair_input_ws): logging.warning( '\nHourly Tair folder does not exist but calc_metric_tair_flag=True' '\n Setting calc_metric_tair_flag=False\n {}'.format( metric_tair_input_ws)) calc_metric_tair_flag = False if (calc_metric_ea_flag or calc_metric_wind_flag or calc_metric_etr_flag or calc_metric_tair_flag): metric_hourly_re = re.compile(config.get('INPUTS', 'metric_hourly_re')) metric_daily_re = re.compile(config.get('INPUTS', 'metric_daily_re')) if calc_swb_ke_flag: awc_input_path = config.get('INPUTS', 'awc_input_path') etr_input_ws = config.get('INPUTS', 'etr_input_folder') ppt_input_ws = config.get('INPUTS', 'ppt_input_folder') etr_input_re = re.compile(config.get('INPUTS', 'etr_input_re')) ppt_input_re = re.compile(config.get('INPUTS', 'ppt_input_re')) if not os.path.isfile(awc_input_path): logging.warning( '\nAWC raster does not exist but calc_swb_ke_flag=True' '\n Setting calc_swb_ke_flag=False\n {}'.format( awc_input_path)) calc_swb_ke_flag = False if not os.path.isdir(etr_input_ws): logging.warning( '\nDaily ETr folder does not exist but calc_swb_ke_flag=True' '\n Setting calc_swb_ke_flag=False\n {}'.format( etr_input_ws)) calc_swb_ke_flag = False if not os.path.isdir(ppt_input_ws): logging.warning( '\nDaily PPT folder does not exist but calc_swb_ke_flag=True' '\n Setting calc_swb_ke_flag=False\n {}'.format( ppt_input_ws)) calc_swb_ke_flag = False # Build folders for support rasters if ((calc_fmask_common_flag or calc_refl_toa_flag or # calc_refl_sur_ledaps_flag or calc_ts_bt_flag or calc_metric_ea_flag or calc_metric_wind_flag or calc_metric_etr_flag or calc_metric_tair_flag or calc_swb_ke_flag) and not os.path.isdir(image.support_ws)): os.makedirs(image.support_ws) if calc_refl_toa_flag and not os.path.isdir(image.refl_toa_ws): os.makedirs(image.refl_toa_ws) # if calc_refl_sur_ledaps_flag and not os.path.isdir(image.refl_sur_ws): # os.makedirs(image.refl_sur_ws) # DEADBEEF - This is being further down just for the Fmask images # # Apply overwrite flag # if overwrite_flag: # overwrite_list = [ # image.fmask_cloud_raster, image.fmask_snow_raster, # image.fmask_water_raster # # image.elev_raster, image.landuse_raster # # image.common_area_raster # ] # for overwrite_path in overwrite_list: # try: # dripy.remove_file(image.fmask_cloud_raster) # except: # pass # Use QA band to build common area rasters logging.info('\nCommon Area Raster') qa_ds = gdal.Open(dn_image_dict[image.qa_band], 0) common_geo = drigo.raster_ds_geo(qa_ds) common_extent = drigo.raster_ds_extent(qa_ds) common_proj = drigo.raster_ds_proj(qa_ds) common_osr = drigo.raster_ds_osr(qa_ds) # Initialize common_area as all non-fill QA values qa_array = drigo.raster_ds_to_array(qa_ds, return_nodata=False) common_array = qa_array != 1 common_rows, common_cols = common_array.shape del qa_ds # Erode and dilate to remove fringe on edge # Default is to not smooth, but user can force smoothing # This needs to be applied before Fmask if edge_smooth_flag and image.prefix in ['LT05', 'LE07']: struct = ndimage.generate_binary_structure(2, 2).astype(np.uint8) if image.prefix == 'LT05': cells = 8 elif image.prefix == 'LE07': cells = 2 else: cells = 0 common_array = ndimage.binary_dilation( ndimage.binary_erosion(common_array, struct, cells), struct, cells) # Try applying user defined cloud masks to common_area cloud_mask_path = os.path.join( cloud_mask_ws, image.folder_id + '_mask.shp') if cloud_mask_flag and os.path.isfile(cloud_mask_path): logging.info(' Applying cloud mask shapefile') feature_path = os.path.join( cloud_mask_ws, (image.folder_id + '_mask.shp')) logging.info(' {}'.format(feature_path)) cloud_mask_memory_ds = drigo.polygon_to_raster_ds( feature_path, nodata_value=0, burn_value=1, output_osr=common_osr, output_cs=30, output_extent=common_extent) cloud_array = drigo.raster_ds_to_array( cloud_mask_memory_ds, return_nodata=False) # DEADBEEF - If user sets a cloud mask, # it is probably better than Fmask # Eventually change "if" calc_fmask_common_flag: to "elif" common_array[cloud_array == 1] = 0 del cloud_mask_memory_ds, cloud_array # Remove Fmask cloud, shadow, and snow pixels from common_area if calc_fmask_common_flag: logging.info(' Applying Fmask to common area') fmask_array = et_numpy.bqa_fmask_func(qa_array) fmask_mask = (fmask_array >= 2) & (fmask_array <= 4) if fmask_smooth_flag: logging.debug( ' Smoothing (dilate/erode/erode/dilate) Fmask clouds, shadows,' ' and snow pixels by {} cells'.format(fmask_smooth_cells)) # ArcGIS smoothing procedure fmask_mask = ndimage.binary_dilation( fmask_mask, iterations=fmask_smooth_cells, structure=ndimage.generate_binary_structure(2, 2)) fmask_mask = ndimage.binary_erosion( fmask_mask, iterations=fmask_smooth_cells, structure=ndimage.generate_binary_structure(2, 2)) fmask_mask = ndimage.binary_erosion( fmask_mask, iterations=fmask_smooth_cells, structure=ndimage.generate_binary_structure(2, 2)) fmask_mask = ndimage.binary_dilation( fmask_mask, iterations=fmask_smooth_cells, structure=ndimage.generate_binary_structure(2, 2)) if fmask_erode_flag: logging.debug( ' Eroding Fmask clouds, shadows, and snow pixels by ' '{} cells'.format(fmask_erode_cells)) fmask_mask = ndimage.binary_erosion( fmask_mask, iterations=fmask_erode_cells, structure=ndimage.generate_binary_structure(2, 2)) if fmask_buffer_flag: logging.debug( ' Dilating (buffering) Fmask clouds, shadows, and snow pixels ' 'by {} cells'.format(fmask_buffer_cells)) fmask_mask = ndimage.binary_dilation( fmask_mask, iterations=fmask_buffer_cells, structure=ndimage.generate_binary_structure(2, 2)) # Reset common_array for buffered cells common_array[fmask_mask] = 0 del fmask_array, fmask_mask # Check that there are some cloud free pixels if not np.any(common_array): logging.error( ' ERROR: There are no cloud/snow free pixels, returning False') return False # Always overwrite common area raster # if not os.path.isfile(image.common_area_raster): drigo.array_to_raster( common_array, image.common_area_raster, output_geo=common_geo, output_proj=common_proj, stats_flag=stats_flag) # Print common geo/extent logging.debug(' Common geo: {}'.format(common_geo)) logging.debug(' Common extent: {}'.format(common_extent)) # Extract Fmask components as separate rasters if (calc_fmask_flag or calc_fmask_cloud_flag or calc_fmask_snow_flag or calc_fmask_water_flag): logging.info('\nFmask') fmask_array = et_numpy.bqa_fmask_func(qa_array) # Remove existing Fmask rasters if (calc_fmask_flag and overwrite_flag and os.path.isfile(image.fmask_output_raster)): logging.debug(' Overwriting: {}'.format( image.fmask_output_raster)) dripy.remove_file(image.fmask_output_raster) if (calc_fmask_cloud_flag and overwrite_flag and os.path.isfile(image.fmask_cloud_raster)): logging.debug(' Overwriting: {}'.format( image.fmask_cloud_raster)) dripy.remove_file(image.fmask_cloud_raster) if (calc_fmask_snow_flag and overwrite_flag and os.path.isfile(image.fmask_snow_raster)): logging.debug(' Overwriting: {}'.format( image.fmask_snow_raster)) dripy.remove_file(image.fmask_snow_raster) if (calc_fmask_water_flag and overwrite_flag and os.path.isfile(image.fmask_water_raster)): logging.debug(' Overwriting: {}'.format( image.fmask_water_raster)) dripy.remove_file(image.fmask_water_raster) # Save Fmask data as separate rasters if (calc_fmask_flag and not os.path.isfile(image.fmask_output_raster)): logging.debug(' Saving Fmask raster') drigo.array_to_raster( fmask_array.astype(np.uint8), image.fmask_output_raster, output_geo=common_geo, output_proj=common_proj, mask_array=None, output_nodata=255, stats_flag=stats_flag) if (calc_fmask_cloud_flag and not os.path.isfile(image.fmask_cloud_raster)): logging.debug(' Saving Fmask cloud raster') fmask_cloud_array = (fmask_array == 2) | (fmask_array == 4) drigo.array_to_raster( fmask_cloud_array.astype(np.uint8), image.fmask_cloud_raster, output_geo=common_geo, output_proj=common_proj, mask_array=None, output_nodata=255, stats_flag=stats_flag) del fmask_cloud_array if (calc_fmask_snow_flag and not os.path.isfile(image.fmask_snow_raster)): logging.debug(' Saving Fmask snow raster') fmask_snow_array = (fmask_array == 3) drigo.array_to_raster( fmask_snow_array.astype(np.uint8), image.fmask_snow_raster, output_geo=common_geo, output_proj=common_proj, mask_array=None, output_nodata=255, stats_flag=stats_flag) del fmask_snow_array if (calc_fmask_water_flag and not os.path.isfile(image.fmask_water_raster)): logging.debug(' Saving Fmask water raster') fmask_water_array = (fmask_array == 1) drigo.array_to_raster( fmask_water_array.astype(np.uint8), image.fmask_water_raster, output_geo=common_geo, output_proj=common_proj, mask_array=None, output_nodata=255, stats_flag=stats_flag) del fmask_water_array del fmask_array # # Calculate elevation # if calc_elev_flag and not os.path.isfile(elev_path): # logging.info('Elevation') # elev_array, elev_nodata = drigo.raster_to_array( # elev_pr_path, 1, common_extent) # drigo.array_to_raster( # elev_array, elev_raster, # output_geo=common_geo, output_proj=env.snap_proj, # mask_array=common_array, stats_flag=stats_flag) # del elev_array, elev_nodata, elev_path # # # Calculate landuse # if calc_landuse_flag and not os.path.isfile(landuse_raster): # logging.info('Landuse') # landuse_array, landuse_nodata = drigo.raster_to_array( # landuse_pr_path, 1, common_extent) # drigo.array_to_raster( # landuse_array, landuse_raster, # output_geo=common_geo, output_proj=env.snap_proj, # mask_array=common_array, stats_flag=stats_flag) # del landuse_array, landuse_nodata, landuse_raster # Calculate toa reflectance # f32_gtype, f32_nodata = numpy_to_gdal_type(np.float32) if calc_refl_toa_flag: logging.info('Top-of-Atmosphere Reflectance') if os.path.isfile(image.refl_toa_raster) and overwrite_flag: logging.debug(' Overwriting: {}'.format( image.refl_toa_raster)) dripy.remove_file(image.refl_toa_raster) if not os.path.isfile(image.refl_toa_raster): # First build empty composite raster drigo.build_empty_raster( image.refl_toa_raster, image.band_toa_cnt, np.float32, None, env.snap_proj, env.cellsize, common_extent) # cos_theta_solar_flt = et_common.cos_theta_solar_func( # image.sun_elevation) # Process by block logging.info('Processing by block') logging.debug(' Mask cols/rows: {}/{}'.format( common_cols, common_rows)) for b_i, b_j in drigo.block_gen(common_rows, common_cols, bs): logging.debug(' Block y: {:5d} x: {:5d}'.format(b_i, b_j)) block_data_mask = drigo.array_to_block( common_array, b_i, b_j, bs).astype(np.bool) block_rows, block_cols = block_data_mask.shape block_geo = drigo.array_offset_geo(common_geo, b_j, b_i) block_extent = drigo.geo_extent( block_geo, block_rows, block_cols) logging.debug(' Block rows: {} cols: {}'.format( block_rows, block_cols)) logging.debug(' Block extent: {}'.format(block_extent)) logging.debug(' Block geo: {}'.format(block_geo)) # Process each TOA band # for band, band_i in sorted(image.band_toa_dict.items()): for band, dn_image in sorted(dn_image_dict.items()): if band not in image.band_toa_dict.keys(): continue # thermal_band_flag = (band == image.thermal_band) # Set 0 as nodata value drigo.raster_path_set_nodata(dn_image, 0) # Calculate TOA reflectance dn_array, dn_nodata = drigo.raster_to_array( dn_image, 1, block_extent) dn_array = dn_array.astype(np.float64) # dn_array = dn_array.astype(np.float32) dn_array[dn_array == 0] = np.nan # if image.type in ['Landsat4', 'Landsat5', 'Landsat7']: refl_toa_array = et_numpy.l457_refl_toa_band_func( dn_array, image.cos_theta_solar, image.dr, image.esun_dict[band], image.lmin_dict[band], image.lmax_dict[band], image.qcalmin_dict[band], image.qcalmax_dict[band]) elif image.type in ['Landsat8']: refl_toa_array = et_numpy.l8_refl_toa_band_func( dn_array, image.cos_theta_solar, image.refl_mult_dict[band], image.refl_add_dict[band]) # if (image.type in ['Landsat4', 'Landsat5', 'Landsat7'] and # not thermal_band_flag): # refl_toa_array = et_numpy.l457_refl_toa_band_func( # dn_array, image.cos_theta_solar, # image.dr, image.esun_dict[band], # image.lmin_dict[band], image.lmax_dict[band], # image.qcalmin_dict[band], # image.qcalmax_dict[band]) # # image.rad_mult_dict[band], # # image.rad_add_dict[band]) # elif (image.type in ['Landsat8'] and # not thermal_band_flag): # refl_toa_array = et_numpy.l8_refl_toa_band_func( # dn_array, image.cos_theta_solar, # image.refl_mult_dict[band], # image.refl_add_dict[band]) # elif (image.type in ['Landsat4', 'Landsat5', 'Landsat7'] and # thermal_band_flag): # refl_toa_array = et_numpy.l457_ts_bt_band_func( # dn_array, # image.lmin_dict[band], image.lmax_dict[band], # image.qcalmin_dict[band], # image.qcalmax_dict[band], # # image.rad_mult_dict[band], # # image.rad_add_dict[band], # image.k1_dict[band], image.k2_dict[band]) # elif (image.type in ['Landsat8'] and # thermal_band_flag): # refl_toa_array = et_numpy.l8_ts_bt_band_func( # dn_array, # image.rad_mult_dict[band], # image.rad_add_dict[band], # image.k1_dict[band], image.k2_dict[band]) # refl_toa_array = et_numpy.refl_toa_band_func( # dn_array, cos_theta_solar_flt, # image.dr, image.esun_dict[band], # image.lmin_dict[band], image.lmax_dict[band], # image.qcalmin_dict[band], image.qcalmax_dict[band], # thermal_band_flag) drigo.block_to_raster( refl_toa_array.astype(np.float32), image.refl_toa_raster, b_i, b_j, band=image.band_toa_dict[band]) # drigo.array_to_comp_raster( # refl_toa_array.astype(np.float32), # image.refl_toa_raster, # image.band_toa_dict[band], common_array) del refl_toa_array, dn_array if stats_flag: drigo.raster_statistics(image.refl_toa_raster) # # Process each TOA band # # for band, band_i in sorted(image.band_toa_dict.items()): # for band, dn_image in sorted(dn_image_dict.items()): # thermal_band_flag = (band == image.thermal_band) # # Set 0 as nodata value # drigo.raster_path_set_nodata(dn_image, 0) # # Calculate TOA reflectance # dn_array, dn_nodata = drigo.raster_to_array( # dn_image, 1, common_extent) # dn_array = dn_array.astype(np.float64) # # dn_array = dn_array.astype(np.float32) # dn_array[dn_array == 0] = np.nan # # # if (image.type in ['Landsat4', 'Landsat5', 'Landsat7'] and # not thermal_band_flag): # refl_toa_array = et_numpy.l457_refl_toa_band_func( # dn_array, image.cos_theta_solar, # image.dr, image.esun_dict[band], # image.lmin_dict[band], image.lmax_dict[band], # image.qcalmin_dict[band], image.qcalmax_dict[band]) # # image.rad_mult_dict[band], image.rad_add_dict[band]) # elif (image.type in ['Landsat4', 'Landsat5', 'Landsat7'] and # thermal_band_flag): # refl_toa_array = et_numpy.l457_ts_bt_band_func( # dn_array, image.lmin_dict[band], image.lmax_dict[band], # image.qcalmin_dict[band], image.qcalmax_dict[band], # # image.rad_mult_dict[band], image.rad_add_dict[band], # image.k1_dict[band], image.k2_dict[band]) # elif (image.type in ['Landsat8'] and # not thermal_band_flag): # refl_toa_array = et_numpy.l8_refl_toa_band_func( # dn_array, image.cos_theta_solar, # image.refl_mult_dict[band], image.refl_add_dict[band]) # elif (image.type in ['Landsat8'] and # thermal_band_flag): # refl_toa_array = et_numpy.l8_ts_bt_band_func( # dn_array, # image.rad_mult_dict[band], image.rad_add_dict[band], # image.k1_dict[band], image.k2_dict[band]) # # refl_toa_array = et_numpy.refl_toa_band_func( # # dn_array, cos_theta_solar_flt, # # image.dr, image.esun_dict[band], # # image.lmin_dict[band], image.lmax_dict[band], # # image.qcalmin_dict[band], image.qcalmax_dict[band], # # thermal_band_flag) # drigo.array_to_comp_raster( # refl_toa_array.astype(np.float32), image.refl_toa_raster, # image.band_toa_dict[band], common_array) # del refl_toa_array, dn_array # Calculate brightness temperature if calc_ts_bt_flag: logging.info('Brightness Temperature') if os.path.isfile(image.ts_bt_raster) and overwrite_flag: logging.debug(' Overwriting: {}'.format(image.ts_bt_raster)) dripy.remove_file(image.ts_bt_raster) if not os.path.isfile(image.ts_bt_raster): band = image.thermal_band thermal_dn_path = dn_image_dict[band] drigo.raster_path_set_nodata(thermal_dn_path, 0) thermal_dn_array, thermal_dn_nodata = drigo.raster_to_array( thermal_dn_path, 1, common_extent, return_nodata=True) thermal_dn_mask = thermal_dn_array != thermal_dn_nodata if image.type in ['Landsat4', 'Landsat5', 'Landsat7']: ts_bt_array = et_numpy.l457_ts_bt_band_func( thermal_dn_array, image.lmin_dict[band], image.lmax_dict[band], image.qcalmin_dict[band], image.qcalmax_dict[band], # image.rad_mult_dict[band], image.rad_add_dict[band], image.k1_dict[band], image.k2_dict[band]) elif image.type in ['Landsat8']: ts_bt_array = et_numpy.l8_ts_bt_band_func( thermal_dn_array, image.rad_mult_dict[band], image.rad_add_dict[band], image.k1_dict[band], image.k2_dict[band]) # thermal_rad_array = et_numpy.refl_toa_band_func( # thermal_dn_array, image.cos_theta_solar, # image.dr, image.esun_dict[band], # image.lmin_dict[band], image.lmax_dict[band], # image.qcalmin_dict[band], image.qcalmax_dict[band], # thermal_band_flag=True) # ts_bt_array = et_numpy.ts_bt_func( # thermal_rad_array, image.k1_dict[image.thermal_band], # image.k2_dict[image.thermal_band]) ts_bt_array[~thermal_dn_mask] = np.nan drigo.array_to_raster( ts_bt_array, image.ts_bt_raster, output_geo=common_geo, output_proj=env.snap_proj, # mask_array=common_array, stats_flag=stats_flag) # del thermal_dn_array, thermal_rad_array del thermal_dn_path, thermal_dn_array, ts_bt_array # Interpolate/project/clip METRIC hourly/daily rasters if (calc_metric_ea_flag or calc_metric_wind_flag or calc_metric_etr_flag): logging.info('METRIC hourly/daily rasters') # Get bracketing hours from image acquisition time image_prev_dt = image.acq_datetime.replace( minute=0, second=0, microsecond=0) image_next_dt = image_prev_dt + timedelta(seconds=3600) # Get NLDAS properties from one of the images input_ws = os.path.join( metric_etr_input_ws, str(image_prev_dt.year)) try: input_path = [ os.path.join(input_ws, file_name) for file_name in os.listdir(input_ws) for match in [metric_hourly_re.match(file_name)] if (match and (image_prev_dt.strftime('%Y%m%d') == match.group('YYYYMMDD')))][0] except IndexError: logging.error(' No hourly file for {}'.format( image_prev_dt.strftime('%Y-%m-%d %H00'))) return False try: input_ds = gdal.Open(input_path) input_osr = drigo.raster_ds_osr(input_ds) # input_proj = drigo.osr_proj(input_osr) input_extent = drigo.raster_ds_extent(input_ds) input_cs = drigo.raster_ds_cellsize(input_ds, x_only=True) # input_geo = input_extent.geo(input_cs) input_x, input_y = input_extent.origin() input_ds = None except: logging.error(' Could not get default input image properties') logging.error(' {}'.format(input_path)) return False # Project Landsat scene extent to NLDAS GCS common_gcs_osr = common_osr.CloneGeogCS() common_gcs_extent = drigo.project_extent( common_extent, common_osr, common_gcs_osr, cellsize=env.cellsize) common_gcs_extent.buffer_extent(0.1) common_gcs_extent.adjust_to_snap( 'EXPAND', input_x, input_y, input_cs) # common_gcs_geo = common_gcs_extent.geo(input_cs) def metric_weather_func(output_raster, input_ws, input_re, prev_dt, next_dt, resample_method=gdal.GRA_NearestNeighbour, rounding_flag=False): """Interpolate/project/clip METRIC hourly rasters""" logging.debug(' Output: {}'.format(output_raster)) if os.path.isfile(output_raster): if overwrite_flag: logging.debug(' Overwriting output') dripy.remove_file(output_raster) else: logging.debug(' Skipping, file already exists ' + 'and overwrite is False') return False prev_ws = os.path.join(input_ws, str(prev_dt.year)) next_ws = os.path.join(input_ws, str(next_dt.year)) # Technically previous and next could come from different days # or even years, although this won't happen in the U.S. try: prev_path = [ os.path.join(prev_ws, input_name) for input_name in os.listdir(prev_ws) for input_match in [input_re.match(input_name)] if (input_match and (prev_dt.strftime('%Y%m%d') == input_match.group('YYYYMMDD')))][0] logging.debug(' Input prev: {}'.format(prev_path)) except IndexError: logging.error(' No previous hourly file') logging.error(' {}'.format(prev_dt)) return False try: next_path = [ os.path.join(next_ws, input_name) for input_name in os.listdir(next_ws) for input_match in [input_re.match(input_name)] if (input_match and (next_dt.strftime('%Y%m%d') == input_match.group('YYYYMMDD')))][0] logging.debug(' Input next: {}'.format(next_path)) except IndexError: logging.error(' No next hourly file') logging.error(' {}'.format(next_dt)) return False # Band numbers are 1's based prev_band = int(prev_dt.strftime('%H')) + 1 next_band = int(next_dt.strftime('%H')) + 1 logging.debug(' Input prev band: {}'.format(prev_band)) logging.debug(' Input next band: {}'.format(next_band)) # Read arrays prev_array = drigo.raster_to_array( prev_path, band=prev_band, mask_extent=common_gcs_extent, return_nodata=False) next_array = drigo.raster_to_array( next_path, band=next_band, mask_extent=common_gcs_extent, return_nodata=False) if not np.any(prev_array) or not np.any(next_array): logging.warning('\nWARNING: Input NLDAS array is all nodata\n') return None output_array = hourly_interpolate_func( prev_array, next_array, prev_dt, next_dt, image.acq_datetime) output_array = drigo.project_array( output_array, resample_method, input_osr, input_cs, common_gcs_extent, common_osr, env.cellsize, common_extent, output_nodata=None) # Apply common area mask output_array[~common_array] = np.nan # Reduce the file size by rounding to the nearest n digits if rounding_flag: output_array = np.around(output_array, rounding_digits) # Force output to 32-bit float drigo.array_to_raster( output_array.astype(np.float32), output_raster, output_geo=common_geo, output_proj=common_proj, stats_flag=stats_flag) del output_array return True # Ea - Project to Landsat scene after clipping if calc_metric_ea_flag: logging.info(' Hourly vapor pressure (Ea)') metric_weather_func( image.metric_ea_raster, metric_ea_input_ws, metric_hourly_re, image_prev_dt, image_next_dt, gdal.GRA_Bilinear, rounding_flag=True) # Wind - Project to Landsat scene after clipping if calc_metric_wind_flag: logging.info(' Hourly windspeed') metric_weather_func( image.metric_wind_raster, metric_wind_input_ws, metric_hourly_re, image_prev_dt, image_next_dt, gdal.GRA_NearestNeighbour, rounding_flag=False) # ETr - Project to Landsat scene after clipping if calc_metric_etr_flag: logging.info(' Hourly reference ET (ETr)') metric_weather_func( image.metric_etr_raster, metric_etr_input_ws, metric_hourly_re, image_prev_dt, image_next_dt, gdal.GRA_NearestNeighbour, rounding_flag=False) # ETr 24hr - Project to Landsat scene after clipping if calc_metric_etr_flag: logging.info(' Daily reference ET (ETr)') logging.debug(' Output: {}'.format( image.metric_etr_24hr_raster)) if (os.path.isfile(image.metric_etr_24hr_raster) and overwrite_flag): logging.debug(' Overwriting output') os.remove(image.metric_etr_24hr_raster) if not os.path.isfile(image.metric_etr_24hr_raster): etr_prev_ws = os.path.join( metric_etr_input_ws, str(image_prev_dt.year)) try: input_path = [ os.path.join(etr_prev_ws, file_name) for file_name in os.listdir(etr_prev_ws) for match in [metric_daily_re.match(file_name)] if (match and (image_prev_dt.strftime('%Y%m%d') == match.group('YYYYMMDD')))][0] logging.debug(' Input: {}'.format(input_path)) except IndexError: logging.error(' No daily file for {}'.format( image_prev_dt.strftime('%Y-%m-%d'))) return False output_array = drigo.raster_to_array( input_path, mask_extent=common_gcs_extent, return_nodata=False) output_array = drigo.project_array( output_array, gdal.GRA_NearestNeighbour, input_osr, input_cs, common_gcs_extent, common_osr, env.cellsize, common_extent, output_nodata=None) # Apply common area mask output_array[~common_array] = np.nan # Reduce the file size by rounding to the nearest n digits # output_array = np.around(output_array, rounding_digits) drigo.array_to_raster( output_array, image.metric_etr_24hr_raster, output_geo=common_geo, output_proj=common_proj, stats_flag=stats_flag) del output_array del input_path # Tair - Project to Landsat scene after clipping if calc_metric_tair_flag: logging.info(' Hourly air temperature (Tair)') metric_weather_func( image.metric_tair_raster, metric_tair_input_ws, metric_hourly_re, image_prev_dt, image_next_dt, gdal.GRA_NearestNeighbour, rounding_flag=False) # Cleanup del image_prev_dt, image_next_dt # Soil Water Balance if calc_swb_ke_flag: logging.info('Daily soil water balance') # Check if output file already exists logging.debug(' Ke: {}'.format(image.ke_raster)) if os.path.isfile(image.ke_raster): if overwrite_flag: logging.debug(' Overwriting output') dripy.remove_file(image.ke_raster) else: logging.debug(' Skipping, file already ' 'exists and overwrite is False') return False ke_array = et_common.raster_swb_func( image.acq_datetime, common_osr, env.cellsize, common_extent, awc_input_path, etr_input_ws, etr_input_re, ppt_input_ws, ppt_input_re, spinup_days=spinup_days, min_spinup_days=min_spinup_days) # Apply common area mask ke_array[~common_array] = np.nan # Reduce the file size by rounding to the nearest 2 digits np.around(ke_array, 2, out=ke_array) # Force output to 32-bit float drigo.array_to_raster( ke_array.astype(np.float32), image.ke_raster, output_geo=common_geo, output_proj=common_proj, stats_flag=stats_flag) # Remove Landsat TOA rasters if not keep_dn_flag: for landsat_item in dripy.build_file_list( image.orig_data_ws, image.image_name_re): os.remove(os.path.join(image.orig_data_ws, landsat_item)) return True
def main(cimis_ws=os.getcwd(), gridmet_ws=None, ancillary_ws=os.getcwd(), etr_flag=False, eto_flag=False, start_date=None, end_date=None, stats_flag=True, overwrite_flag=False): """Fill missing CIMIS days with projected data from GRIDMET Parameters ---------- cimis_ws : str Root folder path of CIMIS data. gridmet_ws : str Root folder path of GRIDMET data. ancillary_ws : str Folder of ancillary rasters. etr_flag : bool, optional If True, compute alfalfa reference ET (ETr). eto_flag : bool, optional If True, compute grass reference ET (ETo). start_date : str, optional ISO format date (YYYY-MM-DD). end_date : str, optional ISO format date (YYYY-MM-DD). stats_flag : bool, optional If True, compute raster statistics (the default is True). overwrite_flag : bool, optional If True, overwrite existing files (the default is False). Returns ------- None Notes ----- Currently missing (CGM 2014-08-15) 2010-11-16 -> 2010-11-23 """ logging.info('\nFilling CIMIS with GRIDMET') cimis_re = re.compile( '(?P<VAR>etr)_(?P<YYYY>\d{4})_daily_(?P<GRID>\w+).img$') # gridmet_re = re.compile( # '(?P<VAR>ppt)_(?P<YYY>\d{4})_daily_(?P<GRID>\w+).img$') gridmet_fmt = 'etr_{}_daily_gridmet.img' # Compute ETr and/or ETo if not etr_flag and not eto_flag: logging.info(' ETo/ETr flag(s) not set, defaulting to ETr') etr_flag = True logging.debug(' CIMIS: {}'.format(cimis_ws)) logging.debug(' GRIDMET: {}'.format(gridmet_ws)) # If a date is not set, process 2017 try: start_dt = dt.datetime.strptime(start_date, '%Y-%m-%d') logging.debug(' Start date: {}'.format(start_dt)) except: start_dt = dt.datetime(2017, 1, 1) logging.info(' Start date: {}'.format(start_dt)) try: end_dt = dt.datetime.strptime(end_date, '%Y-%m-%d') logging.debug(' End date: {}'.format(end_dt)) except: end_dt = dt.datetime(2017, 12, 31) logging.info(' End date: {}'.format(end_dt)) # Get GRIDMET spatial reference and cellsize from elevation raster # gridmet_elev_raster = os.path.join(ancillary_ws, 'gridmet_elev.img') # Get CIMIS spatial reference and cellsize from mask raster cimis_mask_raster = os.path.join(ancillary_ws, 'cimis_mask.img') # Resample type # 0 = GRA_NearestNeighbour, Nearest neighbour (select on one input pixel) # 1 = GRA_Bilinear,Bilinear (2x2 kernel) # 2 = GRA_Cubic, Cubic Convolution Approximation (4x4 kernel) # 3 = GRA_CubicSpline, Cubic B-Spline Approximation (4x4 kernel) # 4 = GRA_Lanczos, Lanczos windowed sinc interpolation (6x6 kernel) # 5 = GRA_Average, Average (computes the average of all non-NODATA contributing pixels) # 6 = GRA_Mode, Mode (selects the value which appears most often of all the sampled points) resample_type = gdal.GRA_Bilinear # ETo/ETr workspaces cimis_eto_ws = os.path.join(cimis_ws, 'eto') cimis_etr_ws = os.path.join(cimis_ws, 'etr') gridmet_eto_ws = os.path.join(gridmet_ws, 'eto') gridmet_etr_ws = os.path.join(gridmet_ws, 'etr') # This allows GDAL to throw Python Exceptions # gdal.UseExceptions() # mem_driver = gdal.GetDriverByName('MEM') # Get CIMIS grid properties from mask logging.info('\nCIMIS Properties') cimis_mask_ds = gdal.Open(cimis_mask_raster) cimis_osr = drigo.raster_ds_osr(cimis_mask_ds) cimis_proj = drigo.osr_proj(cimis_osr) cimis_cs = drigo.raster_ds_cellsize(cimis_mask_ds, x_only=True) cimis_extent = drigo.raster_ds_extent(cimis_mask_ds) cimis_geo = cimis_extent.geo(cimis_cs) cimis_mask_ds = None logging.debug(' Projection: {}'.format(cimis_proj)) logging.debug(' Cellsize: {}'.format(cimis_cs)) logging.debug(' Geo: {}'.format(cimis_geo)) logging.debug(' Extent: {}'.format(cimis_extent)) # Read the CIMIS mask array if present cimis_mask, cimis_mask_nodata = drigo.raster_to_array(cimis_mask_raster) cimis_mask = cimis_mask != cimis_mask_nodata # # Get extent/geo from elevation raster # logging.info('\nGRIDMET Properties') # gridmet_ds = gdal.Open(gridmet_elev_raster) # gridmet_osr = drigo.raster_ds_osr(gridmet_ds) # gridmet_proj = drigo.osr_proj(gridmet_osr) # gridmet_cs = drigo.raster_ds_cellsize(gridmet_ds, x_only=True) # gridmet_full_extent = drigo.raster_ds_extent(gridmet_ds) # gridmet_full_geo = gridmet_full_extent.geo(gridmet_cs) # gridmet_x, gridmet_y = gridmet_full_extent.origin() # gridmet_ds = None # logging.debug(' Projection: {}'.format(gridmet_proj)) # logging.debug(' Cellsize: {}'.format(gridmet_cs)) # logging.debug(' Geo: {}'.format(gridmet_full_geo)) # logging.debug(' Extent: {}'.format(gridmet_full_extent)) # # Project CIMIS extent to the GRIDMET spatial reference # logging.info('\nGet CIMIS extent in GRIDMET spat. ref.') # gridmet_sub_extent = drigo.project_extent( # cimis_extent, cimis_osr, gridmet_osr, cimis_cs) # gridmet_sub_extent.buffer_extent(4 * gridmet_cs) # gridmet_sub_extent.adjust_to_snap( # 'EXPAND', gridmet_x, gridmet_y, gridmet_cs) # gridmet_sub_geo = gridmet_sub_extent.geo(gridmet_cs) # logging.debug(' Geo: {}'.format(gridmet_sub_geo)) # logging.debug(' Extent: {}'.format(gridmet_sub_extent)) # Process Missing ETo if eto_flag: logging.info('\nETo') for cimis_name in sorted(os.listdir(cimis_eto_ws)): logging.debug("\n{}".format(cimis_name)) cimis_match = cimis_re.match(cimis_name) if not cimis_match: logging.debug(' Regular expression didn\'t match, skipping') continue year = int(cimis_match.group('YYYY')) logging.info(" {}".format(str(year))) if start_dt is not None and year < start_dt.year: logging.debug(' Before start date, skipping') continue elif end_dt is not None and year > end_dt.year: logging.debug(' After end date, skipping') continue cimis_path = os.path.join(cimis_eto_ws, cimis_name) gridmet_path = os.path.join(gridmet_eto_ws, gridmet_fmt.format(str(year))) if not os.path.isfile(gridmet_path): logging.debug(' GRIDMET raster does not exist, skipping') continue if not os.path.isfile(cimis_path): logging.error(' CIMIS raster does not exist, skipping') continue # Check all valid dates in the year year_dates = _utils.date_range(dt.datetime(year, 1, 1), dt.datetime(year + 1, 1, 1)) for date_dt in year_dates: if start_dt is not None and date_dt < start_dt: continue elif end_dt is not None and date_dt > end_dt: continue doy = int(date_dt.strftime('%j')) # Look for arrays that don't have data eto_array = drigo.raster_to_array(cimis_path, band=doy, return_nodata=False) if np.any(np.isfinite(eto_array)): logging.debug(' {} - no missing data, skipping'.format( date_dt.strftime('%Y-%m-%d'))) continue else: logging.info(' {}'.format(date_dt.strftime('%Y-%m-%d'))) # # This is much faster but doesn't apply the CIMIS mask # # Create an in memory dataset of the full ETo array # eto_full_rows, eto_full_cols = eto_full_array[:,:,doy_i].shape # eto_full_type, eto_full_nodata = numpy_to_gdal_type(np.float32) # eto_full_ds = mem_driver.Create( # '', eto_full_cols, eto_full_rows, 1, eto_full_type) # eto_full_ds.SetProjection(gridmet_proj) # eto_full_ds.SetGeoTransform(gridmet_full_geo) # eto_full_band = eto_full_ds.GetRasterBand(1) # # eto_full_band.Fill(eto_full_nodata) # eto_full_band.SetNoDataValue(eto_full_nodata) # eto_full_band.WriteArray(eto_full_array[:,:,doy_i], 0, 0) # # # Extract the subset # eto_sub_array, eto_sub_nodata = drigo.raster_ds_to_array( # eto_full_ds, 1, gridmet_sub_extent) # eto_sub_rows, eto_sub_cols = eto_sub_array.shape # eto_full_ds = None # # # Create projected raster # eto_sub_ds = mem_driver.Create( # '', eto_sub_cols, eto_sub_rows, 1, eto_full_type) # eto_sub_ds.SetProjection(gridmet_proj) # eto_sub_ds.SetGeoTransform(gridmet_sub_geo) # eto_sub_band = eto_sub_ds.GetRasterBand(1) # eto_sub_band.Fill(eto_sub_nodata) # eto_sub_band.SetNoDataValue(eto_sub_nodata) # eto_sub_band.WriteArray(eto_sub_array, 0, 0) # eto_sub_ds.FlushCache() # # # Project input DEM to CIMIS spat. ref. # drigo.project_raster_ds( # eto_sub_ds, gridmet_path, resample_type, # env.snap_proj, env.cellsize, cimis_extent) # eto_sub_ds = None # Extract the subset gridmet_ds = gdal.Open(gridmet_path) gridmet_extent = drigo.raster_ds_extent(gridmet_ds) gridmet_cs = drigo.raster_ds_cellsize(gridmet_ds, x_only=True) gridmet_osr = drigo.raster_ds_osr(gridmet_ds) eto_full_array = drigo.raster_ds_to_array(gridmet_ds, band=doy, return_nodata=False) gridmet_ds = None # Get the projected subset of the full ETo array # This is slower than projecting the subset above eto_sub_array = drigo.project_array(eto_full_array, resample_type, gridmet_osr, gridmet_cs, gridmet_extent, cimis_osr, cimis_cs, cimis_extent) # Save the projected array drigo.array_to_comp_raster(eto_sub_array, cimis_path, band=doy, stats_flag=False) # drigo.array_to_raster( # eto_sub_array, output_path, output_geo=cimis_geo, # output_proj=cimis_proj, stats_flag=False) # drigo.array_to_raster( # eto_sub_array, output_path, # output_geo=cimis_geo, output_proj=cimis_proj, # mask_array=cimis_mask, stats_flag=False) del eto_sub_array, eto_full_array if stats_flag: drigo.raster_statistics(cimis_path) # Process Missing ETr if etr_flag: logging.info('\nETr') for cimis_name in sorted(os.listdir(cimis_etr_ws)): cimis_match = cimis_re.match(cimis_name) if not cimis_match: continue year = int(cimis_match.group('YYYY')) if start_dt is not None and year < start_dt.year: continue elif end_dt is not None and year > end_dt.year: continue logging.info("{}".format(str(year))) cimis_path = os.path.join(cimis_etr_ws, cimis_name) gridmet_path = os.path.join(gridmet_etr_ws, gridmet_fmt.format(str(year))) if not os.path.isfile(gridmet_path): continue if not os.path.isfile(cimis_path): logging.error(' CIMIS raster does not exist') continue # Check all valid dates in the year year_dates = _utils.date_range(dt.datetime(year, 1, 1), dt.datetime(year + 1, 1, 1)) for date_dt in year_dates: if start_dt is not None and date_dt < start_dt: continue elif end_dt is not None and date_dt > end_dt: continue doy = int(date_dt.strftime('%j')) # Look for arrays that don't have data etr_array = drigo.raster_to_array(cimis_path, band=doy, return_nodata=False) if np.any(np.isfinite(etr_array)): logging.debug(' {} - skipping'.format( date_dt.strftime('%Y-%m-%d'))) continue else: logging.info(' {}'.format(date_dt.strftime('%Y-%m-%d'))) # Extract the subset gridmet_ds = gdal.Open(gridmet_path) gridmet_extent = drigo.raster_ds_extent(gridmet_ds) gridmet_cs = drigo.raster_ds_cellsize(gridmet_ds, x_only=True) gridmet_osr = drigo.raster_ds_osr(gridmet_ds) etr_full_array = drigo.raster_ds_to_array(gridmet_ds, band=doy, return_nodata=False) gridmet_ds = None # Get the projected subset of the full ETr array # This is slower than projecting the subset etr_sub_array = drigo.project_array(etr_full_array, resample_type, gridmet_osr, gridmet_cs, gridmet_extent, cimis_osr, cimis_cs, cimis_extent) # # Save the projected array drigo.array_to_comp_raster(etr_sub_array, cimis_path, band=doy, stats_flag=False) # drigo.array_to_raster( # etr_sub_array, output_path, # output_geo=cimis_geo, output_proj=cimis_proj, # mask_array=cimis_mask, stats_flag=False) del etr_sub_array, etr_full_array if stats_flag: drigo.raster_statistics(cimis_path) logging.debug('\nScript Complete')