Example #1
0
    def init_imager_scattering(self):
        if self.scattering_model == None:
            self.scattering_model = so.ScatteringModel()

        # First some preliminary definitions
        wavelength = C/self.obs_next.rf*100.0 #Observing wavelength [cm]
        wavelengthbar = wavelength/(2.0*np.pi) #lambda/(2pi) [cm]
        N = self.prior_next.xdim
        FOV = self.prior_next.psize * N * self.scattering_model.observer_screen_distance #Field of view, in cm, at the scattering screen


        # The ensemble-average convolution kernel and its gradients
        self._ea_ker = self.scattering_model.Ensemble_Average_Kernel(self.prior_next, wavelength_cm = wavelength)
        ea_ker_gradient = so.Wrapped_Gradient(self._ea_ker/(FOV/N))
        self._ea_ker_gradient_x = -ea_ker_gradient[1]
        self._ea_ker_gradient_y = -ea_ker_gradient[0]

        # The power spectrum (note: rotation is not currently implemented; the gradients would need to be modified slightly)
        self._sqrtQ = np.real(self.scattering_model.sqrtQ_Matrix(self.prior_next,t_hr=0.0))
Example #2
0
    def objgrad_scattering(self, minvec):
        """Current stochastic optics objective function gradient
        """
        wavelength = C / self.obs_next.rf * 100.0  #Observing wavelength [cm]
        wavelengthbar = wavelength / (2.0 * np.pi)  #lambda/(2pi) [cm]
        N = self.prior_next.xdim
        #Field of view, in cm, at the scattering screen
        FOV = self.prior_next.psize * N * self.scattering_model.observer_screen_distance
        rF = self.scattering_model.rF(wavelength)

        imvec = minvec[:N**2]
        EpsilonList = minvec[N**2:]
        if self.transform_next == 'log':
            imvec = np.exp(imvec)

        IM = ehtim.image.Image(imvec.reshape(N, N),
                               self.prior_next.psize,
                               self.prior_next.ra,
                               self.prior_next.dec,
                               rf=self.obs_next.rf,
                               source=self.prior_next.source,
                               mjd=self.prior_next.mjd)
        #the scattered image vector
        scatt_im = self.scattering_model.Scatter(
            IM,
            Epsilon_Screen=so.MakeEpsilonScreenFromList(EpsilonList, N),
            ea_ker=self._ea_ker,
            sqrtQ=self._sqrtQ,
            Linearized_Approximation=True).imvec

        EA_Image = self.scattering_model.Ensemble_Average_Blur(
            IM, ker=self._ea_ker)
        EA_Gradient = so.Wrapped_Gradient(
            (EA_Image.imvec / (FOV / N)).reshape(N, N))
        #The gradient signs don't actually matter, but let's make them match intuition (i.e., right to left, bottom to top)
        EA_Gradient_x = -EA_Gradient[1]
        EA_Gradient_y = -EA_Gradient[0]

        Epsilon_Screen = so.MakeEpsilonScreenFromList(EpsilonList, N)
        phi = self.scattering_model.MakePhaseScreen(
            Epsilon_Screen,
            IM,
            obs_frequency_Hz=self.obs_next.rf,
            sqrtQ_init=self._sqrtQ).imvec.reshape((N, N))
        phi_Gradient = so.Wrapped_Gradient(phi / (FOV / N))
        phi_Gradient_x = -phi_Gradient[1]
        phi_Gradient_y = -phi_Gradient[0]

        #Entropy gradient; wrt unscattered image so unchanged by scattering
        regterm = 0
        reg_term_dict = self.make_reggrad_dict(imvec)
        for regname in sorted(self.reg_term_next.keys()):
            regterm += self.reg_term_next[regname] * reg_term_dict[regname]

        # Chi^2 gradient wrt the unscattered image
        # First, the chi^2 gradient wrt to the scattered image
        datterm = 0.
        chi2_term_dict = self.make_chisqgrad_dict(scatt_im)
        for dname in sorted(self.dat_term_next.keys()):
            datterm += self.dat_term_next[dname] * (chi2_term_dict[dname] - 1.)
        dchisq_dIa = datterm.reshape((N, N))
        # Now the chain rule factor to get the chi^2 gradient wrt the unscattered image
        gx = (rF**2.0 * so.Wrapped_Convolve(
            self._ea_ker_gradient_x[::-1, ::-1], phi_Gradient_x *
            (dchisq_dIa))).flatten()
        gy = (rF**2.0 * so.Wrapped_Convolve(
            self._ea_ker_gradient_y[::-1, ::-1], phi_Gradient_y *
            (dchisq_dIa))).flatten()
        chisq_grad_im = so.Wrapped_Convolve(self._ea_ker[::-1, ::-1],
                                            (dchisq_dIa)).flatten() + gx + gy

        # Gradient of the data chi^2 wrt to the epsilon screen
        #Preliminary Definitions
        chisq_grad_epsilon = np.zeros(N**2 - 1)
        i_grad = 0
        ell_mat = np.zeros((N, N))
        m_mat = np.zeros((N, N))
        for ell in range(0, N):
            for m in range(0, N):
                ell_mat[ell, m] = ell
                m_mat[ell, m] = m

        #Real part; top row
        for t in range(1, (N + 1) / 2):
            s = 0
            grad_term = so.Wrapped_Gradient(
                wavelengthbar / FOV * self._sqrtQ[s][t] * 2.0 *
                np.cos(2.0 * np.pi / N *
                       (ell_mat * s + m_mat * t)) / (FOV / N))
            grad_term_x = -grad_term[1]
            grad_term_y = -grad_term[0]
            chisq_grad_epsilon[i_grad] = np.sum(
                dchisq_dIa * rF**2 *
                (EA_Gradient_x * grad_term_x + EA_Gradient_y * grad_term_y))
            i_grad = i_grad + 1

        #Real part; remainder
        for s in range(1, (N + 1) / 2):
            for t in range(N):
                grad_term = so.Wrapped_Gradient(
                    wavelengthbar / FOV * self._sqrtQ[s][t] * 2.0 *
                    np.cos(2.0 * np.pi / N *
                           (ell_mat * s + m_mat * t)) / (FOV / N))
                grad_term_x = -grad_term[1]
                grad_term_y = -grad_term[0]
                chisq_grad_epsilon[i_grad] = np.sum(
                    dchisq_dIa * rF**2 * (EA_Gradient_x * grad_term_x +
                                          EA_Gradient_y * grad_term_y))
                i_grad = i_grad + 1

        #Imaginary part; top row
        for t in range(1, (N + 1) / 2):
            s = 0
            grad_term = so.Wrapped_Gradient(
                -wavelengthbar / FOV * self._sqrtQ[s][t] * 2.0 *
                np.sin(2.0 * np.pi / N *
                       (ell_mat * s + m_mat * t)) / (FOV / N))
            grad_term_x = -grad_term[1]
            grad_term_y = -grad_term[0]
            chisq_grad_epsilon[i_grad] = np.sum(
                dchisq_dIa * rF**2 *
                (EA_Gradient_x * grad_term_x + EA_Gradient_y * grad_term_y))
            i_grad = i_grad + 1

        #Imaginary part; remainder
        for s in range(1, (N + 1) / 2):
            for t in range(N):
                grad_term = so.Wrapped_Gradient(
                    -wavelengthbar / FOV * self._sqrtQ[s][t] * 2.0 *
                    np.sin(2.0 * np.pi / N *
                           (ell_mat * s + m_mat * t)) / (FOV / N))
                grad_term_x = -grad_term[1]
                grad_term_y = -grad_term[0]
                chisq_grad_epsilon[i_grad] = np.sum(
                    dchisq_dIa * rF**2 * (EA_Gradient_x * grad_term_x +
                                          EA_Gradient_y * grad_term_y))
                i_grad = i_grad + 1

        # Gradient of the chi^2 regularization term for the epsilon screen
        chisq_epsilon_grad = self.alpha_phi_next * 2.0 * EpsilonList / (
            (N * N - 1) / 2.0)

        # chain rule term for change of variables
        if self.transform_next == 'log':
            regterm *= imvec
            chisq_grad_im *= imvec

        return np.concatenate(((regterm + chisq_grad_im),
                               (chisq_grad_epsilon + chisq_epsilon_grad)))