def replace_visibilities_galario(visdataloc,sbmodelloc,modelvisloc): #this needs to be open, channel by channel modelimage_cube = fits.getdata(sbmodelloc) #this can be the same throughout modelheader = fits.getheader(sbmodelloc) #these need to be peeled, channel by channel for the following uu_cube, vv_cube, ww_cube = uvutil.uvload(visdataloc) vis_complex_cube, wgt_cube = uvutil.visload(visdataloc) #this can be the same throughout pcd = uvutil.pcdload(visdataloc) #all the following is done channel by channel for chan in range(modelimage_cube.shape[0]): uu=np.ones((uu_cube.shape[0],uu_cube.shape[1],1,uu_cube.shape[3])) vv=np.ones((vv_cube.shape[0],vv_cube.shape[1],1,vv_cube.shape[3])) uu[:,:,0,:]=uu_cube[:,:,chan,:] vv[:,:,0,:]=vv_cube[:,:,chan,:] modelimage=modelimage_cube[chan] uushape = uu.shape if len(uushape) == 2: npol = uushape[0] nrow = uushape[1] uushape = (npol, 1, nrow) uu = uu.flatten() vv = vv.flatten() uu=uu.copy(order='C') vv=vv.copy(order='C') modelimage=np.roll(np.flip(modelimage,axis=0),1,axis=0).copy(order='C').byteswap().newbyteorder() model_complex = sampleImage(modelimage, np.absolute(modelheader['CDELT1'])/180*np.pi, uu, vv) # sample_vis.uvmodel(modelimage, modelheader, uu, vv, pcd) vis_complex = model_complex.reshape(uushape) vis_complex_cube[:,:,chan,:]=vis_complex[:,:,0,:] if chan%10==0: print chan #modelvisloc='../replaced_visib.uvfits' os.system('rm -rf ' + modelvisloc[:-7]+'*') cmd = 'cp ' + visdataloc + ' ' + modelvisloc os.system(cmd) real = np.real(vis_complex_cube) imag = np.imag(vis_complex_cube) visfile = fits.open(modelvisloc, mode='update') visibilities = visfile[0].data visheader = visfile[0].header if visheader['NAXIS'] == 7: visibilities['DATA'][:, 0, 0, :, :, :, 0] = real visibilities['DATA'][:, 0, 0, :, :, :, 1] = imag elif visheader['NAXIS'] == 6: visibilities['DATA'][:, 0, 0, :, :, 0] = real visibilities['DATA'][:, 0, 0, :, :, 1] = imag else: print("Visibility dataset has >7 or <6 axes. I can't read this.") #visibilities['DATA'][:, 0, 0, :, :, 2] = wgt visfile[0].data = visibilities visfile.flush() visfile.close()
def make_model_visibilities(self, cube, testMode=False, loadMode=False): model_cont = self.model_cont self.modelimage = self.make_kinms_model(cube) model = model_cont + self.modelimage xpos, ypos = self.xpos_center_padded, self.ypos_center_padded model_padded = np.transpose( np.pad(model, ((ypos - self.Nypix_small // 2, self.Nypix - ypos - self.Nypix_small // 2), (xpos - self.Nxpix_small // 2, self.Nxpix - xpos - self.Nxpix_small // 2), (0, 0)), mode='constant'), (2, 0, 1)) if testMode: np.save("test.npy", model_padded) print("testing") if loadMode: model_padded = np.load("test.npy") print("loading KinMS cube from test.npy") modelimage_cube = model_padded vis_complex_model = np.copy(self.vis_complex_model_template) for chan in range(modelimage_cube.shape[0]): uu = np.ones((self.uu_cube.shape[0], self.uu_cube.shape[1], 1, self.uu_cube.shape[3])) vv = np.ones((self.vv_cube.shape[0], self.vv_cube.shape[1], 1, self.vv_cube.shape[3])) uu[:, :, 0, :] = self.uu_cube[:, :, chan, :] vv[:, :, 0, :] = self.vv_cube[:, :, chan, :] modelimage = modelimage_cube[chan] uushape = uu.shape uu = uu.flatten() vv = vv.flatten() uu = uu.copy(order='C') vv = vv.copy(order='C') modelimage = np.roll(np.flip(modelimage, axis=0), 1, axis=0).copy( order='C') # .byteswap().newbyteorder() model_complex = sampleImage( modelimage, np.absolute(self.modelheader['CDELT1']) / 180 * np.pi, uu, vv) # this uses galario #model_complex = sample_vis.uvmodel(modelimage, modelheader, uu, vv, pcd) vis_complex = model_complex.reshape(uushape) vis_complex_model[:, :, chan, :] = vis_complex[:, :, 0, :] #replace_visibilities('HZ10_spw01_comb.uvfits','my_img_mod.fits','model_visib.uvfits') #vis_complex_model,bb = uvutil.visload('model_visib.uvfits') return vis_complex_model
def interpolate_model(u, v, freq, model, nthreads=1, dRA=0., dDec=0.): double.threads(nthreads) real = [] imag = [] dxy = (model.x[1] - model.x[0])*arcsec for i in range(len(model.freq)): vis = double.sampleImage(model.image[:,:,i,0].copy(order='C'), \ dxy, u, v, dRA=dRA*arcsec, dDec=dDec*arcsec) real.append(vis.real.reshape((u.size,1))) imag.append(vis.imag.reshape((u.size,1))) real = numpy.concatenate(real, axis=1) imag = numpy.concatenate(imag, axis=1) return Visibilities(u, v, freq, real, imag, numpy.ones(real.shape))
def compare_vis_galario(datfile='data/HD163296.CO32.regridded.cen15',modfile='model/testpy_alma',new_weight=[1,],systematic=False,isgas=True,plot_resid=False): '''Calculate the raw chi-squared based on the difference between the model and data visibilities. :param datfile: (default = 'data/HD163296.CO32.regridded.cen15') The base name for the data file. The code reads in the visibilities from datfile+'.vis.fits' :param modfile" (default='model/testpy_alma') The base name for the model file. The code reads in the visibilities from modfile+'.model.vis.fits' :param new_weight: An array containing the weights to be used in the chi-squared calculation. This should have the same dimensions as the real and imaginary part of the visibilities (ie Nbas x Nchan) :param systematic: The systematic weight to be applied. The value sent with this keyword is used to scale the absolute flux level of the model. It is defined such that a value >1 decreases the model and a value <1 increases the model (the model visibilities are divided by the systematic parameter). It is meant to mimic a true flux in the data which is larger or smaller by the fraction systematic (e.g. specifying systematic=1.2 is equivalent to saying that the true flux of the data is 20% brighter than what has been observed, with this scaling applied to the model instead of changing the data) :param isgas: If the data is line emission then the data has an extra dimension covering the >1 channels. Set this keyword to ensure that the data is read in properly. Conversely, if you are comparing continuum data then set this keyword to False. ''' #Limit the multi-threading of Galario (necessary on the computing cluster) gdouble.threads(1) # - Read in object visibilities obj = fits.open(datfile+'.vis.fits') freq0 = obj[0].header['crval4'] u_obj,v_obj = (obj[0].data['UU']*freq0).astype(np.float64),(obj[0].data['VV']*freq0).astype(np.float64) vis_obj = (obj[0].data['data']).squeeze() if isgas: if obj[0].header['telescop'] == 'ALMA': if obj[0].header['naxis3'] == 2: real_obj = (vis_obj[:,:,0,0]+vis_obj[:,:,1,0])/2. imag_obj = (vis_obj[:,:,0,1]+vis_obj[:,:,1,1])/2. weight_real = vis_obj[:,:,0,2] weight_imag = vis_obj[:,:,1,2] else: real_obj = vis_obj[::2,:,0] imag_obj = vis_obj[::2,:,1] else: if obj[0].header['telescop'] == 'ALMA': if obj[0].header['naxis3'] == 2: real_obj = (vis_obj[:,0,0]+vis_obj[:,1,0])/2. imag_obj = (vis_obj[:,0,1]+vis_obj[:,1,1])/2. weight_real = vis_obj[:,0,2] weight_imag = vis_obj[:,1,2] obj.close() #Generate model visibilities model_fits = fits.open(modfile+'.fits') model = model_fits[0].data.squeeze() nxy,dxy = model_fits[0].header['naxis1'],np.radians(np.abs(model_fits[0].header['cdelt1'])) model_fits.close() if isgas: real_model = np.zeros(real_obj.shape) imag_model = np.zeros(imag_obj.shape) for i in range(real_obj.shape[1]): vis = gdouble.sampleImage(np.flipud(model[i,:,:]).byteswap().newbyteorder(),dxy,u_obj,v_obj) real_model[:,i] = vis.real imag_model[:,i] = vis.imag else: vis = gdouble.sampleImage(model.byteswap().newbyteorder(),dxy,u_obj,v_obj) real_model = vis.real imag_model = vis.imag if systematic: real_model = real_model/systematic imag_model = imag_model/systematic if len(new_weight) > 1: weight_real = new_weight weight_imag = new_weight weight_real[real_obj==0] = 0. weight_imag[imag_obj==0] = 0. print('Removed data %i' % ((weight_real ==0).sum()+(weight_imag==0).sum())) if plot_resid: #Code to plot, and fit, residuals #If errors are Gaussian, then residuals should have gaussian shape #If error size is correct, residuals will have std=1 uv = np.sqrt(u_obj**2+v_obj**2) use = (weight_real > .05) & (weight_imag>.05) diff = np.concatenate((((real_model[use]-real_obj[use])*np.sqrt(weight_real[use])),((imag_model[use]-imag_obj[use])*np.sqrt(weight_imag[use])))) diff = diff.flatten() n,bins,patches = plt.hist(diff,10000,normed=1,histtype='step',color='k',label='Data',lw=3) popt,pcov = curve_fit(gaussian,bins[1:],n) y=gaussian(bins,popt[0],popt[1],popt[2]) print('Gaussian fit parameters (amp,width,center): ',popt) print('If errors are properly scaled, then width should be close to 1') plt.plot(bins,y,'r--',lw=6,label='gaussuian') #slight deviations from gaussian, but gaussian is still the best... plt.xlabel('(Model-Data)/$\sigma$',fontweight='bold',fontsize=20) ax=plt.gca() for tick in ax.xaxis.get_major_ticks(): tick.label1.set_fontsize(20) tick.label1.set_fontweight('bold') for tick in ax.yaxis.get_major_ticks(): tick.label1.set_fontsize(20) tick.label1.set_fontweight('bold') plt.show() chi = ((real_model-real_obj)**2*weight_real).sum() + ((imag_model-imag_obj)**2*weight_imag).sum() return chi
def loglike(self,cube): ''' This function calculates the model ln(likelihood). Parameters ---------- gassigma: float The gas dispersion in km/s bright_std: float The size as gaussian FWHM in arcsec vmax: float The max velocity in km/s, the asymptote of the arctan vel_scale: float The radial distance, in arcsec, where velocity goes to vmax/2 vel_cen: float The velocity center in km/s away from central channel, increasing vel_cen moves it to later channels, i.e. same direction as the channel ordering inc: float Inclination, is 0 for face on and 90 for edge-on posang: float Position angle starting with red emission from horizontal to the right (toward decreasing RA), and increasing counterclockwise (when we have a - in front of vmax). posang near 0, and - in front of vmax, means the emission moves right to left as channels increase. positive posang rotates this pattern toward the north, in a counterclockwise manner x_cen, y_cen: (float,float) Center position for the disk, they are in arcsec. y_cen actually controls the x-axis and positive means increasing x of center. x_cen controls y axis, and positive means increasing y of center intflux: float Line integrated flux in Jy km/s Returns ------- ln_like+self.offset_lnlike: float We offset the ln_like value by a constant to make the number be small enough for Multinest to be able to work with. Definition of posang for the rotating disk: If velprof=vmax*np.arctan(velrad/vel_scale)/np.pi*2 posang 0: to the right posang 90: downwards posang 180: to the left posang 270 (=-90): upward If velprof=-vmax*np.arctan(velrad/vel_scale)/np.pi*2 posang 0: to the left posang 90: upward posang 180: to the right posang 270 (=-90): downward For example: if the emission is moving from left to right, as channels increase (toward lower frequency and higher velocity, red). Then need posang=180 if minus sign in front of vmax. ''' gassigma,bright_std,vmax,vel_scale,vel_cen,inc,posang,x_cen,y_cen,intflux=cube[0],cube[1],cube[2],cube[3],cube[4],cube[5],cube[6],cube[7],cube[8],cube[9] model_cont=self.model_cont sbprof=np.exp(-self.sbrad**2/2/(bright_std/2.355)**2) velprof=vmax*np.arctan(self.velrad/vel_scale)/np.pi*2 self.modelimage=KinMS(self.xs, self.ys, self.vs, cellSize=self.cellsize, dv=self.dv, beamSize=0, inc=inc, gasSigma=gassigma, sbProf=sbprof, sbRad=self.sbrad, velRad=self.velrad, velProf=velprof, diskThick=0, cleanOut=True, ra=0, dec=0, nSamps=self.nsamps, posAng=posang, intFlux=intflux, inClouds=[], vLOS_clouds=[], flux_clouds=0, vSys=0, restFreq=115.271e9, phaseCen=np.array([x_cen,y_cen]), vOffset=vel_cen, fixSeed=False, vRadial=0, vPosAng=0, #vPhaseCen=np.array([x_cen,y_cen]), #That ^ was a workaround for a bug in KinMS that has now been fixed returnClouds=False, gasGrav=False, fileName=False) model = model_cont+self.modelimage xpos,ypos=self.xpos_center_padded,self.ypos_center_padded model_padded=np.transpose(np.pad(model,((ypos-self.Nypix_small/2,self.Nypix-ypos-self.Nypix_small/2),(xpos-self.Nxpix_small/2,self.Nxpix-xpos-self.Nxpix_small/2),(0,0)),mode='constant'),(2,0,1)) modelimage_cube = model_padded vis_complex_model=np.copy(self.vis_complex_model_template) for chan in range(modelimage_cube.shape[0]): uu=np.ones((self.uu_cube.shape[0],self.uu_cube.shape[1],1,self.uu_cube.shape[3])) vv=np.ones((self.vv_cube.shape[0],self.vv_cube.shape[1],1,self.vv_cube.shape[3])) uu[:,:,0,:]=self.uu_cube[:,:,chan,:] vv[:,:,0,:]=self.vv_cube[:,:,chan,:] modelimage=modelimage_cube[chan] uushape = uu.shape uu = uu.flatten() vv = vv.flatten() uu=uu.copy(order='C') #This vv=vv.copy(order='C') #this modelimage=np.roll(np.flip(modelimage,axis=0),1,axis=0).copy(order='C')#.byteswap().newbyteorder() #This model_complex = sampleImage(modelimage, np.absolute(self.modelheader['CDELT1'])/180*np.pi, uu, vv) #this uses galario #model_complex = sample_vis.uvmodel(modelimage, modelheader, uu, vv, pcd) vis_complex = model_complex.reshape(uushape) vis_complex_model[:,:,chan,:]=vis_complex[:,:,0,:] #replace_visibilities('HZ10_spw01_comb.uvfits','my_img_mod.fits','model_visib.uvfits') #vis_complex_model,bb = uvutil.visload('model_visib.uvfits') vis_complex_model=vis_complex_model.flatten()[self.good_vis] def find_param(scale): diff_all=np.abs(self.vis_complex_data-vis_complex_model*scale) return np.sum(self.wgt_data*diff_all*diff_all) ln_like=-0.5*find_param(1) print(ln_like) return ln_like+self.offset_lnlike
# Do the Fourier transform with TrIFT u, v = numpy.meshgrid(numpy.linspace(-3., 3., 100), numpy.linspace(-3., 3., 100)) u = u.reshape((u.size, )) v = v.reshape((v.size, )) vis = trift.trift_cextended(x, y, flux, u, v, 0., 0.) # Do the Fourier transform with GALARIO. dxy = xx[0, 1] - xx[0, 0] vvis = double.sampleImage(fflux, dxy, u, v, origin="lower") # NOTE: GALARIO appears to be off by the complex conjugate, possibly because # CASA spits out visibilities that need to be complex conjugated to have the # proper orientation (see note by Urvashi Rau, relayed by Ian through # MPoL or Ryan through vis_sample. vvis = numpy.conj(vvis) # And do just a standard, numpy fft. vvvis = numpy.fft.fftshift(numpy.fft.fft2(numpy.fft.ifftshift(fflux[:, ::-1]))) uu = numpy.fft.fftshift(numpy.fft.fftfreq(1024, dxy)) vv = numpy.fft.fftshift(numpy.fft.fftfreq(1024, dxy))
def mcmc(self, nwalk=16, nsteps=10, nthreads=1, burn=5, out_dir=''): '''Do the mcmc. Parameters ---------- nwalk : int Number of walkers. nsteps : int Number of mcmc steps. nthreads : int Number of threads. burn : int Number of steps to count as burn in. out_dir : str Where to put results. ''' sampler = emcee.EnsembleSampler(nwalk, self.img.n_params, self.lnprob, threads=nthreads) # initialize the walkers pos = [ self.p0 + self.p0 * 0.1 * np.random.randn(self.img.n_params) for i in range(nwalk) ] # execute the MCMC pos, prob, state = sampler.run_mcmc(pos, nsteps) model_name = self.img.Dens.model if not os.path.exists(out_dir): os.mkdir(out_dir) # see what the chains look like, skip a burn in period if desired fig, ax = plt.subplots(self.img.n_params + 1, 2, figsize=(9.5, 5), sharex='col', sharey=False) for j in range(nwalk): ax[-1, 0].plot(sampler.lnprobability[j, :burn]) for i in range(self.img.n_params): ax[i, 0].plot(sampler.chain[j, :burn, i]) ax[i, 0].set_ylabel(self.img.params[i]) for j in range(nwalk): ax[-1, 1].plot(sampler.lnprobability[j, burn:]) for i in range(self.img.n_params): ax[i, 1].plot(sampler.chain[j, burn:, i]) ax[i, 1].set_ylabel(self.img.params[i]) ax[-1, 0].set_xlabel('burn in') ax[-1, 1].set_xlabel('sampling') fig.savefig(out_dir + '/chains-' + model_name + '.png') # make the corner plot fig = corner.corner(sampler.chain[:, burn:, :].reshape( (-1, self.img.n_params)), labels=self.img.params, show_titles=True) fig.savefig(out_dir + '/corner-' + model_name + '.png') # get the median parameters self.p = np.median(sampler.chain[:, burn:, :].reshape( (-1, self.img.n_params)), axis=0) self.s = np.std(sampler.chain[:, burn:, :].reshape( (-1, self.img.n_params)), axis=0) print('best fit parameters: {}'.format(self.p)) # recompute the limits for the full rotated image self.img.compute_rmax(self.p, image_full=True) fig, ax = plt.subplots() ax.imshow(self.img.image_full(self.p)[self.img.cc], origin='bottom') fig.savefig(out_dir + '/best-' + model_name + '.png') # save the chains to file np.savez_compressed(out_dir + '/chains-' + model_name + '.npz', sampler.chain, sampler.lnprobability) # save the visibilities for subtraction from the data vis_mod = gd.sampleImage(self.img.pb * self.img.image(self.p[3:]), self.dxy, self.u, self.v, dRA=self.p[0] * arcsec, dDec=self.p[1] * arcsec, PA=np.deg2rad(self.p[2])) np.save(out_dir + '/vis-' + model_name + '.npy', vis_mod)