resultsFolder = Path(obsConf['data_location']['results_folder']) fileList = obsConf['data_location']['file_list'] objList = obsConf['data_location']['object_list'] z_list = obsConf['sample_data']['z_array'] norm_flux = obsConf['sample_data']['norm_flux'] percentil_array = obsConf['sample_data']['percentil_array'] voxel_grid_size = obsConf['sample_data']['grid_shape_array'] # Store emissivity ratios at standard conditions H1 = pn.RecAtom('H', 1) temp, den = 10000.0, 100.0 theoEmis_dict = {} for chemLabel, plotLabel in label_Conver.items(): ion, wave, latexLabel = sr.label_decomposition(chemLabel, scalar_output=True) dict_label = f'{plotLabel}/Hdelta' theoRatio = H1.getEmissivity(temp, den, wave=wave) / H1.getEmissivity( temp, den, wave=4102) theoEmis_dict[dict_label] = theoRatio red_model = sr.ExtinctionModel(Rv=obsConf['extinction']['R_v'], red_curve=obsConf['extinction']['red_law']) # Data location objFolder = resultsFolder db_address = objFolder / 'J0838_blue_database.fits' linesMaps_fits_address = resultsFolder / f'J0838_lineParamMaps.fits' # ----------------------------------------- Generate the image data # # # Empty containers for the images
# Add missing rows S2_6716A_m_flux = objLinesDF.loc[ 'S2_6716A', 'obsFlux'] + objLinesDF.loc['S2_6731A', 'obsFlux'] S2_6716A_m_err = np.sqrt(objLinesDF.loc['S2_6716A', 'obsFluxErr']**2 + objLinesDF.loc['S2_6731A', 'obsFluxErr']**2) S2_6716A_m_lambda = (objLinesDF.loc['S2_6716A', 'obsFlux'] + objLinesDF.loc['S2_6731A', 'obsFlux']) / 2 objLinesDF.loc['S2_6716A_m', 'obsFlux'] = S2_6716A_m_flux objLinesDF.loc['S2_6716A_m', 'obsFluxErr'] = S2_6716A_m_err objLinesDF.loc['S2_6716A_m', 'f_lambda'] = S2_6716A_m_lambda tableLines = sr_lineLabels.copy() i_6725A = sr_lineLabels.index('S2_6731A') + 1 tableLines.insert(i_6725A, 'S2_6716A_m') ion_array, wave_array, latexLabel_array = sr.label_decomposition( tableLines, combined_dict=combined_line_dict) table_headers = [ 'Line ID', 'Observed flux', r'\makecell{Bayesian: \\ Direct method}', r'\makecell{\textsc{HII-CHI-mistry: } \\ Spherical}', r'\makecell{\textsc{HII-CHI-mistry: } \\ Plane-Parallel}', r'\makecell{Bayesian \textsc{HII-CHI-mistry: } \\ Plane-Parallel}', r'\makecell{Bayesian \\ Direct Method + \textsc{HII-CHI-mistry} \\ Plane-Parallel}' ] txt_headers = [ 'Observed_flux', 'Observed_err', 'DirectMethod_fitFlux', 'DirectMethod_fitSigma', 'DirectMethod_difPercentage', 'HIICHImistry_Spherical_fitFlux', 'HIICHImistry_Spherical_fitSigma',
cube_address_i = fitsFolder / fileList[i] mask_address = dataFolder / obsConf['data_location']['mask_global'] db_address = objFolder / f'{obj}_database.fits' # Load the data wave, data, header = sr.import_fits_data(cube_address_i, instrument='fits-cube', frame_idx=0) mask_global_DF = sr.lineslogFile_to_DF(mask_address) # Declare voxels to analyse flux5007_image = fits.getdata(db_address, f'{ref_flux_line}_flux', ver=1) flux5007_levels = np.nanpercentile(flux5007_image, percentil_array) ion, wavelength, latexLabel = sr.label_decomposition( ref_flux_line, scalar_output=True) for idx_level, flux_level in enumerate(flux5007_levels): if idx_level + 1 < len(flux5007_levels): if idx_level == 0: maFlux_image = np.ma.masked_where( (flux5007_image >= flux5007_levels[idx_level + 1]), flux5007_image) else: maFlux_image = np.ma.masked_where( (flux5007_image <= flux5007_levels[idx_level]) & (flux5007_image >= flux5007_levels[idx_level + 1]), flux5007_image)
model_variables = ['logOH', 'logU', 'logNO'] gw = sr.ModelGridWrapper() grid_dict, axes_cords_a = gw.ndarray_from_DF(grid_3D_DF, axes_columns=model_variables) grid_interpolators = gw.generate_xo_interpolators(grid_dict, model_variables, axes_cords_a, interp_type='point') exclude_lines = np.array( ['H1_4861A', 'N1_5198A', 'N1_5200A', 'C2_4267A', 'O2_4651A', 'C2_4659A']) min_wavelength = 4700 input_lines = np.array(list(grid_dict.keys())) ion_array, wave_array, latex_array = sr.label_decomposition(input_lines) idcs_lines = ~np.isin(input_lines, exclude_lines) & (min_wavelength < wave_array) input_lines = input_lines[idcs_lines] r_steps = 5 logOH_range = np.round(np.linspace(7.15, 9.0, r_steps), 3) logU_range = np.round(np.linspace(-3.90, -1.40, r_steps), 3) logNO_range = np.round(np.linspace(-1.90, -0.01, r_steps), 3) i_step, n_steps = 0, logNO_range.size * logOH_range.size * logNO_range.size # Loop throught the grid of synthetic conditions (around 30 seconds per fit) objFolder = resultsFolder / f'CGCG007/' # outputFits = objFolder / f'grid_logOH_logU_logNO.fits' outputFits = objFolder / f'grid_logOH_logU_logNO_advi.fits'
mainLinesLog = objFolder/f'{obj}_BR_linesLog.txt' mainLogDF = sr.lineslogFile_to_DF(mainLinesLog) flux_Hbeta, err_Hbeta = mainLogDF.loc['H1_4861A', 'intg_flux'], mainLogDF.loc['H1_4861A', 'intg_err'] flux_norm = ufloat(flux_Hbeta, err_Hbeta) idcs_obsLines = ~mainLogDF.index.str.contains('_b') obsLines = mainLogDF.loc[idcs_obsLines].index.values linesFlux = mainLogDF.loc[idcs_obsLines, 'intg_flux'].values LinesErr = mainLogDF.loc[idcs_obsLines, 'intg_err'].values lineFluxArray = unumpy.uarray(linesFlux, LinesErr) lineNormArray = lineFluxArray/flux_norm ion_array, wave_array, latexLabel_array = sr.label_decomposition(obsLines, combined_dict=obsData['default_line_fitting']) # Plot Configuration defaultConf = STANDARD_PLOT.copy() rcParams.update(defaultConf) # plt.locator_params(axis='x', nbins=obsLines.size) x_loc = np.arange(obsLines.size) fig, ax = plt.subplots(figsize=(12, 8)) ax.set_xticks(x_loc) ax.set_xticklabels(latexLabel_array, rotation=90) ax.errorbar(x_loc, unumpy.nominal_values(lineNormArray), yerr=unumpy.std_devs(lineNormArray), fmt='o', color='black', label='OSIRIS') # Loop through the extensions and put the data in the plot for ext in ['_B', '_R']:
# First page has the default (primary) data new_hdul.append(fits.PrimaryHDU()) # Second page for the fits file plot configuration col_waves = fits.Column(name='wave', array=wave, format='1E') hdu_table = fits.BinTableHDU.from_columns([col_waves], name='PlotConf') new_hdul.append(hdu_table) for key in coordinates_keys_list: new_hdul[1].header[key] = cube.data_header[key] new_hdul[1].header['NPIXWAVE'] = cube.data_header['NAXIS3'] # Create flux maps for the main lines: for lineLabel, lineLimits in lineAreas.items(): plot_image_file = objFolder/f'{obj}_{lineLabel}_contours.png' ion, wavelength, latexLabel = sr.label_decomposition(lineLabel, scalar_output=True) # Extract cube slice using mpdaf defult tools. # This requires the input wavelengths to be on the same scale as in the cube line_image = cube.get_image(np.array(lineLimits) * (1 + z_objs[i]), subtract_off=True) flux_image = line_image.data.data levelContours = np.nanpercentile(flux_image, pertil_array) # Store fluxes and contours hdu_image = fits.ImageHDU(name=f'{lineLabel}_flux', data=flux_image, ver=1) for idx, level in enumerate(levelContours): level_label = f'hierarch P{int(pertil_array[idx]*100)}' hdu_image.header[level_label] = level new_hdul.append(hdu_image) # Plot the image:
'Ne3': 7.065 + 0.15 * n_obj, 'Fe3': 5.055 + 0.15 * n_obj, 'Ar3': 5.725 + 0.15 * n_obj, 'Ar4': 5.065 + 0.15 * n_obj} # Declare lines to simulate merged_lines = {'O2_3726A_m': 'O2_3726A-O2_3729A', 'O2_7319A_m': 'O2_7319A-O2_7330A'} objParams['input_lines'] = ['H1_4341A', 'H1_4861A', 'H1_6563A', 'He1_4026A', 'He1_4471A', 'He1_5876A', 'He1_6678A', 'He1_7065A', 'He2_4686A', 'O2_3726A_m', 'O2_7319A_m', 'O3_4363A', 'O3_4959A', 'O3_5007A', 'N2_6548A', 'Ne3_3968A', 'Fe3_4658A', 'N2_6584A', 'S2_6716A', 'S2_6731A', 'S3_6312A', 'S3_9069A', 'S3_9531A', 'Ar3_7136A', 'Ar4_4740A'] # We use the default lines database to generate the synthetic emission lines log for this simulation linesLogPath = os.path.join(sr._literatureDataFolder, sr._default_cfg['data_location']['lines_data_file']) ion_array, wavelength_array, latexLabel_array = sr.label_decomposition(objParams['input_lines'], combined_dict=merged_lines) # Define a pandas dataframe to contain the lines data linesLogHeaders = ['wavelength', 'intg_flux', 'intg_err', 'ion', 'blended_label', 'latexLabel'] objLinesDF = pd.DataFrame(index=objParams['input_lines'], columns=linesLogHeaders) objLinesDF = objLinesDF.assign(wavelength=wavelength_array, ion=ion_array, latexLabel=latexLabel_array, blended_label='None') objLinesDF.sort_values(by=['wavelength'], ascending=True, inplace=True) # Blended labels idcs_blended = objLinesDF.index.isin(merged_lines.keys()) objLinesDF.loc[idcs_blended, 'blended_label'] = list(merged_lines.values()) # Declare extinction properties objRed = sr.ExtinctionModel(Rv=objParams['simulation_properties']['R_v'], red_curve=objParams['simulation_properties']['reddenig_curve'],
z_i = hdrs[1]["z"][0] lm = sr.LineMesurer(wave, flux, redshift=z_i, normFlux=normFlux) norm_spec = lm.continuum_remover(noiseRegionLims=noise_region) obsLinesTable = lm.line_finder(norm_spec, noiseWaveLim=noise_region, intLineThreshold=1) matchedDF = lm.match_lines(obsLinesTable, maskDF) # lm.plot_spectrum(obsLinesTable=obsLinesTable, matchedLinesDF=matchedDF, specLabel=f'Emission line detection') for line in linesForced: if line not in matchedDF.index: matchedDF.loc[line] = maskDF.loc[line] matchedDF.sort_values(by=['wavelength'], ascending=True, inplace=True) # Adding latex label to the plot ion_array, wavelength_array, latexLabel_array = sr.label_decomposition(matchedDF.index.values) matchedDF['latexLabel'] = latexLabel_array # Improve line region selection lm.plot_line_mask_selection(matchedDF, local_mask) # # Measure the emission lines # lm = sr.LineMesurer(wave, flux, redshift=z_i, normFlux=normFlux) # objMaskDF = sr.lineslogFile_to_DF(local_mask) # for i, lineLabel in enumerate(objMaskDF.index.values): # wave_regions = objMaskDF.loc[lineLabel, 'w1':'w6'].values # lm.fit_from_wavelengths(lineLabel, wave_regions) # lm.plot_line_grid(lm.linesDF) # ------------------------------ Check available lines
cube_address_i = dataFolder/fileList[i] objFolder = resultsFolder db_addresss = resultsFolder/f'{obj}_database.txt' # Load data obj_db = pd.read_csv(db_addresss, delim_whitespace=True, header=0, index_col=0) wave, cube, header = sr.import_fits_data(cube_address_i, instrument='MUSE') # Plot the line flux maps cube_shape = obsData['sample_data']['cube_size_array'] for lineComp in obsData['default_line_fitting']['H1_6563A_b'].split('-'): for param in ['gauss_flux', 'mu', 'v_r', 'sigma', 'sigma_vel']: column_name = f'{lineComp}-{param}' lineFlux_i = np.reshape(obj_db[column_name].values, cube_shape.astype(int)) ion, wave, latexCode = sr.label_decomposition(lineComp, scalar_output=True) # Define image countours based on the flux percentiles levelFlux_i = np.percentile(lineFlux_i[lineFlux_i > 0], pertil_array) levels_text_i = ['None'] * len(levelFlux_i) for idx, per in enumerate(pertil_array): levels_text_i[idx] = f'{levelFlux_i[idx]:.2f} $P_{{{per}}}$' # Crop image to the biggest square with non-nans nans = np.isnan(lineFlux_i) nancols = np.all(nans, axis=0) nanrows = np.all(nans, axis=1) firstcol = nancols.argmin() firstrow = nanrows.argmin() lastcol = len(nancols) - nancols[::-1].argmin() lastrow = len(nanrows) - nanrows[::-1].argmin()
gridLineDict, gridAxDict = sr.load_ionization_grid(log_scale=True) lineInterpolator_dict = gridInterpolatorFunction(gridLineDict, gridAxDict['logU'], gridAxDict['Teff'], gridAxDict['OH'], interp_type='cube') # Declare lines to simulate lineLabels = np.array([ 'O2_3726A_m', 'He1_4471A', 'He2_4686A', 'O3_5007A', 'He1_5876A', 'S2_6716A_m' ]) objParams['input_lines'] = lineLabels # We use the default lines database to generate the synthetic emission lines log for this simulation ion_array, wavelength_array, latexLabel_array = sr.label_decomposition( objParams['input_lines']) # Define a pandas dataframe to contain the lines data linesLogHeaders = [ 'wavelength', 'obsFlux', 'obsFluxErr', 'ion', 'blended_label', 'latexLabel' ] objLinesDF = pd.DataFrame(index=lineLabels, columns=linesLogHeaders) objLinesDF['ion'] = ion_array objLinesDF['wavelength'] = wavelength_array objLinesDF['latexLabel'] = latexLabel_array # Declare extinction properties objRed = sr.ExtinctionModel( Rv=objParams['simulation_properties']['R_v'], red_curve=objParams['simulation_properties']['reddenig_curve'], data_folder=objParams['data_location']['external_data_folder'])
print(f'\n- {obj}') file_address_i = f'{dataFolder}/{fileList[i]}' wave, cube, header = sr.import_fits_data(file_address_i, instrument='MUSE') wave = wave / (1 + z_objs[i]) print(f'\n-- {header["OBJECT"]}') # Get astronomical coordinates one pixel coord_sky = cube.wcs.pix2sky(idx_voxel, unit=u.deg) dec, ra = deg2sexa(coord_sky)[0] wcs_cube = WCS(cube.data_header) # Treat all the lines for lineLabel, lineLimits in lineAreas.items(): # Get line flux region ion, lineWave, latexlabel = sr.label_decomposition([lineLabel]) # lineIdcs = np.searchsorted(wave, np.array(lineLimits)) # lineImage = cube[lineIdcs[0]:lineIdcs[1], :, :].sum(axis=0)/wave[lineIdcs[0]:lineIdcs[1]].size # print(lineLabel, wave[lineIdcs[0]:lineIdcs[1]].size) # flux_image = lineImage.data.data line_image = cube.get_image(np.array(lineLimits) * (1 + z_objs[i]), subtract_off=True) flux_image = line_image.data.data # Plot line image map with coordinates labelsDict = {'xlabel': r'RA', 'ylabel': r'DEC', 'title': r'Galaxy {} {}'.format(obj, latexlabel[0])} # Plot Configuration defaultConf = STANDARD_PLOT.copy()