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()
예제 #10
0
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