def temporal_smearing(self, lobs, zsource, cosmo=None): """ Temporal smearing due to turbulent scattering Parameters ---------- lobs : Quantity Observed wavelength zsource : float cosmo : astropy.cosmology, optional Returns ------- tau : Quantity temporal broadening """ # Cosmology if cosmo is None: from astropy.cosmology import Planck15 as cosmo D_S = cosmo.angular_diameter_distance(zsource) D_L = cosmo.angular_diameter_distance(self.zL) D_LS = cosmo.angular_diameter_distance_z1z2(self.zL, zsource) # Angular theta = self.angular_broadening(lobs, zsource, cosmo=cosmo) # Calculate tau = D_L * D_S * (theta.to('radian').value)**2 / D_LS / const.c / ( 1 + self.zL) # Return return tau.to('ms')
def cal_einstein_radius_in_arcsec(z_l,z_s,sigma): #b_sie = 4*pi * sigma^2/c^2 * D_ls/D_s c = const.c.value / 1000 #to km/s v_fac = (sigma/c)**2 d_fac = cosmo.angular_diameter_distance_z1z2(z_l, z_s).value/cosmo.angular_diameter_distance(z_s).value radian_to_arcsec = 180.0/np.pi*60*60 return 4.0*np.pi*v_fac*d_fac*radian_to_arcsec
def update(val): zL,zS = slzL.val,slzS.val xL,yL = slxL.val, slyL.val ML,eL,PAL = slML.val,sleL.val,slPAL.val sh,sha = slss.val,slsa.val xs,ys = slxs.val, slys.val Fs,ws = slFs.val, slws.val ns,ars,pas = slns.val,slars.val,slPAs.val newDd = cosmo.angular_diameter_distance(zL).value newDs = cosmo.angular_diameter_distance(zS).value newDds= cosmo.angular_diameter_distance_z1z2(zL,zS).value newLens = vl.SIELens(zLens,xL,yL,10**ML,eL,PAL) newShear = vl.ExternalShear(sh,sha) newSource = vl.SersicSource(zS,True,xs,ys,Fs,ws,ns,ars,pas) xs,ys = vl.LensRayTrace(xim,yim,[newLens,newShear],newDd,newDs,newDds) imbg = vl.SourceProfile(xim,yim,newSource,[newLens,newShear]) imlensed = vl.SourceProfile(xs,ys,newSource,[newLens,newShear]) caustics = vl.CausticsSIE(newLens,newDd,newDs,newDds,newShear) ax.cla() ax.imshow(imbg,cmap=cmbg,extent=[xim.min(),xim.max(),yim.min(),yim.max()],origin='lower') ax.imshow(imlensed,cmap=cmlens,extent=[xim.min(),xim.max(),yim.min(),yim.max()],origin='lower') mu = imlensed.sum()*(xim[0,1]-xim[0,0])**2 / newSource.flux['value'] ax.text(0.9,1.02,'$\\mu$ = {0:.2f}'.format(mu),transform=ax.transAxes) #for i in range(caustics.shape[0]): # ax.plot(caustics[i,0,:],caustics[i,1,:],'k-') for caustic in caustics: ax.plot(caustic[:,0],caustic[:,1],'k-') f.canvas.draw_idle()
def create_modelimage(lens,source,xmap,ymap,xemit,yemit,indices, Dd=None,Ds=None,Dds=None,sourcedatamap=None): """ Creates a model lensed image given the objects and map coordinates specified. Supposed to be common for both image fitting and visibility fitting, so we don't need any data here. Returns: immap A 2D array representing the field evaluated at xmap,ymap with all sources included. mus: A numpy array of length N_sources containing the magnifications of each source (1 if unlensed). """ lens = list(np.array([lens]).flatten()) # Ensure lens(es) are a list source = list(np.array([source]).flatten()) # Ensure source(s) are a list mus = np.zeros(len(source)) immap, imsrc = np.zeros(xmap.shape), np.zeros(xemit.shape) # If we didn't get pre-calculated distances, figure them here assuming Planck15 if np.any((Dd is None,Ds is None, Dds is None)): from astropy.cosmology import Planck15 as cosmo Dd = cosmo.angular_diameter_distance(lens[0].z).value Ds = cosmo.angular_diameter_distance(source[0].z).value Dds= cosmo.angular_diameter_distance_z1z2(lens[0].z,source[0].z).value # Do the raytracing for this set of lens & shear params xsrc,ysrc = LensRayTrace(xemit,yemit,lens,Dd,Ds,Dds) if sourcedatamap is not None: # ... then particular source(s) are specified for this map for jsrc in sourcedatamap: if source[jsrc].lensed: ims = SourceProfile(xsrc,ysrc,source[jsrc],lens) imsrc += ims mus[jsrc] = ims.sum()*(xemit[0,1]-xemit[0,0])**2./source[jsrc].flux['value'] else: immap += SourceProfile(xmap,ymap,source[jsrc],lens); mus[jsrc] = 1. else: # Assume we put all sources in this map/field for j,src in enumerate(source): if src.lensed: ims = SourceProfile(xsrc,ysrc,src,lens) imsrc += ims mus[j] = ims.sum()*(xemit[0,1]-xemit[0,0])**2./src.flux['value'] else: immap += SourceProfile(xmap,ymap,src,lens); mus[j] = 1. # Try to reproduce matlab's antialiasing thing; this uses a 3lobe lanczos low-pass filter imsrc = Image.fromarray(imsrc) resize = np.array(imsrc.resize((int(indices[1]-indices[0]),int(indices[3]-indices[2])),Image.ANTIALIAS)) immap[indices[2]:indices[3],indices[0]:indices[1]] += resize # Flip image to match sky coords (so coordinate convention is +y = N, +x = W, angle is deg E of N) immap = immap[::-1,:] # last, correct for pixel size. immap *= (xmap[0,1]-xmap[0,0])**2. return immap,mus
def update(val): zL, zS = slzL.val, slzS.val xL, yL = slxL.val, slyL.val ML, eL, PAL = slML.val, sleL.val, slPAL.val sh, sha = slss.val, slsa.val xs, ys = slxs.val, slys.val Fs, ws = slFs.val, slws.val ns, ars, pas = slns.val, slars.val, slPAs.val newDd = cosmo.angular_diameter_distance(zL).value newDs = cosmo.angular_diameter_distance(zS).value newDds = cosmo.angular_diameter_distance_z1z2(zL, zS).value newLens = vl.SIELens(zLens, xL, yL, 10**ML, eL, PAL) newShear = vl.ExternalShear(sh, sha) newSource = vl.SersicSource(zS, True, xs, ys, Fs, ws, ns, ars, pas) xs, ys = vl.LensRayTrace(xim, yim, [newLens, newShear], newDd, newDs, newDds) imbg = vl.SourceProfile(xim, yim, newSource, [newLens, newShear]) imlensed = vl.SourceProfile(xs, ys, newSource, [newLens, newShear]) caustics = vl.CausticsSIE(newLens, newDd, newDs, newDds, newShear) ax.cla() ax.imshow(imbg, cmap=cmbg, extent=[xim.min(), xim.max(), yim.min(), yim.max()], origin='lower') ax.imshow(imlensed, cmap=cmlens, extent=[xim.min(), xim.max(), yim.min(), yim.max()], origin='lower') mu = imlensed.sum() * (xim[0, 1] - xim[0, 0])**2 / newSource.flux['value'] ax.text(0.9, 1.02, '$\\mu$ = {0:.2f}'.format(mu), transform=ax.transAxes) #for i in range(caustics.shape[0]): # ax.plot(caustics[i,0,:],caustics[i,1,:],'k-') for caustic in caustics: ax.plot(caustic[:, 0], caustic[:, 1], 'k-') f.canvas.draw_idle()
def update(val): zL,zS = slzL.val,slzS.val xL,yL = slxL.val, slyL.val ML,eL,PAL = slML.val,sleL.val,slPAL.val sh,sha = slss.val,slsa.val newDd = cosmo.angular_diameter_distance(zL).value newDs = cosmo.angular_diameter_distance(zS).value newDds= cosmo.angular_diameter_distance_z1z2(zL,zS).value newLens = vl.SIELens(zLens,xL,yL,10**ML,eL,PAL) newShear = vl.ExternalShear(sh,sha) xsource,ysource = vl.LensRayTrace(xim,yim,[newLens,newShear],newDd,newDs,newDds) caustics = vl.get_caustics([newLens,newShear],newDd,newDs,newDds) ax.cla() ax.plot(xsource,ysource,'b-') for caustic in caustics: ax.plot(caustic[:,0],caustic[:,1],'k-') #ax.set_xlim(-0.5,0.5) #ax.set_ylim(-0.5,0.5) #for i in range(len(xs)): # p[i].set_xdata(xs[i]) # p[i].set_ydata(ys[i]) f.canvas.draw_idle()
def angular_broadening(self, lobs, zsource, cosmo=None): """ Broadening of a point source due to turbulent scattering Parameters ---------- lobs : Quantity Observed wavelength zsource : float Redshift of radio source Returns ------- theta : Quantity Angular broadening. Radius (half-width at half-max) """ if self.regime == 0: raise ValueError("Need to set rdiff and the regime first!") if cosmo is None: from astropy.cosmology import Planck15 as cosmo # f if (self.regime == 1) or np.isclose(self.beta, 4.): f = 1.18 elif (self.regime == 2) and np.isclose(self.beta, 11 / 3.): f = 1.01 # Distances D_S = cosmo.angular_diameter_distance(zsource) D_LS = cosmo.angular_diameter_distance_z1z2(self.zL, zsource) if self.verbose: print("D_LS={}, D_S={}".format(D_LS, D_S)) D_LS_D_S = D_LS / D_S # Evaluate k = 2 * np.pi / (lobs / (1 + self.zL) ) # Are we sure about this (1+z) factor?! self.theta = f * D_LS_D_S / (k * self.rdiff) * u.radian return self.theta.to('arcsec')
xim, yim = np.meshgrid(xim, yim) zLens, zSource = 0.8, 5.656 xLens, yLens = 0., 0. MLens, eLens, PALens = 2.87e11, 0.5, 70. xSource, ySource, FSource = 0.216, 0.24, 0.02 # arcsec, arcsec, Jy aSource, nSource, arSource, PAsource = 0.1, 0.5, 1.0, 120. - 90 # arcsec,[],[],deg CCW from x-axis shear, shearangle = 0.12, 120. Lens = vl.SIELens(zLens, xLens, yLens, MLens, eLens, PALens) Shear = vl.ExternalShear(shear, shearangle) Source = vl.SersicSource(zSource, True, xSource, ySource, FSource, aSource, nSource, arSource, PAsource) Dd = cosmo.angular_diameter_distance(zLens).value Ds = cosmo.angular_diameter_distance(zSource).value Dds = cosmo.angular_diameter_distance_z1z2(zLens, zSource).value xsource, ysource = vl.LensRayTrace(xim, yim, [Lens, Shear], Dd, Ds, Dds) imbg = vl.SourceProfile(xim, yim, Source, [Lens, Shear]) imlensed = vl.SourceProfile(xsource, ysource, Source, [Lens, Shear]) caustics = vl.CausticsSIE(Lens, Dd, Ds, Dds, Shear) f = pl.figure(figsize=(12, 6)) ax = f.add_subplot(111, aspect='equal') pl.subplots_adjust(right=0.48, top=0.97, bottom=0.03, left=0.05) cmbg = cm.cool cmbg._init() cmbg._lut[0, -1] = 0.
def lens_efficiency(z_lens, z_src): """Calculates the efficiency of the lensing system given source and lens redshifts.""" dist_lens_source = cosmo.angular_diameter_distance_z1z2(z_lens, z_src).value dist_observer_source = cosmo.angular_diameter_distance(z_src).value return dist_lens_source / dist_observer_source
def __init__( self, mag_zero=25.5, mag_iso=22.5, exposure=1610.0, fwhm_psf=0.18, pixel_size=0.1, n_xy=64, f_sub=0.05, beta=-1.9, m_min_calib=1e6 * M_s, m_max_sub_div_M_hst_calib=0.01, m_200_min_sub=1e7 * M_s, m_200_max_sub_div_M_hst=0.01, M_200_sigma_v_scatter=False, params_eval=None, calculate_joint_score=False, calculate_msub_derivatives=False, calculate_sub_residuals=False, draw_host_mass=True, draw_host_redshift=True, draw_alignment=True, roi_size=2., ): """ Class to simulation an observation strong lensing image, with substructure sprinkled in. :param mag_zero: Zero-point magnitude of observation :param mag_iso: Magnitude of isotropic sky brightness :param exposure: Exposure time of observation, in seconds (including gain) :param fwhm_psf: FWHM of Gaussian PSF, in arcsecs :param pixel_size: Pixel side size, in arcsecs :param n_xy: Number of pixels (along x and y) of observation :param f_sub: Fraction of total contained mass in substructure :param beta: Slope in the subhaalo mass function :param m_min_calib: Minimum mass above which subhalo mass fraction is `f_sub` :param m_max_sub_div_M_hst_calib: Maximum mass below which subhalo mass fraction is `f_sub`, in units of the host halo mass :param m_200_min_sub: Lowest mass of subhalos to draw :param m_200_max_sub_div_M_hst: Maximum mass of subhalos to draw, in units of host halo mass :param M_200_sigma_v_scatter: Whether to apply lognormal scatter in sigma_v to M_200_host mapping :param params_eval: Parameters (f_sub, beta) for which p(x,z|params) will be calculated :param calculate_joint_score: Whether grad_params log p(x,z|params) will be calculated :param calculate_msub_derivatives: Whether to calculate derivatives of image wrt subhalos masses :param calculate_residuals: Whether to calculate residual images wrt subhalos """ # beta = -2.0 is forbidden! if np.abs((beta + 2.)) < 1.e-3: beta = -2.001 # Store input self.mag_zero = mag_zero self.mag_iso = mag_iso self.exposure = exposure self.fwhm_psf = fwhm_psf self.pixel_size = pixel_size self.n_xy = n_xy self.f_sub = f_sub self.beta = beta self.m_min_calib = m_min_calib self.m_max_sub_div_M_hst_calib = m_max_sub_div_M_hst_calib self.m_200_min_sub = m_200_min_sub self.m_200_max_sub_div_M_hst = m_200_max_sub_div_M_hst self.M_200_sigma_v_scatter = M_200_sigma_v_scatter self.params_eval = params_eval self.calculate_joint_score = calculate_joint_score self.draw_host_mass = draw_host_mass self.draw_host_redshift = draw_host_redshift self.draw_alignment = draw_alignment self.coordinate_limit = pixel_size * n_xy / 2.0 # Draw lens properties consistent with Collett et al [1507.02657] # Clip lens redshift `z_l` to be less than 1; high-redshift lenses no good for our purposes! if self.draw_host_redshift: self.z_l = 2.0 while self.z_l > 1.0: self.z_l = 10 ** np.random.normal(-0.25, 0.25) else: self.z_l = 10.0 ** -0.25 if self.draw_host_mass: self.sigma_v = np.random.normal(225, 50) else: self.sigma_v = 225.0 if self.draw_alignment: self.theta_x_0 = np.random.normal(0, 0.2) self.theta_y_0 = np.random.normal(0, 0.2) else: self.theta_x_0 = 0.0 self.theta_y_0 = 0.0 q = 1 # For now, hard-code host to be spherical # Fix the source properties to reasonable mean-ish values self.theta_s_e = 0.2 self.z_s = 1.5 self.mag_s = 23.0 # Get relevant distances self.D_l = Planck15.angular_diameter_distance(z=self.z_l).value * Mpc D_s = Planck15.angular_diameter_distance(z=self.z_s).value * Mpc D_ls = Planck15.angular_diameter_distance_z1z2(z1=self.z_l, z2=self.z_s).value * Mpc # Get properties for NFW host DM halo if draw_host_mass: self.M_200_hst = self.M_200_sigma_v(self.sigma_v * Kmps, scatter=M_200_sigma_v_scatter) else: self.M_200_hst = self.M_200_sigma_v(self.sigma_v * Kmps, scatter=0.0) c_200_hst = MassProfileNFW.c_200_SCP(self.M_200_hst) r_s_hst, rho_s_hst = MassProfileNFW.get_r_s_rho_s_NFW(self.M_200_hst, c_200_hst) # Get properties for SIE host self.theta_E = MassProfileSIE.theta_E(self.sigma_v * Kmps, D_ls, D_s) # Don't consider configuration with subhalo fraction > 1! self.f_sub_realiz = 2.0 while self.f_sub_realiz > 1.0: # Generate a subhalo population... ps = SubhaloPopulation( f_sub=f_sub, beta=beta, M_hst=self.M_200_hst, c_hst=c_200_hst, m_min=m_200_min_sub, m_max=m_200_max_sub_div_M_hst * self.M_200_hst, m_min_calib=m_min_calib, m_max_calib=m_max_sub_div_M_hst_calib * self.M_200_hst, theta_s=r_s_hst / self.D_l, theta_roi=roi_size * self.theta_E, theta_E=self.theta_E, params_eval=params_eval, calculate_joint_score=calculate_joint_score, ) # ... and grab its properties self.m_subs = ps.m_sample self.n_sub_roi = ps.n_sub_roi self.theta_xs = ps.theta_x_sample self.theta_ys = ps.theta_y_sample self.f_sub_realiz = ps.f_sub_realiz self.n_sub_in_ring = ps.n_sub_in_ring self.f_sub_in_ring = ps.f_sub_in_ring self.n_sub_near_ring = ps.n_sub_near_ring self.f_sub_near_ring = ps.f_sub_near_ring # Convert magnitude for source and isotropic component to expected counts self.S_tot = self._mag_to_flux(self.mag_s, self.mag_zero) self.f_iso = self._mag_to_flux(self.mag_iso, self.mag_zero) # Set host properties. Host assumed to be at the center of the image. self.hst_param_dict = {"profile": "SIE", "theta_x_0": 0.0, "theta_y_0": 0.0, "theta_E": self.theta_E, "q": q} lens_list = [self.hst_param_dict] # Set subhalo properties for i_sub, (m, theta_x, theta_y) in enumerate(zip(self.m_subs, self.theta_xs, self.theta_ys)): c = MassProfileNFW.c_200_SCP(m) r_s, rho_s = MassProfileNFW.get_r_s_rho_s_NFW(m, c) sub_param_dict = {"profile": "NFW", "theta_x_0": theta_x, "theta_y_0": theta_y, "M_200": m, "r_s": r_s, "rho_s": rho_s} lens_list.append(sub_param_dict) # Set source properties src_param_dict = {"profile": "Sersic", "theta_x_0": self.theta_x_0, "theta_y_0": self.theta_y_0, "S_tot": self.S_tot, "theta_e": self.theta_s_e, "n_srsc": 1} # Set observation and global properties observation_dict = { "n_x": n_xy, "n_y": n_xy, "theta_x_lims": (-self.coordinate_limit, self.coordinate_limit), "theta_y_lims": (-self.coordinate_limit, self.coordinate_limit), "exposure": exposure, "f_iso": self.f_iso, } global_dict = {"z_s": self.z_s, "z_l": self.z_l} # Inititalize lensing class and produce lensed image lsi = LensingSim(lens_list, [src_param_dict], global_dict, observation_dict) self.image = lsi.lensed_image() self.image_poiss = np.random.poisson(self.image) # Poisson fluctuate self.image_poiss_psf = self._convolve_psf(self.image_poiss, fwhm_psf, pixel_size) # Convolve with PSF # Augmented data self.joint_log_probs = ps.joint_log_probs self.joint_scores = ps.joint_scores # Optionally, compute derivatives of image wrt each subahlo mass (takes ~1s/subhalo) if calculate_msub_derivatives: self._calculate_derivs() # Optionally, compute derivatives of image wrt each subahlo mass (takes ~1s/subhalo) if calculate_sub_residuals: self._calculate_residuals()
def monte_tau(zeval, nrand=100, nHI=0.1, avg_ne=-2.6, sigma_ne=0.5, cosmo=None, lobs=50*u.cm, turb=None): """ Generate random draws of tau at a series of redshifts Parameters ---------- zeval : ndarray Array of redshifts for evaluation nrand : int, optional Number of samples on NHI avg_ne : float, optional Average log10 electron density / cm**3 sigma_ne : float, optional Error in log10 ne nHI : float, optional Fiducial value for n_HI; used for DL value lobs : Quantity Wavelength for analysis turb : Turbulence object, optional Usually defined internally and that is the highly recommended approach cosmo : astropy.cosmology, optional Defaults to Planck15 Returns ------- rand_tau : ndarray (nrand, nz) Random tau values reported in ms (but without explicit astropy Units) """ # Init ne_param = dict(value=avg_ne, sigma=sigma_ne) # Neeleman+15 dla_fits = load_dla_fits() if cosmo is None: from astropy.cosmology import Planck15 as cosmo # Setup NHI lgNmax = np.linspace(20.3, 22., 10000) intfN = _int_dbl_pow(dla_fits['fN']['dpow'], lgNmax=lgNmax) # Spline interp_fN = interp1d(intfN/intfN[-1], lgNmax)#, kind='cubic') # Setup z zvals = np.linspace(0., 7., 10000) nz_s = _dla_nz(zvals) nz_s[0] = 0. # Turbulence if turb is None: turb = _init_dla_turb() f_ne=turb.ne zsource = 2. turb.set_rdiff(lobs) fiducial_tau = turb.temporal_smearing(lobs, zsource) # Take out the cosmology f_D_S = cosmo.angular_diameter_distance(zsource) f_D_L = cosmo.angular_diameter_distance(turb.zL) f_D_LS = cosmo.angular_diameter_distance_z1z2(turb.zL, zsource) fiducial_tau = fiducial_tau / f_D_LS / f_D_L * f_D_S * (1+turb.zL)**3 # ms/Mpc kpc_cm = (1*u.kpc).to('cm').value rand_tau = np.zeros((nrand, zeval.size)) # Loop on zeval for ss,izeval in enumerate(zeval): avg_nz = _dla_nz(izeval) rn = np.random.poisson(avg_nz, size=nrand) ndla = np.sum(rn) if ndla == 0: continue # Get random NHI rval = np.random.uniform(size=ndla) rNHI = interp_fN(rval) DL = 10.**rNHI / nHI / kpc_cm # Get random z imin = np.argmin(np.abs(zvals-izeval)) interp_z = interp1d(nz_s[0:imin]/nz_s[imin-1], zvals[0:imin])#, kind='cubic') rval = np.random.uniform(size=ndla) rz = interp_z(rval) # Cosmology D_S = cosmo.angular_diameter_distance(izeval) D_L = cosmo.angular_diameter_distance(rz) D_LS = cosmo.angular_diameter_distance_z1z2(rz, izeval) # Get random n_e rne = 10.**(ne_param['value'] + ne_param['sigma']*np.random.normal(size=ndla)) # Calculate (scale) rtau = fiducial_tau * (D_LS * D_L / D_S) * (rne/f_ne.to('cm**-3').value)**2 / (1+rz)**3 # Generate, fill taus = np.zeros((nrand, np.max(rn))) kk = 0 for jj,irn in enumerate(rn): if irn > 0: taus[jj,0:irn] = rtau[kk:kk+irn] kk += irn # Finish -- add in quadrature final_tau = np.sqrt(np.sum(taus**2, axis=1)) # Save rand_tau[:,ss] = final_tau # Return return rand_tau
yim = np.arange(-3,3,.03) xim,yim = np.meshgrid(xim,yim) zLens,zSource = 0.8,5.656 xLens,yLens = 0.,0. MLens,eLens,PALens = 2.87e11,0.5,90. xSource,ySource,FSource,sSource = 0.216,-0.24,0.023,0.074 Lens = vl.SIELens(zLens,xLens,yLens,MLens,eLens,PALens) Shear= vl.ExternalShear(0.,0.) lens = [Lens,Shear] Source = vl.GaussSource(zSource,True,xSource,ySource,FSource,sSource) Dd = cosmo.angular_diameter_distance(zLens).value Ds = cosmo.angular_diameter_distance(zSource).value Dds = cosmo.angular_diameter_distance_z1z2(zLens,zSource).value caustics = vl.get_caustics(lens,Dd,Ds,Dds) xsource,ysource = vl.LensRayTrace(xim,yim,lens,Dd,Ds,Dds) f = pl.figure() ax = f.add_subplot(111,aspect='equal') pl.subplots_adjust(bottom=0.25,top=0.98) ax.plot(xsource,ysource,'b-') for caustic in caustics: ax.plot(caustic[:,0],caustic[:,1],'k-') # Put in a bunch of sliders to control lensing parameters
def plot_images(data, mcmcresult, returnimages=False, plotcombined=False, plotall=False, imsize=256, pixsize=0.2, taper=0., **kwargs): """ Create a five-panel figure from data and chains, showing data, best-fit model, residuals, high-res image, source plane Inputs: data: The visdata object(s) to be imaged. If more than one is passed, they'll be imaged/differenced separately. chains: A result from running LensModelMCMC. returnimages: bool, optional If True, will also return a list of numpy arrays containing the imaged data, interpolated model, and full-res model. Default is False. plotcombined: bool, optional, default False If True, plots only a single row of images, after combining all datasets in `data' and applying any necessary rescaling/shifting contained in `mcmcresult'. plotall: bool, optional, default False If True, plots each dataset in its own row *and* the combined dataset in an extra row. Returns: If returnimages is False: f, axarr: A matplotlib figure and array of Axes objects. If returnimages is True: f,axarr,imagelist: Same as above; imagelist is a list of length (# of datasets), containing four arrays each, representing the data, interpolated model, full-resolution model, and source plane. """ limits = kwargs.pop('limits', [ -imsize * pixsize / 2., +imsize * pixsize / 2., -imsize * pixsize / 2., +imsize * pixsize / 2. ]) cmap = kwargs.pop('cmap', cm.Greys) mapcontours = kwargs.pop('mapcontours', np.delete(np.arange(-21, 22, 3), 7)) rescontours = kwargs.pop('rescontours', np.array([-6, -5, -4, -3, -2, 2, 3, 4, 5, 6])) level = kwargs.pop('level', None) logmodel = kwargs.pop('logmodel', False) datasets = list(np.array([data]).flatten()) # shorthand for later c = copy.deepcopy(mcmcresult['chains']) # Now all these things are saved separately, don't have to do the BS above lens = mcmcresult['best-fit']['lens'] source = mcmcresult['best-fit']['source'] scaleamp = mcmcresult['best-fit']['scaleamp'] if 'scaleamp' in mcmcresult[ 'best-fit'].keys() else np.ones(len(datasets)) shiftphase = mcmcresult['best-fit'][ 'shiftphase'] if 'shiftphase' in mcmcresult['best-fit'].keys( ) else np.zeros((len(datasets), 2)) sourcedatamap = mcmcresult[ 'sourcedatamap'] if 'sourcedatamap' in mcmcresult.keys( ) else [None] * len(datasets) modelcal = mcmcresult['modelcal'] if 'modelcal' in mcmcresult.keys( ) else [False] * len(datasets) if plotall: f, axarr = plt.subplots(len(datasets) + 1, 5, figsize=(14, 4 * (len(datasets) + 1))) axarr = np.atleast_2d(axarr) images = [[] for _ in range(len(datasets) + 1)] if sourcedatamap[0] is not None: warnings.warn( "sourcedatamap[0] is not None. Are you sure you want plotall=True?" ) sourcedatamap.append(None) f.subplots_adjust(left=0.05, bottom=0.05, top=0.95, right=0.99) elif plotcombined: f, axarr = plt.subplots(1, 5, figsize=(14, 4)) axarr = np.atleast_2d(axarr) images = [[]] if sourcedatamap[0] is not None: warnings.warn( "sourcedatamap[0] is not None, and has been set to None. Are you sure you want plotcombined=True? This could break the source plane plot." ) sourcedatamap = [None] f.subplots_adjust(left=0.05, bottom=0.05, top=0.95, right=0.99) else: f, axarr = plt.subplots(len(datasets), 5, figsize=(14, 4 * len(datasets))) axarr = np.atleast_2d(axarr) images = [[] for _ in range(len(datasets))] # effing mutable lists. f.subplots_adjust(left=0.05, bottom=0.05, top=0.95, right=0.99) plotdata, plotinterp = [], [] for i, dset in enumerate(datasets): # Get us some coordinates. xmap,ymap,xemit,yemit,ix = GenerateLensingGrid(datasets,mcmcresult['xmax'],\ mcmcresult['highresbox'],mcmcresult['fieldres'],mcmcresult['emitres']) # Create model image immap,_ = create_modelimage(lens,source,xmap,ymap,xemit,yemit,\ ix,sourcedatamap=sourcedatamap[i]) # And interpolate onto uv-coords of dataset interpdata = fft_interpolate(dset,immap,xmap,ymap,ug=None,\ scaleamp=scaleamp[i],shiftphase=shiftphase[i]) if modelcal[i]: selfcal, _ = model_cal(dset, interpdata) else: selfcal = copy.deepcopy(dset) plotdata.append(selfcal) plotinterp.append(interpdata) if plotall: plotdata.append(concatvis(plotdata)) plotinterp.append(concatvis(plotinterp)) elif plotcombined: plotdata = [concatvis(plotdata)] plotinterp = [concatvis(plotinterp)] for row in range(axarr.shape[0]): # Image the data imdata = uvimageslow(plotdata[row], imsize, pixsize, taper) # Image the model immodel = uvimageslow(plotinterp[row], imsize, pixsize, taper) # And the residuals imdiff = imdata - immodel if returnimages: images[row].append(imdata) images[row].append(immodel) # Plot everything up ext = [ -imsize * pixsize / 2., imsize * pixsize / 2., -imsize * pixsize / 2., imsize * pixsize / 2. ] # Figure out what to use as the noise level; sum of weights if no user-supplied value if level is None: s = ((plotdata[row].sigma**-2.).sum())**-0.5 else: try: s = [e for e in level][i] except TypeError: s = float(level) print("Data - Model rms: {0:0.3e}".format(imdiff.std())) axarr[row, 0].imshow(imdata, interpolation='nearest', extent=ext, cmap=cmap) axarr[row, 0].contour(imdata, extent=ext, colors='k', origin='image', levels=s * mapcontours) axarr[row, 0].set_xlim(limits[0], limits[1]) axarr[row, 0].set_ylim(limits[2], limits[3]) axarr[row,1].imshow(immodel,interpolation='nearest',extent=ext,cmap=cmap,\ vmin=imdata.min(),vmax=imdata.max()) axarr[row, 1].contour(immodel, extent=ext, colors='k', origin='image', levels=s * mapcontours) axarr[row, 1].set_xlim(limits[0], limits[1]) axarr[row, 1].set_ylim(limits[2], limits[3]) axarr[row,2].imshow(imdiff,interpolation='nearest',extent=ext,cmap=cmap,\ vmin=imdata.min(),vmax=imdata.max()) axarr[row, 2].contour(imdiff, extent=ext, colors='k', origin='image', levels=s * rescontours) axarr[row, 2].set_xlim(limits[0], limits[1]) axarr[row, 2].set_ylim(limits[2], limits[3]) if np.log10(s) < -6.: sig, unit = 1e9 * s, 'nJy' elif np.log10(s) < -3.: sig, unit = 1e6 * s, '$\mu$Jy' elif np.log10(s) < 0.: sig, unit = 1e3 * s, 'mJy' else: sig, unit = s, 'Jy' axarr[row, 2].text(0.05, 0.05, "Data 1$\sigma$ = {0:.1f}{1:s}".format(sig, unit), transform=axarr[row, 2].transAxes, bbox=dict(fc='w')) # For the last two panels, give the apparent emission at higher resolution # and the intrinsic source plane structure. # Create model image at higher res, remove unlensed sources src = [src for src in source if src.lensed] imemit,_ = create_modelimage(lens,src,xemit,yemit,xemit,yemit,\ [0,xemit.shape[1],0,xemit.shape[0]],sourcedatamap=sourcedatamap[row]) images[row].append(imemit) xcen = center_of_mass(imemit)[1] * (xemit[0, 1] - xemit[0, 0]) + xemit.min() ycen = -center_of_mass(imemit)[0] * (xemit[0, 1] - xemit[0, 0]) + yemit.max() dx = 0.5 * (xemit.max() - xemit.min()) dy = 0.5 * (yemit.max() - yemit.min()) if logmodel: norm = SymLogNorm( 0.01 * imemit.max() ) #imemit = np.log10(imemit); vmin = imemit.min()-2. else: norm = None #vmin = imemit.min() axarr[row,3].imshow(imemit,interpolation='nearest',\ extent=[xemit.min(),xemit.max(),yemit.min(),yemit.max()],cmap=cmap,norm=norm) axarr[row, 3].set_xlim(xcen - dx, xcen + dx) axarr[row, 3].set_ylim(ycen - dy, ycen + dy) # And create source plane using the exact grids the code used during fitting. imsource = np.zeros(xemit.shape) for s in src: imsource += SourceProfile(xemit, yemit, s, lens) * (xemit[0, 1] - xemit[0, 0])**2. images[row].append(imsource) xcen = center_of_mass(imsource)[1] * (xemit[0, 1] - xemit[0, 0]) + xemit.min() ycen = -center_of_mass(imemit)[0] * (xemit[0, 1] - xemit[0, 0]) + yemit.max() dx = 0.5 * (xemit.max() - xemit.min()) dy = 0.5 * (yemit.max() - yemit.min()) axarr[row, 4].imshow( imsource, interpolation='nearest', extent=[xemit.min(), xemit.max(), yemit.min(), yemit.max()], cmap=cmap, norm=SymLogNorm(0.01 * imsource.max()), origin='lower') axarr[row, 4].set_xlim(xcen - dx, xcen + dx) axarr[row, 4].set_ylim(ycen - dy, ycen + dy) # Need to precalculate distances to get caustics Dd = Planck15.angular_diameter_distance(lens[0].z).value Ds = Planck15.angular_diameter_distance(source[0].z).value Dds = Planck15.angular_diameter_distance_z1z2(lens[0].z, source[0].z).value caustics = get_caustics(lens, Dd, Ds, Dds, highresbox=mcmcresult['highresbox'], numres=mcmcresult['emitres']) for caustic in caustics: axarr[row, 3].plot(caustic[:, 0], caustic[:, 1], ls='-', marker='', lw=1, color='r') axarr[row, 4].plot(caustic[:, 0], caustic[:, 1], ls='-', marker='', lw=1, color='r') s = imdiff.std() if np.log10(s) < -6.: sig, unit = 1e9 * s, 'nJy' elif np.log10(s) < -3.: sig, unit = 1e6 * s, '$\mu$Jy' elif np.log10(s) < 0.: sig, unit = 1e3 * s, 'mJy' else: sig, unit = s, 'Jy' # Label some axes and such axarr[row, 0].set_title(plotdata[row].filename + '\nDirty Image') axarr[row, 1].set_title('Model Dirty Image') axarr[row, 2].set_title('Residual Map rms={0:.1f}{1:s}'.format(sig, unit)) if logmodel: axarr[row, 3].set_title('High-res Model (log-scale)') else: axarr[row, 3].set_title('High-res Model') axarr[row, 4].set_title('Source Plane Model') if returnimages: return f, axarr, images else: return f, axarr