def refit_2comp_wide(reg, snr_min=3): ncomp = [1, 2] # load the fitted parameters for nc in ncomp: if not str(nc) in reg.ucube.pcubes: if not str(nc) in reg.ucube.paraPaths: reg.ucube.paraPaths[str(nc)]= '{}/{}_{}vcomp.fits'.format(reg.ucube.paraDir, reg.ucube.paraNameRoot, nc) if nc==2 and not ('2_noWideDelV' in reg.ucube.paraPaths): reg.ucube.load_model_fit(reg.ucube.paraPaths[str(nc)], nc) reg.ucube.pcubes['2_noWideDelV'] =\ "{}_noWideDelV".format(os.path.splitext(reg.ucube.paraPaths[str(nc)])[0]) else: reg.ucube.load_model_fit(reg.ucube.paraPaths[str(nc)], nc) wide_comp_guess = get_2comp_wide_guesses(reg) # use the one component fit and the refined 1-componet guess for the residual to perform the two components fit final_guess = np.append(reg.ucube.pcubes['1'].parcube, wide_comp_guess, axis=0) # fit over where one-component was a better fit in the last iteration (since we are only interested in recovering # a second componet that is found in wide seperation) lnk21 = reg.ucube.get_AICc_likelihood(2, 1) mask = lnk21 < 5 mask = dilation(mask) # combine the mask with where 1 component model is better fitted than the noise to save some computational time lnk10 = reg.ucube.get_AICc_likelihood(1, 0) mask = np.logical_and(mask, lnk10 > 5) mask_size = np.sum(mask) print("refit mask size: {}".format(mask_size)) if mask_size > 1: ucube_new = UCube.UltraCube(reg.ucube.cubefile) ucube_new.fit_cube(ncomp=[2], maskmap=mask, snr_min=snr_min, guesses=final_guess) # do a model comparison between the new two component fit verses the original one lnk_NvsO = UCube.calc_AICc_likelihood(ucube_new, 2, 2, ucube_B=reg.ucube) # mask over where one comp fit is more robust good_mask = np.logical_and(lnk_NvsO > 0, lnk21 < 5) # replace the values replace_para(reg.ucube.pcubes['2'], ucube_new.pcubes['2'], good_mask) # save the final fit model #UCube.save_fit(pcube_final_2, reg.ucube.paraPaths['2'], ncomp=2) #save_fit(pcube, savename, ncomp) else: print("not enough pixels to refit, no-refit is done")
def fit_best_2comp_residual_cnv(reg, window_hwidth=3.5, res_snr_cut=5, savefit=True): # fit the residual of the best fitted model (note, this approach may not hold well if the two-slab model # insufficiently at describing the observation. Luckily, however, this fit is only to provide initial guess for the # final fit) # the default window_hwidth = 3.5 is about half-way between the main hyperfine and the satellite # need a mechanism to make sure reg.ucube.pcubes['1'], reg.ucube.pcubes['2'] exists cube_res_cnv = get_best_2comp_residual_cnv(reg, masked=True, window_hwidth=window_hwidth, res_snr_cut=res_snr_cut) ncomp = 1 # note: no further masking is applied to vmap, as we assume only pixels with good vlsr will be used if not hasattr(reg, 'ucube_cnv'): # if convolved cube was not used to produce initial guesses, use the full resolution 1-comp fit as the reference from scipy.ndimage.filters import median_filter pcube1 = reg.ucube.pcubes['1'] vmap = median_filter(pcube1.parcube[0], size=3) # median smooth within a 3x3 square vmap = cnvtool.regrid(vmap, header1=get_skyheader(pcube1.header), header2=get_skyheader(cube_res_cnv.header)) else: vmap = reg.ucube_cnv.pcubes['1'].parcube[0] moms_res_cnv = mmg.vmask_moments(cube_res_cnv, vmap=vmap, window_hwidth=window_hwidth) gg = mmg.moment_guesses(moms_res_cnv[1], moms_res_cnv[2], ncomp, moment0=moms_res_cnv[0]) # should try to use UCubePlus??? may want to avoid saving too many intermediate cube products reg.ucube_res_cnv = UCube.UltraCube(cube=cube_res_cnv) reg.ucube_res_cnv.fit_cube(ncomp=[1], snr_min=3, guesses=gg) # save the residual fit if savefit: oriParaPath = reg.ucube.paraPaths[str(ncomp)] savename = "{}_onBestResidual.fits".format(os.path.splitext(oriParaPath)[0]) reg.ucube_res_cnv.save_fit(savename, ncomp)
def __init__(self, cubePath, paraNameRoot, paraDir=None, cnv_factor=2): self.cubePath = cubePath self.paraNameRoot = paraNameRoot self.paraDir = paraDir self.ucube = UCube.UCubePlus(cubePath, paraNameRoot=paraNameRoot, paraDir=paraDir, cnv_factor=cnv_factor) # for convolving cube self.cnv_factor = cnv_factor
def refit_swap_2comp(reg, snr_min=3): ncomp = [1, 2] # load the fitted parameters for nc in ncomp: if not str(nc) in reg.ucube.pcubes: # no need to worry about wide seperation as they likley don't overlap in velocity space reg.ucube.load_model_fit(reg.ucube.paraPaths[str(nc)], nc) # refit only over where two component models are already determined to be better # note: this may miss a few fits where the swapped two-comp may return a better result? lnk21 = reg.ucube.get_AICc_likelihood(2, 1) mask = lnk21 > 5 gc.collect() # swap the parameter of the two slabs and use it as the initial guesses guesses = reg.ucube.pcubes['2'].parcube.copy() for i in range(4): guesses[i], guesses[i+4] = guesses[i+4], guesses[i] ucube_new = UCube.UltraCube(reg.ucube.cubefile) ucube_new.fit_cube(ncomp=[2], maskmap=mask, snr_min=snr_min, guesses=guesses) gc.collect() # do a model comparison between the new two component fit verses the original one lnk_NvsO = UCube.calc_AICc_likelihood(ucube_new, 2, 2, ucube_B=reg.ucube) gc.collect() # adopt the better fit parameters into the final map good_mask = lnk_NvsO > 0 # replace the values replace_para(reg.ucube.pcubes['2'], ucube_new.pcubes['2'], good_mask)
def get_best_2comp_residual_cnv(reg, masked=True, window_hwidth=3.5, res_snr_cut=5): # return convolved residual cube. If masked is True, only convolve over where 'excessive' residual # above a peak SNR value of res_snr_cut masked # need a mechanism to make sure reg.ucube.pcubes['1'], reg.ucube.pcubes['2'] exists res_cube = get_best_2comp_residual(reg) best_res = res_cube._data cube_res = SpectralCube(data=best_res, wcs=reg.ucube.pcubes['2'].wcs.copy(), header=reg.ucube.pcubes['2'].header.copy()) if masked: best_rms = UCube.get_rms(res_cube._data) # calculate the peak SNR value of the best-fit residual over the main hyperfine components vmap = reg.ucube.pcubes['1'].parcube[0] # make want to double check that masked cube always masks out nan values res_main_hf = mmg.vmask_cube(res_cube, vmap, window_hwidth=window_hwidth) if res_main_hf.size > 1e7: # to avoid loading entire cube and stress the memory how = 'slice' else: # note: 'auto' currently returns slice for n > 1e8 how = 'auto' # enable huge operations (note: not needed when "how" is chosen wisely, which it should be) res_main_hf.allow_huge_operations = True res_main_hf_snr = res_main_hf.max(axis=0, how=how).value / best_rms res_main_hf.allow_huge_operations = False # mask out residual with SNR values over the cut threshold mask_res = res_main_hf_snr > res_snr_cut mask_res = dilation(mask_res) cube_res_masked = cube_res.with_mask(~mask_res) else: cube_res_masked = cube_res cube_res_cnv = cnvtool.convolve_sky_byfactor(cube_res_masked, factor=reg.cnv_factor, edgetrim_width=None, snrmasked=False, iterrefine=False) cube_res_cnv = cube_res_cnv.with_spectral_unit(u.km / u.s, velocity_convention='radio') return cube_res_cnv
def get_convolved_cube(reg, update=True, cnv_cubePath=None, edgetrim_width=5, paraNameRoot=None, paraDir=None): if cnv_cubePath is None: root = "conv{0}Xbeam".format(int(np.rint(reg.cnv_factor))) reg.cnv_cubePath = "{0}_{1}.fits".format(os.path.splitext(reg.cubePath)[0], root) else: reg.cnv_cubePath = cnv_cubePath reg.cnv_para_paths ={} if update or (not os.path.isfile(reg.cnv_cubePath)): reg.ucube.convolve_cube(factor=reg.cnv_factor, savename=reg.cnv_cubePath, edgetrim_width=edgetrim_width) if paraNameRoot is None: paraNameRoot = "{}_conv{}Xbeam".format(reg.paraNameRoot, int(np.rint(reg.cnv_factor))) if paraDir is None: paraDir = reg.paraDir reg.ucube_cnv = UCube.UCubePlus(cubefile=reg.cnv_cubePath, paraNameRoot=paraNameRoot, paraDir=paraDir, cnv_factor=reg.cnv_factor)
def get_best_2comp_snr_mod(reg): modbest = get_best_2comp_model(reg) res_cube = get_best_2comp_residual(reg) best_rms = UCube.get_rms(res_cube._data) return np.nanmax(modbest, axis=0)/best_rms
def save_best_2comp_fit(reg): # should be renamed to determine_best_2comp_fit or something along that line # currently use np.nan for pixels with no models ncomp = [1, 2] # ideally, a copy function should be in place of reloading # a new Region object is created start fresh on some of the functions (e.g., aic comparison) reg_final = Region(reg.cubePath, reg.paraNameRoot, reg.paraDir) # start out clean, especially since the deepcopy function doesn't work well for pyspeckit cubes # load the file based on the passed in reg, rather than the default for nc in ncomp: if not str(nc) in reg.ucube.pcubes: reg_final.load_fits(ncomp=[nc]) else: # load files using paths from reg if they exist print("loading model from: {}".format(reg.ucube.paraPaths[str(nc)])) reg_final.ucube.load_model_fit(filename=reg.ucube.paraPaths[str(nc)], ncomp=nc) pcube_final = reg_final.ucube.pcubes['2'].copy('deep') # make the 2-comp para maps with the best fit model lnk21 = reg_final.ucube.get_AICc_likelihood(2, 1) mask = lnk21 > 5 print("2comp pix: {}".format(np.sum(mask))) pcube_final.parcube[:4, ~mask] = reg_final.ucube.pcubes['1'].parcube[:4, ~mask].copy() pcube_final.errcube[:4, ~mask] = reg_final.ucube.pcubes['1'].errcube[:4, ~mask].copy() pcube_final.parcube[4:8, ~mask] = np.nan pcube_final.errcube[4:8, ~mask] = np.nan lnk10 = reg_final.ucube.get_AICc_likelihood(1, 0) mask = lnk10 > 5 pcube_final.parcube[:, ~mask] = np.nan pcube_final.errcube[:, ~mask] = np.nan # use the default file formate to save the finals nc = 2 if not str(nc) in reg_final.ucube.paraPaths: reg_final.ucube.paraPaths[str(nc)] = '{}/{}_{}vcomp.fits'.format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot, nc) savename = "{}_final.fits".format(os.path.splitext(reg_final.ucube.paraPaths['2'])[0]) UCube.save_fit(pcube_final, savename=savename, ncomp=2) hdr2D =reg.ucube.cube.wcs.celestial.to_header() # save the lnk21 map savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para","lnk21")) save_map(lnk21, hdr2D, savename) # save the lnk10 map savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para","lnk10")) save_map(lnk10, hdr2D, savename) # create and save the lnk20 map for reference: lnk20 = reg_final.ucube.get_AICc_likelihood(2, 0) savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para","lnk20")) save_map(lnk20, hdr2D, savename) # save the SNR map snr_map = get_best_2comp_snr_mod(reg_final) savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para","SNR")) save_map(snr_map, hdr2D, savename) # create moment0 map modbest = get_best_2comp_model(reg_final) cube_mod = SpectralCube(data=modbest, wcs=reg_final.ucube.pcubes['2'].wcs.copy(), header=reg_final.ucube.pcubes['2'].header.copy()) # make sure the spectral unit is in km/s before making moment maps cube_mod = cube_mod.with_spectral_unit('km/s', velocity_convention='radio') mom0_mod = cube_mod.moment0() savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para", "model_mom0")) mom0_mod.write(savename, overwrite=True) # created masked mom0 map with model as the mask mom0 = UCube.get_masked_moment(cube=reg_final.ucube.cube, model=modbest, order=0, expand=20, mask=None) savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para", "mom0")) mom0.write(savename, overwrite=True) # save reduced chi-squred maps # would be useful to check if 3rd component is needed savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para", "chi2red_final")) chi_map = UCube.get_chisq(cube=reg_final.ucube.cube, model=modbest, expand=20, reduced=True, usemask=True, mask=None) save_map(chi_map, hdr2D, savename) # save reduced chi-squred maps for 1 comp and 2 comp individually chiRed_1c = reg_final.ucube.get_reduced_chisq(1) chiRed_2c = reg_final.ucube.get_reduced_chisq(2) savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para", "chi2red_1c")) save_map(chiRed_1c, hdr2D, savename) savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para", "chi2red_2c")) save_map(chiRed_2c, hdr2D, savename) return reg