diff --git a/Metallicity_Stack_Commons/analysis/__init__.py b/Metallicity_Stack_Commons/analysis/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Metallicity_Stack_Commons/analysis/composite_indv_detect.py b/Metallicity_Stack_Commons/analysis/composite_indv_detect.py new file mode 100644 index 0000000..9e75238 --- /dev/null +++ b/Metallicity_Stack_Commons/analysis/composite_indv_detect.py @@ -0,0 +1,122 @@ +from os.path import join +from os.path import exists + +import numpy as np +from astropy.io import ascii as asc +from astropy.table import Table + +from ..temp_metallicity_calc import metallicity_calculation +from .. import OIII_r +from ..column_names import bin_names0, indv_names0, temp_metal_names0 +from ..column_names import filename_dict + +ID_name = indv_names0[0] +bin_ID_name = bin_names0[0] + + +def main(fitspath, dataset, revised=False, det3=True): + """ + Purpose: + Reads in composite table(s) containing bin information to + determine temperature-based metallicity from composite average + T_e and individual line ratios ([OII]/H-beta, [OIII]/H-beta) + + :param fitspath: str containing folder path + :param dataset: str containing sub-folder (specific to stacking approach) + :param revised: Bool indicates whether to use revised bin properties + (e.g., *.revised.tbl files) + :param det3: Bool indicates whether individual galaxy files is limited to + those satisfying emission-line det3 requirement + Default: True + + Files identified by default + composite_file: str containing filename of composite data + e.g., '[dataset]/bin_derived_properties.tbl' or + '[dataset]/bin_derived_properties.revised.tbl' + indv_em_line_file: str containing filename that contains + emission-line information for each galaxy + e.g., 'individual_properties.tbl' + indv_bin_file: str containing filename tha contains bin information + for each galaxy + e.g., '[dataset]/individual_bin_info.tbl' + outfile: str containing filename of output file + e.g., '[dataset]/individual_derived_properties.tbl' + """ + + # Define [composite_file] + t_comp = filename_dict['bin_derived_prop'] if not revised else \ + filename_dict['bin_derived_prop'] + composite_file = join(fitspath, dataset, t_comp) + if not exists(composite_file): + print("ERROR: File not found! "+composite_file) + return + + # Read in composite table + composite_table = asc.read(composite_file) + + bin_id = composite_table['bin_ID'].data + bin_temp = composite_table['T_e'].data + + # Define [indv_em_line_file] + indv_em_line_file = join(fitspath, dataset, filename_dict['indv_prop']) + if not exists(indv_em_line_file): + print("ERROR: File not found! "+indv_em_line_file) + return + + # Read in tables containing line ratios, etc. + indv_em_line_table = asc.read(indv_em_line_file) + + # Define [indv_bin_file] + indv_bin_file = join(fitspath, dataset, filename_dict['indv_bin_info']) + if not exists(indv_bin_file): + print("ERROR: File not found! "+indv_bin_file) + return + + # Read in tables containing bin info for individual + indv_bin_info_table = asc.read(indv_bin_file) + + # Populate composite temperature for individual galaxies + adopted_temp = np.zeros(len(indv_em_line_table)) + bin_id_indv = np.zeros(len(indv_em_line_table)) + for comp_bin, comp_temp in zip(bin_id, bin_temp): + bin_idx = np.where(indv_bin_info_table['bin_ID'].data == comp_bin)[0] + adopted_temp[bin_idx] = comp_temp + bin_id_indv[bin_idx] = comp_bin + + O2 = indv_em_line_table['OII_3727_Flux_Gaussian'].data # [OII]3726,3728 fluxes + O3 = indv_em_line_table['OIII_5007_Flux_Gaussian'].data * OIII_r # [OIII]4959,5007 fluxes (Assume 3.1:1 ratio) + Hb = indv_em_line_table['HBETA_Flux_Gaussian'].data # H-beta fluxes + + if det3: + com_O_log, metal_dict = metallicity_calculation(adopted_temp, O2/Hb, O3/Hb) + else: + det3 = np.where((indv_bin_info_table['Detection'] == 1.0) | (indv_bin_info_table['Detection'] == 0.5))[0] + temp_com_O_log, temp_metal_dict = \ + metallicity_calculation(adopted_temp[det3], O2[det3]/Hb[det3], + O3[det3]/Hb[det3]) + com_O_log = np.zeros(len(indv_em_line_table)) + com_O_log[det3] = temp_com_O_log + + metal_dict = dict() + for key0 in temp_metal_dict.keys(): + metal_dict[key0] = np.zeros(len(indv_em_line_table)) + metal_dict[key0][det3] = temp_metal_dict[key0] + + # Define [indv_derived_prop_table] to include ID, bin_ID, composite T_e, + # and 12+log(O/H) + arr0 = [indv_em_line_table[ID_name], bin_id_indv, adopted_temp, com_O_log] + names0 = [ID_name, bin_ID_name] + temp_metal_names0[:2] + + # Include other metallicities + arr0 += list(metal_dict.values()) + names0 += metal_dict.keys() + indv_derived_prop_table = Table(arr0, names=names0) + + outfile = join(fitspath, dataset, filename_dict['indv_derived_prop']) + + # Write Astropy ASCII table containing composite T_e and derived metallicity + if exists(outfile): + print("File exists! Overwriting : ", outfile) + else: + print("Writing : ", outfile) + indv_derived_prop_table.write(outfile, overwrite=True, format='ascii.fixed_width_two_line') diff --git a/Metallicity_Stack_Commons/column_names.py b/Metallicity_Stack_Commons/column_names.py new file mode 100644 index 0000000..3ad850f --- /dev/null +++ b/Metallicity_Stack_Commons/column_names.py @@ -0,0 +1,136 @@ +from . import line_name, line_type + + +# Need to define here +def line_fit_suffix_add(line_name0, line_type0): + """ + Purpose: + Simple list comprehension combining emission line fit suffixes with + the emission line. This works for individual lines + + :param line_name0: str containing the line name + :param line_type0: str containing the emisison-line type (e.g., 'Balmer') + :return: gauss_lines_names: list with str formatted as [LINE]_[SUFFIX] + """ + + gauss_lines_names = ['{}_{}'.format(line_name0, suffix) for suffix in gauss_names0] + if line_type0 == 'Balmer': + gauss_lines_names += ['{}_{}'.format(line_name0, suffix) for suffix in balmer_names0] + + return gauss_lines_names + + +# These are common/general column names + +# Column names for bin information +bin_names0 = ['bin_ID', 'N_stack', 'Detection'] + +# Column names for individual galaxies/spectra +indv_names0 = ['ID', 'logR23', 'logO32', 'logM', 'logLHb', 'two_beta', 'three_beta'] + +# Dust attenuation +dust0 = ['E(B-V)', 'HgHb', 'HdHb'] + +# Column names for bin information in stellar mass and H-beta luminosity +bin_mzevolve_names0 = ['logM_min', 'logM_max', 'logM_avg', 'logM_median', + 'logLHb_min', 'logLHb_max', 'logLHb_avg', 'logLHb_median'] + +# Column names for bin information in R23 and O32 line ratios +bin_zcalbase_names0 = ['logR23_min', 'logR23_max', 'logR23_avg', 'logR23_median', + 'logO32_min', 'logO32_max', 'logO32_avg', 'logO32_median'] + +# Column names for composite line ratios +bin_ratios0 = ['logR23_composite', 'logO32_composite', + 'two_beta_composite', 'three_beta_composite'] + +# Column names for Gaussian fitting +# This is just the suffix +gauss_names0 = ['Flux_Gaussian', 'Flux_Observed', 'S/N', 'Center', 'Norm', + 'Median', 'Sigma'] +balmer_names0 = ['Abs_Norm', 'Abs_Sigma'] + +# Emission-line fit column names with [LINE] prefix +gauss_lines_names0 = [] +for line0, type0 in zip(line_name, line_type): + gauss_lines_names0 += line_fit_suffix_add(line0, type0) + + +# Temperature and metallicity properties +temp_metal_names0 = ['T_e', '12+log(O/H)', 'log(O+/H)', 'log(O++/H)', 'O+/H', 'O++/H'] + +# Dictionary containing filenames +filename_dict = dict() + +# Bin-related files +filename_dict['bin_info'] = 'bin_info.tbl' +filename_dict['bin_valid'] = 'bin_validation.tbl' +filename_dict['bin_fit'] = 'bin_emission_line_fit.tbl' +filename_dict['bin_fit_rev'] = filename_dict['bin_fit'].replace('.tbl', '.revised.tbl') +filename_dict['bin_derived_prop'] = 'bin_derived_properties.tbl' +filename_dict['bin_derived_prop_rev'] = filename_dict['bin_derived_prop'].replace('.tbl', '.revised.tbl') + +# Individual galaxy/spectra-related files +filename_dict['indv_prop'] = 'individual_properties.tbl' +filename_dict['indv_bin_info'] = 'individual_bin_info.tbl' +filename_dict['indv_derived_prop'] = 'individual_derived_properties.tbl' + + +def merge_column_names(*args): + """ + Purpose: + Merges multiple lists containing column names. + + Usage: + column_names = merge_column_names(bin_names0, indv_names0) + + :param args: An undefined number of lists + :return merge_list: + """ + + merge_list = list() + + arg_count = len(args) + if arg_count > 0: + for elem in args: + merge_list += elem + + return merge_list + + +def remove_from_list(list0, remove_entries): + """ + Purpose: + Remove entries from list + + :param list0: list of column names + :param remove_entries: list of column names to remove + """ + + dup_list0 = list0.copy() + + for entry in remove_entries: + dup_list0.remove(entry) + + return dup_list0 + + +def indv_R23_O32(): + """ + Purpose: + Use remove_from_list() to provide simplified list that contains ID, logR23 and logO32 + + :return: list containing just ID, logR23, logO32 + """ + + return remove_from_list(indv_names0, ['logM', 'logLHb']) + + +def indv_M_LHb(): + """ + Purpose: + Use remove_from_list() to provide simplified list that contains ID, logM and logLHb + + :return: list containing just ID, logM, logLHb + """ + + return remove_from_list(indv_names0, ['logR23', 'logO32']) diff --git a/Metallicity_Stack_Commons/temp_metallicity_calc.py b/Metallicity_Stack_Commons/temp_metallicity_calc.py index 839cdb6..0a4fa76 100644 --- a/Metallicity_Stack_Commons/temp_metallicity_calc.py +++ b/Metallicity_Stack_Commons/temp_metallicity_calc.py @@ -1,6 +1,7 @@ import numpy as np from . import k_dict +from .column_names import temp_metal_names0 k_4363 = k_dict['OIII_4363'] k_5007 = k_dict['OIII_5007'] @@ -73,7 +74,8 @@ def metallicity_calculation(T_e, TWO_BETA, THREE_BETA): com_O = O_s_ion + O_d_ion com_O_log = np.log10(com_O) + 12 - metal_dict = dict(O_s_ion=O_s_ion, O_d_ion=O_d_ion, - O_s_ion_log=O_s_ion_log, O_d_ion_log=O_d_ion_log) + keys = temp_metal_names0[2:] + arr0 = [O_s_ion, O_d_ion, O_s_ion_log, O_d_ion_log] + metal_dict = dict(zip(keys, arr0)) return com_O_log, metal_dict