def aggregate_illumination_time(self, pixc, mask): """ Aggregate illumination time """ LOGGER.info("aggregating illumination time") pixc_illumination_time = pixc['pixel_cloud']['illumination_time'] pixc_illumination_time_tai = pixc['pixel_cloud']['illumination_time_tai'] self.illumination_time = np.ma.masked_all((self.size_y, self.size_x)) self.illumination_time_tai = np.ma.masked_all((self.size_y, self.size_x)) for i in range(0, self.size_y): for j in range(0, self.size_x): good = mask[self.proj_mapping[i][j]] if np.any(good): self.illumination_time[i][j] = ag.simple( pixc_illumination_time[self.proj_mapping[i][j]][good], metric='mean') self.illumination_time_tai[i][j] = ag.simple( pixc_illumination_time_tai[self.proj_mapping[i][j]][good], metric='mean') # Set the time coverage start and end based on illumination time if np.all(self.illumination_time.mask): self.time_coverage_start = SWOTRaster.products.EMPTY_DATETIME self.time_coverage_end = SWOTRaster.products.EMPTY_DATETIME else: start_illumination_time = np.min(self.illumination_time) end_illumination_time = np.max(self.illumination_time) start_time = datetime.utcfromtimestamp( (SWOTRaster.products.SWOT_EPOCH - SWOTRaster.products.UNIX_EPOCH).total_seconds() \ + start_illumination_time) stop_time = datetime.utcfromtimestamp( (SWOTRaster.products.SWOT_EPOCH - SWOTRaster.products.UNIX_EPOCH).total_seconds() \ + end_illumination_time) self.time_coverage_start = start_time.strftime( SWOTRaster.products.DATETIME_FORMAT_STR) self.time_coverage_end = stop_time.strftime( SWOTRaster.products.DATETIME_FORMAT_STR) # Set tai_utc_difference min_illumination_time_index = np.unravel_index( np.argmin(self.illumination_time), self.illumination_time.shape) self.tai_utc_difference = \ self.illumination_time_tai[min_illumination_time_index] \ - self.illumination_time[min_illumination_time_index] # Set leap second if pixc.leap_second == SWOTRaster.products.EMPTY_LEAPSEC: self.leap_second = SWOTRaster.products.EMPTY_LEAPSEC else: leap_second = datetime.strptime(pixc.leap_second, SWOTRaster.products.LEAPSEC_FORMAT_STR) if leap_second < start_time or leap_second > end_time: leap_second = SWOTRaster.products.EMPTY_LEAPSEC self.leap_second = leap_second.strftime( SWOTRaster.products.LEAPSEC_FORMAT_STR)
def aggregate_sig0(self, pixc, mask): """ Aggregate sigma0 """ LOGGER.info("aggregating sigma0") pixc_sig0 = pixc['pixel_cloud']['sig0'] pixc_sig0_uncert = pixc['pixel_cloud']['sig0_uncert'] self.sig0 = np.ma.masked_all((self.size_y, self.size_x)) self.sig0_u = np.ma.masked_all((self.size_y, self.size_x)) self.sig0_qual = np.ma.ones((self.size_y, self.size_x)) self.n_sig0_pix = np.ma.zeros((self.size_y, self.size_x)) for i in range(0, self.size_y): for j in range(0, self.size_x): good = mask[self.proj_mapping[i][j]] if np.any(good): grid_sig0 = ag.sig0_with_uncerts( pixc_sig0[self.proj_mapping[i][j]], good, pixc_sig0_uncert[self.proj_mapping[i][j]], method='rare') self.sig0[i][j] = grid_sig0[0] self.sig0_u[i][j] = grid_sig0[2] n_sig0_px = ag.simple(good, metric='sum') if n_sig0_px > 0: self.n_sig0_pix[i][j] = n_sig0_px # TODO: more complex qual handling self.sig0_qual[i][j] = np.logical_or( self.sig0_u[i][j] >= SIG0_BAD_UNCERT, self.n_sig0_pix[i][j] <= BAD_NUM_PIXELS)
def aggregate_water_area(self, pixc, mask): """ Aggregate water area, water fraction and associated uncertainties """ LOGGER.info("aggregating water area") pixc_pixel_area = pixc['pixel_cloud']['pixel_area'] pixc_water_fraction = pixc['pixel_cloud']['water_frac'] pixc_water_fraction_uncert = pixc['pixel_cloud']['water_frac_uncert'] pixc_darea_dheight = pixc['pixel_cloud']['darea_dheight'] pixc_pfd = pixc['pixel_cloud']['false_detection_rate'] pixc_pmd = pixc['pixel_cloud']['missed_detection_rate'] pixc_classif = pixc['pixel_cloud']['classification'] self.water_area = np.ma.masked_all((self.size_y, self.size_x)) self.water_area_u = np.ma.masked_all((self.size_y, self.size_x)) self.water_frac = np.ma.masked_all((self.size_y, self.size_x)) self.water_frac_u = np.ma.masked_all((self.size_y, self.size_x)) self.water_area_qual = np.ma.ones((self.size_y, self.size_x)) self.n_water_area_pix = np.ma.zeros((self.size_y, self.size_x)) for i in range(0, self.size_y): for j in range(0, self.size_x): good = mask[self.proj_mapping[i][j]] if np.any(good): grid_area = ag.area_with_uncert( pixc_pixel_area[self.proj_mapping[i][j]], pixc_water_fraction[self.proj_mapping[i][j]], pixc_water_fraction_uncert[self.proj_mapping[i][j]], pixc_darea_dheight[self.proj_mapping[i][j]], pixc_classif[self.proj_mapping[i][j]], pixc_pfd[self.proj_mapping[i][j]], pixc_pmd[self.proj_mapping[i][j]], good, method=self.area_agg_method, interior_water_klasses=self.interior_water_classes, water_edge_klasses=self.water_edge_classes, land_edge_klasses=self.land_edge_classes, dark_water_klasses=self.dark_water_classes) self.water_area[i][j] = grid_area[0] self.water_area_u[i][j] = grid_area[1] if self.projection_type == 'utm': pixel_area = self.resolution**2 elif self.projection_type == 'geo': px_latitude = self.y_min + self.resolution*i pixel_area = SWOTRaster.raster_crs.wgs84_px_area( px_latitude, self.resolution) else: raise ValueError( 'Unknown projection type: {}'.format( self.projection_type)) self.water_frac[i][j] = grid_area[0]/pixel_area self.water_frac_u[i][j] = grid_area[1]/pixel_area self.n_water_area_pix[i][j] = ag.simple(good, metric='sum') # TODO: more complex qual handling self.water_area_qual[i][j] = np.logical_or( self.water_frac_u[i][j] >= WATER_FRAC_BAD_UNCERT, self.n_water_area_pix[i][j] <= BAD_NUM_PIXELS)
def aggregate_cross_track(self, pixc, mask): """ Aggregate cross track """ LOGGER.info("aggregating cross track") pixc_cross_track = pixc['pixel_cloud']['cross_track'] self.cross_track = np.ma.masked_all((self.size_y, self.size_x)) self.n_other_pix = np.ma.zeros((self.size_y, self.size_x)) for i in range(0, self.size_y): for j in range(0, self.size_x): good = mask[self.proj_mapping[i][j]] if np.any(good): self.cross_track[i][j] = ag.simple( pixc_cross_track[self.proj_mapping[i][j]][good], metric='mean') self.n_other_pix[i][j] = ag.simple(good, metric='sum')
def aggregate_corrections(self, pixc, mask): """ Aggregate geophysical corrections """ LOGGER.info("aggregating corrections") pixc_geoid = pixc['pixel_cloud']['geoid'] pixc_solid_earth_tide = pixc['pixel_cloud']['solid_earth_tide'] pixc_load_tide_fes = pixc['pixel_cloud']['load_tide_fes'] pixc_load_tide_got = pixc['pixel_cloud']['load_tide_got'] pixc_pole_tide = pixc['pixel_cloud']['pole_tide'] pixc_model_dry_tropo_cor = pixc['pixel_cloud']['model_dry_tropo_cor'] pixc_model_wet_tropo_cor = pixc['pixel_cloud']['model_wet_tropo_cor'] pixc_iono_cor_gim_ka = pixc['pixel_cloud']['iono_cor_gim_ka'] self.geoid = np.ma.masked_all((self.size_y, self.size_x)) self.solid_earth_tide = np.ma.masked_all((self.size_y, self.size_x)) self.load_tide_fes = np.ma.masked_all((self.size_y, self.size_x)) self.load_tide_got = np.ma.masked_all((self.size_y, self.size_x)) self.pole_tide = np.ma.masked_all((self.size_y, self.size_x)) self.model_dry_tropo_cor = np.ma.masked_all((self.size_y, self.size_x)) self.model_wet_tropo_cor = np.ma.masked_all((self.size_y, self.size_x)) self.iono_cor_gim_ka = np.ma.masked_all((self.size_y, self.size_x)) for i in range(0, self.size_y): for j in range(0, self.size_x): good = mask[self.proj_mapping[i][j]] if np.any(good): self.geoid[i][j] = ag.simple( pixc_geoid[self.proj_mapping[i][j]][good], metric='mean') self.solid_earth_tide[i][j] = ag.simple( pixc_solid_earth_tide[self.proj_mapping[i][j]][good], metric='mean') self.load_tide_fes[i][j] = ag.simple( pixc_load_tide_fes[self.proj_mapping[i][j]][good], metric='mean') self.load_tide_got[i][j] = ag.simple( pixc_load_tide_got[self.proj_mapping[i][j]][good], metric='mean') self.pole_tide[i][j] = ag.simple( pixc_pole_tide[self.proj_mapping[i][j]][good], metric='mean') self.model_dry_tropo_cor[i][j] = ag.simple( pixc_model_dry_tropo_cor[self.proj_mapping[i][j]][good], metric='mean') self.model_wet_tropo_cor[i][j] = ag.simple( pixc_model_wet_tropo_cor[self.proj_mapping[i][j]][good], metric='mean') self.iono_cor_gim_ka[i][j] = ag.simple( pixc_iono_cor_gim_ka[self.proj_mapping[i][j]][good], metric='mean')
def aggregate_classification(self, pixc, mask): """ Aggregate binary classification """ LOGGER.info("aggregating classification") pixc_classif = pixc['pixel_cloud']['classification'] self.classification = np.ma.masked_all((self.size_y, self.size_x)) for i in range(0, self.size_y): for j in range(0, self.size_x): good = mask[self.proj_mapping[i][j]] if np.any(good): self.classification[i][j] = ag.simple( pixc_classif[self.proj_mapping[i][j]][good], metric='mode')
def aggregate_inc(self, pixc, mask): """ Aggregate incidence angle """ LOGGER.info("aggregating incidence angle") pixc_inc = pixc['pixel_cloud']['inc'] self.inc = np.ma.masked_all((self.size_y, self.size_x)) for i in range(0, self.size_y): for j in range(0, self.size_x): good = mask[self.proj_mapping[i][j]] if np.any(good): self.inc[i][j] = ag.simple( pixc_inc[self.proj_mapping[i][j]][good], metric='mean')
def aggregate_dark_frac(self, pixc, mask): """ Aggregate dark water fraction """ LOGGER.info("aggregating dark fraction") pixc_classif = pixc['pixel_cloud']['classification'] pixc_pixel_area = pixc['pixel_cloud']['pixel_area'] pixc_water_fraction = pixc['pixel_cloud']['water_frac'] dark_mask = np.isin(pixc_classif, self.dark_water_classes) self.dark_frac = np.ma.masked_all((self.size_y, self.size_x)) for i in range(0, self.size_y): for j in range(0, self.size_x): good = mask[self.proj_mapping[i][j]] if np.any(good): good_dark = np.logical_and( dark_mask[self.proj_mapping[i][j]], good) dark_area = ag.simple( pixc_pixel_area[self.proj_mapping[i][j]][good_dark], metric='sum') total_area, _ = ag.area_only( pixc_pixel_area[self.proj_mapping[i][j]], pixc_water_fraction[self.proj_mapping[i][j]], pixc_classif[self.proj_mapping[i][j]], good, method=self.area_agg_method, interior_water_klasses=self.interior_water_classes, water_edge_klasses=self.water_edge_classes, land_edge_klasses=self.land_edge_classes, dark_water_klasses=self.dark_water_classes) # If we don't have any water at all, we have no dark water... if total_area==0: self.dark_frac[i][j] = 0 else: self.dark_frac[i][j] = dark_area/total_area
def aggregate_wse(self, pixc, mask, use_improved_geoloc=True): """ Aggregate water surface elevation and associated uncertainties """ LOGGER.info("aggregating wse") pixc_height = pixc['pixel_cloud']['height'] pixc_num_rare_looks = pixc['pixel_cloud']['eff_num_rare_looks'] pixc_num_med_looks = pixc['pixel_cloud']['eff_num_medium_looks'] pixc_power_plus_y = pixc['pixel_cloud']['power_plus_y'] pixc_power_minus_y = pixc['pixel_cloud']['power_minus_y'] pixc_dh_dphi = pixc['pixel_cloud']['dheight_dphase'] pixc_dlat_dphi = pixc['pixel_cloud']['dlatitude_dphase'] pixc_dlon_dphi = pixc['pixel_cloud']['dlongitude_dphase'] pixc_phase_noise_std = pixc['pixel_cloud']['phase_noise_std'] pixc_height_std = np.abs(pixc_phase_noise_std * pixc_dh_dphi) # set bad pix height std to high number to deweight # instead of giving infs/nans bad_num = 1.0e5 pixc_height_std[pixc_height_std<=0] = bad_num pixc_height_std[np.isinf(pixc_height_std)] = bad_num pixc_height_std[np.isnan(pixc_height_std)] = bad_num looks_to_efflooks = pixc['pixel_cloud'].looks_to_efflooks if use_improved_geoloc: # Flatten ifgram with improved geoloc and height target_xyz = geoloc.convert_llh2ecef( pixc['pixel_cloud']['improved_latitude'], pixc['pixel_cloud']['improved_longitude'], pixc['pixel_cloud']['improved_height'], GEN_RAD_EARTH_EQ, GEN_RAD_EARTH_POLE) else: # Flatten ifgram with original geoloc and improved height target_xyz = geoloc.convert_llh2ecef( pixc['pixel_cloud']['latitude'], pixc['pixel_cloud']['longitude'], pixc['pixel_cloud']['improved_height'], GEN_RAD_EARTH_EQ, GEN_RAD_EARTH_POLE) pixc_ifgram = pixc['pixel_cloud']['interferogram'] tvp_plus_y_antenna_xyz = (pixc['tvp']['plus_y_antenna_x'], pixc['tvp']['plus_y_antenna_y'], pixc['tvp']['plus_y_antenna_z']) tvp_minus_y_antenna_xyz = (pixc['tvp']['minus_y_antenna_x'], pixc['tvp']['minus_y_antenna_y'], pixc['tvp']['minus_y_antenna_z']) pixc_tvp_index = ag.get_sensor_index(pixc) pixc_wavelength = pixc.wavelength flat_ifgram = ag.flatten_interferogram(pixc_ifgram, tvp_plus_y_antenna_xyz, tvp_minus_y_antenna_xyz, target_xyz, pixc_tvp_index, pixc_wavelength) self.wse = np.ma.masked_all((self.size_y, self.size_x)) self.wse_u = np.ma.masked_all((self.size_y, self.size_x)) self.wse_qual = np.ma.ones((self.size_y, self.size_x)) self.n_wse_pix = np.ma.zeros((self.size_y, self.size_x)) for i in range(0, self.size_y): for j in range(0, self.size_x): good = mask[self.proj_mapping[i][j]] if np.any(good): grid_height = ag.height_with_uncerts( pixc_height[self.proj_mapping[i][j]], good, pixc_num_rare_looks[self.proj_mapping[i][j]], pixc_num_med_looks[self.proj_mapping[i][j]], flat_ifgram[self.proj_mapping[i][j]], pixc_power_minus_y[self.proj_mapping[i][j]], pixc_power_plus_y[self.proj_mapping[i][j]], looks_to_efflooks, pixc_dh_dphi[self.proj_mapping[i][j]], pixc_dlat_dphi[self.proj_mapping[i][j]], pixc_dlon_dphi[self.proj_mapping[i][j]], pixc_height_std[self.proj_mapping[i][j]], method=self.height_agg_method) self.wse[i][j] = grid_height[0] self.wse_u[i][j] = grid_height[2] self.n_wse_pix[i][j] = ag.simple(good, metric='sum') # TODO: more complex qual handling self.wse_qual[i][j] = np.logical_or( self.wse_u[i][j] >= WSE_BAD_UNCERT, self.n_wse_pix[i][j] <= BAD_NUM_PIXELS) self.apply_wse_corrections()
def rasterize_region_maps(raster_filename, int_pixc_filename, region_map_river, region_map_lake, alg_cfg, rt_cfg): raster_in = SWOTRaster.products.RasterUTM.from_ncfile(raster_filename) pixc = SWOTRaster.products.ScenePixc.from_ncfile(int_pixc_filename) # use improved geolocation if specified in config use_improved_geoloc = False if alg_cfg['height_constrained_geoloc_source'].lower() == 'lowres_raster' or \ alg_cfg['height_constrained_geoloc_source'].lower() == 'pixcvec': use_improved_geoloc = True pixc_mask = pixc.get_valid_mask(use_improved_geoloc=use_improved_geoloc) pixc_mask = np.logical_and( pixc_mask, np.isin( pixc['pixel_cloud']['classification'], np.concatenate( (alg_cfg['interior_water_classes'], alg_cfg['water_edge_classes'], alg_cfg['land_edge_classes'], alg_cfg['dark_water_classes'])))) raster_mapping = raster_in.get_raster_mapping( pixc, pixc_mask, use_improved_geoloc=use_improved_geoloc) size_y = raster_in.dimensions['y'] size_x = raster_in.dimensions['x'] region_map_river_pixc = region_map_river[ pixc['pixel_cloud']['azimuth_index'], pixc['pixel_cloud']['range_index']] region_map_lake_pixc = region_map_lake[ pixc['pixel_cloud']['azimuth_index'], pixc['pixel_cloud']['range_index']] pixc_mask_river_regions = np.logical_and(pixc_mask, region_map_river_pixc != -1) pixc_mask_lake_regions = np.logical_and(pixc_mask, region_map_lake_pixc != -1) region_map_river_raster = np.ma.masked_all((size_y, size_x), dtype=np.int32) region_map_lake_raster = np.ma.masked_all((size_y, size_x), dtype=np.int32) for i in range(0, size_y): for j in range(0, size_x): if len(raster_mapping[i][j]) != 0: good_river = pixc_mask_river_regions[raster_mapping[i][j]] good_lake = pixc_mask_lake_regions[raster_mapping[i][j]] river_tmp = ag.simple( region_map_river_pixc[raster_mapping[i][j]][good_river], metric='mode') lake_tmp = ag.simple( region_map_lake_pixc[raster_mapping[i][j]][good_lake], metric='mode') if river_tmp.size > 0 and not np.isnan(river_tmp): region_map_river_raster[i][j] = river_tmp if lake_tmp.size > 0 and not np.isnan(lake_tmp): region_map_lake_raster[i][j] = lake_tmp return region_map_river_raster, region_map_lake_raster