# Image total flux with the bispectrum flux = np.sum(im.imvec) #out = mx.maxen_amp_cphase(obs, gaussprior, gaussprior, flux, maxit=50, alpha_clphase=1000, alpha_visamp=1000) out = mx.maxen_bs(obs, gaussprior, gaussprior, flux, maxit=25, alpha=5000) # Blur the image with a circular beam and image again to help convergance out = mx.blur_circ(out, res) out = mx.maxen_bs(obs, out, out, flux, maxit=100, alpha=500, entropy="tv") out = mx.blur_circ(out, res/2) out = mx.maxen_bs(obs, out, out, flux, maxit=100, alpha=100, entropy="tv") out = mx.blur_circ(out, res/2) out = mx.maxen_bs(obs, out, out, flux, maxit=100, alpha=50, entropy="tv") # Blur the final image with 1/2 the clean beam outblur = vb.blur_gauss(out, beamparams, 0.5) out.display() # Image Polarization # out = mx.maxen_m(obs, out, beta=100, maxit=250, polentropy="hw") # Save the images outname = "test" out.save_txt(outname + '.txt') out.save_fits(outname + '.fits') outblur.save_txt(outname + '_blur.txt') outblur.save_fits(outname + '_blur.fits')
def Scatter(Unscattered_Image, Epsilon_Screen=np.array([]), DisplayPhi=False, DisplayImage=False): #This module takes an unscattered image and Fourier components of the phase screen to produce a scattered image #Epsilon_Screen represents the normalized complex spectral values for the phase screen #Note: an odd image dimension is required # First some preliminary definitions wavelength = C/Unscattered_Image.rf*100.0 #Observing wavelength [cm] wavelengthbar = wavelength/(2.0*np.pi) #lambda/(2pi) [cm] D_dist = 8.023*10**21 #Observer-Scattering distance [cm] R_dist = 1.790*10**22 #Source-Scattering distance [cm] Mag = D_dist/R_dist r0_maj = (wavelength/0.13)**-1.0*3.134*10**8 #Phase coherence length [cm] r0_min = (wavelength/0.13)**-1.0*6.415*10**8 #Phase coherence length [cm] rF = (wavelength/0.13)**0.5*1.071*10**10 #Fresnel scale [cm] r_in = 1000*10**5 #inner scale [km] r_out = 10**20 #outer scale [km] scatt_alpha = 5.0/3.0 #power-law index FOV = Unscattered_Image.psize * Unscattered_Image.xdim * D_dist #Field of view, in cm, at the scattering screen def Q(qx, qy): #Power spectrum of phase fluctuations #x is aligned with the major axis; y is aligned with the minor axis qmin = 2.0*np.pi/r_out qmax = 2.0*np.pi/r_in #rotate qx and qy as needed PA = (90 - vb.POS_ANG) * np.pi/180.0 qx_rot = qx*np.cos(PA) + qy*np.sin(PA) qy_rot = -qx*np.sin(PA) + qy*np.cos(PA) return 2.0**scatt_alpha * np.pi * scatt_alpha * scipy.special.gamma(1.0 + scatt_alpha/2.0)/scipy.special.gamma(1.0 - scatt_alpha/2.0)*wavelengthbar**-2.0*(r0_maj*r0_min)**-(scatt_alpha/2.0) * ( (r0_maj/r0_min)*qx_rot**2.0 + (r0_min/r0_maj)*qy_rot**2.0 + qmin**2.0)**(-(scatt_alpha+2.0)/2.0) * np.exp(-((qx_rot**2.0 + qy_rot**2.0)/qmax**2.0)**0.5) #First we need to calculate the ensemble-average image by blurring the unscattered image with the correct kernel EA_Image = vb.blur_gauss(Unscattered_Image, vb.sgra_kernel_params(Unscattered_Image.rf), frac=1.0, frac_pol=0) if Epsilon_Screen.shape[0] == 0: return EA_Image else: Nx = Epsilon_Screen.shape[1] Ny = Epsilon_Screen.shape[0] #Next, we need the gradient of the ensemble-average image EA_Gradient = Wrapped_Gradient((EA_Image.imvec/(FOV/Nx)).reshape(EA_Image.ydim, EA_Image.xdim)) #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] #Now we'll calculate the phase screen gradient sqrtQ = np.zeros((Ny,Nx)) #just to get the dimensions correct dq = 2.0*np.pi/FOV #this is the spacing in wavenumber for x in range(0, Nx): for y in range(0, Ny): x2 = x y2 = y if x2 > (Nx-1)/2: x2 = x2 - Nx if y2 > (Ny-1)/2: y2 = y2 - Ny sqrtQ[y][x] = Q(dq*x2,dq*y2)**0.5 sqrtQ[0][0] = 0.0 #A DC offset doesn't affect scattering #We'll now calculate the phase screen. We could calculate the gradient directly, but this is more bulletproof for now phi = np.real(wavelengthbar/FOV*Epsilon_Screen.shape[0]*Epsilon_Screen.shape[1]*np.fft.ifft2( sqrtQ*Epsilon_Screen)) phi_Image = vb.Image(phi, EA_Image.psize, EA_Image.ra, EA_Image.dec, rf=EA_Image.rf, source=EA_Image.source, mjd=EA_Image.mjd) if DisplayPhi: phi_Image.display() #Next, we need the gradient of the ensemble-average image phi_Gradient = Wrapped_Gradient(phi/(FOV/Nx)) #The gradient signs don't actually matter, but let's make them match intuition (i.e., right to left, bottom to top) phi_Gradient_x = -phi_Gradient[1] phi_Gradient_y = -phi_Gradient[0] #Now we can patch together the average image AI = (EA_Image.imvec).reshape(Ny,Nx) + rF**2.0 * ( EA_Gradient_x*phi_Gradient_x + EA_Gradient_y*phi_Gradient_y ) #Optional: eliminate negative flux #AI = abs(AI) #Make it into a proper image format AI_Image = vb.Image(AI, EA_Image.psize, EA_Image.ra, EA_Image.dec, rf=EA_Image.rf, source=EA_Image.source, mjd=EA_Image.mjd) if DisplayImage: plot_scatt(Unscattered_Image.imvec, EA_Image.imvec, AI_Image.imvec, phi_Image.imvec, Unscattered_Image, 0, 0, ipynb=False) return AI_Image
beamparams = obs.fit_beam() res = 1 / np.max(obs.unpack('uvdist')['uvdist']) print beamparams print res out_cl = mx.maxen_onlyclosure(obs, gaussprior, flux = 1.0, maxit=50, alpha_clphase=10, alpha_clamp=10, gamma=500, delta=1e10, entropy="simple", stop=1e-15, grads=True) out_cl = mx.maxen_onlyclosure(obs, mx.blur_circ(out_cl, 1e-10), flux = 1.0, maxit=100, alpha_clphase=10, alpha_clamp=10, gamma=500, delta=1e10, entropy="tv", stop=1e-10, grads=True) out_cl = mx.maxen_onlyclosure(obs, mx.blur_circ(out_cl, 1e-10), flux = 1.0, maxit=100, alpha_clphase=5, alpha_clamp=5, gamma=500, delta=1e10, entropy="tv", stop=1e-10, grads=True) out_cl = mx.maxen_onlyclosure(obs, mx.blur_circ(out_cl, 1e-10), flux = 1.0, maxit=100, alpha_clphase=5, alpha_clamp=5, gamma=500, delta=1e10, entropy="tv", stop=1e-10, grads=True) out_cl = mx.maxen_onlyclosure(obs, mx.blur_circ(out_cl, 1e-10), flux = 1.0, maxit=100, alpha_clphase=5, alpha_clamp=5, gamma=500, delta=1e10, entropy="tv", stop=1e-10, grads=True) mx.blur_circ(out_cl, 0.5e-10).display() im.save_txt("Truth_MAD-Disk.txt") vb.blur_gauss(im, beamparams, 0.5, frac_pol=0).save_txt("Truth_MAD-Disk_halfCLEAN.txt") out_cl.save_txt("ClosureOnly_MAD-Disk_EHT2017wKP_wRedundant.txt") vb.blur_gauss(out_cl, beamparams, 0.5, frac_pol=0).save_txt("ClosureOnly_MAD-Disk_EHT2017wKP_wRedundant_halfCLEAN.txt") mx.blur_circ(out_cl, 0.5e-10).display() out_cl = mx.maxen_onlyclosure(obs, mx.blur_circ(out_cl, 1e-10), flux = 1.0, maxit=100, alpha_clphase=10, alpha_clamp=10, gamma=500, delta=500, entropy="simple", stop=1e-10)