def computeImpGeoloc(in_productType, in_objPixc, in_indices, in_height):
    """
    Refines geolocation for in_objPixc pixels corresponding to indices in_indices (in in_objPix)
        
    :param in_productType: type of product among "SP"=LakeSP and "TILE"=LakeTile
    :type in_productType: string
    :param in_objPixc: pixel cloud from which to compute improved geolocation
    :type in_objPixc: proc_pixc.PixelCloud or proc_pixc_sp.PixelCloudSP object
    :param in_indices: indices of pixels related to the same object
    :type in_indices: 1D-array of int
    :param in_height: new height of each point used for improved geoloc
    :type in_height: 1D-array of float
        
    :return out_lon_corr: improved longitude of pixels of in_indices
    :rtype: 1D-array of float
    :return out_lat_corr: improved latitude of pixels of in_indices
    :rtype: 1D-array of float
    :return out_lat_corr: improved latitude of pixels of in_indices
    :rtype: 1D-array of float
    """
    logger = logging.getLogger("proc_pixc_vec")
    nb_pix = in_indices.size
    logger.debug("> %d PixC to deal with", nb_pix)
        
    # 1 - Prepare data for Damien's algo
    # 1.1 - Convert geodetic coordinates (lat, lon, height) to cartesian coordinates (x, y, z)
    x, y, z = my_geoloc.convert_llh2ecef(in_objPixc.latitude[in_indices], in_objPixc.longitude[in_indices], in_objPixc.height[in_indices], my_var.GEN_RAD_EARTH_EQ, my_var.GEN_RAD_EARTH_POLE)
    # 1.2 - Get position of associated along-track pixels (in cartesian coordinates)
    nadir_x = in_objPixc.nadir_x[in_indices]
    nadir_y = in_objPixc.nadir_y[in_indices]
    nadir_z = in_objPixc.nadir_z[in_indices]
    # 1.3 - Get velocity of associated along-track pixels (in cartesian coordinates)
    nadir_vx = in_objPixc.nadir_vx[in_indices]
    nadir_vy = in_objPixc.nadir_vy[in_indices]
    nadir_vz = in_objPixc.nadir_vz[in_indices]
    # 1.4 - Get distance from satellite to target point
    ri = in_objPixc.near_range + in_objPixc.range_index[in_indices] * my_var.GEN_RANGE_SPACING
    
    # 2 - Use Damien's algo
    # 2.1 - Init output vectors
    out_lat_corr = np.zeros(nb_pix)  # Improved latitudes
    out_lon_corr = np.zeros(nb_pix)  # Improved longitudes
    out_height_corr = np.zeros(nb_pix)  # Improved heights
    # 2.2 - Improve geolocation
    p_final, p_final_llh, h_mu, (iter_grad,nfev_minimize_scalar) = my_geoloc.pointcloud_height_geoloc_vect(np.transpose(np.array([x, y, z])), in_objPixc.height[in_indices],
                                                                                                           np.transpose(np.array([nadir_x, nadir_y, nadir_z])),
                                                                                                           np.transpose(np.array([nadir_vx, nadir_vy, nadir_vz])),
                                                                                                           ri, in_height, 
                                                                                                           recompute_Doppler=True, recompute_R=True, verbose=False, 
                                                                                                           max_iter_grad=1, height_goal=1.e-3, safe_flag=True)
    # 2.3 - Save output variables
    out_lat_corr, out_lon_corr, out_height_corr = np.transpose(p_final_llh)
    
    # 2.4 - Return output between 0 and 360 degrees (pixel cloud format)
    return my_tools.convert_to_0_360(out_lon_corr), out_lat_corr, out_height_corr
    def taylor_improved_geoloc(self):
        """
        Improve the height of noisy point (in object sensor)
        """

        nb_pix = self.pixcvec.height.size
        # Convert geodetic coordinates (lat, lon, height) to cartesian coordinates (x, y, z)
        x, y, z = geoloc.convert_llh2ecef(self.pixcvec.latitude,
                                          self.pixcvec.longitude,
                                          self.pixcvec.height,
                                          GEN_RAD_EARTH_EQ, GEN_RAD_EARTH_POLE)

        # Get position of associated along-track pixels (in cartesian coordinates)
        nadir_x = self.sensor.nadir_x
        nadir_y = self.sensor.nadir_y
        nadir_z = self.sensor.nadir_z

        # Get velocity of associated along-track pixels (in cartesian coordinates)
        nadir_vx = self.sensor.nadir_vx
        nadir_vy = self.sensor.nadir_vy
        nadir_vz = self.sensor.nadir_vz

        # Get distance from satellite to target point
        ri = self.pixcvec.near_range + self.pixcvec.range_idx * self.pixcvec.range_spacing

        # Init output vectors
        self.out_lat_corr = np.zeros(nb_pix)  # Improved latitudes
        self.out_lon_corr = np.zeros(nb_pix)  # Improved longitudes
        self.out_height_corr = np.zeros(nb_pix)  # Improved heights

        # need to remap illumnation time to nearest sensor index
        # TODO replace this by a call to a get_sensor_index or equivalent function
        # that either interpolates the sensor or does something more efficient
        f = interpolate.interp1d(self.sensor.time,
                                 range(len(self.sensor.time)))
        sensor_s = (np.rint(f(self.pixc.illumination_time))).astype(int)

        # Loop over each pixel (could be vectorized)
        # vectorisation
        h_noisy = self.pixcvec.height
        nadir_x_vect = np.zeros(nb_pix)
        nadir_y_vect = np.zeros(nb_pix)
        nadir_z_vect = np.zeros(nb_pix)
        nadir_vx_vect = np.zeros(nb_pix)
        nadir_vy_vect = np.zeros(nb_pix)
        nadir_vz_vect = np.zeros(nb_pix)

        for i in np.arange(nb_pix):
            ind_sensor = sensor_s[i]
            nadir_x_vect[i] = nadir_x[ind_sensor]
            nadir_y_vect[i] = nadir_y[ind_sensor]
            nadir_z_vect[i] = nadir_z[ind_sensor]
            nadir_vx_vect[i] = nadir_vx[ind_sensor]
            nadir_vy_vect[i] = nadir_vy[ind_sensor]
            nadir_vz_vect[i] = nadir_vz[ind_sensor]

        # improuve height with vectorised pixel
        p_final, p_final_llh, h_mu, (
            iter_grad,
            nfev_minimize_scalar) = geoloc.pointcloud_height_geoloc_vect(
                np.transpose(np.array([x, y, z])),
                h_noisy,
                np.transpose(
                    np.array([nadir_x_vect, nadir_y_vect, nadir_z_vect])),
                np.transpose(
                    np.array([nadir_vx_vect, nadir_vy_vect, nadir_vz_vect])),
                ri,
                self.new_height,
                recompute_doppler=True,
                recompute_range=True,
                verbose=False,
                max_iter_grad=1,
                height_goal=1.e-3)

        self.out_lat_corr, self.out_lon_corr, self.out_height_corr = np.transpose(
            p_final_llh)
 def swotlib_improved_geoloc(self):
     """
     wrapper for functions that use the actual geolocation in swotlib
     """
     # import python/swotlib-only stuff
     import swot.proc.geolocate
     import swot.proc.base_classes
     import swot.multilook.multilook as ml
     import swot.refloc.refloc
     #print ("got here", self.sensor)
     # make swot.proc sensor file from damiens version
     sensor = swot.proc.base_classes.TVP()#Sensor()
     sensor.time = np.array(self.sensor.time, dtype=np.double)
     sensor.x = np.array(self.sensor.nadir_x, dtype=np.double)
     sensor.y = np.array(self.sensor.nadir_y, dtype=np.double)
     sensor.z = np.array(self.sensor.nadir_z, dtype=np.double)
     sensor.vx = np.array(self.sensor.nadir_vx, dtype=np.double)
     sensor.vy = np.array(self.sensor.nadir_vy, dtype=np.double)
     sensor.vz = np.array(self.sensor.nadir_vz, dtype=np.double)
     sensor.ref_leverarm_x = np.array(self.sensor.ref_leverarm_x, dtype=np.double)
     sensor.ref_leverarm_y = np.array(self.sensor.ref_leverarm_y, dtype=np.double)
     sensor.ref_leverarm_z = np.array(self.sensor.ref_leverarm_z, dtype=np.double)
     sensor.sec_leverarm_x = np.array(self.sensor.sec_leverarm_x, dtype=np.double)
     sensor.sec_leverarm_y = np.array(self.sensor.sec_leverarm_y, dtype=np.double)
     sensor.sec_leverarm_z = np.array(self.sensor.sec_leverarm_z, dtype=np.double)
     #
     #sensor.baseline_left_x = np.array(self.sensor.baseline_left_x,dtype=np.double)
     #sensor.baseline_left_y = np.array(self.sensor.baseline_left_y,dtype=np.double)
     #sensor.baseline_left_z = np.array(self.sensor.baseline_left_z, dtype=np.double)
     #sensor.baseline_right_x = np.array(self.sensor.baseline_right_x, dtype=np.double)
     #sensor.baseline_right_y = np.array(self.sensor.baseline_right_y, dtype=np.double)
     #sensor.baseline_right_z = np.array(self.sensor.baseline_right_z ,dtype=np.double)
     #print ("#########sensor:",sensor.x)
     # get the azimuth looks
     azimuth_looks = int(np.nanmedian(self.pixc.num_rare_looks))
     #print ('#########az_looks:',azimuth_looks)
     line_to_sensor = np.arange(len(sensor.x))
     # fake these so we dont have to read them in and mess with the interface
     #sensor.time = np.array(line_to_sensor,dtype=np.double)
     #lat, lon, height = geoloc.convert_ecef2llh(
     #    sensor.x, sensor.y, sensor.z, GEN_RAD_EARTH_EQ, GEN_RAD_EARTH_POLE)
     #sensor.latitude = np.zeros(np.shape(sensor.x))
     #sensor.longitude = np.zeros(np.shape(sensor.x))
     #sensor.altitude =  np.zeros(np.shape(sensor.x))
     #sensor.heading = np.zeros(np.shape(sensor.x))
     
     rare_line_to_sensor = ml.boxcar_downsample(
         line_to_sensor[np.newaxis].T, azimuth_looks, 1,
         agg_type='sample')
     
     # get the swath side
     swath_side = 'Left'
     swath_side_int = 1
     if self.pixc.tile_ref.endswith('R'):
         swath_side = 'Right'
         swath_side_int = -1
     # make a refloc object
     attributes = {}#pixc.attributes
     attributes['nr_pixels'] = self.pixc.nr_pixels
     attributes['nr_lines'] = self.pixc.nr_lines
     attributes['wavelength'] = self.pixc.wavelength
     attributes['range_spacing'] = self.pixc.range_spacing
     attributes['near_range'] = self.pixc.near_range
     attributes['swath_side_flag'] = swath_side_int
     refloc = swot.refloc.refloc.refloc_from_sensor(
         sensor, attributes, rare_line_to_sensor)
     
     # set xyz image
     # Convert geodetic coordinates (lat, lon, height) to cartesian coordinates (x, y, z)
     x, y, z = geoloc.convert_llh2ecef(
         self.pixcvec.latitude, 
         self.pixcvec.longitude, 
         self.pixcvec.height, 
         GEN_RAD_EARTH_EQ, GEN_RAD_EARTH_POLE)
     #
     X = np.zeros((attributes['nr_lines'],attributes['nr_pixels']))
     Y = np.zeros((attributes['nr_lines'],attributes['nr_pixels']))
     Z = np.zeros((attributes['nr_lines'],attributes['nr_pixels']))
     X[self.pixcvec.azimuth_idx,self.pixcvec.range_idx] = x
     Y[self.pixcvec.azimuth_idx,self.pixcvec.range_idx] = y
     Z[self.pixcvec.azimuth_idx,self.pixcvec.range_idx] = z
     refloc.set_xyz(X,Y,Z)
     
     # set s_image
     use_illumination_time = True
     if use_illumination_time:
         # use the s_image in the pixc file
         s_image = np.zeros((attributes['nr_lines'],attributes['nr_pixels']))
                                 
         #### OLD WAY
         #~ sensor_s = [np.argmin(abs(self.sensor.time 
                                   #~ - self.pixc.illumination_time[k])) 
                     #~ for k in range(len(self.pixc.illumination_time))]
                     
         f = interpolate.interp1d(self.sensor.time,range(len(self.sensor.time)))
         sensor_s = (np.rint(f(self.pixc.illumination_time))).astype(np.double)
                     
         s_image[self.pixc.azimuth_index,self.pixc.range_index] = sensor_s[:]
         refloc.set_s_prof(s_image)
     else:
         # recompute s-image using pixc geoloc as refloc
         refloc.compute_s_prof(0, attributes['nr_lines'])
     #refloc.compute_s_prof(0, attributes['nr_lines'])
     # make H_new as a 2d image
     H_new = np.zeros((attributes['nr_lines'],attributes['nr_pixels']))
     H_new[self.pixcvec.azimuth_idx,self.pixcvec.range_idx] = self.new_height[:]
     
     # finally call the function that does the work 
     #llh = swot.proc.geolocate.height_constrained_geoloc_grad_search (
     #    refloc,
     #    sensor,
     #    H_new,
     #    self.pixc.wavelength,
     #    swath_side_int,
     #    maxiter=10)
     xyz = swot.proc.geolocate.fixed_height_geolocation (
         refloc,
         sensor,
         H_new,
         self.pixc.wavelength)
     llh = swot.proc.geolocate.xyz2llh(xyz)
     # map to outputs
     lat = np.squeeze(llh[0,:,:])
     lon = np.squeeze(llh[1,:,:])
     height = np.squeeze(llh[2,:,:])
     
     msk = np.zeros((attributes['nr_lines'],attributes['nr_pixels']))
     msk[self.pixcvec.azimuth_idx,self.pixcvec.range_idx] = 1
     self.OUT_lat_corr = lat[msk==1]
     self.OUT_lon_corr = lon[msk==1]
     self.OUT_height_corr = height[msk==1]
    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 taylor_improved_geoloc(self):
        """ Improve the height of noisy point (in object sensor) """
        LOGGER.info("doing taylor improved geolocation")

        nb_pix = self.pixc['pixel_cloud']['height'].size
        # Convert geodetic coordinates (lat, lon, height) to cartesian coordinates (x, y, z)
        x, y, z = geoloc.convert_llh2ecef(self.pixc['pixel_cloud']['latitude'],
                                          self.pixc['pixel_cloud']['longitude'],
                                          self.pixc['pixel_cloud']['height'],
                                          GEN_RAD_EARTH_EQ, GEN_RAD_EARTH_POLE)

        # Get position of associated along-track pixels (in cartesian coordinates)
        nadir_x = self.pixc['tvp']['x']
        nadir_y = self.pixc['tvp']['y']
        nadir_z = self.pixc['tvp']['z']

        # Get velocity of associated along-track pixels (in cartesian coordinates)
        nadir_vx = self.pixc['tvp']['vx']
        nadir_vy = self.pixc['tvp']['vy']
        nadir_vz = self.pixc['tvp']['vz']

        # Get distance from satellite to target point
        ri = self.pixc.near_range + (self.pixc['pixel_cloud']['range_index']
                                     * self.pixc.nominal_slant_range_spacing)

        # Init output vectors
        self.out_lat_corr = np.zeros(nb_pix)  # Improved latitudes
        self.out_lon_corr = np.zeros(nb_pix)  # Improved longitudes
        self.out_height_corr = np.zeros(nb_pix)  # Improved heights

        # Remap illumnation time to nearest sensor index
        sensor_s = ag.get_sensor_index(self.pixc)

        # Loop over each pixel (could be vectorized)
        h_noisy = self.pixc['pixel_cloud']['height']
        nadir_x_vect = np.zeros(nb_pix)
        nadir_y_vect = np.zeros(nb_pix)
        nadir_z_vect = np.zeros(nb_pix)
        nadir_vx_vect = np.zeros(nb_pix)
        nadir_vy_vect = np.zeros(nb_pix)
        nadir_vz_vect = np.zeros(nb_pix)

        for i in np.arange(nb_pix):
            ind_sensor = sensor_s[i]
            nadir_x_vect[i] = nadir_x[ind_sensor]
            nadir_y_vect[i] = nadir_y[ind_sensor]
            nadir_z_vect[i] = nadir_z[ind_sensor]
            nadir_vx_vect[i] = nadir_vx[ind_sensor]
            nadir_vy_vect[i] = nadir_vy[ind_sensor]
            nadir_vz_vect[i] = nadir_vz[ind_sensor]

        # improve height with vectorised pixel
        p_final, p_final_llh, h_mu, (iter_grad, nfev_minimize_scalar) = \
            geoloc.pointcloud_height_geoloc_vect(np.transpose(np.array([x, y, z])),
                                                 h_noisy,
                                                 np.transpose(np.array(
                                                     [nadir_x_vect, nadir_y_vect,
                                                      nadir_z_vect])),
                                                 np.transpose(np.array(
                                                     [nadir_vx_vect, nadir_vy_vect,
                                                      nadir_vz_vect])),
                                                 ri, self.new_height,
                                                 recompute_doppler=True,
                                                 recompute_range=True, verbose=False,
                                                 max_iter_grad=1, height_goal=1.e-3)

        self.out_lat_corr, self.out_lon_corr, self.out_height_corr = np.transpose(
            p_final_llh)