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))
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)))