def spec_curve_fit(bin_num, map_name = map_column_dens): # following loop has not good style. One should build in some break statements or error messages # if files repeatedly appear in loop. for one_file in files: if 'NH3_11' in one_file: file_name_NH3_11 = one_file if 'NH3_22' in one_file: file_name_NH3_22 = one_file if 'NH3_33' in one_file: file_name_NH3_33 = one_file y, x, med = binning(bin_width, bin_num) s11, _, offset_velocity11, sp_av11 = averaging_over_dopplervel(file_name_NH3_11, y, x) s22, _, offset_velocity22, sp_av22 = averaging_over_dopplervel(file_name_NH3_22, y, x) s33, _, offset_velocity33, sp_av33 = averaging_over_dopplervel(file_name_NH3_33, y, x) xarr11 = SpectroscopicAxis(offset_velocity11*u.km/u.s, velocity_convention='radio', refX=freq_dict['oneone']).as_unit(u.GHz) xarr22 = SpectroscopicAxis(offset_velocity22*u.km/u.s, velocity_convention='radio', refX=freq_dict['twotwo']).as_unit(u.GHz) xarr33 = SpectroscopicAxis(offset_velocity33*u.km/u.s, velocity_convention='radio', refX=freq_dict['threethree']).as_unit(u.GHz) sp11 = psk.Spectrum(data=s11, xarr=xarr11, xarrkwargs={'unit':'km/s'},unit='K') sp22 = psk.Spectrum(data=s22, xarr=xarr22, xarrkwargs={'unit':'km/s'},unit='K') sp33 = psk.Spectrum(data=s33, xarr=xarr33, xarrkwargs={'unit':'km/s'},unit='K') # This joins all the spectra together into one object. allspec = psk.Spectra([sp11,sp22,sp33]) allspec.xarr.as_unit('Hz',velocity_convention='radio') # This add the cold_ammonia model to the list of things we can use for fitting allspec.specfit.Registry.add_fitter('cold_ammonia',ammonia.cold_ammonia_model(),6) # This does the fit. The values of the guess are # Kinetic Temperature (usually about 15 to 25 K) # Excitation Temperature (between 2.73 K and the excitation temperature) # Log Column Density of ammonia # Line width (~1 km/s) # Offset velocity (you will usually use 0 instead of 8.5) # Ortho fraction (leave at 0) allspec.specfit(fittype='cold_ammonia',guesses=[23,5,13.1,1,0,0]) # You can make a plot here. fig = plt.figure() allspec.plotter() allspec.specfit.plot_fit(lw=1, components=True) plt.xlim((23.692,23.697)) # plt.xlim((23.72,23.725)) # plt.xlim((23.8692, 23.8708)) # plt.savefig("OrionA:pyspeckit_fit_bin_width=%rthis_bin=%r.ps" %(bin_width, this_bin)) plt.savefig("Map=%r:bin_num=%r_pyspeckit_fit_NH3_11TEST.ps"%(map_name, bin_num)) plt.show() # returns the values of the fitted parameters: T_K, T_ex, N, sigma, v, F_0 return allspec.specfit.parinfo, allspec.specfit.parinfo.errors
def nh3_spectrum(pars, kms_vals, lines=['oneone', 'twotwo'], snr=5, snr_line='oneone', seed=None): # building a spectroscopic axis xarr_dict = {} for line in lines: xarr_dict[line] = pyspeckit.units.SpectroscopicAxis(kms_vals, 'km/s') xarr_dict[line].refX = ammonia_constants.freq_dict[line] * u.Hz xarr_dict[line].velocity_convention = 'radio' # TODO: bug... see if #182 fixes it #xarr_dict[line].convert_to_unit('GHz') xarr_dict[line] = xarr_dict[line].as_unit('GHz') xarr = SpectroscopicAxes([xarr_dict[line] for line in lines]) xarr.refX = ammonia_constants.freq_dict['oneone'] * u.Hz xarr.velocity_convention = 'radio' xarr.convert_to_unit('km/s') # making synthetic spectra sp = pyspeckit.Spectrum(data=np.zeros_like(xarr.value), xarr=xarr) sp.Registry.add_fitter('cold_ammonia', ammonia.cold_ammonia_model(), 6) sp.specfit.fitter = sp.specfit.Registry.multifitters['cold_ammonia'] sp.specfit.fittype = 'cold_ammonia' signal = sp.specfit.get_full_model(pars=pars) sp.data = signal line_mask = xarr_dict[snr_line].min(), xarr_dict[snr_line].max() # GHz std_noise = sp.slice(*line_mask).data.max() / snr np.random.seed(seed=0) try: noise = np.random.normal(0, std_noise, sp.xarr.size) except ValueError: # ValueError("scale <= 0") noise = 0 sp.data += noise sp.error = np.zeros_like(sp.data) + std_noise return sp
def update_NH3_moment0(region_name='L1688', file_extension='_DR1', threshold=None, save_masked=False): """ Function to update moment calculation based on centroid velocity from line fit. For a given NH3(1,1) cube, we check which channels have flux in the model cube, and then use those channels as the appropiate channels for integration. Based on code provided by Vlas Sokolov Parameters ---------- region : str Name of region to re-calculate moment map file_extension : str filename extension threshold : float minimum threshold in model cube used to identify channels with emission Default is down to the machine precision, a better result could be obtained with 0.0125 save_masked : Boolean Keyword to store the masked cube used in the integrated intensity calculation. This is useful to Usage: import GAS GAS.PropertyMaps.update_NH3_moment0(region_name='NGC1333', file_extension='_DR1', threshold=0.0125, save_masked=True) """ fit_file='{0}/{0}_parameter_maps_{1}.fits'.format(region_name,file_extension) for line_i in ['11','22']: file_in ='{0}/{0}_NH3_{2}_base{1}.fits'.format(region_name,file_extension,line_i) file_out='{0}/{0}_NH3_{2}_base{1}_mom0_QA.fits'.format(region_name,file_extension,line_i) file_rms='{0}/{0}_NH3_{2}_base{1}_rms_QA.fits'.format(region_name,file_extension,line_i) file_rms_mom='{0}/{0}_NH3_{2}_base{1}_mom0_sigma_QA.fits'.format(region_name,file_extension,line_i) file_temp='{0}/{0}_NH3_{2}_base{1}_masked_temp.fits'.format(region_name,file_extension,line_i) # Load pyspeckit cube pycube = pyspeckit.Cube(file_in) if 'FITTYPE' in fits.getheader(fit_file): # 'FITTYPE' is not present in old versions of the parameter files pycube.load_model_fit( fit_file, npars=6, npeaks=1) else: if not 'cold_ammonia' in pycube.specfit.Registry.multifitters: pycube.specfit.Registry.add_fitter('cold_ammonia',ammonia.cold_ammonia_model(),6) pycube.load_model_fit( fit_file, npars=6, npeaks=1, fittype='cold_ammonia') # If threshold is not defined, then use the machine accuracy if threshold == None: threshold=np.finfo(pycube.data.dtype).eps # Get model cube from pyspeckit, this take some time modelcube = pycube.get_modelcube() # Use spectral cube to calculate integrated intensity maps cube_raw = SpectralCube.read(file_in) # in km/s not Hz cube = cube_raw.with_spectral_unit(u.km / u.s,velocity_convention='radio') vaxis=cube.spectral_axis dv=np.abs(vaxis[1]-vaxis[0]) # define mask mask3d = modelcube > threshold # What to do with pixels without signal # Calculate mean velocity and velocity dispersion vmap=pycube.parcube[4,:,:] sigma_map=pycube.parcube[3,:,:] vmean=np.mean(vmap[vmap != 0])*u.km/u.s if line_i == '11': sigma_v=( np.mean(sigma_map[vmap != 0]) + 0.15)*u.km/u.s else: sigma_v=( np.mean(sigma_map[vmap != 0]))*u.km/u.s total_spc=np.sqrt( (vaxis-vmean)**2)/sigma_v < 3.0 # im_mask=np.sum(mask3d, axis=0) for ii in np.arange( im_mask.shape[1]): for jj in np.arange( im_mask.shape[0]): if (im_mask[jj,ii] == 0) or (pycube.parcube[3,jj,ii] < 3*pycube.errcube[3,jj,ii]): mask3d[:,jj,ii] = total_spc n_chan=np.sum(mask3d, axis=0) # create masked cube cube2 = cube.with_mask(mask3d) cube3 = cube.with_mask(~mask3d) # if save_masked: cube2.write( file_temp, overwrite=True) # calculate moment map moment_0 = cube2.moment(axis=0) moment_0.write( file_out, overwrite=True) rms=cube3.std(axis=0) rms.write( file_rms, overwrite=True) mom_0_rms=rms * dv * np.sqrt(n_chan) mom_0_rms.write( file_rms_mom, overwrite=True)
moment1[moment1>vmax] = vmax-0.2 guesses[0,:,:] = 12 # Kinetic temperature guesses[1,:,:] = 3 # Excitation Temp guesses[2,:,:] = 14.5 # log(column) guesses[3,:,:] = moment2 # Line width / 5 (the NH3 moment overestimates linewidth) guesses[4,:,:] = moment1 # Line centroid guesses[5,:,:] = 0.0 # F(ortho) - ortho NH3 fraction (fixed) if do_plot: import matplotlib.pyplot as plt plt.imshow( w11, origin='lower',interpolation='nearest') plt.show() F=False T=True if not 'cold_ammonia' in cubes.specfit.Registry.multifitters: cubes.specfit.Registry.add_fitter('cold_ammonia',ammonia.cold_ammonia_model(),6) print('start fit') cubes.fiteach(fittype='cold_ammonia', guesses=guesses, integral=False, verbose_level=3, fixed=[F,F,F,F,F,T], signal_cut=2, limitedmax=[F,F,T,F,T,T], maxpars=[0,0,17.0,0,vmax,1], limitedmin=[T,T,T,T,T,T], minpars=[5,2.8,12.0,0.04,vmin,0], start_from_point=(xmax,ymax), use_neighbor_as_guess=True, position_order = 1/peaksnr, errmap=errmap11, multicore=multicore) fitcubefile = fits.PrimaryHDU(data=np.concatenate([cubes.parcube,cubes.errcube]), header=cubes.header)
def hmm1_cubefit(vmin=3.4, vmax=5.0, tk_ave=10., do_plot=False, snr_min=5.0, multicore=1, do_thin=False): """ Fit NH3(1,1) and (2,2) cubes for H-MM1. It fits all pixels with SNR larger than requested. Initial guess is based on moment maps and neighboring pixels. The fitting can be done in parallel mode using several cores, however, this is dangerous for large regions, where using a good initial guess is important. It stores the result in a FITS cube. TODO: -convert FITS cube into several FITS files -Improve initial guess Parameters ---------- vmin : numpy.float Minimum centroid velocity to plot, in km/s. vmax : numpy.float Maximum centroid velocity to plot, in km/s. tk_ave : numpy.float Mean kinetic temperature of the region, in K. do_plot : bool If True, then a map of the region to map is shown. snr_min : numpy.float Minimum signal to noise ratio of the spectrum to be fitted. multicore : int Numbers of cores to use for parallel processing. """ cube11sc = SpectralCube.read(OneOneFile) cube22sc = SpectralCube.read(TwoTwoFile) cube11_v = cube11sc.with_spectral_unit(u.km / u.s, velocity_convention='radio', rest_value=freq11) cube22_v = cube22sc.with_spectral_unit(u.km / u.s, velocity_convention='radio', rest_value=freq22) from pyspeckit.spectrum.units import SpectroscopicAxis spec11 = SpectroscopicAxis(cube11_v.spectral_axis, refX=freq11, velocity_convention='radio') spec22 = SpectroscopicAxis(cube22_v.spectral_axis, refX=freq22, velocity_convention='radio') errmap11 = fits.getdata(RMSFile_11) errmap22 = fits.getdata(RMSFile_22) errmap_K = errmap11 #[errmap11, errmap22] Tpeak11 = fits.getdata(OneOnePeak) moment1 = fits.getdata(OneOneMom1) moment2 = (fits.getdata(OneOneMom2))**0.5 snr = cube11sc.filled_data[:].value / errmap11 peaksnr = Tpeak11 / errmap11 planemask = (peaksnr > snr_min) # *(errmap11 < 0.15) planemask = remove_small_objects(planemask, min_size=40) planemask = opening(planemask, disk(1)) #planemask = (peaksnr>20) * (errmap11 < 0.2) mask = (snr > 3) * planemask maskcube = cube11sc.with_mask(mask.astype(bool)) maskcube = maskcube.with_spectral_unit(u.km / u.s, velocity_convention='radio') slab = maskcube.spectral_slab(vmax * u.km / u.s, vmin * u.km / u.s) w11 = slab.moment(order=0, axis=0).value peakloc = np.nanargmax(w11) ymax, xmax = np.unravel_index(peakloc, w11.shape) moment2[np.isnan(moment2)] = 0.2 moment2[moment2 < 0.2] = 0.2 ## Load FITS files cube11 = pyspeckit.Cube(OneOneFile, maskmap=planemask) cube22 = pyspeckit.Cube(TwoTwoFile, maskmap=planemask) # Stack files cubes = pyspeckit.CubeStack([cube11, cube22], maskmap=planemask) cubes.unit = "K" # Define initial guess guesses = np.zeros((6, ) + cubes.cube.shape[1:]) moment1[moment1 < vmin] = vmin + 0.2 moment1[moment1 > vmax] = vmax - 0.2 guesses[0, :, :] = tk_ave # Kinetic temperature guesses[1, :, :] = 7 # Excitation Temp guesses[2, :, :] = 14.5 # log(column) guesses[ 3, :, :] = moment2 # Line width / 5 (the NH3 moment overestimates linewidth) guesses[4, :, :] = moment1 # Line centroid guesses[5, :, :] = 0.5 # F(ortho) - ortho NH3 fraction (fixed) if do_plot: import matplotlib.pyplot as plt plt.imshow(w11 * planemask, origin='lower') plt.show() print('start fit') cubes.specfit.Registry.add_fitter('cold_ammonia', ammonia.cold_ammonia_model(), 6) if do_thin: file_out = "{0}H-MM1_cold_parameter_maps_snr{1}_thin_v1.fits".format( fit_dir, snr_min) else: file_out = "{0}H-MM1_cold_parameter_maps_snr{1}_thick_v1.fits".format( fit_dir, snr_min) cubes.fiteach(fittype='cold_ammonia', guesses=guesses, integral=False, verbose_level=3, fixed=[do_thin, False, False, False, False, True], signal_cut=2, limitedmax=[True, False, False, False, True, True], maxpars=[20, 15, 20, 0.4, vmax, 1], limitedmin=[True, True, True, True, True, True], minpars=[5, 2.8, 12.0, 0.05, vmin, 0], start_from_point=(xmax, ymax), use_neighbor_as_guess=True, position_order=1 / peaksnr, errmap=errmap_K, multicore=multicore) # Store fits into FITS cube fitcubefile = fits.PrimaryHDU(data=np.concatenate( [cubes.parcube, cubes.errcube]), header=cubes.header) fitcubefile.header.set('PLANE1', 'TKIN') fitcubefile.header.set('PLANE2', 'TEX') fitcubefile.header.set('PLANE3', 'COLUMN') fitcubefile.header.set('PLANE4', 'SIGMA') fitcubefile.header.set('PLANE5', 'VELOCITY') fitcubefile.header.set('PLANE6', 'FORTHO') fitcubefile.header.set('PLANE7', 'eTKIN') fitcubefile.header.set('PLANE8', 'eTEX') fitcubefile.header.set('PLANE9', 'eCOLUMN') fitcubefile.header.set('PLANE10', 'eSIGMA') fitcubefile.header.set('PLANE11', 'eVELOCITY') fitcubefile.header.set('PLANE12', 'eFORTHO') fitcubefile.header.set('CDELT3', 1) fitcubefile.header.set('CTYPE3', 'FITPAR') fitcubefile.header.set('CRVAL3', 0) fitcubefile.header.set('CRPIX3', 1) fitcubefile.writeto(file_out, overwrite=True)
def cubefit(region='NGC1333', blorder=1, vmin=5, vmax=15, do_plot=False, snr_min=5.0, multicore=1, file_extension=None, mask_function = None, gauss_fit=False): """ Fit NH3(1,1) and (2,2) cubes for the requested region. It fits all pixels with SNR larger than requested. Initial guess is based on moment maps and neighboring pixels. The fitting can be done in parallel mode using several cores, however, this is dangerous for large regions, where using a good initial guess is important. It stores the result in a FITS cube. TODO: -Improve initial guess Parameters ---------- region : str Name of region to reduce blorder : int order of baseline removed vmin : numpy.float Minimum centroid velocity to plot, in km/s. vmax : numpy.float Maximum centroid velocity to plot, in km/s. do_plot : bool If True, then a map of the region to map is shown. snr_min : numpy.float Minimum signal to noise ratio of the spectrum to be fitted. multicore : int Numbers of cores to use for parallel processing. file_extension : str File extension of the input maps. Default is 'base#' where # is the blorder parameter above. mask_function : fun function to create a custom made mask for analysis. Defaults to using `default_masking` """ if file_extension: root = file_extension else: # root = 'base{0}'.format(blorder) root = 'all' OneOneIntegrated = '{0}/{0}_NH3_11_{1}_mom0.fits'.format(region,root) OneOneFile = '{0}/{0}_NH3_11_{1}.fits'.format(region,root) RMSFile = '{0}/{0}_NH3_11_{1}_rms.fits'.format(region,root) TwoTwoFile = '{0}/{0}_NH3_22_{1}.fits'.format(region,root) ThreeThreeFile = '{0}/{0}_NH3_33_{1}.fits'.format(region,root) cube11sc = SpectralCube.read(OneOneFile) cube22sc = SpectralCube.read(TwoTwoFile) errmap11 = fits.getdata(RMSFile) rms = np.nanmedian(errmap11) snr = cube11sc.filled_data[:].value/errmap11 peaksnr = np.max(snr,axis=0) if mask_function is None: planemask = default_masking(peaksnr,snr_min = snr_min) else: planemask = mask_function(peaksnr,snr_min = snr_min) #planemask = (peaksnr>20) * (errmap11 < 0.2) mask = (snr>3)*planemask maskcube = cube11sc.with_mask(mask.astype(bool)) maskcube = maskcube.with_spectral_unit(u.km/u.s,velocity_convention='radio') slab = maskcube.spectral_slab( vmax*u.km/u.s, vmin*u.km/u.s) w11=slab.moment( order=0, axis=0).value peakloc = np.nanargmax(w11) ymax,xmax = np.unravel_index(peakloc,w11.shape) moment1 = slab.moment( order=1, axis=0).value moment2 = (slab.moment( order=2, axis=0).value)**0.5 moment2[np.isnan(moment2)]=0.2 moment2[moment2<0.2]=0.2 cube11 = pyspeckit.Cube(OneOneFile,maskmap=planemask) cube11.unit="K" cube22 = pyspeckit.Cube(TwoTwoFile,maskmap=planemask) cube22.unit="K" #cube33 = pyspeckit.Cube(ThreeThreeFile,maskmap=planemask) #cube33.unit="K" # removed as long as we're not modeling OPR cubes = pyspeckit.CubeStack([cube11,cube22],maskmap=planemask) cubes.unit="K" guesses = np.zeros((6,)+cubes.cube.shape[1:]) moment1[moment1<vmin] = vmin+0.2 moment1[moment1>vmax] = vmax-0.2 guesses[0,:,:] = 12 # Kinetic temperature guesses[1,:,:] = 3 # Excitation Temp guesses[2,:,:] = 14.5 # log(column) guesses[3,:,:] = moment2 # Line width / 5 (the NH3 moment overestimates linewidth) guesses[4,:,:] = moment1 # Line centroid guesses[5,:,:] = 0.0 # F(ortho) - ortho NH3 fraction (fixed) if do_plot: import matplotlib.pyplot as plt plt.imshow( w11, origin='lower',interpolation='nearest') plt.show() F=False T=True if not 'cold_ammonia' in cubes.specfit.Registry.multifitters: cubes.specfit.Registry.add_fitter('cold_ammonia',ammonia.cold_ammonia_model(),6) print('start fit') cubes.fiteach(fittype='cold_ammonia', guesses=guesses, integral=False, verbose_level=3, fixed=[F,F,F,F,F,T], signal_cut=2, limitedmax=[F,F,T,F,T,T], maxpars=[0,0,17.0,0,vmax,1], limitedmin=[T,T,T,T,T,T], minpars=[5,2.8,12.0,0.04,vmin,0], start_from_point=(xmax,ymax), use_neighbor_as_guess=True, position_order = 1/peaksnr, errmap=errmap11, multicore=multicore) fitcubefile = fits.PrimaryHDU(data=np.concatenate([cubes.parcube,cubes.errcube]), header=cubes.header) fitcubefile.header.set('PLANE1','TKIN') fitcubefile.header.set('PLANE2','TEX') fitcubefile.header.set('PLANE3','COLUMN') fitcubefile.header.set('PLANE4','SIGMA') fitcubefile.header.set('PLANE5','VELOCITY') fitcubefile.header.set('PLANE6','FORTHO') fitcubefile.header.set('PLANE7','eTKIN') fitcubefile.header.set('PLANE8','eTEX') fitcubefile.header.set('PLANE9','eCOLUMN') fitcubefile.header.set('PLANE10','eSIGMA') fitcubefile.header.set('PLANE11','eVELOCITY') fitcubefile.header.set('PLANE12','eFORTHO') fitcubefile.header.set('CDELT3',1) fitcubefile.header.set('CTYPE3','FITPAR') fitcubefile.header.set('CRVAL3',0) fitcubefile.header.set('CRPIX3',1) fitcubefile.writeto("{0}/{0}_parameter_maps_{1}.fits".format(region,root),clobber=True) if gauss_fit==True: molecules = ['C2S', 'HC7N_22_21', 'HC7N_21_20', 'HC5N'] for i in molecules: gauss_fitter(region=region, mol=i, vmin=vmin, vmax=vmax, snr_min=snr_min, multicore=multicore, file_extension=file_extension)
def update_NH3_moment0(region_name='L1688', file_extension='DR1_rebase3', threshold=0.0125, trim_edge=True, save_masked=False): """ Function to update moment calculation based on centroid velocity from line fit. For a given NH3(1,1) cube, we check which channels have flux in the model cube, and then use those channels as the appropiate channels for integration. Based on code provided by Vlas Sokolov Parameters ---------- region : str Name of region to re-calculate moment map file_extension : str filename extension threshold : float minimum threshold in model cube used to identify channels with emission Default is down to the machine precision, a better result could be obtained with 0.0125 trim_edge : Boolean Keyword to trim noisy edges of output maps using disk erode save_masked : Boolean Keyword to store the masked cube used in the integrated intensity calculation. This is useful to Usage: import GAS GAS.PropertyMaps.update_NH3_moment0(region_name='NGC1333', file_extension='DR1_rebase3', threshold=0.0125, save_masked=True) """ fit_file='{0}/{0}_parameter_maps_{1}.fits'.format(region_name,file_extension) for line_i in ['11','22']: file_in ='{0}/{0}_NH3_{2}_{1}.fits'.format(region_name,file_extension,line_i) file_out='{0}/{0}_NH3_{2}_{1}_mom0_QA.fits'.format(region_name,file_extension,line_i) file_rms='{0}/{0}_NH3_{2}_{1}_rms_QA.fits'.format(region_name,file_extension,line_i) file_rms_mom='{0}/{0}_NH3_{2}_{1}_mom0_sigma_QA.fits'.format(region_name,file_extension,line_i) file_temp='{0}/{0}_NH3_{2}_{1}_masked_temp.fits'.format(region_name,file_extension,line_i) # Load pyspeckit cube pycube = pyspeckit.Cube(file_in) if 'FITTYPE' in fits.getheader(fit_file): # 'FITTYPE' is not present in old versions of the parameter files pycube.load_model_fit( fit_file, npars=6, npeaks=1) else: if not 'cold_ammonia' in pycube.specfit.Registry.multifitters: pycube.specfit.Registry.add_fitter('cold_ammonia',ammonia.cold_ammonia_model(),6) pycube.load_model_fit( fit_file, npars=6, npeaks=1, fittype='cold_ammonia') # If threshold is not defined, then use the machine accuracy if threshold == None: threshold=np.finfo(pycube.data.dtype).eps # Get model cube from pyspeckit, this take some time modelcube = pycube.get_modelcube() # Use spectral cube to calculate integrated intensity maps cube_raw = SpectralCube.read(file_in) # in km/s not Hz cube = cube_raw.with_spectral_unit(u.km / u.s,velocity_convention='radio') if trim_edge: cube = trim_edge_spectral_cube(cube) vaxis=cube.spectral_axis dv=np.abs(vaxis[1]-vaxis[0]) # define mask mask3d = modelcube > threshold # What to do with pixels without signal # Calculate mean velocity and velocity dispersion vmap=pycube.parcube[4,:,:] sigma_map=pycube.parcube[3,:,:] vmean=np.mean(vmap[vmap != 0])*u.km/u.s if line_i == '11': sigma_v=( np.median(sigma_map[vmap != 0]) + 0.15)*u.km/u.s else: sigma_v=( np.median(sigma_map[vmap != 0]))*u.km/u.s total_spc=np.sqrt( (vaxis-vmean)**2)/sigma_v < 3.0 # im_mask=np.sum(mask3d, axis=0) # Here checking for bad fits. Places where parameter uncertainties are zero or unreasonably low # Probably a more elegant way to do this! for ii in np.arange( im_mask.shape[1]): for jj in np.arange( im_mask.shape[0]): if ((im_mask[jj,ii] == 0) or (pycube.parcube[3,jj,ii] < 3*pycube.errcube[3,jj,ii]) or (pycube.errcube[4,jj,ii] == 0) or (pycube.errcube[1,jj,ii] < 0.01) or (pycube.parcube[0,jj,ii] == 5)): mask3d[:,jj,ii] = total_spc n_chan=np.sum(mask3d, axis=0) # create masked cube cube2 = cube.with_mask(mask3d) cube3 = cube.with_mask(~mask3d) # if save_masked: cube2.write( file_temp, overwrite=True) # calculate moment map moment_0 = cube2.moment(axis=0) moment_0.write( file_out, overwrite=True) rms=cube3.std(axis=0) rms.write( file_rms, overwrite=True)
line = 'NH3_11' OneOneFile = 'nh3_data/{0}_NH3_11_{1}_trim.fits'.format(region, file_extension) TwoTwoFile = 'nh3_data/{0}_NH3_22_{1}_trim.fits'.format(region, file_extension) FitFile = 'propertyMaps/{0}_parameter_maps_{1}_flag.fits'.format( region, file_extension) cube11 = pyspeckit.Cube(OneOneFile) cube11.unit = 'K' cube22 = pyspeckit.Cube(TwoTwoFile) cube22.unit = 'K' cubes = pyspeckit.CubeStack([cube11, cube22]) cubes.unit = 'K' if not 'cold_ammonia' in cubes.specfit.Registry.multifitters: cubes.specfit.Registry.add_fitter('cold_ammonia', ammonia.cold_ammonia_model(), 6) #cubes.load_model_fit(FitFile,6,npeaks=1,fittype='cold_ammonia') #cubes.specfit.parinfo[5]['fixed'] = True pix_coords = [54, 184] sp = cubes.get_spectrum(pix_coords[0], pix_coords[1]) F = False T = True sp.specfit(fittype='cold_ammonia', guesses=[10, 3, 14, 0.3, 3.33, 0], fixed=[F, F, F, F, F, T]) #sp.specfit(fittype='cold_ammonia',guesses=[8,3,14,0.24,3.33,0],fixed=[F,F,F,F,F,T]) # Set up plot parameters
def spec_curve_fit(bin_num, map_name=map_column_dens): # following loop has not good style. One should build in some break statements or error messages # if files repeatedly appear in loop. for one_file in files: if 'NH3_11' in one_file: file_name_NH3_11 = one_file if 'NH3_22' in one_file: file_name_NH3_22 = one_file if 'NH3_33' in one_file: file_name_NH3_33 = one_file y, x, med = binning(bin_width, bin_num) s11, _, offset_velocity11, sp_av11 = averaging_over_dopplervel( file_name_NH3_11, y, x) s22, _, offset_velocity22, sp_av22 = averaging_over_dopplervel( file_name_NH3_22, y, x) s33, _, offset_velocity33, sp_av33 = averaging_over_dopplervel( file_name_NH3_33, y, x) xarr11 = SpectroscopicAxis(offset_velocity11 * u.km / u.s, velocity_convention='radio', refX=freq_dict['oneone']).as_unit(u.GHz) xarr22 = SpectroscopicAxis(offset_velocity22 * u.km / u.s, velocity_convention='radio', refX=freq_dict['twotwo']).as_unit(u.GHz) xarr33 = SpectroscopicAxis(offset_velocity33 * u.km / u.s, velocity_convention='radio', refX=freq_dict['threethree']).as_unit(u.GHz) sp11 = psk.Spectrum(data=s11, xarr=xarr11, xarrkwargs={'unit': 'km/s'}, unit='K') sp22 = psk.Spectrum(data=s22, xarr=xarr22, xarrkwargs={'unit': 'km/s'}, unit='K') sp33 = psk.Spectrum(data=s33, xarr=xarr33, xarrkwargs={'unit': 'km/s'}, unit='K') # This joins all the spectra together into one object. allspec = psk.Spectra([sp11, sp22, sp33]) allspec.xarr.as_unit('Hz', velocity_convention='radio') # This add the cold_ammonia model to the list of things we can use for fitting allspec.specfit.Registry.add_fitter('cold_ammonia', ammonia.cold_ammonia_model(), 6) # This does the fit. The values of the guess are # Kinetic Temperature (usually about 15 to 25 K) # Excitation Temperature (between 2.73 K and the excitation temperature) # Log Column Density of ammonia # Line width (~1 km/s) # Offset velocity (you will usually use 0 instead of 8.5) # Ortho fraction (leave at 0) allspec.specfit(fittype='cold_ammonia', guesses=[23, 5, 13.1, 1, 0, 0]) # You can make a plot here. fig = plt.figure() allspec.plotter() allspec.specfit.plot_fit(lw=1, components=True) plt.xlim((23.692, 23.697)) # plt.xlim((23.72,23.725)) # plt.xlim((23.8692, 23.8708)) # plt.savefig("OrionA:pyspeckit_fit_bin_width=%rthis_bin=%r.ps" %(bin_width, this_bin)) plt.savefig("Map=%r:bin_num=%r_pyspeckit_fit_NH3_11TEST.ps" % (map_name, bin_num)) plt.show() # returns the values of the fitted parameters: T_K, T_ex, N, sigma, v, F_0 return allspec.specfit.parinfo, allspec.specfit.parinfo.errors
def cubefit(region='NGC1333', blorder=1, vmin=5, vmax=15, do_plot=False, snr_min=5.0, multicore=1, file_extension=None, mask_function = None): """ Fit NH3(1,1) and (2,2) cubes for the requested region. It fits all pixels with SNR larger than requested. Initial guess is based on moment maps and neighboring pixels. The fitting can be done in parallel mode using several cores, however, this is dangerous for large regions, where using a good initial guess is important. It stores the result in a FITS cube. TODO: -Improve initial guess Parameters ---------- region : str Name of region to reduce blorder : int order of baseline removed vmin : numpy.float Minimum centroid velocity to plot, in km/s. vmax : numpy.float Maximum centroid velocity to plot, in km/s. do_plot : bool If True, then a map of the region to map is shown. snr_min : numpy.float Minimum signal to noise ratio of the spectrum to be fitted. multicore : int Numbers of cores to use for parallel processing. file_extension : str File extension of the input maps. Default is 'base#' where # is the blorder parameter above. mask_function : fun function to create a custom made mask for analysis. Defaults to using `default_masking` """ if file_extension: root = file_extension else: root = 'base{0}'.format(blorder) OneOneIntegrated = '{0}/{0}_NH3_11_base{1}_mom0.fits'.format(region,root) OneOneFile = '{0}/{0}_NH3_11_base{1}.fits'.format(region,root) RMSFile = '{0}/{0}_NH3_11_base{1}_rms.fits'.format(region,root) TwoTwoFile = '{0}/{0}_NH3_22_base{1}.fits'.format(region,root) ThreeThreeFile = '{0}/{0}_NH3_33_base{1}.fits'.format(region,root) cube11sc = SpectralCube.read(OneOneFile) cube22sc = SpectralCube.read(TwoTwoFile) errmap11 = fits.getdata(RMSFile) rms = np.nanmedian(errmap11) snr = cube11sc.filled_data[:].value/errmap11 peaksnr = np.max(snr,axis=0) if mask_function is None: planemask = default_masking(peaksnr,snr_min = snr_min) else: planemask = mask_function(peaksnr,snr_min = snr_min) #planemask = (peaksnr>20) * (errmap11 < 0.2) mask = (snr>3)*planemask maskcube = cube11sc.with_mask(mask.astype(bool)) maskcube = maskcube.with_spectral_unit(u.km/u.s,velocity_convention='radio') slab = maskcube.spectral_slab( vmax*u.km/u.s, vmin*u.km/u.s) w11=slab.moment( order=0, axis=0).value peakloc = np.nanargmax(w11) ymax,xmax = np.unravel_index(peakloc,w11.shape) moment1 = slab.moment( order=1, axis=0).value moment2 = (slab.moment( order=2, axis=0).value)**0.5 moment2[np.isnan(moment2)]=0.2 moment2[moment2<0.2]=0.2 cube11 = pyspeckit.Cube(OneOneFile,maskmap=planemask) cube11.unit="K" cube22 = pyspeckit.Cube(TwoTwoFile,maskmap=planemask) cube22.unit="K" #cube33 = pyspeckit.Cube(ThreeThreeFile,maskmap=planemask) #cube33.unit="K" # removed as long as we're not modeling OPR cubes = pyspeckit.CubeStack([cube11,cube22],maskmap=planemask) cubes.unit="K" guesses = np.zeros((6,)+cubes.cube.shape[1:]) moment1[moment1<vmin] = vmin+0.2 moment1[moment1>vmax] = vmax-0.2 guesses[0,:,:] = 12 # Kinetic temperature guesses[1,:,:] = 3 # Excitation Temp guesses[2,:,:] = 14.5 # log(column) guesses[3,:,:] = moment2 # Line width / 5 (the NH3 moment overestimates linewidth) guesses[4,:,:] = moment1 # Line centroid guesses[5,:,:] = 0.0 # F(ortho) - ortho NH3 fraction (fixed) if do_plot: import matplotlib.pyplot as plt plt.imshow( w11, origin='lower',interpolation='nearest') plt.show() F=False T=True if not 'cold_ammonia' in cubes.specfit.Registry.multifitters: cubes.specfit.Registry.add_fitter('cold_ammonia',ammonia.cold_ammonia_model(),6) print('start fit') cubes.fiteach(fittype='cold_ammonia', guesses=guesses, integral=False, verbose_level=3, fixed=[F,F,F,F,F,T], signal_cut=2, limitedmax=[F,F,T,F,T,T], maxpars=[0,0,17.0,0,vmax,1], limitedmin=[T,T,T,T,T,T], minpars=[5,2.8,12.0,0.04,vmin,0], start_from_point=(xmax,ymax), use_neighbor_as_guess=True, position_order = 1/peaksnr, errmap=errmap11, multicore=multicore) fitcubefile = fits.PrimaryHDU(data=np.concatenate([cubes.parcube,cubes.errcube]), header=cubes.header) fitcubefile.header.update('PLANE1','TKIN') fitcubefile.header.update('PLANE2','TEX') fitcubefile.header.update('PLANE3','COLUMN') fitcubefile.header.update('PLANE4','SIGMA') fitcubefile.header.update('PLANE5','VELOCITY') fitcubefile.header.update('PLANE6','FORTHO') fitcubefile.header.update('PLANE7','eTKIN') fitcubefile.header.update('PLANE8','eTEX') fitcubefile.header.update('PLANE9','eCOLUMN') fitcubefile.header.update('PLANE10','eSIGMA') fitcubefile.header.update('PLANE11','eVELOCITY') fitcubefile.header.update('PLANE12','eFORTHO') fitcubefile.header.update('CDELT3',1) fitcubefile.header.update('CTYPE3','FITPAR') fitcubefile.header.update('CRVAL3',0) fitcubefile.header.update('CRPIX3',1) fitcubefile.writeto("{0}/{0}_parameter_maps_{1}.fits".format(region,root),clobber=True)