def kurucz2moog(kurucz_path): # gfall08oct17.dat kurucz_all = pd.read_fwf('files/linelist/kurucz/gfall08oct17.dat', colspecs=[(0, 11), (11, 18), (18, 24), (24, 36), (52, 64), (93, 98), (109, 116)], names=[ 'wavelength', 'loggf_init', 'ele', 'E(cm-1)_1', 'E(cm-1)_2', 'C6', 'hpf_frac' ]) kurucz_all['ele'] = kurucz_all['ele'] // 1 + kurucz_all['ele'] % 1 * 10 kurucz_all['EP_1'] = kurucz_all['E(cm-1)_1'] / ( 1 / constants.h / constants.c).to(u.cm**-1 / u.eV).value kurucz_all['EP_2'] = kurucz_all['E(cm-1)_2'] / ( 1 / constants.h / constants.c).to(u.cm**-1 / u.eV).value kurucz_all['EP'] = np.where((kurucz_all['EP_1'] <= kurucz_all['EP_2']), kurucz_all['EP_1'], kurucz_all['EP_2']) kurucz_all['loggf'] = kurucz_all['loggf_init'] + kurucz_all['hpf_frac'] indices = (kurucz_all['ele'] % 1 <= 0.2) & ~np.isnan(kurucz_all['loggf']) & ( kurucz_all['wavelength'] >= 200) & (kurucz_all['EP'] <= 50) kurucz_use = kurucz_all.loc[ indices, ['wavelength', 'ele', 'EP', 'loggf', 'C6']].reset_index(drop=True) kurucz_use['wavelength'] = kurucz_use['wavelength'] * 10 kurucz_use['D0'] = np.nan kurucz_use['EW'] = np.nan line_data.save_linelist(kurucz_use, 'files/linelist/kurucz/kurucz.list', wav_start=2000, wav_end=7e5) return kurucz_use
def mb992moog(mb99_path, save_path): mb99_j = pd.read_fwf(mb99_path, colspecs=[(0, 7), (8, 16), (24, 29), (32, 37), (48, 56)], names=['ele', 'wavelength', 'EP', 'loggf', 'C6']) mb99_j['ele'] = mb99_j['ele'].map(ele2ele_num) mb99_j['D0'] = np.nan mb99_j['EW'] = np.nan mb99_j_out = mb99_j[['wavelength', 'ele', 'EP', 'loggf', 'C6', 'D0', 'EW']] line_data.save_linelist(mb99_j_out, save_path, header='MB99 linelist')
def ges2moog(ges_path, save_path): GES = pd.read_csv(ges_path, sep='\t') GES['diss_energy'] = np.nan GES = GES[GES['moog_support'] == 'T'] GES_moog = GES[[ 'wave_A', 'spectrum_moog_species', 'lower_state_eV', 'loggf', 'waals', 'diss_energy', 'theoretical_ew' ]] GES_moog.columns = [ 'wavelength', 'element_index', 'EP', 'loggf', 'C6', 'D0', 'theoretical_ew' ] line_data.save_linelist(GES_moog, save_path, header='MB99 linelist')
def prepare_file(self, model_file=None, model_type='moog', loggf_cut=None, abun_change=None, molecules=None, atmosphere=1, lines=1): ''' Prepare the model, linelist and control files for MOOG. Can either provide stellar parameters and wavelengths or provide file names. If fine name(s) provided, the files will be copied to working directory for calculation. Parameters ---------- model_file : str, optional The name of the model file. If not specified will use internal Kurucz model. model_type : str, optional The type of the model file. Default is "moog" (then no conversion of format will be done); can be "moog", "kurucz-atlas9" and "kurucz-atlas12". logf_cut : float, optional The cut in loggf; if specified will only include the lines with loggf >= loggf_cut. abun_change : dict of pairs {int:float, ...} Abundance change, have to be a dict of pairs of atomic number and [X/Fe] values. ''' private.subprocess.run(['rm', MOOG_run_path + 'batch.par']) private.subprocess.run(['rm', MOOG_run_path + 'model.mod']) private.subprocess.run(['rm', MOOG_run_path + 'line.list']) private.os.system('rm ' + MOOG_run_path + 'MOOG.out*') if model_file == None: # Model file is not specified, will download Kurucz model according to stellar parameters. model.interpolate_model(self.teff, self.logg, self.m_h, abun_change=abun_change, molecules=molecules) self.model_file = 'model.mod' else: # Model file is specified; record model file name and copy to working directory. if model_type == 'moog': private.subprocess.run(['cp', model_file, MOOG_run_path], encoding='UTF-8', stdout=private.subprocess.PIPE) self.model_file = model_file.split('/')[-1] elif model_type[:6] == 'kurucz': model.KURUCZ_convert(model_path=model_file, abun_change=abun_change, model_type=model_type[7:], molecules=molecules) self.model_file = 'model.mod' if self.line_list[-5:] != '.list': # Linelist file is not specified, use internal line list; line_list = line_data.read_linelist(self.line_list, loggf_cut=loggf_cut) # Input EW into the linelist line_list = line_list[ (line_list['wavelength'] >= self.start_wav) & (line_list['wavelength'] <= self.end_wav)].reset_index( drop=True) line_list.loc[1:, 'wavelength'] = -line_list.loc[1:, 'wavelength'] line_list['EW'] = private.np.nan line_list.loc[0, 'EW'] = self.EW line_data.save_linelist(line_list, MOOG_run_path + 'line.list', negative=True) self.line_list = 'line.list' elif self.line_list[-5:] == '.list': # Linelist file is specified; record linelist file name and copy to working directory. private.subprocess.run(['cp', self.line_list, MOOG_run_path], encoding='UTF-8', stdout=private.subprocess.PIPE) self.line_list = self.line_list.split('/')[-1] # Input EW into the linelist line_list = line_data.read_linelist(MOOG_run_path + self.line_list) line_list.loc[1:, 'wavelength'] = -line_list.loc[1:, 'wavelength'] line_list['EW'] = private.np.nan line_list.loc[0, 'EW'] = self.EW line_data.save_linelist(line_list, MOOG_run_path + 'line.list', negative=True) # Create parameter file. self.create_para_file(self.ele, atmosphere=atmosphere, lines=lines)
def plot_contri_func(teff, logg, fe_h, resolution, line_list, line_wav_input=None, line_id=None, target_line_df=None): if target_line_df is None and (line_wav_input is None or line_id is None): raise ValueError( 'Please provide target_line_df or both line_wav_input and line_id.' ) if target_line_df is not None: wav_start = private.np.min(target_line_df['wavelength']) - 7 wav_end = private.np.max(target_line_df['wavelength']) + 7 s = synth.synth(teff, logg, fe_h, wav_start, wav_end, resolution, line_list=line_list) else: s = synth.synth(teff, logg, fe_h, line_wav_input - 7, line_wav_input + 7, resolution, line_list=line_list) # Whole spectra s.prepare_file() s.run_moog() s.read_spectra() wav_all, flux_all = s.wav, s.flux # Target line excluded linelist_all = line_data.read_linelist(MOOG_run_path + 'line.list') if target_line_df is not None: line_index_all = line_data.find_lines(target_line_df, linelist_all) else: smooth_width = line_wav_input / resolution indices = (private.np.abs(linelist_all['wavelength'] - line_wav_input) <= smooth_width) & (linelist_all['id'] == line_id) line_index_all = linelist_all[indices].index private.plt.figure(figsize=(14, 5 * len(line_index_all))) plot_index = 1 for line_index in line_index_all: linelist_exclude = linelist_all.drop(line_index).reset_index(drop=True) line_data.save_linelist(linelist_exclude, MOOG_run_path + 'line.list') s.run_moog() s.read_spectra() wav_exclude, flux_exclude = s.wav, s.flux # Target line only linelist_target = linelist_all.loc[line_index:line_index].reset_index( drop=True) line_wavlength = linelist_target.loc[0, 'wavelength'] line_loggf = linelist_target.loc[0, 'loggf'] line_EP = linelist_target.loc[0, 'EP'] s.prepare_file(atmosphere=2, lines=4) line_data.save_linelist(linelist_target, MOOG_run_path + 'line.list') s.run_moog() s.read_spectra() wav_target, flux_target = s.wav, s.flux # Calculate the EW and blending fraction EW = (private.np.sum(1 - flux_all) * 0.02 - private.np.sum(1 - flux_exclude) * 0.02) * 1000 depth = 1 - private.np.min( flux_all[private.np.abs(wav_all - line_wavlength) <= 0.01]) r_blend_depth = (1 - flux_exclude[private.np.argmin( private.np.abs(wav_exclude - line_wavlength))]) / (1 - flux_all[ private.np.argmin(private.np.abs(wav_all - line_wavlength))]) # Plot the line information CF_dict, atmosphere = cal_contri_func(MOOG_run_path + 'MOOG.out1', line_id=1) Ic_sum = private.np.sum(CF_dict['CF_Ic']) Dlp_sum = private.np.sum(CF_dict['CF_Dlp']) ax = private.plt.subplot(len(line_index_all), 2, plot_index) private.plt.plot(wav_all, flux_all, label='all lines included') private.plt.plot(wav_exclude, flux_exclude, label='target line excluded') private.plt.plot(wav_target, flux_target, label='target line only') private.plt.plot(line_wavlength, 1, alpha=0, label='EW={:.2f} m$\mathrm{{\AA}}$'.format(EW)) private.plt.plot(line_wavlength, 1, alpha=0, label='$d$={:.2f}'.format(depth)) private.plt.plot( line_wavlength, 1, alpha=0, label='$f_\mathrm{{blend,depth}}$={:.2f}'.format(r_blend_depth)) private.plt.axvline(wav_all[private.np.argmin( private.np.abs(wav_all - line_wavlength))], zorder=0, ls='--', c='gray') private.plt.xlim(line_wavlength - 5, line_wavlength + 5) private.plt.legend() private.plt.xlabel(r'Wavelength ($\mathrm{\AA}$)') private.plt.ylabel('Normalized flux') if target_line_df is not None: line_id = linelist_all.loc[line_index, 'id'] private.plt.title( 'Teff={:.0f}, logg={:.2f}, [Fe/H]={:.2f}, line_id={:.1f}, EP={:.2f}, loggf={:.3f}' .format(teff, logg, fe_h, line_id, line_EP, line_loggf)) plot_index += 1 ax = private.plt.subplot(len(line_index_all), 2, plot_index) private.plt.plot(private.np.log10(CF_dict['tau_ref']), CF_dict['CF_Dlp'] / max(CF_dict['CF_Ic']), label='CF: $D_l^p$') private.plt.plot(private.np.log10(CF_dict['tau_ref']), CF_dict['CF_Ilp'] / max(CF_dict['CF_Ic']), label='CF: $I_l^p$') private.plt.plot(private.np.log10(CF_dict['tau_ref']), CF_dict['CF_Dl'] / max(CF_dict['CF_Ic']), label='CF: $D_l$') if Dlp_sum / Ic_sum < 0.1: private.plt.ylim(private.plt.ylim()) private.plt.plot(private.np.log10(CF_dict['tau_ref']), CF_dict['CF_Ic'] / max(CF_dict['CF_Ic']), c='gray', label='CF: $I_c$') private.plt.xlabel(r'$\log{\tau_\mathrm{ref}}$') private.plt.ylabel('CF: max($I_c$) normalized as 1') private.plt.title('Contribution function') ax2 = private.plt.twinx() private.plt.plot(private.np.log10(atmosphere['tauref']), atmosphere['T'], ls='--', c='gray', zorder=0, label='T (K)') private.plt.ylabel('T (K)') lines, labels = ax.get_legend_handles_labels() lines2, labels2 = ax2.get_legend_handles_labels() ax2.legend(lines + lines2, labels + labels2) plot_index += 1 private.plt.tight_layout()
def cal_blending_ratio(teff, logg, fe_h, resolution, line_list, wav_range, weedout=True): wav_start = wav_range[0] - 7 wav_end = wav_range[1] + 7 s = synth.synth(teff, logg, fe_h, wav_start, wav_end, resolution, line_list=line_list, weedout=weedout) # Whole spectra s.prepare_file() s.run_moog() s.read_spectra(unlock=False) s.weedout = False wav_all, flux_all = s.wav, s.flux # Target line excluded linelist_all = line_data.read_linelist(s.rundir_path + line_list) indices = (linelist_all['wavelength'] >= wav_range[0]) & (linelist_all['wavelength'] <= wav_range[1]) linelist_out = linelist_all[indices].reset_index(drop=True) line_index_all = linelist_all[indices].index r_blend_depth = [] r_blend_EW = [] depth = [] for line_index in line_index_all: linelist_exclude = linelist_all.drop(line_index).reset_index(drop=True) line_data.save_linelist(linelist_exclude, s.rundir_path + line_list) s.run_moog() s.read_spectra() wav_exclude, flux_exclude = s.wav, s.flux # Calculate the EW and blending fraction linelist_target = linelist_all.loc[line_index:line_index].reset_index( drop=True) line_wavlength = linelist_target.loc[0, 'wavelength'] EW = (private.np.sum(1 - flux_all) * 0.02 - private.np.sum(1 - flux_exclude) * 0.02) * 1000 if flux_exclude[private.np.argmin( private.np.abs(wav_exclude - line_wavlength))] - flux_all[ private.np.argmin( private.np.abs(wav_exclude - line_wavlength))] < 1e-5: r_blend_depth.append(1.0) else: r_blend_depth.append( (1 - flux_exclude[private.np.argmin( private.np.abs(wav_exclude - line_wavlength))]) / (1 - flux_all[private.np.argmin( private.np.abs(wav_all - line_wavlength))])) EW_indices = private.np.abs( wav_exclude - line_wavlength) < line_wavlength / resolution * 3 r_blend_EW.append( private.np.sum(1 - flux_exclude[EW_indices]) / private.np.sum(1 - flux_all[EW_indices])) depth.append(1 - private.np.min(flux_all[ private.np.abs(wav_all - line_wavlength) <= 0.03])) linelist_out['depth'] = depth linelist_out['r_blend_depth'] = r_blend_depth linelist_out['r_blend_EW'] = r_blend_EW return linelist_out
def vald2moog_format(init_linelist_name, out_linelist_name, loggf_cut=None): ''' Transform VALD linelist download from VALD website into MOOG format. Parameters ---------- init_linelist_name : str The VALD format line list. out_linelist_name : str Output line list name head : int, optional If specified then only save the first `head` number of lines. loggf_cut : float, optional Cut on loggf (only save for the lines with loggf > loggf_cut) ''' # Find the footer index of VALD line pair with open(init_linelist_name) as file: contents = file.readlines() try: footer_index = len(contents) - contents.index( '* oscillator strengths were scaled by the solar isotopic ratios.\n' ) except ValueError: footer_index = 0 # Delete all the '. file = open(init_linelist_name) file_content = file.readlines() for i in range(len(file_content)): file_content[i] = file_content[i].replace("'", '') file.close() file = open(init_linelist_name, 'w') file.writelines(file_content) file.close() # subprocess.run(['sed', "s/'//g", init_linelist_name, '>', 'temp']) # subprocess.run(['mv', "temp", init_linelist_name]) vald_init = pd.read_csv(init_linelist_name, skiprows=2, skipfooter=footer_index, usecols=range(9), engine='python', names=[ 'element', 'wavelength', 'EP', 'loggf', 'rad_damp', 'Stark_damp', 'Walls_damp', 'Lande_factor', 'Comment' ]) if loggf_cut != None: vald_init = vald_init[vald_init['loggf'] >= loggf_cut] vald_init['element_all'] = vald_init[['element', 'Comment' ]].apply(lambda x: ', '.join(x), axis=1) vald_init['element_index'] = vald_init['element_all'].map(element2index) vald_init['diss_energy'] = vald_init['element_index'].map(get_diss_energy) vald_out = vald_init[[ 'wavelength', 'element_index', 'EP', 'loggf', 'Walls_damp', 'diss_energy' ]] vald_out.columns = [ 'wavelength', 'element_index', 'EP', 'loggf', 'C6', 'diss_energy' ] vald_out = vald_out.astype(np.float64) # Remove triple or higher ionized lines; MOOG cannot do this. vald_out = vald_out[ np.around(np.mod(vald_out['element_index'], 1), decimals=1) < 0.3] line_data.save_linelist(vald_out, out_linelist_name)