def main(biophysical_file, output_file): # Read the required data lai_cab, geo_coding = su.read_snappy_product(biophysical_file, 'lai_cab') lai_cw = su.read_snappy_product(biophysical_file, 'lai_cw')[0] cab = np.clip(np.array(lai_cab), 0.0, 140.0) refl_vis, trans_vis = cab_to_vis_spectrum(cab) cw = np.clip(np.array(lai_cw), 0.0, 0.1) refl_nir, trans_nir = cw_to_nir_spectrum(cw) su.write_snappy_product(output_file, [{ 'band_name': 'refl_vis_c', 'band_data': refl_vis }, { 'band_name': 'refl_nir_c', 'band_data': refl_nir }, { 'band_name': 'trans_vis_c', 'band_data': trans_vis }, { 'band_name': 'trans_nir_c', 'band_data': trans_nir }], 'leafSpectra', geo_coding)
def main(sza_file, biophysical_file, min_frac_green, output_file): # Read the required data fapar, geo_coding = su.read_snappy_product(biophysical_file, 'fapar') fapar = fapar.astype(np.float32) lai = su.read_snappy_product(biophysical_file, 'lai')[0].astype(np.float32) sza = su.read_snappy_product(sza_file, 'sun_zenith')[0].astype(np.float32) # Calculate fraction of vegetation which is green f_g = np.ones(lai.shape, np.float32) # Iterate until f_g converges converged = np.zeros(lai.shape, dtype=bool) # For pixels where LAI or FAPAR are below tolerance threshold of the S2 biophysical # processor, assume that the soil is bare and f_g = 1 converged[np.logical_or(lai <= 0.2, fapar <= 0.1)] = True for c in range(50): f_g_old = f_g.copy() fipar = TSEB.calc_F_theta_campbell(sza[~converged], lai[~converged]/f_g[~converged], w_C=1, Omega0=1, x_LAD=1) f_g[~converged] = fapar[~converged] / fipar f_g = np.clip(f_g, min_frac_green, 1.) converged = np.logical_or(np.isnan(f_g), np.abs(f_g - f_g_old) < 0.02) if np.all(converged): break su.write_snappy_product(output_file, [{'band_name': 'frac_green', 'band_data': f_g}], 'fracGreen', geo_coding)
def main(source, template, output, resample_algorithm): # Save source and template to GeoTIFF becasue it will need to be read by GDAL temp_file = tempfile.NamedTemporaryFile(suffix=".tif", delete=False) temp_source_path = temp_file.name temp_file.close() su.copy_bands_to_file(source, temp_source_path) temp_file = tempfile.NamedTemporaryFile(suffix=".tif", delete=False) temp_template_path = temp_file.name temp_file.close() su.copy_bands_to_file(template, temp_template_path) # Wrap the source based on tamplate wraped = gu.resample_with_gdalwarp(temp_source_path, temp_template_path, resample_algorithm) # Save with snappy name, geo_coding = su.get_product_info(template)[0:2] bands = su.get_bands_info(source) for i, band in enumerate(bands): band['band_data'] = wraped.GetRasterBand(i + 1).ReadAsArray() su.write_snappy_product(output, bands, name, geo_coding) # Clean up try: os.remove(temp_source_path) os.remove(temp_template_path) except Exception: pass
def main(meteo_product, at_band, vp_band, ap_band, at_height, output_file): at, geo_coding = su.read_snappy_product(meteo_product, at_band) at = at.astype(np.float32) vp = su.read_snappy_product(meteo_product, vp_band)[0].astype(np.float32) ap = su.read_snappy_product(meteo_product, ap_band)[0].astype(np.float32) irrad = rad.calc_longwave_irradiance(vp, at, ap, at_height) band_data = [{'band_name': 'longwave_irradiance', 'band_data': irrad}] su.write_snappy_product(output_file, band_data, 'longwaveIrradiance', geo_coding)
def main(ief_file, mi_file, output_file): # Read the required data le_band, geo_coding = su.read_snappy_product(ief_file, 'latent_heat_flux') le_band = le_band.astype(np.float32) sdn_band = su.read_snappy_product(mi_file, 'clear_sky_solar_radiation')[0].astype(np.float32) sdn_24_band = su.read_snappy_product(mi_file, 'average_daily_solar_irradiance')[0].astype(np.float32) le = np.array(le_band) sdn = np.array(sdn_band) sdn_24 = np.array(sdn_24_band) et_daily = met.flux_2_evaporation(sdn_24 * le / sdn, T_K=20+273.15, time_domain=24) su.write_snappy_product(output_file, [{'band_name': 'daily_evapotranspiration', 'band_data': et_daily}], 'dailySpectra', geo_coding)
def main(lai_map, landcover_params_map, soil_roughness, output_file): lai, geo_coding = su.read_snappy_product(lai_map, 'lai') lai = lai.astype(np.float32) height = su.read_snappy_product(landcover_params_map, 'veg_height')[0].astype(np.float32) height_width_ratio = su.read_snappy_product( landcover_params_map, 'veg_height_width_ratio')[0].astype(np.float32) fractional_cover = su.read_snappy_product( landcover_params_map, 'veg_fractional_cover')[0].astype(np.float32) classification = su.read_snappy_product( landcover_params_map, 'igbp_classification')[0].astype(np.float32) z_OM = np.full(lai.shape, np.nan, np.float32) d_0 = np.full(lai.shape, np.nan, np.float32) i = lai <= 0 z_OM[i] = soil_roughness d_0[i] = 0 i = lai > 0 z_OM[i], d_0[i] = res.calc_roughness(lai[i], height[i], height_width_ratio[i], classification[i], fractional_cover[i]) band_data = [{ 'band_name': 'roughness_length', 'band_data': z_OM }, { 'band_name': 'zero_plane_displacement', 'band_data': d_0 }] su.write_snappy_product(output_file, band_data, 'aerodynamicRoughness', geo_coding)
def main(lsp_product, lai_product, csp_product, mi_product, sza_product, soil_ref_vis, soil_ref_nir, output_file): refl_vis_c, geo_coding = su.read_snappy_product(lsp_product, 'refl_vis_c') refl_vis_c = refl_vis_c.astype(np.float32) refl_nir_c = su.read_snappy_product(lsp_product, 'refl_nir_c')[0].astype(np.float32) trans_vis_c = su.read_snappy_product(lsp_product, 'trans_vis_c')[0].astype(np.float32) trans_nir_c = su.read_snappy_product(lsp_product, 'trans_nir_c')[0].astype(np.float32) lai = su.read_snappy_product(lai_product, 'lai')[0].astype(np.float32) lad = su.read_snappy_product( csp_product, 'veg_inclination_distribution')[0].astype(np.float32) frac_cover = su.read_snappy_product( csp_product, 'veg_fractional_cover')[0].astype(np.float32) hw_ratio = su.read_snappy_product( csp_product, 'veg_height_width_ratio')[0].astype(np.float32) p = su.read_snappy_product(mi_product, 'air_pressure')[0].astype(np.float32) irradiance = su.read_snappy_product( mi_product, 'clear_sky_solar_radiation')[0].astype(np.float32) sza = su.read_snappy_product(sza_product, 'solar_zenith_tn')[0].astype(np.float32) net_rad_c = np.zeros(lai.shape, np.float32) net_rad_s = np.zeros(lai.shape, np.float32) soil_ref_vis = np.full(lai.shape, soil_ref_vis, np.float32) soil_ref_nir = np.full(lai.shape, soil_ref_nir, np.float32) #Estimate diffuse and direct irradiance difvis, difnir, fvis, fnir = rad.calc_difuse_ratio(irradiance, sza, p) skyl = difvis * fvis + difnir * fnir irradiance_dir = irradiance * (1.0 - skyl) irradiance_dif = irradiance * skyl # Net shortwave radition for bare soil i = lai <= 0 spectra_soil = fvis[i] * soil_ref_vis[i] + fnir[i] * soil_ref_nir[i] net_rad_s[i] = (1. - spectra_soil) * (irradiance_dir[i] + irradiance_dif[i]) # Net shortwave radiation for vegetated areas i = lai > 0 F = lai[i] / frac_cover[i] # Clumping index omega0 = ci.calc_omega0_Kustas(lai[i], frac_cover[i], lad[i], isLAIeff=True) omega = ci.calc_omega_Kustas(omega0, sza[i], hw_ratio[i]) lai_eff = F * omega [net_rad_c[i], net_rad_s[i]] = rad.calc_Sn_Campbell( lai[i], sza[i], irradiance_dir[i], irradiance_dif[i], fvis[i], fnir[i], refl_vis_c[i], trans_vis_c[i], refl_nir_c[i], trans_nir_c[i], soil_ref_vis[i], soil_ref_nir[i], lad[i], lai_eff) band_data = [{ 'band_name': 'net_shortwave_radiation_canopy', 'band_data': net_rad_c }, { 'band_name': 'net_shortwave_radiation_soil', 'band_data': net_rad_s }] su.write_snappy_product(output_file, band_data, 'netShortwaveRadiation', geo_coding)
def main(high_res_reflectance, low_res_lst, high_res_dem, lst_quality_mask, elevation_band, lst_good_quality_flags, cv_homogeneity_threshold, moving_window_size, parallel_jobs, output): print('INFO: Preparing high-resolution data...') # Elevation temp_file = tempfile.NamedTemporaryFile(suffix=".tif", delete=False) temp_dem_file = temp_file.name temp_file.close() su.copy_bands_to_file(high_res_dem, temp_dem_file, [elevation_band]) # Reflectance temp_file = tempfile.NamedTemporaryFile(suffix=".tif", delete=False) temp_refl_file = temp_file.name temp_file.close() su.copy_bands_to_file(high_res_reflectance, temp_refl_file) # Combine all high-resolution data into one virtual raster vrt_filename = pth.splitext(temp_refl_file)[0] + ".vrt" fp = gu.merge_raster_layers([temp_refl_file, temp_dem_file], vrt_filename, separate=True) fp = None high_res_filename = vrt_filename print('INFO: Preparing low-resolution data...') # LST temp_file = tempfile.NamedTemporaryFile(suffix=".tif", delete=False) temp_lst_file = temp_file.name temp_file.close() su.copy_bands_to_file(low_res_lst, temp_lst_file, ["LST"]) # Quality mask temp_file = tempfile.NamedTemporaryFile(suffix=".tif", delete=False) temp_mask_file = temp_file.name temp_file.close() su.copy_bands_to_file(lst_quality_mask, temp_mask_file) # Set disaggregator options flags = [int(i) for i in lst_good_quality_flags.split(",")] dms_options = { "highResFiles": [high_res_filename], "lowResFiles": [temp_lst_file], "lowResQualityFiles": [temp_mask_file], "lowResGoodQualityFlags": flags, "cvHomogeneityThreshold": cv_homogeneity_threshold, "movingWindowSize": moving_window_size, "disaggregatingTemperature": True, "baggingRegressorOpt": { "n_jobs": parallel_jobs, "n_estimators": 30, "max_samples": 0.8, "max_features": 0.8 } } disaggregator = DecisionTreeSharpener(**dms_options) # Sharpen print("INFO: Training regressor...") disaggregator.trainSharpener() print("INFO: Sharpening...") downscaled_file = disaggregator.applySharpener(high_res_filename, temp_lst_file) print("INFO: Residual analysis...") residual_image, corrected_image = disaggregator.residualAnalysis( downscaled_file, temp_lst_file, temp_mask_file, doCorrection=True) # Save the sharpened file band = { "band_name": "LST", "description": "Sharpened Sentinel-3 LST", "unit": "K", "band_data": corrected_image.GetRasterBand(1).ReadAsArray() } geo_coding = su.get_product_info(high_res_reflectance)[1] su.write_snappy_product(output, [band], "sharpenedLST", geo_coding) # Clean up try: os.remove(temp_dem_file) os.remove(temp_refl_file) os.remove(temp_lst_file) os.remove(temp_mask_file) except Exception: pass
def main(lst, lst_vza, lai, csp, fgv, ar, mi, nsr, li, mask, soil_roughness, alpha_pt, atmospheric_measurement_height, green_vegetation_emissivity, soil_emissivity, save_component_fluxes, save_component_temperature, save_aerodynamic_parameters, output_file): # Read the required data lst = su.read_snappy_product(lst, 'sharpened_LST')[0].astype(np.float32) vza = su.read_snappy_product(lst_vza, 'sat_zenith_tn')[0].astype(np.float32) lai, geo_coding = su.read_snappy_product(lai, 'lai') lai = lai.astype(np.float32) lad = su.read_snappy_product( csp, 'veg_inclination_distribution')[0].astype(np.float32) frac_cover = su.read_snappy_product(csp, 'veg_fractional_cover')[0].astype( np.float32) h_w_ratio = su.read_snappy_product( csp, 'veg_height_width_ratio')[0].astype(np.float32) leaf_width = su.read_snappy_product(csp, 'veg_leaf_width')[0].astype(np.float32) veg_height = su.read_snappy_product(csp, 'veg_height')[0].astype(np.float32) landcover_band = su.read_snappy_product( csp, 'igbp_classification')[0].astype(np.float32) frac_green = su.read_snappy_product(fgv, 'frac_green')[0].astype(np.float32) z_0M = su.read_snappy_product(ar, 'roughness_length')[0].astype(np.float32) d_0 = su.read_snappy_product(ar, 'zero_plane_displacement')[0].astype( np.float32) ta = su.read_snappy_product(mi, 'air_temperature')[0].astype(np.float32) u = su.read_snappy_product(mi, 'wind_speed')[0].astype(np.float32) ea = su.read_snappy_product(mi, 'vapour_pressure')[0].astype(np.float32) p = su.read_snappy_product(mi, 'air_pressure')[0].astype(np.float32) shortwave_rad_c = su.read_snappy_product( nsr, 'net_shortwave_radiation_canopy')[0].astype(np.float32) shortwave_rad_s = su.read_snappy_product( nsr, 'net_shortwave_radiation_soil')[0].astype(np.float32) longwave_irrad = su.read_snappy_product( li, 'longwave_irradiance')[0].astype(np.float32) mask = su.read_snappy_product(mask, 'mask')[0].astype(np.float32) # Model outputs t_s = np.full(lai.shape, np.nan, np.float32) t_c = np.full(lai.shape, np.nan, np.float32) t_ac = np.full(lai.shape, np.nan, np.float32) h_s = np.full(lai.shape, np.nan, np.float32) h_c = np.full(lai.shape, np.nan, np.float32) le_s = np.full(lai.shape, np.nan, np.float32) le_c = np.full(lai.shape, np.nan, np.float32) g = np.full(lai.shape, np.nan, np.float32) ln_s = np.full(lai.shape, np.nan, np.float32) ln_c = np.full(lai.shape, np.nan, np.float32) r_s = np.full(lai.shape, np.nan, np.float32) r_x = np.full(lai.shape, np.nan, np.float32) r_a = np.full(lai.shape, np.nan, np.float32) u_friction = np.full(lai.shape, np.nan, np.float32) mol = np.full(lai.shape, np.nan, np.float32) n_iterations = np.full(lai.shape, np.nan, np.float32) flag = np.full(lai.shape, 255) # ====================================== # First process bare soil cases i = np.logical_and(lai <= 0, mask == 1) t_s[i] = lst[i] # Calculate soil fluxes [ flag[i], ln_s[i], le_s[i], h_s[i], g[i], r_a[i], u_friction[i], mol[i], n_iterations[i] ] = TSEB.OSEB(lst[i], ta[i], u[i], ea[i], p[i], shortwave_rad_s[i], longwave_irrad[i], soil_emissivity, z_0M[i], d_0[i], atmospheric_measurement_height, atmospheric_measurement_height, calcG_params=[[1], 0.35]) # Set canopy fluxes to 0 ln_c[i] = 0.0 le_c[i] = 0.0 h_c[i] = 0.0 # ====================================== # Then process vegetated cases i = np.logical_and(lai > 0, mask == 1) # Emissivity of canopy containing green and non-green elements. emissivity_veg = green_vegetation_emissivity * frac_green[i] + 0.91 * ( 1 - frac_green[i]) # Caculate component fluxes [ flag[i], t_s[i], t_c[i], t_ac[i], ln_s[i], ln_c[i], le_c[i], h_c[i], le_s[i], h_s[i], g[i], r_s[i], r_x[i], r_a[i], u_friction[i], mol[i], n_iterations[i] ] = TSEB.TSEB_PT(lst[i], vza[i], ta[i], u[i], ea[i], p[i], shortwave_rad_c[i], shortwave_rad_s[i], longwave_irrad[i], lai[i], veg_height[i], emissivity_veg, soil_emissivity, z_0M[i], d_0[i], atmospheric_measurement_height, atmospheric_measurement_height, f_c=frac_cover[i], f_g=frac_green[i], w_C=h_w_ratio[i], leaf_width=leaf_width[i], z0_soil=soil_roughness, alpha_PT=alpha_pt, x_LAD=lad[i], calcG_params=[[1], 0.35], resistance_form=[0, {}]) # Calculate the bulk fluxes le = le_c + le_s h = h_c + h_s r_ns = shortwave_rad_c + shortwave_rad_s r_nl = ln_c + ln_s r_n = r_ns + r_nl band_data = [{ 'band_name': 'sensible_heat_flux', 'band_data': h }, { 'band_name': 'latent_heat_flux', 'band_data': le }, { 'band_name': 'ground_heat_flux', 'band_data': g }, { 'band_name': 'net_radiation', 'band_data': r_n }, { 'band_name': 'quality_flag', 'band_data': flag }] if save_component_fluxes: band_data.extend([{ 'band_name': 'sensible_heat_flux_canopy', 'band_data': h_c }, { 'band_name': 'sensible_heat_flux_soil', 'band_data': h_s }, { 'band_name': 'latent_heat_flux_canopy', 'band_data': le_c }, { 'band_name': 'latent_heat_flux_soil', 'band_data': le_s }, { 'band_name': 'net_longwave_radiation_canopy', 'band_data': ln_c }, { 'band_name': 'net_longwave_radiation_soil', 'band_data': ln_s }]) if save_component_temperature: band_data.extend([{ 'band_name': 'temperature_canopy', 'band_data': t_c }, { 'band_name': 'temperature_soil', 'band_data': t_s }, { 'band_name': 'temperature_canopy_air', 'band_data': t_ac }]) if save_aerodynamic_parameters: band_data.extend([{ 'band_name': 'resistance_surface', 'band_data': r_a }, { 'band_name': 'resistance_canopy', 'band_data': r_x }, { 'band_name': 'resistance_soil', 'band_data': r_s }, { 'band_name': 'friction_velocity', 'band_data': u_friction }, { 'band_name': 'monin_obukhov_length', 'band_data': mol }]) su.write_snappy_product(output_file, band_data, 'turbulentFluxes', geo_coding)
def main(low_res_lst, sharp_lst, gt_high_res_lst, save_residuals, output_residual): # Read rasters from BEAM-DIMAP products low_res_raster, _ = su.read_snappy_product(low_res_lst, band_name='LST') sharp_raster, geo_coding = su.read_snappy_product(sharp_lst, band_name='LST') gt_high_res_raster, _ = su.read_snappy_product(gt_high_res_lst, band_name='LST') height, width = sharp_raster.shape # Create baseline nearest-neighbor-interpolation sharpening baseline_raster = cv2.resize(low_res_raster, dsize=(width, height), interpolation=cv2.INTER_NEAREST) # Make sure ground-truth and sharpened LST are the same size gt_high_res_raster = cv2.resize(gt_high_res_raster, dsize=(width, height), interpolation=cv2.INTER_NEAREST) # Get quality pixels quality_mask = ~np.isnan(sharp_raster) # Ignore pixels with NaN values n_quality_pixels = np.sum(quality_mask) # Evaluate baseline baseline_residual = gt_high_res_raster - baseline_raster rmse = np.sqrt( np.nansum(baseline_residual[quality_mask]**2) / n_quality_pixels) median_bias = np.nanmedian(baseline_residual[quality_mask]) std_bias = np.nanstd(baseline_residual[quality_mask]) print("\nBaseline nearest neighbor upsampling:") print("\tRMSE: {:.2f}".format(rmse)) print("\tMedian bias: {:.2f}".format(median_bias)) print("\tStandard deviation of bias: {:.2f}".format(std_bias)) # Evaluate sharpening sharp_residual = gt_high_res_raster - sharp_raster rmse = np.sqrt( np.nansum(sharp_residual[quality_mask]**2) / n_quality_pixels) median_bias = np.nanmedian(sharp_residual[quality_mask]) std_bias = np.nanstd(sharp_residual[quality_mask]) print("\nSharpening:") print("\tRMSE: {:.2f}".format(rmse)) print("\tMedian bias: {:.2f}".format(median_bias)) print("\tStandard deviation of bias: {:.2f}".format(std_bias)) if save_residuals: # Save the residuals baseline_band = { "band_name": "baseline_LST_residual", "description": "Residual of the baseline LST upsampling via " + "nearest neighbor interpolation", "unit": "K", "band_data": baseline_residual } sharp_band = { "band_name": "sharp_LST_residual", "description": "Residual of the sharpened LST", "unit": "K", "band_data": sharp_residual } if output_residual is None: output_residual = os.path.splitext(low_res_lst)[0] + \ 'residuals.dim' su.write_snappy_product(output_residual, [baseline_band, sharp_band], "sharpening_residuals", geo_coding)
def main(elevation_map, elevation_band, ecmwf_data_file, date_time_utc, time_zone, prepare_temperature, prepare_vapour_pressure, prepare_air_pressure, prepare_wind_speed, prepare_clear_sky_solar_radiation, prepare_daily_solar_irradiance, output_file): # Save elevation to GeoTIFF becasue it will need to be read by GDAL later temp_file = tempfile.NamedTemporaryFile(suffix=".tif", delete=False) temp_elev_path = temp_file.name temp_file.close() su.copy_bands_to_file(elevation_map, temp_elev_path, [elevation_band]) # Calculate required meteorological parameters bands = [] if prepare_temperature: data = eu.get_ECMWF_data(ecmwf_data_file, 'air_temperature', date_time_utc, temp_elev_path, time_zone) bands.append({ 'band_data': data, 'band_name': 'air_temperature', 'description': 'Air temperature at 100 m above surface(K)' }) if prepare_vapour_pressure: data = eu.get_ECMWF_data(ecmwf_data_file, 'vapour_pressure', date_time_utc, temp_elev_path, time_zone) bands.append({ 'band_data': data, 'band_name': 'vapour_pressure', 'description': 'Surface vapour pressure (mb)' }) if prepare_air_pressure: data = eu.get_ECMWF_data(ecmwf_data_file, 'air_pressure', date_time_utc, temp_elev_path, time_zone) bands.append({ 'band_data': data, 'band_name': 'air_pressure', 'description': 'Surface air pressure (mb)' }) if prepare_wind_speed: data = eu.get_ECMWF_data(ecmwf_data_file, 'wind_speed', date_time_utc, temp_elev_path, time_zone) bands.append({ 'band_data': data, 'band_name': 'wind_speed', 'description': 'Wind speed at 100 m above surface (m/s)' }) if prepare_clear_sky_solar_radiation: data = eu.get_ECMWF_data(ecmwf_data_file, 'clear_sky_solar_radiation', date_time_utc, temp_elev_path, time_zone) bands.append({ 'band_data': data, 'band_name': 'clear_sky_solar_radiation', 'description': 'Instantenous clear sky surface solar irradiance (W/m^2)' }) if prepare_daily_solar_irradiance: data = eu.get_ECMWF_data(ecmwf_data_file, 'average_daily_solar_irradiance', date_time_utc, temp_elev_path, time_zone) bands.append({ 'band_data': data, 'band_name': 'average_daily_solar_irradiance', 'description': 'Average daily solar irradiance (W/m^2)' }) # Save the output file geo_coding = su.read_snappy_product(elevation_map, elevation_band)[1] su.write_snappy_product(output_file, bands, 'ecmwfData', geo_coding)
def main(landsat_product_path, band_number, lst_output): # Find files for the specified TIR band tir_files = glob( os.path.join(landsat_product_path, '*_B{}*'.format(band_number))) try: # If more than one matching file, open the first match by default tir_file = tir_files[0] except IndexError: print("Found zero files corresponding to band {}".format(band)) tir_data = gdal.Open(tir_file) tir_raster = tir_data.GetRasterBand(1).ReadAsArray().astype(float) # Get conversion parameters from the metadata metadata_files = glob(os.path.join(landsat_product_path, '*_MTL*')) try: # If more than one matching file, open the first match by default metadata_file = metadata_files[0] except IndexError: print("Found zero metadata (MTL) files") params = get_conversion_params(metadata_file, band_number) print('INFO: Converting DN to TOA spectral radiance...') radiance = dn_to_radiance(tir_raster, params['radiance_mult_band'], params['radiance_add_band']) print('INFO: Converting TOA spectral radiance to ' + 'at-sensor brightness temperature...') bt = radiance_to_bt(radiance, params['k1'], params['k2']) print('INFO: Estimating land surface emissivity...') lse = land_surface_emissivity(landsat_product_path) print('INFO: Converting at-sensor brightness temperature to ' + 'land surface temperature...') lst = bt_to_lst(bt, lse, band_number) # Write estimated LST into new GeoTiff print('INFO: Saving output...') driver = gdal.GetDriverByName("GTiff") driver.Register() # Ensure that output is saved in GeoTiff format file_name = os.path.splitext(lst_output)[0] + '.TIF' lst_data = driver.CreateCopy(file_name, tir_data, strict=0) lst_data.GetRasterBand(1).WriteArray(lst) lst_data.GetRasterBand(1).FlushCache() # Clean up tir_data = None lst_data = None try: os.remove(os.path.splitext(lst_output)[0] + '.IMD') except Exception: pass # Keep a BEAM-DIMAP file instead if the output extension is '.dim' ext = os.path.splitext(lst_output)[-1] if ext.casefold() == '.dim': # Read from recently saved GeoTiff old_file_name = file_name product = ProductIO.readProduct(old_file_name) band = { "band_name": "LST", "description": "LST estimated from Landsat TIR", "unit": "K", "band_data": lst } geo_coding = product.getSceneGeoCoding() file_name = os.path.splitext(lst_output)[0] + '.dim' su.write_snappy_product(file_name, [band], "Landsat_LST", geo_coding) try: os.remove(old_file_name) # Remove GeoTiff copy except Exception: pass elif (ext.casefold() != '.TIF') and (ext.casefold() != '.TIFF'): print("INFO: Given output file extension was not recognized. " + "Output was saved as a GeoTiff instead.")
def main(landcover_map, lai_map, fgv_map, landcover_band, lookup_table, produce_vh, produce_fc, produce_chwr, produce_lw, produce_lid, produce_igbp, output_file): # Read the required data PARAMS = ['veg_height', 'lai_max', 'is_herbaceous', 'veg_fractional_cover', 'veg_height_width_ratio', 'veg_leaf_width', 'veg_inclination_distribution', 'igbp_classification' ] landcover, geo_coding = su.read_snappy_product(landcover_map, landcover_band) landcover = landcover.astype(np.float32) lai = su.read_snappy_product(lai_map, 'lai')[0].astype(np.float32) fg = su.read_snappy_product(fgv_map, 'frac_green')[0].astype(np.float32) with open(lookup_table, 'r') as fp: lines = fp.readlines() headers = lines[0].rstrip().split(';') values = [x.rstrip().split(';') for x in lines[1:]] lut = {key: [float(x[idx]) for x in values if len(x) == len(headers)] for idx, key in enumerate(headers)} for param in PARAMS: if param not in lut.keys(): print(f'Error: Missing {param} in the look-up table') return band_data = [] param_value = np.ones(landcover.shape, np.float32) + np.nan if produce_vh: for lc_class in np.unique(landcover[~np.isnan(landcover)]): lc_pixels = np.where(landcover == lc_class) lc_index = lut["landcover_class"].index(lc_class) param_value[lc_pixels] = lut['veg_height'][lc_index] # Vegetation height in herbaceous vegetation depends on plant area index if lut["is_herbaceous"][lc_index] == 1: pai = lai / fg pai = pai[lc_pixels] param_value[lc_pixels] = \ 0.1 * param_value[lc_pixels] + 0.9 * param_value[lc_pixels] *\ np.minimum((pai / lut['veg_height'][lc_index])**3.0, 1.0) band_data.append({'band_name': 'veg_height', 'band_data': param_value}) if produce_fc: band_name = 'veg_fractional_cover' param_value = _estimate_param_value(landcover, lut, band_name) band_data.append({'band_name': band_name, 'band_data': param_value}) if produce_chwr: band_name = 'veg_height_width_ratio' param_value = _estimate_param_value(landcover, lut, band_name) band_data.append({'band_name': band_name, 'band_data': param_value}) if produce_lw: band_name = 'veg_leaf_width' param_value = _estimate_param_value(landcover, lut, band_name) band_data.append({'band_name': band_name, 'band_data': param_value}) if produce_lid: band_name = 'veg_inclination_distribution' param_value = _estimate_param_value(landcover, lut, band_name) band_data.append({'band_name': band_name, 'band_data': param_value}) if produce_igbp: band_name = 'igbp_classification' param_value = _estimate_param_value(landcover, lut, band_name) band_data.append({'band_name': band_name, 'band_data': param_value}) su.write_snappy_product(output_file, band_data, 'landcoverParams', geo_coding)
def main(sentinel_2_reflectance, sentinel_3_lst, high_res_dem, high_res_geom, lst_quality_mask, date_time_utc, elevation_band, lst_good_quality_flags, cv_homogeneity_threshold, moving_window_size, parallel_jobs, output): # Derive illumination conditions from the DEM print('INFO: Deriving solar illumination conditions...') temp_file = tempfile.NamedTemporaryFile(suffix=".tif", delete=False) temp_dem_file = temp_file.name temp_file.close() su.copy_bands_to_file(high_res_dem, temp_dem_file, [elevation_band]) temp_slope_file = gu.slope_from_dem(temp_dem_file) temp_aspect_file = gu.aspect_from_dem(temp_dem_file) slope = gu.raster_data(temp_slope_file) aspect = gu.raster_data(temp_aspect_file) try: lat = su.read_snappy_product(high_res_geom, 'latitude_tx')[0] except RuntimeError: lat = su.read_snappy_product(high_res_geom, 'latitude_in')[0] try: lon = su.read_snappy_product(high_res_geom, 'longitude_tx')[0] except RuntimeError: lon = su.read_snappy_product(high_res_geom, 'longitude_in')[0] doy = date_time_utc.timetuple().tm_yday ftime = date_time_utc.hour + date_time_utc.minute/60.0 cos_theta = incidence_angle_tilted(lat, lon, doy, ftime, stdlon=0, A_ZS=aspect, slope=slope) proj, gt = gu.raster_info(temp_dem_file)[0:2] temp_cos_theta_file = pth.splitext(temp_dem_file)[0] + '_cos_theta.tif' fp = gu.save_image(cos_theta, gt, proj, temp_cos_theta_file) fp = None slope = None aspect = None cos_theta = None print('INFO: Preparing high-resolution data...') # Combine all high-resolution data into one virtual raster temp_file = tempfile.NamedTemporaryFile(suffix=".tif", delete=False) temp_refl_file = temp_file.name temp_file.close() su.copy_bands_to_file(sentinel_2_reflectance, temp_refl_file) vrt_filename = pth.splitext(temp_refl_file)[0]+".vrt" fp = gu.merge_raster_layers([temp_refl_file, temp_dem_file, temp_cos_theta_file], vrt_filename, separate=True) fp = None high_res_filename = vrt_filename # Save low resolution files as geotiffs temp_file = tempfile.NamedTemporaryFile(suffix=".tif", delete=False) temp_lst_file = temp_file.name temp_file.close() su.copy_bands_to_file(sentinel_3_lst, temp_lst_file, ["LST"]) temp_file = tempfile.NamedTemporaryFile(suffix=".tif", delete=False) temp_mask_file = temp_file.name temp_file.close() su.copy_bands_to_file(lst_quality_mask, temp_mask_file) # Set options of the disaggregator flags = [int(i) for i in lst_good_quality_flags.split(",")] dms_options =\ {"highResFiles": [high_res_filename], "lowResFiles": [temp_lst_file], "lowResQualityFiles": [temp_mask_file], "lowResGoodQualityFlags": flags, "cvHomogeneityThreshold": cv_homogeneity_threshold, "movingWindowSize": moving_window_size, "disaggregatingTemperature": True, "baggingRegressorOpt": {"n_jobs": parallel_jobs, "n_estimators": 30, "max_samples": 0.8, "max_features": 0.8}} disaggregator = DecisionTreeSharpener(**dms_options) # Do the sharpening print("INFO: Training regressor...") disaggregator.trainSharpener() print("INFO: Sharpening...") downscaled_file = disaggregator.applySharpener(high_res_filename, temp_lst_file) print("INFO: Residual analysis...") residual_image, corrected_image = disaggregator.residualAnalysis(downscaled_file, temp_lst_file, temp_mask_file, doCorrection=True) # Save the sharpened file band = {"band_name": "sharpened_LST", "description": "Sharpened Sentinel-3 LST", "unit": "K", "band_data": corrected_image.GetRasterBand(1).ReadAsArray()} geo_coding = su.get_product_info(sentinel_2_reflectance)[1] su.write_snappy_product(output, [band], "sharpenedLST", geo_coding) # Clean up try: os.remove(temp_dem_file) os.remove(temp_aspect_file) os.remove(temp_slope_file) os.remove(temp_cos_theta_file) os.remove(temp_refl_file) os.remove(temp_lst_file) os.remove(temp_mask_file) except Exception: pass