Loading etl/mdl/mdl_psk_decomposition.py +71 −28 Changes for etl/mdl/mdl_psk_decomposition.py: 71 added lines, 28 removed lines. Original line number Diff line number Diff line Loading @@ -10,27 +10,57 @@ from astropy.constants import c as speed_of_light matplotlib.use('Qt5Agg') def get_bic(residuals: np.array, rms: float, number_of_parameters: int, number_of_samples: int, with_likehood: bool = False): if with_likehood is True: bic = (np.nansum(residuals ** 2, axis=0) / (rms ** 2) + number_of_samples * np.log(2 * np.pi) + number_of_samples * np.log(rms ** 2) + np.log(number_of_samples) * number_of_parameters) else: bic = (number_of_samples * np.log(np.nansum(residuals ** 2, axis=0) / number_of_samples) + np.log(number_of_samples) * number_of_parameters) return bic datadir = os.path.join('assets', 'data') filename = 'G332.96_CH3OH_3mm_feather.fits' # filename = 'G332.96_CH3OH_3mm_feather.fits' # filename = 'G28_CH3OH_3mm_feather.fits' # filename = 'G12_CH3OH_3mm_ACA_MA.fits' filename = 'G14_CH3OH_3mm_feather.fits' # filename = 'test_subcube.fits' cube = pyspeckit.Cube(os.path.join(datadir, filename), format='fits') rest_frequencies = np.array([96.739358, 96.74142, 96.744545, 96.755501]) * u.GHz freq_to_vel = u.doppler_radio(rest_frequencies[0]) vlsr = -67.6 * u.km / u.s # vlsr = -67.6 * u.km / u.s # vlsr = 79.6 * u.km / u.s # vlsr = 34.4 * u.km / u.s vlsr = 40.5 * u.km / u.s frequency_offset = vlsr.to(u.Hz, equivalencies=freq_to_vel) - rest_frequencies[0] doppler_adjusted_frequencies = rest_frequencies + frequency_offset cube = cube.slice(96.755, 96.775, unit=u.GHz) #cube = cube.slice(96.755, 96.775, unit=u.GHz) # cube = cube.slice(96.700, 96.740, unit=u.GHz) cube = cube.slice(96.710, 96.750, unit=u.GHz) delta_freq = rest_frequencies.diff() rms = 0.0034 # rms = 0.0034 # rms = 0.003 # rms = 0.002 rms = 0.0032 # Test double component # cube.cube[:, 0, 0] = np.roll(cube.cube[:, 0, 0], -15) + cube.cube[:, 0, 0] spec_sum = np.nansum(cube.cube, axis=0) # spec_sum = -np.where(spec_sum < 0, 0, spec_sum) # spec_sum[255:275, 50:70] *= -1 threshold_spec_sum = 4 * np.sqrt(cube.shape[0]) * rms starting_point = np.unravel_index(np.argmax(spec_sum), spec_sum.shape) threshold_spec_sum = 3 * np.sqrt(cube.shape[0]) * rms fit_mask = np.where(spec_sum > threshold_spec_sum, True, False) linewidth_guess = 1.5 * u.km / u.s linewidth_guess_hz = linewidth_guess / speed_of_light.to(u.km / u.s) * rest_frequencies[0].to(u.Hz).value / 2.355 tied_pars = { 'PAR_VELO': 1, 'DELTA_FREQ_1': delta_freq[0].to(u.Hz).value, Loading @@ -40,12 +70,12 @@ tied_pars = { } with open(os.path.join('assets', 'templates', 'tied_3mm.template'), 'r') as template: tied = template.read().replace('\n', '').format(**tied_pars).split(',') limits = [(rms, 0) for idx in range(len(tied))] limits = [(rms, 10) for idx in range(len(tied))] limited = [(True, False) for idx in range(len(tied))] guesses = [0.029, doppler_adjusted_frequencies[0].to(u.Hz).value, 50000, 0.029, doppler_adjusted_frequencies[1].to(u.Hz).value, 50000, 0.01, doppler_adjusted_frequencies[2].to(u.Hz).value, 50000, 0.005, doppler_adjusted_frequencies[3].to(u.Hz).value, 50000] guesses = [0.029, doppler_adjusted_frequencies[0].to(u.Hz).value, linewidth_guess_hz, 0.029, doppler_adjusted_frequencies[1].to(u.Hz).value, linewidth_guess_hz, 0.01, doppler_adjusted_frequencies[2].to(u.Hz).value, linewidth_guess_hz, 0.005, doppler_adjusted_frequencies[3].to(u.Hz).value, linewidth_guess_hz] cube.fiteach(guesses=guesses, start_from_point=(starting_point[1], starting_point[0]), Loading @@ -59,18 +89,24 @@ cube.fiteach(guesses=guesses, residuals = cube.cube - cube.get_modelcube(update=True) number_of_parameters = tied.count('') bic = - np.nansum(-residuals ** 2, axis=0) / (rms ** 2) - cube.shape[0] * np.log(np.sqrt(2 * np.pi) * rms) + np.log( cube.shape[0]) * number_of_parameters bic = get_bic(residuals=residuals, rms=rms, number_of_parameters=number_of_parameters, number_of_samples=cube.shape[0], with_likehood=True) threshold = 2 * (cube.shape[0]) - cube.shape[0] * np.log(np.sqrt(2 * np.pi) * rms) + np.log( cube.shape[0]) * number_of_parameters threshold = (1.5 * cube.shape[0] + cube.shape[0] * np.log(2 * np.pi) + cube.shape[0] * np.log(rms ** 2) + np.log(cube.shape[0]) * number_of_parameters) fit_results = cube.parcube.copy() for idx_frequency in range(number_of_parameters // 6): idx_shift = idx_frequency * 12 velocity_map = (cube.parcube[1 + idx_shift, :, :] * u.Hz).to(u.km / u.s, equivalencies=freq_to_vel).value linewidth_map = 2.355 * ((cube.parcube[2 + idx_shift, :, :] * u.Hz) / rest_frequencies[0].to(u.Hz)).value * speed_of_light.to( linewidth_map = 2.355 * ( (cube.parcube[2 + idx_shift, :, :] * u.Hz) / rest_frequencies[0].to(u.Hz)).value * speed_of_light.to( u.km / u.s).value linewidth_map = np.where(linewidth_map == 0, np.nan, linewidth_map) velocity_map = np.where(velocity_map == 0, np.nan, velocity_map) ratio_map_87_86 = (cube.parcube[6 + idx_shift, :, :] / cube.parcube[idx_shift, :, :]) fit_results[1 + idx_shift, :, :] = velocity_map fit_results[2 + idx_shift, :, :] = linewidth_map Loading @@ -91,11 +127,13 @@ max_components = 3 final_pars = np.zeros((number_of_parameters * max_components, cube.parcube.shape[1], cube.parcube.shape[2])) * np.nan indices_to_keep = np.array((0, 1, 2, 3, 6, 9)) _indices_to_keep = np.array((0, 1, 2, 3, 6, 9)) final_pars[0:number_of_parameters, :, :] = np.where(fit_mask, fit_results[indices_to_keep, :, :], np.nan) _indices_to_keep = indices_to_keep.copy() final_pars[0:number_of_parameters, :, :] = np.where((fit_mask == True) & (fit_results[0, :, :] > 0), fit_results[indices_to_keep, :, :], np.nan) for components in range(max_components - 1): refit_mask = np.where(bic > threshold, True, False) final_pars_old = final_pars.copy() if np.sum(refit_mask) > 0: idx_shift = (components + 1) * 12 Loading @@ -109,14 +147,14 @@ for components in range(max_components - 1): with open(os.path.join('assets', 'templates', 'tied_3mm.template'), 'r') as template: tied += template.read().replace('\n', '').format(**tied_pars).split(',') guesses += [0.029, doppler_adjusted_frequencies[0].to(u.Hz).value + 1e5 * idx_shift, 50000, 0.029, doppler_adjusted_frequencies[1].to(u.Hz).value + 1e5 * idx_shift, 50000, 0.01, doppler_adjusted_frequencies[2].to(u.Hz).value + 1e5 * idx_shift, 50000, 0.005, doppler_adjusted_frequencies[3].to(u.Hz).value + 1e5 * idx_shift, 50000] guesses += [0.029, doppler_adjusted_frequencies[0].to(u.Hz).value + 1e5 * idx_shift, linewidth_guess_hz, 0.029, doppler_adjusted_frequencies[1].to(u.Hz).value + 1e5 * idx_shift, linewidth_guess_hz, 0.01, doppler_adjusted_frequencies[2].to(u.Hz).value + 1e5 * idx_shift, linewidth_guess_hz, 0.005, doppler_adjusted_frequencies[3].to(u.Hz).value + 1e5 * idx_shift, linewidth_guess_hz] limits = [(rms, 0) for idx in range(len(tied))] limited = [(True, False) for idx in range(len(tied))] starting_point = np.unravel_index(np.argmax(spec_sum[refit_mask]), spec_sum.shape) starting_point = np.unravel_index(np.argmax(np.where(refit_mask == True, spec_sum, -1)), spec_sum.shape) cube.fiteach(guesses=guesses, start_from_point=(starting_point[1], starting_point[0]), Loading @@ -127,13 +165,18 @@ for components in range(max_components - 1): use_nearest_as_guess=True) residuals = cube.cube - cube.get_modelcube(update=True) number_of_parameters = tied.count('') new_bic = - np.nansum(-residuals ** 2, axis=0) / (rms ** 2) - cube.shape[0] * np.log( np.sqrt(2 * np.pi) * rms) + np.log(cube.shape[0]) * number_of_parameters new_bic = get_bic(residuals=residuals, rms=rms, number_of_parameters=number_of_parameters, number_of_samples=cube.shape[0], with_likehood=True) fit_results = cube.parcube.copy() for idx_to_change in range(components + 2): velocity_map = (cube.parcube[1 + (12 * idx_to_change), :, :] * u.Hz).to(u.km / u.s, equivalencies=freq_to_vel).value linewidth_map = 2.355 * ((cube.parcube[2 + (12 * idx_to_change), :, :] * u.Hz) / rest_frequencies[0].to(u.Hz)).value * speed_of_light.to( velocity_map = (cube.parcube[1 + (12 * idx_to_change), :, :] * u.Hz).to(u.km / u.s, equivalencies=freq_to_vel).value linewidth_map = 2.355 * ((cube.parcube[2 + (12 * idx_to_change), :, :] * u.Hz) / rest_frequencies[0].to( u.Hz)).value * speed_of_light.to( u.km / u.s).value ratio_map_87_86 = (cube.parcube[6 + (12 * idx_to_change), :, :] / cube.parcube[(12 * idx_to_change), :, :]) fit_results[1 + (12 * idx_to_change), :, :] = velocity_map Loading @@ -142,7 +185,7 @@ for components in range(max_components - 1): final_pars[0:6 + 6 * (components + 1), :, :] = np.where((bic / new_bic > 1) & (refit_mask), fit_results[ _indices_to_keep, :, :], final_pars[0:6 + 6 * (components + 1), :, :]) final_pars_old[0:6 + 6 * (components + 1), :, :]) print(bic / new_bic) bic = new_bic Loading Loading
etl/mdl/mdl_psk_decomposition.py +71 −28 Changes for etl/mdl/mdl_psk_decomposition.py: 71 added lines, 28 removed lines. Original line number Diff line number Diff line Loading @@ -10,27 +10,57 @@ from astropy.constants import c as speed_of_light matplotlib.use('Qt5Agg') def get_bic(residuals: np.array, rms: float, number_of_parameters: int, number_of_samples: int, with_likehood: bool = False): if with_likehood is True: bic = (np.nansum(residuals ** 2, axis=0) / (rms ** 2) + number_of_samples * np.log(2 * np.pi) + number_of_samples * np.log(rms ** 2) + np.log(number_of_samples) * number_of_parameters) else: bic = (number_of_samples * np.log(np.nansum(residuals ** 2, axis=0) / number_of_samples) + np.log(number_of_samples) * number_of_parameters) return bic datadir = os.path.join('assets', 'data') filename = 'G332.96_CH3OH_3mm_feather.fits' # filename = 'G332.96_CH3OH_3mm_feather.fits' # filename = 'G28_CH3OH_3mm_feather.fits' # filename = 'G12_CH3OH_3mm_ACA_MA.fits' filename = 'G14_CH3OH_3mm_feather.fits' # filename = 'test_subcube.fits' cube = pyspeckit.Cube(os.path.join(datadir, filename), format='fits') rest_frequencies = np.array([96.739358, 96.74142, 96.744545, 96.755501]) * u.GHz freq_to_vel = u.doppler_radio(rest_frequencies[0]) vlsr = -67.6 * u.km / u.s # vlsr = -67.6 * u.km / u.s # vlsr = 79.6 * u.km / u.s # vlsr = 34.4 * u.km / u.s vlsr = 40.5 * u.km / u.s frequency_offset = vlsr.to(u.Hz, equivalencies=freq_to_vel) - rest_frequencies[0] doppler_adjusted_frequencies = rest_frequencies + frequency_offset cube = cube.slice(96.755, 96.775, unit=u.GHz) #cube = cube.slice(96.755, 96.775, unit=u.GHz) # cube = cube.slice(96.700, 96.740, unit=u.GHz) cube = cube.slice(96.710, 96.750, unit=u.GHz) delta_freq = rest_frequencies.diff() rms = 0.0034 # rms = 0.0034 # rms = 0.003 # rms = 0.002 rms = 0.0032 # Test double component # cube.cube[:, 0, 0] = np.roll(cube.cube[:, 0, 0], -15) + cube.cube[:, 0, 0] spec_sum = np.nansum(cube.cube, axis=0) # spec_sum = -np.where(spec_sum < 0, 0, spec_sum) # spec_sum[255:275, 50:70] *= -1 threshold_spec_sum = 4 * np.sqrt(cube.shape[0]) * rms starting_point = np.unravel_index(np.argmax(spec_sum), spec_sum.shape) threshold_spec_sum = 3 * np.sqrt(cube.shape[0]) * rms fit_mask = np.where(spec_sum > threshold_spec_sum, True, False) linewidth_guess = 1.5 * u.km / u.s linewidth_guess_hz = linewidth_guess / speed_of_light.to(u.km / u.s) * rest_frequencies[0].to(u.Hz).value / 2.355 tied_pars = { 'PAR_VELO': 1, 'DELTA_FREQ_1': delta_freq[0].to(u.Hz).value, Loading @@ -40,12 +70,12 @@ tied_pars = { } with open(os.path.join('assets', 'templates', 'tied_3mm.template'), 'r') as template: tied = template.read().replace('\n', '').format(**tied_pars).split(',') limits = [(rms, 0) for idx in range(len(tied))] limits = [(rms, 10) for idx in range(len(tied))] limited = [(True, False) for idx in range(len(tied))] guesses = [0.029, doppler_adjusted_frequencies[0].to(u.Hz).value, 50000, 0.029, doppler_adjusted_frequencies[1].to(u.Hz).value, 50000, 0.01, doppler_adjusted_frequencies[2].to(u.Hz).value, 50000, 0.005, doppler_adjusted_frequencies[3].to(u.Hz).value, 50000] guesses = [0.029, doppler_adjusted_frequencies[0].to(u.Hz).value, linewidth_guess_hz, 0.029, doppler_adjusted_frequencies[1].to(u.Hz).value, linewidth_guess_hz, 0.01, doppler_adjusted_frequencies[2].to(u.Hz).value, linewidth_guess_hz, 0.005, doppler_adjusted_frequencies[3].to(u.Hz).value, linewidth_guess_hz] cube.fiteach(guesses=guesses, start_from_point=(starting_point[1], starting_point[0]), Loading @@ -59,18 +89,24 @@ cube.fiteach(guesses=guesses, residuals = cube.cube - cube.get_modelcube(update=True) number_of_parameters = tied.count('') bic = - np.nansum(-residuals ** 2, axis=0) / (rms ** 2) - cube.shape[0] * np.log(np.sqrt(2 * np.pi) * rms) + np.log( cube.shape[0]) * number_of_parameters bic = get_bic(residuals=residuals, rms=rms, number_of_parameters=number_of_parameters, number_of_samples=cube.shape[0], with_likehood=True) threshold = 2 * (cube.shape[0]) - cube.shape[0] * np.log(np.sqrt(2 * np.pi) * rms) + np.log( cube.shape[0]) * number_of_parameters threshold = (1.5 * cube.shape[0] + cube.shape[0] * np.log(2 * np.pi) + cube.shape[0] * np.log(rms ** 2) + np.log(cube.shape[0]) * number_of_parameters) fit_results = cube.parcube.copy() for idx_frequency in range(number_of_parameters // 6): idx_shift = idx_frequency * 12 velocity_map = (cube.parcube[1 + idx_shift, :, :] * u.Hz).to(u.km / u.s, equivalencies=freq_to_vel).value linewidth_map = 2.355 * ((cube.parcube[2 + idx_shift, :, :] * u.Hz) / rest_frequencies[0].to(u.Hz)).value * speed_of_light.to( linewidth_map = 2.355 * ( (cube.parcube[2 + idx_shift, :, :] * u.Hz) / rest_frequencies[0].to(u.Hz)).value * speed_of_light.to( u.km / u.s).value linewidth_map = np.where(linewidth_map == 0, np.nan, linewidth_map) velocity_map = np.where(velocity_map == 0, np.nan, velocity_map) ratio_map_87_86 = (cube.parcube[6 + idx_shift, :, :] / cube.parcube[idx_shift, :, :]) fit_results[1 + idx_shift, :, :] = velocity_map fit_results[2 + idx_shift, :, :] = linewidth_map Loading @@ -91,11 +127,13 @@ max_components = 3 final_pars = np.zeros((number_of_parameters * max_components, cube.parcube.shape[1], cube.parcube.shape[2])) * np.nan indices_to_keep = np.array((0, 1, 2, 3, 6, 9)) _indices_to_keep = np.array((0, 1, 2, 3, 6, 9)) final_pars[0:number_of_parameters, :, :] = np.where(fit_mask, fit_results[indices_to_keep, :, :], np.nan) _indices_to_keep = indices_to_keep.copy() final_pars[0:number_of_parameters, :, :] = np.where((fit_mask == True) & (fit_results[0, :, :] > 0), fit_results[indices_to_keep, :, :], np.nan) for components in range(max_components - 1): refit_mask = np.where(bic > threshold, True, False) final_pars_old = final_pars.copy() if np.sum(refit_mask) > 0: idx_shift = (components + 1) * 12 Loading @@ -109,14 +147,14 @@ for components in range(max_components - 1): with open(os.path.join('assets', 'templates', 'tied_3mm.template'), 'r') as template: tied += template.read().replace('\n', '').format(**tied_pars).split(',') guesses += [0.029, doppler_adjusted_frequencies[0].to(u.Hz).value + 1e5 * idx_shift, 50000, 0.029, doppler_adjusted_frequencies[1].to(u.Hz).value + 1e5 * idx_shift, 50000, 0.01, doppler_adjusted_frequencies[2].to(u.Hz).value + 1e5 * idx_shift, 50000, 0.005, doppler_adjusted_frequencies[3].to(u.Hz).value + 1e5 * idx_shift, 50000] guesses += [0.029, doppler_adjusted_frequencies[0].to(u.Hz).value + 1e5 * idx_shift, linewidth_guess_hz, 0.029, doppler_adjusted_frequencies[1].to(u.Hz).value + 1e5 * idx_shift, linewidth_guess_hz, 0.01, doppler_adjusted_frequencies[2].to(u.Hz).value + 1e5 * idx_shift, linewidth_guess_hz, 0.005, doppler_adjusted_frequencies[3].to(u.Hz).value + 1e5 * idx_shift, linewidth_guess_hz] limits = [(rms, 0) for idx in range(len(tied))] limited = [(True, False) for idx in range(len(tied))] starting_point = np.unravel_index(np.argmax(spec_sum[refit_mask]), spec_sum.shape) starting_point = np.unravel_index(np.argmax(np.where(refit_mask == True, spec_sum, -1)), spec_sum.shape) cube.fiteach(guesses=guesses, start_from_point=(starting_point[1], starting_point[0]), Loading @@ -127,13 +165,18 @@ for components in range(max_components - 1): use_nearest_as_guess=True) residuals = cube.cube - cube.get_modelcube(update=True) number_of_parameters = tied.count('') new_bic = - np.nansum(-residuals ** 2, axis=0) / (rms ** 2) - cube.shape[0] * np.log( np.sqrt(2 * np.pi) * rms) + np.log(cube.shape[0]) * number_of_parameters new_bic = get_bic(residuals=residuals, rms=rms, number_of_parameters=number_of_parameters, number_of_samples=cube.shape[0], with_likehood=True) fit_results = cube.parcube.copy() for idx_to_change in range(components + 2): velocity_map = (cube.parcube[1 + (12 * idx_to_change), :, :] * u.Hz).to(u.km / u.s, equivalencies=freq_to_vel).value linewidth_map = 2.355 * ((cube.parcube[2 + (12 * idx_to_change), :, :] * u.Hz) / rest_frequencies[0].to(u.Hz)).value * speed_of_light.to( velocity_map = (cube.parcube[1 + (12 * idx_to_change), :, :] * u.Hz).to(u.km / u.s, equivalencies=freq_to_vel).value linewidth_map = 2.355 * ((cube.parcube[2 + (12 * idx_to_change), :, :] * u.Hz) / rest_frequencies[0].to( u.Hz)).value * speed_of_light.to( u.km / u.s).value ratio_map_87_86 = (cube.parcube[6 + (12 * idx_to_change), :, :] / cube.parcube[(12 * idx_to_change), :, :]) fit_results[1 + (12 * idx_to_change), :, :] = velocity_map Loading @@ -142,7 +185,7 @@ for components in range(max_components - 1): final_pars[0:6 + 6 * (components + 1), :, :] = np.where((bic / new_bic > 1) & (refit_mask), fit_results[ _indices_to_keep, :, :], final_pars[0:6 + 6 * (components + 1), :, :]) final_pars_old[0:6 + 6 * (components + 1), :, :]) print(bic / new_bic) bic = new_bic Loading