示例#1
0
 def _load_emus(self, sensor):
     AEE = AtmosphericEmulationEngine(sensor, self.emus_dir)
     up_bounds = AEE.emulators[0].inputs[:, 4:7].max(axis=0)
     low_bounds = AEE.emulators[0].inputs[:, 4:7].min(axis=0)
     bounds = np.array([low_bounds, up_bounds]).T
     return AEE, bounds
示例#2
0
 def _load_emus(self):
     self.AEE = AtmosphericEmulationEngine(self.sensor, self.emus_dir)
     up_bounds = self.AEE.emulators[0].inputs[:, 4:7].max(axis=0)
     low_bounds = self.AEE.emulators[0].inputs[:, 4:7].min(axis=0)
     self.bounds = np.array([low_bounds, up_bounds]).T
class solving_atmo_paras(object):
    '''
    A class taking the toa, boa, initial [aot, water, ozone], [vza, sza, vaa, saa], elevation and emulators
    to do the atmospheric parameters retrival and do the atmopsheric correction.  
    '''
    def __init__(self,
                 sensor,
                 emus_dir,
                 boa,
                 toa,
                 sza,
                 vza,
                 saa,
                 vaa,
                 elevation,
                 boa_qa,
                 boa_bands,
                 band_indexs,
                 mask,
                 prior,
                 brdf_std,
                 atmosphere=None,
                 subsample=None,
                 subsample_start=0,
                 bands=None):

        self.alpha = -1.42  #angstrom exponent for continental type aerosols
        self.sensor = sensor
        self.emus_dir = emus_dir
        self.boa, self.toa = boa, toa
        self.atmosphere = atmosphere
        self.sza, self.vza = sza, vza
        self.saa, self.vaa = saa, vaa
        self.elevation = elevation
        self.boa_qa = boa_qa
        self.boa_bands = boa_bands
        self.band_weights = (np.array(self.boa_bands) / 1000.)**self.alpha
        self.band_indexs = band_indexs
        self.mask = mask
        self.prior = prior
        self.brdf_std = brdf_std
        if subsample is None:
            self.subsample = 1
        else:
            self.subsample = subsample
        self.subsample_sta = subsample_start

    def _load_emus(self):
        self.AEE = AtmosphericEmulationEngine(self.sensor, self.emus_dir)
        up_bounds = self.AEE.emulators[0].inputs[:, 4:7].max(axis=0)
        low_bounds = self.AEE.emulators[0].inputs[:, 4:7].min(axis=0)
        self.bounds = np.array([low_bounds, up_bounds]).T

    def _load_unc(self):
        uc = grab_uncertainty(self.boa, self.boa_bands, self.boa_qa,
                              self.brdf_std)
        self.boa_unc = uc.get_boa_unc()
        self.aot_unc = uc.aot_unc
        self.water_unc = uc.water_unc
        self.ozone_unc = uc.ozone_unc

    def _sort_emus_inputs(self, ):

        assert self.boa.shape[
            1:] == self.mask.shape, 'mask should have the same shape as the last two axises of boa.'
        assert self.boa.shape == self.toa.shape, 'toa and boa should have the same shape.'
        assert self.boa.shape == self.boa_unc.shape, 'boa and boa_unc should have the same shape.'
        if self.atmosphere is not None:
            assert self.atmosphere.shape[
                0] == 3, 'Three parameters, i.e. AOT, water and Ozone are needed.'
            assert self.boa.shape[1:] == self.atmosphere.shape[
                1:], 'boa and atmosphere should have the same shape in the last two axises.'
        # make the boa and toa to be the shape of nbands * nsample
        # and apply the flattened mask and subsample
        if self.mask.ndim == 2:
            flat_mask = self.mask[self.subsample_sta::self.subsample, \
                                  self.subsample_sta::self.subsample].flatten()
        elif self.mask.ndim == 1:
            flat_mask = self.mask[self.subsample_sta::self.subsample]
        else:
            raise IOError('Wrong shape mask is given.')

        if self.boa.ndim == 3:
            flat_boa = self.boa[:,self.subsample_sta::self.subsample, \
                                  self.subsample_sta::self.subsample].reshape(self.boa.shape[0], -1)[..., flat_mask]
        elif self.boa.ndim == 2:
            flat_boa = self.boa[:,
                                self.subsample_sta::self.subsample][...,
                                                                    flat_mask]
        else:
            raise IOError('Wrong shape BOA is given.')

        if self.toa.ndim == 3:
            flat_toa     = self.toa[:,self.subsample_sta::self.subsample, \
                                      self.subsample_sta::self.subsample].reshape(self.toa.shape[0], -1)[..., flat_mask]
        elif self.toa.ndim == 2:
            flat_toa = self.toa[:,
                                self.subsample_sta::self.subsample][...,
                                                                    flat_mask]
        else:
            raise IOError('Wrong shape TOA is given.')
        if self.boa_unc.ndim == 3:
            flat_boa_unc = self.boa_unc[:,self.subsample_sta::self.subsample, \
                                          self.subsample_sta::self.subsample].reshape(self.toa.shape[0], -1)[..., flat_mask]
        elif self.boa_unc.ndim == 2:
            flat_boa_unc = self.boa_unc[:, self.subsample_sta::self.subsample][
                ..., flat_mask]
        else:
            raise IOError('Wrong shape BOA uncertainty is given.')

        if self.atmosphere is not None:
            if self.atmosphere.ndim == 3:
                flat_atmos = self.atmosphere[:, self.subsample_sta::self.subsample, \
                                                self.subsample_sta::self.subsample].reshape(3, -1)[..., flat_mask]
            elif self.atmosphere.ndim == 2:
                flat_atmos = self.atmosphere[:, self.subsample_sta::self.
                                             subsample][..., flat_mask]

            self.flat_atmos = flat_atmos
        else:
            flat_atmos = np.array([])
            self.flat_atmos = flat_atmos
        flat_angs_ele = []
        for i in [self.sza, self.vza, self.saa, self.vaa]:
            if isinstance(i, (float, int)):
                flat_angs_ele.append(i)
            elif i.ndim == 3:
                assert i.shape[0] == self.boa.shape[
                    0], 'check the shape of angles.'
                flat_i = i[:,self.subsample_sta::self.subsample, \
                      self.subsample_sta::self.subsample].reshape(i.shape[0], -1)[..., flat_mask]
            elif (i.ndim == 2) & (i.shape == self.boa.shape[1:]):
                flat_i = i[self.subsample_sta::self.subsample, \
                    self.subsample_sta::self.subsample].flatten()[flat_mask]
            elif (i.ndim == 2) & (i.shape != self.boa.shape[1:]):
                assert i.shape[0] == self.boa.shape[
                    0], 'check the shape of angles.'
                flat_i = i[:, self.subsample_sta::self.subsample][...,
                                                                  flat_mask]
            elif (i.ndim == 1) & (i.shape[0] == self.boa.shape[0]):
                flat_i = i
            else:
                raise IOError('Wrong shape angles is given.')
            flat_angs_ele.append([np.array(ang) for ang in \
             np.ones(flat_boa.shape)*flat_i]) # make sure the type dose not change...

        if isinstance(self.elevation, (float, int)):
            flat_angs_ele.append(self.elevation)

        elif self.elevation.ndim == 2:
            flat_ele  = self.elevation[self.subsample_sta::self.subsample, \
                                       self.subsample_sta::self.subsample].flatten()[flat_mask]
            flat_angs_ele.append(flat_ele)
        elif self.elevation.ndim == 1:
            flat_ele = self.elevation[self.subsample_sta::self.
                                      subsample][flat_mask]
            flat_angs_ele.append(flat_ele)

        ## for the prior
        if np.array(self.prior).ndim == 1:
            self.flat_prior = np.array(self.prior)
        elif np.array(self.prior).ndim == 2:
            assert self.prior.shape[1] == self.boa.shape[
                1], 'prior should have the same shape as the second axis of boa.'
            self.flat_prior = np.array(
                self.prior)[:, self.subsample_sta::self.subsample][...,
                                                                   flat_mask]
        elif np.array(self.prior).ndim == 3:
            assert self.prior.shape == self.boa.shape[
                1:], 'prior should have the same shape as the last two axises of boa.'
            self.flat_prior = self.prior[:, self.subsample_sta::self.subsample, \
                                            self.subsample_sta::self.subsample].reshape(3,-1)[..., flat_mask]

        return flat_mask, flat_boa, flat_toa, flat_boa_unc, flat_atmos, flat_angs_ele  # [sza, vza, saa, vaa, elevation]

    def obs_cost(self, is_full=False):

        flat_mask, flat_boa, flat_toa, flat_boa_unc, flat_atmos, [
            sza, vza, saa, vaa, elevation
        ] = self._sort_emus_inputs()
        for i in [
                flat_mask, flat_boa, flat_toa, flat_boa_unc, flat_atmos, sza,
                vza, saa, vaa, elevation
        ]:
            if np.array(i).size == 0:
                return 0., np.array(
                    self.flat_prior
                )  # any empty array result in earlier leaving the estimation
        H0, dH = self.AEE.emulator_reflectance_atmosphere(
            flat_boa,
            flat_atmos,
            sza,
            vza,
            saa,
            vaa,
            elevation,
            bands=self.band_indexs)
        H0, dH = np.array(H0), np.array(dH)
        diff = (H0 - flat_toa)  # order is important!
        correction_mask = np.isfinite(diff)
        # correction mask to set 0 or larger number?
        diff[~correction_mask] = 0.
        dH[~correction_mask, :] = 0.
        J = (0.5 * self.band_weights[..., None] * diff**2 /
             (self.band_weights[..., None].sum() * flat_boa_unc**2)).sum(
                 axis=(0, 1))
        full_dJ = [
            self.band_weights[..., None] * dH[:, :, i] * diff /
            (self.band_weights[..., None].sum() * flat_boa_unc**2)
            for i in xrange(4, 7)
        ]
        if is_full:
            J_ = np.array(full_dJ).sum(axis=(1, ))
        else:
            J_ = np.array(full_dJ).sum(axis=(1, 2))

        return J, J_

    def prior_cost(self, is_full=False):
        # maybe need to update to per pixel basis uncertainty
        # instead of using scaler values 0.5, 0.5, 0.001
        uncs = np.array([self.aot_unc, self.water_unc, self.ozone_unc])[...,
                                                                        None]
        if self.flat_atmos.size == 0:
            return 0., np.array([0., 0., 0.])
        if self.flat_prior.ndim == 1:
            J = 0.5 * (self.flat_atmos -
                       self.flat_prior[..., None])**2 / uncs**2
            full_dJ = (self.flat_atmos - self.flat_prior[..., None]) / uncs**2
        else:
            J = 0.5 * (self.flat_atmos - self.flat_prior)**2 / uncs**2
            full_dJ = (self.flat_atmos - self.flat_prior) / uncs**2
        if is_full:
            J_ = np.array(full_dJ)
        else:
            J_ = np.array(full_dJ).sum(axis=(1, ))

        J = np.array(J).sum()
        return J, J_

    def smooth_cost(self, ):
        '''
        need to add first order regulization
        '''
        J = 0
        J_ = np.array([0., 0., 0.])
        return J, J_

    def optimization(self, ):
        '''
        An optimization function used for the retrieval of atmospheric parameters
        '''
        p0 = self.prior
        #for _aod in np.arange(max(p0[0]-self.aot_unc, 0), min(p0[0]+self.aot_unc, 2), 0.1):
        #    p          = (_aod,) + self.prior[1:]
        #    self.prior = p
        psolve = optimize.fmin_l_bfgs_b(self.fmin_l_bfgs_cost, p0, approx_grad=0, iprint = -1, \
                                        pgtol=1e-6,factr=1000, bounds=self.bounds,fprime=None)
        #psolve2 = optimize.fmin(self.fmin_cost, p0, full_output=True, maxiter=100, maxfun=150, disp=0)
        return psolve  #, psolve2

    def fmin_l_bfgs_cost(self, p):

        self.atmosphere = np.array(
            [i * np.ones(self.toa.shape[1:]) for i in p])

        obs_J, obs_J_ = self.obs_cost()
        prior_J, prior_J_ = self.prior_cost()
        smooth_J, smooth_J_ = self.smooth_cost()

        J = obs_J + prior_J + smooth_J
        J_ = obs_J_ + prior_J_ + smooth_J_

        return J, J_

    def fmin_cost(self, p):

        self.atmosphere = np.array(
            [i * np.ones(self.toa.shape[1:]) for i in p])

        obs_J, obs_J_ = self.obs_cost()
        prior_J, prior_J_ = self.prior_cost()
        smooth_J, smooth_J_ = self.smooth_cost()

        J = obs_J + prior_J + smooth_J
        J_ = obs_J_ + prior_J_ + smooth_J_

        return J
示例#4
0
class atmo_cor(object):
    '''
    A class taking the toa, boa, initial [aot, water, ozone], [vza, sza, vaa, saa], elevation and emulators
    to do the atmospheric parameters retrival and do the atmopsheric correction.  
    '''
    def __init__(self,
                 sensor,
                 emus_dir,
                 boa,
                 toa,
                 atmosphere,
                 sza,
                 vza,
                 saa,
                 vaa,
                 elevation,
                 boa_qa,
                 boa_bands,
                 band_indexs,
                 mask,
                 prior,
                 subsample=None,
                 subsample_start=0,
                 gradient_refl=True,
                 bands=None):

        self.alpha = -1.42  #angstrom exponent for continental type aerosols
        self.sensor = sensor
        self.emus_dir = emus_dir
        self.boa, self.toa = boa, toa
        self.atmosphere = atmosphere
        self.sza, self.vza = sza, vza
        self.saa, self.vaa = saa, vaa
        self.elevation = elevation
        self.boa_qa = boa_qa
        self.boa_bands = boa_bands
        self.band_weights = (np.array(self.boa_bands) / 1000.)**self.alpha
        self.band_indexs = band_indexs
        self.mask = mask
        self.prior = prior
        if subsample is None:
            self.subsample = 1
        else:
            self.subsample = subsample
        self.subsample_sta = subsample_start

    def _load_emus(self):
        self.AEE = AtmosphericEmulationEngine(self.sensor, self.emus_dir)
        up_bounds = self.AEE.emulators[0].inputs[:, 4:7].max(axis=0)
        low_bounds = self.AEE.emulators[0].inputs[:, 4:7].min(axis=0)
        self.bounds = np.array([low_bounds, up_bounds]).T

    def _load_unc(self):
        uc = grab_uncertainty(self.boa, self.boa_bands, self.boa_qa)
        self.boa_unc = uc.get_boa_unc()
        self.aot_unc = uc.aot_unc
        self.water_unc = uc.water_unc
        self.ozone_unc = uc.ozone_unc

    def _sort_emus_inputs(self, ):

        assert self.boa.shape[
            -2:] == self.mask.shape, 'mask should have the same shape as the last two axises of boa.'
        assert self.boa.shape == self.toa.shape, 'toa and boa should have the same shape.'
        assert self.boa.shape == self.boa_unc.shape, 'boa and boa_unc should have the same shape.'
        assert self.atmosphere.shape[
            0] == 3, 'Three parameters, i.e. AOT, water and Ozone are needed.'
        assert self.boa.shape[-2:] == self.atmosphere.shape[
            -2:], 'boa and atmosphere should have the same shape in the last two axises.'
        # make the boa and toa to be the shape of nbands * nsample
        # and apply the flattened mask and subsample
        flat_mask = self.mask.flatten()[self.subsample_sta::self.subsample]
        flat_boa = self.boa.reshape(
            self.boa.shape[0],
            -1)[..., self.subsample_sta::self.subsample][..., flat_mask]
        flat_toa = self.toa.reshape(
            self.toa.shape[0],
            -1)[..., self.subsample_sta::self.subsample][..., flat_mask]
        flat_boa_unc = self.boa_unc.reshape(
            self.toa.shape[0],
            -1)[..., self.subsample_sta::self.subsample][..., flat_mask]
        flat_atmos = self.atmosphere.reshape(
            3, -1)[..., self.subsample_sta::self.subsample][..., flat_mask]
        flat_angs_ele = []
        for i in [self.sza, self.vza, self.saa, self.vaa, self.elevation]:
            if isinstance(i, (float, int)):
                flat_angs_ele.append(i)
            else:
                assert i.shape == self.boa.shape[
                    -2:], 'i should have the same shape as the last two axises of boa.'
                flat_i = i.flatten()[self.subsample_sta::self.
                                     subsample][flat_mask]
                flat_angs_ele.append(flat_i)
        ## for the prior
        if np.array(self.prior).ndim == 1:
            self.flat_prior = np.array(self.prior)
        else:
            assert self.prior.shape == self.boa.shape[
                -2:], 'prior should have the same shape as the last two axises of boa.'
            self.flat_prior = self.prior.reshape(
                3, -1)[..., self.subsample_sta::self.subsample][..., flat_mask]
        self.flat_atmos = flat_atmos

        return flat_mask, flat_boa, flat_toa, flat_boa_unc, flat_atmos, flat_angs_ele  # [sza, vza, saa, vaa, elevation]

    def obs_cost(self, is_full=False):

        flat_mask, flat_boa, flat_toa, flat_boa_unc, flat_atmos, [
            sza, vza, saa, vaa, elevation
        ] = self._sort_emus_inputs()
        H0, dH = self.AEE.emulator_reflectance_atmosphere(
            flat_boa,
            flat_atmos,
            sza,
            vza,
            saa,
            vaa,
            elevation,
            bands=self.band_indexs)
        H0, dH = np.array(H0), np.array(dH)
        diff = (flat_toa - H0
                )  #[..., None] dd an extra dimentiaon to match the dH
        correction_mask = np.isfinite(diff).all(axis=0)
        diff[:, ~correction_mask] = 0.
        dH[:, ~correction_mask, :] = 0.
        J = (0.5 * self.band_weights[..., None] * diff**2 /
             flat_boa_unc**2).sum(axis=(0, 1))
        full_dJ = [
            self.band_weights[..., None] * dH[:, :, i] * diff / flat_boa_unc**2
            for i in xrange(4, 7)
        ]
        if is_full:
            J_ = np.array(full_dJ).sum(axis=(1, ))
        else:
            J_ = np.array(full_dJ).sum(axis=(1, 2))

        return J, J_

    def prior_cost(self, is_full=False):
        # maybe need to update to per pixel basis uncertainty
        # instead of using scaler values 0.5, 0.5, 0.001
        uncs = np.array([self.aot_unc, self.water_unc, self.ozone_unc])[...,
                                                                        None]
        if self.flat_prior.ndim == 1:
            J = 0.5 * (self.flat_atmos -
                       self.flat_prior[..., None])**2 / uncs**2
            full_dJ = (self.flat_atmos - self.flat_prior[..., None]) / uncs**2
        else:
            J = 0.5 * (self.flat_atmos - self.flat_prior)**2 / uncs**2
            full_dJ = (self.flat_atmos - self.flat_prior) / uncs**2
        if is_full:
            J_ = np.array(full_dJ)
        else:
            J_ = np.array(full_dJ).sum(axis=(1, ))

        J = np.array(J).sum()
        return J, J_

    def smooth_cost(self, ):
        '''
        need to add first order regulization
        '''
        J = 0
        J_ = np.array([0, 0, 0])
        return J, J_

    def optimization(self, ):
        '''
        An optimization function used for the retrieval of atmospheric parameters
        '''
        p0 = 0.2, 3.4, 0.5
        psolve1 = optimize.fmin_l_bfgs_b(self.fmin_l_bfgs_cost,
                                         p0,
                                         approx_grad=0,
                                         iprint=1,
                                         bounds=self.bounds,
                                         fprime=None)
        psolve2 = optimize.fmin(self.fmin_cost,
                                p0,
                                full_output=True,
                                maxiter=100,
                                maxfun=150,
                                disp=0)
        return psolve1, psolve2

    def fmin_l_bfgs_cost(self, p):

        self.atmosphere = np.ones(self.toa.shape[-2:]) * np.array(p)[..., None,
                                                                     None]

        obs_J, obs_J_ = self.obs_cost()
        prior_J, prior_J_ = self.prior_cost()
        smooth_J, smooth_J_ = self.smooth_cost()

        J = obs_J + prior_J + smooth_J
        J_ = obs_J_ + prior_J_ + smooth_J_

        return J, J_

    def fmin_cost(self, p):

        self.atmosphere = np.ones(self.toa.shape[-2:]) * np.array(p)[..., None,
                                                                     None]

        obs_J, obs_J_ = self.obs_cost()
        prior_J, prior_J_ = self.prior_cost()
        smooth_J, smooth_J_ = self.smooth_cost()

        J = obs_J + prior_J + smooth_J
        J_ = obs_J_ + prior_J_ + smooth_J_

        return J
示例#5
0
 def _load_inverse_emus(self, sensor):
     AEE = AtmosphericEmulationEngine(sensor, self.emus_dir)
     return AEE